Compare commits

...

20 Commits

Author SHA1 Message Date
community-scripts-pr-app[bot] 8b99d3b1cc Update CHANGELOG.md (#15430)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-27 02:52:41 +00:00
Copilot 039470965b fix(endurain): replace Poetry/uv-pip backend setup with uv sync --frozen --no-dev (#15429)
* Initial plan

* fix: remove exclude-newer constraint from pyproject.toml before uv pip install in endurain

* fix(endurain): replace poetry+uv pip with uv sync --frozen --no-dev

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-06-27 12:52:18 +10:00
community-scripts-pr-app[bot] 8e4a9829cf Update CHANGELOG.md (#15428)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-26 19:58:28 +00:00
community-scripts-pr-app[bot] f1eee5f5ed Update CHANGELOG.md (#15427)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-26 19:58:10 +00:00
CanbiZ (MickLesk) fb14e6ae8b fix(setup_docker): don't abort update on docker pull failure (#15410)
During the container update check, a failing 'docker pull' (local-only images, registry or permission errors) aborted the whole script under errexit. Ignore pull failures and skip containers whose digest could not be resolved.
2026-06-26 21:58:08 +02:00
CanbiZ (MickLesk) 4142c5c2d3 fix(docuseal): use real SECRET_KEY_BASE for db:migrate on update (#15411)
SECRET_KEY_BASE_DUMMY forced Rails to write tmp/local_secret.txt, which failed with EACCES during update and aborted db:migrate. Drop the dummy flag so the real SECRET_KEY_BASE from .env is used, and ensure tmp exists.
2026-06-26 21:57:46 +02:00
community-scripts-pr-app[bot] d85914530f Update CHANGELOG.md (#15426)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-26 19:57:30 +00:00
community-scripts-pr-app[bot] 3d9e67292b Update CHANGELOG.md (#15425)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-26 19:57:21 +00:00
community-scripts-pr-app[bot] ae60dc138b Update CHANGELOG.md (#15424)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-26 19:57:10 +00:00
community-scripts-pr-app[bot] 14a85a8591 Update CHANGELOG.md (#15423)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-26 19:56:54 +00:00
CanbiZ (MickLesk) 1be64c1994 bun: correct install for degoog (#15412)
* fix(degoog): restore bun symlinks after curl-impersonate update

The curl-impersonate CLEAN_INSTALL wipes /usr/local/bin, which removed the bun/bunx symlinks during update. Re-create them after the release deploy.

* clean install curl-impersonate

* sorting
2026-06-26 21:56:48 +02:00
community-scripts-pr-app[bot] 340695b9bd Update CHANGELOG.md (#15422)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-26 19:56:34 +00:00
CanbiZ (MickLesk) ba31c925e3 Validate kernel selection input in kernel-clean (#15414)
- Trim whitespace, skip empty tokens and reject non-numeric input so a
  malformed selection no longer feeds garbage into `sed -n "<index>p"`.
- Reject reversed ranges (start greater than end) with a clear message.
- Replace `grep | wc -l` with `grep -c` (ShellCheck SC2126).
2026-06-26 21:56:28 +02:00
CanbiZ (MickLesk) 868b405082 Fix clean-lxcs exclude matching and set -e cancel handling (#15413)
- Replace the array-style exclude check (`${excluded_containers[@]}` on a
  plain string) with an explicit per-VMID loop, resolving the ShellCheck
  SC2199/SC2076 errors and avoiding accidental substring matches.
- Abort cleanly when the checklist dialog is cancelled instead of relying
  on an unreachable `$?` test under `set -eEuo pipefail`.
- Exit gracefully on a declined confirmation prompt.
- Use `pct exec ... -- hostname` for consistent argument handling.
2026-06-26 21:56:23 +02:00
community-scripts-pr-app[bot] 60266b9c17 Update CHANGELOG.md (#15421)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-26 19:56:21 +00:00
community-scripts-pr-app[bot] ea8b87fd7f Update CHANGELOG.md (#15420)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-26 19:56:14 +00:00
CanbiZ (MickLesk) 58145d5bd3 Harden microcode download/install in microcode and pbs-microcode (#15415)
- AMD: download directly to "$microcode" instead of a convoluted, unquoted
  basename of the full URL (fixes ShellCheck SC2046) and pin to https.
- Quote dpkg install and cleanup paths (SC2086) and use rm -f.
- Normalize the Debian pool URLs (drop the stray double/triple slashes).
- Define color variables directly instead of via $(echo ...) (SC2116/SC2028).
2026-06-26 21:56:00 +02:00
CanbiZ (MickLesk) 9fbe2de1cb Refactor: reduce IP-Tag resource usage and clean up ShellCheck findings (#15418)
* Reduce IP-Tag resource usage and clean up ShellCheck findings

Performance / resource fixes in the generated service:
- VM IP detection only queries the QEMU guest agent when it is actually
  enabled in the VM config. Previously every VM without an agent stalled
  the loop for the full `qm guest cmd` timeout on each cycle; the timeout
  is also lowered from 8s to 5s.
- Skip the ARP/ping fallback for VMs entirely when the guest agent already
  returned addresses, avoiding needless ping probes every run.
- Snapshot `ip neighbor show` once per host instead of invoking it per MAC
  in the VM and LXC lookups.
- Lower ping verification to a 1s timeout (`-W 1`).

ShellCheck cleanup in the installer:
- Define color variables directly instead of via $(echo ...) (SC2116/SC2028).
- Use `read -rp` everywhere (SC2162).
- Replace Unicode quotes with ASCII in a status message (SC1111).

* Cut IP-Tag CPU usage by avoiding per-guest pct/qm status calls

The periodic check spawned one `pct status` per container and one
`qm status` per VM each cycle. Both are heavy Perl tools (~hundreds of ms
CPU per invocation), so on hosts with many guests the 5-minute run caused
a noticeable CPU spike.

- Derive LXC status from the single `pct list` call that is already made
  for enumeration.
- Add one `qm list` call to collect all VM statuses at once.
- Store both in a per-cycle STATUS_CACHE and read from it instead of
  calling `pct status` / `qm status` per guest (with a fallback for direct
  calls outside the cycle).
2026-06-26 21:55:53 +02:00
community-scripts-pr-app[bot] c918dee5fe Update CHANGELOG.md (#15419)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-26 19:53:49 +00:00
CanbiZ (MickLesk) 0774772b87 QoL: scaling-governor extend selection and guard missing cpufreq (#15416) 2026-06-26 21:53:22 +02:00
12 changed files with 167 additions and 91 deletions
+19
View File
@@ -486,6 +486,12 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
</details>
## 2026-06-27
### ❔ Uncategorized
- fix(endurain): replace Poetry/uv-pip backend setup with uv sync --frozen --no-dev [@Copilot](https://github.com/Copilot) ([#15429](https://github.com/community-scripts/ProxmoxVE/pull/15429))
## 2026-06-26
### 🚀 Updated Scripts
@@ -494,15 +500,28 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
- #### 🐞 Bug Fixes
- Docuseal: use real SECRET_KEY_BASE for db:migrate on update [@MickLesk](https://github.com/MickLesk) ([#15411](https://github.com/community-scripts/ProxmoxVE/pull/15411))
- bun: correct install for degoog [@MickLesk](https://github.com/MickLesk) ([#15412](https://github.com/community-scripts/ProxmoxVE/pull/15412))
- fix databasus update/install errors [@asylumexp](https://github.com/asylumexp) ([#15403](https://github.com/community-scripts/ProxmoxVE/pull/15403))
### 💾 Core
- #### 🐞 Bug Fixes
- tools.func: fix setup_docker - don't abort update on docker pull failure [@MickLesk](https://github.com/MickLesk) ([#15410](https://github.com/community-scripts/ProxmoxVE/pull/15410))
- fix(build.func): set /dev/kfd GID in fix_gpu_gids for AMD ROCm [@jamiej](https://github.com/jamiej) ([#15401](https://github.com/community-scripts/ProxmoxVE/pull/15401))
- fix alpine mktmp error [@asylumexp](https://github.com/asylumexp) ([#15398](https://github.com/community-scripts/ProxmoxVE/pull/15398))
### 🧰 Tools
- #### 🔧 Refactor
- Refactor: reduce IP-Tag resource usage and clean up ShellCheck findings [@MickLesk](https://github.com/MickLesk) ([#15418](https://github.com/community-scripts/ProxmoxVE/pull/15418))
- QoL: kernel-clean: Validate kernel selection input [@MickLesk](https://github.com/MickLesk) ([#15414](https://github.com/community-scripts/ProxmoxVE/pull/15414))
- QoL: clean-lxcs exclude matching and set -e cancel handling [@MickLesk](https://github.com/MickLesk) ([#15413](https://github.com/community-scripts/ProxmoxVE/pull/15413))
- QoL: Harden microcode download/install in microcode and pbs-microcode [@MickLesk](https://github.com/MickLesk) ([#15415](https://github.com/community-scripts/ProxmoxVE/pull/15415))
- QoL: scaling-governor extend selection and guard missing cpufreq [@MickLesk](https://github.com/MickLesk) ([#15416](https://github.com/community-scripts/ProxmoxVE/pull/15416))
## 2026-06-25
### 🆕 New Scripts
+2 -2
View File
@@ -38,7 +38,7 @@ function update_script() {
create_backup /opt/degoog/.env \
/opt/degoog/data
if ! command -v bun >/dev/null 2>&1; then
if [[ ! -x /root/.bun/bin/bun ]]; then
msg_info "Installing Bun"
export BUN_INSTALL="/root/.bun"
curl -fsSL https://bun.sh/install | $STD bash
@@ -52,7 +52,7 @@ function update_script() {
msg_ok "Updated Valkey"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "degoog" "fccview/degoog" "prebuild" "latest" "/opt/degoog" "degoog_*_prebuild.tar.gz"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "curl-impersonate" "lexiforest/curl-impersonate" "prebuild" "latest" "/usr/local/bin" "curl-impersonate-v*.$(uname -m)-linux-gnu.tar.gz"
fetch_and_deploy_gh_release "curl-impersonate" "lexiforest/curl-impersonate" "prebuild" "latest" "/usr/local/bin" "curl-impersonate-v*.$(uname -m)-linux-gnu.tar.gz"
restore_backup
+1 -1
View File
@@ -55,7 +55,7 @@ function update_script() {
eval "$(rbenv init - bash)" 2>/dev/null || true
export RAILS_ENV=production
export NODE_ENV=production
export SECRET_KEY_BASE_DUMMY=1
mkdir -p /opt/docuseal/tmp
set -a
source /opt/docuseal/.env
set +a
+1 -4
View File
@@ -63,10 +63,7 @@ function update_script() {
cd /opt/endurain/backend
UV_VERSION=$(grep -Po 'required-version\s*=\s*"\K[^"]+' pyproject.toml 2>/dev/null || echo "0.11.18")
UV_VERSION="$UV_VERSION" setup_uv
$STD poetry export -f requirements.txt --output requirements.txt --without-hashes
$STD uv venv --clear
$STD uv pip install -r requirements.txt
$STD uv pip install pytz
$STD uv sync --frozen --no-dev
msg_ok "Backend Updated"
msg_info "Starting Service"
+1 -8
View File
@@ -83,14 +83,7 @@ msg_info "Setting up Backend"
cd /opt/endurain/backend
UV_VERSION=$(grep -Po 'required-version\s*=\s*"\K[^"]+' pyproject.toml 2>/dev/null || echo "0.11.18")
UV_VERSION="$UV_VERSION" setup_uv
$STD uv tool install poetry
$STD uv tool update-shell
export PATH="/root/.local/bin:$PATH"
$STD poetry self add poetry-plugin-export
$STD poetry export -f requirements.txt --output requirements.txt --without-hashes
$STD uv venv --clear
$STD uv pip install -r requirements.txt
$STD uv pip install pytz
$STD uv sync --frozen --no-dev
msg_ok "Setup Backend"
msg_info "Creating Service"
+7 -7
View File
@@ -4614,11 +4614,11 @@ EOF
local image=$(echo "$container" | awk '{print $2}')
local current_digest=$(docker inspect "$name" --format='{{.Image}}' 2>/dev/null | cut -d':' -f2 | cut -c1-12)
# Pull latest image digest
docker pull "$image" >/dev/null 2>&1
# Pull latest image digest (ignore failures, e.g. local-only images or registry/permission issues)
docker pull "$image" >/dev/null 2>&1 || true
local latest_digest=$(docker inspect "$image" --format='{{.Id}}' 2>/dev/null | cut -d':' -f2 | cut -c1-12)
if [ "$current_digest" != "$latest_digest" ]; then
if [ -n "$latest_digest" ] && [ "$current_digest" != "$latest_digest" ]; then
containers_with_updates+=("$name")
container_info+=("${index}) ${name} (${image})")
((index++))
@@ -7561,8 +7561,8 @@ setup_nodejs() {
}
# Install global Node modules
if [[ -n "$NODE_MODULE" ]] || (( node_major >= 25 )); then
if (( node_major >= 25 )) && [[ ",${NODE_MODULE}," != *",corepack,"* ]] && [[ "$NODE_MODULE" != corepack* ]]; then
if [[ -n "$NODE_MODULE" ]] || ((node_major >= 25)); then
if ((node_major >= 25)) && [[ ",${NODE_MODULE}," != *",corepack,"* ]] && [[ "$NODE_MODULE" != corepack* ]]; then
NODE_MODULE="${NODE_MODULE:+$NODE_MODULE,}corepack"
fi
@@ -7624,12 +7624,12 @@ setup_nodejs() {
fi
fi
done
if (( failed_modules > 0 )); then
if ((failed_modules > 0)); then
msg_warn "$failed_modules Node.js module(s) failed: $NODE_MODULE"
fi
fi
if [[ "$NODE_COREPACK_ENABLE" == "1" ]] && (( wants_corepack )) && command -v corepack >/dev/null 2>&1; then
if [[ "$NODE_COREPACK_ENABLE" == "1" ]] && ((wants_corepack)) && command -v corepack >/dev/null 2>&1; then
msg_info "Enabling corepack"
if $STD corepack enable 2>/dev/null; then
msg_ok "Enabled corepack"
+72 -32
View File
@@ -22,10 +22,10 @@ APP="IP-Tag"
hostname=$(hostname)
# Color variables
YW=$(echo "\033[33m")
GN=$(echo "\033[1;92m")
RD=$(echo "\033[01;31m")
CL=$(echo "\033[m")
YW="\033[33m"
GN="\033[1;92m"
RD="\033[01;31m"
CL="\033[m"
BFR="\\r\\033[K"
HOLD=" "
CM="${GN}${CL} "
@@ -127,7 +127,7 @@ update_installation() {
echo -e "\n${YW}Configuration file already exists.${CL}"
echo -e "${YW}Note: No critical changes were made in this version.${CL}"
while true; do
read -p "Do you want to replace it with defaults? (y/n): " yn
read -rp "Do you want to replace it with defaults? (y/n): " yn
case $yn in
[Yy]*)
interactive_config_setup
@@ -176,7 +176,7 @@ export FORCE_SINGLE_RUN=true
exec "$SCRIPT_FILE"
EOF
chmod +x /usr/local/bin/iptag-run
msg_ok "Created iptag-run executable - You can execute this manually by entering iptag-run in the Proxmox host, so the script is executed by hand."
msg_ok "Created iptag-run executable - You can execute this manually by entering 'iptag-run' in the Proxmox host, so the script is executed by hand."
msg_info "Restarting service"
systemctl daemon-reload &>/dev/null
@@ -208,7 +208,7 @@ install_command_only() {
else
stop_spinner
echo -e "\n${YW}Configuration file already exists.${CL}"
read -p "Do you want to reconfigure tag format? (y/n): " reconfigure
read -rp "Do you want to reconfigure tag format? (y/n): " reconfigure
case $reconfigure in
[Yy]*)
interactive_config_setup_command
@@ -285,7 +285,7 @@ interactive_config_setup_command() {
echo -e "${GN}3)${CL} full - Show full IP address (e.g., 192.168.0.100)"
while true; do
read -p "Enter your choice (1-3) [1]: " tag_choice
read -rp "Enter your choice (1-3) [1]: " tag_choice
case ${tag_choice:-1} in
1)
TAG_FORMAT="last_two_octets"
@@ -323,7 +323,7 @@ interactive_config_setup() {
echo -e "${GN}3)${CL} full - Show full IP address (e.g., 192.168.0.100)"
while true; do
read -p "Enter your choice (1-3) [1]: " tag_choice
read -rp "Enter your choice (1-3) [1]: " tag_choice
case ${tag_choice:-1} in
1)
TAG_FORMAT="last_two_octets"
@@ -352,7 +352,7 @@ interactive_config_setup() {
echo -e "${YW}Recommended range: 300-3600 seconds${CL}"
while true; do
read -p "Enter interval in seconds [300]: " interval_input
read -rp "Enter interval in seconds [300]: " interval_input
interval_input=${interval_input:-300}
if [[ $interval_input =~ ^[0-9]+$ ]] && [ $interval_input -ge 300 ] && [ $interval_input -le 7200 ]; then
@@ -563,9 +563,10 @@ get_vm_ips() {
debug_log "vm $vmid: starting IP detection"
# Check if VM is running first
local vm_status=""
if command -v qm >/dev/null 2>&1; then
# Check if VM is running first (status comes from the cached `qm list`,
# falling back to `qm status` only when called outside the normal cycle).
local vm_status="${STATUS_CACHE[vm_${vmid}]:-}"
if [[ -z "$vm_status" ]] && command -v qm >/dev/null 2>&1; then
vm_status=$(qm status "$vmid" 2>/dev/null | awk '{print $2}')
fi
@@ -578,33 +579,43 @@ get_vm_ips() {
local mac_addresses=$(grep -E "^net[0-9]+:" "$vm_config" | grep -oE "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}" | head -3)
debug_log "vm $vmid: found MACs: $mac_addresses"
# Method 1: QM guest agent (most reliable for current IP)
if command -v qm >/dev/null 2>&1; then
debug_log "vm $vmid: trying qm guest agent first"
local qm_ips=$(timeout 8 qm guest cmd "$vmid" network-get-interfaces 2>/dev/null | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | grep -v "127.0.0.1" | head -3)
# Method 1: QEMU guest agent (most reliable for current IP). Only query it
# when the agent is actually enabled in the VM config, otherwise the call
# blocks until the timeout on every VM without an agent.
local agent_enabled=0
if [[ "$(grep -E '^agent:' "$vm_config" 2>/dev/null)" =~ (^agent:[[:space:]]*1|enabled=1) ]]; then
agent_enabled=1
fi
if [[ "$agent_enabled" == "1" ]] && command -v qm >/dev/null 2>&1; then
debug_log "vm $vmid: querying guest agent"
local qm_ips=$(timeout 5 qm guest cmd "$vmid" network-get-interfaces 2>/dev/null | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | grep -v "127.0.0.1" | head -3)
for qm_ip in $qm_ips; do
if [[ "$qm_ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
debug_log "vm $vmid: found IP $qm_ip via qm guest cmd"
ips+="$qm_ip "
fi
done
else
debug_log "vm $vmid: guest agent not enabled, skipping qm guest cmd"
fi
# Method 2: Fresh ARP table lookup (force refresh)
if [[ -n "$mac_addresses" ]]; then
debug_log "vm $vmid: refreshing ARP table and checking"
# Try to refresh ARP table by pinging network ranges
# Method 2: ARP table lookup (only if the guest agent gave us nothing).
if [[ -z "$ips" && -n "$mac_addresses" ]]; then
debug_log "vm $vmid: checking ARP table"
# Snapshot the neighbor table once instead of per MAC
local neigh_table
neigh_table=$(ip neighbor show 2>/dev/null)
for mac in $mac_addresses; do
local mac_lower=$(echo "$mac" | tr '[:upper:]' '[:lower:]')
# First check current ARP table
local current_ip=$(ip neighbor show | grep "$mac_lower" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1)
# Check current ARP table
local current_ip=$(echo "$neigh_table" | grep "$mac_lower" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1)
# If found in ARP, verify it's still valid by trying to ping
if [[ -n "$current_ip" && "$current_ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
debug_log "vm $vmid: found IP $current_ip in ARP table for MAC $mac_lower, verifying..."
# Quick ping test to verify IP is still active
if timeout 2 ping -c 1 "$current_ip" >/dev/null 2>&1; then
if timeout 1 ping -c 1 -W 1 "$current_ip" >/dev/null 2>&1; then
debug_log "vm $vmid: verified IP $current_ip is active via ping"
ips+="$current_ip "
else
@@ -628,7 +639,7 @@ get_vm_ips() {
if [[ -n "$dhcp_ip" && "$dhcp_ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
debug_log "vm $vmid: found IP $dhcp_ip via DHCP leases"
# Verify this IP responds
if timeout 2 ping -c 1 "$dhcp_ip" >/dev/null 2>&1; then
if timeout 1 ping -c 1 -W 1 "$dhcp_ip" >/dev/null 2>&1; then
debug_log "vm $vmid: verified DHCP IP $dhcp_ip is active"
ips+="$dhcp_ip "
break 2
@@ -652,6 +663,9 @@ get_vm_ips() {
# Cache for configs to avoid repeated reads
declare -A CONFIG_CACHE
declare -A IP_CACHE
# Status cache populated once per check from `pct list` / `qm list` to avoid
# spawning an expensive `pct status` / `qm status` (Perl) per guest each cycle.
declare -A STATUS_CACHE
# Update tags for container or VM
update_tags() {
@@ -836,7 +850,16 @@ update_all_tags() {
# Get list of all containers/VMs
if [[ "$type" == "lxc" ]]; then
vmids=($(pct list 2>/dev/null | grep -v VMID | awk '{print $1}'))
# A single `pct list` call yields both the VMID list and the running
# status, so we never need a per-container `pct status` afterwards.
local pct_list_output
pct_list_output=$(pct list 2>/dev/null)
vmids=($(echo "$pct_list_output" | awk 'NR>1 {print $1}'))
local _vmid _status _rest
while read -r _vmid _status _rest; do
[[ "$_vmid" == "VMID" || -z "$_vmid" ]] && continue
STATUS_CACHE["lxc_${_vmid}"]="$_status"
done <<<"$pct_list_output"
else
# More efficient: direct file listing instead of ls+sed
vmids=()
@@ -845,6 +868,15 @@ update_all_tags() {
local basename="${conf##*/}"
vmids+=("${basename%.conf}")
done
# A single `qm list` call yields the status for all VMs, avoiding a
# per-VM `qm status`.
if command -v qm >/dev/null 2>&1; then
local _vmid _name _status _rest
while read -r _vmid _name _status _rest; do
[[ "$_vmid" == "VMID" || -z "$_vmid" ]] && continue
STATUS_CACHE["vm_${_vmid}"]="$_status"
done <<<"$(qm list 2>/dev/null)"
fi
fi
count=${#vmids[@]}
@@ -881,6 +913,7 @@ check() {
# Clear caches before each run
CONFIG_CACHE=()
IP_CACHE=()
STATUS_CACHE=()
# Update LXC containers
update_all_tags "lxc"
@@ -925,8 +958,12 @@ get_lxc_ips() {
debug_log "lxc $vmid: starting IP detection"
# Check if LXC is running
local lxc_status=$(pct status "${vmid}" 2>/dev/null | awk '{print $2}')
# Check if LXC is running (status comes from the cached `pct list`,
# falling back to `pct status` only when called outside the normal cycle).
local lxc_status="${STATUS_CACHE[lxc_${vmid}]:-}"
if [[ -z "$lxc_status" ]]; then
lxc_status=$(pct status "${vmid}" 2>/dev/null | awk '{print $2}')
fi
if [[ "$lxc_status" != "running" ]]; then
debug_log "lxc $vmid: not running (status: $lxc_status)"
return
@@ -952,9 +989,12 @@ get_lxc_ips() {
if [[ -z "$ips" && -f "$pve_lxc_config" ]]; then
local mac_addrs=$(grep -Eo 'hwaddr=([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}' "$pve_lxc_config" | cut -d'=' -f2)
if [[ -n "$mac_addrs" ]]; then
# Snapshot the neighbor table once instead of per MAC
local neigh_table
neigh_table=$(ip neighbor show 2>/dev/null)
while IFS= read -r mac_addr; do
[[ -z "$mac_addr" ]] && continue
local arp_ip=$(ip neighbor show | grep -i "$mac_addr" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1)
local arp_ip=$(echo "$neigh_table" | grep -i "$mac_addr" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1)
if [[ -n "$arp_ip" && "$arp_ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
debug_log "lxc $vmid: found IP $arp_ip via ARP table for MAC $mac_addr"
ips="${ips}${ips:+ }${arp_ip}"
@@ -996,7 +1036,7 @@ echo -e "${GN}3)${CL} Update existing installation"
echo -e "${RD}4)${CL} Cancel"
while true; do
read -p "Enter your choice (1-4): " choice
read -rp "Enter your choice (1-4): " choice
case $choice in
1)
INSTALL_MODE="service"
@@ -1025,7 +1065,7 @@ done
echo -e "\n${YW}This will install ${APP} on ${hostname} in $INSTALL_MODE mode.${CL}"
while true; do
read -p "Proceed? (y/n): " yn
read -rp "Proceed? (y/n): " yn
case $yn in
[Yy]*)
break
@@ -1072,7 +1112,7 @@ if [[ "$INSTALL_MODE" == "service" ]]; then
else
stop_spinner
echo -e "\n${YW}Configuration file already exists.${CL}"
read -p "Do you want to reconfigure tag format and loop interval? (y/n): " reconfigure
read -rp "Do you want to reconfigure tag format and loop interval? (y/n): " reconfigure
case $reconfigure in
[Yy]*)
interactive_config_setup
+15 -8
View File
@@ -30,7 +30,7 @@ declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "clean-lxcs" "
header_info
echo "Loading..."
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Proxmox VE LXC Updater" --yesno "This will clean logs, cache and update package lists on selected LXC Containers. Proceed?" 10 58
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Proxmox VE LXC Updater" --yesno "This will clean logs, cache and update package lists on selected LXC Containers. Proceed?" 10 58 || exit 0
NODE=$(hostname)
EXCLUDE_MENU=()
@@ -42,17 +42,17 @@ while read -r TAG ITEM; do
EXCLUDE_MENU+=("$TAG" "$ITEM " "OFF")
done < <(pct list | awk 'NR>1')
excluded_containers=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Containers on $NODE" --checklist "\nSelect containers to skip from cleaning:\n" \
16 $((MSG_MAX_LENGTH + 23)) 6 "${EXCLUDE_MENU[@]}" 3>&1 1>&2 2>&3 | tr -d '"')
if [ $? -ne 0 ]; then
exit
# Capture the selection; abort cleanly if the user cancels the dialog
# (set -e would otherwise terminate on the failing command substitution).
if ! excluded_containers=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Containers on $NODE" --checklist "\nSelect containers to skip from cleaning:\n" \
16 $((MSG_MAX_LENGTH + 23)) 6 "${EXCLUDE_MENU[@]}" 3>&1 1>&2 2>&3 | tr -d '"'); then
exit 0
fi
function run_lxc_clean() {
local container=$1
header_info
name=$(pct exec "$container" hostname)
name=$(pct exec "$container" -- hostname)
pct exec "$container" -- bash -c '
BL="\033[36m"; GN="\033[1;92m"; CL="\033[m"
@@ -84,7 +84,14 @@ function run_lxc_clean() {
}
for container in $(pct list | awk '{if(NR>1) print $1}'); do
if [[ " ${excluded_containers[@]} " =~ " $container " ]]; then
excluded=0
for ex in $excluded_containers; do
if [[ "$ex" == "$container" ]]; then
excluded=1
break
fi
done
if [[ "$excluded" -eq 1 ]]; then
header_info
echo -e "${BL}[Info]${GN} Skipping ${BL}$container${CL}"
sleep 1
+14 -4
View File
@@ -55,12 +55,23 @@ read -r selected
selected_indices=()
IFS=',' read -r -a tokens <<<"$selected"
for token in "${tokens[@]}"; do
# Strip surrounding whitespace and skip empty tokens
token="${token//[[:space:]]/}"
[ -z "$token" ] && continue
if [[ "$token" =~ ^([0-9]+)-([0-9]+)$ ]]; then
for ((i = BASH_REMATCH[1]; i <= BASH_REMATCH[2]; i++)); do
start=${BASH_REMATCH[1]}
end=${BASH_REMATCH[2]}
if ((start > end)); then
echo -e "${RD}Ignoring invalid range '${token}' (start greater than end).${CL}"
continue
fi
for ((i = start; i <= end; i++)); do
selected_indices+=("$i")
done
else
elif [[ "$token" =~ ^[0-9]+$ ]]; then
selected_indices+=("$token")
else
echo -e "${RD}Ignoring invalid selection '${token}'.${CL}"
fi
done
@@ -101,8 +112,7 @@ for kernel in "${kernels_to_remove[@]}"; do
remaining=$(dpkg --list |
awk '/^ii/ {print $2}' |
grep -E "^proxmox-kernel-${minor_version}\." |
grep -v "^${kernel}$" |
wc -l)
grep -cv "^${kernel}$")
if [ "$remaining" -eq 0 ]; then
pkgs_to_remove+=("$meta")
fi
+11 -11
View File
@@ -16,10 +16,10 @@ function header_info {
EOF
}
RD=$(echo "\033[01;31m")
YW=$(echo "\033[33m")
GN=$(echo "\033[1;92m")
CL=$(echo "\033[m")
RD="\033[01;31m"
YW="\033[33m"
GN="\033[1;92m"
CL="\033[m"
BFR="\\r\\033[K"
HOLD="-"
CM="${GN}${CL}"
@@ -47,7 +47,7 @@ intel() {
sleep 1
fi
intel_microcode=$(curl -fsSL "https://ftp.debian.org/debian/pool/non-free-firmware/i/intel-microcode//" | grep -o 'href="[^"]*amd64.deb"' | sed 's/href="//;s/"//')
intel_microcode=$(curl -fsSL "https://ftp.debian.org/debian/pool/non-free-firmware/i/intel-microcode/" | grep -o 'href="[^"]*amd64.deb"' | sed 's/href="//;s/"//')
[ -z "$intel_microcode" ] && {
whiptail --backtitle "Proxmox VE Helper Scripts" --title "No Microcode Found" --msgbox "It appears there were no microcode packages found\n Try again later." 10 68
msg_info "Exiting"
@@ -80,17 +80,17 @@ intel() {
msg_ok "Downloaded the Intel Processor Microcode Package $microcode"
msg_info "Installing $microcode (Patience)"
dpkg -i $microcode &>/dev/null
dpkg -i "$microcode" &>/dev/null
msg_ok "Installed $microcode"
msg_info "Cleaning up"
rm $microcode
rm -f "$microcode"
msg_ok "Cleaned"
echo -e "\nIn order to apply the changes, a system reboot will be necessary.\n"
}
amd() {
amd_microcode=$(curl -fsSL "https://ftp.debian.org/debian/pool/non-free-firmware/a/amd64-microcode///" | grep -o 'href="[^"]*amd64.deb"' | sed 's/href="//;s/"//')
amd_microcode=$(curl -fsSL "https://ftp.debian.org/debian/pool/non-free-firmware/a/amd64-microcode/" | grep -o 'href="[^"]*amd64.deb"' | sed 's/href="//;s/"//')
[ -z "$amd_microcode" ] && {
whiptail --backtitle "Proxmox VE Helper Scripts" --title "No Microcode Found" --msgbox "It appears there were no microcode packages found\n Try again later." 10 68
@@ -120,15 +120,15 @@ amd() {
}
msg_info "Downloading the AMD Processor Microcode Package $microcode"
curl -fsSL "https://ftp.debian.org/debian/pool/non-free-firmware/a/amd64-microcode/$microcode" -o $(basename "https://ftp.debian.org/debian/pool/non-free-firmware/a/amd64-microcode/$microcode")
curl -fsSL --proto '=https' "https://ftp.debian.org/debian/pool/non-free-firmware/a/amd64-microcode/$microcode" -o "$microcode"
msg_ok "Downloaded the AMD Processor Microcode Package $microcode"
msg_info "Installing $microcode (Patience)"
dpkg -i $microcode &>/dev/null
dpkg -i "$microcode" &>/dev/null
msg_ok "Installed $microcode"
msg_info "Cleaning up"
rm $microcode
rm -f "$microcode"
msg_ok "Cleaned"
echo -e "\nIn order to apply the changes, a system reboot will be necessary.\n"
}
+9 -9
View File
@@ -18,10 +18,10 @@ EOF
}
# Color definitions
RD=$(echo "\033[01;31m")
YW=$(echo "\033[33m")
GN=$(echo "\033[1;92m")
CL=$(echo "\033[m")
RD="\033[01;31m"
YW="\033[33m"
GN="\033[1;92m"
CL="\033[m"
BFR="\\r\\033[K"
HOLD="-"
CM="${GN}${CL}"
@@ -94,11 +94,11 @@ intel() {
msg_ok "Downloaded Intel processor microcode package $microcode"
msg_info "Installing $microcode (this might take a while)"
dpkg -i $microcode &>/dev/null
dpkg -i "$microcode" &>/dev/null
msg_ok "Installed $microcode"
msg_info "Cleaning up"
rm $microcode
rm -f "$microcode"
msg_ok "Clean up complete"
echo -e "\nA system reboot is required to apply the changes.\n"
}
@@ -137,15 +137,15 @@ amd() {
}
msg_info "Downloading AMD processor microcode package $microcode"
curl -fsSL "https://ftp.debian.org/debian/pool/non-free-firmware/a/amd64-microcode/$microcode" -o $(basename "https://ftp.debian.org/debian/pool/non-free-firmware/a/amd64-microcode/$microcode")
curl -fsSL --proto '=https' "https://ftp.debian.org/debian/pool/non-free-firmware/a/amd64-microcode/$microcode" -o "$microcode"
msg_ok "Downloaded AMD processor microcode package $microcode"
msg_info "Installing $microcode (this might take a while)"
dpkg -i $microcode &>/dev/null
dpkg -i "$microcode" &>/dev/null
msg_ok "Installed $microcode"
msg_info "Cleaning up"
rm $microcode
rm -f "$microcode"
msg_ok "Clean up complete"
echo -e "\nA system reboot is required to apply the changes.\n"
}
+15 -5
View File
@@ -20,16 +20,26 @@ header_info() {
EOF
}
header_info
whiptail --backtitle "Proxmox VE Helper Scripts" --title "CPU Scaling Governors" --yesno "View/Change CPU Scaling Governors. Proceed?" 10 58
current_governor=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor)
whiptail --backtitle "Proxmox VE Helper Scripts" --title "CPU Scaling Governors" --yesno "View/Change CPU Scaling Governors. Proceed?" 10 58 || exit 0
GOV_BASE="/sys/devices/system/cpu/cpu0/cpufreq"
if [[ ! -r "$GOV_BASE/scaling_governor" || ! -r "$GOV_BASE/scaling_available_governors" ]]; then
whiptail --backtitle "Proxmox VE Helper Scripts" --title "CPU Scaling Not Available" \
--msgbox "CPU frequency scaling is not available on this system.\n\nThis is normal when no cpufreq driver is active (e.g. CPU power management handled by the BIOS, or certain virtualized hosts)." 12 70
clear
exit 0
fi
current_governor=$(cat "$GOV_BASE/scaling_governor")
GOVERNORS_MENU=()
MSG_MAX_LENGTH=0
while read -r TAG ITEM; do
OFFSET=2
((${#ITEM} + OFFSET > MSG_MAX_LENGTH)) && MSG_MAX_LENGTH=${#ITEM}+OFFSET
GOVERNORS_MENU+=("$TAG" "$ITEM " "OFF")
done < <(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors | tr ' ' '\n' | grep -v "$current_governor")
scaling_governor=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Current CPU Scaling Governor is set to $current_governor" --checklist "\nSelect the Scaling Governor to use:\n" 16 $((MSG_MAX_LENGTH + 58)) 6 "${GOVERNORS_MENU[@]}" 3>&1 1>&2 2>&3 | tr -d '"')
done < <(tr ' ' '\n' <"$GOV_BASE/scaling_available_governors" | sed '/^$/d' | grep -vxF "$current_governor")
# A radiolist is used on purpose: only a single governor can be active at a time.
scaling_governor=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Current CPU Scaling Governor is set to $current_governor" --radiolist "\nSelect the Scaling Governor to use:\n" 16 $((MSG_MAX_LENGTH + 58)) 6 "${GOVERNORS_MENU[@]}" 3>&1 1>&2 2>&3 | tr -d '"')
[ -z "$scaling_governor" ] && {
whiptail --backtitle "Proxmox VE Helper Scripts" --title "No CPU Scaling Governor Selected" --msgbox "It appears that no CPU Scaling Governor was selected" 10 68
clear
@@ -49,7 +59,7 @@ yes)
EXISTING_CRONTAB=$(crontab -l 2>/dev/null)
if [[ -n "$EXISTING_CRONTAB" ]]; then
TEMP_CRONTAB_FILE=$(mktemp)
echo "$EXISTING_CRONTAB" | grep -v "@reboot (sleep 60 && echo*" >"$TEMP_CRONTAB_FILE"
echo "$EXISTING_CRONTAB" | grep -vF "@reboot (sleep 60 && echo" >"$TEMP_CRONTAB_FILE"
crontab "$TEMP_CRONTAB_FILE"
rm "$TEMP_CRONTAB_FILE"
fi