Compare commits

...

10 Commits

Author SHA1 Message Date
MickLesk
8f8e1d0313 Trim comments 2026-09-10 14:18:24 +02:00
MickLesk
a8c8f1cb10 Rewrite the retired Gitea base in every container before updating it
git.community-scripts.org was a mirror of the same repositories and is
gone. A container built against it cannot update: the older entrypoint
pulls ct/<app>.sh straight from the dead host, so it never reaches the
update helper that could repair itself.

Rewriting it from the host is the one place that reaches those, and it
is where people already sweep all their containers. Only the host and
Gitea's /raw/<kind>/ segment change, so a fork keeps its own owner,
repo and ref.
2026-09-10 14:11:30 +02:00
community-scripts-pr-app[bot]
2802f0fc55 Update CHANGELOG.md (#17153)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-09-10 11:49:47 +00:00
push-app-to-main[bot]
7c822e1642 Safebucket (#17096)
* Add safebucket (ct)

* Update default var_arm64 value to 'yes'

Changed default value of var_arm64 to 'yes' in safebucket.sh.

* safebucket-install.sh aktualisieren

Co-authored-by: Tobias <96661824+CrazyWolf13@users.noreply.github.com>

* Refactor ARCH variable usage in safebucket.sh

* Refactor Safebucket installation script

---------

Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com>
Co-authored-by: CanbiZ (MickLesk) <47820557+MickLesk@users.noreply.github.com>
Co-authored-by: Michel Roegl-Brunner <73236783+michelroegl-brunner@users.noreply.github.com>
Co-authored-by: Tobias <96661824+CrazyWolf13@users.noreply.github.com>
2026-09-10 13:49:15 +02:00
MickLesk
902b341327 Merge branch 'main' of https://github.com/community-scripts/ProxmoxVE into feat/guest-delete-vms 2026-09-10 10:39:42 +02:00
MickLesk
cca5e8320a lxc-delete: also delete VMs, not just containers
One checklist now lists containers and VMs side by side, each tagged with its
type, with separate ALL CT / ALL VM entries. VMs stop via qm stop and are
removed with qm destroy --purge --destroy-unreferenced-disks.

Two fixes fall out of the rework: the destroy exit status is read from the
background job rather than from the spinner, so failures actually surface, and
a guest is only stopped once its deletion is confirmed.
2026-09-10 10:38:39 +02:00
community-scripts-pr-app[bot]
6109ccf128 Update CHANGELOG.md (#17151)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-09-10 08:33:51 +00:00
Andrew Jones
639eb8e839 fix(solidtime): prevent composer install from hanging on root prompt (#17146)
composer's root/superuser safety prompt blocks on stdin during update_script,
since the container's terminal isn't attached to answer it. Set
COMPOSER_ALLOW_SUPERUSER=1 to suppress the prompt, matching composer's
documented approach for running as root non-interactively.
2026-09-10 10:33:16 +02:00
community-scripts-pr-app[bot]
cb1090623d Update CHANGELOG.md (#17148)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-09-10 04:28:37 +00:00
Stephen Chin
9101f0c5f4 fix(hermesagent): wait for root gateway cleanup (#17147)
Co-authored-by: Stephen Chin <1290231+steveonjava@users.noreply.github.com>
2026-09-10 06:28:10 +02:00
8 changed files with 456 additions and 52 deletions

View File

@@ -540,6 +540,19 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
</details>
## 2026-09-10
### 🆕 New Scripts
- Safebucket ([#17096](https://github.com/community-scripts/ProxmoxVE/pull/17096))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- fix(solidtime): prevent composer install from hanging on root prompt [@supersoju](https://github.com/supersoju) ([#17146](https://github.com/community-scripts/ProxmoxVE/pull/17146))
- fix(hermesagent): wait for root gateway cleanup [@steveonjava](https://github.com/steveonjava) ([#17147](https://github.com/community-scripts/ProxmoxVE/pull/17147))
## 2026-09-09
### 🆕 New Scripts

6
ct/headers/safebucket Normal file
View File

@@ -0,0 +1,6 @@
_____ ____ __ __ __
/ ___/____ _/ __/__ / /_ __ _______/ /_____ / /_
\__ \/ __ `/ /_/ _ \/ __ \/ / / / ___/ //_/ _ \/ __/
___/ / /_/ / __/ __/ /_/ / /_/ / /__/ ,< / __/ /_
/____/\__,_/_/ \___/_.___/\__,_/\___/_/|_|\___/\__/

View File

@@ -56,6 +56,11 @@ function update_script() {
mapfile -t root_gateway_pids < <(ps -eo user=,pid=,args= | awk '$1 == "root" && $0 ~ /\/home\/hermes\/\.hermes\/hermes-agent\/venv\/bin\/python -m hermes_cli\.main gateway run --replace$/ { print $2 }')
if ((${#root_gateway_pids[@]})); then
kill -TERM "${root_gateway_pids[@]}"
for pid in "${root_gateway_pids[@]}"; do
while kill -0 "$pid" 2>/dev/null; do
sleep 0.1
done
done
fi
chown -R hermes:hermes /home/hermes
msg_ok "Updated Hermes Agent"

63
ct/safebucket.sh Normal file
View File

@@ -0,0 +1,63 @@
#!/usr/bin/env bash
_CS_DEFAULT_URL="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main"
_cs_boot="${COMMUNITY_SCRIPTS_CORE_DIR:-$(dirname "${BASH_SOURCE[0]}")/../../core}/core/build.func"
source "$_cs_boot" 2>/dev/null || source <(curl -fsSL "${COMMUNITY_SCRIPTS_CORE_URL:-https://raw.githubusercontent.com/community-scripts/core/main}/core/build.func")
# Copyright (c) 2021-2026 community-scripts ORG
# Author: renizmy
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/safebucket/safebucket
APP="Safebucket"
var_tags="${var_tags:-files;sharing}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-1024}"
var_disk="${var_disk:-10}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -f /opt/safebucket/safebucket ]]; then
msg_error "No ${APP} Installation Found!"
exit 1
fi
if check_for_gh_release "safebucket" "safebucket/safebucket"; then
msg_info "Stopping Service"
systemctl stop safebucket
msg_ok "Stopped Service"
create_backup /opt/safebucket/config.yaml /opt/safebucket/data/
fetch_and_deploy_gh_release "safebucket" "safebucket/safebucket" "singlefile" "latest" "/opt/safebucket" "safebucket-linux-$(arch_resolve)"
restore_backup
msg_info "Configuring Safebucket"
chown -R safebucket:safebucket /opt/safebucket
msg_ok "Configured Safebucket"
msg_info "Starting Service"
systemctl start safebucket
msg_ok "Started Service"
msg_ok "Updated successfully!"
fi
exit
}
start
build_container
description
msg_ok "Completed successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8080${CL}"

View File

@@ -45,7 +45,7 @@ function update_script() {
msg_info "Updating Application"
cd /opt/solidtime
$STD composer install --no-dev --optimize-autoloader
COMPOSER_ALLOW_SUPERUSER=1 $STD composer install --no-dev --optimize-autoloader
$STD npm install
$STD npm run build
$STD php artisan migrate --force

View File

@@ -0,0 +1,226 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: renizmy
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/safebucket/safebucket
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_info "Installing Dependencies"
$STD apt install -y awscli
msg_ok "Installed Dependencies"
msg_info "Installing Garage"
useradd --system --no-create-home --shell /usr/sbin/nologin garage 2>/dev/null || true
GARAGE_VERSION=$(get_latest_gh_tag "deuxfleurs-org/garage" "v")
if [[ -z "$GARAGE_VERSION" ]]; then
msg_error "Could not determine latest stable Garage version"
exit 1
fi
curl -fsSL "https://garagehq.deuxfleurs.fr/_releases/${GARAGE_VERSION}/$(arch_resolve "x86_64-unknown-linux-musl" "aarch64-unknown-linux-musl")/garage" -o /usr/local/bin/garage
chmod +x /usr/local/bin/garage
mkdir -p /opt/garage/{data,meta}
RPC_SECRET=$(openssl rand -hex 32)
ADMIN_TOKEN=$(openssl rand -base64 32)
cat <<EOF >/opt/garage/garage.toml
metadata_dir = "/opt/garage/meta"
data_dir = "/opt/garage/data"
db_engine = "lmdb"
replication_factor = 1
rpc_bind_addr = "[::]:3901"
rpc_public_addr = "127.0.0.1:3901"
rpc_secret = "${RPC_SECRET}"
[s3_api]
s3_region = "garage"
api_bind_addr = "[::]:3900"
root_domain = ".s3.garage.localhost"
[admin]
api_bind_addr = "[::]:3903"
admin_token = "${ADMIN_TOKEN}"
EOF
chmod 600 /opt/garage/garage.toml
chown -R garage:garage /opt/garage
cat <<EOF >/etc/systemd/system/garage.service
[Unit]
Description=Garage Object Storage
After=network.target
[Service]
Type=simple
User=garage
Group=garage
WorkingDirectory=/opt/garage
ExecStart=/usr/local/bin/garage -c /opt/garage/garage.toml server
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now garage
msg_ok "Installed Garage"
msg_info "Configuring Garage Bucket"
RETRIES=0
until garage -c /opt/garage/garage.toml status &>/dev/null; do
RETRIES=$((RETRIES + 1))
if [[ $RETRIES -ge 60 ]]; then
msg_error "Garage did not become ready within 60 seconds"
exit 1
fi
sleep 1
done
NODE_ID=$(garage -c /opt/garage/garage.toml status 2>/dev/null | awk '/^[0-9a-f]/{print $1; exit}')
if [[ -z "$NODE_ID" ]]; then
msg_error "Could not determine Garage node ID from cluster status"
exit 1
fi
GARAGE_CAPACITY="${GARAGE_CAPACITY:-$(df -BG --output=avail /opt/garage | awk 'NR==2{gsub(/G/,"",$1); v=$1-1; print (v<1?1:v)"G"}')}"
$STD garage -c /opt/garage/garage.toml layout assign -z dc1 -c "${GARAGE_CAPACITY}" "${NODE_ID}"
$STD garage -c /opt/garage/garage.toml layout apply --version 1
GARAGE_KEY_INFO=$(garage -c /opt/garage/garage.toml key create safebucket-key)
GARAGE_ACCESS_KEY=$(echo "$GARAGE_KEY_INFO" | awk '/Key ID:/{print $3}')
GARAGE_SECRET_KEY=$(echo "$GARAGE_KEY_INFO" | awk '/Secret key:/{print $3}')
$STD garage -c /opt/garage/garage.toml bucket create safebucket
$STD garage -c /opt/garage/garage.toml bucket allow --read --write --owner safebucket --key safebucket-key
msg_ok "Configured Garage Bucket"
msg_info "Applying CORS Policy to Bucket"
export AWS_ACCESS_KEY_ID="${GARAGE_ACCESS_KEY}"
export AWS_SECRET_ACCESS_KEY="${GARAGE_SECRET_KEY}"
export AWS_DEFAULT_REGION="garage"
if aws s3api put-bucket-cors \
--bucket safebucket \
--endpoint-url "http://127.0.0.1:3900" \
--cors-configuration '{"CORSRules":[{"AllowedHeaders":["*"],"AllowedMethods":["GET","PUT","POST","DELETE","HEAD"],"AllowedOrigins":["http://'"${LOCAL_IP}"':8080"],"ExposeHeaders":["ETag"]}]}' &>/dev/null; then
msg_ok "Applied CORS Policy to Bucket"
else
msg_warn "Could not apply CORS policy automatically; direct browser uploads may fail until CORS is configured manually"
fi
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_DEFAULT_REGION
fetch_and_deploy_gh_release "safebucket" "safebucket/safebucket" "singlefile" "latest" "/opt/safebucket" "safebucket-linux-$(arch_resolve)"
msg_info "Configuring Safebucket"
useradd --system --no-create-home --shell /usr/sbin/nologin safebucket 2>/dev/null || true
mkdir -p /opt/safebucket/data/{notifications,activity}
TOKEN_SECRET=$(openssl rand -base64 32)
MFA_KEY=$(openssl rand -base64 48 | tr -dc 'a-zA-Z0-9' | cut -c1-32)
ADMIN_PASSWORD=$(openssl rand -hex 12)
cat <<EOF >/opt/safebucket/config.yaml
app:
profile: default
log_level: info
api_url: http://${LOCAL_IP}:8080
web_url: http://${LOCAL_IP}:8080
allowed_origins:
- http://${LOCAL_IP}:8080
port: 8080
token_secret: "${TOKEN_SECRET}"
mfa_encryption_key: "${MFA_KEY}"
mfa_required: false
admin_email: admin@safebucket.io
admin_password: "${ADMIN_PASSWORD}"
trash_retention_days: 7
max_upload_size: 5368709120
trusted_proxies:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
- 127.0.0.0/8
- ::1/128
- fc00::/7
static_files:
enabled: true
database:
type: sqlite
sqlite:
path: /opt/safebucket/data/safebucket.db
cache:
type: memory
storage:
type: s3
s3:
bucket_name: safebucket
endpoint: 127.0.0.1:3900
external_endpoint: http://${LOCAL_IP}:3900
access_key: ${GARAGE_ACCESS_KEY}
secret_key: ${GARAGE_SECRET_KEY}
region: garage
force_path_style: true
use_tls: false
events:
type: memory
queues:
notifications:
name: safebucket-notifications
object_deletion:
name: safebucket-object-deletion
bucket_events:
name: safebucket-bucket-events
notifier:
type: filesystem
filesystem:
directory: /opt/safebucket/data/notifications
activity:
type: filesystem
filesystem:
directory: /opt/safebucket/data/activity
auth:
providers:
local:
name: local
type: local
sharing:
allowed: true
domains: []
EOF
chmod 600 /opt/safebucket/config.yaml
chown -R safebucket:safebucket /opt/safebucket
msg_ok "Configured Safebucket"
msg_info "Creating Service"
cat <<EOF >/etc/systemd/system/safebucket.service
[Unit]
Description=Safebucket File Sharing Platform
After=network-online.target garage.service
Wants=network-online.target
Requires=garage.service
[Service]
Type=simple
User=safebucket
Group=safebucket
WorkingDirectory=/opt/safebucket
Environment=CONFIG_FILE_PATH=/opt/safebucket/config.yaml
ExecStart=/opt/safebucket/safebucket
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now safebucket
msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc

View File

@@ -7,11 +7,11 @@
function header_info {
clear
cat <<"EOF"
____ __ _ ________ ____ __ __
/ __ \_________ _ ______ ___ ____ _ __ / / | |/ / ____/ / __ \___ / /__ / /____
/ /_/ / ___/ __ \| |/_/ __ `__ \/ __ \| |/_/ / / | / / / / / / _ \/ / _ \/ __/ _ \
/ ____/ / / /_/ /> </ / / / / / /_/ /> < / /___/ / /___ / /_/ / __/ / __/ /_/ __/
/_/ /_/ \____/_/|_/_/ /_/ /_/\____/_/|_| /_____/_/|_\____/ /_____/\___/_/\___/\__/\___/
____ ______ __ ____ __ __
/ __ \_________ _ ______ ___ ____ _ __ / ____/_ _____ _____/ /_ / __ \___ / /__ / /____
/ /_/ / ___/ __ \| |/_/ __ `__ \/ __ \| |/_/ / / __/ / / / _ \/ ___/ __/ / / / / _ \/ / _ \/ __/ _ \
/ ____/ / / /_/ /> </ / / / / / /_/ /> < / /_/ / /_/ / __(__ ) /_ / /_/ / __/ / __/ /_/ __/
/_/ /_/ \____/_/|_/_/ /_/ /_/\____/_/|_| \____/\__,_/\___/____/\__/ /_____/\___/_/\___/\__/\___/
EOF
}
@@ -42,76 +42,146 @@ CM="${TAB}✔️${TAB}${CL}"
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true
declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "lxc-delete" "pve"
GUEST_LOG=$(mktemp)
trap 'rm -f "$GUEST_LOG"' EXIT
# pct and qm differ in both their subcommands and their list layout, so every
# guest carries its type from the menu through to the destroy call.
stop_guest() {
local type=$1 id=$2 pid
if [ "$type" == "ct" ]; then
pct stop "$id" >"$GUEST_LOG" 2>&1 &
else
qm stop "$id" >"$GUEST_LOG" 2>&1 &
fi
pid=$!
spinner "$pid"
wait "$pid" || true
}
destroy_guest() {
local type=$1 id=$2 pid
if [ "$type" == "ct" ]; then
pct destroy "$id" -f >"$GUEST_LOG" 2>&1 &
else
qm destroy "$id" --purge --destroy-unreferenced-disks >"$GUEST_LOG" 2>&1 &
fi
pid=$!
spinner "$pid"
wait "$pid"
}
header_info
echo "Loading..."
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Proxmox VE LXC Deletion" --yesno "This will delete LXC containers. Proceed?" 10 58
whiptail --backtitle "Proxmox VE Helper Scripts" --title "Proxmox VE Guest Deletion" --yesno "This will delete LXC containers and/or VMs. Proceed?" 10 58
NODE=$(hostname)
containers=$(pct list | tail -n +2 | awk '{print $0 " " $4}')
containers=$(pct list 2>/dev/null | tail -n +2 || true)
vms=$(qm list 2>/dev/null | tail -n +2 || true)
if [ -z "$containers" ]; then
whiptail --title "LXC Container Delete" --msgbox "No LXC containers available!" 10 60
if [ -z "$containers" ] && [ -z "$vms" ]; then
whiptail --title "Guest Delete" --msgbox "No LXC containers or VMs available!" 10 60
exit 234
fi
menu_items=("ALL" "Delete ALL containers" "OFF") # Add as first option
FORMAT="%-10s %-15s %-10s"
declare -A GUEST_TYPE=()
menu_items=()
FORMAT="%-4s %-20s %-10s"
while read -r container; do
container_id=$(echo $container | awk '{print $1}')
container_name=$(echo $container | awk '{print $2}')
container_status=$(echo $container | awk '{print $3}')
formatted_line=$(printf "$FORMAT" "$container_name" "$container_status")
menu_items+=("$container_id" "$formatted_line" "OFF")
done <<<"$containers"
if [ -n "$containers" ]; then
menu_items+=("ALL-CT" "$(printf "$FORMAT" "CT" "Delete ALL containers" "")" "OFF")
while read -r line; do
[ -z "$line" ] && continue
# pct list: VMID Status [Lock] Name -- Lock is usually blank, so take the
# name from the end of the row rather than a fixed column.
container_id=$(awk '{print $1}' <<<"$line")
container_status=$(awk '{print $2}' <<<"$line")
container_name=$(awk '{print $NF}' <<<"$line")
GUEST_TYPE[$container_id]="ct"
menu_items+=("$container_id" "$(printf "$FORMAT" "CT" "$container_name" "$container_status")" "OFF")
done <<<"$containers"
fi
CHOICES=$(whiptail --title "LXC Container Delete" \
--checklist "Select LXC containers to delete:" 25 60 13 \
"${menu_items[@]}" 3>&2 2>&1 1>&3)
if [ -n "$vms" ]; then
menu_items+=("ALL-VM" "$(printf "$FORMAT" "VM" "Delete ALL VMs" "")" "OFF")
while read -r line; do
[ -z "$line" ] && continue
# qm list: VMID NAME STATUS MEM(MB) BOOTDISK(GB) PID
vm_id=$(awk '{print $1}' <<<"$line")
vm_name=$(awk '{print $2}' <<<"$line")
vm_status=$(awk '{print $3}' <<<"$line")
GUEST_TYPE[$vm_id]="vm"
menu_items+=("$vm_id" "$(printf "$FORMAT" "VM" "$vm_name" "$vm_status")" "OFF")
done <<<"$vms"
fi
CHOICES=$(whiptail --title "Guest Delete" \
--checklist "Select LXC containers and VMs to delete:" 25 70 13 \
"${menu_items[@]}" 3>&2 2>&1 1>&3 || true)
if [ -z "$CHOICES" ]; then
whiptail --title "LXC Container Delete" \
--msgbox "No containers selected!" 10 60
whiptail --title "Guest Delete" \
--msgbox "No guests selected!" 10 60
exit 0
fi
read -p "Delete containers manually or automatically? (Default: manual) m/a: " DELETE_MODE
read -p "Delete guests manually or automatically? (Default: manual) m/a: " DELETE_MODE
DELETE_MODE=${DELETE_MODE:-m}
selected_ids=$(echo "$CHOICES" | tr -d '"' | tr -s ' ' '\n')
# Expand the ALL entries, keeping each ID once so selecting ALL alongside a
# single guest does not try to destroy that guest twice.
expanded_ids=""
for choice in $(echo "$CHOICES" | tr -d '"' | tr -s ' ' '\n'); do
case "$choice" in
ALL-CT) expanded_ids+=$'\n'$(awk '{print $1}' <<<"$containers") ;;
ALL-VM) expanded_ids+=$'\n'$(awk '{print $1}' <<<"$vms") ;;
*) expanded_ids+=$'\n'"$choice" ;;
esac
done
selected_ids=$(echo "$expanded_ids" | sed '/^$/d' | awk '!seen[$0]++')
# If "ALL" is selected, override with all container IDs
if echo "$selected_ids" | grep -q "^ALL$"; then
selected_ids=$(echo "$containers" | awk '{print $1}')
fi
for guest_id in $selected_ids; do
guest_type="${GUEST_TYPE[$guest_id]:-}"
if [ -z "$guest_type" ]; then
echo -e "${BL}[Info]${RD} Skipping unknown guest $guest_id...${CL}"
continue
fi
for container_id in $selected_ids; do
status=$(pct status $container_id)
if [ "$status" == "status: running" ]; then
echo -e "${BL}[Info]${GN} Stopping container $container_id...${CL}"
pct stop $container_id &
sleep 5
echo -e "${BL}[Info]${GN} Container $container_id stopped.${CL}"
if [ "$guest_type" == "ct" ]; then
label="container $guest_id"
else
label="VM $guest_id"
fi
if [[ "$DELETE_MODE" == "a" ]]; then
echo -e "${BL}[Info]${GN} Automatically deleting container $container_id...${CL}"
pct destroy "$container_id" -f &
pid=$!
spinner $pid
[ $? -eq 0 ] && echo "Container $container_id deleted." || whiptail --title "Error" --msgbox "Failed to delete container $container_id." 10 60
echo -e "${BL}[Info]${GN} Automatically deleting $label...${CL}"
else
read -p "Delete container $container_id? (y/N): " CONFIRM
if [[ "$CONFIRM" =~ ^[Yy]$ ]]; then
echo -e "${BL}[Info]${GN} Deleting container $container_id...${CL}"
pct destroy "$container_id" -f &
pid=$!
spinner $pid
[ $? -eq 0 ] && echo "Container $container_id deleted." || whiptail --title "Error" --msgbox "Failed to delete container $container_id." 10 60
else
echo -e "${BL}[Info]${RD} Skipping container $container_id...${CL}"
read -p "Delete $label? (y/N): " CONFIRM
if [[ ! "$CONFIRM" =~ ^[Yy]$ ]]; then
echo -e "${BL}[Info]${RD} Skipping $label...${CL}"
continue
fi
echo -e "${BL}[Info]${GN} Deleting $label...${CL}"
fi
# Stop only once the deletion is confirmed, so declining leaves a running
# guest running instead of powering it off on the way out.
if [ "$guest_type" == "ct" ]; then
status=$(pct status "$guest_id" 2>/dev/null || echo "unknown")
else
status=$(qm status "$guest_id" 2>/dev/null || echo "unknown")
fi
if [ "$status" == "status: running" ]; then
echo -e "${BL}[Info]${GN} Stopping $label...${CL}"
stop_guest "$guest_type" "$guest_id"
echo -e "${BL}[Info]${GN} ${label^} stopped.${CL}"
fi
if destroy_guest "$guest_type" "$guest_id"; then
echo -e "${CM}${GN}${label^} deleted.${CL}"
else
whiptail --title "Error" --msgbox "Failed to delete ${label}.\n\n$(tail -n 5 "$GUEST_LOG")" 15 70
fi
done

View File

@@ -178,6 +178,24 @@ function resolve_service_script() {
return 1
}
# The retired Gitea mirror. The old entrypoint pulls ct/<app>.sh straight from
# it and never reaches the update helper that would repair itself, so rewrite it
# here. Only host and /raw/<kind>/ change; owner, repo and ref are kept.
function repair_update_url() {
local container="$1"
pct exec "$container" -- sh -c '
[ -f /usr/bin/update ] || exit 1
grep -q git.community-scripts.org /usr/bin/update || exit 1
sed -i \
-e "s|https://git[.]community-scripts[.]org/|https://raw.githubusercontent.com/|g" \
-e "s|/raw/branch/|/|g" -e "s|/raw/tag/|/|g" -e "s|/raw/commit/|/|g" \
/usr/bin/update
' >/dev/null 2>&1 || return 1
echo -e "${BL}[INFO]${CL} Repaired update URL (Gitea -> GitHub) in container $container"
log_write "Container $container: rewrote the retired Gitea base in /usr/bin/update"
}
function detect_service() {
local container="$1"
local tmpdir update_file
@@ -489,6 +507,9 @@ for container in $CHOICE; do
sleep 5
fi
#0.5) Rewrite a retired Gitea base before anything reads it.
repair_update_url "$container"
#1) Detect service using the service name in the update command
detect_service $container