source: Klonkt/scripts/klonkt-refresh-updater.sh@ 12bed59

main
Last change on this file since 12bed59 was 12bed59, checked in by Robin <roboburr@…>, 5 weeks ago

Zet de oude klonkt.service opzij; maskeren werkte niet

Correctie op f434294. Daar maskeerde ik de oude unit om te voorkomen dat een
systemctl restart klonkt hem uit de dood liet opstaan. Getest met een
user-unit blijkt dat niet te werken:

Failed to mask unit: File '.../masktest.service' already exists

systemctl mask legt een symlink naar /dev/null op het pad van de unit, maar
install.sh schrijft klonkt.service in /etc/systemd/system, de map met de
hoogste prioriteit. Er is dan geen plek meer om de mask neer te zetten en
systemd weigert. Na de mislukte mask start restart de unit gewoon nog
(exitcode 0), dus de fix deed niets.

Erger: die mask stond zonder vangnet onder set -euo pipefail. In het
migratiescript zou hij de migratie afbreken NADAT de data al verplaatst was.
De fix was dus niet alleen nutteloos maar ook gevaarlijk.

Wat wel werkt, en nu getest is in beide richtingen: het unit-bestand opzij
zetten met een tijdstempel en daemon-reload. systemd kent de unit dan niet
meer, en een restart faalt hard met "Unit klonkt.service not found"
(exitcode 5) in plaats van stilletjes een tweede proces te starten dat een
lege database in de checkout schrijft. Terugzetten plus daemon-reload maakt
hem weer gewoon startbaar, dus de rollback blijft intact.

Changed files:
scripts/klonkt-migrate-data.sh

  • eigen stap 'Retiring klonkt.service': stop, disable, bestand naar klonkt.service.retired-<tijdstempel>, daemon-reload
  • stop en disable krijgen een vangnet zodat een al gestopte unit de migratie niet afbreekt
  • waarom maskeren hier niet kan, staat erbij; dat is niet vanzelfsprekend

scripts/klonkt-refresh-updater.sh

  • zelfde aanpak voor al gemigreerde servers, met een expliciete waarschuwing als het verplaatsen niet lukt

deploy/MULTI-INSTANCE.md

  • rollback bijgewerkt naar het terugzetten van het bestand

-robo
Co-Authored-By: Claude Fable 5 <noreply@…>

  • Property mode set to 100755
