Compare commits

..

9 Commits

Author SHA1 Message Date
MickLesk 96723236bc Update storage-share-helper.sh 2026-07-21 09:17:37 +02:00
MickLesk 3426588c64 stupid whiptail.. now done 2026-07-21 09:11:34 +02:00
MickLesk a810413522 Allow removing multiple LXC mountpoints
Update `remove_lxc_mountpoint` in `storage-share-helper.sh` to support multi-select mountpoint removal for a container. Each selected mountpoint is now confirmed individually (default No), processed independently, and reported in a final result summary with `removed`, `FAILED`, or `skipped` status.
2026-07-21 09:02:40 +02:00
MickLesk 3531a1f9ee fix whiptail pick mountpoint 2026-07-21 09:02:18 +02:00
MickLesk 42860b7978 fix ui bug, more space for container names 2026-07-21 09:00:07 +02:00
MickLesk 36210eaa14 broken whiptail in menu 4 2026-07-21 08:54:48 +02:00
MickLesk b02abea42c add dynamic whiptail (feedback from #15882) 2026-07-21 08:49:51 +02:00
MickLesk fcfb2d8089 bump function call 2026-07-21 08:40:12 +02:00
CanbiZ (MickLesk) 829704e09e pve-tool: storage share helper script for Proxmox
This script provides a menu-driven interface for managing various storage types in Proxmox, including SMB, NFS, and iSCSI. It includes functions for testing mounts, adding storage, and managing LXC mountpoints.
2026-07-18 09:45:56 +02:00
7 changed files with 853 additions and 415 deletions
-170
View File
@@ -1,173 +1,3 @@
## 2026-07-18
### 💾 Core
- #### ✨ New Features
- core: add configurable host CA inheritance during bootstrap [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15840](https://github.com/community-scripts/ProxmoxVE/pull/15840))
- #### 🔧 Refactor
- tools.func: Safe Delete Directorys & Update PYTHON_VERSION with setup_uv [@MickLesk](https://github.com/MickLesk) ([#15870](https://github.com/community-scripts/ProxmoxVE/pull/15870))
### 🧰 Tools
- #### ✨ New Features
- [tools.update-lxcs] feat: optional reporting success/failures to heathchecks.io (or others) [@sir106](https://github.com/sir106) ([#15701](https://github.com/community-scripts/ProxmoxVE/pull/15701))
## 2026-07-17
### 🆕 New Scripts
- Invidious ([#15824](https://github.com/community-scripts/ProxmoxVE/pull/15824))
- OxiCloud ([#15823](https://github.com/community-scripts/ProxmoxVE/pull/15823))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- webtrees: initialize database schema before admin user creation [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15837](https://github.com/community-scripts/ProxmoxVE/pull/15837))
- Fix DocuSeal missing Leptonica deps on install and update [@Copilot](https://github.com/Copilot) ([#15858](https://github.com/community-scripts/ProxmoxVE/pull/15858))
- apache-guacamole: detect installed extensions during update [@TowyTowy](https://github.com/TowyTowy) ([#15841](https://github.com/community-scripts/ProxmoxVE/pull/15841))
- CLIProxyAPI: fix update deleting config.yaml [@austinpilz](https://github.com/austinpilz) ([#15834](https://github.com/community-scripts/ProxmoxVE/pull/15834))
- esphome: install libusb-1.0-0 for ESP-IDF native builds [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15838](https://github.com/community-scripts/ProxmoxVE/pull/15838))
- #### ✨ New Features
- AFFiNE: Bump to 0.27.0 [@MickLesk](https://github.com/MickLesk) ([#15848](https://github.com/community-scripts/ProxmoxVE/pull/15848))
- n8n: unpin / use latest release [@MickLesk](https://github.com/MickLesk) ([#15817](https://github.com/community-scripts/ProxmoxVE/pull/15817))
- Pin Opencloud to v7.3.0 [@vhsdream](https://github.com/vhsdream) ([#15826](https://github.com/community-scripts/ProxmoxVE/pull/15826))
- #### 🔧 Refactor
- SFTPGo: Update APT Repo & Re-Enable Script [@MickLesk](https://github.com/MickLesk) ([#15829](https://github.com/community-scripts/ProxmoxVE/pull/15829))
### 💾 Core
- #### ✨ New Features
- tools.func: enhance rbenv with profile updates / bundle in bashrc [@MickLesk](https://github.com/MickLesk) ([#15822](https://github.com/community-scripts/ProxmoxVE/pull/15822))
- feat(build.func): notify users when already on a pinned script version [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15819](https://github.com/community-scripts/ProxmoxVE/pull/15819))
- #### 💥 Breaking Changes
- MongoDB: Implement kernel version check and patch [@MickLesk](https://github.com/MickLesk) ([#15821](https://github.com/community-scripts/ProxmoxVE/pull/15821))
### 🧰 Tools
- #### ✨ New Features
- update-lxc: autoremove and autoclean after apt full-upgrade [@soupy-boy](https://github.com/soupy-boy) ([#15831](https://github.com/community-scripts/ProxmoxVE/pull/15831))
## 2026-07-16
### 🆕 New Scripts
- Sync-In ([#15812](https://github.com/community-scripts/ProxmoxVE/pull/15812))
- Beaverhabits ([#15813](https://github.com/community-scripts/ProxmoxVE/pull/15813))
- Notediscovery ([#15811](https://github.com/community-scripts/ProxmoxVE/pull/15811))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Pin Immich to v3.0.3 [@vhsdream](https://github.com/vhsdream) ([#15790](https://github.com/community-scripts/ProxmoxVE/pull/15790))
## 2026-07-15
### 🆕 New Scripts
- Nexterm ([#15688](https://github.com/community-scripts/ProxmoxVE/pull/15688))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- 2fauth: minor fixes for 8.0.0 [@MickLesk](https://github.com/MickLesk) ([#15795](https://github.com/community-scripts/ProxmoxVE/pull/15795))
- SnapOtter: refactor update process to prebuild [@MickLesk](https://github.com/MickLesk) ([#15797](https://github.com/community-scripts/ProxmoxVE/pull/15797))
### 💾 Core
- #### 🔧 Refactor
- tools.func: default Docker setup to official repo [@MickLesk](https://github.com/MickLesk) ([#15794](https://github.com/community-scripts/ProxmoxVE/pull/15794))
## 2026-07-14
### 🆕 New Scripts
- Grav ([#15773](https://github.com/community-scripts/ProxmoxVE/pull/15773))
- Yuvomi ([#15772](https://github.com/community-scripts/ProxmoxVE/pull/15772))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Lychee: Preserve uploads and ownership during update [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15768](https://github.com/community-scripts/ProxmoxVE/pull/15768))
- Wanderer: Clean deploy and install plugins for v0.20.0 update [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15759](https://github.com/community-scripts/ProxmoxVE/pull/15759))
- FileFlows: Handle update API 401, force update, and Node install [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15766](https://github.com/community-scripts/ProxmoxVE/pull/15766))
- BirdNET-Go: Match new upstream release asset naming [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15758](https://github.com/community-scripts/ProxmoxVE/pull/15758))
- [Upstream Fix] Immich: Fix loader priority [@vhsdream](https://github.com/vhsdream) ([#15755](https://github.com/community-scripts/ProxmoxVE/pull/15755))
- #### ✨ New Features
- Bump OpenCloud version to v7.2.2 [@MickLesk](https://github.com/MickLesk) ([#15769](https://github.com/community-scripts/ProxmoxVE/pull/15769))
- Silverbullet: Add optional Runtime API install via Chromium [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15761](https://github.com/community-scripts/ProxmoxVE/pull/15761))
- #### 💥 Breaking Changes
- Pangolin: Bump to 1.20.0 | BREAKING: Switch to PostgreSQL [@MickLesk](https://github.com/MickLesk) ([#15682](https://github.com/community-scripts/ProxmoxVE/pull/15682))
- #### 🔧 Refactor
- AFFiNE: Pin to v0.26.3 [@MickLesk](https://github.com/MickLesk) ([#15782](https://github.com/community-scripts/ProxmoxVE/pull/15782))
## 2026-07-13
### 🆕 New Scripts
- LeafWiki ([#15748](https://github.com/community-scripts/ProxmoxVE/pull/15748))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- fix(hyperion): keep service running after container reboot [@TowyTowy](https://github.com/TowyTowy) ([#15653](https://github.com/community-scripts/ProxmoxVE/pull/15653))
- Change sign-in URL to admin URL in affine.sh [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15741](https://github.com/community-scripts/ProxmoxVE/pull/15741))
- immich: use actual PostgreSQL version for VectorChord package lookup [@mnavon](https://github.com/mnavon) ([#15705](https://github.com/community-scripts/ProxmoxVE/pull/15705))
- fix storyteller release selection for stable web tags [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15736](https://github.com/community-scripts/ProxmoxVE/pull/15736))
- Docmost: Fix update procedure [@MickLesk](https://github.com/MickLesk) ([#15732](https://github.com/community-scripts/ProxmoxVE/pull/15732))
- fix(shinobi): remove obsolete --unsafe-perm npm flag [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15730](https://github.com/community-scripts/ProxmoxVE/pull/15730))
- #### 💥 Breaking Changes
- reitti: update to v5 [@CrazyWolf13](https://github.com/CrazyWolf13) ([#15635](https://github.com/community-scripts/ProxmoxVE/pull/15635))
### 💾 Core
- #### 🐞 Bug Fixes
- fix(build.func): parse script status without jq dependency [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15729](https://github.com/community-scripts/ProxmoxVE/pull/15729))
- #### 🔧 Refactor
- tools.func: some improvements (sql injection / command injection / guard) [@MickLesk](https://github.com/MickLesk) ([#15661](https://github.com/community-scripts/ProxmoxVE/pull/15661))
## 2026-07-12
### 🆕 New Scripts
- AFFiNE ([#15690](https://github.com/community-scripts/ProxmoxVE/pull/15690))
### 🚀 Updated Scripts
- Immich: Bump version to 3.0.2 [@vhsdream](https://github.com/vhsdream) ([#15668](https://github.com/community-scripts/ProxmoxVE/pull/15668))
### ❔ Uncategorized
- fix(immich): correct Python indentation error in ct/immich.sh heredoc patch [@Copilot](https://github.com/Copilot) ([#15723](https://github.com/community-scripts/ProxmoxVE/pull/15723))
## 2026-07-11 ## 2026-07-11
### 🆕 New Scripts ### 🆕 New Scripts
+125 -28
View File
@@ -77,9 +77,6 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
@@ -93,7 +90,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
<details> <details>
<summary><h4>July (18 entries)</h4></summary> <summary><h4>July (11 entries)</h4></summary>
[View July 2026 Changelog](.github/changelogs/2026/07.md) [View July 2026 Changelog](.github/changelogs/2026/07.md)
@@ -505,30 +502,6 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
</details> </details>
## 2026-07-19
### 💾 Core
- Revert "core: add configurable host CA inheritance during bootstrap" [@MickLesk](https://github.com/MickLesk) ([#15886](https://github.com/community-scripts/ProxmoxVE/pull/15886))
## 2026-07-18
### 💾 Core
- #### ✨ New Features
- core: add configurable host CA inheritance during bootstrap [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15840](https://github.com/community-scripts/ProxmoxVE/pull/15840))
- #### 🔧 Refactor
- tools.func: Safe Delete Directorys & Update PYTHON_VERSION with setup_uv [@MickLesk](https://github.com/MickLesk) ([#15870](https://github.com/community-scripts/ProxmoxVE/pull/15870))
### 🧰 Tools
- #### ✨ New Features
- [tools.update-lxcs] feat: optional reporting success/failures to heathchecks.io (or others) [@sir106](https://github.com/sir106) ([#15701](https://github.com/community-scripts/ProxmoxVE/pull/15701))
## 2026-07-17 ## 2026-07-17
### 🆕 New Scripts ### 🆕 New Scripts
@@ -1163,3 +1136,127 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
- chore(ct): sync coredns defaults with PocketBase [@github-actions[bot]](https://github.com/github-actions[bot]) ([#15182](https://github.com/community-scripts/ProxmoxVE/pull/15182)) - chore(ct): sync coredns defaults with PocketBase [@github-actions[bot]](https://github.com/github-actions[bot]) ([#15182](https://github.com/community-scripts/ProxmoxVE/pull/15182))
- chore(ct): sync gatus defaults with PocketBase [@github-actions[bot]](https://github.com/github-actions[bot]) ([#15184](https://github.com/community-scripts/ProxmoxVE/pull/15184)) - chore(ct): sync gatus defaults with PocketBase [@github-actions[bot]](https://github.com/github-actions[bot]) ([#15184](https://github.com/community-scripts/ProxmoxVE/pull/15184))
- chore(ct): sync bitmagnet defaults with PocketBase [@github-actions[bot]](https://github.com/github-actions[bot]) ([#15183](https://github.com/community-scripts/ProxmoxVE/pull/15183)) - chore(ct): sync bitmagnet defaults with PocketBase [@github-actions[bot]](https://github.com/github-actions[bot]) ([#15183](https://github.com/community-scripts/ProxmoxVE/pull/15183))
## 2026-06-18
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- flowise: add deps / uv / python 3.11 [@MickLesk](https://github.com/MickLesk) ([#15177](https://github.com/community-scripts/ProxmoxVE/pull/15177))
- #### 💥 Breaking Changes
- refactor: crafty-controller [@CrazyWolf13](https://github.com/CrazyWolf13) ([#15178](https://github.com/community-scripts/ProxmoxVE/pull/15178))
## 2026-06-17
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- kasm: fix release detection [@CrazyWolf13](https://github.com/CrazyWolf13) ([#15151](https://github.com/community-scripts/ProxmoxVE/pull/15151))
- #### ✨ New Features
- trek: update install and upgrade workflow for v3.1.0 [@MickLesk](https://github.com/MickLesk) ([#15165](https://github.com/community-scripts/ProxmoxVE/pull/15165))
- #### 💥 Breaking Changes
- TREK: Pin version [@tremor021](https://github.com/tremor021) ([#15156](https://github.com/community-scripts/ProxmoxVE/pull/15156))
- #### 🔧 Refactor
- chore(paperless-ngx): pin version to prevent v3 update [@tomfrenzel](https://github.com/tomfrenzel) ([#15171](https://github.com/community-scripts/ProxmoxVE/pull/15171))
### 🧰 Tools
- #### 🐞 Bug Fixes
- immich public proxy: replace npm install with npm ci for consistent dependency installation [@MickLesk](https://github.com/MickLesk) ([#15166](https://github.com/community-scripts/ProxmoxVE/pull/15166))
## 2026-06-16
### 🆕 New Scripts
- Feishin ([#15130](https://github.com/community-scripts/ProxmoxVE/pull/15130))
- Kiwix ([#15131](https://github.com/community-scripts/ProxmoxVE/pull/15131))
- Add runtime status guard and deleted script stubs [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15125](https://github.com/community-scripts/ProxmoxVE/pull/15125))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- fix(degoog): use localhost for valkey url [@ethan-hgwr](https://github.com/ethan-hgwr) ([#15149](https://github.com/community-scripts/ProxmoxVE/pull/15149))
- Fix InvoiceShelf install/update Yarn package manager mismatch [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15141](https://github.com/community-scripts/ProxmoxVE/pull/15141))
- fix storyteller install failure with yarn 4 corepack [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15140](https://github.com/community-scripts/ProxmoxVE/pull/15140))
- fix: generate policy-compliant OpenObserve root password [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15137](https://github.com/community-scripts/ProxmoxVE/pull/15137))
## 2026-06-15
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Watcharr: Clean install on update [@tremor021](https://github.com/tremor021) ([#15119](https://github.com/community-scripts/ProxmoxVE/pull/15119))
- Vaultwarden: extend version check for VaultWarden update [@MickLesk](https://github.com/MickLesk) ([#15105](https://github.com/community-scripts/ProxmoxVE/pull/15105))
- #### ✨ New Features
- degoog: add curl-impersonate to script [@MickLesk](https://github.com/MickLesk) ([#15117](https://github.com/community-scripts/ProxmoxVE/pull/15117))
### 💾 Core
- #### ✨ New Features
- tools.func: extend mesa-vulkan-drivers and vulkan-tools to installation for ARC GPU's [@MickLesk](https://github.com/MickLesk) ([#15106](https://github.com/community-scripts/ProxmoxVE/pull/15106))
- #### 🔧 Refactor
- core: improve mirror selection and error handling [@MickLesk](https://github.com/MickLesk) ([#15108](https://github.com/community-scripts/ProxmoxVE/pull/15108))
- core: implement gateway validation for DHCP and static networks [@MickLesk](https://github.com/MickLesk) ([#15107](https://github.com/community-scripts/ProxmoxVE/pull/15107))
## 2026-06-14
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Iinvoiceninja: fix nginx setup assets port [@MickLesk](https://github.com/MickLesk) ([#15090](https://github.com/community-scripts/ProxmoxVE/pull/15090))
- CheckMK: remove stale backup site before creating new backup during update [@MickLesk](https://github.com/MickLesk) ([#15088](https://github.com/community-scripts/ProxmoxVE/pull/15088))
- #### 🔧 Refactor
- Refactor: Implement backup functions for scripts C-D [@tremor021](https://github.com/tremor021) ([#15096](https://github.com/community-scripts/ProxmoxVE/pull/15096))
## 2026-06-13
### 🆕 New Scripts
- BookOrbit ([#15080](https://github.com/community-scripts/ProxmoxVE/pull/15080))
### 🚀 Updated Scripts
- Update authentik version to 2026.5.3 [@thieneret](https://github.com/thieneret) ([#15093](https://github.com/community-scripts/ProxmoxVE/pull/15093))
- #### 🐞 Bug Fixes
- Immich: Update image-processing libraries [@vhsdream](https://github.com/vhsdream) ([#15082](https://github.com/community-scripts/ProxmoxVE/pull/15082))
- HomeBox: Support v0.26.0 [@tomfrenzel](https://github.com/tomfrenzel) ([#15086](https://github.com/community-scripts/ProxmoxVE/pull/15086))
- #### 🔧 Refactor
- Refactor: Implement backup functions for scripts A-B [@tremor021](https://github.com/tremor021) ([#15075](https://github.com/community-scripts/ProxmoxVE/pull/15075))
## 2026-06-12
### 🆕 New Scripts
- Twenty ([#15047](https://github.com/community-scripts/ProxmoxVE/pull/15047))
- Alpine-Cinny ([#15044](https://github.com/community-scripts/ProxmoxVE/pull/15044))
### 💾 Core
- #### ✨ New Features
- [core] Implement backup and restore functions [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15067](https://github.com/community-scripts/ProxmoxVE/pull/15067))
+15 -144
View File
@@ -1009,7 +1009,6 @@ base_settings() {
APT_CACHER=${var_apt_cacher:-""} APT_CACHER=${var_apt_cacher:-""}
APT_CACHER_IP=${var_apt_cacher_ip:-""} APT_CACHER_IP=${var_apt_cacher_ip:-""}
INHERIT_HOST_CA="${var_inherit_host_ca:-auto}"
# Runtime check: Verify APT cacher is reachable if configured # Runtime check: Verify APT cacher is reachable if configured
if [[ -n "$APT_CACHER_IP" && "$APT_CACHER" == "yes" ]]; then if [[ -n "$APT_CACHER_IP" && "$APT_CACHER" == "yes" ]]; then
@@ -1089,7 +1088,7 @@ load_vars_file() {
# Allowed var_* keys # Allowed var_* keys
local VAR_WHITELIST=( local VAR_WHITELIST=(
var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_github_token var_gpu var_http_no_proxy var_http_proxy var_inherit_host_ca var_keyctl var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_github_token var_gpu var_http_no_proxy var_http_proxy var_keyctl
var_gateway var_hostname var_ipv6_method var_mac var_mknod var_mount_fs var_mtu var_gateway var_hostname var_ipv6_method var_mac var_mknod var_mount_fs var_mtu
var_net var_nesting var_ns var_os var_protection var_pw var_ram var_tags var_timezone var_tun var_unprivileged var_net var_nesting var_ns var_os var_protection var_pw var_ram var_tags var_timezone var_tun var_unprivileged
var_verbose var_version var_vlan var_ssh var_ssh_authorized_key var_container_storage var_template_storage var_searchdomain var_verbose var_version var_vlan var_ssh var_ssh_authorized_key var_container_storage var_template_storage var_searchdomain
@@ -1286,12 +1285,6 @@ load_vars_file() {
continue continue
fi fi
;; ;;
var_inherit_host_ca)
if [[ "$var_val" != "yes" && "$var_val" != "no" && "$var_val" != "auto" ]]; then
msg_warn "Invalid host CA inheritance value '$var_val' in $file (must be yes/no/auto), ignoring"
continue
fi
;;
var_container_storage | var_template_storage) var_container_storage | var_template_storage)
# Validate that the storage exists and is active on the current node # Validate that the storage exists and is active on the current node
local _storage_status local _storage_status
@@ -1331,7 +1324,7 @@ default_var_settings() {
# Allowed var_* keys (alphabetically sorted) # Allowed var_* keys (alphabetically sorted)
# Note: Removed var_ctid (can only exist once), var_ipv6_static (static IPs are unique) # Note: Removed var_ctid (can only exist once), var_ipv6_static (static IPs are unique)
local VAR_WHITELIST=( local VAR_WHITELIST=(
var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_github_token var_gpu var_http_no_proxy var_http_proxy var_inherit_host_ca var_keyctl var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_github_token var_gpu var_http_no_proxy var_http_proxy var_keyctl
var_gateway var_hostname var_ipv6_method var_mac var_mknod var_mount_fs var_mtu var_gateway var_hostname var_ipv6_method var_mac var_mknod var_mount_fs var_mtu
var_net var_nesting var_ns var_os var_protection var_pw var_ram var_tags var_timezone var_tun var_unprivileged var_net var_nesting var_ns var_os var_protection var_pw var_ram var_tags var_timezone var_tun var_unprivileged
var_verbose var_version var_vlan var_ssh var_ssh_authorized_key var_container_storage var_template_storage var_verbose var_version var_vlan var_ssh var_ssh_authorized_key var_container_storage var_template_storage
@@ -1414,7 +1407,6 @@ var_ssh=no
# HTTP/HTTPS proxy (optional - for networks requiring a proxy) # HTTP/HTTPS proxy (optional - for networks requiring a proxy)
# var_http_proxy=http://proxy.local:8080 # var_http_proxy=http://proxy.local:8080
# var_http_no_proxy=localhost,127.0.0.1,.local # var_http_no_proxy=localhost,127.0.0.1,.local
# var_inherit_host_ca=auto
# Features/Tags/verbosity # Features/Tags/verbosity
var_fuse=no var_fuse=no
@@ -1515,7 +1507,7 @@ get_app_defaults_path() {
if ! declare -p VAR_WHITELIST >/dev/null 2>&1; then if ! declare -p VAR_WHITELIST >/dev/null 2>&1; then
# Note: Removed var_ctid (can only exist once), var_ipv6_static (static IPs are unique) # Note: Removed var_ctid (can only exist once), var_ipv6_static (static IPs are unique)
declare -ag VAR_WHITELIST=( declare -ag VAR_WHITELIST=(
var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_github_token var_gpu var_http_no_proxy var_http_proxy var_inherit_host_ca var_keyctl var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_github_token var_gpu var_http_no_proxy var_http_proxy var_keyctl
var_gateway var_hostname var_ipv6_method var_mac var_mknod var_mount_fs var_mtu var_gateway var_hostname var_ipv6_method var_mac var_mknod var_mount_fs var_mtu
var_net var_nesting var_ns var_os var_protection var_pw var_ram var_tags var_timezone var_tun var_unprivileged var_net var_nesting var_ns var_os var_protection var_pw var_ram var_tags var_timezone var_tun var_unprivileged
var_verbose var_version var_vlan var_ssh var_ssh_authorized_key var_container_storage var_template_storage var_searchdomain var_verbose var_version var_vlan var_ssh var_ssh_authorized_key var_container_storage var_template_storage var_searchdomain
@@ -1665,7 +1657,6 @@ _build_current_app_vars_tmp() {
_apt_cacher_ip="${APT_CACHER_IP:-}" _apt_cacher_ip="${APT_CACHER_IP:-}"
_http_proxy="${HTTP_PROXY:-${var_http_proxy:-}}" _http_proxy="${HTTP_PROXY:-${var_http_proxy:-}}"
_http_no_proxy="${HTTP_NO_PROXY:-${var_http_no_proxy:-}}" _http_no_proxy="${HTTP_NO_PROXY:-${var_http_no_proxy:-}}"
_inherit_host_ca="${INHERIT_HOST_CA:-${var_inherit_host_ca:-auto}}"
_fuse="${ENABLE_FUSE:-no}" _fuse="${ENABLE_FUSE:-no}"
_tun="${ENABLE_TUN:-no}" _tun="${ENABLE_TUN:-no}"
_gpu="${ENABLE_GPU:-no}" _gpu="${ENABLE_GPU:-no}"
@@ -1719,7 +1710,6 @@ _build_current_app_vars_tmp() {
[ -n "$_apt_cacher_ip" ] && echo "var_apt_cacher_ip=$(_sanitize_value "$_apt_cacher_ip")" [ -n "$_apt_cacher_ip" ] && echo "var_apt_cacher_ip=$(_sanitize_value "$_apt_cacher_ip")"
[ -n "$_http_proxy" ] && echo "var_http_proxy=$(_sanitize_value "$_http_proxy")" [ -n "$_http_proxy" ] && echo "var_http_proxy=$(_sanitize_value "$_http_proxy")"
[ -n "$_http_no_proxy" ] && echo "var_http_no_proxy=$(_sanitize_value "$_http_no_proxy")" [ -n "$_http_no_proxy" ] && echo "var_http_no_proxy=$(_sanitize_value "$_http_no_proxy")"
[ -n "$_inherit_host_ca" ] && echo "var_inherit_host_ca=$(_sanitize_value "$_inherit_host_ca")"
[ -n "$_fuse" ] && echo "var_fuse=$(_sanitize_value "$_fuse")" [ -n "$_fuse" ] && echo "var_fuse=$(_sanitize_value "$_fuse")"
[ -n "$_tun" ] && echo "var_tun=$(_sanitize_value "$_tun")" [ -n "$_tun" ] && echo "var_tun=$(_sanitize_value "$_tun")"
@@ -1884,7 +1874,7 @@ advanced_settings() {
TAGS="community-script${var_tags:+;${var_tags}}" TAGS="community-script${var_tags:+;${var_tags}}"
fi fi
local STEP=1 local STEP=1
local MAX_STEP=31 local MAX_STEP=30
# Store values for back navigation - inherit from var_* app defaults # Store values for back navigation - inherit from var_* app defaults
local _ct_type="${var_unprivileged:-1}" local _ct_type="${var_unprivileged:-1}"
@@ -1906,7 +1896,6 @@ advanced_settings() {
local _apt_cacher_ip="${var_apt_cacher_ip:-}" local _apt_cacher_ip="${var_apt_cacher_ip:-}"
local _http_proxy="${var_http_proxy:-}" local _http_proxy="${var_http_proxy:-}"
local _http_no_proxy="${var_http_no_proxy:-}" local _http_no_proxy="${var_http_no_proxy:-}"
local _inherit_host_ca="${var_inherit_host_ca:-auto}"
local _mtu="${var_mtu:-}" local _mtu="${var_mtu:-}"
local _sd="${var_searchdomain:-}" local _sd="${var_searchdomain:-}"
local _ns="${var_ns:-}" local _ns="${var_ns:-}"
@@ -2736,47 +2725,9 @@ advanced_settings() {
;; ;;
# ═══════════════════════════════════════════════════════════════════════════ # ═══════════════════════════════════════════════════════════════════════════
# STEP 25: Host CA Inheritance # STEP 25: Container Timezone
# ═══════════════════════════════════════════════════════════════════════════ # ═══════════════════════════════════════════════════════════════════════════
25) 25)
local host_ca_count=0
local host_ca_dir="/usr/local/share/ca-certificates"
local cert
shopt -s nullglob
for cert in "$host_ca_dir"/*.crt; do
host_ca_count=$((host_ca_count + 1))
done
shopt -u nullglob
if [[ $host_ca_count -eq 0 ]]; then
_inherit_host_ca="auto"
((STEP++))
continue
fi
local host_ca_default_flag=""
[[ "$_inherit_host_ca" == "no" ]] && host_ca_default_flag="--defaultno"
if whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
--title "HOST CA INHERITANCE" \
--ok-button "Next" --cancel-button "Back" \
$host_ca_default_flag \
--yesno "\nInherit host CA certificates into this container?\n\nDetected on host: ${host_ca_count} certificate(s) in:\n${host_ca_dir}\n\nRecommended for private PKI / TLS-inspection environments.\n\n(App default: ${var_inherit_host_ca:-auto})" 16 72; then
_inherit_host_ca="yes"
else
if [ $? -eq 1 ]; then
_inherit_host_ca="no"
else
((STEP--))
continue
fi
fi
((STEP++))
;;
# ═══════════════════════════════════════════════════════════════════════════
# STEP 26: Container Timezone
# ═══════════════════════════════════════════════════════════════════════════
26)
local tz_hint="$_ct_timezone" local tz_hint="$_ct_timezone"
[[ -z "$tz_hint" ]] && tz_hint="(empty - will use host timezone)" [[ -z "$tz_hint" ]] && tz_hint="(empty - will use host timezone)"
@@ -2799,9 +2750,9 @@ advanced_settings() {
;; ;;
# ═══════════════════════════════════════════════════════════════════════════ # ═══════════════════════════════════════════════════════════════════════════
# STEP 27: Container Protection # STEP 26: Container Protection
# ═══════════════════════════════════════════════════════════════════════════ # ═══════════════════════════════════════════════════════════════════════════
27) 26)
local protect_default_flag="--defaultno" local protect_default_flag="--defaultno"
[[ "$_protect_ct" == "yes" || "$_protect_ct" == "1" ]] && protect_default_flag="" [[ "$_protect_ct" == "yes" || "$_protect_ct" == "1" ]] && protect_default_flag=""
@@ -2823,9 +2774,9 @@ advanced_settings() {
;; ;;
# ═══════════════════════════════════════════════════════════════════════════ # ═══════════════════════════════════════════════════════════════════════════
# STEP 28: Device Node Creation (mknod) # STEP 27: Device Node Creation (mknod)
# ═══════════════════════════════════════════════════════════════════════════ # ═══════════════════════════════════════════════════════════════════════════
28) 27)
local mknod_default_flag="--defaultno" local mknod_default_flag="--defaultno"
[[ "$_enable_mknod" == "1" ]] && mknod_default_flag="" [[ "$_enable_mknod" == "1" ]] && mknod_default_flag=""
@@ -2847,9 +2798,9 @@ advanced_settings() {
;; ;;
# ═══════════════════════════════════════════════════════════════════════════ # ═══════════════════════════════════════════════════════════════════════════
# STEP 29: Mount Filesystems # STEP 28: Mount Filesystems
# ═══════════════════════════════════════════════════════════════════════════ # ═══════════════════════════════════════════════════════════════════════════
29) 28)
local mount_hint="" local mount_hint=""
[[ -n "$_mount_fs" ]] && mount_hint="$_mount_fs" || mount_hint="(none)" [[ -n "$_mount_fs" ]] && mount_hint="$_mount_fs" || mount_hint="(none)"
@@ -2870,9 +2821,9 @@ advanced_settings() {
;; ;;
# ═══════════════════════════════════════════════════════════════════════════ # ═══════════════════════════════════════════════════════════════════════════
# STEP 30: Optional host-side post-install hook (path on the Proxmox HOST) # STEP 29: Optional host-side post-install hook (path on the Proxmox HOST)
# ═══════════════════════════════════════════════════════════════════════════ # ═══════════════════════════════════════════════════════════════════════════
30) 29)
local _hook_prompt="Optional: absolute path to a *.sh file ON THE PROXMOX HOST. local _hook_prompt="Optional: absolute path to a *.sh file ON THE PROXMOX HOST.
It runs as root on the HOST (NOT in the LXC) after the container It runs as root on the HOST (NOT in the LXC) after the container
@@ -2922,9 +2873,9 @@ Leave empty to skip."
;; ;;
# ═══════════════════════════════════════════════════════════════════════════ # ═══════════════════════════════════════════════════════════════════════════
# STEP 31: Verbose Mode & Confirmation # STEP 30: Verbose Mode & Confirmation
# ═══════════════════════════════════════════════════════════════════════════ # ═══════════════════════════════════════════════════════════════════════════
31) 30)
local verbose_default_flag="--defaultno" local verbose_default_flag="--defaultno"
[[ "$_verbose" == "yes" ]] && verbose_default_flag="" [[ "$_verbose" == "yes" ]] && verbose_default_flag=""
@@ -2953,7 +2904,6 @@ Leave empty to skip."
local apt_display="${_apt_cacher:-no}" local apt_display="${_apt_cacher:-no}"
[[ "$_apt_cacher" == "yes" && -n "$_apt_cacher_ip" ]] && apt_display="$_apt_cacher_ip" [[ "$_apt_cacher" == "yes" && -n "$_apt_cacher_ip" ]] && apt_display="$_apt_cacher_ip"
local http_proxy_display="${_http_proxy:-(none)}" local http_proxy_display="${_http_proxy:-(none)}"
local inherit_ca_display="${_inherit_host_ca:-auto}"
local post_install_display="${_post_install:-(none)}" local post_install_display="${_post_install:-(none)}"
local post_install_warn="" local post_install_warn=""
@@ -2984,7 +2934,6 @@ Advanced:
Timezone: $tz_display Timezone: $tz_display
APT Cacher: $apt_display APT Cacher: $apt_display
HTTP Proxy: $http_proxy_display HTTP Proxy: $http_proxy_display
Inherit Host CAs: $inherit_ca_display
Verbose: $_verbose Verbose: $_verbose
Post-Install Script: ${post_install_display}${post_install_warn}" Post-Install Script: ${post_install_display}${post_install_warn}"
@@ -3030,7 +2979,6 @@ Advanced:
APT_CACHER_IP="$_apt_cacher_ip" APT_CACHER_IP="$_apt_cacher_ip"
HTTP_PROXY="$_http_proxy" HTTP_PROXY="$_http_proxy"
HTTP_NO_PROXY="$_http_no_proxy" HTTP_NO_PROXY="$_http_no_proxy"
INHERIT_HOST_CA="$_inherit_host_ca"
VERBOSE="$_verbose" VERBOSE="$_verbose"
var_post_install="$_post_install" var_post_install="$_post_install"
@@ -3049,7 +2997,6 @@ Advanced:
var_sdn_vnet="$_sdn_vnet" var_sdn_vnet="$_sdn_vnet"
var_http_proxy="$_http_proxy" var_http_proxy="$_http_proxy"
var_http_no_proxy="$_http_no_proxy" var_http_no_proxy="$_http_no_proxy"
var_inherit_host_ca="$_inherit_host_ca"
# Format optional values # Format optional values
[[ -n "$_mtu" ]] && MTU=",mtu=$_mtu" || MTU="" [[ -n "$_mtu" ]] && MTU=",mtu=$_mtu" || MTU=""
@@ -3998,81 +3945,6 @@ EOF
msg_ok "Applied HTTP proxy in container" msg_ok "Applied HTTP proxy in container"
} }
# ------------------------------------------------------------------------------
# _apply_host_ca_certs_in_container()
#
# - Copies administrator-provided CA certificates from the Proxmox host into the
# container before base package bootstrap
# - Source: /usr/local/share/ca-certificates/*.crt (Debian convention)
# - Refreshes the container trust store when update-ca-certificates is available
# - No-op when no host certificates are present; failures are non-fatal
# ------------------------------------------------------------------------------
_apply_host_ca_certs_in_container() {
local host_ca_dir="/usr/local/share/ca-certificates"
[[ -z "${CTID:-}" ]] && return 0
local inherit_host_ca="${INHERIT_HOST_CA:-${var_inherit_host_ca:-auto}}"
local -a host_certs=()
local cert
shopt -s nullglob
for cert in "$host_ca_dir"/*.crt; do
host_certs+=("$cert")
done
shopt -u nullglob
[[ ${#host_certs[@]} -eq 0 ]] && return 0
case "${inherit_host_ca,,}" in
no | false | 0 | off)
msg_warn "Skipping host CA inheritance by configuration (${#host_certs[@]} host certificate(s) available)"
return 0
;;
esac
msg_info "Inheriting host CA certificates into container"
local found=${#host_certs[@]}
local copied=0
local skipped=0
local cert_name
pct exec "$CTID" -- mkdir -p /usr/local/share/ca-certificates >/dev/null 2>&1 || {
msg_warn "Failed to create CA certificate directory in container"
return 0
}
for cert in "${host_certs[@]}"; do
cert_name="$(basename "$cert")"
if [[ ! -r "$cert" || "$cert_name" != *.crt ]]; then
msg_warn "Skipping invalid or unreadable host CA certificate: ${cert_name}"
skipped=$((skipped + 1))
continue
fi
if pct push "$CTID" "$cert" "/usr/local/share/ca-certificates/${cert_name}" >/dev/null 2>&1; then
pct exec "$CTID" -- chmod 644 "/usr/local/share/ca-certificates/${cert_name}" >/dev/null 2>&1 || true
copied=$((copied + 1))
else
msg_warn "Failed to push host CA certificate: ${cert_name}"
skipped=$((skipped + 1))
fi
done
if [[ $copied -eq 0 ]]; then
msg_warn "No host CA certificates were copied (${found} found, ${skipped} skipped)"
return 0
fi
local refresh_shell="bash"
[[ "$var_os" == "alpine" ]] && refresh_shell="ash"
if pct exec "$CTID" -- "$refresh_shell" -c 'command -v update-ca-certificates >/dev/null 2>&1 && update-ca-certificates' >/dev/null 2>&1; then
msg_ok "Inherited ${copied} host CA certificate(s) and updated trust store (${skipped} skipped)"
else
msg_warn "Copied ${copied} host CA certificate(s), but trust store update failed or update-ca-certificates is unavailable (${skipped} skipped)"
fi
}
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# build_container() # build_container()
# #
@@ -4693,7 +4565,6 @@ EOF
local install_exit_code=0 local install_exit_code=0
_apply_http_proxy_in_container _apply_http_proxy_in_container
_apply_host_ca_certs_in_container
# Continue with standard container setup # Continue with standard container setup
if [ "$var_os" == "alpine" ]; then if [ "$var_os" == "alpine" ]; then
+11 -21
View File
@@ -2544,7 +2544,7 @@ fetch_and_deploy_gh_tag() {
mkdir -p "$target" mkdir -p "$target"
if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then
find "${target:?}" -mindepth 1 -delete rm -rf "${target:?}/"*
fi fi
tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || { tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || {
@@ -2737,7 +2737,7 @@ fetch_and_deploy_gl_tag() {
mkdir -p "$target" mkdir -p "$target"
if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then
find "${target:?}" -mindepth 1 -delete rm -rf "${target:?}/"*
fi fi
tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || { tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || {
@@ -3472,7 +3472,7 @@ fetch_and_deploy_codeberg_release() {
mkdir -p "$target" mkdir -p "$target"
if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then
find "${target:?}" -mindepth 1 -delete rm -rf "${target:?}/"*
fi fi
tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || { tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || {
@@ -3575,7 +3575,7 @@ fetch_and_deploy_codeberg_release() {
mkdir -p "$target" mkdir -p "$target"
if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then
find "${target:?}" -mindepth 1 -delete rm -rf "${target:?}/"*
fi fi
tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || { tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || {
@@ -3694,7 +3694,7 @@ fetch_and_deploy_codeberg_release() {
unpack_tmp=$(mktemp -d) unpack_tmp=$(mktemp -d)
mkdir -p "$target" mkdir -p "$target"
if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then
find "${target:?}" -mindepth 1 -delete rm -rf "${target:?}/"*
fi fi
if [[ "$filename" == *.zip ]]; then if [[ "$filename" == *.zip ]]; then
@@ -4112,7 +4112,7 @@ fetch_and_deploy_gh_release() {
mkdir -p "$target" mkdir -p "$target"
if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then
find "${target:?}" -mindepth 1 -delete rm -rf "${target:?}/"*
fi fi
tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || { tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || {
@@ -4292,7 +4292,7 @@ fetch_and_deploy_gh_release() {
unpack_tmp=$(mktemp -d) unpack_tmp=$(mktemp -d)
mkdir -p "$target" mkdir -p "$target"
if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then
find "${target:?}" -mindepth 1 -delete rm -rf "${target:?}/"*
fi fi
if [[ "$filename" == *.zip ]]; then if [[ "$filename" == *.zip ]]; then
@@ -7157,7 +7157,7 @@ setup_meilisearch() {
MEILI_DB_PATH="${MEILI_DB_PATH:-/var/lib/meilisearch/data}" MEILI_DB_PATH="${MEILI_DB_PATH:-/var/lib/meilisearch/data}"
msg_info "Removing old MeiliSearch database for migration" msg_info "Removing old MeiliSearch database for migration"
find "${MEILI_DB_PATH:?}" -mindepth 1 -delete rm -rf "${MEILI_DB_PATH:?}"/*
# Import dump using CLI flag (this is the supported method) # Import dump using CLI flag (this is the supported method)
local DUMP_FILE="${MEILI_DUMP_DIR}/${DUMP_UID}.dump" local DUMP_FILE="${MEILI_DUMP_DIR}/${DUMP_UID}.dump"
@@ -9131,16 +9131,6 @@ setup_uv() {
msg_ok "uvx wrapper installed" msg_ok "uvx wrapper installed"
fi fi
# Install specific Python version if requested (even when uv is already up to date)
if [[ -n "${PYTHON_VERSION:-}" ]]; then
msg_info "Installing Python $PYTHON_VERSION via uv"
$STD uv python install "$PYTHON_VERSION" || {
msg_error "Failed to install Python $PYTHON_VERSION"
return 150
}
msg_ok "Python $PYTHON_VERSION installed"
fi
return 0 return 0
fi fi
@@ -9400,7 +9390,7 @@ fetch_and_deploy_from_url() {
mkdir -p "$directory" mkdir -p "$directory"
if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then
find "${directory:?}" -mindepth 1 -delete rm -rf "${directory:?}/"*
fi fi
local unpack_tmp local unpack_tmp
@@ -9976,7 +9966,7 @@ fetch_and_deploy_gl_release() {
mkdir -p "$target" mkdir -p "$target"
if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then
find "${target:?}" -mindepth 1 -delete rm -rf "${target:?}/"*
fi fi
tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || { tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || {
@@ -10138,7 +10128,7 @@ fetch_and_deploy_gl_release() {
unpack_tmp=$(mktemp -d) unpack_tmp=$(mktemp -d)
mkdir -p "$target" mkdir -p "$target"
if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then
find "${target:?}" -mindepth 1 -delete rm -rf "${target:?}/"*
fi fi
if [[ "$filename" == *.zip ]]; then if [[ "$filename" == *.zip ]]; then
+2 -9
View File
@@ -116,9 +116,6 @@ add() {
# Add container IDs to exclude from updates (comma-separated): # Add container IDs to exclude from updates (comma-separated):
# EXCLUDE=100,101,102 # EXCLUDE=100,101,102
EXCLUDE= EXCLUDE=
# Healthchecks.io Ping URL (optional)
# PING_URL=
CONF CONF
ok "Created config ${CONF_FILE}" ok "Created config ${CONF_FILE}"
fi fi
@@ -238,11 +235,9 @@ view_cron_config() {
fi fi
if [[ -f "$CONF_FILE" ]]; then if [[ -f "$CONF_FILE" ]]; then
echo -e " \e[36mConfig file:\e[0m ${CONF_FILE}" echo -e " \e[36mConfig file:\e[0m ${CONF_FILE}"
local excludes ping_url local excludes
excludes=$(grep -oP '^\s*EXCLUDE\s*=\s*\K.*' "$CONF_FILE" 2>/dev/null || true) excludes=$(grep -oP '^\s*EXCLUDE\s*=\s*\K.*' "$CONF_FILE" 2>/dev/null || true)
ping_url=$(grep -oP '^\s*PING_URL\s*=\s*\K.*' "$CONF_FILE" 2>/dev/null | tr -d '"' | tr -d "'" || true)
echo -e " \e[36mExcluded:\e[0m ${excludes:-(none)}" echo -e " \e[36mExcluded:\e[0m ${excludes:-(none)}"
echo -e " \e[36mPing URL:\e[0m ${ping_url:-(none)}"
echo "" echo ""
echo -e " \e[90m--- ${CONF_FILE} ---\e[0m" echo -e " \e[90m--- ${CONF_FILE} ---\e[0m"
cat "$CONF_FILE" cat "$CONF_FILE"
@@ -289,11 +284,9 @@ show_status() {
fi fi
if [[ -f "$CONF_FILE" ]]; then if [[ -f "$CONF_FILE" ]]; then
local excludes ping_url local excludes
excludes=$(grep -oP '^\s*EXCLUDE\s*=\s*\K.*' "$CONF_FILE" 2>/dev/null || echo "(none)") excludes=$(grep -oP '^\s*EXCLUDE\s*=\s*\K.*' "$CONF_FILE" 2>/dev/null || echo "(none)")
ping_url=$(grep -oP '^\s*PING_URL\s*=\s*\K.*' "$CONF_FILE" 2>/dev/null | tr -d '"' | tr -d "'" || echo "(none)")
echo -e " \e[36mExcluded:\e[0m ${excludes:-"(none)"}" echo -e " \e[36mExcluded:\e[0m ${excludes:-"(none)"}"
echo -e " \e[36mPing URL:\e[0m ${ping_url:-"(none)"}"
fi fi
if [[ -f "$LOG_FILE" ]]; then if [[ -f "$LOG_FILE" ]]; then
+693
View File
@@ -0,0 +1,693 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk (CanbiZ)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/refs/heads/main/misc/core.func)
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true
load_functions
declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "storage-share-helper" "pve"
set -eEuo pipefail
function header_info() {
clear
cat <<"EOF"
_____ __ ___ _________
/ ___// /_____ _________ _____ ____ / | / _/ __ \
\__ \/ __/ __ \/ ___/ __ `/ __ `/ _ \ / /| | / // / / /
___/ / /_/ /_/ / / / /_/ / /_/ / __/ / ___ |_/ // /_/ /
/____/\__/\____/_/ \__,_/\__, /\___/ /_/ |_/___/_____/
/____/
Proxmox Storage Allrounder
SMB | NFS | iSCSI | LVM-on-iSCSI | LXC Mountpoints | Host Shares
EOF
}
pause() {
read -r -p "Press Enter to continue..." _
}
require_pve() {
if ! command -v pct >/dev/null 2>&1 || ! command -v pvesm >/dev/null 2>&1; then
msg_error "This script must run on a Proxmox VE host (pct/pvesm missing)."
exit 1
fi
}
ensure_packages() {
local packages=()
command -v whiptail >/dev/null 2>&1 || packages+=("whiptail")
command -v mount.cifs >/dev/null 2>&1 || packages+=("cifs-utils")
command -v showmount >/dev/null 2>&1 || packages+=("nfs-common")
command -v iscsiadm >/dev/null 2>&1 || packages+=("open-iscsi")
if [[ ${#packages[@]} -gt 0 ]]; then
msg_info "Installing required packages: ${packages[*]}"
apt update >/dev/null 2>&1
apt install -y "${packages[@]}" >/dev/null 2>&1
msg_ok "Dependencies installed"
fi
}
confirm_start() {
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Share Allrounder" \
--yesno "This AIO wizard can test and configure SMB/NFS/iSCSI, create/remove Proxmox storages, manage LXC mountpoints and optionally create host shares. Proceed?" 13 100
}
read_input() {
local title="$1"
local prompt="$2"
local default_value="${3:-}"
whiptail --backtitle "Proxmox VE Helper Scripts" --title "$title" \
--inputbox "$prompt" 11 100 "$default_value" 3>&1 1>&2 2>&3
}
read_password() {
local title="$1"
local prompt="$2"
whiptail --backtitle "Proxmox VE Helper Scripts" --title "$title" \
--passwordbox "$prompt" 11 100 3>&1 1>&2 2>&3
}
confirm_yes_no() {
local title="$1"
local prompt="$2"
local height="${3:-11}"
local width="${4:-100}"
whiptail --backtitle "Proxmox VE Helper Scripts" --title "$title" \
--yesno "$prompt" "$height" "$width"
}
# Destructive confirmation: defaults to "No" so a stray Enter never removes anything.
confirm_danger() {
local title="$1"
local prompt="$2"
local height="${3:-15}"
local width="${4:-100}"
whiptail --backtitle "Proxmox VE Helper Scripts" --title "$title" \
--defaultno --yesno "$prompt" "$height" "$width"
}
# Shown before slow data gathering. Goes to stderr: inside $(...) captures, stdout is
# swallowed — stderr is the real terminal.
show_loading() {
echo -e "${YW}Loading... gathering data, this can take a moment (CTRL+C to abort)${CL}" >&2
}
# Info popup that stays visible inside $(...) captures: whiptail draws its UI on
# stdout, so without 1>&2 the dialog would be captured and the script appears hung.
notice_box() {
local title="$1"
local text="$2"
whiptail --backtitle "Proxmox VE Helper Scripts" --title "$title" \
--msgbox "$text" 10 80 1>&2
}
# Interactive container picker (read-only): returns the chosen CTID on stdout.
pick_container() {
local title="$1"
local -a rows=()
local ctid status name label
show_loading
while IFS=$'\t' read -r ctid status name; do
[[ -z "$ctid" ]] && continue
label=$(printf '%-58s' "${name:-<no-name>} [${status}]")
rows+=("$ctid" "$label")
done < <(pct list 2>/dev/null | awk 'NR>1 {print $1"\t"$2"\t"$NF}')
if [[ ${#rows[@]} -eq 0 ]]; then
notice_box "$title" "No LXC containers found on this host."
return 1
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "$title" \
--menu "Select a container:" 24 80 16 "${rows[@]}" 3>&1 1>&2 2>&3
}
# Interactive multi-select picker over ALL mountpoints across ALL containers (read-only).
# Returns chosen entries as "<ctid>:<mpX>" tokens on stdout.
# Reads /etc/pve/lxc/*.conf directly (one 'pct config' per CT is far too slow);
# awk stops at the first '[section]' so snapshot mp entries are not listed.
pick_all_mountpoints_multi() {
local title="$1"
local -a rows=()
local conf ctid name line key def label
show_loading
for conf in /etc/pve/lxc/*.conf; do
[[ -e "$conf" ]] || continue
ctid="$(basename "$conf" .conf)"
name=$(awk '/^\[/{exit} $1=="hostname:"{print $2; exit}' "$conf")
while IFS= read -r line; do
[[ -z "$line" ]] && continue
key="${line%%:*}"
def="${line#*: }"
label=$(printf '%-86s' "CT ${ctid} ${name:-<no-name>} | ${key}: ${def}")
rows+=("${ctid}:${key}" "$label" "OFF")
done < <(awk '/^\[/{exit} /^mp[0-9]+:/{print}' "$conf")
done
if [[ ${#rows[@]} -eq 0 ]]; then
notice_box "$title" "No LXC mountpoints found on any container."
return 1
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "$title" \
--checklist "Select mountpoint(s) to remove across all containers (Space to toggle, Enter to confirm):" \
24 112 16 "${rows[@]}" 3>&1 1>&2 2>&3
}
# Interactive multi-select storage picker (read-only): returns chosen storage IDs on stdout.
pick_storages_multi() {
local title="$1"
local -a rows=()
local stype sid label
show_loading
while read -r stype sid; do
[[ -z "$sid" ]] && continue
label=$(printf '%-58s' "[${stype}]")
rows+=("$sid" "$label" "OFF")
done < <(awk -F': ' '/^[a-z]+: /{print $1, $2}' /etc/pve/storage.cfg 2>/dev/null)
if [[ ${#rows[@]} -eq 0 ]]; then
notice_box "$title" "No storages found in /etc/pve/storage.cfg."
return 1
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "$title" \
--checklist "Select storage(s) to remove (Space to toggle, Enter to confirm):" \
24 80 16 "${rows[@]}" 3>&1 1>&2 2>&3
}
# Interactive multi-select container picker (read-only): returns chosen CTIDs on stdout.
pick_containers_multi() {
local title="$1"
local -a rows=()
local ctid status name label
show_loading
while IFS=$'\t' read -r ctid status name; do
[[ -z "$ctid" ]] && continue
label=$(printf '%-58s' "${name:-<no-name>} [${status}]")
rows+=("$ctid" "$label" "OFF")
done < <(pct list 2>/dev/null | awk 'NR>1 {print $1"\t"$2"\t"$NF}')
if [[ ${#rows[@]} -eq 0 ]]; then
notice_box "$title" "No LXC containers found on this host."
return 1
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "$title" \
--checklist "Select one or more containers (Space to toggle, Enter to confirm):" \
24 80 16 "${rows[@]}" 3>&1 1>&2 2>&3
}
manual_smb_test() {
header_info
local server share username password domain vers mount_dir mount_opts
server=$(read_input "SMB Test" "SMB server/IP (e.g. 10.0.1.9)") || return
share=$(read_input "SMB Test" "Share name (without leading //)" "Proxmox") || return
username=$(read_input "SMB Test" "Username" "proxmox") || return
password=$(read_password "SMB Test" "Password for ${username}") || return
domain=$(read_input "SMB Test" "Domain/Workgroup (optional, leave empty if not needed)") || return
vers=$(read_input "SMB Test" "SMB version (e.g. 3.0, 3.1.1)" "3.1.1") || return
mount_dir="/mnt/test-smb"
mkdir -p "$mount_dir"
mount_opts="username=${username},password=${password},vers=${vers},sec=ntlmssp"
if [[ -n "$domain" ]]; then
mount_opts+=";domain=${domain}"
fi
msg_info "Testing SMB mount on ${mount_dir}"
if mount -t cifs "//${server}/${share}" "$mount_dir" -o "${mount_opts//;/,}" >/dev/null 2>&1; then
touch "${mount_dir}/smb-test-$(date +%s)" >/dev/null 2>&1 || true
umount "$mount_dir" >/dev/null 2>&1 || true
msg_ok "SMB test successful"
else
msg_error "SMB test failed. Check network/firewall/credentials/share permissions."
fi
pause
}
manual_nfs_test() {
header_info
local server export_path mount_dir
server=$(read_input "NFS Test" "NFS server/IP (e.g. 10.0.6.159)") || return
export_path=$(read_input "NFS Test" "NFS export path (e.g. /srv/proxmox-nfs)") || return
mount_dir="/mnt/test-nfs"
mkdir -p "$mount_dir"
msg_info "Testing NFS mount on ${mount_dir}"
if mount -t nfs "${server}:${export_path}" "$mount_dir" >/dev/null 2>&1; then
touch "${mount_dir}/nfs-test-$(date +%s)" >/dev/null 2>&1 || true
umount "$mount_dir" >/dev/null 2>&1 || true
msg_ok "NFS test successful"
else
msg_error "NFS test failed. Check export/firewall/network permissions."
fi
pause
}
manual_iscsi_discovery() {
header_info
local portal
portal=$(read_input "iSCSI Discovery" "iSCSI portal IP/FQDN (e.g. 10.0.1.20)") || return
msg_info "Running iSCSI target discovery on ${portal}"
if iscsiadm -m discovery -t sendtargets -p "$portal"; then
msg_ok "iSCSI discovery completed"
else
msg_error "iSCSI discovery failed"
fi
pause
}
add_smb_storage() {
header_info
local storage_id server share username password content nodes options
storage_id=$(read_input "Add SMB/CIFS Storage" "Storage ID (unique, e.g. smb-media)") || return
server=$(read_input "Add SMB/CIFS Storage" "SMB server/IP") || return
share=$(read_input "Add SMB/CIFS Storage" "Share name (without //)") || return
username=$(read_input "Add SMB/CIFS Storage" "Username") || return
password=$(read_password "Add SMB/CIFS Storage" "Password for ${username}") || return
content=$(read_input "Add SMB/CIFS Storage" "Content types (comma separated)" "backup,iso,vztmpl,snippets") || return
nodes=$(read_input "Add SMB/CIFS Storage" "Nodes (optional, comma separated)") || return
options=$(read_input "Add SMB/CIFS Storage" "Mount options (optional, e.g. vers=3.1.1,domain=WORKGROUP)") || return
local cmd=(pvesm add cifs "$storage_id" --server "$server" --share "$share" --username "$username" --password "$password" --content "$content")
[[ -n "$nodes" ]] && cmd+=(--nodes "$nodes")
[[ -n "$options" ]] && cmd+=(--options "$options")
if "${cmd[@]}" >/dev/null 2>&1; then
msg_ok "SMB storage '${storage_id}' added"
else
msg_error "Failed to add SMB storage '${storage_id}'"
fi
pause
}
add_nfs_storage() {
header_info
local storage_id server export_path content nodes options
storage_id=$(read_input "Add NFS Storage" "Storage ID (unique, e.g. nfs-vmdata)") || return
server=$(read_input "Add NFS Storage" "NFS server/IP") || return
export_path=$(read_input "Add NFS Storage" "Export path") || return
content=$(read_input "Add NFS Storage" "Content types (comma separated)" "images,rootdir") || return
nodes=$(read_input "Add NFS Storage" "Nodes (optional, comma separated)") || return
options=$(read_input "Add NFS Storage" "Mount options (optional)") || return
local cmd=(pvesm add nfs "$storage_id" --server "$server" --export "$export_path" --content "$content")
[[ -n "$nodes" ]] && cmd+=(--nodes "$nodes")
[[ -n "$options" ]] && cmd+=(--options "$options")
if "${cmd[@]}" >/dev/null 2>&1; then
msg_ok "NFS storage '${storage_id}' added"
else
msg_error "Failed to add NFS storage '${storage_id}'"
fi
pause
}
add_iscsi_storage() {
header_info
local storage_id portal target nodes
storage_id=$(read_input "Add iSCSI Storage" "Storage ID (unique, e.g. iscsi-synology)") || return
portal=$(read_input "Add iSCSI Storage" "Portal IP/FQDN") || return
target=$(read_input "Add iSCSI Storage" "Target IQN (e.g. iqn.2000-01.com.synology:...)") || return
nodes=$(read_input "Add iSCSI Storage" "Nodes (optional, comma separated)") || return
local cmd=(pvesm add iscsi "$storage_id" --portal "$portal" --target "$target")
[[ -n "$nodes" ]] && cmd+=(--nodes "$nodes")
if "${cmd[@]}" >/dev/null 2>&1; then
msg_ok "iSCSI storage '${storage_id}' added"
else
msg_error "Failed to add iSCSI storage '${storage_id}'"
fi
pause
}
add_lvm_on_base_storage() {
header_info
local storage_id base_storage vgname content shared
storage_id=$(read_input "Add LVM Storage" "LVM Storage ID (unique, e.g. lvm-iscsi01)") || return
base_storage=$(read_input "Add LVM Storage" "Base storage ID (usually iSCSI storage ID)") || return
vgname=$(read_input "Add LVM Storage" "Volume Group name on target") || return
content=$(read_input "Add LVM Storage" "Content types (comma separated)" "images,rootdir") || return
shared=$(read_input "Add LVM Storage" "Shared across nodes? 1=yes, 0=no" "1") || return
local cmd=(pvesm add lvm "$storage_id" --base "$base_storage" --vgname "$vgname" --content "$content" --shared "$shared")
if "${cmd[@]}" >/dev/null 2>&1; then
msg_ok "LVM storage '${storage_id}' added"
else
msg_error "Failed to add LVM storage '${storage_id}'"
fi
pause
}
remove_storage() {
header_info
local selection storage_id
local -a results=()
selection=$(pick_storages_multi "Remove Storage") || return
if [[ -z "$selection" ]]; then
msg_warn "No storage selected."
pause
return
fi
# Confirm each selected storage separately (defaults to No).
for storage_id in $selection; do
storage_id="${storage_id//\"/}"
[[ -z "$storage_id" ]] && continue
if confirm_danger "Remove Storage" \
"Really remove storage '${storage_id}' from the Proxmox config?
This removes the storage definition only.
Data on the underlying share/target is NOT deleted."; then
if pvesm remove "$storage_id" >/dev/null 2>&1; then
results+=("removed ${storage_id}")
else
results+=("FAILED ${storage_id}")
fi
else
results+=("skipped ${storage_id}")
fi
done
header_info
echo -e "${BL}Remove storage — result${CL}\n"
printf ' %s\n' "${results[@]}"
echo
pause
}
find_next_mp_slot() {
local ctid="$1"
local used
used=$(pct config "$ctid" | awk -F: '/^mp[0-9]+:/ {gsub("mp", "", $1); print $1}')
for i in $(seq 0 255); do
if ! grep -qx "$i" <<<"$used"; then
echo "$i"
return
fi
done
echo ""
}
add_lxc_mountpoint() {
header_info
local ctid host_path ct_path mp_slot
ctid=$(pick_container "LXC: add mountpoint") || return
host_path=$(read_input "LXC Mountpoint" "Host path (must exist, e.g. /mnt/pve/smb-media)") || return
ct_path=$(read_input "LXC Mountpoint" "Container path (e.g. /mnt/media)") || return
if [[ ! -d "$host_path" ]]; then
msg_error "Host path does not exist: ${host_path}"
pause
return
fi
mp_slot=$(find_next_mp_slot "$ctid")
if [[ -z "$mp_slot" ]]; then
msg_error "No free mp slot available for container ${ctid}"
pause
return
fi
confirm_yes_no "LXC: add mountpoint" \
"Add mp${mp_slot} to CT ${ctid}?
${host_path} -> ${ct_path}" 13 100 || return
if pct set "$ctid" -mp"$mp_slot" "$host_path",mp="$ct_path" >/dev/null 2>&1; then
msg_ok "Added mp${mp_slot}: ${host_path} -> ${ct_path} on CT ${ctid}"
msg_warn "If CT is unprivileged, ensure UID/GID mapping and filesystem permissions fit your workload."
else
msg_error "Failed to add mountpoint to CT ${ctid}"
fi
pause
}
remove_lxc_mountpoint() {
header_info
local selection entry ctid mp_key mp_def
local -a results=()
selection=$(pick_all_mountpoints_multi "LXC: remove mountpoint") || return
if [[ -z "$selection" ]]; then
msg_warn "No mountpoint selected."
pause
return
fi
# Confirm each selected mountpoint separately (defaults to No).
for entry in $selection; do
entry="${entry//\"/}"
[[ -z "$entry" ]] && continue
ctid="${entry%%:*}"
mp_key="${entry#*:}"
mp_def=$(pct config "$ctid" | awk -F': ' -v k="$mp_key" '$1==k{print $2}')
if confirm_danger "LXC: remove mountpoint" \
"Remove ${mp_key} from CT ${ctid}?
${mp_key}: ${mp_def}
This only detaches the mountpoint from the container.
Data on the host is NOT deleted."; then
if pct set "$ctid" -delete "$mp_key" >/dev/null 2>&1; then
results+=("removed CT ${ctid} ${mp_key}")
else
results+=("FAILED CT ${ctid} ${mp_key}")
fi
else
results+=("skipped CT ${ctid} ${mp_key}")
fi
done
header_info
echo -e "${BL}Remove mountpoint — result${CL}\n"
printf ' %s\n' "${results[@]}"
echo
pause
}
list_lxc_mountpoints() {
header_info
local selection ctid mps
selection=$(pick_containers_multi "LXC: list mountpoints") || return
if [[ -z "$selection" ]]; then
msg_warn "No container selected."
pause
return
fi
for ctid in $selection; do
ctid="${ctid//\"/}"
[[ -z "$ctid" ]] && continue
echo -e "${BL}Mountpoints for CT ${ctid}${CL}"
mps=$(pct config "$ctid" | awk '/^mp[0-9]+:/{print}')
if [[ -n "$mps" ]]; then
echo "$mps"
else
echo " (no mountpoints configured)"
fi
echo
done
pause
}
host_create_samba_share() {
header_info
local share_name share_path user_name user_pass
share_name=$(read_input "Host Samba Share" "Share name (e.g. data)") || return
share_path=$(read_input "Host Samba Share" "Share path on host (e.g. /srv/samba/data)" "/srv/samba/${share_name}") || return
user_name=$(read_input "Host Samba Share" "Linux/Samba username") || return
user_pass=$(read_password "Host Samba Share" "Password for ${user_name}") || return
msg_info "Installing Samba on host if needed"
apt update >/dev/null 2>&1
apt install -y samba >/dev/null 2>&1
mkdir -p "$share_path"
getent group sambashare >/dev/null 2>&1 || groupadd sambashare
id "$user_name" >/dev/null 2>&1 || useradd -M -s /usr/sbin/nologin -G sambashare "$user_name"
usermod -aG sambashare "$user_name"
chown -R root:sambashare "$share_path"
chmod 2775 "$share_path"
if ! (
echo "$user_pass"
echo "$user_pass"
) | smbpasswd -s -a "$user_name" >/dev/null 2>&1; then
msg_error "Failed to set Samba password for ${user_name}"
pause
return
fi
if ! grep -q "^\[${share_name}\]" /etc/samba/smb.conf; then
cat <<EOF >>/etc/samba/smb.conf
[${share_name}]
comment = Proxmox Host Share (${share_name})
path = ${share_path}
browseable = yes
read only = no
guest ok = no
create mask = 0664
directory mask = 2775
valid users = @sambashare
EOF
fi
testparm -s >/dev/null 2>&1 || {
msg_error "Samba config validation failed (testparm). Check /etc/samba/smb.conf"
pause
return
}
systemctl enable --now smbd nmbd >/dev/null 2>&1
systemctl restart smbd nmbd >/dev/null 2>&1
msg_ok "Host SMB share created: //$(hostname -I | awk '{print $1}')/${share_name}"
msg_warn "Best practice: prefer running Samba in a dedicated LXC/VM for cleaner host separation."
pause
}
host_create_nfs_export() {
header_info
local export_path subnet options
export_path=$(read_input "Host NFS Export" "Export path on host (e.g. /srv/proxmox-nfs)" "/srv/proxmox-nfs") || return
subnet=$(read_input "Host NFS Export" "Allowed subnet/CIDR (e.g. 10.0.0.0/16)") || return
options=$(read_input "Host NFS Export" "Export options" "rw,sync,no_subtree_check,no_root_squash") || return
msg_info "Installing NFS server on host if needed"
apt update >/dev/null 2>&1
apt install -y nfs-kernel-server >/dev/null 2>&1
mkdir -p "$export_path"
chmod 0770 "$export_path"
if ! grep -qE "^${export_path//\//\/}[[:space:]]+${subnet//\//\/}\(" /etc/exports; then
echo "${export_path} ${subnet}(${options})" >>/etc/exports
fi
exportfs -ra >/dev/null 2>&1
systemctl enable --now nfs-kernel-server >/dev/null 2>&1
msg_ok "Host NFS export created: ${export_path} ${subnet}(${options})"
msg_warn "Best practice: use host exports carefully; dedicated storage VM/LXC is often cleaner."
pause
}
show_status() {
header_info
echo -e "${BL}pvesm status${CL}"
pvesm status || true
echo
echo -e "${BL}Mounted /mnt/pve paths${CL}"
mount | grep /mnt/pve || true
echo
echo -e "${BL}Mounted CIFS/NFS/iSCSI related paths${CL}"
mount | grep -E ' type (cifs|nfs|nfs4)' || true
echo
echo -e "${BL}iSCSI sessions${CL}"
iscsiadm -m session 2>/dev/null || true
echo
pause
}
main_menu() {
while true; do
local choice
choice=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Share Allrounder" \
--menu "Select action (read-only actions are safe; write/remove actions ask for confirmation):" 30 116 22 \
" " "────────── READ-ONLY (safe, no changes) ──────────" \
"1" "Test | SMB: manual mount test" \
"2" "Test | NFS: manual mount test" \
"3" "Test | iSCSI: discovery test" \
"4" "Read | LXC: list mountpoints" \
"5" "Read | Show storage/mount/iSCSI status" \
" " "────────── WRITE (modifies config / host) ──────────" \
"6" "Write | Proxmox: add SMB/CIFS storage" \
"7" "Write | Proxmox: add NFS storage" \
"8" "Write | Proxmox: add iSCSI storage" \
"9" "Write | Proxmox: add LVM on base storage (e.g. iSCSI)" \
"10" "Write | LXC: add bind mountpoint (pct set -mpX)" \
"11" "Write | Host: install Samba + create SMB share" \
"12" "Write | Host: install NFS server + create export" \
" " "────────── REMOVE (destructive, defaults to No) ──────────" \
"13" "Remove | Proxmox: remove storage definition" \
"14" "Remove | LXC: remove mountpoint (pct set -delete mpX)" \
"0" "Exit" 3>&1 1>&2 2>&3) || break
# '|| true' so a cancelled sub-dialog (whiptail returns non-zero) returns to the
# menu instead of tripping 'set -e' and exiting the whole script.
case "$choice" in
1) manual_smb_test || true ;;
2) manual_nfs_test || true ;;
3) manual_iscsi_discovery || true ;;
4) list_lxc_mountpoints || true ;;
5) show_status || true ;;
6) add_smb_storage || true ;;
7) add_nfs_storage || true ;;
8) add_iscsi_storage || true ;;
9) add_lvm_on_base_storage || true ;;
10) add_lxc_mountpoint || true ;;
11) host_create_samba_share || true ;;
12) host_create_nfs_export || true ;;
13) remove_storage || true ;;
14) remove_lxc_mountpoint || true ;;
0) break ;;
*) ;;
esac
done
}
header_info
root_check
pve_check
require_pve
ensure_packages
confirm_start || exit 0
main_menu
header_info
msg_ok "Finished."
+6 -42
View File
@@ -11,15 +11,14 @@
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
CONF_FILE="/etc/update-lxcs.conf" CONF_FILE="/etc/update-lxcs.conf"
LOG_FILE="/var/log/update-lxcs-cron.log"
PING_URL="" echo -e "\n $(date)"
# Collect excluded containers from arguments # Collect excluded containers from arguments
excluded_containers=("$@") excluded_containers=("$@")
# Merge exclusions and healthchecks URL from config file if it exists # Merge exclusions from config file if it exists
if [[ -f "$CONF_FILE" ]]; then if [[ -f "$CONF_FILE" ]]; then
PING_URL=$(grep -oP '^\s*PING_URL\s*=\s*\K.+' "$CONF_FILE" 2>/dev/null | tr -d '"' | tr -d "'" || true)
conf_exclude=$(grep -oP '^\s*EXCLUDE\s*=\s*\K[0-9,]+' "$CONF_FILE" 2>/dev/null || true) conf_exclude=$(grep -oP '^\s*EXCLUDE\s*=\s*\K[0-9,]+' "$CONF_FILE" 2>/dev/null || true)
IFS=',' read -ra conf_ids <<<"$conf_exclude" IFS=',' read -ra conf_ids <<<"$conf_exclude"
for id in "${conf_ids[@]}"; do for id in "${conf_ids[@]}"; do
@@ -28,17 +27,6 @@ if [[ -f "$CONF_FILE" ]]; then
done done
fi fi
# Overwrite logfile on each run when healthchecks is used
if [[ -n "$PING_URL" ]]; then
true > "$LOG_FILE"
fi
if [[ -n "$PING_URL" ]]; then
curl -fsS -m 10 --retry 5 "${PING_URL}/start" -o /dev/null 2>/dev/null || true
fi
echo -e "\n $(date)"
function update_container() { function update_container() {
local container=$1 local container=$1
local name local name
@@ -50,36 +38,12 @@ function update_container() {
alpine) pct exec "$container" -- ash -c "apk -U upgrade" ;; alpine) pct exec "$container" -- ash -c "apk -U upgrade" ;;
archlinux) pct exec "$container" -- bash -c "pacman -Syyu --noconfirm" ;; archlinux) pct exec "$container" -- bash -c "pacman -Syyu --noconfirm" ;;
fedora | rocky | centos | alma) pct exec "$container" -- bash -c "dnf -y update && dnf -y upgrade" ;; fedora | rocky | centos | alma) pct exec "$container" -- bash -c "dnf -y update && dnf -y upgrade" ;;
ubuntu | debian | devuan) pct exec "$container" -- bash -c "apt-get update; DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::='--force-confold' dist-upgrade -y; status=\$?; rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED || true; exit \$status" ;; ubuntu | debian | devuan) pct exec "$container" -- bash -c "apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::='--force-confold' dist-upgrade -y; rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED" ;;
opensuse) pct exec "$container" -- bash -c "zypper ref && zypper --non-interactive dup" ;; opensuse) pct exec "$container" -- bash -c "zypper ref && zypper --non-interactive dup" ;;
*) echo " [Warn] Unknown OS type '$os' for container $container, skipping" ;; *) echo " [Warn] Unknown OS type '$os' for container $container, skipping" ;;
esac esac
} }
update_status=0
# Define exit handler to send healthchecks.io status (with logfile on failure/success)
function exit_handler() {
local exit_code=$?
if [[ -n "$PING_URL" ]]; then
sync
if [[ $exit_code -ne 0 || $update_status -ne 0 ]]; then
if [[ -f "$LOG_FILE" ]]; then
curl -fsS -m 10 --retry 5 --data-binary @"$LOG_FILE" "${PING_URL}/fail" -o /dev/null 2>/dev/null || true
else
curl -fsS -m 10 --retry 5 "${PING_URL}/fail" -o /dev/null 2>/dev/null || true
fi
else
if [[ -f "$LOG_FILE" ]]; then
curl -fsS -m 10 --retry 5 --data-binary @"$LOG_FILE" "$PING_URL" -o /dev/null 2>/dev/null || true
else
curl -fsS -m 10 --retry 5 "$PING_URL" -o /dev/null 2>/dev/null || true
fi
fi
fi
}
trap exit_handler EXIT
for container in $(pct list | awk '{if(NR>1) print $1}'); do for container in $(pct list | awk '{if(NR>1) print $1}'); do
excluded=false excluded=false
for excluded_container in "${excluded_containers[@]}"; do for excluded_container in "${excluded_containers[@]}"; do
@@ -101,7 +65,7 @@ for container in $(pct list | awk '{if(NR>1) print $1}'); do
echo -e "[Info] Starting $container" echo -e "[Info] Starting $container"
pct start "$container" pct start "$container"
sleep 5 sleep 5
update_container "$container" || { echo " [Error] Update failed for $container"; update_status=1; } update_container "$container" || echo " [Error] Update failed for $container"
# check if patchmon agent is present in container and run a report if found # check if patchmon agent is present in container and run a report if found
if pct exec "$container" -- [ -e "/usr/local/bin/patchmon-agent" ]; then if pct exec "$container" -- [ -e "/usr/local/bin/patchmon-agent" ]; then
echo -e "${BL}[Info]${GN} patchmon-agent found in ${BL} $container ${CL}, triggering report. \n" echo -e "${BL}[Info]${GN} patchmon-agent found in ${BL} $container ${CL}, triggering report. \n"
@@ -110,7 +74,7 @@ for container in $(pct list | awk '{if(NR>1) print $1}'); do
echo -e "[Info] Shutting down $container" echo -e "[Info] Shutting down $container"
pct shutdown "$container" --timeout 60 & pct shutdown "$container" --timeout 60 &
elif [ "$status" == "status: running" ]; then elif [ "$status" == "status: running" ]; then
update_container "$container" || { echo " [Error] Update failed for $container"; update_status=1; } update_container "$container" || echo " [Error] Update failed for $container"
# check if patchmon agent is present in container and run a report if found # check if patchmon agent is present in container and run a report if found
if pct exec "$container" -- [ -e "/usr/local/bin/patchmon-agent" ]; then if pct exec "$container" -- [ -e "/usr/local/bin/patchmon-agent" ]; then
echo -e "${BL}[Info]${GN} patchmon-agent found in ${BL} $container ${CL}, triggering report. \n" echo -e "${BL}[Info]${GN} patchmon-agent found in ${BL} $container ${CL}, triggering report. \n"