mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2025-08-14 08:52:22 +00:00
Compare commits
194 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
11fbfda6bf | ||
|
4f0353d0fb | ||
|
a605d68d73 | ||
|
237b7fbf1b | ||
|
4a7e21f6b4 | ||
|
b7017573b8 | ||
|
a98b087c5d | ||
|
161c840136 | ||
|
4dd2abc202 | ||
|
cc0e9f61a7 | ||
|
21a658f1f4 | ||
|
b99f391c2a | ||
|
9abe25b91a | ||
|
2531fc6dac | ||
|
e5551cb179 | ||
|
4728b7a8b7 | ||
|
2863921e15 | ||
|
b93668edfe | ||
|
8ae91b8c31 | ||
|
894a23d701 | ||
|
3598906cbd | ||
|
75c12e2d4b | ||
|
d6e0519a3d | ||
|
41efc71626 | ||
|
6e3d97f472 | ||
|
9d58d02522 | ||
|
fe86396b21 | ||
|
97994f7632 | ||
|
33d63457b3 | ||
|
ed36d9e953 | ||
|
9a478d74d2 | ||
|
72d72544a4 | ||
|
4bbbe81182 | ||
|
a0af0c2492 | ||
|
ce7d3e4702 | ||
|
1bb4ca8541 | ||
|
ea65445772 | ||
|
972db8fcea | ||
|
a3c12631f0 | ||
|
3cadfd08d8 | ||
|
104f3de013 | ||
|
713b41bd52 | ||
|
253093fa2f | ||
|
f36af5af64 | ||
|
97b6c0e44d | ||
|
c4f6dabd4d | ||
|
d1c8aeb25d | ||
|
6e1cb2e0fe | ||
|
da9762f60e | ||
|
27affdec14 | ||
|
433a19e46a | ||
|
da9db9d3d1 | ||
|
ed4b0eba2f | ||
|
615aecf80f | ||
|
4622d1a610 | ||
|
f1b80d8f57 | ||
|
e76e303383 | ||
|
97133c3fcb | ||
|
450610b6e6 | ||
|
4dc3fd92cc | ||
|
f4b5e7c044 | ||
|
6c0b2a468d | ||
|
e33f724f1b | ||
|
b0d5562917 | ||
|
eecf7a2194 | ||
|
54fd8a0332 | ||
|
b6ca91980b | ||
|
6af7e2d749 | ||
|
86d334c204 | ||
|
585a4fa449 | ||
|
7438073e7e | ||
|
6e808ae35a | ||
|
99ec64e852 | ||
|
eeac63c0a5 | ||
|
5d5a3c3301 | ||
|
31e9730236 | ||
|
69b32a02ff | ||
|
a222df8176 | ||
|
7f4c99be60 | ||
|
ccff657a62 | ||
|
fb258499e1 | ||
|
79c6d6c742 | ||
|
80d9d5480c | ||
|
958a553922 | ||
|
a44bbc3513 | ||
|
d7f2f4a3e7 | ||
|
073566a23e | ||
|
590aecfcf1 | ||
|
77ab52310e | ||
|
2c2ccddbe4 | ||
|
87062db9d5 | ||
|
b74701dbc5 | ||
|
a88db8830b | ||
|
36cd83c796 | ||
|
a039c93c05 | ||
|
57b4ade3be | ||
|
87ce6cfa98 | ||
|
6a99c8c81d | ||
|
46e8188d5a | ||
|
3c990df1fe | ||
|
8969bc5aa6 | ||
|
45e8ca8d42 | ||
|
39930153c9 | ||
|
5890e46db3 | ||
|
c5c06a08ba | ||
|
2a0e677a89 | ||
|
8f7a968dc9 | ||
|
20cfc50448 | ||
|
4bf019ec7e | ||
|
57fe45484c | ||
|
7744f4ed76 | ||
|
a43e81e229 | ||
|
f6ad7e250b | ||
|
0f2b0482ec | ||
|
21d850d39e | ||
|
d3f2e42301 | ||
|
df68154f10 | ||
|
f8ebf03afd | ||
|
23f8b97319 | ||
|
d712054353 | ||
|
58da896b14 | ||
|
8db57bda6e | ||
|
53f29ec710 | ||
|
43a8fc0e86 | ||
|
7f2adb068e | ||
|
218ae9f9bf | ||
|
350c03874d | ||
|
575c0e5bf9 | ||
|
3a890ba2c7 | ||
|
2a345f4869 | ||
|
658ebbd84d | ||
|
0c54ade367 | ||
|
f16ba64026 | ||
|
d72127aaeb | ||
|
40e0b1291c | ||
|
0fae7f0166 | ||
|
6f916a4c32 | ||
|
41979d5389 | ||
|
0d51205bd6 | ||
|
416dd52a30 | ||
|
850e45b9a5 | ||
|
040d2ca7f6 | ||
|
e173072622 | ||
|
991dd80382 | ||
|
5fc5d02134 | ||
|
0f51256add | ||
|
a78860dbc4 | ||
|
f655a3c52d | ||
|
b69aebd5be | ||
|
769a7c391f | ||
|
9a4d55aa36 | ||
|
e776acfbab | ||
|
b4f58286b4 | ||
|
59779cc931 | ||
|
567bcecc80 | ||
|
0ca87dc29b | ||
|
6e0824e357 | ||
|
9a8a620658 | ||
|
eb1db3120d | ||
|
98a9225c32 | ||
|
1b8fb766a8 | ||
|
c28ef3ec3b | ||
|
fab3f0630c | ||
|
d2499ad157 | ||
|
724a37bbf4 | ||
|
c5f1c30b1c | ||
|
e90363df71 | ||
|
0932008619 | ||
|
a24e00ad5a | ||
|
fab938055f | ||
|
b2026b0dac | ||
|
c1c742084e | ||
|
7140f590cf | ||
|
dcc26ad666 | ||
|
70f1ecad49 | ||
|
03c7383b54 | ||
|
d3734971cc | ||
|
cff8358b3e | ||
|
42d691c4ce | ||
|
33dcbe8b5a | ||
|
980c7a4390 | ||
|
1b7f881d5a | ||
|
8635e2cf67 | ||
|
e36bc8bab2 | ||
|
693da7733f | ||
|
6b6128d92d | ||
|
64586a44b4 | ||
|
2d28ecca32 | ||
|
92f3edb337 | ||
|
32f8edecdd | ||
|
14b061cd28 | ||
|
aeb90cbdd2 | ||
|
e2a0b627b2 | ||
|
de5eb0d914 |
90
CHANGELOG.md
90
CHANGELOG.md
@ -1,3 +1,93 @@
|
||||
## 2025-08-06
|
||||
|
||||
### New version v1.1.4
|
||||
|
||||
### Added
|
||||
|
||||
- **Proxmox 9 Compatibility Preparation**
|
||||
This version prepares **ProxMenux** for the upcoming **Proxmox VE 9**:
|
||||
- The function to add the official Proxmox repositories now supports the new `.sources` format used in Proxmox 9, while maintaining backward compatibility with Proxmox 8.
|
||||
- Banner removal is now optionally supported for Proxmox 9.
|
||||
|
||||
- **xshok-proxmox Detection**
|
||||
Added a check to detect if the `xshok-proxmox` post-install script has already been executed.
|
||||
If detected, a warning is shown to avoid conflicting adjustments:
|
||||
|
||||
```
|
||||
It appears that you have already executed the xshok-proxmox post-install script on this system.
|
||||
|
||||
If you continue, some adjustments may be duplicated or conflict with those already made by xshok.
|
||||
|
||||
Do you want to continue anyway?
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Improved
|
||||
|
||||
- **Banner Removal (Proxmox 8.4.9+)**
|
||||
Updated the logic for removing the subscription banner in **Proxmox 8.4.9**, due to changes in `proxmoxlib.js`.
|
||||
|
||||
- **LXC Disk Passthrough (Persistent UUID)**
|
||||
The function to add a physical disk to an LXC container now uses **UUID-based persistent paths**.
|
||||
This ensures that disks remain correctly mounted, even if the `/dev/sdX` order changes due to new hardware.
|
||||
|
||||
```bash
|
||||
PERSISTENT_DISK=$(get_persistent_path "$DISK")
|
||||
if [[ "$PERSISTENT_DISK" != "$DISK" ]] ...
|
||||
```
|
||||
|
||||
- **System Utilities Installer**
|
||||
Now checks whether APT sources are available before installing selected tools.
|
||||
If a new Proxmox installation has no active repos, it will **automatically add the default sources** to avoid installation failure.
|
||||
|
||||
- **IOMMU Activation on ZFS Systems**
|
||||
The function that enables IOMMU for passthrough now verifies existing kernel parameters to avoid duplication if the user has already configured them manually.
|
||||
|
||||
---
|
||||
|
||||
### Fixed
|
||||
|
||||
- Minor code cleanup and improved runtime performance across several modules.
|
||||
|
||||
|
||||
|
||||
## 2025-07-20
|
||||
|
||||
### Changed
|
||||
|
||||
- **Subscription Banner Removal (Proxmox 8.4.5+)**
|
||||
Improved the `remove_subscription_banner` function to ensure compatibility with Proxmox 8.4.5, where the banner removal method was failing after clean installations.
|
||||
|
||||
- **Improved Log2RAM Detection**
|
||||
In both the automatic and customizable post-install scripts, the logic for Log2RAM installation has been improved.
|
||||
Now it correctly detects if Log2RAM is already configured and avoids triggering errors or reconfiguration.
|
||||
|
||||
- **Optimized Figurine Installation**
|
||||
The `install_figurine` function now avoids duplicating `.bashrc` entries if the customization for the root prompt already exists.
|
||||
|
||||
|
||||
### Added
|
||||
|
||||
- **New Function: Persistent Network Interface Naming**
|
||||
Added a new function `setup_persistent_network` to create stable network interface names using `.link` files based on MAC addresses.
|
||||
This avoids unpredictable renaming (e.g., `enp2s0` becoming `enp3s0`) when hardware changes, PCI topology shifts, or passthrough configurations are applied.
|
||||
|
||||
**Why use `.link` files?**
|
||||
Because predictable interface names in `systemd` can change with hardware reordering or replacement. Using static `.link` files bound to MAC addresses ensures consistency, especially on systems with multiple NICs or passthrough setups.
|
||||
|
||||
Special thanks to [@Andres_Eduardo_Rojas_Moya] for contributing the persistent
|
||||
network naming function and for the original idea.
|
||||
|
||||
```bash
|
||||
[Match]
|
||||
MACAddress=XX:XX:XX:XX:XX:XX
|
||||
|
||||
[Link]
|
||||
Name=eth0
|
||||
```
|
||||
|
||||
|
||||
## 2025-07-01
|
||||
|
||||
### New version v1.1.3
|
||||
|
@ -59,7 +59,7 @@ Then, follow the on-screen options to manage your Proxmox server efficiently.
|
||||
|
||||
## 📌 System Requirements
|
||||
🖥 **Compatible with:**
|
||||
- Proxmox VE 8.x**
|
||||
- Proxmox VE 8.x and 9.x
|
||||
|
||||
📦 **Dependencies:**
|
||||
- `bash`, `curl`, `wget`, `jq`, `whiptail`, `python3-venv` (These dependencies are installed automatically during setup.)
|
||||
|
@ -498,6 +498,8 @@ install_translation_version() {
|
||||
show_installation_options() {
|
||||
local current_install_type
|
||||
current_install_type=$(check_existing_installation)
|
||||
local pve_version
|
||||
pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+' | head -1)
|
||||
|
||||
local menu_title="ProxMenux Installation"
|
||||
local menu_text="Choose installation type:"
|
||||
@ -516,10 +518,30 @@ show_installation_options() {
|
||||
esac
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
if [[ "$pve_version" -ge 9 ]]; then
|
||||
INSTALL_TYPE=$(whiptail --backtitle "ProxMenux" --title "$menu_title" --menu "\n$menu_text" 14 70 2 \
|
||||
"1" "Normal Version (English only)" 3>&1 1>&2 2>&3)
|
||||
|
||||
if [ -z "$INSTALL_TYPE" ]; then
|
||||
msg_warn "Installation cancelled."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
INSTALL_TYPE=$(whiptail --backtitle "ProxMenux" --title "$menu_title" --menu "\n$menu_text" 14 70 2 \
|
||||
"1" "Normal Version (English only)" \
|
||||
"2" "Translation Version (Multi-language support)" 3>&1 1>&2 2>&3)
|
||||
|
||||
if [ -z "$INSTALL_TYPE" ]; then
|
||||
msg_warn "Installation cancelled."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
|
||||
if [ -z "$INSTALL_TYPE" ]; then
|
||||
msg_warn "Installation cancelled."
|
||||
exit 1
|
||||
|
659
json/cache.json
659
json/cache.json
@ -1908,6 +1908,663 @@
|
||||
"de": "Automatisiertes Post-Installationsskript",
|
||||
"it": "Script automatico post-installazione",
|
||||
"pt": "Script automatizado pós-instalação"
|
||||
},
|
||||
"Network Management - SAFE MODE": {
|
||||
"es": "Gestión de red - Modo seguro",
|
||||
"fr": "Gestion du réseau - Mode sans risque",
|
||||
"de": "Netzwerkverwaltung - SICHERER MODUS",
|
||||
"it": "Gestione rete - Modalità sicura",
|
||||
"pt": "Gerenciamento de rede - Modo seguro"
|
||||
},
|
||||
"Show Interface Details": {
|
||||
"es": "Mostrar detalles de la interfaz",
|
||||
"fr": "Afficher les détails de l'interface",
|
||||
"de": "Schnittstellendetails anzeigen",
|
||||
"it": "Mostra dettagli dell'interfaccia",
|
||||
"pt": "Mostrar detalhes da interface"
|
||||
},
|
||||
"Show Bridge Status": {
|
||||
"es": "Mostrar estado del puente",
|
||||
"fr": "Afficher l'état du pont",
|
||||
"de": "Bridge-Status anzeigen",
|
||||
"it": "Mostra stato del bridge",
|
||||
"pt": "Mostrar status da ponte"
|
||||
},
|
||||
"Show Routing Table": {
|
||||
"es": "Mostrar tabla de enrutamiento",
|
||||
"fr": "Afficher la table de routage",
|
||||
"de": "Routing-Tabelle anzeigen",
|
||||
"it": "Mostra tabella di routing",
|
||||
"pt": "Mostrar tabela de roteamento"
|
||||
},
|
||||
"Test Connectivity": {
|
||||
"es": "Probar conectividad",
|
||||
"fr": "Tester la connectivité",
|
||||
"de": "Konnektivität testen",
|
||||
"it": "Verifica la connettività",
|
||||
"pt": "Testar conectividade"
|
||||
},
|
||||
"Advanced Diagnostics": {
|
||||
"es": "Diagnóstico avanzado",
|
||||
"fr": "Diagnostic avancé",
|
||||
"de": "Erweiterte Diagnose",
|
||||
"it": "Diagnostica avanzata",
|
||||
"pt": "Diagnóstico avançado"
|
||||
},
|
||||
"Analyze Bridge Configuration": {
|
||||
"es": "Analizar configuración del puente",
|
||||
"fr": "Analyser la configuration du pont",
|
||||
"de": "Bridge-Konfiguration analysieren",
|
||||
"it": "Analizza configurazione bridge",
|
||||
"pt": "Analisar configuração da ponte"
|
||||
},
|
||||
"Analyze Network Configuration": {
|
||||
"es": "Analizar configuración de red",
|
||||
"fr": "Analyser la configuration du réseau",
|
||||
"de": "Netzwerkkonfiguration analysieren",
|
||||
"it": "Analizza configurazione di rete",
|
||||
"pt": "Analisar configuração de rede"
|
||||
},
|
||||
"Restart Network Service": {
|
||||
"es": "Reiniciar servicio de red",
|
||||
"fr": "Redémarrer le service réseau",
|
||||
"de": "Netzwerkdienst neu starten",
|
||||
"it": "Riavvia servizio di rete",
|
||||
"pt": "Reiniciar serviço de rede"
|
||||
},
|
||||
"Show Network Config File": {
|
||||
"es": "Mostrar archivo de configuración de red",
|
||||
"fr": "Afficher le fichier de configuration réseau",
|
||||
"de": "Netzwerkkonfigurationsdatei anzeigen",
|
||||
"it": "Mostra file di configurazione di rete",
|
||||
"pt": "Mostrar arquivo de configuração de rede"
|
||||
},
|
||||
"Create Network Backup": {
|
||||
"es": "Crear copia de seguridad de red",
|
||||
"fr": "Créer une sauvegarde du réseau",
|
||||
"de": "Netzwerk-Backup erstellen",
|
||||
"it": "Crea backup della rete",
|
||||
"pt": "Criar backup de rede"
|
||||
},
|
||||
"Restore Network Backup": {
|
||||
"es": "Restaurar copia de seguridad de red",
|
||||
"fr": "Restaurer la sauvegarde du réseau",
|
||||
"de": "Netzwerk-Backup wiederherstellen",
|
||||
"it": "Ripristina backup della rete",
|
||||
"pt": "Restaurar backup de rede"
|
||||
},
|
||||
"Analyzing Bridge Configuration - READ ONLY MODE": {
|
||||
"es": "Analizando configuración del puente - Solo lectura",
|
||||
"fr": "Analyse de la configuration du pont - Mode lecture seule",
|
||||
"de": "Bridge-Konfiguration analysieren - Nur-Lese-Modus",
|
||||
"it": "Analisi configurazione bridge - Solo lettura",
|
||||
"pt": "Analisando configuração da ponte - Modo somente leitura"
|
||||
},
|
||||
"BRIDGE CONFIGURATION ANALYSIS": {
|
||||
"es": "Análisis de configuración del puente",
|
||||
"fr": "Analyse de la configuration du pont",
|
||||
"de": "Bridge-Konfigurationsanalyse",
|
||||
"it": "Analisi configurazione bridge",
|
||||
"pt": "Análise de configuração da ponte"
|
||||
},
|
||||
"Bridge": {
|
||||
"es": "Puente",
|
||||
"fr": "Pont",
|
||||
"de": "Bridge",
|
||||
"it": "Bridge",
|
||||
"pt": "Ponte"
|
||||
},
|
||||
"Status": {
|
||||
"es": "Estado",
|
||||
"fr": "Statut",
|
||||
"de": "Status",
|
||||
"it": "Stato",
|
||||
"pt": "Status"
|
||||
},
|
||||
"IP": {
|
||||
"es": "IP",
|
||||
"fr": "IP",
|
||||
"de": "IP",
|
||||
"it": "IP",
|
||||
"pt": "IP"
|
||||
},
|
||||
"Configured Ports": {
|
||||
"es": "Puertos configurados",
|
||||
"fr": "Ports configurés",
|
||||
"de": "Konfigurierte Ports",
|
||||
"it": "Porte configurate",
|
||||
"pt": "Portas configuradas"
|
||||
},
|
||||
"Port": {
|
||||
"es": "Puerto",
|
||||
"fr": "Port",
|
||||
"de": "Port",
|
||||
"it": "Porta",
|
||||
"pt": "Porta"
|
||||
},
|
||||
"EXISTS": {
|
||||
"es": "Existe",
|
||||
"fr": "Existe",
|
||||
"de": "Existiert",
|
||||
"it": "Esiste",
|
||||
"pt": "Existe"
|
||||
},
|
||||
"ANALYSIS SUMMARY": {
|
||||
"es": "Resumen del análisis",
|
||||
"fr": "Résumé de l'analyse",
|
||||
"de": "Analyse-Zusammenfassung",
|
||||
"it": "Riepilogo analisi",
|
||||
"pt": "Resumo da análise"
|
||||
},
|
||||
"Bridges analyzed": {
|
||||
"es": "Puentes analizados",
|
||||
"fr": "Ponts analysés",
|
||||
"de": "Analysierte Bridges",
|
||||
"it": "Bridge analizzati",
|
||||
"pt": "Pontes analisadas"
|
||||
},
|
||||
"Issues found": {
|
||||
"es": "Problemas encontrados",
|
||||
"fr": "Problèmes trouvés",
|
||||
"de": "Gefundene Probleme",
|
||||
"it": "Problemi trovati",
|
||||
"pt": "Problemas encontrados"
|
||||
},
|
||||
"Physical interfaces available": {
|
||||
"es": "Interfaces físicas disponibles",
|
||||
"fr": "Interfaces physiques disponibles",
|
||||
"de": "Verfügbare physische Schnittstellen",
|
||||
"it": "Interfacce fisiche disponibili",
|
||||
"pt": "Interfaces físicas disponíveis"
|
||||
},
|
||||
"No bridge configuration issues found": {
|
||||
"es": "No se encontraron problemas en la configuración del puente",
|
||||
"fr": "Aucun problème de configuration du pont trouvé",
|
||||
"de": "Keine Bridge-Konfigurationsprobleme gefunden",
|
||||
"it": "Nessun problema di configurazione del bridge trovato",
|
||||
"pt": "Nenhum problema encontrado na configuração da ponte"
|
||||
},
|
||||
"Bridge Configuration Analysis": {
|
||||
"es": "Análisis de configuración del puente",
|
||||
"fr": "Analyse de la configuration du pont",
|
||||
"de": "Bridge-Konfigurationsanalyse",
|
||||
"it": "Analisi configurazione bridge",
|
||||
"pt": "Análise de configuração da ponte"
|
||||
},
|
||||
"Real-time network usage (iftop)": {
|
||||
"es": "Uso de red en tiempo real (iftop)",
|
||||
"fr": "Utilisation du réseau en temps réel (iftop)",
|
||||
"de": "Echtzeit-Netzwerkauslastung (iftop)",
|
||||
"it": "Utilizzo rete in tempo reale (iftop)",
|
||||
"pt": "Uso de rede em tempo real (iftop)"
|
||||
},
|
||||
"Network monitoring tool (iptraf-ng)": {
|
||||
"es": "Herramienta de monitoreo de red (iptraf-ng)",
|
||||
"fr": "Outil de surveillance réseau (iptraf-ng)",
|
||||
"de": "Netzwerküberwachungstool (iptraf-ng)",
|
||||
"it": "Strumento di monitoraggio rete (iptraf-ng)",
|
||||
"pt": "Ferramenta de monitoramento de rede (iptraf-ng)"
|
||||
},
|
||||
"iftop usage": {
|
||||
"es": "Uso de iftop",
|
||||
"fr": "Utilisation de iftop",
|
||||
"de": "Verwendung von iftop",
|
||||
"it": "Utilizzo di iftop",
|
||||
"pt": "Uso do iftop"
|
||||
},
|
||||
"To exit iftop, press q": {
|
||||
"es": "Para salir de iftop, pulse q",
|
||||
"fr": "Pour quitter iftop, appuyez sur q",
|
||||
"de": "Zum Beenden von iftop, q drücken",
|
||||
"it": "Per uscire da iftop, premi q",
|
||||
"pt": "Para sair do iftop, pressione q"
|
||||
},
|
||||
"iptraf-ng usage": {
|
||||
"es": "Uso de iptraf-ng",
|
||||
"fr": "Utilisation de iptraf-ng",
|
||||
"de": "Verwendung von iptraf-ng",
|
||||
"it": "Utilizzo di iptraf-ng",
|
||||
"pt": "Uso do iptraf-ng"
|
||||
},
|
||||
"To exit iptraf-ng, press x": {
|
||||
"es": "Para salir de iptraf-ng, pulse x",
|
||||
"fr": "Pour quitter iptraf-ng, appuyez sur x",
|
||||
"de": "Zum Beenden von iptraf-ng, x drücken",
|
||||
"it": "Per uscire da iptraf-ng, premi x",
|
||||
"pt": "Para sair do iptraf-ng, pressione x"
|
||||
},
|
||||
"Proxmox VE 8 to 9 Manual Upgrade Guide": {
|
||||
"es": "Guía de actualización manual de Proxmox VE 8 a 9",
|
||||
"fr": "Guide de mise à niveau manuelle de Proxmox VE 8 vers 9",
|
||||
"de": "Manuelles Upgrade-Handbuch: Proxmox VE 8 auf 9",
|
||||
"it": "Guida all'aggiornamento manuale da Proxmox VE 8 a 9",
|
||||
"pt": "Guia de atualização manual do Proxmox VE 8 para 9"
|
||||
},
|
||||
"Source:": {
|
||||
"es": "Fuente:",
|
||||
"fr": "Source :",
|
||||
"de": "Quelle:",
|
||||
"it": "Fonte:",
|
||||
"pt": "Fonte:"
|
||||
},
|
||||
"IMPORTANT PREREQUISITES:": {
|
||||
"es": "REQUISITOS PREVIOS IMPORTANTES:",
|
||||
"fr": "PRÉREQUIS IMPORTANTS :",
|
||||
"de": "WICHTIGE VORAUSSETZUNGEN:",
|
||||
"it": "PREREQUISITI IMPORTANTI:",
|
||||
"pt": "PRÉ-REQUISITOS IMPORTANTES:"
|
||||
},
|
||||
"System must be updated to latest PVE 8.4+ before starting": {
|
||||
"es": "El sistema debe estar actualizado a la versión PVE 8.4+ antes de comenzar",
|
||||
"fr": "Le système doit être mis à jour vers PVE 8.4+ avant de commencer",
|
||||
"de": "Das System muss vor dem Start auf PVE 8.4+ aktualisiert sein",
|
||||
"it": "Il sistema deve essere aggiornato a PVE 8.4+ prima di iniziare",
|
||||
"pt": "O sistema deve estar atualizado para PVE 8.4+ antes de começar"
|
||||
},
|
||||
"Use SSH or terminal access (SSH recommended)": {
|
||||
"es": "Use acceso por SSH o terminal (se recomienda SSH)",
|
||||
"fr": "Utilisez un accès SSH ou terminal (SSH recommandé)",
|
||||
"de": "SSH- oder Terminalzugang verwenden (SSH empfohlen)",
|
||||
"it": "Usa accesso SSH o terminale (consigliato SSH)",
|
||||
"pt": "Use acesso por SSH ou terminal (SSH recomendado)"
|
||||
},
|
||||
"Use tmux or screen to avoid interruptions": {
|
||||
"es": "Use tmux o screen para evitar interrupciones",
|
||||
"fr": "Utilisez tmux ou screen pour éviter les interruptions",
|
||||
"de": "Verwenden Sie tmux oder screen, um Unterbrechungen zu vermeiden",
|
||||
"it": "Usa tmux o screen per evitare interruzioni",
|
||||
"pt": "Use tmux ou screen para evitar interrupções"
|
||||
},
|
||||
"Have valid backups of all VMs and containers": {
|
||||
"es": "Tenga copias de seguridad válidas de todas las VMs y contenedores",
|
||||
"fr": "Ayez des sauvegardes valides de toutes les VM et conteneurs",
|
||||
"de": "Halten Sie gültige Backups aller VMs und Container bereit",
|
||||
"it": "Avere backup validi di tutte le VM e i container",
|
||||
"pt": "Tenha backups válidos de todas as VMs e contêineres"
|
||||
},
|
||||
"At least 5GB free space on root filesystem": {
|
||||
"es": "Al menos 5 GB de espacio libre en el sistema de archivos raíz",
|
||||
"fr": "Au moins 5 Go d’espace libre sur le système de fichiers racine",
|
||||
"de": "Mindestens 5 GB freier Speicherplatz auf dem Root-Dateisystem",
|
||||
"it": "Almeno 5 GB di spazio libero sul filesystem root",
|
||||
"pt": "Pelo menos 5 GB de espaço livre no sistema de arquivos raiz"
|
||||
},
|
||||
"Do not run the upgrade from the Web UI virtual console (it will disconnect)": {
|
||||
"es": "No ejecute la actualización desde la consola virtual de la interfaz web (se desconectará)",
|
||||
"fr": "N’exécutez pas la mise à niveau depuis la console virtuelle de l’interface Web (elle se déconnectera)",
|
||||
"de": "Führen Sie das Upgrade nicht über die virtuelle Konsole der Web-UI aus (die Verbindung wird getrennt)",
|
||||
"it": "Non eseguire l’aggiornamento dalla console virtuale dell’interfaccia Web (si disconnetterà)",
|
||||
"pt": "Não execute a atualização pelo console virtual da interface Web (a conexão será interrompida)"
|
||||
},
|
||||
"Update system to latest PVE 8.4+ (if not done already):": {
|
||||
"es": "Actualizar el sistema a PVE 8.4+ (si aún no se ha hecho):",
|
||||
"fr": "Mettre à jour le système vers PVE 8.4+ (si ce n’est pas déjà fait) :",
|
||||
"de": "System auf PVE 8.4+ aktualisieren (falls noch nicht geschehen):",
|
||||
"it": "Aggiornare il sistema a PVE 8.4+ (se non già fatto):",
|
||||
"pt": "Atualizar o sistema para PVE 8.4+ (se ainda não foi feito):"
|
||||
},
|
||||
"Or use ProxMenux update function": {
|
||||
"es": "O use la función de actualización de ProxMenux",
|
||||
"fr": "Ou utilisez la fonction de mise à jour de ProxMenux",
|
||||
"de": "Oder verwenden Sie die Aktualisierungsfunktion von ProxMenux",
|
||||
"it": "Oppure usa la funzione di aggiornamento di ProxMenux",
|
||||
"pt": "Ou use a função de atualização do ProxMenux"
|
||||
},
|
||||
"Verify PVE version (must be 8.4.1 or newer):": {
|
||||
"es": "Verificar la versión de PVE (debe ser 8.4.1 o superior):",
|
||||
"fr": "Vérifier la version de PVE (doit être 8.4.1 ou plus récente) :",
|
||||
"de": "PVE-Version prüfen (muss 8.4.1 oder neuer sein):",
|
||||
"it": "Verificare la versione di PVE (deve essere 8.4.1 o successiva):",
|
||||
"pt": "Verificar a versão do PVE (deve ser 8.4.1 ou superior):"
|
||||
},
|
||||
"If this node runs hyper-converged Ceph: ensure Ceph is 19.x (Squid) BEFORE upgrading PVE.": {
|
||||
"es": "Si este nodo ejecuta Ceph hiperconvergente: asegúrese de que Ceph sea 19.x (Squid) ANTES de actualizar PVE.",
|
||||
"fr": "Si ce nœud exécute un Ceph hyperconvergé : assurez-vous que Ceph est en 19.x (Squid) AVANT de mettre à niveau PVE.",
|
||||
"de": "Wenn dieser Knoten hyperkonvergentes Ceph betreibt: Stellen Sie sicher, dass Ceph 19.x (Squid) ist, BEVOR Sie PVE aktualisieren.",
|
||||
"it": "Se questo nodo esegue Ceph iperconvergente: assicurarsi che Ceph sia 19.x (Squid) PRIMA di aggiornare PVE.",
|
||||
"pt": "Se este nó executa Ceph hiperconvergente: certifique-se de que o Ceph esteja em 19.x (Squid) ANTES de atualizar o PVE."
|
||||
},
|
||||
"If not 19.x, upgrade Ceph (Reef→Squid) first per the official guide:": {
|
||||
"es": "Si no es 19.x, actualice primero Ceph (Reef→Squid) según la guía oficial:",
|
||||
"fr": "Si ce n’est pas 19.x, mettez d’abord à niveau Ceph (Reef→Squid) selon le guide officiel :",
|
||||
"de": "Wenn nicht 19.x, aktualisieren Sie Ceph zuerst (Reef→Squid) gemäß der offiziellen Anleitung:",
|
||||
"it": "Se non è 19.x, aggiornare prima Ceph (Reef→Squid) secondo la guida ufficiale:",
|
||||
"pt": "Se não for 19.x, atualize primeiro o Ceph (Reef→Squid) conforme o guia oficial:"
|
||||
},
|
||||
"Run upgrade checklist script:": {
|
||||
"es": "Ejecutar el script de la lista de verificación de actualización:",
|
||||
"fr": "Exécuter le script de liste de vérification de mise à niveau :",
|
||||
"de": "Upgrade-Checklisten-Skript ausführen:",
|
||||
"it": "Eseguire lo script della checklist di aggiornamento:",
|
||||
"pt": "Executar o script da lista de verificação de atualização:"
|
||||
},
|
||||
"If it warns about 'systemd-boot' meta-package, remove it:": {
|
||||
"es": "Si advierte sobre el metapaquete 'systemd-boot', elimínelo:",
|
||||
"fr": "S’il signale le méta-paquet « systemd-boot », supprimez-le :",
|
||||
"de": "Wenn vor dem Metapaket „systemd-boot“ gewarnt wird, entfernen Sie es:",
|
||||
"it": "Se avvisa del metapacchetto 'systemd-boot', rimuoverlo:",
|
||||
"pt": "Se alertar sobre o metapacote 'systemd-boot', remova-o:"
|
||||
},
|
||||
"Start terminal multiplexer (recommended):": {
|
||||
"es": "Iniciar un multiplexor de terminal (recomendado):",
|
||||
"fr": "Démarrer un multiplexeur de terminal (recommandé) :",
|
||||
"de": "Terminal-Multiplexer starten (empfohlen):",
|
||||
"it": "Avviare un multiplexer di terminale (consigliato):",
|
||||
"pt": "Iniciar um multiplexador de terminal (recomendado):"
|
||||
},
|
||||
"# Recommended: avoids disconnection during upgrade": {
|
||||
"es": "# Recomendado: evita desconexiones durante la actualización",
|
||||
"fr": "# Recommandé : évite les déconnexions pendant la mise à niveau",
|
||||
"de": "# Empfohlen: vermeidet Verbindungsabbrüche während des Upgrades",
|
||||
"it": "# Consigliato: evita disconnessioni durante l’aggiornamento",
|
||||
"pt": "# Recomendado: evita desconexões durante a atualização"
|
||||
},
|
||||
"# Alternative if you prefer screen": {
|
||||
"es": "# Alternativa si prefiere screen",
|
||||
"fr": "# Alternative si vous préférez screen",
|
||||
"de": "# Alternative, wenn Sie screen bevorzugen",
|
||||
"it": "# Alternativa se preferisci screen",
|
||||
"pt": "# Alternativa se preferir screen"
|
||||
},
|
||||
"Update Debian repositories to Trixie:": {
|
||||
"es": "Actualizar los repositorios de Debian a Trixie:",
|
||||
"fr": "Mettre à jour les dépôts Debian vers Trixie :",
|
||||
"de": "Debian-Repositories auf Trixie aktualisieren:",
|
||||
"it": "Aggiornare i repository Debian a Trixie:",
|
||||
"pt": "Atualizar os repositórios Debian para Trixie:"
|
||||
},
|
||||
"Update PVE enterprise repository (Only if using enterprise):": {
|
||||
"es": "Actualizar el repositorio empresarial de PVE (solo si usa enterprise):",
|
||||
"fr": "Mettre à jour le dépôt entreprise de PVE (uniquement si vous utilisez enterprise) :",
|
||||
"de": "PVE-Enterprise-Repository aktualisieren (nur bei Verwendung von Enterprise):",
|
||||
"it": "Aggiornare il repository enterprise di PVE (solo se si usa enterprise):",
|
||||
"pt": "Atualizar o repositório enterprise do PVE (apenas se usar enterprise):"
|
||||
},
|
||||
"Skip this step if using no-subscription repository": {
|
||||
"es": "Omita este paso si usa el repositorio sin suscripción",
|
||||
"fr": "Ignorez cette étape si vous utilisez le dépôt sans abonnement",
|
||||
"de": "Überspringen Sie diesen Schritt, wenn Sie das No-Subscription-Repository verwenden",
|
||||
"it": "Saltare questo passaggio se si usa il repository senza sottoscrizione",
|
||||
"pt": "Pule esta etapa se usar o repositório sem assinatura"
|
||||
},
|
||||
"Add new PVE 9 enterprise repository (deb822 format) (Only if using enterprise):": {
|
||||
"es": "Agregar el nuevo repositorio empresarial de PVE 9 (formato deb822) (solo si usa enterprise):",
|
||||
"fr": "Ajouter le nouveau dépôt entreprise de PVE 9 (format deb822) (uniquement si vous utilisez enterprise) :",
|
||||
"de": "Neues PVE-9-Enterprise-Repository (deb822-Format) hinzufügen (nur bei Enterprise):",
|
||||
"it": "Aggiungere il nuovo repository enterprise di PVE 9 (formato deb822) (solo se si usa enterprise):",
|
||||
"pt": "Adicionar o novo repositório enterprise do PVE 9 (formato deb822) (apenas se usar enterprise):"
|
||||
},
|
||||
"Only if using enterprise subscription": {
|
||||
"es": "Solo si utiliza suscripción empresarial",
|
||||
"fr": "Uniquement si vous avez un abonnement entreprise",
|
||||
"de": "Nur bei vorhandener Enterprise-Abonnement",
|
||||
"it": "Solo se si dispone di una sottoscrizione enterprise",
|
||||
"pt": "Apenas se você tiver assinatura enterprise"
|
||||
},
|
||||
"OR add new PVE 9 no-subscription repository:": {
|
||||
"es": "O agregar el nuevo repositorio de PVE 9 sin suscripción:",
|
||||
"fr": "OU ajouter le nouveau dépôt PVE 9 sans abonnement :",
|
||||
"de": "ODER das neue PVE-9-No-Subscription-Repository hinzufügen:",
|
||||
"it": "OPPURE aggiungere il nuovo repository PVE 9 senza sottoscrizione:",
|
||||
"pt": "OU adicionar o novo repositório PVE 9 sem assinatura:"
|
||||
},
|
||||
"Only if using no-subscription repository": {
|
||||
"es": "Solo si usa el repositorio sin suscripción",
|
||||
"fr": "Uniquement si vous utilisez le dépôt sans abonnement",
|
||||
"de": "Nur bei Verwendung des No-Subscription-Repository",
|
||||
"it": "Solo se si usa il repository senza sottoscrizione",
|
||||
"pt": "Apenas se usar o repositório sem assinatura"
|
||||
},
|
||||
"Refresh APT index and verify repositories:": {
|
||||
"es": "Actualizar el índice de APT y verificar los repositorios:",
|
||||
"fr": "Actualiser l’index APT et vérifier les dépôts :",
|
||||
"de": "APT-Index aktualisieren und Repositories prüfen:",
|
||||
"it": "Aggiornare l’indice APT e verificare i repository:",
|
||||
"pt": "Atualizar o índice do APT e verificar os repositórios:"
|
||||
},
|
||||
"Ensure there are no errors and that proxmox-ve candidate shows 9.x": {
|
||||
"es": "Asegúrese de que no haya errores y de que el candidato de proxmox-ve sea 9.x",
|
||||
"fr": "Assurez-vous qu’il n’y a aucune erreur et que le candidat proxmox-ve indique 9.x",
|
||||
"de": "Stellen Sie sicher, dass keine Fehler auftreten und der proxmox-ve-Kandidat 9.x anzeigt",
|
||||
"it": "Assicurarsi che non vi siano errori e che il candidato di proxmox-ve sia 9.x",
|
||||
"pt": "Certifique-se de que não há erros e que o candidato proxmox-ve mostre 9.x"
|
||||
},
|
||||
"Update Ceph repository (Only if using Ceph):": {
|
||||
"es": "Actualizar el repositorio de Ceph (solo si usa Ceph):",
|
||||
"fr": "Mettre à jour le dépôt Ceph (uniquement si vous utilisez Ceph) :",
|
||||
"de": "Ceph-Repository aktualisieren (nur bei Verwendung von Ceph):",
|
||||
"it": "Aggiornare il repository di Ceph (solo se si usa Ceph):",
|
||||
"pt": "Atualizar o repositório do Ceph (apenas se usar Ceph):"
|
||||
},
|
||||
"Use enterprise URL if you have subscription.": {
|
||||
"es": "Use la URL enterprise si dispone de suscripción.",
|
||||
"fr": "Utilisez l’URL enterprise si vous avez un abonnement.",
|
||||
"de": "Verwenden Sie die Enterprise-URL, wenn Sie ein Abonnement haben.",
|
||||
"it": "Usa l’URL enterprise se hai una sottoscrizione.",
|
||||
"pt": "Use a URL enterprise se tiver assinatura."
|
||||
},
|
||||
"Remove old repository files:": {
|
||||
"es": "Eliminar los archivos de repositorio antiguos:",
|
||||
"fr": "Supprimer les anciens fichiers de dépôt :",
|
||||
"de": "Alte Repository-Dateien entfernen:",
|
||||
"it": "Rimuovere i vecchi file di repository:",
|
||||
"pt": "Remover arquivos antigos de repositório:"
|
||||
},
|
||||
"Also comment any remaining 'bookworm' entries in *.list if present.": {
|
||||
"es": "Comente también cualquier entrada restante de ‘bookworm’ en *.list si existe.",
|
||||
"fr": "Commentez également toute entrée ‘bookworm’ restante dans *.list si présente.",
|
||||
"de": "Kommentieren Sie außerdem verbleibende ‚bookworm‘-Einträge in *.list, falls vorhanden.",
|
||||
"it": "Commentare anche eventuali voci ‘bookworm’ rimanenti in *.list se presenti.",
|
||||
"pt": "Comente também quaisquer entradas ‘bookworm’ restantes em *.list, se houver."
|
||||
},
|
||||
"Update package index:": {
|
||||
"es": "Actualizar el índice de paquetes:",
|
||||
"fr": "Mettre à jour l’index des paquets :",
|
||||
"de": "Paketindex aktualisieren:",
|
||||
"it": "Aggiornare l’indice dei pacchetti:",
|
||||
"pt": "Atualizar o índice de pacotes:"
|
||||
},
|
||||
"Disable kernel audit messages (optional but recommended):": {
|
||||
"es": "Desactivar los mensajes de auditoría del kernel (opcional pero recomendado):",
|
||||
"fr": "Désactiver les messages d’audit du noyau (optionnel mais recommandé) :",
|
||||
"de": "Kernel-Audit-Meldungen deaktivieren (optional, aber empfohlen):",
|
||||
"it": "Disabilitare i messaggi di audit del kernel (opzionale ma consigliato):",
|
||||
"pt": "Desativar as mensagens de auditoria do kernel (opcional, mas recomendado):"
|
||||
},
|
||||
"Start the main system upgrade:": {
|
||||
"es": "Iniciar la actualización principal del sistema:",
|
||||
"fr": "Démarrer la mise à niveau principale du système :",
|
||||
"de": "Hauptsystem-Upgrade starten:",
|
||||
"it": "Avviare l’aggiornamento principale del sistema:",
|
||||
"pt": "Iniciar a atualização principal do sistema:"
|
||||
},
|
||||
"This will take time. Answer prompts carefully - see notes below.": {
|
||||
"es": "Esto llevará tiempo. Responda a las indicaciones con cuidado (vea las notas a continuación).",
|
||||
"fr": "Cela prendra du temps. Répondez aux invites avec attention (voir les notes ci-dessous).",
|
||||
"de": "Dies wird einige Zeit dauern. Beantworten Sie Rückfragen sorgfältig (siehe Hinweise unten).",
|
||||
"it": "Questo richiederà tempo. Rispondi con attenzione alle richieste (vedi note sotto).",
|
||||
"pt": "Isso levará tempo. Responda às solicitações com atenção (veja as notas abaixo)."
|
||||
},
|
||||
"UPGRADE PROMPTS - RECOMMENDED ANSWERS:": {
|
||||
"es": "INDICACIONES DE ACTUALIZACIÓN - RESPUESTAS RECOMENDADAS:",
|
||||
"fr": "INVITES DE MISE À NIVEAU - RÉPONSES RECOMMANDÉES :",
|
||||
"de": "UPGRADE-AUFFORDERUNGEN – EMPFOHLENE ANTWORTEN:",
|
||||
"it": "PROMPT DI AGGIORNAMENTO - RISPOSTE CONSIGLIATE:",
|
||||
"pt": "PROMPTS DE ATUALIZAÇÃO - RESPOSTAS RECOMENDADAS:"
|
||||
},
|
||||
"Keep current version (N)": {
|
||||
"es": "Mantener la versión actual (N)",
|
||||
"fr": "Conserver la version actuelle (N)",
|
||||
"de": "Aktuelle Version beibehalten (N)",
|
||||
"it": "Mantieni la versione corrente (N)",
|
||||
"pt": "Manter a versão atual (N)"
|
||||
},
|
||||
"Install maintainer's version (Y)": {
|
||||
"es": "Instalar la versión del mantenedor del paquete (Y)",
|
||||
"fr": "Installer la version du mainteneur du paquet (Y)",
|
||||
"de": "Version des Paketbetreuers installieren (Y)",
|
||||
"it": "Installare la versione del maintainer del pacchetto (Y)",
|
||||
"pt": "Instalar a versão do mantenedor do pacote (Y)"
|
||||
},
|
||||
"Keep current version (N) if modified": {
|
||||
"es": "Mantener la versión actual (N) si está modificada",
|
||||
"fr": "Conserver la version actuelle (N) si elle a été modifiée",
|
||||
"de": "Aktuelle Version beibehalten (N), falls angepasst",
|
||||
"it": "Mantieni la versione corrente (N) se modificata",
|
||||
"pt": "Manter a versão atual (N) se estiver modificada"
|
||||
},
|
||||
"Service restarts:": {
|
||||
"es": "Reinicios de servicios:",
|
||||
"fr": "Redémarrages de services :",
|
||||
"de": "Neustarts von Diensten:",
|
||||
"it": "Riavvii dei servizi:",
|
||||
"pt": "Reinicializações de serviços:"
|
||||
},
|
||||
"Use default (Yes)": {
|
||||
"es": "Usar la opción predeterminada (Sí)",
|
||||
"fr": "Utiliser l’option par défaut (Oui)",
|
||||
"de": "Standardoption verwenden (Ja)",
|
||||
"it": "Usare l’opzione predefinita (Sì)",
|
||||
"pt": "Usar a opção padrão (Sim)"
|
||||
},
|
||||
"Press 'q' to exit": {
|
||||
"es": "Presione «q» para salir",
|
||||
"fr": "Appuyez sur « q » pour quitter",
|
||||
"de": "Drücken Sie „q“, um zu beenden",
|
||||
"it": "Premi «q» per uscire",
|
||||
"pt": "Pressione «q» para sair"
|
||||
},
|
||||
"If booting in EFI mode with root on LVM: install GRUB for EFI": {
|
||||
"es": "Si inicia en modo EFI con root en LVM: instale GRUB para EFI",
|
||||
"fr": "Si vous démarrez en mode EFI avec root sur LVM : installez GRUB pour EFI",
|
||||
"de": "Wenn Sie im EFI-Modus mit Root auf LVM booten: GRUB für EFI installieren",
|
||||
"it": "Se l’avvio è in modalità EFI con root su LVM: installare GRUB per EFI",
|
||||
"pt": "Se iniciar em modo EFI com root no LVM: instale o GRUB para EFI"
|
||||
},
|
||||
"Per official known issues; ensures proper boot after upgrade": {
|
||||
"es": "Según las incidencias conocidas oficiales, garantiza un arranque correcto tras la actualización",
|
||||
"fr": "Selon les problèmes connus officiels, cela garantit un démarrage correct après la mise à niveau",
|
||||
"de": "Laut den offiziellen Known Issues sorgt dies für einen ordnungsgemäßen Start nach dem Upgrade",
|
||||
"it": "Secondo le note ufficiali dei problemi noti, garantisce un avvio corretto dopo l’aggiornamento",
|
||||
"pt": "De acordo com os problemas conhecidos oficiais, garante uma inicialização correta após a atualização"
|
||||
},
|
||||
"Run checklist again to verify upgrade:": {
|
||||
"es": "Ejecutar de nuevo la lista de verificación para comprobar la actualización:",
|
||||
"fr": "Relancer la liste de vérification pour valider la mise à niveau :",
|
||||
"de": "Checkliste erneut ausführen, um das Upgrade zu verifizieren:",
|
||||
"it": "Eseguire nuovamente la checklist per verificare l’aggiornamento:",
|
||||
"pt": "Executar novamente a lista de verificação para validar a atualização:"
|
||||
},
|
||||
"Should show fewer or no issues": {
|
||||
"es": "Debería mostrar menos problemas o ninguno",
|
||||
"fr": "Devrait afficher moins de problèmes, voire aucun",
|
||||
"de": "Sollte weniger oder keine Probleme anzeigen",
|
||||
"it": "Dovrebbe mostrare meno problemi o nessuno",
|
||||
"pt": "Deve mostrar menos problemas ou nenhum"
|
||||
},
|
||||
"Reboot the system:": {
|
||||
"es": "Reiniciar el sistema:",
|
||||
"fr": "Redémarrer le système :",
|
||||
"de": "System neu starten:",
|
||||
"it": "Riavviare il sistema:",
|
||||
"pt": "Reiniciar o sistema:"
|
||||
},
|
||||
"After reboot, verify PVE version:": {
|
||||
"es": "Después del reinicio, verificar la versión de PVE:",
|
||||
"fr": "Après le redémarrage, vérifier la version de PVE :",
|
||||
"de": "Nach dem Neustart die PVE-Version prüfen:",
|
||||
"it": "Dopo il riavvio, verificare la versione di PVE:",
|
||||
"pt": "Após reiniciar, verificar a versão do PVE:"
|
||||
},
|
||||
"Should show pve-manager/9.x.x": {
|
||||
"es": "Debería mostrar pve-manager/9.x.x",
|
||||
"fr": "Devrait afficher pve-manager/9.x.x",
|
||||
"de": "Sollte pve-manager/9.x.x anzeigen",
|
||||
"it": "Dovrebbe mostrare pve-manager/9.x.x",
|
||||
"pt": "Deve mostrar pve-manager/9.x.x"
|
||||
},
|
||||
"Optional: Modernize repository sources:": {
|
||||
"es": "Opcional: Modernizar las fuentes de repositorio:",
|
||||
"fr": "Optionnel : Moderniser les sources des dépôts :",
|
||||
"de": "Optional: Repository-Quellen modernisieren:",
|
||||
"it": "Opzionale: Modernizzare le fonti del repository:",
|
||||
"pt": "Opcional: Modernizar as fontes de repositório:"
|
||||
},
|
||||
"Converts to deb822; keeps .list backups as .bak": {
|
||||
"es": "Convierte a deb822; mantiene copias .list como .bak",
|
||||
"fr": "Convertit en deb822 ; conserve les sauvegardes .list en .bak",
|
||||
"de": "Konvertiert zu deb822; behält .list-Backups als .bak bei",
|
||||
"it": "Converte in deb822; mantiene i backup .list come .bak",
|
||||
"pt": "Converte para deb822; mantém backups .list como .bak"
|
||||
},
|
||||
"CLUSTER UPGRADE NOTES:": {
|
||||
"es": "NOTAS DE ACTUALIZACIÓN DEL CLÚSTER:",
|
||||
"fr": "NOTES DE MISE À NIVEAU DU CLUSTER :",
|
||||
"de": "HINWEISE ZUM CLUSTER-UPGRADE:",
|
||||
"it": "NOTE DI AGGIORNAMENTO DEL CLUSTER:",
|
||||
"pt": "NOTAS DE ATUALIZAÇÃO DO CLUSTER:"
|
||||
},
|
||||
"Upgrade one node at a time": {
|
||||
"es": "Actualizar un nodo a la vez",
|
||||
"fr": "Mettre à niveau un nœud à la fois",
|
||||
"de": "Jeweils nur einen Knoten aktualisieren",
|
||||
"it": "Aggiornare un nodo alla volta",
|
||||
"pt": "Atualizar um nó por vez"
|
||||
},
|
||||
"Migrate VMs away from node being upgraded": {
|
||||
"es": "Migrar las VMs fuera del nodo que se está actualizando",
|
||||
"fr": "Migrer les VM hors du nœud en cours de mise à niveau",
|
||||
"de": "VMs vom zu aktualisierenden Knoten weg migrieren",
|
||||
"it": "Migrare le VM dal nodo in aggiornamento",
|
||||
"pt": "Migrar as VMs para fora do nó em atualização"
|
||||
},
|
||||
"Wait for each node to complete before starting next": {
|
||||
"es": "Esperar a que cada nodo termine antes de empezar con el siguiente",
|
||||
"fr": "Attendre que chaque nœud soit terminé avant de commencer le suivant",
|
||||
"de": "Warten, bis jeder Knoten abgeschlossen ist, bevor der nächste beginnt",
|
||||
"it": "Attendere che ogni nodo termini prima di iniziare il successivo",
|
||||
"pt": "Aguardar cada nó concluir antes de iniciar o próximo"
|
||||
},
|
||||
"HA groups will be migrated to HA rules automatically": {
|
||||
"es": "Los grupos de HA se migrarán automáticamente a reglas de HA",
|
||||
"fr": "Les groupes HA seront migrés automatiquement vers des règles HA",
|
||||
"de": "HA-Gruppen werden automatisch in HA-Regeln migriert",
|
||||
"it": "I gruppi HA verranno migrati automaticamente a regole HA",
|
||||
"pt": "Grupos de HA serão migrados automaticamente para regras de HA"
|
||||
},
|
||||
"TROUBLESHOOTING:": {
|
||||
"es": "SOLUCIÓN DE PROBLEMAS:",
|
||||
"fr": "DÉPANNAGE :",
|
||||
"de": "FEHLERBEHEBUNG:",
|
||||
"it": "RISOLUZIONE DEI PROBLEMI:",
|
||||
"pt": "SOLUÇÃO DE PROBLEMAS:"
|
||||
},
|
||||
"If upgrade fails:": {
|
||||
"es": "Si la actualización falla:",
|
||||
"fr": "Si la mise à niveau échoue :",
|
||||
"de": "Wenn das Upgrade fehlschlägt:",
|
||||
"it": "Se l’aggiornamento fallisce:",
|
||||
"pt": "Se a atualização falhar:"
|
||||
},
|
||||
"If repositories error:": {
|
||||
"es": "Si hay errores de repositorios:",
|
||||
"fr": "En cas d’erreurs de dépôts :",
|
||||
"de": "Bei Repository-Fehlern:",
|
||||
"it": "In caso di errori dei repository:",
|
||||
"pt": "Se houver erros nos repositórios:"
|
||||
},
|
||||
"If 'proxmox-ve' removal warning:": {
|
||||
"es": "Si aparece advertencia de eliminación de ‘proxmox-ve’:",
|
||||
"fr": "Si un avertissement de suppression de ‘proxmox-ve’ apparaît :",
|
||||
"de": "Bei Warnung zur Entfernung von ‚proxmox-ve‘:",
|
||||
"it": "Se compare un avviso di rimozione di ‘proxmox-ve’:",
|
||||
"pt": "Se aparecer um aviso de remoção de ‘proxmox-ve’:"
|
||||
},
|
||||
"Emergency recovery:": {
|
||||
"es": "Recuperación de emergencia:",
|
||||
"fr": "Récupération d’urgence :",
|
||||
"de": "Notfallwiederherstellung:",
|
||||
"it": "Ripristino di emergenza:",
|
||||
"pt": "Recuperação de emergência:"
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -413,6 +413,18 @@
|
||||
"password": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Bar-Assistant",
|
||||
"slug": "bar-assistant",
|
||||
"desc": "Bar Assistant is all-in-one solution for managing your home bar. Compared to other recipe management software that usually tries to be more for general use, Bar Assistant is made specifically for managing cocktail recipes. This means that there are a lot of cocktail-oriented features, like ingredient substitutes, first-class ingredients, ABV calculations, unit switching and more..",
|
||||
"script": "ct/bar-assistant.sh",
|
||||
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/bar-assistant.sh",
|
||||
"categories": [
|
||||
24
|
||||
],
|
||||
"notes": [],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
"name": "Barcode Buddy",
|
||||
"slug": "barcode-buddy",
|
||||
@ -549,24 +561,6 @@
|
||||
],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
"name": "Calibre-Web",
|
||||
"slug": "calibre-web",
|
||||
"desc": "Calibre-Web is a web app for browsing, reading and downloading eBooks stored in a Calibre database.",
|
||||
"script": "ct/calibre-web.sh",
|
||||
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/calibre-web.sh",
|
||||
"categories": [
|
||||
11
|
||||
],
|
||||
"notes": [
|
||||
"Add Calibre-Web Extras via `update`"
|
||||
],
|
||||
"type": "ct",
|
||||
"default_credentials": {
|
||||
"username": "admin",
|
||||
"password": "admin123"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "CasaOS",
|
||||
"slug": "casaos",
|
||||
@ -650,6 +644,18 @@
|
||||
],
|
||||
"type": "pve"
|
||||
},
|
||||
{
|
||||
"name": "Cleanuparr",
|
||||
"slug": "cleanuparr",
|
||||
"desc": "Cleanuparr is a tool for automating the cleanup of unwanted or blocked files in Sonarr, Radarr, and supported download clients like qBittorrent, Transmission, and Deluge. It removes incomplete, blocked, or malicious downloads and can trigger replacement searches to ensure your media library stays complete and up-to-date.",
|
||||
"script": "ct/cleanuparr.sh",
|
||||
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/cleanuparr.sh",
|
||||
"categories": [
|
||||
14
|
||||
],
|
||||
"notes": [],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
"name": "Cloudflare-DDNS",
|
||||
"slug": "cloudflare-ddns",
|
||||
@ -679,6 +685,20 @@
|
||||
],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
"name": "Cloudreve",
|
||||
"slug": "cloudreve",
|
||||
"desc": "Cloudreve is an open-source, community-driven cloud storage system that provides file sharing, synchronization, and management features. It supports a wide range of storage backends and integrates with various notification and logging platforms.",
|
||||
"script": "ct/cloudreve.sh",
|
||||
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/cloudreve.sh",
|
||||
"categories": [
|
||||
12
|
||||
],
|
||||
"notes": [
|
||||
"After Installation: Register your user -> Login -> Dashboard -> Accept Primary URL."
|
||||
],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
"name": "Cockpit",
|
||||
"slug": "cockpit",
|
||||
@ -988,7 +1008,7 @@
|
||||
{
|
||||
"name": "Docmost",
|
||||
"slug": "docmost",
|
||||
"desc": "Open-source collaborative wiki and documentation software Create, collaborate, and share knowledge seamlessly with Docmost. Ideal for managing your wiki, knowledge-base, documentation and a lot more.",
|
||||
"desc": "Open-source collaborative wiki and documentation software. Create, collaborate, and share knowledge seamlessly with Docmost. Ideal for managing your wiki, knowledge-base, documentation and a lot more.",
|
||||
"script": "ct/docmost.sh",
|
||||
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/docmost.sh",
|
||||
"categories": [
|
||||
@ -1618,7 +1638,8 @@
|
||||
4
|
||||
],
|
||||
"notes": [
|
||||
"Configuration settings: `/etc/headscale/config.yaml`"
|
||||
"Configuration settings: `/etc/headscale/config.yaml`",
|
||||
"Access headscale-admin UI via `http://<LXC-IP>/admin/`"
|
||||
],
|
||||
"type": "ct"
|
||||
},
|
||||
@ -1675,23 +1696,6 @@
|
||||
"notes": [],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
"name": "Home Assistant Core",
|
||||
"slug": "homeassistant-core",
|
||||
"desc": "A standalone installation of Home Assistant Core refers to a setup where the Home Assistant Core software is installed directly on a device or operating system, without the use of Docker containers. This provides a simpler, but less flexible and scalable solution, as the software is tightly coupled with the underlying system.",
|
||||
"script": "ct/homeassistant-core.sh",
|
||||
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/homeassistant-core.sh",
|
||||
"categories": [
|
||||
16
|
||||
],
|
||||
"notes": [
|
||||
"If the LXC is created Privileged, the script will automatically set up USB passthrough.",
|
||||
"Requires PVE 8.2.2 with kernel 6.8.4-3-pve or newer",
|
||||
"Deprecation-Warning: This Core-based setup will be deprecated by August 2025. Use Home Assistant OS is strongly recommended to ensure long-term stability and updates.",
|
||||
"config path: `/root/.homeassistant`"
|
||||
],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
"name": "Home Assistant Container",
|
||||
"slug": "homeassistant",
|
||||
@ -1718,9 +1722,7 @@
|
||||
"categories": [
|
||||
24
|
||||
],
|
||||
"notes": [
|
||||
".env file location: `/opt/.env`"
|
||||
],
|
||||
"notes": [],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
@ -1768,6 +1770,20 @@
|
||||
],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
"name": "HortusFox",
|
||||
"slug": "hortusfox",
|
||||
"desc": "HortusFox is a collaborative plant management system for plant enthusiasts. Manage, document and track your entire plant collection \u2013 self-hosted and privacy-friendly.",
|
||||
"script": "ct/hortusfox.sh",
|
||||
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/hortusfox.sh",
|
||||
"categories": [
|
||||
24
|
||||
],
|
||||
"notes": [
|
||||
"Login Credentials : `cat ~/hortusfox.creds`"
|
||||
],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
"name": "Proxmox VE Host Backup",
|
||||
"slug": "host-backup",
|
||||
@ -1937,6 +1953,25 @@
|
||||
"notes": [],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
"name": "Jeedom",
|
||||
"slug": "jeedom",
|
||||
"desc": "Jeedom is a home automation system that is free, open, and cloudless. It allows users to manage and automate various aspects of their homes by creating objects, installing plugins for added functionalities, and connecting to a Market account for services. It also supports direct access URLs and user management.",
|
||||
"script": "ct/jeedom.sh",
|
||||
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/jeedom.sh",
|
||||
"categories": [
|
||||
16
|
||||
],
|
||||
"notes": [
|
||||
"WARNING: Installation sources scripts outside of Community Scripts repo. Please check the source before installing.",
|
||||
"Only OS packages are updateable. To update Jeedom, please use the web interface."
|
||||
],
|
||||
"type": "ct",
|
||||
"default_credentials": {
|
||||
"username": "admin",
|
||||
"password": "admin"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Jellyfin Media Server",
|
||||
"slug": "jellyfin",
|
||||
@ -2084,9 +2119,14 @@
|
||||
],
|
||||
"notes": [
|
||||
"First start can take a few minutes",
|
||||
"This script requires some extra steps after the installation, Please checkout the `https://github.com/community-scripts/ProxmoxVE/discussions/193`"
|
||||
"This script requires some extra steps after the installation, Please checkout the `https://github.com/community-scripts/ProxmoxVE/discussions/193`",
|
||||
"When updating, if you had modified cache-ispn.xml: Re-apply your changes to the new file, otherwise leave it unchanged."
|
||||
],
|
||||
"type": "ct"
|
||||
"type": "ct",
|
||||
"default_credentials": {
|
||||
"username": "tmpadm",
|
||||
"password": "admin123"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Kimai",
|
||||
@ -2222,6 +2262,21 @@
|
||||
"notes": [],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
"name": "LinkStack",
|
||||
"slug": "linkstack",
|
||||
"desc": "LinkStack is an open-source, self-hosted alternative to Linktree, allowing users to create a customizable profile page to share multiple links, hosted on their own server.",
|
||||
"script": "ct/linkstack.sh",
|
||||
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/linkstack.sh",
|
||||
"categories": [
|
||||
9
|
||||
],
|
||||
"notes": [
|
||||
"LinkStack can be updated via the user interface.",
|
||||
"Complete setup via the web interface at http://<container-ip>/. Check installation logs: `cat ~/linkstack-install.log`"
|
||||
],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
"name": "Linkwarden",
|
||||
"slug": "linkwarden",
|
||||
@ -2384,6 +2439,18 @@
|
||||
],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
"name": "Mealie",
|
||||
"slug": "mealie",
|
||||
"desc": "Mealie is a self hosted recipe manager, meal planner and shopping list with a RestAPI backend and a reactive frontend built in Vue for a pleasant user experience for the whole family. Easily add recipes into your database by providing the URL and Mealie will automatically import the relevant data, or add a family recipe with the UI editor. Mealie also provides an API for interactions from 3rd party applications.",
|
||||
"script": "ct/mealie.sh",
|
||||
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/mealie.sh",
|
||||
"categories": [
|
||||
13
|
||||
],
|
||||
"notes": [],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
"name": "MediaMTX",
|
||||
"slug": "mediamtx",
|
||||
@ -2653,7 +2720,9 @@
|
||||
"categories": [
|
||||
16
|
||||
],
|
||||
"notes": [],
|
||||
"notes": [
|
||||
"You may need to configure the `WEBHOOK_URL` in the config file when using a domain."
|
||||
],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
@ -2783,7 +2852,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "NIC Offloading Fix",
|
||||
"name": "Intel e1000e NIC Offloading Fix",
|
||||
"slug": "nic-offloading-fix",
|
||||
"desc": "This script automates the process of disabling network interface card (NIC) offloading features specifically for Intel e1000e network interfaces on Linux systems.",
|
||||
"script": "tools/pve/nic-offloading-fix.sh",
|
||||
@ -3048,7 +3117,7 @@
|
||||
"script": "ct/onlyoffice.sh",
|
||||
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/onlyoffice.sh",
|
||||
"categories": [
|
||||
9
|
||||
12
|
||||
],
|
||||
"notes": [
|
||||
"Database / RabbitMQ Credentials: `cat ~/onlyoffice.creds`"
|
||||
@ -3168,23 +3237,18 @@
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
"name": "OPNsense",
|
||||
"slug": "opnsense-vm",
|
||||
"desc": "OPNsense is an open-source firewall and routing platform based on FreeBSD. It provides advanced security features, including intrusion detection, VPN support, traffic shaping, and web filtering, with an intuitive web interface for easy management. Known for its reliability and regular updates, OPNsense is a popular choice for both businesses and home networks.",
|
||||
"script": "vm/opnsense-vm.sh",
|
||||
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/vm/opnsense-vm.sh",
|
||||
"name": "OTS",
|
||||
"slug": "ots",
|
||||
"desc": "One-Time-Secret sharing platform with a symmetric 256bit AES encryption in the browser.",
|
||||
"script": "ct/ots.sh",
|
||||
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/ots.sh",
|
||||
"categories": [
|
||||
4,
|
||||
2
|
||||
6
|
||||
],
|
||||
"notes": [
|
||||
"It will fail with default settings if there is no vmbr0 and vmbr1 on your node. Use advanced settings in this case."
|
||||
"When it is in used external please use it behind reverse proxy or create your own certificates"
|
||||
],
|
||||
"type": "vm",
|
||||
"default_credentials": {
|
||||
"username": "root",
|
||||
"password": "opnsense"
|
||||
}
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
"name": "Outline",
|
||||
@ -3259,6 +3323,22 @@
|
||||
"notes": [],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
"name": "Palmr",
|
||||
"slug": "palmr",
|
||||
"desc": "Palmr is a fast and secure platform for sharing files, built with performance and privacy in mind.",
|
||||
"script": "ct/palmr.sh",
|
||||
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/palmr.sh",
|
||||
"categories": [
|
||||
11
|
||||
],
|
||||
"notes": [
|
||||
"This LXC is very memory-hungry when updating; it requires at least 6GB RAM, but RAM may be reduced to as low as 2GB when running normally",
|
||||
"To use a bind mount for storage, create symlinks to your mount for both `uploads` and `temp-uploads` in `/opt/palmr_data`",
|
||||
"To use Palmr with a reverse proxy, uncomment `SECURE_SITE` in `/opt/palmr/apps/server/.env`"
|
||||
],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
"name": "PaperlessAI",
|
||||
"slug": "paperless-ai",
|
||||
@ -3849,7 +3929,7 @@
|
||||
9
|
||||
],
|
||||
"notes": [
|
||||
"Create Proxmox-API-Token first: `https://github.com/rcourtman/Pulse?tab=readme-ov-file#creating-a-proxmox-api-token`",
|
||||
"Create Proxmox-API-Token first: `https://github.com/rcourtman/Pulse?tab=readme-ov-file#creating-api-token`",
|
||||
"After installation, access the web interface to configure your Proxmox connection details through the built-in setup wizard"
|
||||
],
|
||||
"type": "ct"
|
||||
@ -4057,6 +4137,18 @@
|
||||
"notes": [],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
"name": "Salt",
|
||||
"slug": "salt",
|
||||
"desc": "SaltStack Salt is a software for automating the management and configuration of IT infrastructure and applications. It is an event-driven automation tool and framework used to deploy, configure, and manage complex IT systems. Its primary functions include configuration management, where it ensures consistent configurations and manages operating system deployment and software installation. It also automates and orchestrates routine IT processes and can create self-aware, self-healing systems.",
|
||||
"script": "ct/salt.sh",
|
||||
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/salt.sh",
|
||||
"categories": [
|
||||
19
|
||||
],
|
||||
"notes": [],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
"name": "Proxmox VE CPU Scaling Governor",
|
||||
"slug": "scaling-governor",
|
||||
@ -4071,18 +4163,6 @@
|
||||
],
|
||||
"type": "pve"
|
||||
},
|
||||
{
|
||||
"name": "SearXNG",
|
||||
"slug": "searxng",
|
||||
"desc": "SearXNG is a free internet metasearch engine which aggregates results from up to 215 search services. Users are neither tracked nor profiled. Additionally, SearXNG can be used over Tor for online anonymity.",
|
||||
"script": "ct/searxng.sh",
|
||||
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/searxng.sh",
|
||||
"categories": [
|
||||
0
|
||||
],
|
||||
"notes": [],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
"name": "seelf",
|
||||
"slug": "seelf",
|
||||
@ -4275,6 +4355,20 @@
|
||||
"password": "null"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Suwayomi-Server",
|
||||
"slug": "suwayomi-server",
|
||||
"desc": "A free and open source manga reader server that runs extensions built for Mihon (Tachiyomi).",
|
||||
"script": "ct/suwayomiserver.sh",
|
||||
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/suwayomiserver.sh",
|
||||
"categories": [
|
||||
13
|
||||
],
|
||||
"notes": [
|
||||
"This application can be conflicting with Kaspersky products. You maybe need to disable Kaspersky in order to use this application."
|
||||
],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
"name": "Syncthing",
|
||||
"slug": "syncthing",
|
||||
@ -4349,6 +4443,21 @@
|
||||
],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
"name": "Teamspeak-Server",
|
||||
"slug": "teamspeak-server",
|
||||
"desc": "TeamSpeak is a voice over IP (VoIP) application, primarily used by gamers and teams to chat in real time on dedicated servers. It delivers crystal\u2011clear, low\u2011latency voice communication.",
|
||||
"script": "ct/teamspeak-server.sh",
|
||||
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/teamspeak-server.sh",
|
||||
"categories": [
|
||||
24
|
||||
],
|
||||
"notes": [
|
||||
"Use `journalctl -u teamspeak-server.service` inside Debian LXC console to check for admin credentials!",
|
||||
"Use `cat /var/log/teamspeak.err.log` inside Alpine LXC console to check for admin credentials!"
|
||||
],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
"name": "Technitium DNS",
|
||||
"slug": "technitiumdns",
|
||||
@ -4470,6 +4579,21 @@
|
||||
"notes": [],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
"name": "Tududi",
|
||||
"slug": "tududi",
|
||||
"desc": "Self-hosted task management with functional programming architecture, hierarchical organization, and multi-language support.",
|
||||
"script": "ct/tududi.sh",
|
||||
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/tududi.sh",
|
||||
"categories": [
|
||||
12
|
||||
],
|
||||
"notes": [
|
||||
"Create users like this: `cd /opt/tududi` => `npm run user:create <email> <password>`",
|
||||
"Database location: `/opt/tududi-db`. Uploads: `/opt/tududi-uploads`"
|
||||
],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
"name": "TurnKey",
|
||||
"slug": "turnkey",
|
||||
@ -4539,20 +4663,6 @@
|
||||
],
|
||||
"type": "vm"
|
||||
},
|
||||
{
|
||||
"name": "Ubuntu 24.10",
|
||||
"slug": "ubuntu2410-vm",
|
||||
"desc": "Ubuntu is a distribution based on Debian, designed to have regular releases and a consistent user experience.",
|
||||
"script": "vm/ubuntu2410-vm.sh",
|
||||
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/vm/ubuntu2410-vm.sh",
|
||||
"categories": [
|
||||
2
|
||||
],
|
||||
"notes": [
|
||||
"after installation, checkout: \u00b4https://github.com/community-scripts/ProxmoxVE/discussions/272\u00b4"
|
||||
],
|
||||
"type": "vm"
|
||||
},
|
||||
{
|
||||
"name": "Ubuntu 25.04",
|
||||
"slug": "ubuntu2504-vm",
|
||||
@ -4733,7 +4843,9 @@
|
||||
"categories": [
|
||||
8
|
||||
],
|
||||
"notes": [],
|
||||
"notes": [
|
||||
"Included option to install VictoriaLogs."
|
||||
],
|
||||
"type": "ct"
|
||||
},
|
||||
{
|
||||
|
@ -31,7 +31,7 @@ if [[ -f "$UTILS_FILE" ]]; then
|
||||
fi
|
||||
load_language
|
||||
initialize_cache
|
||||
show_proxmenux_logo
|
||||
|
||||
# ==========================================================
|
||||
|
||||
|
||||
|
335
scripts/global/common-functions.sh
Normal file
335
scripts/global/common-functions.sh
Normal file
@ -0,0 +1,335 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# Common Functions for Proxmox VE Scripts
|
||||
# ==========================================================
|
||||
|
||||
# Configuration
|
||||
REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
|
||||
BASE_DIR="/usr/local/share/proxmenux"
|
||||
UTILS_FILE="$BASE_DIR/utils.sh"
|
||||
VENV_PATH="/opt/googletrans-env"
|
||||
TOOLS_JSON="/usr/local/share/proxmenux/installed_tools.json"
|
||||
|
||||
if [[ -f "$UTILS_FILE" ]]; then
|
||||
source "$UTILS_FILE"
|
||||
fi
|
||||
|
||||
load_language
|
||||
initialize_cache
|
||||
|
||||
|
||||
get_pve_info() {
|
||||
local pve_full_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+\.[0-9]+\.[0-9]+' | head -1)
|
||||
local pve_major=$(echo "$pve_full_version" | cut -d. -f1)
|
||||
local os_codename="$(grep "VERSION_CODENAME=" /etc/os-release | cut -d"=" -f 2 | xargs)"
|
||||
|
||||
if [ -z "$os_codename" ]; then
|
||||
os_codename=$(lsb_release -cs 2>/dev/null)
|
||||
fi
|
||||
|
||||
|
||||
local target_codename
|
||||
if [ "$pve_major" -ge 9 ] 2>/dev/null; then
|
||||
target_codename="trixie"
|
||||
else
|
||||
target_codename="$os_codename"
|
||||
if [ -z "$target_codename" ]; then
|
||||
target_codename="bookworm"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "$pve_full_version|$pve_major|$os_codename|$target_codename"
|
||||
}
|
||||
|
||||
|
||||
lvm_repair_check() {
|
||||
msg_info "$(translate "Checking and repairing old LVM PV headers (if needed)...")"
|
||||
|
||||
if ! command -v pvs >/dev/null 2>&1; then
|
||||
msg_info "$(translate "LVM tools not available, skipping LVM check")"
|
||||
return
|
||||
fi
|
||||
|
||||
pvs_output=$(LC_ALL=C pvs -v 2>&1 | grep "old PV header" || true)
|
||||
if [ -z "$pvs_output" ]; then
|
||||
msg_ok "$(translate "No PVs with old headers found.")"
|
||||
return
|
||||
fi
|
||||
|
||||
declare -A vg_map
|
||||
while read -r line; do
|
||||
pv=$(echo "$line" | grep -o '/dev/[^ ]*' || true)
|
||||
if [ -n "$pv" ]; then
|
||||
vg=$(pvs -o vg_name --noheadings "$pv" 2>/dev/null | awk '{print $1}' || true)
|
||||
if [ -n "$vg" ]; then
|
||||
vg_map["$vg"]=1
|
||||
fi
|
||||
fi
|
||||
done <<< "$pvs_output"
|
||||
|
||||
for vg in "${!vg_map[@]}"; do
|
||||
msg_warn "$(translate "Old PV header(s) found in VG $vg. Updating metadata...")"
|
||||
vgck --updatemetadata "$vg" 2>/dev/null
|
||||
vgchange -ay "$vg" 2>/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
msg_warn "$(translate "Metadata update failed for VG $vg. Review manually.")"
|
||||
else
|
||||
msg_ok "$(translate "Metadata updated successfully for VG $vg")"
|
||||
fi
|
||||
done
|
||||
|
||||
msg_ok "$(translate "LVM PV headers check completed")"
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
cleanup_duplicate_repos_pve9() {
|
||||
msg_info "$(translate "Cleaning up duplicate repositories...")"
|
||||
|
||||
local sources_file="/etc/apt/sources.list"
|
||||
local temp_file=$(mktemp)
|
||||
local cleaned_count=0
|
||||
declare -A seen_repos
|
||||
|
||||
|
||||
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||
if [[ "$line" =~ ^[[:space:]]*# ]] || [[ -z "$line" ]]; then
|
||||
echo "$line" >> "$temp_file"
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$line" =~ ^deb ]]; then
|
||||
read -r _ url dist components <<< "$line"
|
||||
local key="${url}_${dist}"
|
||||
if [[ -v "seen_repos[$key]" ]]; then
|
||||
echo "# $line" >> "$temp_file"
|
||||
cleaned_count=$((cleaned_count + 1))
|
||||
msg_info "$(translate "Commented duplicate: $url $dist")"
|
||||
else
|
||||
echo "$line" >> "$temp_file"
|
||||
seen_repos[$key]="$components"
|
||||
fi
|
||||
else
|
||||
echo "$line" >> "$temp_file"
|
||||
fi
|
||||
done < "$sources_file"
|
||||
|
||||
mv "$temp_file" "$sources_file"
|
||||
chmod 644 "$sources_file"
|
||||
|
||||
|
||||
if [ -f "/etc/apt/sources.list.d/proxmox.sources" ]; then
|
||||
|
||||
|
||||
|
||||
if grep -q "^deb.*download\.proxmox\.com" "$sources_file"; then
|
||||
sed -i '/^deb.*download\.proxmox\.com/s/^/# /' "$sources_file"
|
||||
cleaned_count=$((cleaned_count + 1))
|
||||
fi
|
||||
|
||||
for list_file in /etc/apt/sources.list.d/pve-*.list; do
|
||||
if [ -f "$list_file" ] && [[ "$list_file" != "/etc/apt/sources.list.d/pve-enterprise.list" ]]; then
|
||||
if grep -q "^deb" "$list_file"; then
|
||||
sed -i 's/^deb/# deb/g' "$list_file"
|
||||
cleaned_count=$((cleaned_count + 1))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -f "/etc/apt/sources.list.d/debian.sources" ]; then
|
||||
|
||||
if grep -q "^deb.*deb\.debian\.org" "$sources_file"; then
|
||||
sed -i '/^deb.*deb\.debian\.org/s/^/# /' "$sources_file"
|
||||
cleaned_count=$((cleaned_count + 1))
|
||||
|
||||
fi
|
||||
|
||||
if grep -q "^deb.*security\.debian\.org" "$sources_file"; then
|
||||
sed -i '/^deb.*security\.debian\.org/s/^/# /' "$sources_file"
|
||||
cleaned_count=$((cleaned_count + 1))
|
||||
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
if [ -f "/etc/apt/sources.list.d/proxmox.sources" ]; then
|
||||
for old_file in /etc/apt/sources.list.d/pve-public-repo.list /etc/apt/sources.list.d/pve-install-repo.list; do
|
||||
if [ -f "$old_file" ]; then
|
||||
rm -f "$old_file"
|
||||
cleaned_count=$((cleaned_count + 1))
|
||||
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ $cleaned_count -gt 0 ]; then
|
||||
msg_ok "$(translate "Cleaned up $cleaned_count duplicate/old repositories")"
|
||||
apt-get update > /dev/null 2>&1 || true
|
||||
else
|
||||
msg_ok "$(translate "No duplicate repositories found")"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
|
||||
cleanup_duplicate_repos_pve9_() {
|
||||
msg_info "$(translate "Cleaning up duplicate repositories...")"
|
||||
|
||||
local sources_file="/etc/apt/sources.list"
|
||||
local temp_file=$(mktemp)
|
||||
local cleaned_count=0
|
||||
declare -A seen_repos
|
||||
|
||||
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||
if [[ "$line" =~ ^[[:space:]]*# ]] || [[ -z "$line" ]]; then
|
||||
echo "$line" >> "$temp_file"
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$line" =~ ^deb ]]; then
|
||||
read -r _ url dist components <<< "$line"
|
||||
local key="${url}_${dist}"
|
||||
if [[ -v "seen_repos[$key]" ]]; then
|
||||
echo "# $line" >> "$temp_file"
|
||||
cleaned_count=$((cleaned_count + 1))
|
||||
else
|
||||
echo "$line" >> "$temp_file"
|
||||
seen_repos[$key]="$components"
|
||||
fi
|
||||
else
|
||||
echo "$line" >> "$temp_file"
|
||||
fi
|
||||
done < "$sources_file"
|
||||
|
||||
mv "$temp_file" "$sources_file"
|
||||
chmod 644 "$sources_file"
|
||||
|
||||
for src in proxmox debian ceph; do
|
||||
local sources_path="/etc/apt/sources.list.d/${src}.sources"
|
||||
if [ -f "$sources_path" ]; then
|
||||
case "$src" in
|
||||
proxmox)
|
||||
url_match="download.proxmox.com"
|
||||
;;
|
||||
debian)
|
||||
url_match="deb.debian.org"
|
||||
;;
|
||||
ceph)
|
||||
url_match="download.proxmox.com/ceph"
|
||||
;;
|
||||
*)
|
||||
url_match=""
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ -n "$url_match" ]]; then
|
||||
if grep -q "^deb.*$url_match" "$sources_file"; then
|
||||
sed -i "/^deb.*$url_match/s/^/# /" "$sources_file"
|
||||
cleaned_count=$((cleaned_count + 1))
|
||||
fi
|
||||
fi
|
||||
|
||||
for list_file in /etc/apt/sources.list.d/*.list; do
|
||||
[[ -f "$list_file" ]] || continue
|
||||
if grep -q "^deb.*$url_match" "$list_file"; then
|
||||
sed -i "/^deb.*$url_match/s/^/# /" "$list_file"
|
||||
cleaned_count=$((cleaned_count + 1))
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $cleaned_count -gt 0 ]; then
|
||||
msg_ok "$(translate "Cleaned up $cleaned_count duplicate/old repositories")"
|
||||
apt-get update > /dev/null 2>&1 || true
|
||||
else
|
||||
msg_ok "$(translate "No duplicate repositories found")"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cleanup_duplicate_repos_pve8() {
|
||||
msg_info "$(translate "Cleaning up duplicate repositories...")"
|
||||
|
||||
local cleaned_count=0
|
||||
local sources_file="/etc/apt/sources.list"
|
||||
|
||||
|
||||
if [[ -f "$sources_file" ]]; then
|
||||
local temp_file
|
||||
temp_file=$(mktemp)
|
||||
declare -A seen_repos
|
||||
|
||||
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||
if [[ "$line" =~ ^[[:space:]]*# ]] || [[ -z "$line" ]]; then
|
||||
echo "$line" >> "$temp_file"
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$line" =~ ^[[:space:]]*deb ]]; then
|
||||
read -r _ url dist components <<< "$line"
|
||||
local key="${url}_${dist}"
|
||||
if [[ -v "seen_repos[$key]" ]]; then
|
||||
echo "# $line" >> "$temp_file"
|
||||
cleaned_count=$((cleaned_count + 1))
|
||||
else
|
||||
echo "$line" >> "$temp_file"
|
||||
seen_repos[$key]="$components"
|
||||
fi
|
||||
else
|
||||
echo "$line" >> "$temp_file"
|
||||
fi
|
||||
done < "$sources_file"
|
||||
|
||||
mv "$temp_file" "$sources_file"
|
||||
chmod 644 "$sources_file"
|
||||
fi
|
||||
|
||||
|
||||
local old_pve_files=(/etc/apt/sources.list.d/pve-*.list /etc/apt/sources.list.d/proxmox.list)
|
||||
|
||||
for file in "${old_pve_files[@]}"; do
|
||||
if [[ -f "$file" ]]; then
|
||||
local base_name
|
||||
base_name=$(basename "$file" .list)
|
||||
local sources_equiv="/etc/apt/sources.list.d/${base_name}.sources"
|
||||
|
||||
if [[ -f "$sources_equiv" ]] && grep -q "^Enabled: *true" "$sources_equiv"; then
|
||||
msg_info "$(translate "Removing old repository file: $(basename "$file")")"
|
||||
rm -f "$file"
|
||||
cleaned_count=$((cleaned_count + 1))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
if [ "$cleaned_count" -gt 0 ]; then
|
||||
msg_ok "$(translate "Cleaned up $cleaned_count duplicate/old repositories")"
|
||||
apt-get update > /dev/null 2>&1 || true
|
||||
else
|
||||
msg_ok "$(translate "No duplicate repositories found")"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
|
||||
cleanup_duplicate_repos() {
|
||||
local pve_version
|
||||
pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+' | head -1)
|
||||
|
||||
if [[ -z "$pve_version" ]]; then
|
||||
msg_error "Unable to detect Proxmox version."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ "$pve_version" -ge 9 ]]; then
|
||||
cleanup_duplicate_repos_pve9
|
||||
else
|
||||
cleanup_duplicate_repos_pve8
|
||||
fi
|
||||
}
|
76
scripts/global/remove-banner-pve8.sh
Normal file
76
scripts/global/remove-banner-pve8.sh
Normal file
@ -0,0 +1,76 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# Remove Subscription Banner - Proxmox VE 8.4.9
|
||||
# ==========================================================
|
||||
REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
|
||||
BASE_DIR="/usr/local/share/proxmenux"
|
||||
UTILS_FILE="$BASE_DIR/utils.sh"
|
||||
VENV_PATH="/opt/googletrans-env"
|
||||
TOOLS_JSON="/usr/local/share/proxmenux/installed_tools.json"
|
||||
|
||||
if [[ -f "$UTILS_FILE" ]]; then
|
||||
source "$UTILS_FILE"
|
||||
fi
|
||||
|
||||
load_language
|
||||
initialize_cache
|
||||
|
||||
|
||||
ensure_tools_json() {
|
||||
[ -f "$TOOLS_JSON" ] || echo "{}" > "$TOOLS_JSON"
|
||||
}
|
||||
|
||||
register_tool() {
|
||||
local tool="$1"
|
||||
local state="$2"
|
||||
ensure_tools_json
|
||||
jq --arg t "$tool" --argjson v "$state" '.[$t]=$v' "$TOOLS_JSON" > "$TOOLS_JSON.tmp" && mv "$TOOLS_JSON.tmp" "$TOOLS_JSON"
|
||||
}
|
||||
|
||||
remove_subscription_banner_pve8() {
|
||||
local JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js"
|
||||
local GZ_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.gz"
|
||||
local APT_HOOK="/etc/apt/apt.conf.d/no-nag-script"
|
||||
local BACKUP_FILE="${JS_FILE}.bak.$(date +%F_%T)"
|
||||
|
||||
local pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+\.[0-9]+' | head -1)
|
||||
local pve_major=$(echo "$pve_version" | cut -d. -f1)
|
||||
|
||||
if [[ "$pve_major" -ne 8 ]]; then
|
||||
msg_error "This script is only for Proxmox VE 8.x. Detected: $pve_version"
|
||||
return 1
|
||||
fi
|
||||
|
||||
msg_info "Detected Proxmox VE $pve_version - Applying safe JS patch..."
|
||||
|
||||
if [[ ! -f "$JS_FILE" ]]; then
|
||||
msg_error "JavaScript file not found: $JS_FILE"
|
||||
return 1
|
||||
fi
|
||||
|
||||
cp "$JS_FILE" "$BACKUP_FILE"
|
||||
|
||||
|
||||
sed -i "s/No valid subscription/Subscription active/g" "$JS_FILE"
|
||||
sed -i "s/Ext.Msg.WARNING/Ext.Msg.INFO/g" "$JS_FILE"
|
||||
sed -i "s/res.data.status.toLowerCase() !== 'active'/false/g" "$JS_FILE"
|
||||
sed -i "s/subscriptionActive: ''/subscriptionActive: true/g" "$JS_FILE"
|
||||
|
||||
[[ -f "$GZ_FILE" ]] && rm -f "$GZ_FILE"
|
||||
|
||||
find /var/cache/pve-manager/ -name "*.js*" -delete 2>/dev/null || true
|
||||
find /var/lib/pve-manager/ -name "*.js*" -delete 2>/dev/null || true
|
||||
|
||||
[[ -f "$APT_HOOK" ]] && rm -f "$APT_HOOK"
|
||||
|
||||
|
||||
msg_ok "Subscription banner removed successfully."
|
||||
|
||||
register_tool "subscription_banner" true
|
||||
}
|
||||
|
||||
|
||||
|
||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||||
remove_subscription_banner_pve8
|
||||
fi
|
119
scripts/global/remove-banner-pve9.sh
Normal file
119
scripts/global/remove-banner-pve9.sh
Normal file
@ -0,0 +1,119 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# Remove Subscription Banner - Proxmox VE 9.x ONLY
|
||||
# ==========================================================
|
||||
REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
|
||||
BASE_DIR="/usr/local/share/proxmenux"
|
||||
UTILS_FILE="$BASE_DIR/utils.sh"
|
||||
VENV_PATH="/opt/googletrans-env"
|
||||
TOOLS_JSON="/usr/local/share/proxmenux/installed_tools.json"
|
||||
|
||||
if [[ -f "$UTILS_FILE" ]]; then
|
||||
source "$UTILS_FILE"
|
||||
fi
|
||||
|
||||
load_language
|
||||
initialize_cache
|
||||
|
||||
# Tool registration system
|
||||
ensure_tools_json() {
|
||||
[ -f "$TOOLS_JSON" ] || echo "{}" > "$TOOLS_JSON"
|
||||
}
|
||||
|
||||
register_tool() {
|
||||
local tool="$1"
|
||||
local state="$2"
|
||||
ensure_tools_json
|
||||
jq --arg t "$tool" --argjson v "$state" '.[$t]=$v' "$TOOLS_JSON" > "$TOOLS_JSON.tmp" && mv "$TOOLS_JSON.tmp" "$TOOLS_JSON"
|
||||
}
|
||||
|
||||
remove_subscription_banner_pve9() {
|
||||
local JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js"
|
||||
local MIN_JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.min.js"
|
||||
local GZ_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.gz"
|
||||
local APT_HOOK="/etc/apt/apt.conf.d/no-nag-script"
|
||||
|
||||
# Verify PVE 9.x
|
||||
local pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+\.[0-9]+' | head -1)
|
||||
local pve_major=$(echo "$pve_version" | cut -d. -f1)
|
||||
|
||||
if [ "$pve_major" -lt 9 ] 2>/dev/null; then
|
||||
msg_error "This script is for PVE 9.x only. Detected PVE $pve_version"
|
||||
return 1
|
||||
fi
|
||||
|
||||
msg_info "Detected Proxmox VE $pve_version - Applying PVE 9.x patches"
|
||||
|
||||
# Verify that the file exists
|
||||
if [ ! -f "$JS_FILE" ]; then
|
||||
msg_error "JavaScript file not found: $JS_FILE"
|
||||
return 1
|
||||
fi
|
||||
|
||||
|
||||
# Create backup of original file
|
||||
local backup_file="${JS_FILE}.backup.pve9.$(date +%Y%m%d_%H%M%S)"
|
||||
cp "$JS_FILE" "$backup_file"
|
||||
|
||||
# Clean any existing problematic APT hooks
|
||||
for f in /etc/apt/apt.conf.d/*nag*; do
|
||||
[[ -e "$f" ]] && rm -f "$f"
|
||||
done
|
||||
|
||||
|
||||
# Main subscription check patches for PVE 9
|
||||
sed -i "s/res\.data\.status\.toLowerCase() !== 'active'/false/g" "$JS_FILE"
|
||||
sed -i "s/subscriptionActive: ''/subscriptionActive: true/g" "$JS_FILE"
|
||||
sed -i "s/title: gettext('No valid subscription')/title: gettext('Community Edition')/g" "$JS_FILE"
|
||||
|
||||
# Additional UX improvements for PVE 9
|
||||
sed -i "s/You do not have a valid subscription for this server/Community Edition - No subscription required/g" "$JS_FILE"
|
||||
sed -i "s/Enterprise repository needs valid subscription/Enterprise repository configured/g" "$JS_FILE"
|
||||
sed -i "s/icon: Ext\.Msg\.WARNING/icon: Ext.Msg.INFO/g" "$JS_FILE"
|
||||
|
||||
# Additional subscription patterns that may exist in PVE 9
|
||||
sed -i "s/subscription = !(/subscription = false \&\& (/g" "$JS_FILE"
|
||||
|
||||
# Remove compressed/minified files to force regeneration
|
||||
[[ -f "$GZ_FILE" ]] && rm -f "$GZ_FILE"
|
||||
[[ -f "$MIN_JS_FILE" ]] && rm -f "$MIN_JS_FILE"
|
||||
|
||||
# Clear various caches
|
||||
find /var/cache/pve-manager/ -name "*.js*" -delete 2>/dev/null || true
|
||||
find /var/lib/pve-manager/ -name "*.js*" -delete 2>/dev/null || true
|
||||
|
||||
# Create PVE 9.x specific APT hook
|
||||
[[ -f "$APT_HOOK" ]] && rm -f "$APT_HOOK"
|
||||
cat > "$APT_HOOK" << 'EOF'
|
||||
DPkg::Post-Invoke {
|
||||
"test -e /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js && sed -i 's/res\\.data\\.status\\.toLowerCase() !== '\''active'\''/false/g' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js || true";
|
||||
"test -e /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js && sed -i 's/subscriptionActive: '\'\'\''/subscriptionActive: true/g' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js || true";
|
||||
"test -e /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js && sed -i 's/title: gettext('\''No valid subscription'\'')/title: gettext('\''Community Edition'\'')/g' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js || true";
|
||||
"test -e /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js && sed -i 's/subscription = !(/subscription = false \\&\\& (/g' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js || true";
|
||||
"rm -f /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.min.js /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.gz || true";
|
||||
};
|
||||
EOF
|
||||
|
||||
chmod 644 "$APT_HOOK"
|
||||
|
||||
# Verify APT hook syntax
|
||||
if ! apt-config dump >/dev/null 2>&1; then
|
||||
msg_warn "APT hook has syntax issues, removing..."
|
||||
rm -f "$APT_HOOK"
|
||||
else
|
||||
msg_ok "APT hook created successfully"
|
||||
fi
|
||||
|
||||
|
||||
msg_ok "Subscription banner removed successfully for Proxmox VE $pve_version"
|
||||
msg_ok "Banner removal process completed"
|
||||
|
||||
|
||||
register_tool "subscription_banner" true
|
||||
}
|
||||
|
||||
|
||||
# Execute function if called directly
|
||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||||
remove_subscription_banner_pve9
|
||||
fi
|
337
scripts/global/update-pve.sh
Normal file
337
scripts/global/update-pve.sh
Normal file
@ -0,0 +1,337 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# Proxmox VE Update Script
|
||||
# ==========================================================
|
||||
|
||||
# Configuration
|
||||
REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
|
||||
BASE_DIR="/usr/local/share/proxmenux"
|
||||
UTILS_FILE="$BASE_DIR/utils.sh"
|
||||
VENV_PATH="/opt/googletrans-env"
|
||||
TOOLS_JSON="/usr/local/share/proxmenux/installed_tools.json"
|
||||
|
||||
if [[ -f "$UTILS_FILE" ]]; then
|
||||
source "$UTILS_FILE"
|
||||
fi
|
||||
|
||||
load_language
|
||||
initialize_cache
|
||||
|
||||
ensure_tools_json() {
|
||||
[ -f "$TOOLS_JSON" ] || echo "{}" > "$TOOLS_JSON"
|
||||
}
|
||||
|
||||
register_tool() {
|
||||
local tool="$1"
|
||||
local state="$2"
|
||||
ensure_tools_json
|
||||
jq --arg t "$tool" --argjson v "$state" '.[$t]=$v' "$TOOLS_JSON" > "$TOOLS_JSON.tmp" && mv "$TOOLS_JSON.tmp" "$TOOLS_JSON"
|
||||
}
|
||||
|
||||
download_common_functions() {
|
||||
if ! source <(curl -s "$REPO_URL/scripts/global/common-functions.sh"); then
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
update_pve9() {
|
||||
local start_time=$(date +%s)
|
||||
local log_file="/var/log/proxmox-update-$(date +%Y%m%d-%H%M%S).log"
|
||||
local changes_made=false
|
||||
local OS_CODENAME="$(grep "VERSION_CODENAME=" /etc/os-release | cut -d"=" -f 2 | xargs)"
|
||||
local TARGET_CODENAME="trixie"
|
||||
|
||||
if [ -z "$OS_CODENAME" ]; then
|
||||
OS_CODENAME=$(lsb_release -cs 2>/dev/null || echo "trixie")
|
||||
fi
|
||||
|
||||
download_common_functions
|
||||
|
||||
|
||||
msg_info2 "$(translate "Detected: Proxmox VE 9.x (Current: $OS_CODENAME, Target: $TARGET_CODENAME)")"
|
||||
echo
|
||||
|
||||
local available_space=$(df /var/cache/apt/archives | awk 'NR==2 {print int($4/1024)}')
|
||||
if [ "$available_space" -lt 1024 ]; then
|
||||
msg_error "$(translate "Insufficient disk space. Available: ${available_space}MB")"
|
||||
echo -e
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! ping -c 1 download.proxmox.com >/dev/null 2>&1; then
|
||||
msg_error "$(translate "Cannot reach Proxmox repositories")"
|
||||
echo -e
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
return 1
|
||||
fi
|
||||
|
||||
|
||||
disable_sources_repo() {
|
||||
local file="$1"
|
||||
if [[ -f "$file" ]]; then
|
||||
sed -i ':a;/^\n*$/{$d;N;ba}' "$file"
|
||||
|
||||
if grep -q "^Enabled:" "$file"; then
|
||||
sed -i 's/^Enabled:.*$/Enabled: false/' "$file"
|
||||
else
|
||||
echo "Enabled: false" >> "$file"
|
||||
fi
|
||||
|
||||
if ! grep -q "^Types: " "$file"; then
|
||||
msg_warn "$(translate "Malformed .sources file detected, removing: $(basename "$file")")"
|
||||
rm -f "$file"
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if disable_sources_repo "/etc/apt/sources.list.d/pve-enterprise.sources"; then
|
||||
msg_ok "$(translate "Enterprise Proxmox repository disabled")"
|
||||
changes_made=true
|
||||
fi
|
||||
|
||||
if disable_sources_repo "/etc/apt/sources.list.d/ceph.sources"; then
|
||||
msg_ok "$(translate "Enterprise Proxmox Ceph repository disabled")"
|
||||
changes_made=true
|
||||
fi
|
||||
|
||||
for legacy_file in /etc/apt/sources.list.d/pve-public-repo.list \
|
||||
/etc/apt/sources.list.d/pve-install-repo.list \
|
||||
/etc/apt/sources.list.d/debian.list; do
|
||||
if [[ -f "$legacy_file" ]]; then
|
||||
rm -f "$legacy_file"
|
||||
msg_ok "$(translate "Removed legacy repository: $(basename "$legacy_file")")"
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
if [[ -f /etc/apt/sources.list.d/debian.sources ]]; then
|
||||
rm -f /etc/apt/sources.list.d/debian.sources
|
||||
msg_ok "$(translate "Old debian.sources file removed to prevent duplication")"
|
||||
fi
|
||||
|
||||
|
||||
msg_info "$(translate "Creating Proxmox VE 9.x no-subscription repository...")"
|
||||
cat > /etc/apt/sources.list.d/proxmox.sources << EOF
|
||||
Enabled: true
|
||||
Types: deb
|
||||
URIs: http://download.proxmox.com/debian/pve
|
||||
Suites: ${TARGET_CODENAME}
|
||||
Components: pve-no-subscription
|
||||
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
|
||||
EOF
|
||||
msg_ok "$(translate "Proxmox VE 9.x no-subscription repository created")"
|
||||
changes_made=true
|
||||
|
||||
|
||||
|
||||
msg_info "$(translate "Creating Debian ${TARGET_CODENAME} sources file...")"
|
||||
cat > /etc/apt/sources.list.d/debian.sources << EOF
|
||||
Types: deb
|
||||
URIs: http://deb.debian.org/debian/
|
||||
Suites: ${TARGET_CODENAME} ${TARGET_CODENAME}-updates
|
||||
Components: main contrib non-free-firmware
|
||||
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
|
||||
|
||||
Types: deb
|
||||
URIs: http://security.debian.org/debian-security/
|
||||
Suites: ${TARGET_CODENAME}-security
|
||||
Components: main contrib non-free-firmware
|
||||
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
|
||||
EOF
|
||||
|
||||
|
||||
|
||||
msg_ok "$(translate "Debian repositories configured for $TARGET_CODENAME")"
|
||||
|
||||
local firmware_conf="/etc/apt/apt.conf.d/no-firmware-warnings.conf"
|
||||
if [ ! -f "$firmware_conf" ]; then
|
||||
msg_info "$(translate "Disabling non-free firmware warnings...")"
|
||||
echo 'APT::Get::Update::SourceListWarnings::NonFreeFirmware "false";' > "$firmware_conf"
|
||||
msg_ok "$(translate "Non-free firmware warnings disabled")"
|
||||
fi
|
||||
|
||||
cleanup_duplicate_repos
|
||||
|
||||
update_output=$(apt-get update 2>&1)
|
||||
update_exit_code=$?
|
||||
|
||||
if [ $update_exit_code -eq 0 ]; then
|
||||
msg_ok "$(translate "Package lists updated successfully")"
|
||||
else
|
||||
if echo "$update_output" | grep -q "NO_PUBKEY\|GPG error"; then
|
||||
msg_info "$(translate "Fixing GPG key issues...")"
|
||||
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys $(echo "$update_output" | grep "NO_PUBKEY" | sed 's/.*NO_PUBKEY //' | head -1) 2>/dev/null
|
||||
if apt-get update > "$log_file" 2>&1; then
|
||||
msg_ok "$(translate "Package lists updated after GPG fix")"
|
||||
else
|
||||
msg_error "$(translate "Failed to update package lists. Check log: $log_file")"
|
||||
return 1
|
||||
fi
|
||||
elif echo "$update_output" | grep -q "404\|Failed to fetch"; then
|
||||
msg_warn "$(translate "Some repositories are not available, continuing with available ones...")"
|
||||
else
|
||||
msg_error "$(translate "Failed to update package lists. Check log: $log_file")"
|
||||
echo "Error details: $update_output"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
|
||||
if apt policy 2>/dev/null | grep -q "${TARGET_CODENAME}.*pve-no-subscription"; then
|
||||
msg_ok "$(translate "Proxmox VE 9.x repositories verified")"
|
||||
else
|
||||
msg_warn "$(translate "Proxmox VE 9.x repositories verification inconclusive, continuing...")"
|
||||
fi
|
||||
|
||||
local current_pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+\.[0-9]+\.[0-9]+' | head -1)
|
||||
local available_pve_version=$(apt-cache policy pve-manager 2>/dev/null | grep -oP 'Candidate: \K[0-9]+\.[0-9]+\.[0-9]+' | head -1)
|
||||
local upgradable=$(apt list --upgradable 2>/dev/null | grep -c "upgradable")
|
||||
local security_updates=$(apt list --upgradable 2>/dev/null | grep -c "security")
|
||||
|
||||
show_update_menu() {
|
||||
local current_version="$1"
|
||||
local target_version="$2"
|
||||
local upgradable_count="$3"
|
||||
local security_count="$4"
|
||||
|
||||
local menu_text="$(translate "System Update Information")\n\n"
|
||||
menu_text+="$(translate "Current PVE Version"): $current_version\n"
|
||||
if [ -n "$target_version" ] && [ "$target_version" != "$current_version" ]; then
|
||||
menu_text+="$(translate "Available PVE Version"): $target_version\n"
|
||||
fi
|
||||
menu_text+="\n$(translate "Package Updates Available"): $upgradable_count\n"
|
||||
menu_text+="$(translate "Security Updates"): $security_count\n\n"
|
||||
|
||||
if [ "$upgradable_count" -eq 0 ]; then
|
||||
menu_text+="$(translate "System is already up to date")"
|
||||
whiptail --title "$(translate "Update Status")" --msgbox "$menu_text" 15 70
|
||||
return 2
|
||||
else
|
||||
menu_text+="$(translate "Do you want to proceed with the system update?")"
|
||||
if whiptail --title "$(translate "Proxmox Update")" --yesno "$menu_text" 18 70; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
show_update_menu "$current_pve_version" "$available_pve_version" "$upgradable" "$security_updates"
|
||||
MENU_RESULT=$?
|
||||
|
||||
if [[ $MENU_RESULT -eq 1 ]]; then
|
||||
msg_info2 "$(translate "Update cancelled by user")"
|
||||
apt-get -y autoremove > /dev/null 2>&1 || true
|
||||
apt-get -y autoclean > /dev/null 2>&1 || true
|
||||
return 0
|
||||
elif [[ $MENU_RESULT -eq 2 ]]; then
|
||||
msg_ok "$(translate "System is already up to date. No update needed.")"
|
||||
apt-get -y autoremove > /dev/null 2>&1 || true
|
||||
apt-get -y autoclean > /dev/null 2>&1 || true
|
||||
return 0
|
||||
fi
|
||||
|
||||
msg_info "$(translate "Removing conflicting utilities...")"
|
||||
if /usr/bin/env DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::='--force-confdef' purge ntp openntpd systemd-timesyncd > /dev/null 2>&1; then
|
||||
msg_ok "$(translate "Conflicting utilities removed")"
|
||||
else
|
||||
msg_warn "$(translate "Some conflicting utilities may not have been removed")"
|
||||
fi
|
||||
|
||||
|
||||
msg_info "$(translate "Updating packages...")"
|
||||
apt-get install pv -y > /dev/null 2>&1
|
||||
msg_ok "$(translate "Packages updated successfully")"
|
||||
|
||||
tput sc
|
||||
|
||||
DEBIAN_FRONTEND=noninteractive apt-get -y \
|
||||
-o Dpkg::Options::='--force-confdef' \
|
||||
-o Dpkg::Options::='--force-confold' \
|
||||
dist-upgrade 2>&1 | while IFS= read -r line; do
|
||||
|
||||
echo "$line" >> "$log_file"
|
||||
|
||||
if [[ "$line" =~ \[[#=\-]+\]\ *[0-9]{1,3}% ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$line" =~ ^(Setting\ up|Unpacking|Preparing\ to\ unpack|Processing\ triggers\ for) ]]; then
|
||||
package_name=$(echo "$line" | sed -E 's/.*(Setting up|Unpacking|Preparing to unpack|Processing triggers for) ([^ :]+).*/\2/')
|
||||
[ -z "$package_name" ] && package_name="$(translate "Unknown")"
|
||||
|
||||
row=$(( $(tput lines) - 6 ))
|
||||
tput cup $row 0; printf "%s\n" "$(translate "Installing packages...")"
|
||||
tput cup $((row + 1)) 0; printf "%s\n" "──────────────────────────────────────────────"
|
||||
tput cup $((row + 2)) 0; printf "%s %s\n" "$(translate "Package:")" "$package_name"
|
||||
tput cup $((row + 3)) 0; printf "%s\n" "Progress: [ ] 0%"
|
||||
tput cup $((row + 4)) 0; printf "%s\n" "──────────────────────────────────────────────"
|
||||
|
||||
for i in $(seq 1 10); do
|
||||
sleep 0.1
|
||||
progress=$((i * 10))
|
||||
tput cup $((row + 3)) 9
|
||||
printf "[%-50s] %3d%%" "$(printf "#%.0s" $(seq 1 $((progress/2))))" "$progress"
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
tput rc
|
||||
tput ed
|
||||
|
||||
upgrade_exit_code=${PIPESTATUS[0]}
|
||||
|
||||
|
||||
|
||||
|
||||
if [ $upgrade_exit_code -eq 0 ]; then
|
||||
msg_ok "$(translate "System upgrade completed successfully")"
|
||||
else
|
||||
msg_error "$(translate "System upgrade failed. Check log: $log_file")"
|
||||
return 1
|
||||
fi
|
||||
|
||||
|
||||
msg_info "$(translate "Installing essential Proxmox packages...")"
|
||||
local additional_packages="zfsutils-linux proxmox-backup-restore-image chrony"
|
||||
|
||||
if /usr/bin/env DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::='--force-confdef' install $additional_packages >> "$log_file" 2>&1; then
|
||||
msg_ok "$(translate "Essential Proxmox packages installed")"
|
||||
else
|
||||
msg_warn "$(translate "Some essential Proxmox packages may not have been installed")"
|
||||
fi
|
||||
|
||||
lvm_repair_check
|
||||
cleanup_duplicate_repos
|
||||
|
||||
msg_info "$(translate "Performing system cleanup...")"
|
||||
apt-get -y autoremove > /dev/null 2>&1 || true
|
||||
apt-get -y autoclean > /dev/null 2>&1 || true
|
||||
msg_ok "$(translate "Cleanup finished")"
|
||||
|
||||
local end_time=$(date +%s)
|
||||
local duration=$((end_time - start_time))
|
||||
local minutes=$((duration / 60))
|
||||
local seconds=$((duration % 60))
|
||||
|
||||
echo -e "${TAB}${BGN}$(translate "====== PVE UPDATE COMPLETED ======")${CL}"
|
||||
echo -e "${TAB}${GN}⏱️ $(translate "Duration")${CL}: ${BL}${minutes}m ${seconds}s${CL}"
|
||||
echo -e "${TAB}${GN}📄 $(translate "Log file")${CL}: ${BL}$log_file${CL}"
|
||||
echo -e "${TAB}${GN}📦 $(translate "Packages upgraded")${CL}: ${BL}$upgradable${CL}"
|
||||
echo -e "${TAB}${GN}🖥️ $(translate "Proxmox VE")${CL}: ${BL}$target_version (Debian $OS_CODENAME)${CL}"
|
||||
|
||||
msg_ok "$(translate "Proxmox VE 9.x configuration completed.")"
|
||||
}
|
||||
|
||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||||
update_pve9
|
||||
fi
|
284
scripts/global/update-pve8.sh
Normal file
284
scripts/global/update-pve8.sh
Normal file
@ -0,0 +1,284 @@
|
||||
#!/bin/bash
|
||||
# ==========================================================
|
||||
# Proxmox VE 8.x Update Script
|
||||
# ==========================================================
|
||||
|
||||
# Configuration
|
||||
REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
|
||||
BASE_DIR="/usr/local/share/proxmenux"
|
||||
UTILS_FILE="$BASE_DIR/utils.sh"
|
||||
VENV_PATH="/opt/googletrans-env"
|
||||
TOOLS_JSON="/usr/local/share/proxmenux/installed_tools.json"
|
||||
|
||||
if [[ -f "$UTILS_FILE" ]]; then
|
||||
source "$UTILS_FILE"
|
||||
fi
|
||||
|
||||
load_language
|
||||
initialize_cache
|
||||
|
||||
ensure_tools_json() {
|
||||
[ -f "$TOOLS_JSON" ] || echo "{}" > "$TOOLS_JSON"
|
||||
}
|
||||
|
||||
register_tool() {
|
||||
local tool="$1"
|
||||
local state="$2"
|
||||
ensure_tools_json
|
||||
jq --arg t "$tool" --argjson v "$state" '.[$t]=$v' "$TOOLS_JSON" > "$TOOLS_JSON.tmp" && mv "$TOOLS_JSON.tmp" "$TOOLS_JSON"
|
||||
}
|
||||
|
||||
download_common_functions() {
|
||||
if ! source <(curl -s "$REPO_URL/scripts/global/common-functions.sh"); then
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
update_pve8() {
|
||||
local start_time=$(date +%s)
|
||||
local log_file="/var/log/proxmox-update-$(date +%Y%m%d-%H%M%S).log"
|
||||
local changes_made=false
|
||||
local OS_CODENAME="$(grep "VERSION_CODENAME=" /etc/os-release | cut -d"=" -f 2 | xargs)"
|
||||
|
||||
if [ -z "$OS_CODENAME" ]; then
|
||||
OS_CODENAME=$(lsb_release -cs 2>/dev/null || echo "bookworm")
|
||||
fi
|
||||
|
||||
download_common_functions
|
||||
|
||||
msg_info2 "$(translate "Detected: Proxmox VE 8.x (Debian $OS_CODENAME)")"
|
||||
echo
|
||||
|
||||
local available_space=$(df /var/cache/apt/archives | awk 'NR==2 {print int($4/1024)}')
|
||||
if [ "$available_space" -lt 1024 ]; then
|
||||
msg_error "$(translate "Insufficient disk space. Available: ${available_space}MB")"
|
||||
echo -e
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! ping -c 1 download.proxmox.com >/dev/null 2>&1; then
|
||||
msg_error "$(translate "Cannot reach Proxmox repositories")"
|
||||
echo -e
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
return 1
|
||||
fi
|
||||
|
||||
|
||||
if [ -f /etc/apt/sources.list.d/pve-enterprise.list ] && grep -q "^deb" /etc/apt/sources.list.d/pve-enterprise.list; then
|
||||
sed -i "s/^deb/#deb/g" /etc/apt/sources.list.d/pve-enterprise.list
|
||||
msg_ok "$(translate "Enterprise Proxmox repository disabled")"
|
||||
changes_made=true
|
||||
fi
|
||||
|
||||
if [ -f /etc/apt/sources.list.d/ceph.list ] && grep -q "^deb" /etc/apt/sources.list.d/ceph.list; then
|
||||
sed -i "s/^deb/#deb/g" /etc/apt/sources.list.d/ceph.list
|
||||
msg_ok "$(translate "Enterprise Proxmox Ceph repository disabled")"
|
||||
changes_made=true
|
||||
fi
|
||||
|
||||
|
||||
if [ ! -f /etc/apt/sources.list.d/pve-public-repo.list ] || ! grep -q "pve-no-subscription" /etc/apt/sources.list.d/pve-public-repo.list; then
|
||||
echo "deb http://download.proxmox.com/debian/pve $OS_CODENAME pve-no-subscription" > /etc/apt/sources.list.d/pve-public-repo.list
|
||||
msg_ok "$(translate "Free public Proxmox repository enabled")"
|
||||
changes_made=true
|
||||
fi
|
||||
|
||||
|
||||
local sources_file="/etc/apt/sources.list"
|
||||
cp "$sources_file" "${sources_file}.backup.$(date +%Y%m%d_%H%M%S)"
|
||||
|
||||
if grep -q -E "(debian-security -security|debian main$|debian -updates)" "$sources_file"; then
|
||||
sed -i '/^deb.*debian-security -security/d' "$sources_file"
|
||||
sed -i '/^deb.*debian main$/d' "$sources_file"
|
||||
sed -i '/^deb.*debian -updates/d' "$sources_file"
|
||||
changes_made=true
|
||||
msg_ok "$(translate "Malformed repository entries cleaned")"
|
||||
fi
|
||||
|
||||
cat > "$sources_file" << EOF
|
||||
# Debian $OS_CODENAME repositories
|
||||
deb http://deb.debian.org/debian $OS_CODENAME main contrib non-free non-free-firmware
|
||||
deb http://deb.debian.org/debian $OS_CODENAME-updates main contrib non-free non-free-firmware
|
||||
deb http://security.debian.org/debian-security $OS_CODENAME-security main contrib non-free non-free-firmware
|
||||
EOF
|
||||
|
||||
msg_ok "$(translate "Debian repositories configured for $OS_CODENAME")"
|
||||
|
||||
local firmware_conf="/etc/apt/apt.conf.d/no-firmware-warnings.conf"
|
||||
if [ ! -f "$firmware_conf" ]; then
|
||||
echo 'APT::Get::Update::SourceListWarnings::NonFreeFirmware "false";' > "$firmware_conf"
|
||||
fi
|
||||
|
||||
cleanup_duplicate_repos
|
||||
|
||||
msg_info "$(translate "Updating package lists...")"
|
||||
if apt-get update > "$log_file" 2>&1; then
|
||||
msg_ok "$(translate "Package lists updated successfully")"
|
||||
else
|
||||
msg_error "$(translate "Failed to update package lists. Check log: $log_file")"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local current_pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+\.[0-9]+\.[0-9]+' | head -1)
|
||||
local available_pve_version=$(apt-cache policy pve-manager 2>/dev/null | grep -oP 'Candidate: \K[0-9]+\.[0-9]+\.[0-9]+' | head -1)
|
||||
local upgradable=$(apt list --upgradable 2>/dev/null | grep -c "upgradable")
|
||||
local security_updates=$(apt list --upgradable 2>/dev/null | grep -c "security")
|
||||
|
||||
show_update_menu() {
|
||||
local current_version="$1"
|
||||
local target_version="$2"
|
||||
local upgradable_count="$3"
|
||||
local security_count="$4"
|
||||
|
||||
local menu_text="$(translate "System Update Information")\n\n"
|
||||
menu_text+="$(translate "Current PVE Version"): $current_version\n"
|
||||
if [ -n "$target_version" ] && [ "$target_version" != "$current_version" ]; then
|
||||
menu_text+="$(translate "Available PVE Version"): $target_version\n"
|
||||
fi
|
||||
menu_text+="\n$(translate "Package Updates Available"): $upgradable_count\n"
|
||||
menu_text+="$(translate "Security Updates"): $security_count\n\n"
|
||||
|
||||
if [ "$upgradable_count" -eq 0 ]; then
|
||||
menu_text+="$(translate "System is already up to date")"
|
||||
whiptail --title "$(translate "Update Status")" --msgbox "$menu_text" 15 70
|
||||
return 2
|
||||
else
|
||||
menu_text+="$(translate "Do you want to proceed with the system update?")"
|
||||
if whiptail --title "$(translate "Proxmox Update")" --yesno "$menu_text" 18 70; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
show_update_menu "$current_pve_version" "$available_pve_version" "$upgradable" "$security_updates"
|
||||
MENU_RESULT=$?
|
||||
|
||||
if [[ $MENU_RESULT -eq 1 ]]; then
|
||||
msg_info2 "$(translate "Update cancelled by user")"
|
||||
apt-get -y autoremove > /dev/null 2>&1 || true
|
||||
apt-get -y autoclean > /dev/null 2>&1 || true
|
||||
return 0
|
||||
elif [[ $MENU_RESULT -eq 2 ]]; then
|
||||
msg_ok "$(translate "System is already up to date. No update needed.")"
|
||||
apt-get -y autoremove > /dev/null 2>&1 || true
|
||||
apt-get -y autoclean > /dev/null 2>&1 || true
|
||||
return 0
|
||||
fi
|
||||
|
||||
|
||||
local conflicting_packages=$(dpkg -l 2>/dev/null | grep -E "^ii.*(ntp|openntpd|systemd-timesyncd)" | awk '{print $2}')
|
||||
if [ -n "$conflicting_packages" ]; then
|
||||
msg_info "$(translate "Removing conflicting utilities...")"
|
||||
DEBIAN_FRONTEND=noninteractive apt-get -y purge $conflicting_packages >> "$log_file" 2>&1
|
||||
msg_ok "$(translate "Conflicting utilities removed")"
|
||||
fi
|
||||
|
||||
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
export APT_LISTCHANGES_FRONTEND=none
|
||||
export NEEDRESTART_MODE=a
|
||||
export UCF_FORCE_CONFOLD=1
|
||||
export DPKG_OPTIONS="--force-confdef --force-confold"
|
||||
|
||||
msg_info "$(translate "Performing packages upgrade...")"
|
||||
apt-get install pv -y > /dev/null 2>&1
|
||||
total_packages=$(apt-get -s dist-upgrade | grep "^Inst" | wc -l)
|
||||
msg_ok "$(translate "Packages upgrade successfull")"
|
||||
|
||||
if [ "$total_packages" -eq 0 ]; then
|
||||
total_packages=1
|
||||
fi
|
||||
|
||||
tput civis
|
||||
tput sc
|
||||
|
||||
(
|
||||
/usr/bin/env \
|
||||
DEBIAN_FRONTEND=noninteractive \
|
||||
APT_LISTCHANGES_FRONTEND=none \
|
||||
NEEDRESTART_MODE=a \
|
||||
UCF_FORCE_CONFOLD=1 \
|
||||
apt-get -y \
|
||||
-o Dpkg::Options::="--force-confdef" \
|
||||
-o Dpkg::Options::="--force-confold" \
|
||||
dist-upgrade 2>&1 | \
|
||||
while IFS= read -r line; do
|
||||
if [[ "$line" =~ ^(Setting\ up|Unpacking|Preparing\ to\ unpack|Processing\ triggers\ for) ]]; then
|
||||
package_name=$(echo "$line" | sed -E 's/.*(Setting up|Unpacking|Preparing to unpack|Processing triggers for) ([^ ]+).*/\2/')
|
||||
[ -z "$package_name" ] && package_name="$(translate "Unknown")"
|
||||
|
||||
tput rc
|
||||
tput ed
|
||||
|
||||
row=$(( $(tput lines) - 6 ))
|
||||
tput cup $row 0; echo "$(translate "Installing packages...")"
|
||||
tput cup $((row + 1)) 0; echo "──────────────────────────────────────────────"
|
||||
tput cup $((row + 2)) 0; echo "Package: $package_name"
|
||||
tput cup $((row + 3)) 0; echo "Progress: [ ] 0%"
|
||||
tput cup $((row + 4)) 0; echo "──────────────────────────────────────────────"
|
||||
|
||||
for i in $(seq 1 10); do
|
||||
progress=$((i * 10))
|
||||
tput cup $((row + 3)) 9
|
||||
printf "[%-50s] %3d%%" "$(printf "#%.0s" $(seq 1 $((progress/2))))" "$progress"
|
||||
done
|
||||
fi
|
||||
done
|
||||
)
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
tput rc
|
||||
tput ed
|
||||
tput cnorm
|
||||
msg_ok "$(translate "System upgrade completed")"
|
||||
fi
|
||||
|
||||
|
||||
|
||||
local essential_packages=("zfsutils-linux" "proxmox-backup-restore-image" "chrony")
|
||||
local missing_packages=()
|
||||
|
||||
for package in "${essential_packages[@]}"; do
|
||||
if ! dpkg -l 2>/dev/null | grep -q "^ii $package "; then
|
||||
missing_packages+=("$package")
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ${#missing_packages[@]} -gt 0 ]; then
|
||||
msg_info "$(translate "Installing essential Proxmox packages...")"
|
||||
DEBIAN_FRONTEND=noninteractive apt-get -y install "${missing_packages[@]}" >> "$log_file" 2>&1
|
||||
msg_ok "$(translate "Essential Proxmox packages installed")"
|
||||
fi
|
||||
|
||||
lvm_repair_check
|
||||
cleanup_duplicate_repos
|
||||
|
||||
msg_info "$(translate "Performing system cleanup...")"
|
||||
apt-get -y autoremove > /dev/null 2>&1 || true
|
||||
apt-get -y autoclean > /dev/null 2>&1 || true
|
||||
msg_ok "$(translate "Cleanup finished")"
|
||||
|
||||
local end_time=$(date +%s)
|
||||
local duration=$((end_time - start_time))
|
||||
local minutes=$((duration / 60))
|
||||
local seconds=$((duration % 60))
|
||||
|
||||
echo -e "${TAB}${BGN}$(translate "====== PVE UPDATE COMPLETED ======")${CL}"
|
||||
echo -e "${TAB}${GN}⏱️ $(translate "Duration")${CL}: ${BL}${minutes}m ${seconds}s${CL}"
|
||||
echo -e "${TAB}${GN}📄 $(translate "Log file")${CL}: ${BL}$log_file${CL}"
|
||||
echo -e "${TAB}${GN}📦 $(translate "Packages upgraded")${CL}: ${BL}$upgradable${CL}"
|
||||
echo -e "${TAB}${GN}🖥️ $(translate "Proxmox VE")${CL}: ${BL}$target_version (Debian $OS_CODENAME)${CL}"
|
||||
|
||||
|
||||
|
||||
msg_ok "$(translate "Proxmox VE 8 system update completed successfully")"
|
||||
}
|
||||
|
||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||||
update_pve8
|
||||
fi
|
@ -72,8 +72,8 @@ validate_container_id() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Añadir regla udev para Coral USB para persistencia de permisos
|
||||
add_udev_rule_for_coral_usb() {
|
||||
|
||||
add_udev_rule_for_coral_usb_() {
|
||||
RULE_FILE="/etc/udev/rules.d/99-coral-usb.rules"
|
||||
RULE_CONTENT='SUBSYSTEM=="usb", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="9302", MODE="0666", TAG+="uaccess"'
|
||||
|
||||
@ -87,6 +87,22 @@ add_udev_rule_for_coral_usb() {
|
||||
}
|
||||
|
||||
|
||||
add_udev_rule_for_coral_usb() {
|
||||
RULE_FILE="/etc/udev/rules.d/99-coral-usb.rules"
|
||||
RULE_CONTENT='# Coral USB Accelerator
|
||||
SUBSYSTEM=="usb", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="9302", MODE="0666", TAG+="uaccess", SYMLINK+="coral"
|
||||
# Coral Dev Board / Mini PCIe
|
||||
SUBSYSTEM=="usb", ATTRS{idVendor}=="1a6e", ATTRS{idProduct}=="089a", MODE="0666", TAG+="uaccess", SYMLINK+="coral"'
|
||||
|
||||
if [[ ! -f "$RULE_FILE" ]] || ! grep -q "18d1.*9302\|1a6e.*089a" "$RULE_FILE"; then
|
||||
echo "$RULE_CONTENT" > "$RULE_FILE"
|
||||
udevadm control --reload-rules && udevadm trigger
|
||||
msg_ok "$(translate 'Udev rules for Coral USB devices added and rules reloaded.')"
|
||||
else
|
||||
msg_ok "$(translate 'Udev rules for Coral USB devices already exist.')"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
add_mount_if_needed() {
|
||||
local DEVICE="$1"
|
||||
|
135
scripts/lcx/jd2.sh
Normal file
135
scripts/lcx/jd2.sh
Normal file
@ -0,0 +1,135 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script para instalar JDownloader en un contenedor LXC desde el host Proxmox
|
||||
# Autor: MacRimi
|
||||
|
||||
# Mostrar lista de CTs
|
||||
CT_LIST=$(pct list | awk 'NR>1 {print $1, $3}')
|
||||
if [ -z "$CT_LIST" ]; then
|
||||
whiptail --title "Error" --msgbox "No hay contenedores LXC disponibles en el sistema." 8 50
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Seleccionar CT
|
||||
CTID=$(whiptail --title "Instalación de JDownloader" --menu "Selecciona el contenedor donde instalar JDownloader:" 20 60 10 $CT_LIST 3>&1 1>&2 2>&3)
|
||||
if [ -z "$CTID" ]; then
|
||||
whiptail --title "Cancelado" --msgbox "No se ha seleccionado ningún contenedor." 8 40
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Solicitar email
|
||||
EMAIL=$(whiptail --title "Cuenta My JDownloader" --inputbox "Introduce tu correo electrónico para vincular JDownloader:" 10 60 3>&1 1>&2 2>&3)
|
||||
if [ -z "$EMAIL" ]; then
|
||||
whiptail --title "Error" --msgbox "No se ha introducido ningún correo." 8 40
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Solicitar contraseña con confirmación
|
||||
while true; do
|
||||
PASSWORD=$(whiptail --title "Cuenta My JDownloader" --passwordbox "Introduce tu contraseña de My JDownloader:" 10 60 3>&1 1>&2 2>&3)
|
||||
[ -z "$PASSWORD" ] && whiptail --title "Error" --msgbox "No se ha introducido ninguna contraseña." 8 40 && exit 1
|
||||
|
||||
CONFIRM=$(whiptail --title "Confirmación de contraseña" --passwordbox "Repite tu contraseña para confirmar:" 10 60 3>&1 1>&2 2>&3)
|
||||
[ "$PASSWORD" = "$CONFIRM" ] && break
|
||||
whiptail --title "Error" --msgbox "Las contraseñas no coinciden. Intenta de nuevo." 8 50
|
||||
done
|
||||
|
||||
# Confirmación final
|
||||
whiptail --title "Confirmar datos" --yesno "¿Deseas continuar con los siguientes datos?\n\nCorreo: $EMAIL\nContraseña: (oculta)\n\nEsta información se usará para vincular el contenedor con tu cuenta de My.JDownloader." 14 60
|
||||
[ $? -ne 0 ] && whiptail --title "Cancelado" --msgbox "Instalación cancelada por el usuario." 8 40 && exit 1
|
||||
|
||||
clear
|
||||
echo "🔍 Detectando sistema operativo dentro del CT $CTID..."
|
||||
OS_ID=$(pct exec "$CTID" -- awk -F= '/^ID=/{gsub("\"",""); print $2}' /etc/os-release)
|
||||
|
||||
echo "Sistema detectado: $OS_ID"
|
||||
echo "🧰 Preparando entorno..."
|
||||
|
||||
case "$OS_ID" in
|
||||
debian)
|
||||
# Repositorio adicional para Java 8
|
||||
pct exec "$CTID" -- wget -q http://www.mirbsd.org/~tg/Debs/sources.txt/wtf-bookworm.sources
|
||||
pct exec "$CTID" -- mv wtf-bookworm.sources /etc/apt/sources.list.d/
|
||||
pct exec "$CTID" -- apt update -y
|
||||
pct exec "$CTID" -- apt install -y openjdk-8-jdk wget
|
||||
JAVA_PATH="/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java"
|
||||
;;
|
||||
ubuntu)
|
||||
pct exec "$CTID" -- apt update -y
|
||||
pct exec "$CTID" -- apt install -y openjdk-8-jdk wget
|
||||
JAVA_PATH="/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java"
|
||||
;;
|
||||
alpine)
|
||||
pct exec "$CTID" -- apk update
|
||||
pct exec "$CTID" -- apk add openjdk8 wget
|
||||
JAVA_PATH="/usr/lib/jvm/java-1.8-openjdk/bin/java"
|
||||
;;
|
||||
*)
|
||||
echo "❌ Sistema operativo no soportado: $OS_ID"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Crear carpeta de instalación
|
||||
pct exec "$CTID" -- mkdir -p /opt/jdownloader
|
||||
pct exec "$CTID" -- bash -c 'cd /opt/jdownloader && curl -O https://installer.jdownloader.org/JDownloader.jar'
|
||||
|
||||
|
||||
# Crear archivo de configuración JSON para My JDownloader
|
||||
pct exec "$CTID" -- bash -c "mkdir -p /opt/jdownloader/cfg && cat > /opt/jdownloader/cfg/org.jdownloader.api.myjdownloader.MyJDownloaderSettings.json" <<EOF
|
||||
{
|
||||
"email" : "$EMAIL",
|
||||
"password" : "$PASSWORD",
|
||||
"enabled" : true
|
||||
}
|
||||
EOF
|
||||
|
||||
|
||||
# Crear servicio según sistema
|
||||
if [[ "$OS_ID" == "alpine" ]]; then
|
||||
# Servicio OpenRC para Alpine
|
||||
pct exec "$CTID" -- bash -c 'cat > /etc/init.d/jdownloader <<EOF
|
||||
#!/sbin/openrc-run
|
||||
|
||||
command="/usr/bin/java"
|
||||
command_args="-jar /opt/jdownloader/JDownloader.jar -norestart"
|
||||
pidfile="/var/run/jdownloader.pid"
|
||||
name="JDownloader"
|
||||
|
||||
depend() {
|
||||
need net
|
||||
}
|
||||
EOF'
|
||||
|
||||
pct exec "$CTID" -- chmod +x /etc/init.d/jdownloader
|
||||
pct exec "$CTID" -- rc-update add jdownloader default
|
||||
pct exec "$CTID" -- rc-service jdownloader start
|
||||
|
||||
else
|
||||
# Servicio systemd para Debian/Ubuntu
|
||||
pct exec "$CTID" -- bash -c 'cat > /etc/systemd/system/jdownloader.service <<EOF
|
||||
[Unit]
|
||||
Description=JDownloader
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
WorkingDirectory=/opt/jdownloader
|
||||
ExecStart=/usr/bin/java -jar JDownloader.jar -norestart
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF'
|
||||
|
||||
pct exec "$CTID" -- systemctl daemon-reexec
|
||||
pct exec "$CTID" -- systemctl daemon-reload
|
||||
pct exec "$CTID" -- systemctl enable jdownloader
|
||||
pct exec "$CTID" -- systemctl start jdownloader
|
||||
fi
|
||||
|
||||
pct exec "$CTID" -- reboot
|
||||
|
||||
echo -e "\n\033[1;32m✅ JDownloader se ha instalado correctamente en el CT $CTID y está funcionando como servicio.\033[0m"
|
||||
echo -e "\n➡️ Accede a \033[1;34mhttps://my.jdownloader.org\033[0m con tu cuenta para gestionarlo.\n"
|
99
scripts/lcx/jd2_.sh
Normal file
99
scripts/lcx/jd2_.sh
Normal file
@ -0,0 +1,99 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script para instalar JDownloader en un contenedor LXC desde el host Proxmox
|
||||
# Autor: MacRimi
|
||||
|
||||
# Mostrar lista de CTs
|
||||
CT_LIST=$(pct list | awk 'NR>1 {print $1, $3}')
|
||||
if [ -z "$CT_LIST" ]; then
|
||||
whiptail --title "Error" --msgbox "No hay contenedores LXC disponibles en el sistema." 8 50
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Seleccionar CT
|
||||
CTID=$(whiptail --title "Instalación de JDownloader" --menu "Selecciona el contenedor donde instalar JDownloader:" 20 60 10 $CT_LIST 3>&1 1>&2 2>&3)
|
||||
if [ -z "$CTID" ]; then
|
||||
whiptail --title "Cancelado" --msgbox "No se ha seleccionado ningún contenedor." 8 40
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Solicitar email
|
||||
EMAIL=$(whiptail --title "Cuenta My JDownloader" --inputbox "Introduce tu correo electrónico para vincular JDownloader:" 10 60 3>&1 1>&2 2>&3)
|
||||
if [ -z "$EMAIL" ]; then
|
||||
whiptail --title "Error" --msgbox "No se ha introducido ningún correo." 8 40
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Solicitar contraseña
|
||||
while true; do
|
||||
PASSWORD=$(whiptail --title "Cuenta My JDownloader" --passwordbox "Introduce tu contraseña de My JDownloader:" 10 60 3>&1 1>&2 2>&3)
|
||||
if [ -z "$PASSWORD" ]; then
|
||||
whiptail --title "Error" --msgbox "No se ha introducido ninguna contraseña." 8 40
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CONFIRM_PASSWORD=$(whiptail --title "Confirmación de contraseña" --passwordbox "Repite tu contraseña para confirmar:" 10 60 3>&1 1>&2 2>&3)
|
||||
|
||||
if [ "$PASSWORD" = "$CONFIRM_PASSWORD" ]; then
|
||||
break
|
||||
else
|
||||
whiptail --title "Error" --msgbox "Las contraseñas no coinciden. Intenta de nuevo." 8 50
|
||||
fi
|
||||
done
|
||||
|
||||
# Confirmar datos
|
||||
whiptail --title "Confirmar datos" --yesno "¿Deseas continuar con los siguientes datos?\n\nCorreo: $EMAIL\nContraseña: (establecida)\n\nEsta información se usará para vincular el contenedor con tu cuenta de My.JDownloader." 14 60
|
||||
if [ $? -ne 0 ]; then
|
||||
whiptail --title "Cancelado" --msgbox "Instalación cancelada por el usuario." 8 40
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "Instalando JDownloader en CT $CTID..."
|
||||
echo
|
||||
|
||||
# Añadir repositorio alternativo para Java 8 y actualizar
|
||||
pct exec "$CTID" -- wget -q http://www.mirbsd.org/~tg/Debs/sources.txt/wtf-bookworm.sources
|
||||
pct exec "$CTID" -- mv wtf-bookworm.sources /etc/apt/sources.list.d/
|
||||
pct exec "$CTID" -- apt update -y
|
||||
pct exec "$CTID" -- apt install -y openjdk-8-jdk wget
|
||||
|
||||
# Crear carpeta y descargar JDownloader
|
||||
pct exec "$CTID" -- mkdir -p /root/jdownloader
|
||||
pct exec "$CTID" -- bash -c "cd /root/jdownloader && wget -q http://installer.jdownloader.org/JDownloader.jar"
|
||||
|
||||
# Crear archivo de configuración JSON para My JDownloader
|
||||
pct exec "$CTID" -- bash -c "mkdir -p /root/jdownloader/cfg && cat > /root/jdownloader/cfg/org.jdownloader.api.myjdownloader.MyJDownloaderSettings.json" <<EOF
|
||||
|
||||
{
|
||||
"email" : "$EMAIL",
|
||||
"password" : "$PASSWORD",
|
||||
"enabled" : true
|
||||
}
|
||||
EOF
|
||||
|
||||
# Crear servicio systemd
|
||||
pct exec "$CTID" -- bash -c "cat > /etc/systemd/system/jdownloader.service <<EOF
|
||||
[Unit]
|
||||
Description=JDownloader Headless
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=/root/jdownloader
|
||||
ExecStart=/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java -jar JDownloader.jar -norestart
|
||||
Restart=always
|
||||
User=root
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF"
|
||||
|
||||
# Activar y arrancar servicio
|
||||
pct exec "$CTID" -- systemctl daemon-reexec
|
||||
pct exec "$CTID" -- systemctl daemon-reload
|
||||
pct exec "$CTID" -- systemctl enable jdownloader
|
||||
pct exec "$CTID" -- systemctl start jdownloader
|
||||
|
||||
echo -e "\n\033[1;32m✅ JDownloader se ha instalado y está funcionando como servicio en el CT $CTID.\033[0m"
|
||||
echo -e "\nPuedes acceder a \033[1;34mhttps://my.jdownloader.org\033[0m con tu cuenta para gestionarlo.\n"
|
@ -54,7 +54,7 @@ show_menu() {
|
||||
if [[ $EXIT_STATUS -ne 0 ]]; then
|
||||
# ESC pressed or Cancel
|
||||
clear
|
||||
msg_ok "$(translate "Thank you for using ProxMenu. Goodbye!")"
|
||||
msg_ok "$(translate "Thank you for using ProxMenux. Goodbye!")"
|
||||
rm -f "$TEMP_FILE"
|
||||
exit 0
|
||||
fi
|
||||
|
@ -13,13 +13,15 @@
|
||||
# Advanced network management and troubleshooting tool for Proxmox VE.
|
||||
# Features include interface detection, bridge management, connectivity testing,
|
||||
# network diagnostics, configuration backup/restore, and automated repairs.
|
||||
|
||||
# Special thanks to @Andres_Eduardo_Rojas_Moya for contributing the persistent
|
||||
# network naming function and for the original idea.
|
||||
# Configuration ============================================
|
||||
REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
|
||||
BASE_DIR="/usr/local/share/proxmenux"
|
||||
UTILS_FILE="$BASE_DIR/utils.sh"
|
||||
VENV_PATH="/opt/googletrans-env"
|
||||
BACKUP_DIR="/var/backups/proxmenux"
|
||||
TOOLS_JSON="/usr/local/share/proxmenux/installed_tools.json"
|
||||
|
||||
if [[ -f "$UTILS_FILE" ]]; then
|
||||
source "$UTILS_FILE"
|
||||
@ -39,10 +41,19 @@ backup_network_config() {
|
||||
local timestamp=$(date +"%Y-%m-%d_%H-%M-%S")
|
||||
local backup_file="$BACKUP_DIR/interfaces_backup_$timestamp"
|
||||
cp /etc/network/interfaces "$backup_file"
|
||||
msg_ok "$(translate "Network configuration backed up")"
|
||||
echo "$backup_file"
|
||||
}
|
||||
# Tool registration system
|
||||
ensure_tools_json() {
|
||||
[ -f "$TOOLS_JSON" ] || echo "{}" > "$TOOLS_JSON"
|
||||
}
|
||||
|
||||
register_tool() {
|
||||
local tool="$1"
|
||||
local state="$2"
|
||||
ensure_tools_json
|
||||
jq --arg t "$tool" --argjson v "$state" '.[$t]=$v' "$TOOLS_JSON" > "$TOOLS_JSON.tmp" && mv "$TOOLS_JSON.tmp" "$TOOLS_JSON"
|
||||
}
|
||||
# ==========================================================
|
||||
# Network Detection Functions
|
||||
detect_network_method() {
|
||||
@ -100,75 +111,6 @@ get_interface_info() {
|
||||
}
|
||||
|
||||
# ==========================================================
|
||||
# Network Information Functions
|
||||
show_interface_details() {
|
||||
|
||||
NETWORK_METHOD=$(detect_network_method)
|
||||
|
||||
if [[ "$NETWORK_METHOD" != "classic" ]]; then
|
||||
dialog --title "Unsupported Network Stack" \
|
||||
--msgbox "WARNING: This script only supports the classic Debian/Proxmox network configuration (/etc/network/interfaces).\n\nDetected: $NETWORK_METHOD.\n\nAborting for safety.\n\nPlease configure your network using your distribution's supported tools." 14 70
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
local interfaces=($(detect_all_interfaces))
|
||||
local info_text=""
|
||||
|
||||
info_text+="$(translate "Network Interface Details")\n"
|
||||
info_text+="$(printf '=%.0s' {1..50})\n\n"
|
||||
|
||||
for interface in "${interfaces[@]}"; do
|
||||
local details=$(get_interface_info "$interface")
|
||||
IFS='|' read -r name ip status mac <<< "$details"
|
||||
|
||||
info_text+="$(translate "Interface"): $name\n"
|
||||
info_text+=" $(translate "IP Address"): $ip\n"
|
||||
info_text+=" $(translate "Status"): $status\n"
|
||||
info_text+=" $(translate "MAC Address"): $mac\n\n"
|
||||
done
|
||||
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "Interface Details")" \
|
||||
--msgbox "$info_text" 20 70
|
||||
}
|
||||
|
||||
show_bridge_status() {
|
||||
|
||||
NETWORK_METHOD=$(detect_network_method)
|
||||
|
||||
if [[ "$NETWORK_METHOD" != "classic" ]]; then
|
||||
dialog --title "Unsupported Network Stack" \
|
||||
--msgbox "WARNING: This script only supports the classic Debian/Proxmox network configuration (/etc/network/interfaces).\n\nDetected: $NETWORK_METHOD.\n\nAborting for safety.\n\nPlease configure your network using your distribution's supported tools." 14 70
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local bridges=($(detect_bridge_interfaces))
|
||||
local bridge_info=""
|
||||
|
||||
bridge_info+="$(translate "Bridge Configuration Status")\n"
|
||||
bridge_info+="$(printf '=%.0s' {1..40})\n\n"
|
||||
|
||||
if [ ${#bridges[@]} -eq 0 ]; then
|
||||
bridge_info+="$(translate "No bridges found")\n"
|
||||
else
|
||||
for bridge in "${bridges[@]}"; do
|
||||
local details=$(get_interface_info "$bridge")
|
||||
IFS='|' read -r name ip status mac <<< "$details"
|
||||
|
||||
# Get bridge ports
|
||||
local ports=$(grep -A5 "iface $bridge" /etc/network/interfaces 2>/dev/null | grep "bridge-ports" | cut -d' ' -f2-)
|
||||
[ -z "$ports" ] && ports="$(translate "None")"
|
||||
|
||||
bridge_info+="$(translate "Bridge"): $name\n"
|
||||
bridge_info+=" $(translate "IP"): $ip\n"
|
||||
bridge_info+=" $(translate "Status"): $status\n"
|
||||
bridge_info+=" $(translate "Ports"): $ports\n\n"
|
||||
done
|
||||
fi
|
||||
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "Bridge Status")" \
|
||||
--msgbox "$bridge_info" 20 70
|
||||
}
|
||||
|
||||
show_routing_table_() {
|
||||
local route_info=""
|
||||
@ -428,6 +370,7 @@ analyze_bridge_configuration() {
|
||||
--textbox "$temp_file" 25 80
|
||||
rm -f "$temp_file"
|
||||
|
||||
|
||||
# Offer guided repair if issues found
|
||||
if [ $issues_found -gt 0 ]; then
|
||||
if dialog --backtitle "ProxMenux" --title "$(translate "Guided Repair Available")" \
|
||||
@ -437,6 +380,7 @@ analyze_bridge_configuration() {
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
guided_bridge_repair() {
|
||||
local step=1
|
||||
local total_steps=5
|
||||
@ -455,7 +399,8 @@ guided_bridge_repair() {
|
||||
|
||||
show_proxmenux_logo
|
||||
local backup_file=$(backup_network_config)
|
||||
sleep 1
|
||||
msg_ok "$(translate "Network configuration backed up")"
|
||||
sleep 2
|
||||
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "Backup Created")" \
|
||||
--msgbox "$(translate "Safety backup created"): $backup_file\n\n$(translate "You can restore it anytime with"):\ncp $backup_file /etc/network/interfaces" 10 70
|
||||
@ -580,6 +525,12 @@ guided_bridge_repair() {
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# ==========================================================
|
||||
|
||||
|
||||
|
||||
|
||||
analyze_network_configuration() {
|
||||
|
||||
NETWORK_METHOD=$(detect_network_method)
|
||||
@ -693,7 +644,8 @@ guided_configuration_cleanup() {
|
||||
|
||||
show_proxmenux_logo
|
||||
local backup_file=$(backup_network_config)
|
||||
sleep 1
|
||||
msg_ok "$(translate "Network configuration backed up")"
|
||||
sleep 2
|
||||
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "Backup Created")" \
|
||||
--msgbox "$(translate "Safety backup created"): $backup_file\n\n$(translate "You can restore it anytime with"):\ncp $backup_file /etc/network/interfaces" 10 70
|
||||
@ -787,6 +739,68 @@ guided_configuration_cleanup() {
|
||||
}
|
||||
|
||||
|
||||
# ==========================================================
|
||||
|
||||
|
||||
|
||||
setup_persistent_network() {
|
||||
local LINK_DIR="/etc/systemd/network"
|
||||
local BACKUP_DIR="/etc/systemd/network/backup-$(date +%Y%m%d-%H%M%S)"
|
||||
|
||||
if ! dialog --title "$(translate "Network Interface Setup")" \
|
||||
--yesno "\n$(translate "Create persistent network interface names?")" 8 60; then
|
||||
return 1
|
||||
fi
|
||||
show_proxmenux_logo
|
||||
msg_info "$(translate "Setting up persistent network interfaces")"
|
||||
sleep 2
|
||||
# Create directory
|
||||
mkdir -p "$LINK_DIR"
|
||||
|
||||
# Backup existing files
|
||||
if ls "$LINK_DIR"/*.link >/dev/null 2>&1; then
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
cp "$LINK_DIR"/*.link "$BACKUP_DIR"/ 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Process physical interfaces
|
||||
local count=0
|
||||
for iface in $(ls /sys/class/net/ | grep -vE "lo|docker|veth|br-|vmbr|tap|fwpr|fwln|virbr|bond|cilium|zt|wg"); do
|
||||
if [[ -e "/sys/class/net/$iface/device" ]] || [[ -e "/sys/class/net/$iface/phy80211" ]]; then
|
||||
local MAC=$(cat /sys/class/net/$iface/address 2>/dev/null)
|
||||
|
||||
if [[ "$MAC" =~ ^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$ ]]; then
|
||||
local LINK_FILE="$LINK_DIR/10-$iface.link"
|
||||
|
||||
cat > "$LINK_FILE" <<EOF
|
||||
[Match]
|
||||
MACAddress=$MAC
|
||||
|
||||
[Link]
|
||||
Name=$iface
|
||||
EOF
|
||||
chmod 644 "$LINK_FILE"
|
||||
((count++))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $count -gt 0 ]]; then
|
||||
msg_ok "$(translate "Created persistent names for") $count $(translate "interfaces")"
|
||||
msg_ok "$(translate "Changes will apply after reboot.")"
|
||||
else
|
||||
msg_warn "$(translate "No physical interfaces found")"
|
||||
fi
|
||||
register_tool "persistent_network" true
|
||||
echo -e
|
||||
msg_success "$(translate "Press ENTER to continue...")"
|
||||
read -r
|
||||
}
|
||||
|
||||
|
||||
|
||||
# ==========================================================
|
||||
|
||||
|
||||
restart_network_service() {
|
||||
if dialog --title "$(translate "Restart Network")" \
|
||||
@ -849,7 +863,9 @@ create_network_backup_manual() {
|
||||
echo -e
|
||||
msg_info "$(translate "Creating backup of network interfaces configuration...")"
|
||||
sleep 3
|
||||
cleanup
|
||||
backup_network_config
|
||||
msg_ok "$(translate "Network configuration backed up")"
|
||||
echo -e
|
||||
msg_success "$(translate "Press Enter to continue...")"
|
||||
read -r
|
||||
@ -923,44 +939,167 @@ restore_network_backup() {
|
||||
}
|
||||
|
||||
|
||||
# ==========================================================
|
||||
# Main Menu
|
||||
show_main_menu() {
|
||||
while true; do
|
||||
local selection=$(dialog --clear \
|
||||
--backtitle "ProxMenux" \
|
||||
--title "$(translate "Network Management - SAFE MODE")" \
|
||||
--menu "$(translate "Select an option:"):" 20 70 12 \
|
||||
"1" "$(translate "Show Interface Details")" \
|
||||
"2" "$(translate "Show Bridge Status")" \
|
||||
"3" "$(translate "Show Routing Table")" \
|
||||
"4" "$(translate "Test Connectivity")" \
|
||||
"5" "$(translate "Advanced Diagnostics")" \
|
||||
"6" "$(translate "Analyze Bridge Configuration")" \
|
||||
"7" "$(translate "Analyze Network Configuration")" \
|
||||
"8" "$(translate "Restart Network Service")" \
|
||||
"9" "$(translate "Show Network Config File")" \
|
||||
"10" "$(translate "Create Network Backup")" \
|
||||
"11" "$(translate "Restore Network Backup")" \
|
||||
"0" "$(translate "Return to Main Menu")" \
|
||||
3>&1 1>&2 2>&3)
|
||||
launch_iftop() {
|
||||
if ! command -v iftop &>/dev/null; then
|
||||
apt-get update -qq && apt-get install -y iftop &>/dev/null
|
||||
fi
|
||||
|
||||
case $selection in
|
||||
1) show_interface_details ;;
|
||||
2) show_bridge_status ;;
|
||||
3) show_routing_table ;;
|
||||
4) test_connectivity ;;
|
||||
5) advanced_network_diagnostics ;;
|
||||
6) analyze_bridge_configuration ;;
|
||||
7) analyze_network_configuration ;;
|
||||
8) restart_network_service ;;
|
||||
9) show_network_config ;;
|
||||
10) create_network_backup_manual ;;
|
||||
11) restore_network_backup ;;
|
||||
0|"") exec bash <(curl -s "$REPO_URL/scripts/menus/main_menu.sh") ;;
|
||||
esac
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "iftop usage")" --msgbox "\n$(translate "To exit iftop, press q")" 8 50
|
||||
clear
|
||||
iftop
|
||||
}
|
||||
|
||||
launch_iptraf() {
|
||||
if ! command -v iptraf-ng &>/dev/null; then
|
||||
apt-get update -qq && apt-get install -y iptraf-ng &>/dev/null
|
||||
fi
|
||||
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "iptraf-ng usage")" --msgbox "\n$(translate "To exit iptraf-ng, press x")" 8 50
|
||||
clear
|
||||
iptraf-ng
|
||||
}
|
||||
|
||||
|
||||
# ==========================================================
|
||||
|
||||
|
||||
confirm_and_run() {
|
||||
local name="$1"
|
||||
local command="$2"
|
||||
|
||||
dialog --clear --title "$(translate "Confirmation")" \
|
||||
--yesno "\n\n$(translate "Do you want to run the network script from") $name?" 10 70
|
||||
|
||||
response=$?
|
||||
clear
|
||||
|
||||
if [ $response -eq 0 ]; then
|
||||
eval "$command"
|
||||
echo
|
||||
msg_success "$(translate 'Press ENTER to continue...')"
|
||||
read -r _
|
||||
else
|
||||
msg_warn "$(translate "Cancelled by user.")"
|
||||
sleep 1
|
||||
fi
|
||||
}
|
||||
|
||||
# ==========================================================
|
||||
|
||||
declare -a PROXMENUX_SCRIPTS=(
|
||||
"Real-time network usage (iftop)||launch_iftop"
|
||||
"Network monitoring tool (iptraf-ng)||launch_iptraf"
|
||||
"Show Routing Table||show_routing_table"
|
||||
"Test Connectivity||test_connectivity"
|
||||
"Advanced Diagnostics||advanced_network_diagnostics"
|
||||
"Analyze Bridge Configuration||analyze_bridge_configuration"
|
||||
"Analyze Network Configuration||analyze_network_configuration"
|
||||
"Setup Persistent Network Names||setup_persistent_network"
|
||||
"Restart Network Service||restart_network_service"
|
||||
"Show Network Config File||show_network_config"
|
||||
"Create Network Backup||create_network_backup_manual"
|
||||
"Restore Network Backup||restore_network_backup"
|
||||
)
|
||||
|
||||
|
||||
|
||||
declare -a COMMUNITY_SCRIPTS=(
|
||||
"Disable NIC Offloading (Intel e1000e)|Helper-Scripts|confirm_and_run \"Helper-Scripts\" \"bash <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/pve/nic-offloading-fix.sh)\""
|
||||
)
|
||||
|
||||
# ==========================================================
|
||||
format_menu_item() {
|
||||
local description="$1"
|
||||
local source="$2"
|
||||
local total_width=62
|
||||
|
||||
|
||||
local desc_length=${#description}
|
||||
local source_length=${#source}
|
||||
local spaces_needed=$((total_width - desc_length - source_length))
|
||||
|
||||
|
||||
[ $spaces_needed -lt 3 ] && spaces_needed=3
|
||||
|
||||
|
||||
local spacing=""
|
||||
for ((i=0; i<spaces_needed; i++)); do
|
||||
spacing+=" "
|
||||
done
|
||||
|
||||
echo "${description}${spacing}${source}"
|
||||
}
|
||||
|
||||
# ==========================================================
|
||||
show_menu() {
|
||||
while true; do
|
||||
local menu_items=()
|
||||
|
||||
|
||||
declare -A script_commands
|
||||
local counter=1
|
||||
|
||||
for script in "${PROXMENUX_SCRIPTS[@]}"; do
|
||||
IFS='|' read -r name source command <<< "$script"
|
||||
local translated_name="$(translate "$name")"
|
||||
local formatted_item
|
||||
formatted_item=$(format_menu_item "$translated_name" "$source")
|
||||
menu_items+=("$counter" "$formatted_item")
|
||||
script_commands["$counter"]="$command"
|
||||
((counter++))
|
||||
done
|
||||
|
||||
|
||||
menu_items+=("" "")
|
||||
menu_items+=("-" "───────────────────── $(translate "Community Scripts") ──────────────────────")
|
||||
menu_items+=("" "")
|
||||
|
||||
|
||||
for script in "${COMMUNITY_SCRIPTS[@]}"; do
|
||||
IFS='|' read -r name source command <<< "$script"
|
||||
local translated_name="$(translate "$name")"
|
||||
local formatted_item
|
||||
formatted_item=$(format_menu_item "$translated_name" "$source")
|
||||
menu_items+=("$counter" "$formatted_item")
|
||||
script_commands["$counter"]="$command"
|
||||
((counter++))
|
||||
done
|
||||
|
||||
|
||||
menu_items+=("" "")
|
||||
menu_items+=("0" "$(translate "Return to Main Menu")")
|
||||
|
||||
|
||||
exec 3>&1
|
||||
script_selection=$(dialog --clear \
|
||||
--backtitle "ProxMenux" \
|
||||
--title "$(translate "Network Management")" \
|
||||
--menu "\n$(translate "Select a network management option:"):\n" \
|
||||
26 78 19 \
|
||||
"${menu_items[@]}" 2>&1 1>&3)
|
||||
exit_status=$?
|
||||
exec 3>&-
|
||||
|
||||
|
||||
if [ $exit_status -ne 0 ] || [ "$script_selection" = "0" ]; then
|
||||
exec bash <(curl -s "$REPO_URL/scripts/menus/main_menu.sh")
|
||||
fi
|
||||
|
||||
|
||||
if [[ "$script_selection" == "-" || "$script_selection" == "" ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
|
||||
if [[ -n "${script_commands[$script_selection]}" ]]; then
|
||||
eval "${script_commands[$script_selection]}"
|
||||
else
|
||||
msg_error "$(translate "Invalid selection")"
|
||||
sleep 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# ==========================================================
|
||||
show_main_menu
|
||||
|
||||
show_menu
|
||||
|
@ -68,320 +68,99 @@ register_tool() {
|
||||
jq --arg t "$tool" --argjson v "$state" '.[$t]=$v' "$TOOLS_JSON" > "$TOOLS_JSON.tmp" && mv "$TOOLS_JSON.tmp" "$TOOLS_JSON"
|
||||
}
|
||||
|
||||
# ==========================================================
|
||||
lvm_repair_check() {
|
||||
msg_info "$(translate "Checking and repairing old LVM PV headers (if needed)...")"
|
||||
pvs_output=$(LC_ALL=C pvs -v 2>&1 | grep "old PV header")
|
||||
if [ -z "$pvs_output" ]; then
|
||||
msg_ok "$(translate "No PVs with old headers found.")"
|
||||
register_tool "lvm_repair" true
|
||||
return
|
||||
|
||||
|
||||
check_extremeshok_warning() {
|
||||
local marker_file="/etc/extremeshok"
|
||||
|
||||
if [[ -f "$marker_file" ]]; then
|
||||
dialog --backtitle "ProxMenux" --title "xshok-proxmox Post-Install Detected" \
|
||||
--yesno "\n$(translate "It appears that you have already executed the xshok-proxmox post-install script on this system.")\n\n\
|
||||
$(translate "If you continue, some adjustments may be duplicated or conflict with those already made by xshok.")\n\n\
|
||||
$(translate "Do you want to continue anyway?")" 13 70
|
||||
|
||||
local response=$?
|
||||
if [[ $response -ne 0 ]]; then
|
||||
show_proxmenux_logo
|
||||
msg_warn "$(translate "Action cancelled due to previous xshok-proxmox modifications.")"
|
||||
echo -e
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
exit 1
|
||||
fi
|
||||
|
||||
declare -A vg_map
|
||||
while read -r line; do
|
||||
pv=$(echo "$line" | grep -o '/dev/[^ ]*')
|
||||
vg=$(pvs -o vg_name --noheadings "$pv" | awk '{print $1}')
|
||||
if [ -n "$vg" ]; then
|
||||
vg_map["$vg"]=1
|
||||
fi
|
||||
done <<< "$pvs_output"
|
||||
|
||||
for vg in "${!vg_map[@]}"; do
|
||||
msg_warn "$(translate "Old PV header(s) found in VG $vg. Updating metadata...")"
|
||||
vgck --updatemetadata "$vg"
|
||||
vgchange -ay "$vg"
|
||||
if [ $? -ne 0 ]; then
|
||||
msg_warn "$(translate "Metadata update failed for VG $vg. Review manually.")"
|
||||
else
|
||||
msg_ok "$(translate "Metadata updated successfully for VG $vg")"
|
||||
fi
|
||||
done
|
||||
|
||||
msg_ok "$(translate "LVM PV headers check completed")"
|
||||
|
||||
}
|
||||
|
||||
|
||||
# ==========================================================
|
||||
cleanup_duplicate_repos() {
|
||||
local sources_file="/etc/apt/sources.list"
|
||||
local temp_file=$(mktemp)
|
||||
local cleaned_count=0
|
||||
declare -A seen_repos
|
||||
|
||||
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||
if [[ "$line" =~ ^[[:space:]]*# ]] || [[ -z "$line" ]]; then
|
||||
echo "$line" >> "$temp_file"
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$line" =~ ^deb ]]; then
|
||||
read -r _ url dist components <<< "$line"
|
||||
local key="${url}_${dist}"
|
||||
if [[ -v "seen_repos[$key]" ]]; then
|
||||
echo "# $line" >> "$temp_file"
|
||||
cleaned_count=$((cleaned_count + 1))
|
||||
else
|
||||
echo "$line" >> "$temp_file"
|
||||
seen_repos[$key]="$components"
|
||||
fi
|
||||
else
|
||||
echo "$line" >> "$temp_file"
|
||||
fi
|
||||
done < "$sources_file"
|
||||
|
||||
mv "$temp_file" "$sources_file"
|
||||
chmod 644 "$sources_file"
|
||||
|
||||
|
||||
local pve_files=(/etc/apt/sources.list.d/*proxmox*.list /etc/apt/sources.list.d/*pve*.list)
|
||||
local pve_content="deb http://download.proxmox.com/debian/pve ${OS_CODENAME} pve-no-subscription"
|
||||
local pve_public_repo="/etc/apt/sources.list.d/pve-public-repo.list"
|
||||
local pve_public_repo_exists=false
|
||||
|
||||
if [ -f "$pve_public_repo" ] && grep -q "^deb.*pve-no-subscription" "$pve_public_repo"; then
|
||||
pve_public_repo_exists=true
|
||||
fi
|
||||
|
||||
for file in "${pve_files[@]}"; do
|
||||
if [ -f "$file" ] && grep -q "^deb.*pve-no-subscription" "$file"; then
|
||||
if ! $pve_public_repo_exists && [[ "$file" == "$pve_public_repo" ]]; then
|
||||
sed -i 's/^# *deb/deb/' "$file"
|
||||
pve_public_repo_exists=true
|
||||
elif [[ "$file" != "$pve_public_repo" ]]; then
|
||||
sed -i 's/^deb/# deb/' "$file"
|
||||
cleaned_count=$((cleaned_count + 1))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
apt update
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
apt_upgrade() {
|
||||
local pve_version
|
||||
pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+' | head -1)
|
||||
|
||||
|
||||
NECESSARY_REBOOT=1
|
||||
|
||||
|
||||
if [ -f /etc/apt/sources.list.d/pve-enterprise.list ] && grep -q "^deb" /etc/apt/sources.list.d/pve-enterprise.list; then
|
||||
msg_info "$(translate "Disabling enterprise Proxmox repository...")"
|
||||
sed -i "s/^deb/#deb/g" /etc/apt/sources.list.d/pve-enterprise.list
|
||||
msg_ok "$(translate "Enterprise Proxmox repository disabled")"
|
||||
fi
|
||||
|
||||
|
||||
if [ -f /etc/apt/sources.list.d/ceph.list ] && grep -q "^deb" /etc/apt/sources.list.d/ceph.list; then
|
||||
msg_info "$(translate "Disabling enterprise Proxmox Ceph repository...")"
|
||||
sed -i "s/^deb/#deb/g" /etc/apt/sources.list.d/ceph.list
|
||||
msg_ok "$(translate "Enterprise Proxmox Ceph repository disabled")"
|
||||
fi
|
||||
|
||||
|
||||
if [ ! -f /etc/apt/sources.list.d/pve-public-repo.list ] || ! grep -q "pve-no-subscription" /etc/apt/sources.list.d/pve-public-repo.list; then
|
||||
msg_info "$(translate "Enabling free public Proxmox repository...")"
|
||||
echo "deb http://download.proxmox.com/debian/pve ${OS_CODENAME} pve-no-subscription" > /etc/apt/sources.list.d/pve-public-repo.list
|
||||
msg_ok "$(translate "Free public Proxmox repository enabled")"
|
||||
fi
|
||||
|
||||
|
||||
|
||||
sources_file="/etc/apt/sources.list"
|
||||
need_update=false
|
||||
|
||||
|
||||
sed -i 's|ftp.es.debian.org|deb.debian.org|g' "$sources_file"
|
||||
|
||||
|
||||
if grep -q "^deb http://security.debian.org ${OS_CODENAME}-security main contrib" "$sources_file"; then
|
||||
sed -i "s|^deb http://security.debian.org ${OS_CODENAME}-security main contrib|deb http://security.debian.org/debian-security ${OS_CODENAME}-security main contrib non-free non-free-firmware|" "$sources_file"
|
||||
msg_ok "$(translate "Replaced security repository with full version")"
|
||||
need_update=true
|
||||
fi
|
||||
|
||||
|
||||
if ! grep -q "deb http://security.debian.org/debian-security ${OS_CODENAME}-security" "$sources_file"; then
|
||||
echo "deb http://security.debian.org/debian-security ${OS_CODENAME}-security main contrib non-free non-free-firmware" >> "$sources_file"
|
||||
need_update=true
|
||||
fi
|
||||
|
||||
|
||||
if ! grep -q "deb http://deb.debian.org/debian ${OS_CODENAME} " "$sources_file"; then
|
||||
echo "deb http://deb.debian.org/debian ${OS_CODENAME} main contrib non-free non-free-firmware" >> "$sources_file"
|
||||
need_update=true
|
||||
fi
|
||||
|
||||
|
||||
if ! grep -q "deb http://deb.debian.org/debian ${OS_CODENAME}-updates" "$sources_file"; then
|
||||
echo "deb http://deb.debian.org/debian ${OS_CODENAME}-updates main contrib non-free non-free-firmware" >> "$sources_file"
|
||||
need_update=true
|
||||
fi
|
||||
|
||||
msg_ok "$(translate "Debian repositories configured correctly")"
|
||||
|
||||
# ===================================================
|
||||
|
||||
|
||||
if [ ! -f /etc/apt/apt.conf.d/no-bookworm-firmware.conf ]; then
|
||||
msg_info "$(translate "Disabling non-free firmware warnings...")"
|
||||
echo 'APT::Get::Update::SourceListWarnings::NonFreeFirmware "false";' > /etc/apt/apt.conf.d/no-bookworm-firmware.conf
|
||||
msg_ok "$(translate "Non-free firmware warnings disabled")"
|
||||
fi
|
||||
|
||||
|
||||
msg_info "$(translate "Updating package lists...")"
|
||||
if apt-get update > /dev/null 2>&1; then
|
||||
msg_ok "$(translate "Package lists updated")"
|
||||
else
|
||||
msg_error "$(translate "Failed to update package lists")"
|
||||
if [[ -z "$pve_version" ]]; then
|
||||
msg_error "Unable to detect Proxmox version."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ "$pve_version" -ge 9 ]]; then
|
||||
|
||||
msg_info "$(translate "Removing conflicting utilities...")"
|
||||
if /usr/bin/env DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::='--force-confdef' purge ntp openntpd systemd-timesyncd > /dev/null 2>&1; then
|
||||
msg_ok "$(translate "Conflicting utilities removed")"
|
||||
bash <(curl -fsSL "$REPO_URL/scripts/global/update-pve.sh")
|
||||
else
|
||||
msg_error "$(translate "Failed to remove conflicting utilities")"
|
||||
|
||||
bash <(curl -fsSL "$REPO_URL/scripts/global/update-pve8.sh")
|
||||
fi
|
||||
|
||||
|
||||
|
||||
msg_info "$(translate "Performing packages upgrade...")"
|
||||
apt-get install pv -y > /dev/null 2>&1
|
||||
total_packages=$(apt-get -s dist-upgrade | grep "^Inst" | wc -l)
|
||||
|
||||
if [ "$total_packages" -eq 0 ]; then
|
||||
total_packages=1
|
||||
fi
|
||||
msg_ok "$(translate "Packages upgrade successfull")"
|
||||
tput civis
|
||||
tput sc
|
||||
|
||||
|
||||
(
|
||||
/usr/bin/env DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::='--force-confdef' dist-upgrade 2>&1 | \
|
||||
while IFS= read -r line; do
|
||||
if [[ "$line" =~ ^(Setting up|Unpacking|Preparing to unpack|Processing triggers for) ]]; then
|
||||
|
||||
package_name=$(echo "$line" | sed -E 's/.*(Setting up|Unpacking|Preparing to unpack|Processing triggers for) ([^ ]+).*/\2/')
|
||||
|
||||
|
||||
[ -z "$package_name" ] && package_name="$(translate "Unknown")"
|
||||
|
||||
|
||||
tput rc
|
||||
tput ed
|
||||
|
||||
|
||||
row=$(( $(tput lines) - 6 ))
|
||||
tput cup $row 0; echo "$(translate "Installing packages...")"
|
||||
tput cup $((row + 1)) 0; echo "──────────────────────────────────────────────"
|
||||
tput cup $((row + 2)) 0; echo "Package: $package_name"
|
||||
tput cup $((row + 3)) 0; echo "Progress: [ ] 0%"
|
||||
tput cup $((row + 4)) 0; echo "──────────────────────────────────────────────"
|
||||
|
||||
|
||||
for i in $(seq 1 10); do
|
||||
progress=$((i * 10))
|
||||
tput cup $((row + 3)) 9
|
||||
printf "[%-50s] %3d%%" "$(printf "#%.0s" $(seq 1 $((progress/2))))" "$progress"
|
||||
|
||||
done
|
||||
fi
|
||||
done
|
||||
)
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
tput rc
|
||||
tput ed
|
||||
msg_ok "$(translate "System upgrade completed")"
|
||||
fi
|
||||
|
||||
|
||||
|
||||
msg_info "$(translate "Installing additional Proxmox packages...")"
|
||||
if /usr/bin/env DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::='--force-confdef' install zfsutils-linux proxmox-backup-restore-image chrony > /dev/null 2>&1; then
|
||||
msg_ok "$(translate "Additional Proxmox packages installed")"
|
||||
else
|
||||
msg_error "$(translate "Failed to install additional Proxmox packages")"
|
||||
fi
|
||||
|
||||
lvm_repair_check
|
||||
|
||||
cleanup_duplicate_repos
|
||||
|
||||
msg_ok "$(translate "Proxmox update completed")"
|
||||
|
||||
}
|
||||
|
||||
# ==========================================================
|
||||
remove_subscription_banner_() {
|
||||
msg_info "$(translate "Removing Proxmox subscription nag banner...")"
|
||||
local JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js"
|
||||
local GZ_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.gz"
|
||||
local APT_HOOK="/etc/apt/apt.conf.d/no-nag-script"
|
||||
|
||||
if [[ ! -f "$APT_HOOK" ]]; then
|
||||
cat <<'EOF' > "$APT_HOOK"
|
||||
DPkg::Post-Invoke { "dpkg -V proxmox-widget-toolkit | grep -q '/proxmoxlib\.js$'; if [ $? -eq 1 ]; then { echo 'Removing subscription nag from UI...'; sed -i '/.*data\.status.*{/{s/\!//;s/active/NoMoreNagging/;s/Active/NoMoreNagging/}' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js; rm -f /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.gz; }; fi"; };
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [[ -f "$JS_FILE" ]]; then
|
||||
sed -i '/.*data\.status.*{/{s/\!//;s/active/NoMoreNagging/;s/Active/NoMoreNagging/}' "$JS_FILE"
|
||||
[[ -f "$GZ_FILE" ]] && rm -f "$GZ_FILE"
|
||||
touch "$JS_FILE"
|
||||
fi
|
||||
|
||||
apt --reinstall install proxmox-widget-toolkit -y > /dev/null 2>&1
|
||||
|
||||
msg_ok "$(translate "Subscription nag banner removed successfully")"
|
||||
register_tool "subscription_banner" true
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
remove_subscription_banner() {
|
||||
local JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js"
|
||||
local GZ_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.gz"
|
||||
local APT_HOOK="/etc/apt/apt.conf.d/no-nag-script"
|
||||
local pve_version
|
||||
pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+' | head -1)
|
||||
|
||||
# Detect if already applied
|
||||
if grep -q "NoMoreNagging" "$JS_FILE" 2>/dev/null && [[ -f "$APT_HOOK" ]]; then
|
||||
# Already applied, just reapply silently
|
||||
:
|
||||
else
|
||||
# Ask user
|
||||
if ! whiptail --title "$(translate "Proxmox Subscription Banner")" \
|
||||
--yesno "$(translate "Do you want to remove the Proxmox subscription banner from the web interface?")" 10 60; then
|
||||
msg_warn "$(translate "Banner removal cancelled by user.")"
|
||||
if [[ -z "$pve_version" ]]; then
|
||||
msg_error "Unable to detect Proxmox version."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ "$pve_version" -ge 9 ]]; then
|
||||
if ! whiptail --title "Proxmox VE 9.x Subscription Banner Removal" \
|
||||
--yesno "Do you want to remove the Proxmox subscription banner from the web interface for PVE $pve_version?" 10 70; then
|
||||
msg_warn "Banner removal cancelled by user."
|
||||
return 1
|
||||
fi
|
||||
|
||||
msg_info "$(translate "Removing Proxmox subscription nag banner...")"
|
||||
|
||||
if [[ ! -f "$APT_HOOK" ]]; then
|
||||
cat <<'EOF' > "$APT_HOOK"
|
||||
DPkg::Post-Invoke { "dpkg -V proxmox-widget-toolkit | grep -q '/proxmoxlib\.js$'; if [ $? -eq 1 ]; then { echo 'Removing subscription nag from UI...'; sed -i '/.*data\.status.*{/{s/\!//;s/active/NoMoreNagging/;s/Active/NoMoreNagging/}' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js; rm -f /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.gz; }; fi"; };
|
||||
EOF
|
||||
bash <(curl -fsSL "$REPO_URL/scripts/global/remove-banner-pve9.sh")
|
||||
else
|
||||
if ! whiptail --title "Proxmox VE 8.x Subscription Banner Removal" \
|
||||
--yesno "Do you want to remove the Proxmox subscription banner from the web interface for PVE $pve_version?" 10 70; then
|
||||
msg_warn "Banner removal cancelled by user."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ -f "$JS_FILE" ]]; then
|
||||
sed -i '/.*data\.status.*{/{s/\!//;s/active/NoMoreNagging/;s/Active/NoMoreNagging/}' "$JS_FILE"
|
||||
[[ -f "$GZ_FILE" ]] && rm -f "$GZ_FILE"
|
||||
touch "$JS_FILE"
|
||||
bash <(curl -fsSL "$REPO_URL/scripts/global/remove-banner-pve8.sh")
|
||||
fi
|
||||
|
||||
apt --reinstall install proxmox-widget-toolkit -y > /dev/null 2>&1
|
||||
|
||||
msg_ok "$(translate "Subscription nag banner removed successfully")"
|
||||
register_tool "subscription_banner" true
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# ==========================================================
|
||||
|
||||
|
||||
@ -713,7 +492,7 @@ disable_rpc() {
|
||||
}
|
||||
|
||||
# ==========================================================
|
||||
customize_bashrc() {
|
||||
customize_bashrc_() {
|
||||
msg_info "$(translate "Customizing bashrc for root user...")"
|
||||
local bashrc="/root/.bashrc"
|
||||
local bash_profile="/root/.bash_profile"
|
||||
@ -746,53 +525,149 @@ EOF
|
||||
register_tool "bashrc_custom" true
|
||||
}
|
||||
|
||||
|
||||
|
||||
customize_bashrc() {
|
||||
msg_info "$(translate "Customizing bashrc for root user...")"
|
||||
local bashrc="/root/.bashrc"
|
||||
local bash_profile="/root/.bash_profile"
|
||||
local marker_begin="# BEGIN PMX_CORE_BASHRC"
|
||||
local marker_end="# END PMX_CORE_BASHRC"
|
||||
|
||||
|
||||
[ -f "${bashrc}.bak" ] || cp "$bashrc" "${bashrc}.bak" > /dev/null 2>&1
|
||||
|
||||
|
||||
if grep -q "^${marker_begin}$" "$bashrc" 2>/dev/null; then
|
||||
sed -i "/^${marker_begin}$/,/^${marker_end}$/d" "$bashrc"
|
||||
fi
|
||||
|
||||
|
||||
cat >> "$bashrc" << 'EOF'
|
||||
${marker_begin}
|
||||
# ProxMenux core customizations
|
||||
export HISTTIMEFORMAT="%d/%m/%y %T "
|
||||
export PS1="\[\e[31m\][\[\e[m\]\[\e[38;5;172m\]\u\[\e[m\]@\[\e[38;5;153m\]\h\[\e[m\] \[\e[38;5;214m\]\W\[\e[m\]\[\e[31m\]]\[\e[m\]\\$ "
|
||||
alias l='ls -CF'
|
||||
alias la='ls -A'
|
||||
alias ll='ls -alF'
|
||||
alias ls='ls --color=auto'
|
||||
alias grep='grep --color=auto'
|
||||
alias fgrep='fgrep --color=auto'
|
||||
alias egrep='egrep --color=auto'
|
||||
source /etc/profile.d/bash_completion.sh
|
||||
${marker_end}
|
||||
EOF
|
||||
|
||||
|
||||
if ! grep -q "source /root/.bashrc" "$bash_profile" 2>/dev/null; then
|
||||
echo "source /root/.bashrc" >> "$bash_profile" 2>/dev/null
|
||||
fi
|
||||
|
||||
msg_ok "$(translate "Bashrc customization completed")"
|
||||
register_tool "bashrc_custom" true
|
||||
}
|
||||
|
||||
|
||||
|
||||
# ==========================================================
|
||||
|
||||
|
||||
|
||||
install_log2ram_auto() {
|
||||
|
||||
msg_info "$(translate "Checking if system disk is SSD or M.2...")"
|
||||
|
||||
local is_ssd=false
|
||||
local pool disks disk byid_path dev rot
|
||||
|
||||
if grep -qE '^root=ZFS=' /etc/kernel/cmdline 2>/dev/null || mount | grep -q 'on / type zfs'; then
|
||||
|
||||
pool=$(zfs list -Ho name,mountpoint 2>/dev/null | awk '$2=="/"{print $1}' | cut -d/ -f1)
|
||||
disks=$(zpool status "$pool" 2>/dev/null | awk '/ONLINE/ && $1 !~ /:|mirror|raidz|log|spare|config|NAME|rpool|state/ {print $1}' | sort -u)
|
||||
|
||||
is_ssd=true
|
||||
for disk in $disks; do
|
||||
byid_path=$(readlink -f /dev/disk/by-id/*$disk* 2>/dev/null) || continue
|
||||
dev=$(basename "$byid_path" | sed -E 's|[0-9]+$||' | sed -E 's|p$||')
|
||||
rot=$(cat /sys/block/$dev/queue/rotational 2>/dev/null)
|
||||
[[ "$rot" != "0" ]] && is_ssd=false && break
|
||||
done
|
||||
else
|
||||
|
||||
ROOT_PART=$(lsblk -no NAME,MOUNTPOINT | grep ' /$' | awk '{print $1}')
|
||||
SYSTEM_DISK=$(lsblk -no PKNAME /dev/$ROOT_PART 2>/dev/null)
|
||||
SYSTEM_DISK=${SYSTEM_DISK:-sda}
|
||||
|
||||
if [[ "$SYSTEM_DISK" == nvme* || "$(cat /sys/block/$SYSTEM_DISK/queue/rotational 2>/dev/null)" == "0" ]]; then
|
||||
msg_ok "$(translate "System disk ($SYSTEM_DISK) is SSD or M.2. Proceeding with Log2RAM setup.")"
|
||||
is_ssd=true
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$is_ssd" == true ]]; then
|
||||
msg_ok "$(translate "System disk is SSD or M.2. Proceeding with Log2RAM setup.")"
|
||||
else
|
||||
msg_warn "$(translate "System disk ($SYSTEM_DISK) is not SSD/M.2. Skipping Log2RAM installation.")"
|
||||
msg_warn "$(translate "System disk is not SSD/M.2. Skipping Log2RAM installation.")"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Clean up previous state
|
||||
rm -rf /tmp/log2ram
|
||||
rm -f /etc/systemd/system/log2ram*
|
||||
rm -f /etc/systemd/system/log2ram-daily.*
|
||||
rm -f /etc/cron.d/log2ram*
|
||||
rm -f /usr/sbin/log2ram
|
||||
rm -f /etc/log2ram.conf
|
||||
rm -f /usr/local/bin/log2ram-check.sh
|
||||
rm -rf /var/log.hdd
|
||||
systemctl daemon-reexec >/dev/null 2>&1
|
||||
systemctl daemon-reload >/dev/null 2>&1
|
||||
|
||||
msg_info "$(translate "Installing log2ram from GitHub...")"
|
||||
if [[ -f /etc/log2ram.conf ]] && command -v log2ram >/dev/null 2>&1 && systemctl list-units --all | grep -q log2ram; then
|
||||
msg_ok "$(translate "Log2RAM is already installed and configured correctly.")"
|
||||
register_tool "log2ram" true
|
||||
return 0
|
||||
fi
|
||||
|
||||
msg_info "$(translate "Log2RAM proceeding with installation...")"
|
||||
|
||||
|
||||
if [[ -d /tmp/log2ram ]]; then
|
||||
rm -rf /tmp/log2ram
|
||||
fi
|
||||
|
||||
|
||||
[[ -f /etc/systemd/system/log2ram.service ]] && rm -f /etc/systemd/system/log2ram*
|
||||
[[ -f /etc/systemd/system/log2ram-daily.service ]] && rm -f /etc/systemd/system/log2ram-daily.*
|
||||
[[ -f /etc/cron.d/log2ram ]] && rm -f /etc/cron.d/log2ram*
|
||||
[[ -f /usr/sbin/log2ram ]] && rm -f /usr/sbin/log2ram
|
||||
[[ -f /etc/log2ram.conf ]] && rm -f /etc/log2ram.conf
|
||||
[[ -f /usr/local/bin/log2ram-check.sh ]] && rm -f /usr/local/bin/log2ram-check.sh
|
||||
[[ -d /var/log.hdd ]] && rm -rf /var/log.hdd
|
||||
|
||||
systemctl daemon-reexec >/dev/null 2>&1 || true
|
||||
systemctl daemon-reload >/dev/null 2>&1 || true
|
||||
|
||||
|
||||
|
||||
if ! command -v git >/dev/null 2>&1; then
|
||||
apt-get update -qq >/dev/null 2>&1
|
||||
apt-get install -y git >/dev/null 2>&1
|
||||
msg_ok "$(translate "Git installed successfully")"
|
||||
fi
|
||||
|
||||
git clone https://github.com/azlux/log2ram.git /tmp/log2ram >/dev/null 2>>/tmp/log2ram_install.log
|
||||
cd /tmp/log2ram || return 1
|
||||
bash install.sh >>/tmp/log2ram_install.log 2>&1
|
||||
|
||||
if [[ -f /etc/log2ram.conf ]] && systemctl list-units --all | grep -q log2ram; then
|
||||
msg_ok "$(translate "Log2RAM installed successfully")"
|
||||
else
|
||||
msg_error "$(translate "Failed to install Log2RAM. See /tmp/log2ram_install.log")"
|
||||
if ! git clone https://github.com/azlux/log2ram.git /tmp/log2ram >/dev/null 2>>/tmp/log2ram_install.log; then
|
||||
msg_error "$(translate "Failed to clone log2ram repository. Check /tmp/log2ram_install.log")"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Detect RAM
|
||||
cd /tmp/log2ram || {
|
||||
msg_error "$(translate "Failed to access log2ram directory")"
|
||||
return 1
|
||||
}
|
||||
|
||||
if ! bash install.sh >>/tmp/log2ram_install.log 2>&1; then
|
||||
msg_error "$(translate "Failed to run log2ram installer. Check /tmp/log2ram_install.log")"
|
||||
return 1
|
||||
fi
|
||||
|
||||
|
||||
if [[ -f /etc/log2ram.conf ]] && command -v log2ram >/dev/null 2>&1; then
|
||||
msg_ok "$(translate "Log2RAM installed successfully")"
|
||||
else
|
||||
msg_error "$(translate "Log2RAM installation verification failed. Check /tmp/log2ram_install.log")"
|
||||
return 1
|
||||
fi
|
||||
|
||||
|
||||
RAM_SIZE_GB=$(free -g | awk '/^Mem:/{print $2}')
|
||||
[[ -z "$RAM_SIZE_GB" || "$RAM_SIZE_GB" -eq 0 ]] && RAM_SIZE_GB=4
|
||||
|
||||
@ -809,10 +684,21 @@ install_log2ram_auto() {
|
||||
|
||||
msg_ok "$(translate "Detected RAM:") $RAM_SIZE_GB GB — $(translate "Log2RAM size set to:") $LOG2RAM_SIZE"
|
||||
|
||||
|
||||
sed -i "s/^SIZE=.*/SIZE=$LOG2RAM_SIZE/" /etc/log2ram.conf
|
||||
LOG2RAM_BIN="$(command -v log2ram || echo /usr/local/bin/log2ram)"
|
||||
rm -f /etc/cron.daily/log2ram /etc/cron.weekly/log2ram /etc/cron.monthly/log2ram 2>/dev/null || true
|
||||
rm -f /etc/cron.hourly/log2ram
|
||||
echo "0 */$CRON_HOURS * * * root /usr/sbin/log2ram write" > /etc/cron.d/log2ram
|
||||
msg_ok "$(translate "log2ram write scheduled every") $CRON_HOURS $(translate "hour(s)")"
|
||||
|
||||
{
|
||||
echo 'MAILTO=""'
|
||||
echo "0 */$CRON_HOURS * * * root $LOG2RAM_BIN write >/dev/null 2>&1"
|
||||
} > /etc/cron.d/log2ram
|
||||
|
||||
chmod 0644 /etc/cron.d/log2ram
|
||||
chown root:root /etc/cron.d/log2ram
|
||||
msg_ok "$(translate "Log2RAM write scheduled every") $CRON_HOURS $(translate "hour(s)")"
|
||||
|
||||
|
||||
cat << 'EOF' > /usr/local/bin/log2ram-check.sh
|
||||
#!/bin/bash
|
||||
@ -820,19 +706,77 @@ CONF_FILE="/etc/log2ram.conf"
|
||||
LIMIT_KB=$(grep '^SIZE=' "$CONF_FILE" | cut -d'=' -f2 | tr -d 'M')000
|
||||
USED_KB=$(df /var/log --output=used | tail -1)
|
||||
THRESHOLD=$(( LIMIT_KB * 90 / 100 ))
|
||||
|
||||
if (( USED_KB > THRESHOLD )); then
|
||||
/usr/sbin/log2ram write
|
||||
$(command -v log2ram) write
|
||||
fi
|
||||
EOF
|
||||
|
||||
chmod +x /usr/local/bin/log2ram-check.sh
|
||||
echo "*/5 * * * * root /usr/local/bin/log2ram-check.sh" > /etc/cron.d/log2ram-auto-sync
|
||||
{
|
||||
echo 'MAILTO=""'
|
||||
echo "*/5 * * * * root /usr/local/bin/log2ram-check.sh >/dev/null 2>&1"
|
||||
} > /etc/cron.d/log2ram-auto-sync
|
||||
chmod 0644 /etc/cron.d/log2ram-auto-sync
|
||||
chown root:root /etc/cron.d/log2ram-auto-sync
|
||||
msg_ok "$(translate "Auto-sync enabled when /var/log exceeds 90% of") $LOG2RAM_SIZE"
|
||||
|
||||
|
||||
register_tool "log2ram" true
|
||||
}
|
||||
|
||||
|
||||
|
||||
# ==========================================================
|
||||
|
||||
|
||||
setup_persistent_network() {
|
||||
local LINK_DIR="/etc/systemd/network"
|
||||
local BACKUP_DIR="/etc/systemd/network/backup-$(date +%Y%m%d-%H%M%S)"
|
||||
|
||||
|
||||
|
||||
msg_info "$(translate "Setting up persistent network interfaces")"
|
||||
sleep 2
|
||||
|
||||
mkdir -p "$LINK_DIR"
|
||||
|
||||
if ls "$LINK_DIR"/*.link >/dev/null 2>&1; then
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
cp "$LINK_DIR"/*.link "$BACKUP_DIR"/ 2>/dev/null || true
|
||||
fi
|
||||
|
||||
local count=0
|
||||
for iface in $(ls /sys/class/net/ | grep -vE "lo|docker|veth|br-|vmbr|tap|fwpr|fwln|virbr|bond|cilium|zt|wg"); do
|
||||
if [[ -e "/sys/class/net/$iface/device" ]] || [[ -e "/sys/class/net/$iface/phy80211" ]]; then
|
||||
local MAC=$(cat /sys/class/net/$iface/address 2>/dev/null)
|
||||
|
||||
if [[ "$MAC" =~ ^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$ ]]; then
|
||||
local LINK_FILE="$LINK_DIR/10-$iface.link"
|
||||
|
||||
cat > "$LINK_FILE" <<EOF
|
||||
[Match]
|
||||
MACAddress=$MAC
|
||||
|
||||
[Link]
|
||||
Name=$iface
|
||||
EOF
|
||||
chmod 644 "$LINK_FILE"
|
||||
((count++))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $count -gt 0 ]]; then
|
||||
msg_ok "$(translate "Created persistent names for") $count $(translate "interfaces")"
|
||||
msg_ok "$(translate "Changes will apply after reboot.")"
|
||||
else
|
||||
msg_warn "$(translate "No physical interfaces found")"
|
||||
fi
|
||||
register_tool "persistent_network" true
|
||||
|
||||
}
|
||||
|
||||
|
||||
# ==========================================================
|
||||
|
||||
run_complete_optimization() {
|
||||
@ -857,6 +801,7 @@ run_complete_optimization() {
|
||||
disable_rpc
|
||||
customize_bashrc
|
||||
install_log2ram_auto
|
||||
setup_persistent_network
|
||||
|
||||
|
||||
echo -e
|
||||
@ -888,7 +833,7 @@ run_complete_optimization() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
check_extremeshok_warning
|
||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||||
run_complete_optimization
|
||||
fi
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -49,7 +49,7 @@ register_tool() {
|
||||
################################################################
|
||||
|
||||
uninstall_fastfetch() {
|
||||
if ! command -v fastfetch &>/dev/null; then
|
||||
if ! command -v fastfetch &>/dev/null && [[ ! -f /usr/local/bin/fastfetch ]]; then
|
||||
msg_warn "$(translate "Fastfetch is not installed.")"
|
||||
return 0
|
||||
fi
|
||||
@ -58,7 +58,8 @@ uninstall_fastfetch() {
|
||||
rm -f /usr/local/bin/fastfetch /usr/bin/fastfetch
|
||||
rm -rf "$HOME/.config/fastfetch"
|
||||
rm -rf /usr/local/share/fastfetch
|
||||
sed -i '/fastfetch/d' "$HOME/.bashrc" "$HOME/.profile" 2>/dev/null
|
||||
sed -i '/fastfetch/d' "$HOME/.bashrc" "$HOME/.profile" /etc/profile 2>/dev/null
|
||||
sed -i '/# BEGIN FASTFETCH/,/# END FASTFETCH/d' "$HOME/.bashrc"
|
||||
rm -f /etc/profile.d/fastfetch.sh /etc/update-motd.d/99-fastfetch
|
||||
dpkg -r fastfetch &>/dev/null
|
||||
|
||||
@ -68,7 +69,7 @@ uninstall_fastfetch() {
|
||||
|
||||
################################################################
|
||||
|
||||
uninstall_figurine() {
|
||||
uninstall_figurine_() {
|
||||
if ! command -v figurine &>/dev/null; then
|
||||
msg_warn "$(translate "Figurine is not installed.")"
|
||||
return 0
|
||||
@ -83,6 +84,26 @@ uninstall_figurine() {
|
||||
register_tool "figurine" false
|
||||
}
|
||||
|
||||
|
||||
uninstall_figurine() {
|
||||
if ! command -v figurine &>/dev/null; then
|
||||
msg_warn "$(translate "Figurine is not installed.")"
|
||||
return 0
|
||||
fi
|
||||
|
||||
msg_info2 "$(translate "Uninstalling Figurine...")"
|
||||
rm -f /usr/local/bin/figurine
|
||||
rm -f /etc/profile.d/figurine.sh
|
||||
|
||||
sed -i '/lxcclean/d;/lxcupdate/d;/kernelclean/d;/cpugov/d;/updatecerts/d;/seqwrite/d;/seqread/d;/ranwrite/d;/ranread/d' "$HOME/.bashrc" "$HOME/.profile" 2>/dev/null
|
||||
sed -i '/# ProxMenux Figurine aliases and tools/,+20d' "$HOME/.bashrc" "$HOME/.profile" 2>/dev/null
|
||||
sed -i '/# BEGIN PROXMENUX ALIASES/,/# END PROXMENUX ALIASES/d' "$HOME/.bashrc" "$HOME/.profile" 2>/dev/null
|
||||
|
||||
msg_ok "$(translate "Figurine removed from system")"
|
||||
register_tool "figurine" false
|
||||
}
|
||||
|
||||
|
||||
################################################################
|
||||
|
||||
uninstall_kexec() {
|
||||
@ -445,6 +466,29 @@ uninstall_log2ram() {
|
||||
register_tool "log2ram" false
|
||||
}
|
||||
|
||||
|
||||
################################################################
|
||||
|
||||
uninstall_persistent_network() {
|
||||
local LINK_DIR="/etc/systemd/network"
|
||||
|
||||
msg_info "$(translate "Removing all .link files from") $LINK_DIR"
|
||||
sleep 2
|
||||
|
||||
if ! ls "$LINK_DIR"/*.link >/dev/null 2>&1; then
|
||||
msg_warn "$(translate "No .link files found in") $LINK_DIR"
|
||||
return 0
|
||||
fi
|
||||
|
||||
rm -f "$LINK_DIR"/*.link
|
||||
|
||||
msg_ok "$(translate "Removed all .link files from") $LINK_DIR"
|
||||
msg_info "$(translate "Interface names will return to default systemd behavior.")"
|
||||
register_tool "persistent_network" false
|
||||
}
|
||||
|
||||
|
||||
|
||||
################################################################
|
||||
|
||||
migrate_installed_tools() {
|
||||
@ -553,10 +597,14 @@ show_uninstall_menu() {
|
||||
memory_settings) desc="Memory Settings Optimization";;
|
||||
kernel_panic) desc="Kernel Panic Configuration";;
|
||||
apt_ipv4) desc="APT IPv4 Force";;
|
||||
kexec) desc="kexec for quick reboots";;
|
||||
network_optimization) desc="Network Optimizations";;
|
||||
disable_rpc) desc="RPC/rpcbind Disable";;
|
||||
bashrc_custom) desc="Bashrc Customization";;
|
||||
figurine) desc="Figurine";;
|
||||
fastfetch) desc="Fastfetch";;
|
||||
log2ram) desc="Log2ram (SSD Protection)";;
|
||||
persistent_network) desc="Setting persistent network interfaces";;
|
||||
*) desc="$tool";;
|
||||
esac
|
||||
menu_options+=("$tool" "$desc" "off")
|
||||
|
@ -1,13 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# ProxMenu - A menu-driven script for Proxmox VE management
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : MIT (https://raw.githubusercontent.com/MacRimi/ProxMenux/main/LICENSE)
|
||||
# Version : 1.1
|
||||
# Last Updated: 28/06/2025
|
||||
# Version : 1.2
|
||||
# Last Updated: 30/07/2025
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script allows users to assign physical disks to existing
|
||||
@ -17,6 +16,7 @@
|
||||
# - Identifies and displays unassigned physical disks.
|
||||
# - Allows the user to select multiple disks and attach them to a CT.
|
||||
# - Configures the selected disks for the CT and verifies the assignment.
|
||||
# - Uses persistent device paths to avoid issues with device order changes.
|
||||
# ==========================================================
|
||||
|
||||
# Configuration ============================================
|
||||
@ -32,8 +32,66 @@ fi
|
||||
load_language
|
||||
initialize_cache
|
||||
|
||||
# Get OS codename for repository configuration
|
||||
OS_CODENAME="$(grep "VERSION_CODENAME=" /etc/os-release | cut -d"=" -f 2 | xargs )"
|
||||
|
||||
# ==========================================================
|
||||
|
||||
# Function to get persistent device path
|
||||
get_persistent_path() {
|
||||
local device="$1"
|
||||
local persistent_path=""
|
||||
|
||||
# Try by-id first (most reliable)
|
||||
for path in /dev/disk/by-id/*; do
|
||||
if [[ -e "$path" && "$(readlink -f "$path")" == "$device" ]]; then
|
||||
# Prefer ata- or scsi- over wwn- for readability
|
||||
if [[ "$path" =~ ata-|scsi- ]]; then
|
||||
echo "$path"
|
||||
return 0
|
||||
elif [[ -z "$persistent_path" ]]; then
|
||||
persistent_path="$path"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Return the first found by-id path if any
|
||||
if [[ -n "$persistent_path" ]]; then
|
||||
echo "$persistent_path"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Try by-path as fallback
|
||||
for path in /dev/disk/by-path/*; do
|
||||
if [[ -e "$path" && "$(readlink -f "$path")" == "$device" ]]; then
|
||||
echo "$path"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Fallback to original device if no persistent path found
|
||||
msg_warn "$(translate "No persistent path found for") $device, $(translate "using direct path")"
|
||||
echo "$device"
|
||||
}
|
||||
|
||||
# Function to ensure repositories are properly configured
|
||||
ensure_repositories() {
|
||||
local sources_file="/etc/apt/sources.list"
|
||||
local need_update=false
|
||||
|
||||
# Only verify the main repository with contrib and non-free
|
||||
if ! grep -q "deb.*${OS_CODENAME}.*main" "$sources_file"; then
|
||||
echo "deb http://deb.debian.org/debian ${OS_CODENAME} main contrib non-free non-free-firmware" >> "$sources_file"
|
||||
need_update=true
|
||||
fi
|
||||
|
||||
if [ "$need_update" = true ]; then
|
||||
apt update >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
get_disk_info() {
|
||||
local disk=$1
|
||||
MODEL=$(lsblk -dn -o MODEL "$disk" | xargs)
|
||||
@ -41,8 +99,10 @@ get_disk_info() {
|
||||
echo "$MODEL" "$SIZE"
|
||||
}
|
||||
|
||||
CT_LIST=$(pct list | awk 'NR>1 {print $1, $3}')
|
||||
# Ensure repositories are configured
|
||||
ensure_repositories
|
||||
|
||||
CT_LIST=$(pct list | awk 'NR>1 {print $1, $3}')
|
||||
if [ -z "$CT_LIST" ]; then
|
||||
whiptail --title "$(translate "Error")" --msgbox "$(translate "No CTs available in the system.")" 8 40
|
||||
exit 1
|
||||
@ -60,12 +120,11 @@ CTID=$(echo "$CTID" | tr -d '"')
|
||||
clear
|
||||
show_proxmenux_logo
|
||||
echo -e
|
||||
msg_info2 "$(translate "Add Disk") Passthrough $(translate "to a LXC")"
|
||||
msg_title "$(translate "Add Disk") Passthrough $(translate "to a LXC")"
|
||||
echo -e
|
||||
msg_ok "$(translate "CT selected successfully.")"
|
||||
|
||||
CT_STATUS=$(pct status "$CTID" | awk '{print $2}')
|
||||
|
||||
if [ "$CT_STATUS" != "running" ]; then
|
||||
msg_info "$(translate "Starting CT") $CTID..."
|
||||
pct start "$CTID"
|
||||
@ -79,10 +138,10 @@ if [ "$CT_STATUS" != "running" ]; then
|
||||
fi
|
||||
|
||||
CONF_FILE="/etc/pve/lxc/$CTID.conf"
|
||||
|
||||
if grep -q '^unprivileged: 1' "$CONF_FILE"; then
|
||||
if whiptail --title "$(translate "Privileged Container")" \
|
||||
--yesno "$(translate "The selected container is unprivileged. A privileged container is required for direct device passthrough.")\\n\\n$(translate "Do you want to convert it to a privileged container now?")" 12 70; then
|
||||
|
||||
msg_info "$(translate "Stopping container") $CTID..."
|
||||
pct shutdown "$CTID" &>/dev/null
|
||||
for i in {1..10}; do
|
||||
@ -91,15 +150,18 @@ if grep -q '^unprivileged: 1' "$CONF_FILE"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$(pct status "$CTID" | awk '{print $2}')" == "running" ]; then
|
||||
msg_error "$(translate "Failed to stop the container.")"
|
||||
exit 1
|
||||
fi
|
||||
msg_ok "$(translate "Container stopped.")"
|
||||
|
||||
cp "$CONF_FILE" "$CONF_FILE.bak"
|
||||
sed -i '/^unprivileged: 1/d' "$CONF_FILE"
|
||||
echo "unprivileged: 0" >> "$CONF_FILE"
|
||||
msg_ok "$(translate "Container successfully converted to privileged.")"
|
||||
|
||||
msg_info "$(translate "Starting container") $CTID..."
|
||||
pct start "$CTID" &>/dev/null
|
||||
sleep 2
|
||||
@ -123,7 +185,6 @@ MOUNTED_DISKS=$(lsblk -ln -o NAME,MOUNTPOINT | awk '$2!="" {print "/dev/" $1}')
|
||||
|
||||
ZFS_DISKS=""
|
||||
ZFS_RAW=$(zpool list -v -H 2>/dev/null | awk '{print $1}' | grep -v '^NAME$' | grep -v '^-' | grep -v '^mirror')
|
||||
|
||||
for entry in $ZFS_RAW; do
|
||||
path=""
|
||||
if [[ "$entry" == wwn-* || "$entry" == ata-* ]]; then
|
||||
@ -133,6 +194,7 @@ for entry in $ZFS_RAW; do
|
||||
elif [[ "$entry" == /dev/* ]]; then
|
||||
path="$entry"
|
||||
fi
|
||||
|
||||
if [ -n "$path" ]; then
|
||||
base_disk=$(lsblk -no PKNAME "$path" 2>/dev/null)
|
||||
if [ -n "$base_disk" ]; then
|
||||
@ -140,7 +202,6 @@ for entry in $ZFS_RAW; do
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
ZFS_DISKS=$(echo "$ZFS_DISKS" | sort -u)
|
||||
|
||||
is_disk_in_use() {
|
||||
@ -154,6 +215,7 @@ is_disk_in_use() {
|
||||
return 0
|
||||
fi
|
||||
done < <(lsblk -ln -o NAME,FSTYPE "$disk" | tail -n +2)
|
||||
|
||||
if echo "$USED_DISKS" | grep -q "$disk" || echo "$ZFS_DISKS" | grep -q "$disk"; then
|
||||
return 0
|
||||
fi
|
||||
@ -166,6 +228,7 @@ RAID_ACTIVE=$(grep -Po 'md\d+\s*:\s*active\s+raid[0-9]+' /proc/mdstat | awk '{pr
|
||||
|
||||
while read -r DISK; do
|
||||
[[ "$DISK" =~ /dev/zd ]] && continue
|
||||
|
||||
INFO=($(get_disk_info "$DISK"))
|
||||
MODEL="${INFO[@]::${#INFO[@]}-1}"
|
||||
SIZE="${INFO[-1]}"
|
||||
@ -193,6 +256,7 @@ while read -r DISK; do
|
||||
USED_BY=""
|
||||
REAL_PATH=$(readlink -f "$DISK")
|
||||
CONFIG_DATA=$(grep -vE '^\s*#' /etc/pve/qemu-server/*.conf /etc/pve/lxc/*.conf 2>/dev/null)
|
||||
|
||||
if grep -Fq "$REAL_PATH" <<< "$CONFIG_DATA"; then
|
||||
USED_BY="⚠ $(translate "In use")"
|
||||
else
|
||||
@ -220,8 +284,15 @@ while read -r DISK; do
|
||||
SHOW_DISK=false
|
||||
fi
|
||||
|
||||
# Check if disk is already assigned to this CT using persistent paths
|
||||
if pct config "$CTID" | grep -vE '^\s*#|^description:' | grep -q "$DISK"; then
|
||||
SHOW_DISK=false
|
||||
else
|
||||
# Also check persistent paths
|
||||
PERSISTENT_DISK=$(get_persistent_path "$DISK")
|
||||
if [[ "$PERSISTENT_DISK" != "$DISK" ]] && pct config "$CTID" | grep -vE '^\s*#|^description:' | grep -q "$PERSISTENT_DISK"; then
|
||||
SHOW_DISK=false
|
||||
fi
|
||||
fi
|
||||
|
||||
if $SHOW_DISK; then
|
||||
@ -229,6 +300,7 @@ while read -r DISK; do
|
||||
[[ "$IS_RAID" == true ]] && LABEL+=" ⚠ RAID"
|
||||
[[ "$IS_LVM" == true ]] && LABEL+=" ⚠ LVM"
|
||||
[[ "$IS_ZFS" == true ]] && LABEL+=" ⚠ ZFS"
|
||||
|
||||
DESCRIPTION=$(printf "%-30s %10s%s" "$MODEL" "$SIZE" "$LABEL")
|
||||
FREE_DISKS+=("$DISK" "$DESCRIPTION" "OFF")
|
||||
fi
|
||||
@ -270,6 +342,7 @@ msg_info "$(translate "Processing selected disks...")"
|
||||
for DISK in $SELECTED; do
|
||||
DISK=$(echo "$DISK" | tr -d '"')
|
||||
DISK_INFO=$(get_disk_info "$DISK")
|
||||
|
||||
ASSIGNED_TO=""
|
||||
RUNNING_CTS=""
|
||||
RUNNING_VMS=""
|
||||
@ -309,6 +382,7 @@ for DISK in $SELECTED; do
|
||||
fi
|
||||
|
||||
cleanup
|
||||
|
||||
if lsblk "$DISK" | grep -q "raid" || grep -q "${DISK##*/}" /proc/mdstat; then
|
||||
whiptail --title "$(translate "RAID Detected")" --msgbox "$(translate "The disk") $DISK_INFO $(translate "appears to be part of a") RAID. $(translate "For security reasons, the system cannot format it.")\\n\\n$(translate "If you are sure you want to use it, please remove the") RAID metadata $(translate "or format it manually using external tools.")\\n\\n$(translate "After that, run this script again to add it.")" 18 70
|
||||
clear
|
||||
@ -350,12 +424,14 @@ for DISK in $SELECTED; do
|
||||
if [ $? -ne 0 ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
echo -e "$(translate "Creating partition table and partition...")"
|
||||
parted -s "$DISK" mklabel gpt
|
||||
parted -s "$DISK" mkpart primary 0% 100%
|
||||
sleep 2
|
||||
partprobe "$DISK"
|
||||
sleep 2
|
||||
|
||||
PARTITION=$(lsblk -rno NAME "$DISK" | awk -v disk="$(basename "$DISK")" '$1 != disk {print $1; exit}')
|
||||
if [ -n "$PARTITION" ]; then
|
||||
PARTITION="/dev/$PARTITION"
|
||||
@ -383,7 +459,6 @@ for DISK in $SELECTED; do
|
||||
fi
|
||||
|
||||
whiptail --title "$(translate "WARNING")" --yesno "$(translate "WARNING: This operation will FORMAT the disk") $DISK_INFO $(translate "with") $FORMAT_TYPE.\\n\\n$(translate "ALL DATA ON THIS DISK WILL BE PERMANENTLY LOST!")\\n\\n$(translate "Are you sure you want to continue")" 15 70
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
whiptail --title "$(translate "Format Cancelled")" --msgbox "$(translate "Format operation cancelled. The disk will not be added.")" 8 60
|
||||
continue
|
||||
@ -444,32 +519,38 @@ for DISK in $SELECTED; do
|
||||
fi
|
||||
|
||||
##############################################################################
|
||||
# Get persistent path for the partition
|
||||
PERSISTENT_PARTITION=$(get_persistent_path "$PARTITION")
|
||||
|
||||
# Apply passthrough with persistent path
|
||||
CURRENT_FS=$(lsblk -no FSTYPE "$PARTITION" | xargs)
|
||||
if [ "$CURRENT_FS" == "xfs" ] || [ "$FORMAT_TYPE" == "xfs" ]; then
|
||||
|
||||
RESULT=$(pct set "$CTID" -mp${INDEX} "$PARTITION,mp=$MOUNT_POINT,backup=0,ro=0" 2>&1)
|
||||
RESULT=$(pct set "$CTID" -mp${INDEX} "$PERSISTENT_PARTITION,mp=$MOUNT_POINT,backup=0,ro=0" 2>&1)
|
||||
else
|
||||
|
||||
RESULT=$(pct set "$CTID" -mp${INDEX} "$PARTITION,mp=$MOUNT_POINT,backup=0,ro=0,acl=1" 2>&1)
|
||||
RESULT=$(pct set "$CTID" -mp${INDEX} "$PERSISTENT_PARTITION,mp=$MOUNT_POINT,backup=0,ro=0,acl=1" 2>&1)
|
||||
fi
|
||||
|
||||
# Adjust permissions inside the CT
|
||||
pct exec "$CTID" -- chmod -R 775 "$MOUNT_POINT" 2>/dev/null || true
|
||||
|
||||
pct exec "$CTID" -- chmod -R 777 "$MOUNT_POINT" 2>/dev/null || true
|
||||
# Show confirmation with persistent identifier
|
||||
msg_ok "$(translate "Assigned using") $PERSISTENT_PARTITION"
|
||||
##############################################################################
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
MESSAGE="$(translate "The disk") $DISK_INFO $(translate "has been successfully added to CT") $CTID $(translate "as a mount point at") $MOUNT_POINT."
|
||||
MESSAGE+="\\n$(translate "Using persistent path"): $PERSISTENT_PARTITION"
|
||||
|
||||
if [ -n "$ASSIGNED_TO" ]; then
|
||||
MESSAGE+="\\n\\n$(translate "WARNING: This disk is also assigned to the following CT(s):")\\n$ASSIGNED_TO"
|
||||
MESSAGE+="\\n$(translate "Make sure not to start CTs that share this disk at the same time to avoid data corruption.")"
|
||||
fi
|
||||
|
||||
SUCCESS_MESSAGES+="$MESSAGE\\n\\n"
|
||||
((DISKS_ADDED++))
|
||||
else
|
||||
ERROR_MESSAGES+="$(translate "Could not add disk") $DISK_INFO $(translate "to CT") $CTID.\\n$(translate "Error:") $RESULT\\n\\n"
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
msg_ok "$(translate "Disk processing completed.")"
|
||||
@ -485,5 +566,4 @@ fi
|
||||
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
|
||||
exit 0
|
||||
|
267
scripts/utilities/proxmox-upgrade-pve8-to-pve9-manual-guide.sh
Normal file
267
scripts/utilities/proxmox-upgrade-pve8-to-pve9-manual-guide.sh
Normal file
@ -0,0 +1,267 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# ProxMenu - Manual Proxmox VE 8 to 9 Upgrade Guide
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : MIT (https://raw.githubusercontent.com/MacRimi/ProxMenux/main/LICENSE)
|
||||
# Version : 1.0
|
||||
# Last Updated: 13/08/2025
|
||||
# ==========================================================
|
||||
|
||||
# Configuration ============================================
|
||||
REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
|
||||
BASE_DIR="/usr/local/share/proxmenux"
|
||||
UTILS_FILE="$BASE_DIR/utils.sh"
|
||||
VENV_PATH="/opt/googletrans-env"
|
||||
|
||||
if [[ -f "$UTILS_FILE" ]]; then
|
||||
source "$UTILS_FILE"
|
||||
fi
|
||||
load_language
|
||||
initialize_cache
|
||||
# ==========================================================
|
||||
|
||||
show_command() {
|
||||
local step="$1"
|
||||
local description="$2"
|
||||
local command="$3"
|
||||
local note="$4"
|
||||
local command_extra="$5"
|
||||
|
||||
echo -e "${BGN}${step}.${CL} ${BL}${description}${CL}"
|
||||
echo ""
|
||||
echo -e "${TAB}${command}"
|
||||
echo -e
|
||||
[[ -n "$note" ]] && echo -e "${TAB}${DARK_GRAY}${note}${CL}"
|
||||
[[ -n "$command_extra" ]] && echo -e "${TAB}${YW}${command_extra}${CL}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
show_proxmox_upgrade_manual_guide() {
|
||||
clear
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Proxmox VE 8 to 9 Manual Upgrade Guide")"
|
||||
|
||||
echo -e "${TAB}${BL}------------------------------------------------------------------------${CL}"
|
||||
echo -e
|
||||
echo -e "${TAB}${BGN}$(translate "Source:")${CL} ${BL}https://pve.proxmox.com/wiki/Upgrade_from_8_to_9${CL}"
|
||||
echo -e
|
||||
echo -e
|
||||
echo -e "${TAB}${BOLD}$(translate "IMPORTANT PREREQUISITES:")${CL}"
|
||||
echo -e
|
||||
echo -e "${TAB}${BGN}• $(translate "System must be updated to latest PVE 8.4+ before starting")${CL}"
|
||||
echo -e "${TAB}${BGN}• $(translate "Use SSH or terminal access (SSH recommended)")${CL}"
|
||||
echo -e "${TAB}${BGN}• $(translate "Use tmux or screen to avoid interruptions")${CL}"
|
||||
echo -e "${TAB}${BGN}• $(translate "Have valid backups of all VMs and containers")${CL}"
|
||||
echo -e "${TAB}${BGN}• $(translate "At least 5GB free space on root filesystem")${CL}"
|
||||
echo -e "${TAB}${BGN}• $(translate "Do not run the upgrade from the Web UI virtual console (it will disconnect)")${CL}"
|
||||
echo -e
|
||||
echo -e "${TAB}${BL}------------------------------------------------------------------------${CL}"
|
||||
echo -e
|
||||
|
||||
|
||||
show_command "1" \
|
||||
"$(translate "Update system to latest PVE 8.4+ (if not done already):")\n\n" \
|
||||
"apt update && apt dist-upgrade -y" \
|
||||
"$(translate "Or use ProxMenux update function")" \
|
||||
"\n\n"
|
||||
|
||||
|
||||
show_command "2" \
|
||||
"$(translate "Verify PVE version (must be 8.4.1 or newer):")\n\n" \
|
||||
"pveversion" \
|
||||
"" \
|
||||
"\n"
|
||||
|
||||
|
||||
show_command "2.1" \
|
||||
"${YW}$(translate "If this node runs hyper-converged Ceph: ensure Ceph is 19.x (Squid) BEFORE upgrading PVE.")${CL}\n\n" \
|
||||
"ceph --version" \
|
||||
"$(translate "If not 19.x, upgrade Ceph (Reef→Squid) first per the official guide:") ${BL}https://pve.proxmox.com/wiki/Ceph_Squid${CL}" \
|
||||
"\n"
|
||||
|
||||
|
||||
|
||||
show_command "3" \
|
||||
"$(translate "Run upgrade checklist script:")\n\n" \
|
||||
"pve8to9 --full" \
|
||||
"${YW}$(translate "If it warns about 'systemd-boot' meta-package, remove it:")${CL} apt remove systemd-boot" \
|
||||
"\n"
|
||||
|
||||
|
||||
show_command "4" \
|
||||
"$(translate "Start terminal multiplexer (recommended):")\n\n" \
|
||||
"tmux new-session -s upgrade ${DARK_GRAY}$(translate "# Recommended: avoids disconnection during upgrade")${CL}\n\n screen -S upgrade ${DARK_GRAY}$(translate "# Alternative if you prefer screen")${CL}" \
|
||||
"" \
|
||||
"\n"
|
||||
|
||||
|
||||
show_command "5" \
|
||||
"$(translate "Update Debian repositories to Trixie:")\n\n" \
|
||||
"sed -i 's/bookworm/trixie/g' /etc/apt/sources.list" \
|
||||
"" \
|
||||
"\n"
|
||||
|
||||
|
||||
show_command "6" \
|
||||
"${YW}$(translate "Update PVE enterprise repository (Only if using enterprise):")${CL}\n\n" \
|
||||
"${CUS}sed -i 's/bookworm/trixie/g' /etc/apt/sources.list.d/pve-enterprise.list${CL}" \
|
||||
"$(translate "Skip this step if using no-subscription repository")" \
|
||||
"\n\n"
|
||||
|
||||
|
||||
show_command "7" \
|
||||
"${YW}$(translate "Add new PVE 9 enterprise repository (deb822 format) (Only if using enterprise):")${CL}\n\n" \
|
||||
"${CUS}cat > /etc/apt/sources.list.d/pve-enterprise.sources << EOF
|
||||
Types: deb
|
||||
URIs: https://enterprise.proxmox.com/debian/pve
|
||||
Suites: trixie
|
||||
Components: pve-enterprise
|
||||
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
|
||||
EOF${CL}" \
|
||||
"$(translate "Only if using enterprise subscription")" \
|
||||
"\n\n"
|
||||
|
||||
|
||||
show_command "8" \
|
||||
"$(translate "OR add new PVE 9 no-subscription repository:")\n\n" \
|
||||
"cat > /etc/apt/sources.list.d/proxmox.sources << EOF
|
||||
Types: deb
|
||||
URIs: http://download.proxmox.com/debian/pve
|
||||
Suites: trixie
|
||||
Components: pve-no-subscription
|
||||
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
|
||||
EOF" \
|
||||
"$(translate "Only if using no-subscription repository")" \
|
||||
"\n\n"
|
||||
|
||||
|
||||
show_command "8.1" \
|
||||
"$(translate "Refresh APT index and verify repositories:")\n\n" \
|
||||
"apt update && apt policy | sed -n '1,120p'" \
|
||||
"$(translate "Ensure there are no errors and that proxmox-ve candidate shows 9.x")" \
|
||||
"\n"
|
||||
|
||||
|
||||
show_command "9" \
|
||||
"${YW}$(translate "Update Ceph repository (Only if using Ceph):")${CL}\n\n" \
|
||||
"${CUS}cat > /etc/apt/sources.list.d/ceph.sources << EOF
|
||||
Types: deb
|
||||
URIs: http://download.proxmox.com/debian/ceph-squid
|
||||
Suites: trixie
|
||||
Components: no-subscription
|
||||
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
|
||||
EOF${CL}" \
|
||||
"$(translate "Use enterprise URL if you have subscription.")" \
|
||||
"\n\n"
|
||||
|
||||
|
||||
show_command "10" \
|
||||
"$(translate "Remove old repository files:")\n\n" \
|
||||
"rm -f /etc/apt/sources.list.d/pve-enterprise.list /etc/apt/sources.list.d/ceph.list" \
|
||||
"$(translate "Also comment any remaining 'bookworm' entries in *.list if present.")" \
|
||||
"\n"
|
||||
|
||||
|
||||
show_command "11" \
|
||||
"$(translate "Update package index:")\n\n" \
|
||||
"apt update" \
|
||||
"" \
|
||||
"\n"
|
||||
|
||||
|
||||
show_command "12" \
|
||||
"$(translate "Disable kernel audit messages (optional but recommended):")\n\n" \
|
||||
"systemctl disable --now systemd-journald-audit.socket" \
|
||||
"" \
|
||||
"\n"
|
||||
|
||||
|
||||
show_command "13" \
|
||||
"$(translate "Start the main system upgrade:")\n\n" \
|
||||
"apt dist-upgrade" \
|
||||
"$(translate "This will take time. Answer prompts carefully - see notes below.")\n" \
|
||||
"\n"
|
||||
|
||||
|
||||
echo -e "${TAB}${BOLD}$(translate "UPGRADE PROMPTS - RECOMMENDED ANSWERS:")${CL}"
|
||||
echo -e
|
||||
echo -e "${TAB}${BGN}/etc/issue:${CL} ${YW}$(translate "Keep current version (N)")${CL}"
|
||||
echo -e "${TAB}${BGN}/etc/lvm/lvm.conf:${CL} ${YW}$(translate "Install maintainer's version (Y)")${CL}"
|
||||
echo -e "${TAB}${BGN}/etc/ssh/sshd_config:${CL} ${YW}$(translate "Install maintainer's version (Y)")${CL}"
|
||||
echo -e "${TAB}${BGN}/etc/default/grub:${CL} ${YW}$(translate "Keep current version (N) if modified")${CL}"
|
||||
echo -e "${TAB}${BGN}/etc/chrony/chrony.conf:${CL} ${YW}$(translate "Install maintainer's version (Y)")${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Service restarts:")${CL} ${YW}$(translate "Use default (Yes)")${CL}"
|
||||
echo -e "${TAB}${BGN}apt-listchanges:${CL} ${YW}$(translate "Press 'q' to exit")${CL}"
|
||||
echo -e
|
||||
echo -e
|
||||
echo -e
|
||||
|
||||
|
||||
show_command "13.1" \
|
||||
"${YW}$(translate "If booting in EFI mode with root on LVM: install GRUB for EFI")${CL}\n\n" \
|
||||
"[ -d /sys/firmware/efi ] && apt install grub-efi-amd64" \
|
||||
"$(translate "Per official known issues; ensures proper boot after upgrade")" \
|
||||
"\n"
|
||||
|
||||
|
||||
show_command "14" \
|
||||
"$(translate "Run checklist again to verify upgrade:")\n\n" \
|
||||
"pve8to9 --full" \
|
||||
"$(translate "Should show fewer or no issues")" \
|
||||
"\n"
|
||||
|
||||
|
||||
show_command "15" \
|
||||
"$(translate "Reboot the system:")\n\n" \
|
||||
"reboot" \
|
||||
"" \
|
||||
"\n"
|
||||
|
||||
|
||||
show_command "16" \
|
||||
"$(translate "After reboot, verify PVE version:")\n\n" \
|
||||
"pveversion" \
|
||||
"$(translate "Should show pve-manager/9.x.x")" \
|
||||
"\n"
|
||||
|
||||
|
||||
show_command "17" \
|
||||
"$(translate "Optional: Modernize repository sources:")\n\n" \
|
||||
"apt modernize-sources" \
|
||||
"$(translate "Converts to deb822; keeps .list backups as .bak")" \
|
||||
"\n"
|
||||
|
||||
echo -e "${TAB}${BL}------------------------------------------------------------------------${CL}"
|
||||
echo -e
|
||||
echo -e
|
||||
echo -e "${TAB}${BOLD}$(translate "CLUSTER UPGRADE NOTES:")${CL}"
|
||||
echo -e
|
||||
echo -e "${TAB}${BGN}• $(translate "Upgrade one node at a time")${CL}"
|
||||
echo -e "${TAB}${BGN}• $(translate "Migrate VMs away from node being upgraded")${CL}"
|
||||
echo -e "${TAB}${BGN}• $(translate "Wait for each node to complete before starting next")${CL}"
|
||||
echo -e "${TAB}${BGN}• $(translate "HA groups will be migrated to HA rules automatically")${CL}"
|
||||
echo -e
|
||||
echo -e
|
||||
|
||||
echo -e
|
||||
echo -e "${TAB}${BOLD}$(translate "TROUBLESHOOTING:")${CL}"
|
||||
echo -e
|
||||
echo -e "${TAB}${BGN}$(translate "If upgrade fails:")${CL} ${YW}apt -f install${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "If repositories error:")${CL} ${YW}Check /etc/apt/sources.list*${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "If 'proxmox-ve' removal warning:")${CL} ${YW}Fix repository configuration (ensure PVE 9 repo active)${CL}"
|
||||
echo -e "${TAB}${BGN}$(translate "Emergency recovery:")${CL} ${YW}Boot from rescue system${CL}"
|
||||
echo -e
|
||||
echo -e
|
||||
|
||||
echo -e
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
echo -e
|
||||
read -r
|
||||
}
|
||||
|
||||
|
||||
# Main execution
|
||||
show_proxmox_upgrade_manual_guide
|
@ -41,371 +41,45 @@ initialize_cache
|
||||
|
||||
# ==========================================================
|
||||
|
||||
|
||||
|
||||
|
||||
OS_CODENAME="$(grep "VERSION_CODENAME=" /etc/os-release | cut -d"=" -f 2 | xargs )"
|
||||
|
||||
|
||||
if [ -z "$OS_CODENAME" ]; then
|
||||
OS_CODENAME=$(lsb_release -cs 2>/dev/null || echo "bookworm")
|
||||
fi
|
||||
|
||||
# ======================================================
|
||||
# Auxiliary functions
|
||||
# ======================================================
|
||||
|
||||
lvm_repair_check() {
|
||||
msg_info "$(translate "Checking and repairing old LVM PV headers (if needed)...")"
|
||||
|
||||
pvs_output=$(LC_ALL=C pvs -v 2>&1 | grep "old PV header")
|
||||
|
||||
if [ -z "$pvs_output" ]; then
|
||||
msg_ok "$(translate "No PVs with old headers found.")"
|
||||
return
|
||||
fi
|
||||
|
||||
declare -A vg_map
|
||||
|
||||
while read -r line; do
|
||||
pv=$(echo "$line" | grep -o '/dev/[^ ]*')
|
||||
vg=$(pvs -o vg_name --noheadings "$pv" | awk '{print $1}')
|
||||
if [ -n "$vg" ]; then
|
||||
vg_map["$vg"]=1
|
||||
fi
|
||||
done <<< "$pvs_output"
|
||||
|
||||
for vg in "${!vg_map[@]}"; do
|
||||
msg_warn "$(translate "Old PV header(s) found in VG $vg. Updating metadata...")"
|
||||
vgck --updatemetadata "$vg"
|
||||
vgchange -ay "$vg"
|
||||
if [ $? -ne 0 ]; then
|
||||
msg_warn "$(translate "Metadata update failed for VG $vg. Review manually.")"
|
||||
else
|
||||
msg_ok "$(translate "Metadata updated successfully for VG $vg")"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
cleanup_duplicate_repos() {
|
||||
local sources_file="/etc/apt/sources.list"
|
||||
local temp_file=$(mktemp)
|
||||
local cleaned_count=0
|
||||
|
||||
declare -A seen_repos
|
||||
|
||||
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||
if [[ "$line" =~ ^[[:space:]]*# ]] || [[ -z "$line" ]]; then
|
||||
echo "$line" >> "$temp_file"
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$line" =~ ^deb ]]; then
|
||||
read -r _ url dist components <<< "$line"
|
||||
local key="${url}_${dist}"
|
||||
|
||||
if [[ -v "seen_repos[$key]" ]]; then
|
||||
echo "# $line" >> "$temp_file"
|
||||
cleaned_count=$((cleaned_count + 1))
|
||||
else
|
||||
echo "$line" >> "$temp_file"
|
||||
seen_repos[$key]="$components"
|
||||
fi
|
||||
else
|
||||
echo "$line" >> "$temp_file"
|
||||
fi
|
||||
done < "$sources_file"
|
||||
|
||||
mv "$temp_file" "$sources_file"
|
||||
chmod 644 "$sources_file"
|
||||
|
||||
local pve_files=(/etc/apt/sources.list.d/*proxmox*.list /etc/apt/sources.list.d/*pve*.list)
|
||||
local pve_public_repo="/etc/apt/sources.list.d/pve-public-repo.list"
|
||||
local pve_public_repo_exists=false
|
||||
local pve_repo_count=0
|
||||
|
||||
if [ -f "$pve_public_repo" ] && grep -q "^deb.*pve-no-subscription" "$pve_public_repo"; then
|
||||
pve_public_repo_exists=true
|
||||
pve_repo_count=1
|
||||
fi
|
||||
|
||||
for file in "${pve_files[@]}"; do
|
||||
if [ -f "$file" ] && grep -q "^deb.*pve-no-subscription" "$file"; then
|
||||
if ! $pve_public_repo_exists && [[ "$file" == "$pve_public_repo" ]]; then
|
||||
sed -i 's/^# *deb/deb/' "$file"
|
||||
pve_public_repo_exists=true
|
||||
pve_repo_count=1
|
||||
elif [[ "$file" != "$pve_public_repo" ]]; then
|
||||
sed -i 's/^deb/# deb/' "$file"
|
||||
cleaned_count=$((cleaned_count + 1))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $cleaned_count -gt 0 ]; then
|
||||
msg_ok "$(translate "Duplicate repositories cleaned: $cleaned_count")"
|
||||
fi
|
||||
apt update
|
||||
}
|
||||
NECESSARY_REBOOT=1
|
||||
|
||||
apt_upgrade() {
|
||||
local start_time=$(date +%s)
|
||||
local log_file="/var/log/proxmox-update-$(date +%Y%m%d-%H%M%S).log"
|
||||
local changes_made=false
|
||||
local pve_version
|
||||
pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+' | head -1)
|
||||
|
||||
if [[ -z "$pve_version" ]]; then
|
||||
msg_error "Unable to detect Proxmox version."
|
||||
return 1
|
||||
fi
|
||||
|
||||
clear
|
||||
if [[ "$pve_version" -ge 9 ]]; then
|
||||
show_proxmenux_logo
|
||||
echo -e
|
||||
msg_title "$(translate "Proxmox system update")"
|
||||
bash <(curl -fsSL "$REPO_URL/scripts/global/update-pve.sh")
|
||||
|
||||
|
||||
# ======================================================
|
||||
# Basic checks
|
||||
# ======================================================
|
||||
|
||||
# Check minimum disk space
|
||||
local available_space=$(df /var/cache/apt/archives | awk 'NR==2 {print int($4/1024)}')
|
||||
if [ "$available_space" -lt 1024 ]; then
|
||||
msg_error "$(translate "Insufficient disk space. Available: ${available_space}MB")"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check connectivity
|
||||
if ! ping -c 1 download.proxmox.com >/dev/null 2>&1; then
|
||||
msg_error "$(translate "Cannot reach Proxmox repositories")"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# ======================================================
|
||||
# Proxmox repository configuration
|
||||
# ======================================================
|
||||
|
||||
# Disable enterprise Proxmox repository
|
||||
if [ -f /etc/apt/sources.list.d/pve-enterprise.list ] && grep -q "^deb" /etc/apt/sources.list.d/pve-enterprise.list; then
|
||||
msg_info "$(translate "Disabling enterprise Proxmox repository...")"
|
||||
sed -i "s/^deb/#deb/g" /etc/apt/sources.list.d/pve-enterprise.list
|
||||
msg_ok "$(translate "Enterprise Proxmox repository disabled")"
|
||||
changes_made=true
|
||||
fi
|
||||
|
||||
# Disable enterprise Ceph repository
|
||||
if [ -f /etc/apt/sources.list.d/ceph.list ] && grep -q "^deb" /etc/apt/sources.list.d/ceph.list; then
|
||||
msg_info "$(translate "Disabling enterprise Ceph repository...")"
|
||||
sed -i "s/^deb/#deb/g" /etc/apt/sources.list.d/ceph.list
|
||||
msg_ok "$(translate "Enterprise Ceph repository disabled")"
|
||||
changes_made=true
|
||||
fi
|
||||
|
||||
# Enable free public repository
|
||||
if [ ! -f /etc/apt/sources.list.d/pve-public-repo.list ] || ! grep -q "pve-no-subscription" /etc/apt/sources.list.d/pve-public-repo.list; then
|
||||
msg_info "$(translate "Enabling free public Proxmox repository...")"
|
||||
echo "deb http://download.proxmox.com/debian/pve ${OS_CODENAME} pve-no-subscription" > /etc/apt/sources.list.d/pve-public-repo.list
|
||||
msg_ok "$(translate "Free public Proxmox repository enabled")"
|
||||
changes_made=true
|
||||
fi
|
||||
|
||||
# ======================================================
|
||||
# Debian repository configuration
|
||||
# ======================================================
|
||||
|
||||
local sources_file="/etc/apt/sources.list"
|
||||
local debian_changes=false
|
||||
|
||||
# Clean up malformed entries first
|
||||
if grep -q -E "(debian-security -security|debian main$|debian -updates)" "$sources_file"; then
|
||||
msg_info "$(translate "Cleaning malformed repository entries...")"
|
||||
|
||||
# Remove malformed lines that cause 404 errors
|
||||
sed -i '/^deb.*debian-security -security/d' "$sources_file"
|
||||
sed -i '/^deb.*debian main$/d' "$sources_file"
|
||||
sed -i '/^deb.*debian -updates/d' "$sources_file"
|
||||
debian_changes=true
|
||||
msg_ok "$(translate "Cleaning malformed repository sucefull")"
|
||||
fi
|
||||
|
||||
# Replace old mirrors
|
||||
if grep -q "ftp.es.debian.org" "$sources_file"; then
|
||||
sed -i 's|ftp.es.debian.org|deb.debian.org|g' "$sources_file"
|
||||
debian_changes=true
|
||||
fi
|
||||
|
||||
# Fix incomplete security repository line
|
||||
if grep -q "^deb http://security.debian.org ${OS_CODENAME}-security main contrib$" "$sources_file"; then
|
||||
sed -i "s|^deb http://security.debian.org ${OS_CODENAME}-security main contrib$|deb http://security.debian.org/debian-security ${OS_CODENAME}-security main contrib non-free non-free-firmware|" "$sources_file"
|
||||
debian_changes=true
|
||||
fi
|
||||
|
||||
|
||||
local temp_sources=$(mktemp)
|
||||
|
||||
|
||||
grep -E '^[[:space:]]*#|^[[:space:]]*$' "$sources_file" > "$temp_sources"
|
||||
|
||||
|
||||
cat >> "$temp_sources" << EOF
|
||||
|
||||
# Debian ${OS_CODENAME} repositories
|
||||
deb http://deb.debian.org/debian ${OS_CODENAME} main contrib non-free non-free-firmware
|
||||
deb http://deb.debian.org/debian ${OS_CODENAME}-updates main contrib non-free non-free-firmware
|
||||
deb http://security.debian.org/debian-security ${OS_CODENAME}-security main contrib non-free non-free-firmware
|
||||
EOF
|
||||
|
||||
|
||||
if ! cmp -s "$sources_file" "$temp_sources"; then
|
||||
cp "$sources_file" "${sources_file}.backup-$(date +%Y%m%d-%H%M%S)"
|
||||
mv "$temp_sources" "$sources_file"
|
||||
debian_changes=true
|
||||
msg_ok "$(translate "Debian repositories updated")"
|
||||
else
|
||||
rm "$temp_sources"
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Proxmox system update")"
|
||||
bash <(curl -fsSL "$REPO_URL/scripts/global/update-pve8.sh")
|
||||
|
||||
fi
|
||||
|
||||
|
||||
if [ ! -f /etc/apt/apt.conf.d/no-bookworm-firmware.conf ]; then
|
||||
echo 'APT::Get::Update::SourceListWarnings::NonFreeFirmware "false";' > /etc/apt/apt.conf.d/no-bookworm-firmware.conf
|
||||
debian_changes=true
|
||||
fi
|
||||
|
||||
if [ "$debian_changes" = true ]; then
|
||||
changes_made=true
|
||||
fi
|
||||
|
||||
# ======================================================
|
||||
# Clean duplicate repositories
|
||||
# ======================================================
|
||||
|
||||
cleanup_duplicate_repos
|
||||
|
||||
# ======================================================
|
||||
# System update
|
||||
# ======================================================
|
||||
|
||||
# Update package lists
|
||||
if [ "$changes_made" = true ]; then
|
||||
msg_info "$(translate "Updating package lists...")"
|
||||
else
|
||||
msg_info "$(translate "Checking for available updates...")"
|
||||
fi
|
||||
|
||||
if apt-get update > "$log_file" 2>&1; then
|
||||
msg_ok "$(translate "Package lists updated")"
|
||||
else
|
||||
msg_error "$(translate "Failed to update package lists. Check log: $log_file")"
|
||||
|
||||
echo "$(translate "Repository errors found:")"
|
||||
grep -E "Err:|E:" "$log_file" | head -5
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Remove conflicting packages
|
||||
local conflicting_packages=$(dpkg -l 2>/dev/null | grep -E "^ii.*(ntp|openntpd|systemd-timesyncd)" | awk '{print $2}')
|
||||
if [ -n "$conflicting_packages" ]; then
|
||||
msg_info "$(translate "Removing conflicting packages...")"
|
||||
DEBIAN_FRONTEND=noninteractive apt-get -y purge $conflicting_packages >> "$log_file" 2>&1
|
||||
msg_ok "$(translate "Conflicting packages removed")"
|
||||
fi
|
||||
|
||||
# Show update information
|
||||
local upgradable=$(apt list --upgradable 2>/dev/null | grep -c "upgradable")
|
||||
if [ "$upgradable" -gt 0 ]; then
|
||||
|
||||
# Show with dialog if available
|
||||
if command -v whiptail >/dev/null 2>&1; then
|
||||
if whiptail --title "$(translate "Proxmox Update")" \
|
||||
--yesno "$(translate "Found $upgradable packages to upgrade.\n\nProceed with system update?")" 10 60; then
|
||||
msg_info "$(translate "Performing system upgrade. This process may take several minutes...")"
|
||||
else
|
||||
msg_info2 "$(translate "Update cancelled by user")"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
else
|
||||
msg_success "$(translate "System is already up to date")"
|
||||
echo -e
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Perform update
|
||||
# msg_info "$(translate "Performing system upgrade...")"
|
||||
# echo "$(translate "This process may take several minutes...")"
|
||||
|
||||
# Update with logging
|
||||
if DEBIAN_FRONTEND=noninteractive apt-get -y \
|
||||
-o Dpkg::Options::='--force-confdef' \
|
||||
-o Dpkg::Options::='--force-confold' \
|
||||
dist-upgrade >> "$log_file" 2>&1; then
|
||||
|
||||
msg_ok "$(translate "System upgrade completed successfully")"
|
||||
else
|
||||
msg_error "$(translate "System upgrade failed. Check log: $log_file")"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Install essential Proxmox packages if missing
|
||||
local essential_packages=("zfsutils-linux" "proxmox-backup-restore-image" "chrony")
|
||||
local missing_packages=()
|
||||
|
||||
for package in "${essential_packages[@]}"; do
|
||||
if ! dpkg -l 2>/dev/null | grep -q "^ii $package "; then
|
||||
missing_packages+=("$package")
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ${#missing_packages[@]} -gt 0 ]; then
|
||||
msg_info "$(translate "Installing essential Proxmox packages...")"
|
||||
DEBIAN_FRONTEND=noninteractive apt-get -y install "${missing_packages[@]}" >> "$log_file" 2>&1
|
||||
msg_ok "$(translate "Essential Proxmox packages installed")"
|
||||
fi
|
||||
|
||||
# Check LVM
|
||||
lvm_repair_check
|
||||
|
||||
# ======================================================
|
||||
# Final summary - BEFORE reboot logic
|
||||
# ======================================================
|
||||
|
||||
local end_time=$(date +%s)
|
||||
local duration=$((end_time - start_time))
|
||||
local minutes=$((duration / 60))
|
||||
local seconds=$((duration % 60))
|
||||
|
||||
echo ""
|
||||
echo "$(translate "=== UPDATE COMPLETED ===")"
|
||||
echo "$(translate "Duration"): ${minutes}m ${seconds}s"
|
||||
echo "$(translate "Log file"): $log_file"
|
||||
echo "$(translate "Packages upgraded"): $upgradable"
|
||||
echo ""
|
||||
|
||||
msg_success "$(translate "Proxmox system update completed successfully")"
|
||||
}
|
||||
|
||||
|
||||
# ======================================================
|
||||
# Reboot logic - After summary
|
||||
# ======================================================
|
||||
|
||||
# Check if reboot is needed (kernel updates, system packages, etc.)
|
||||
check_reboot() {
|
||||
NECESSARY_REBOOT=0
|
||||
|
||||
# Check for reboot-required file
|
||||
if [ -f /var/run/reboot-required ]; then
|
||||
NECESSARY_REBOOT=1
|
||||
fi
|
||||
|
||||
# Check if kernel was updated
|
||||
if grep -q "linux-image" "$log_file" 2>/dev/null; then
|
||||
NECESSARY_REBOOT=1
|
||||
fi
|
||||
|
||||
# For system updates, it's generally safer to reboot
|
||||
if [ "$upgradable" -gt 0 ]; then
|
||||
NECESSARY_REBOOT=1
|
||||
fi
|
||||
|
||||
if [[ "$NECESSARY_REBOOT" -eq 1 ]]; then
|
||||
if command -v whiptail >/dev/null 2>&1; then
|
||||
if whiptail --title "$(translate "Reboot Required")" \
|
||||
--yesno "$(translate "Some changes require a reboot to take effect. Do you want to restart now?")" 10 60; then
|
||||
|
||||
@ -413,7 +87,7 @@ EOF
|
||||
apt-get -y autoremove >/dev/null 2>&1
|
||||
apt-get -y autoclean >/dev/null 2>&1
|
||||
msg_ok "$(translate "Cleanup finished")"
|
||||
|
||||
echo -e
|
||||
msg_success "$(translate "Press Enter to continue...")"
|
||||
read -r
|
||||
|
||||
@ -424,81 +98,34 @@ EOF
|
||||
apt-get -y autoremove >/dev/null 2>&1
|
||||
apt-get -y autoclean >/dev/null 2>&1
|
||||
msg_ok "$(translate "Cleanup finished")"
|
||||
|
||||
echo -e
|
||||
msg_info2 "$(translate "You can reboot later manually.")"
|
||||
echo -e
|
||||
msg_success "$(translate "Press Enter to continue...")"
|
||||
read -r
|
||||
return 0
|
||||
fi
|
||||
else
|
||||
# Fallback without whiptail
|
||||
echo "$(translate "Reboot now? (y/N): ")"
|
||||
read -r -t 30 response
|
||||
if [[ "$response" =~ ^[Yy]$ ]]; then
|
||||
msg_info "$(translate "Removing no longer required packages and purging old cached updates...")"
|
||||
apt-get -y autoremove >/dev/null 2>&1
|
||||
apt-get -y autoclean >/dev/null 2>&1
|
||||
msg_ok "$(translate "Cleanup finished")"
|
||||
|
||||
msg_warn "$(translate "Rebooting the system...")"
|
||||
sleep 3
|
||||
reboot
|
||||
else
|
||||
msg_info "$(translate "Removing no longer required packages and purging old cached updates...")"
|
||||
apt-get -y autoremove >/dev/null 2>&1
|
||||
apt-get -y autoclean >/dev/null 2>&1
|
||||
msg_ok "$(translate "Cleanup finished")"
|
||||
|
||||
msg_info2 "$(translate "You can reboot later manually.")"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
else
|
||||
msg_info "$(translate "Removing no longer required packages and purging old cached updates...")"
|
||||
apt-get -y autoremove >/dev/null 2>&1
|
||||
apt-get -y autoclean >/dev/null 2>&1
|
||||
msg_ok "$(translate "Cleanup finished")"
|
||||
|
||||
msg_success "$(translate "All changes applied. No reboot required.")"
|
||||
echo -e
|
||||
msg_ok "$(translate "All changes applied. No reboot required.")"
|
||||
echo -e
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
read -r
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to show available update information
|
||||
check_updates_available() {
|
||||
msg_info "$(translate "Checking for available updates...")"
|
||||
|
||||
apt-get update >/dev/null 2>&1
|
||||
local upgradable=$(apt list --upgradable 2>/dev/null | grep -c "upgradable")
|
||||
local security_updates=$(apt list --upgradable 2>/dev/null | grep -c "security")
|
||||
|
||||
if [ "$upgradable" -gt 0 ]; then
|
||||
echo "$(translate "Updates available"): $upgradable"
|
||||
echo "$(translate "Security updates"): $security_updates"
|
||||
cleanup
|
||||
if command -v whiptail >/dev/null 2>&1; then
|
||||
whiptail --title "$(translate "Updates Available")" \
|
||||
--msgbox "$(translate "Updates available: $upgradable\nSecurity updates: $security_updates\n\nUse the update option to proceed.")" 12 60
|
||||
fi
|
||||
else
|
||||
msg_ok "$(translate "System is up to date")"
|
||||
fi
|
||||
}
|
||||
|
||||
# Execute function based on parameter
|
||||
case "${1:-}" in
|
||||
"check")
|
||||
check_updates_available
|
||||
;;
|
||||
"")
|
||||
apt_upgrade
|
||||
;;
|
||||
*)
|
||||
echo "$(translate "Usage: $0 [check]")"
|
||||
echo "$(translate " check - Check for available updates")"
|
||||
echo "$(translate " (no args) - Perform full system update")"
|
||||
;;
|
||||
esac
|
||||
check_reboot
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,13 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# ProxMenux - A menu-driven script for Proxmox VE management
|
||||
# ==========================================================
|
||||
# Author : MacRimi
|
||||
# Copyright : (c) 2024 MacRimi
|
||||
# License : MIT (https://raw.githubusercontent.com/MacRimi/ProxMenux/main/LICENSE)
|
||||
# Version : 1.0
|
||||
# Last Updated: 30/06/2025
|
||||
# Version : 1.1
|
||||
# Last Updated: 30/07/2025
|
||||
# ==========================================================
|
||||
# Description:
|
||||
# This script provides an interactive system utilities installer with a
|
||||
@ -34,8 +33,8 @@
|
||||
# It includes built-in troubleshooting for common PATH and command availability
|
||||
# issues that may occur after package installation.
|
||||
#
|
||||
# Configuration ============================================
|
||||
|
||||
# Configuration ============================================
|
||||
REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
|
||||
BASE_DIR="/usr/local/share/proxmenux"
|
||||
UTILS_FILE="$BASE_DIR/utils.sh"
|
||||
@ -44,66 +43,64 @@ VENV_PATH="/opt/googletrans-env"
|
||||
if [[ -f "$UTILS_FILE" ]]; then
|
||||
source "$UTILS_FILE"
|
||||
fi
|
||||
|
||||
load_language
|
||||
initialize_cache
|
||||
|
||||
OS_CODENAME="$(grep "VERSION_CODENAME=" /etc/os-release | cut -d"=" -f 2 | xargs )"
|
||||
|
||||
# ==========================================================
|
||||
|
||||
|
||||
|
||||
install_system_utils() {
|
||||
|
||||
|
||||
|
||||
command_exists() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
|
||||
ensure_repositories() {
|
||||
local sources_file="/etc/apt/sources.list"
|
||||
local need_update=false
|
||||
|
||||
|
||||
if [[ ! -f "$sources_file" ]]; then
|
||||
msg_warn "$(translate "sources.list not found, creating default Debian repository...")"
|
||||
cat > "$sources_file" << EOF
|
||||
# Default Debian ${OS_CODENAME} repository
|
||||
deb http://deb.debian.org/debian ${OS_CODENAME} main contrib non-free non-free-firmware
|
||||
EOF
|
||||
need_update=true
|
||||
else
|
||||
|
||||
if ! grep -q "deb.*${OS_CODENAME}.*main" "$sources_file"; then
|
||||
echo "deb http://deb.debian.org/debian ${OS_CODENAME} main contrib non-free non-free-firmware" >> "$sources_file"
|
||||
need_update=true
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
if [[ "$need_update" == true ]] || ! apt list --installed >/dev/null 2>&1; then
|
||||
msg_info "$(translate "Updating APT package lists...")"
|
||||
apt-get update -o Acquire::AllowInsecureRepositories=true >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
install_single_package() {
|
||||
local package="$1"
|
||||
local command_name="${2:-$package}"
|
||||
local description="$3"
|
||||
|
||||
msg_info "$(translate "Installing") $package ($description)..."
|
||||
|
||||
|
||||
local install_success=false
|
||||
|
||||
if command_exists apt; then
|
||||
if apt update >/dev/null 2>&1 && apt install -y "$package" >/dev/null 2>&1; then
|
||||
if apt install -y "$package" >/dev/null 2>&1; then
|
||||
install_success=true
|
||||
fi
|
||||
elif command_exists yum; then
|
||||
if yum install -y "$package" >/dev/null 2>&1; then
|
||||
install_success=true
|
||||
fi
|
||||
elif command_exists dnf; then
|
||||
if dnf install -y "$package" >/dev/null 2>&1; then
|
||||
install_success=true
|
||||
fi
|
||||
elif command_exists pacman; then
|
||||
if pacman -S --noconfirm "$package" >/dev/null 2>&1; then
|
||||
install_success=true
|
||||
fi
|
||||
elif command_exists zypper; then
|
||||
if zypper install -y "$package" >/dev/null 2>&1; then
|
||||
install_success=true
|
||||
fi
|
||||
else
|
||||
cleanup
|
||||
msg_error "$(translate "No compatible package manager detected")"
|
||||
return 1
|
||||
fi
|
||||
|
||||
cleanup
|
||||
|
||||
|
||||
if [ "$install_success" = true ]; then
|
||||
|
||||
hash -r 2>/dev/null
|
||||
sleep 1
|
||||
|
||||
if command_exists "$command_name"; then
|
||||
msg_ok "$package $(translate "installed correctly and available")"
|
||||
return 0
|
||||
@ -118,7 +115,6 @@ install_system_utils() {
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
show_main_utilities_menu() {
|
||||
local choice
|
||||
choice=$(dialog --clear --backtitle "ProxMenux" \
|
||||
@ -138,7 +134,6 @@ install_system_utils() {
|
||||
echo "$choice"
|
||||
}
|
||||
|
||||
|
||||
show_custom_selection() {
|
||||
local utilities=(
|
||||
"axel" "$(translate "Download accelerator")" "OFF"
|
||||
@ -175,7 +170,6 @@ install_system_utils() {
|
||||
echo "$selected"
|
||||
}
|
||||
|
||||
|
||||
install_utility_group() {
|
||||
local group_name="$1"
|
||||
shift
|
||||
@ -185,11 +179,16 @@ install_system_utils() {
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Installing group"): $group_name"
|
||||
|
||||
|
||||
if ! ensure_repositories; then
|
||||
msg_error "$(translate "Failed to configure repositories. Installation aborted.")"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local failed=0
|
||||
local success=0
|
||||
local warning=0
|
||||
|
||||
|
||||
declare -A package_to_command=(
|
||||
["mlocate"]="locate"
|
||||
["msr-tools"]="rdmsr"
|
||||
@ -201,11 +200,7 @@ install_system_utils() {
|
||||
|
||||
for util_info in "${utilities[@]}"; do
|
||||
IFS=':' read -r package command description <<< "$util_info"
|
||||
|
||||
|
||||
local verify_command="${package_to_command[$package]:-$command}"
|
||||
|
||||
|
||||
install_single_package "$package" "$verify_command" "$description"
|
||||
local install_result=$?
|
||||
|
||||
@ -214,6 +209,7 @@ install_system_utils() {
|
||||
1) failed=$((failed + 1)) ;;
|
||||
2) warning=$((warning + 1)) ;;
|
||||
esac
|
||||
sleep 2
|
||||
done
|
||||
|
||||
echo
|
||||
@ -227,7 +223,6 @@ install_system_utils() {
|
||||
--msgbox "$(translate "Group"): $group_name\n$(translate "Successful"): $success\n$(translate "With warnings"): $warning\n$(translate "Failed"): $failed" 10 50
|
||||
}
|
||||
|
||||
|
||||
install_selected_utilities() {
|
||||
local selected="$1"
|
||||
|
||||
@ -242,15 +237,18 @@ install_system_utils() {
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Installing selected utilities")"
|
||||
|
||||
|
||||
if ! ensure_repositories; then
|
||||
msg_error "$(translate "Failed to configure repositories. Installation aborted.")"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local failed=0
|
||||
local success=0
|
||||
local warning=0
|
||||
|
||||
|
||||
local selected_array
|
||||
IFS=' ' read -ra selected_array <<< "$selected"
|
||||
|
||||
|
||||
declare -A package_to_command=(
|
||||
["mlocate"]="locate"
|
||||
["msr-tools"]="rdmsr"
|
||||
@ -261,13 +259,8 @@ install_system_utils() {
|
||||
)
|
||||
|
||||
for util in "${selected_array[@]}"; do
|
||||
|
||||
util=$(echo "$util" | tr -d '"')
|
||||
|
||||
|
||||
local verify_command="${package_to_command[$util]:-$util}"
|
||||
|
||||
|
||||
install_single_package "$util" "$verify_command" "$util"
|
||||
local install_result=$?
|
||||
|
||||
@ -276,14 +269,14 @@ install_system_utils() {
|
||||
1) failed=$((failed + 1)) ;;
|
||||
2) warning=$((warning + 1)) ;;
|
||||
esac
|
||||
sleep 2
|
||||
done
|
||||
|
||||
|
||||
if [ -f ~/.bashrc ]; then
|
||||
source ~/.bashrc >/dev/null 2>&1
|
||||
fi
|
||||
hash -r 2>/dev/null
|
||||
|
||||
hash -r 2>/dev/null
|
||||
echo
|
||||
msg_info2 "$(translate "Installation summary"):"
|
||||
msg_ok "$(translate "Successful"): $success"
|
||||
@ -295,7 +288,6 @@ install_system_utils() {
|
||||
--msgbox "$(translate "Selected utilities installation completed")\n$(translate "Successful"): $success\n$(translate "With warnings"): $warning\n$(translate "Failed"): $failed" 12 60
|
||||
}
|
||||
|
||||
|
||||
verify_installations() {
|
||||
clear
|
||||
show_proxmenux_logo
|
||||
@ -352,20 +344,15 @@ install_system_utils() {
|
||||
--msgbox "$summary$status_text" 25 80
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
# Main menu loop
|
||||
while true; do
|
||||
choice=$(show_main_utilities_menu)
|
||||
|
||||
case $choice in
|
||||
1)
|
||||
|
||||
selected=$(show_custom_selection)
|
||||
install_selected_utilities "$selected"
|
||||
;;
|
||||
2)
|
||||
|
||||
all_utils=(
|
||||
"axel:axel:Download accelerator"
|
||||
"dos2unix:dos2unix:Convert DOS/Unix text files"
|
||||
@ -394,7 +381,6 @@ install_system_utils() {
|
||||
install_utility_group "$(translate "ALL Utilities")" "${all_utils[@]}"
|
||||
;;
|
||||
3)
|
||||
|
||||
basic_utils=(
|
||||
"grc:grc:Generic Colouriser"
|
||||
"htop:htop:Process monitor"
|
||||
@ -405,7 +391,6 @@ install_system_utils() {
|
||||
install_utility_group "$(translate "Basic Utilities")" "${basic_utils[@]}"
|
||||
;;
|
||||
4)
|
||||
|
||||
dev_utils=(
|
||||
"git:git:Version control"
|
||||
"vim:vim:Advanced editor"
|
||||
@ -414,7 +399,6 @@ install_system_utils() {
|
||||
install_utility_group "$(translate "Development Tools")" "${dev_utils[@]}"
|
||||
;;
|
||||
5)
|
||||
|
||||
compress_utils=(
|
||||
"zip:zip:ZIP compressor"
|
||||
"unzip:unzip:ZIP extractor"
|
||||
@ -423,7 +407,6 @@ install_system_utils() {
|
||||
install_utility_group "$(translate "Compression Tools")" "${compress_utils[@]}"
|
||||
;;
|
||||
6)
|
||||
|
||||
multiplex_utils=(
|
||||
"screen:screen:Terminal multiplexer"
|
||||
"tmux:tmux:Advanced multiplexer"
|
||||
@ -431,7 +414,6 @@ install_system_utils() {
|
||||
install_utility_group "$(translate "Terminal Multiplexers")" "${multiplex_utils[@]}"
|
||||
;;
|
||||
7)
|
||||
|
||||
analysis_utils=(
|
||||
"jq:jq:JSON processor"
|
||||
"ncdu:ncdu:Disk analyzer"
|
||||
@ -440,7 +422,6 @@ install_system_utils() {
|
||||
install_utility_group "$(translate "Analysis Tools")" "${analysis_utils[@]}"
|
||||
;;
|
||||
8)
|
||||
|
||||
network_utils=(
|
||||
"nethogs:nethogs:Network monitor"
|
||||
"nmap:nmap:Network scanner"
|
||||
@ -466,5 +447,4 @@ install_system_utils() {
|
||||
clear
|
||||
}
|
||||
|
||||
|
||||
install_system_utils
|
@ -52,8 +52,7 @@ NEON_PURPLE_BLUE="\033[38;5;99m"
|
||||
WHITE="\033[38;5;15m"
|
||||
RESET="\033[0m"
|
||||
DARK_GRAY="\033[38;5;244m"
|
||||
DARK_GRAY="\033[38;5;244m"
|
||||
DARK_GRAY="\033[38;5;244m"
|
||||
ORANGE="\033[38;5;208m"
|
||||
YW="\033[33m"
|
||||
YWB="\033[1;33m"
|
||||
GN="\033[1;92m"
|
||||
@ -137,6 +136,12 @@ msg_info2() {
|
||||
echo -e "${TAB}${BOLD}${YW}${HOLD}${msg}${CL}"
|
||||
}
|
||||
|
||||
# Display info message with spinner
|
||||
msg_info3() {
|
||||
local msg="$1"
|
||||
echo -ne "${TAB}${YW}${HOLD}${msg}${CL}"
|
||||
}
|
||||
|
||||
# Display success message
|
||||
msg_success() {
|
||||
if [ -n "$SPINNER_PID" ] && ps -p $SPINNER_PID > /dev/null; then
|
||||
@ -165,7 +170,7 @@ msg_warn() {
|
||||
fi
|
||||
printf "\e[?25h"
|
||||
local msg="$1"
|
||||
echo -e "${BFR}${TAB}${NV}${CL} ${YWB}${msg}${CL}"
|
||||
echo -e "${BFR}${TAB}${CL} ${YWB}${msg}${CL}"
|
||||
}
|
||||
|
||||
|
||||
@ -179,6 +184,12 @@ msg_ok() {
|
||||
echo -e "${BFR}${TAB}${CM}${GN}${msg}${CL}"
|
||||
}
|
||||
|
||||
msg_ok2() {
|
||||
printf "\e[?25h"
|
||||
local msg="$1"
|
||||
echo -e "${BFR}${TAB}${CM}${GN}${msg}${CL}"
|
||||
}
|
||||
|
||||
|
||||
# Display error message
|
||||
msg_error() {
|
||||
@ -249,21 +260,23 @@ translate() {
|
||||
from googletrans import Translator
|
||||
import sys, json, re
|
||||
|
||||
def translate_text(text, dest_lang):
|
||||
def translate_text(text, dest_lang, context):
|
||||
translator = Translator()
|
||||
context = '$TRANSLATION_CONTEXT'
|
||||
try:
|
||||
full_text = context + ' ' + text
|
||||
result = translator.translate(full_text, dest=dest_lang).text
|
||||
# Remove context and any leading/trailing whitespace
|
||||
translated = re.sub(r'^.*?(Translate:|Traducir:|Traduire:|Übersetzen:|Tradurre:|Traduzir:|翻译:|翻訳:)', '', result, flags=re.IGNORECASE | re.DOTALL).strip()
|
||||
translated = re.sub(r'^.*?(Context:|Contexto:|Contexte:|Kontext:|Contesto:|上下文:|コンテキスト:).*?:', '', translated, flags=re.IGNORECASE | re.DOTALL).strip()
|
||||
return json.dumps({'success': True, 'text': translated})
|
||||
print(json.dumps({'success': True, 'text': translated}))
|
||||
except Exception as e:
|
||||
return json.dumps({'success': False, 'error': str(e)})
|
||||
print(json.dumps({'success': False, 'error': str(e)}))
|
||||
|
||||
print(translate_text('$text', '$dest_lang'))
|
||||
")
|
||||
translate_text(
|
||||
json.loads(sys.argv[1]),
|
||||
sys.argv[2],
|
||||
json.loads(sys.argv[3])
|
||||
)
|
||||
" "$(jq -Rn --arg t "$text" '$t')" "$dest_lang" "$(jq -Rn --arg ctx "$TRANSLATION_CONTEXT" '$ctx')")
|
||||
deactivate
|
||||
|
||||
local translation_result=$(echo "$translated" | jq -r '.')
|
||||
|
@ -114,6 +114,7 @@ function select_linux_iso_official() {
|
||||
"Debian 12 Netinst|CLI|ProxMenux|https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-12.10.0-amd64-netinst.iso"
|
||||
"Debian 11 Netinst|CLI|ProxMenux|https://cdimage.debian.org/cdimage/archive/11.11.0/amd64/iso-cd/debian-11.11.0-amd64-netinst.iso"
|
||||
"Fedora Workstation 42|Desktop|ProxMenux|https://download.fedoraproject.org/pub/fedora/linux/releases/42/Workstation/x86_64/iso/Fedora-Workstation-Live-42-1.1.x86_64.iso"
|
||||
"Arch Linux|CLI|ProxMenux|https://geo.mirror.pkgbuild.com/iso/2025.07.01/archlinux-2025.07.01-x86_64.iso"
|
||||
"Rocky Linux 9.5|Desktop|ProxMenux|https://download.rockylinux.org/pub/rocky/9/isos/x86_64/Rocky-9.5-x86_64-dvd.iso"
|
||||
"Linux Mint 22.1|Desktop|ProxMenux|https://mirrors.edge.kernel.org/linuxmint/stable/22.1/linuxmint-22.1-cinnamon-64bit.iso"
|
||||
"openSUSE Leap 15.6|Desktop|ProxMenux|https://download.opensuse.org/distribution/leap/15.6/iso/openSUSE-Leap-15.6-DVD-x86_64-Media.iso"
|
||||
|
@ -36,9 +36,6 @@ fi
|
||||
load_language
|
||||
initialize_cache
|
||||
|
||||
clear
|
||||
show_proxmenux_logo
|
||||
|
||||
# ==========================================================
|
||||
|
||||
|
||||
@ -78,12 +75,15 @@ function run_uupdump_creator() {
|
||||
done
|
||||
|
||||
if [[ ${#MISSING[@]} -gt 0 ]]; then
|
||||
show_proxmenux_logo
|
||||
msg_info "$(translate "Installing dependencies: ${MISSING[*]}")"
|
||||
apt-get update -qq >/dev/null 2>&1
|
||||
if ! apt-get install -y "${MISSING[@]}" >/dev/null 2>&1; then
|
||||
msg_error "$(translate "Failed to install: ${MISSING[*]}")"
|
||||
sleep 2
|
||||
exit 1
|
||||
fi
|
||||
msg_ok "$(translate "All dependencies installed and verified.")"
|
||||
fi
|
||||
|
||||
for i in "${!CMDS[@]}"; do
|
||||
@ -92,17 +92,20 @@ function run_uupdump_creator() {
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ ${#FAILED[@]} -eq 0 ]]; then
|
||||
msg_ok "$(translate "All dependencies installed and verified.")"
|
||||
else
|
||||
msg_error "$(translate "Missing commands after installation: ${FAILED[*]}")"
|
||||
if [[ ${#FAILED[@]} -gt 0 ]]; then
|
||||
show_proxmenux_logo
|
||||
msg_error "$(translate "Missing commands after installation:") ${FAILED[*]}"
|
||||
sleep 2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
|
||||
ISO_DIR=$(detect_iso_dir)
|
||||
if [[ -z "$ISO_DIR" ]]; then
|
||||
show_proxmenux_logo
|
||||
msg_error "$(translate "Could not determine a valid ISO storage directory.")"
|
||||
sleep 2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@ -110,40 +113,63 @@ fi
|
||||
mkdir -p "$ISO_DIR"
|
||||
|
||||
|
||||
DEFAULT_TMP="/root/uup-temp"
|
||||
USER_INPUT=$(dialog --inputbox "Enter temporary folder path (default: $DEFAULT_TMP):" 10 60 "$DEFAULT_TMP" 3>&1 1>&2 2>&3)
|
||||
if [[ $? -ne 0 || -z "$USER_INPUT" ]]; then
|
||||
USER_INPUT="$DEFAULT_TMP"
|
||||
|
||||
DEFAULT_BASE="/root/uup-temp"
|
||||
BASE_INPUT=$(dialog --clear --inputbox "$(translate "Enter base folder for temporary files and converter (default:") $DEFAULT_BASE):" 10 60 "$DEFAULT_BASE" 3>&1 1>&2 2>&3)
|
||||
|
||||
if [[ $? -ne 0 || -z "$BASE_INPUT" ]]; then
|
||||
BASE_INPUT="$DEFAULT_BASE"
|
||||
fi
|
||||
|
||||
#
|
||||
if [[ "$USER_INPUT" == "$DEFAULT_TMP" ]]; then
|
||||
TMP_DIR="$USER_INPUT"
|
||||
CLEAN_ALL=true
|
||||
else
|
||||
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
||||
RANDOM_ID=$(head /dev/urandom | tr -dc a-z0-9 | head -c 4)
|
||||
TMP_DIR="${USER_INPUT%/}/uup-session-${TIMESTAMP}-${RANDOM_ID}"
|
||||
CLEAN_ALL=false
|
||||
fi
|
||||
|
||||
mkdir -p "$TMP_DIR" || {
|
||||
msg_error "$(translate "Failed to create temporary directory:") $TMP_DIR"
|
||||
BASE_CLEAN="$(echo "$BASE_INPUT" | sed 's:[[:space:]]*$::' | sed 's:/*$::')"
|
||||
|
||||
|
||||
if [[ ! -d "$BASE_CLEAN" ]]; then
|
||||
if ! mkdir -p "$BASE_CLEAN"; then
|
||||
show_proxmenux_logo
|
||||
msg_error "$(translate "The selected base folder does not exist and could not be created:") $BASE_CLEAN"
|
||||
sleep 2
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
fi
|
||||
if [[ ! -w "$BASE_CLEAN" ]]; then
|
||||
show_proxmenux_logo
|
||||
msg_error "$(translate "No write permissions on:") $BASE_CLEAN"
|
||||
sleep 2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
TMP_DIR="$BASE_CLEAN/uup-temp"
|
||||
OUT_DIR="$ISO_DIR"
|
||||
CONVERTER="$BASE_CLEAN/uup-converter"
|
||||
|
||||
if ! mkdir -p "$TMP_DIR"; then
|
||||
show_proxmenux_logo
|
||||
msg_error "$(translate "Could not create temporary directory:") $TMP_DIR"
|
||||
sleep 2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! mkdir -p "$CONVERTER"; then
|
||||
show_proxmenux_logo
|
||||
msg_error "$(translate "Could not create converter directory:") $CONVERTER"
|
||||
sleep 2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$TMP_DIR" || { msg_error "$(translate "Failed to access:") $TMP_DIR"; exit 1; }
|
||||
|
||||
OUT_DIR=$(detect_iso_dir)
|
||||
[[ -z "$OUT_DIR" ]] && msg_error "$(translate "Could not determine a valid ISO directory.")" && exit 1
|
||||
mkdir -p "$OUT_DIR"
|
||||
|
||||
|
||||
UUP_URL=$(whiptail --inputbox "$(translate "Paste the UUP Dump URL here")" 10 90 3>&1 1>&2 2>&3)
|
||||
if [[ $? -ne 0 || -z "$UUP_URL" ]]; then
|
||||
msg_warn "$(translate "Cancelled by user or empty URL.")"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ ! "$UUP_URL" =~ id=.+\&pack=.+\&edition=.+ ]]; then
|
||||
show_proxmenux_logo
|
||||
msg_error "$(translate "The URL does not contain the required parameters (id, pack, edition).")"
|
||||
sleep 2
|
||||
return 1
|
||||
@ -155,6 +181,8 @@ LANG=$(echo "$UUP_URL" | grep -oP 'pack=\K[^&]+')
|
||||
EDITION=$(echo "$UUP_URL" | grep -oP 'edition=\K[^&]+')
|
||||
ARCH="amd64"
|
||||
|
||||
show_proxmenux_logo
|
||||
echo -e
|
||||
echo -e "\n${BGN}=============== UUP Dump Creator ===============${CL}"
|
||||
echo -e " ${BGN}🆔 ID:${CL} ${DGN}$BUILD_ID${CL}"
|
||||
echo -e " ${BGN}🌐 Language:${CL} ${DGN}$LANG${CL}"
|
||||
|
@ -1 +1 @@
|
||||
1.1.2
|
||||
1.1.4
|
Loading…
x
Reference in New Issue
Block a user