File size: 4.3 KB
Line 
1#!/usr/bin/env bash
2#
3# (Re)write /usr/local/bin/klonkt-update so it matches how this server runs.
4#
5# Why this exists: the updater is generated once at install time. A server
6# that later migrated to the split layout (klonkt@<slug> units) kept its old
7# updater, which still restarts the retired klonkt.service. Result: the code
8# on disk updates, the restart quietly fails, and the old process keeps
9# serving — half old routes, half new templates, which is how you get a 500
10# on one page and nothing in the logs that says why.
11#
12# Idempotent; safe to run any time:
13#
14# sudo bash /opt/klonkt/scripts/klonkt-refresh-updater.sh
15#
16set -euo pipefail
17
18KLONKT_DIR="${KLONKT_DIR:-/opt/klonkt}"
19KLONKT_USER="${KLONKT_USER:-klonkt}"
20DATA_ROOT="${KLONKT_DATA_ROOT:-/var/lib/klonkt}"
21# Follow whatever branch the checkout is on (stable for most self-hosters).
22BRANCH="${KLONKT_BRANCH:-$(git -C "$KLONKT_DIR" rev-parse --abbrev-ref HEAD 2>/dev/null || echo stable)}"
23
24[ "$(id -u)" = 0 ] || { echo "run this as root (sudo)." >&2; exit 1; }
25[ -d "$KLONKT_DIR/.git" ] || { echo "no git checkout at $KLONKT_DIR" >&2; exit 1; }
26
27cat > /usr/local/bin/klonkt-update <<EOF
28#!/usr/bin/env bash
29set -euo pipefail
30D="${KLONKT_DIR}"
31B=\$(runuser -u ${KLONKT_USER} -- git -C "\$D" rev-parse HEAD 2>/dev/null || true)
32runuser -u ${KLONKT_USER} -- git -C "\$D" fetch --depth 1 origin ${BRANCH}
33runuser -u ${KLONKT_USER} -- git -C "\$D" checkout -qf -B ${BRANCH} FETCH_HEAD
34A=\$(runuser -u ${KLONKT_USER} -- git -C "\$D" rev-parse HEAD)
35if [ "\$B" = "\$A" ]; then
36 echo "Klonkt is already up to date (\$A) — nothing to do."
37 exit 0
38fi
39if ! runuser -u ${KLONKT_USER} -- git -C "\$D" diff --quiet "\$B" "\$A" -- package-lock.json 2>/dev/null; then
40 runuser -u ${KLONKT_USER} -- env HOME="\$D" bash -c "cd '\$D' && npm ci --omit=dev"
41fi
42# Restart every instance sharing this checkout: one directory with an .env
43# under the data root per instance. No instances there = the pre-split
44# single-service layout, which still runs plain klonkt.service.
45N=0
46for d in ${DATA_ROOT}/*/; do
47 [ -f "\$d/.env" ] || continue
48 s=\$(basename "\$d")
49 systemctl restart "klonkt@\$s" && N=\$((N+1))
50done
51if [ "\$N" = 0 ]; then
52 systemctl restart klonkt
53 echo "Klonkt updated (\$A) + restarted."
54else
55 echo "Klonkt updated (\$A) + restarted \$N instance(s)."
56fi
57EOF
58chmod +x /usr/local/bin/klonkt-update
59echo "klonkt-update rewritten: branch ${BRANCH}, code ${KLONKT_DIR}, instances under ${DATA_ROOT}"
60
61# On a split install the old single unit must not be startable at all.
62# `disable` is not enough (restart starts a disabled unit anyway) and `mask`
63# refuses while the real file sits in /etc/systemd/system, the highest-priority
64# directory. Moving the file aside is what actually works: systemd stops
65# knowing the unit, so any restart fails loudly instead of quietly starting a
66# second process that writes an empty database into the checkout.
67SPLIT=0
68for d in "${DATA_ROOT}"/*/; do [ -f "$d/.env" ] && SPLIT=1 && break; done
69if [ "$SPLIT" = 1 ] && [ -f /etc/systemd/system/klonkt.service ]; then
70 systemctl stop klonkt.service 2>/dev/null || true
71 systemctl disable klonkt.service 2>/dev/null || true
72 RETIRED="/etc/systemd/system/klonkt.service.retired-$(date +%Y%m%d%H%M%S)"
73 if mv /etc/systemd/system/klonkt.service "$RETIRED"; then
74 systemctl daemon-reload
75 echo "retired klonkt.service → $RETIRED (move it back + daemon-reload to roll back)"
76 else
77 echo "WARNING: could not move /etc/systemd/system/klonkt.service aside."
78 echo " Until you do, any 'systemctl restart klonkt' starts a second"
79 echo " process that writes an empty database into ${KLONKT_DIR}."
80 fi
81fi
82
83# A leftover storage/ in the checkout means something ran without the instance
84# config. Report it; never delete it unattended — only its owner can tell
85# whether it holds anything.
86if [ "$SPLIT" = 1 ] && [ -e "${KLONKT_DIR}/storage" ]; then
87 echo
88 echo "WARNING: ${KLONKT_DIR}/storage exists while instance data lives in ${DATA_ROOT}."
89 echo " Something ran without the instance .env and wrote here. Check with:"
90 echo " sqlite3 ${KLONKT_DIR}/storage/database.sqlite 'select count(*) from posts;'"
91 echo " If it is empty, it is a stray from a resurrected klonkt.service and"
92 echo " can be removed. If it is NOT empty, do not delete it: ask first."
93fi
Note: See TracBrowser for help on using the repository browser.