#!/usr/bin/env bash # Run on the Proxmox host when shrink_request.json appears in the provisioning dir. # Runs PiShrink on the requested backup image (shrink or shrink+compress). # Requires PiShrink on host (scripts/install-pishrink-on-host.sh). Triggered by cm4-shrink.path. set -e PROV_DIR="${CM4_PROVISIONING_DIR:-/var/lib/cm4-provisioning}" REQUEST_FILE="$PROV_DIR/shrink_request.json" STATUS_FILE="$PROV_DIR/shrink_status.json" [[ -f /opt/cm4-provisioning/env ]] && source /opt/cm4-provisioning/env BACKUPS_DIR="${BACKUPS_DIR:-$PROV_DIR/backups}" PISHRINK="${PISHRINK_SCRIPT:-/usr/local/bin/pishrink.sh}" SHRINK_TIMEOUT="${SHRINK_TIMEOUT:-2100}" write_status() { local phase="$1" name="$2" message="$3" error="$4" printf '{"phase":"%s","name":"%s","message":"%s","error":%s,"updated":%s}\n' \ "$phase" "$name" "$message" \ "$([ -n "$error" ] && echo "\"${error//\"/\\\"}\"" || echo "null")" \ "$(date +%s)" > "$STATUS_FILE" } [[ -f "$REQUEST_FILE" ]] || { echo "No request file"; exit 0; } # Parse request NAME=$(python3 -c "import json; print(json.load(open('$REQUEST_FILE')).get('name',''))") ACTION=$(python3 -c "import json; print(json.load(open('$REQUEST_FILE')).get('action','shrink'))") FORMAT=$(python3 -c "import json; print(json.load(open('$REQUEST_FILE')).get('format','xz'))") rm -f "$REQUEST_FILE" # Validate if [[ -z "$NAME" ]]; then write_status "error" "" "" "Missing name in request" exit 0 fi if [[ "$NAME" != "${NAME##*/}" ]] || [[ "$NAME" == *..* ]]; then write_status "error" "$NAME" "" "Invalid name" exit 0 fi if [[ ! "$NAME" =~ \.img$ ]]; then write_status "error" "$NAME" "" "Only .img files can be shrunk" exit 0 fi PATH_FILE="$BACKUPS_DIR/$NAME" if [[ ! -f "$PATH_FILE" ]]; then write_status "error" "$NAME" "" "File not found" exit 0 fi if [[ ! -x "$PISHRINK" ]]; then write_status "error" "$NAME" "" "PiShrink not installed on host. Run scripts/install-pishrink-on-host.sh" exit 0 fi write_status "running" "$NAME" "Shrinking…" "" OPTS=(-n) if [[ "$ACTION" == "compress" ]]; then if [[ "$FORMAT" == "gz" ]] || [[ "$FORMAT" == "gzip" ]]; then OPTS+=(-z -a) else OPTS+=(-Z -a) fi fi cd "$BACKUPS_DIR" || exit 1 if timeout "$SHRINK_TIMEOUT" "$PISHRINK" "${OPTS[@]}" "$NAME" 2>&1; then if [[ "$ACTION" == "compress" ]]; then ext=".xz" [[ "$FORMAT" == "gz" ]] || [[ "$FORMAT" == "gzip" ]] && ext=".gz" write_status "done" "$NAME" "Compressed to ${NAME}${ext}" "" else write_status "done" "$NAME" "Shrunk $NAME" "" fi else rc=$? write_status "error" "$NAME" "" "PiShrink failed (exit $rc)" fi