|
|
@@ -1,8 +1,8 @@
|
|
|
#!/bin/sh
|
|
|
# YAAR — Update script
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
|
-# Pulls the latest code from master, redeploys the app, and restarts the
|
|
|
-# service. Runs INSIDE the Alpine LXC container as root. Does not touch the
|
|
|
+# Pulls the two app files directly from master, redeploys, and restarts the
|
|
|
+# service. Runs INSIDE the Alpine LXC container as root. Never touches the
|
|
|
# Proxmox host.
|
|
|
#
|
|
|
# Usage (inside the container):
|
|
|
@@ -14,14 +14,15 @@
|
|
|
# One-liner (always fetches the newest update logic too):
|
|
|
# curl -fsSL https://gogs.av2x.dev/av2x/yaar/raw/master/update.sh | sh
|
|
|
#
|
|
|
-# Safety: the current app.py and index.html are backed up before overwriting.
|
|
|
-# If the service fails to start on the new code, the previous version is
|
|
|
-# automatically restored and the service restarted, so YAAR is never left down.
|
|
|
+# Safety: current files are backed up before overwriting. New files are fetched
|
|
|
+# to a temp dir first and only moved into place if BOTH downloads succeed, so a
|
|
|
+# failed pull can't leave a half-updated deploy. If the service fails its health
|
|
|
+# check on the new code, the previous version is restored automatically.
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
|
|
set -e
|
|
|
|
|
|
-GOGS_ARCHIVE="https://gogs.av2x.dev/av2x/yaar/archive/master.tar.gz"
|
|
|
+RAW="https://gogs.av2x.dev/av2x/yaar/raw/master"
|
|
|
|
|
|
YAAR_DIR="/opt/yaar"
|
|
|
WEB_DIR="${YAAR_DIR}/web"
|
|
|
@@ -54,50 +55,50 @@ done
|
|
|
[ "$(id -u)" -eq 0 ] || die "Run as root: sh /opt/yaar/update.sh"
|
|
|
command -v pveversion >/dev/null 2>&1 && \
|
|
|
die "Run this INSIDE the container, not on the Proxmox host."
|
|
|
-[ -d "${YAAR_DIR}" ] || die "${YAAR_DIR} not found — is YAAR installed? Run setup.sh first."
|
|
|
+[ -d "${WEB_DIR}" ] || die "${WEB_DIR} not found — is YAAR installed? Run setup.sh first."
|
|
|
command -v curl >/dev/null 2>&1 || { info "Installing curl..."; apk add --no-cache curl >/dev/null; }
|
|
|
|
|
|
-# ── 1. Download latest ────────────────────────────────────────────────────────
|
|
|
+# ── 1. Fetch new files to a temp dir ──────────────────────────────────────────
|
|
|
+# Download both first; only deploy if BOTH succeed, so we never half-update.
|
|
|
TMP_DIR="$(mktemp -d /tmp/yaar-update.XXXXXX)"
|
|
|
trap 'rm -rf "${TMP_DIR}"' EXIT
|
|
|
+mkdir -p "${TMP_DIR}/templates"
|
|
|
|
|
|
-info "Downloading latest code from master..."
|
|
|
-curl -fsSL "${GOGS_ARCHIVE}" -o "${TMP_DIR}/yaar.tar.gz" \
|
|
|
- || die "Download failed. Check the URL and that the repo is reachable."
|
|
|
-tar -xzf "${TMP_DIR}/yaar.tar.gz" -C "${TMP_DIR}"
|
|
|
-
|
|
|
-# Locate the extracted source root (the folder containing web/app.py).
|
|
|
-SRC="$(dirname "$(find "${TMP_DIR}" -type f -path '*/web/app.py' | head -1)")/.."
|
|
|
-SRC="$(cd "${SRC}" 2>/dev/null && pwd || true)"
|
|
|
-[ -n "${SRC}" ] && [ -f "${SRC}/web/app.py" ] \
|
|
|
- || die "Could not find web/app.py in the downloaded archive."
|
|
|
-[ -f "${SRC}/web/templates/index.html" ] \
|
|
|
- || die "Could not find web/templates/index.html in the downloaded archive."
|
|
|
-success "Downloaded and extracted to ${SRC}"
|
|
|
-
|
|
|
-# ── 2. Back up current code ───────────────────────────────────────────────────
|
|
|
+info "Fetching app.py..."
|
|
|
+curl -fsSL "${RAW}/web/app.py" -o "${TMP_DIR}/app.py" \
|
|
|
+ || die "Failed to download app.py — nothing changed."
|
|
|
+
|
|
|
+info "Fetching index.html..."
|
|
|
+curl -fsSL "${RAW}/web/templates/index.html" -o "${TMP_DIR}/templates/index.html" \
|
|
|
+ || die "Failed to download index.html — nothing changed."
|
|
|
+
|
|
|
+# Sanity: make sure we got real files, not an error page.
|
|
|
+[ -s "${TMP_DIR}/app.py" ] || die "Downloaded app.py is empty."
|
|
|
+head -c 64 "${TMP_DIR}/app.py" | grep -q "python\|import\|#" \
|
|
|
+ || warn "app.py doesn't look like Python — continuing, health check will catch it."
|
|
|
+success "Both files downloaded"
|
|
|
+
|
|
|
+# ── 2. Back up current files ──────────────────────────────────────────────────
|
|
|
STAMP="$(date -u +%Y-%m-%d_%H-%M-%S)"
|
|
|
BACKUP="${BACKUP_DIR}/${STAMP}"
|
|
|
-mkdir -p "${BACKUP}/web/templates"
|
|
|
-info "Backing up current code to ${BACKUP}..."
|
|
|
-[ -f "${WEB_DIR}/app.py" ] && cp "${WEB_DIR}/app.py" "${BACKUP}/web/app.py"
|
|
|
-[ -f "${WEB_DIR}/templates/index.html" ] && cp "${WEB_DIR}/templates/index.html" "${BACKUP}/web/templates/index.html"
|
|
|
+mkdir -p "${BACKUP}/templates"
|
|
|
+info "Backing up current files to ${BACKUP}..."
|
|
|
+[ -f "${WEB_DIR}/app.py" ] && cp "${WEB_DIR}/app.py" "${BACKUP}/app.py"
|
|
|
+[ -f "${WEB_DIR}/templates/index.html" ] && cp "${WEB_DIR}/templates/index.html" "${BACKUP}/templates/index.html"
|
|
|
success "Backup saved"
|
|
|
|
|
|
# Keep only the 5 most recent backups.
|
|
|
-if [ -d "${BACKUP_DIR}" ]; then
|
|
|
- ls -1dt "${BACKUP_DIR}"/*/ 2>/dev/null | tail -n +6 | while read -r old; do
|
|
|
- rm -rf "${old}"
|
|
|
- done
|
|
|
-fi
|
|
|
+ls -1dt "${BACKUP_DIR}"/*/ 2>/dev/null | tail -n +6 | while read -r old; do rm -rf "${old}"; done
|
|
|
|
|
|
-# ── 3. Deploy new code ────────────────────────────────────────────────────────
|
|
|
-info "Deploying new code..."
|
|
|
-cp "${SRC}/web/app.py" "${WEB_DIR}/app.py"
|
|
|
-cp "${SRC}/web/templates/index.html" "${WEB_DIR}/templates/index.html"
|
|
|
-# Refresh the update script itself if it changed (so next run uses newest logic).
|
|
|
-[ -f "${SRC}/update.sh" ] && cp "${SRC}/update.sh" "${YAAR_DIR}/update.sh" && chmod +x "${YAAR_DIR}/update.sh"
|
|
|
-success "New code deployed"
|
|
|
+# ── 3. Deploy (atomic move into place) ────────────────────────────────────────
|
|
|
+info "Deploying new files..."
|
|
|
+mv "${TMP_DIR}/app.py" "${WEB_DIR}/app.py"
|
|
|
+mv "${TMP_DIR}/templates/index.html" "${WEB_DIR}/templates/index.html"
|
|
|
+success "New files deployed"
|
|
|
+
|
|
|
+# Refresh this update script too, so the next run uses the newest logic.
|
|
|
+curl -fsSL "${RAW}/update.sh" -o "${YAAR_DIR}/update.sh" 2>/dev/null \
|
|
|
+ && chmod +x "${YAAR_DIR}/update.sh" || true
|
|
|
|
|
|
# ── 4. Optional dependency upgrade ────────────────────────────────────────────
|
|
|
if [ "${DO_DEPS}" = "1" ]; then
|
|
|
@@ -106,33 +107,27 @@ if [ "${DO_DEPS}" = "1" ]; then
|
|
|
success "Dependencies upgraded — yt-dlp $(${VENV_DIR}/bin/yt-dlp --version)"
|
|
|
fi
|
|
|
|
|
|
-# ── 5. Restart service with auto-rollback ─────────────────────────────────────
|
|
|
+# ── 5. Restart with health check + auto-rollback ──────────────────────────────
|
|
|
info "Restarting YAAR service..."
|
|
|
rc-service yaar restart >/dev/null 2>&1 || true
|
|
|
sleep 2
|
|
|
|
|
|
-# Health check — is the service actually listening on the port?
|
|
|
healthy=0
|
|
|
-if rc-service yaar status 2>/dev/null | grep -q "started"; then
|
|
|
- healthy=1
|
|
|
-fi
|
|
|
-# Secondary check: HTTP response on the port
|
|
|
+rc-service yaar status 2>/dev/null | grep -q "started" && healthy=1
|
|
|
if command -v curl >/dev/null 2>&1; then
|
|
|
- if curl -fsS -o /dev/null --max-time 5 "http://127.0.0.1:${PORT}/" 2>/dev/null; then
|
|
|
- healthy=1
|
|
|
- fi
|
|
|
+ curl -fsS -o /dev/null --max-time 5 "http://127.0.0.1:${PORT}/" 2>/dev/null && healthy=1
|
|
|
fi
|
|
|
|
|
|
if [ "${healthy}" = "1" ]; then
|
|
|
success "Service restarted and healthy on port ${PORT}"
|
|
|
else
|
|
|
- warn "Service did not come up cleanly — rolling back to previous version..."
|
|
|
- [ -f "${BACKUP}/web/app.py" ] && cp "${BACKUP}/web/app.py" "${WEB_DIR}/app.py"
|
|
|
- [ -f "${BACKUP}/web/templates/index.html" ] && cp "${BACKUP}/web/templates/index.html" "${WEB_DIR}/templates/index.html"
|
|
|
+ warn "Service did not come up cleanly — rolling back..."
|
|
|
+ [ -f "${BACKUP}/app.py" ] && cp "${BACKUP}/app.py" "${WEB_DIR}/app.py"
|
|
|
+ [ -f "${BACKUP}/templates/index.html" ] && cp "${BACKUP}/templates/index.html" "${WEB_DIR}/templates/index.html"
|
|
|
rc-service yaar restart >/dev/null 2>&1 || true
|
|
|
sleep 2
|
|
|
if rc-service yaar status 2>/dev/null | grep -q "started"; then
|
|
|
- warn "Rolled back to previous version. YAAR is running on the OLD code."
|
|
|
+ warn "Rolled back — YAAR is running on the PREVIOUS version."
|
|
|
warn "Check ${LOG_DIR}/gunicorn.log for why the new code failed."
|
|
|
exit 1
|
|
|
else
|
|
|
@@ -144,7 +139,6 @@ fi
|
|
|
if [ "${DO_REBOOT}" = "1" ]; then
|
|
|
warn "Rebooting the container in 3 seconds (Ctrl+C to cancel)..."
|
|
|
sleep 3
|
|
|
- # Inside an LXC this signals Proxmox to restart the container.
|
|
|
reboot
|
|
|
exit 0
|
|
|
fi
|
|
|
@@ -157,7 +151,6 @@ printf "${GREEN}║ YAAR updated successfully ║${NC
|
|
|
printf "${GREEN}╠══════════════════════════════════════════════════════╣${NC}\n"
|
|
|
printf "${GREEN}║ Web UI: http://%-34s║${NC}\n" "${HOST_IP}:${PORT}"
|
|
|
printf "${GREEN}║ Backup: %-42s║${NC}\n" "${BACKUP}"
|
|
|
-printf "${GREEN}║ Rollback: cp ${BACKUP}/web/* back, then restart ║${NC}\n"
|
|
|
printf "${GREEN}╚══════════════════════════════════════════════════════╝${NC}\n"
|
|
|
printf "\n"
|
|
|
info "Hard-refresh your browser (Ctrl+Shift+R) to load the new UI."
|