Fix scoped deployment state and config ownership

This commit is contained in:
Frank
2026-08-25 20:24:47 -07:00
parent 3a56a07883
commit bc718f04f4
3 changed files with 65 additions and 9 deletions
+54 -8
View File
@@ -127,15 +127,29 @@ state_revision() {
} }
state_status() { state_status() {
local service="$1" line value local service="$1" line value=pending
if [[ -r "$STATE_DIR/$service" ]]; then if [[ -r "$STATE_DIR/$service" ]]; then
while IFS= read -r line; do while IFS= read -r line; do
case "$line" in case "$line" in
status=*) value="${line#status=}" ;; status=*) value="${line#status=}" ;;
esac esac
done < "$STATE_DIR/$service" done < "$STATE_DIR/$service"
printf '%s' "${value:-pending}"
fi fi
printf '%s' "$value"
}
register_changed_services() {
local base="$1" service recorded status
[[ -n "$base" ]] || return 0
while IFS= read -r service; do
[[ -n "$service" ]] || continue
recorded="$(state_revision "$service")"
status="$(state_status "$service")"
if [[ "$status" != deployed || "$recorded" != "$REVISION" ]]; then
mark_status "$service" pending
fi
done < <(python3 scripts/deploy-plan.py --target "$TARGET" --repo "$REMOTE_DIR" \
--base "$base" --head "$REVISION")
} }
add_changed_services() { add_changed_services() {
@@ -150,13 +164,19 @@ add_changed_services() {
} }
add_pending_services() { add_pending_services() {
local service recorded changed local service recorded status changed
for state_file in "$STATE_DIR"/*; do for state_file in "$STATE_DIR"/*; do
[[ -f "$state_file" ]] || continue [[ -f "$state_file" ]] || continue
service="${state_file##*/}" service="${state_file##*/}"
recorded="$(state_revision "$service")" recorded="$(state_revision "$service")"
status="$(state_status "$service")"
if [[ "$status" != deployed ]]; then
# A pending service was intentionally skipped or its handler
# failed. Retry it even when the checkout has not advanced.
SERVICES+=("$service")
continue
fi
[[ -n "$recorded" && "$recorded" != "$REVISION" ]] || continue [[ -n "$recorded" && "$recorded" != "$REVISION" ]] || continue
[[ "$(state_status "$service")" != deployed ]] || continue
if [[ "$TARGET" == dankclaw && "$service" == frank-default-small ]]; then continue; fi if [[ "$TARGET" == dankclaw && "$service" == frank-default-small ]]; then continue; fi
if [[ "$TARGET" == dankserver && "$service" == frank-default-large ]]; then continue; fi if [[ "$TARGET" == dankserver && "$service" == frank-default-large ]]; then continue; fi
if ! changed="$(python3 scripts/deploy-plan.py --target "$TARGET" \ if ! changed="$(python3 scripts/deploy-plan.py --target "$TARGET" \
@@ -171,12 +191,24 @@ add_pending_services() {
done done
} }
copy_shared_config() { copy_searxng_config() {
run_privileged mkdir -p /opt/searxng/config /opt/prometheus/config /opt/loki/config /opt/alloy/config run_privileged mkdir -p /opt/searxng/config
run_privileged cp shared/searxng/settings.yml /opt/searxng/config/settings.yml run_privileged cp shared/searxng/settings.yml /opt/searxng/config/settings.yml
run_privileged cp shared/searxng/limiter.toml /opt/searxng/config/limiter.toml run_privileged cp shared/searxng/limiter.toml /opt/searxng/config/limiter.toml
}
copy_prometheus_config() {
run_privileged mkdir -p /opt/prometheus/config
run_privileged cp shared/prometheus/prometheus.yml /opt/prometheus/config/prometheus.yml run_privileged cp shared/prometheus/prometheus.yml /opt/prometheus/config/prometheus.yml
}
copy_loki_config() {
run_privileged mkdir -p /opt/loki/config
run_privileged cp shared/loki/loki-config.yaml /opt/loki/config/loki-config.yaml run_privileged cp shared/loki/loki-config.yaml /opt/loki/config/loki-config.yaml
}
copy_alloy_config() {
run_privileged mkdir -p /opt/alloy/config
run_privileged cp shared/alloy/config.alloy /opt/alloy/config/config.alloy run_privileged cp shared/alloy/config.alloy /opt/alloy/config/config.alloy
} }
@@ -221,7 +253,6 @@ deploy_caddy() {
echo "caddy is owned by dankclaw; refusing to deploy it on $TARGET" >&2 echo "caddy is owned by dankclaw; refusing to deploy it on $TARGET" >&2
return 2 return 2
fi fi
copy_shared_config
render_caddyfile render_caddyfile
deploy_homepage deploy_homepage
local cfhash oldhash image local cfhash oldhash image
@@ -285,6 +316,15 @@ deploy_compose_service() {
comfyui|loki|alloy) comfyui|loki|alloy)
build_compose_image "$service" build_compose_image "$service"
;; ;;
prometheus)
copy_prometheus_config
;;
loki)
copy_loki_config
;;
alloy)
copy_alloy_config
;;
esac esac
podman-compose -f dankclaw/compose.yaml up -d --no-deps "$service" podman-compose -f dankclaw/compose.yaml up -d --no-deps "$service"
;; ;;
@@ -331,7 +371,7 @@ install_quadlet() {
} }
deploy_searxng() { deploy_searxng() {
copy_shared_config copy_searxng_config
install_quadlet searxng dankclaw/searxng/quadlet searxng install_quadlet searxng dankclaw/searxng/quadlet searxng
install_quadlet searxng-valkey dankclaw/searxng/quadlet searxng-valkey install_quadlet searxng-valkey dankclaw/searxng/quadlet searxng-valkey
install_quadlet gluetun dankclaw/searxng/quadlet gluetun install_quadlet gluetun dankclaw/searxng/quadlet gluetun
@@ -450,6 +490,12 @@ deploy_service() {
esac esac
} }
if [[ -n "$FROM_REVISION" ]]; then
# Register every changed service before applying the requested scope. This
# preserves an explicit --service selection as pending work for the next
# ordinary deployment.
register_changed_services "$FROM_REVISION"
fi
if [[ "$PENDING" -eq 1 ]]; then if [[ "$PENDING" -eq 1 ]]; then
add_changed_services "$FROM_REVISION" add_changed_services "$FROM_REVISION"
add_pending_services add_pending_services
+2 -1
View File
@@ -208,7 +208,8 @@ if [[ "$NEW_REVISION" != "$EXPECTED_REVISION" ]]; then
echo "FAIL: target checkout is $NEW_REVISION, expected $EXPECTED_REVISION" >&2 echo "FAIL: target checkout is $NEW_REVISION, expected $EXPECTED_REVISION" >&2
exit 1 exit 1
fi fi
exec ./scripts/deploy-remote.sh "$TARGET" "$NEW_REVISION" "$@" exec ./scripts/deploy-remote.sh "$TARGET" "$NEW_REVISION" "$@" \
--from-revision "$OLD_REVISION"
REMOTE_EOF REMOTE_EOF
echo "=== Deploy complete: $TARGET ===" echo "=== Deploy complete: $TARGET ==="
+9
View File
@@ -110,6 +110,15 @@ REMOTE_DEPLOY="$REPO_ROOT/scripts/deploy-remote.sh"
[ "$status" -eq 2 ] [ "$status" -eq 2 ]
} }
@test "remote runner recognizes a pending service at the same revision" {
local state_dir="$(mktemp -d)"
printf 'revision=%s\nstatus=pending\n' "$(git rev-parse HEAD)" > "$state_dir/unknown-service"
run env DEPLOY_STATE_DIR="$state_dir" REMOTE_DIR="$REPO_ROOT" \
bash "$REMOTE_DEPLOY" dankclaw "$(git rev-parse HEAD)" --pending
[ "$status" -eq 2 ]
[[ "$output" == *"unknown-service"* || "$output" == *"not deployed"* ]]
}
@test "top-level deployer delegates to the service-scoped remote runner" { @test "top-level deployer delegates to the service-scoped remote runner" {
grep -q 'deploy-remote.sh' "$REPO_ROOT/scripts/deploy.sh" grep -q 'deploy-remote.sh' "$REPO_ROOT/scripts/deploy.sh"
grep -qE 'SERVICE|service' "$REPO_ROOT/scripts/deploy.sh" grep -qE 'SERVICE|service' "$REPO_ROOT/scripts/deploy.sh"