diff --git a/lib/init/nomad/lib-systemd.sh b/lib/init/nomad/lib-systemd.sh new file mode 100644 index 0000000..4da0fee --- /dev/null +++ b/lib/init/nomad/lib-systemd.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash +# ============================================================================= +# lib/init/nomad/lib-systemd.sh — Shared idempotent systemd-unit installer +# +# Sourced by lib/init/nomad/systemd-nomad.sh and lib/init/nomad/systemd-vault.sh +# (and any future sibling) to collapse the "write unit if content differs, +# daemon-reload, enable (never start)" boilerplate. +# +# Install-but-don't-start is the invariant this helper enforces — mid-migration +# installers land files and enable units; the orchestrator (S0.4) starts them. +# +# Public API (sourced into caller scope): +# +# systemd_require_preconditions UNIT_PATH +# Asserts the caller is uid 0 and `systemctl` is on $PATH. Calls the +# caller's die() with a UNIT_PATH-scoped message on failure. +# +# systemd_install_unit UNIT_PATH UNIT_NAME UNIT_CONTENT +# Writes UNIT_CONTENT to UNIT_PATH (0644 root:root) only if on-disk +# content differs. If written, runs `systemctl daemon-reload`. Then +# enables UNIT_NAME (no-op if already enabled). Never starts the unit. +# +# Caller contract: +# - Callers MUST define `log()` and `die()` before sourcing this file (we +# call log() for status chatter and rely on the caller's error-handling +# stance; `set -e` propagates install/cmp/systemctl failures). +# ============================================================================= + +# systemd_require_preconditions UNIT_PATH +systemd_require_preconditions() { + local unit_path="$1" + if [ "$(id -u)" -ne 0 ]; then + die "must run as root (needs write access to ${unit_path})" + fi + command -v systemctl >/dev/null 2>&1 \ + || die "systemctl not found (systemd is required)" +} + +# systemd_install_unit UNIT_PATH UNIT_NAME UNIT_CONTENT +systemd_install_unit() { + local unit_path="$1" + local unit_name="$2" + local unit_content="$3" + + local needs_reload=0 + if [ ! -f "$unit_path" ] \ + || ! printf '%s\n' "$unit_content" | cmp -s - "$unit_path"; then + log "writing unit → ${unit_path}" + local tmp + tmp="$(mktemp)" + printf '%s\n' "$unit_content" > "$tmp" + install -m 0644 -o root -g root "$tmp" "$unit_path" + rm -f "$tmp" + needs_reload=1 + else + log "unit file already up to date" + fi + + if [ "$needs_reload" -eq 1 ]; then + log "systemctl daemon-reload" + systemctl daemon-reload + fi + + if systemctl is-enabled --quiet "$unit_name" 2>/dev/null; then + log "${unit_name} already enabled" + else + log "systemctl enable ${unit_name}" + systemctl enable "$unit_name" >/dev/null + fi +} diff --git a/lib/init/nomad/systemd-nomad.sh b/lib/init/nomad/systemd-nomad.sh index e9db191..93f85f0 100755 --- a/lib/init/nomad/systemd-nomad.sh +++ b/lib/init/nomad/systemd-nomad.sh @@ -33,13 +33,11 @@ NOMAD_DATA_DIR="/var/lib/nomad" log() { printf '[systemd-nomad] %s\n' "$*"; } die() { printf '[systemd-nomad] ERROR: %s\n' "$*" >&2; exit 1; } -# ── Preconditions ──────────────────────────────────────────────────────────── -if [ "$(id -u)" -ne 0 ]; then - die "must run as root (needs write access to ${UNIT_PATH})" -fi +# shellcheck source=lib-systemd.sh +. "$(dirname "${BASH_SOURCE[0]}")/lib-systemd.sh" -command -v systemctl >/dev/null 2>&1 \ - || die "systemctl not found (systemd is required)" +# ── Preconditions ──────────────────────────────────────────────────────────── +systemd_require_preconditions "$UNIT_PATH" NOMAD_BIN="$(command -v nomad 2>/dev/null || true)" [ -n "$NOMAD_BIN" ] \ @@ -98,33 +96,7 @@ for d in "$NOMAD_CONFIG_DIR" "$NOMAD_DATA_DIR"; do fi done -# ── Install unit file only if content differs ──────────────────────────────── -needs_reload=0 -if [ ! -f "$UNIT_PATH" ] \ - || ! printf '%s\n' "$DESIRED_UNIT" | cmp -s - "$UNIT_PATH"; then - log "writing unit → ${UNIT_PATH}" - tmp="$(mktemp)" - trap 'rm -f "$tmp"' EXIT - printf '%s\n' "$DESIRED_UNIT" > "$tmp" - install -m 0644 -o root -g root "$tmp" "$UNIT_PATH" - rm -f "$tmp" - trap - EXIT - needs_reload=1 -else - log "unit file already up to date" -fi - -# ── Reload + enable ────────────────────────────────────────────────────────── -if [ "$needs_reload" -eq 1 ]; then - log "systemctl daemon-reload" - systemctl daemon-reload -fi - -if systemctl is-enabled --quiet nomad.service 2>/dev/null; then - log "nomad.service already enabled" -else - log "systemctl enable nomad" - systemctl enable nomad.service >/dev/null -fi +# ── Install + reload + enable (shared with systemd-vault.sh via lib-systemd) ─ +systemd_install_unit "$UNIT_PATH" "nomad.service" "$DESIRED_UNIT" log "done — unit installed and enabled (NOT started; S0.4 brings the cluster up)" diff --git a/lib/init/nomad/systemd-vault.sh b/lib/init/nomad/systemd-vault.sh index e386438..8a241d4 100755 --- a/lib/init/nomad/systemd-vault.sh +++ b/lib/init/nomad/systemd-vault.sh @@ -56,13 +56,11 @@ VAULT_HCL_SRC="${REPO_ROOT}/nomad/vault.hcl" log() { printf '[systemd-vault] %s\n' "$*"; } die() { printf '[systemd-vault] ERROR: %s\n' "$*" >&2; exit 1; } -# ── Preconditions ──────────────────────────────────────────────────────────── -if [ "$(id -u)" -ne 0 ]; then - die "must run as root (needs write access to ${UNIT_PATH})" -fi +# shellcheck source=lib-systemd.sh +. "${SCRIPT_DIR}/lib-systemd.sh" -command -v systemctl >/dev/null 2>&1 \ - || die "systemctl not found (systemd is required)" +# ── Preconditions ──────────────────────────────────────────────────────────── +systemd_require_preconditions "$UNIT_PATH" VAULT_BIN="$(command -v vault 2>/dev/null || true)" [ -n "$VAULT_BIN" ] \ @@ -146,33 +144,7 @@ else log "config already up to date" fi -# ── Install unit file only if content differs ──────────────────────────────── -needs_reload=0 -if [ ! -f "$UNIT_PATH" ] \ - || ! printf '%s\n' "$DESIRED_UNIT" | cmp -s - "$UNIT_PATH"; then - log "writing unit → ${UNIT_PATH}" - tmp="$(mktemp)" - trap 'rm -f "$tmp"' EXIT - printf '%s\n' "$DESIRED_UNIT" > "$tmp" - install -m 0644 -o root -g root "$tmp" "$UNIT_PATH" - rm -f "$tmp" - trap - EXIT - needs_reload=1 -else - log "unit file already up to date" -fi - -# ── Reload + enable ────────────────────────────────────────────────────────── -if [ "$needs_reload" -eq 1 ]; then - log "systemctl daemon-reload" - systemctl daemon-reload -fi - -if systemctl is-enabled --quiet vault.service 2>/dev/null; then - log "vault.service already enabled" -else - log "systemctl enable vault" - systemctl enable vault.service >/dev/null -fi +# ── Install + reload + enable (shared with systemd-nomad.sh via lib-systemd) ─ +systemd_install_unit "$UNIT_PATH" "vault.service" "$DESIRED_UNIT" log "done — unit+config installed and enabled (NOT started; vault-init.sh next)"