Constants UPPER_SNAKE, mutable locals PascalCase, braced expansions throughout, per Development/Coding conventions in the vault.
130 lines
4.6 KiB
Bash
Executable File
130 lines
4.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Install the CD webhook receiver on this host.
|
|
#
|
|
# Idempotent: re-run it after editing targets.json, after rotating a secret, or
|
|
# after pulling a new version of this repository. It re-renders the hooks file
|
|
# and restarts the daemon; it never touches a project repository or uas-ng.
|
|
#
|
|
# Prerequisites:
|
|
# * adnanh/webhook on PATH (or WEBHOOK_BIN pointing at it)
|
|
# * a host-local secrets file, see secrets.env.example
|
|
# * this host present in targets.json under "hosts"
|
|
|
|
set -Eeuo pipefail
|
|
|
|
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
|
readonly REPO_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)"
|
|
|
|
readonly CONFIG_DIR="${XDG_CONFIG_HOME:-${HOME}/.config}/cd-webhook"
|
|
readonly HOOKS_FILE="${CONFIG_DIR}/hooks.json"
|
|
readonly SECRETS_FILE="${CONFIG_DIR}/secrets.env"
|
|
readonly SYSTEMD_DIR="${HOME}/.config/systemd/user"
|
|
readonly UNIT_NAME="cd-webhook.service"
|
|
|
|
info() { printf '\n\033[1m==> %s\033[0m\n' "$*"; }
|
|
ok() { printf ' ok %s\n' "$*"; }
|
|
die() { printf '\n\033[31mERROR\033[0m %s\n' "$*" >&2; exit 1; }
|
|
|
|
# ------------------------------------------------------------ prerequisites --
|
|
|
|
info "Checking prerequisites"
|
|
|
|
for Tool in python3 docker curl flock stdbuf; do
|
|
command -v "${Tool}" >/dev/null 2>&1 || die "required tool not found: ${Tool}"
|
|
done
|
|
ok "python3, docker, curl, flock, stdbuf"
|
|
|
|
WEBHOOK_BIN="${WEBHOOK_BIN:-$(command -v webhook || true)}"
|
|
[[ -n "${WEBHOOK_BIN}" && -x "${WEBHOOK_BIN}" ]] || die \
|
|
"adnanh/webhook not found. Install it, or set WEBHOOK_BIN=/path/to/webhook.
|
|
Debian/Ubuntu: sudo apt install webhook
|
|
Or a release binary from https://github.com/adnanh/webhook/releases"
|
|
ok "webhook binary: ${WEBHOOK_BIN}"
|
|
|
|
docker info >/dev/null 2>&1 || die \
|
|
"cannot talk to Docker as $(whoami). The deploy runs as this user, so this
|
|
account needs working access to the Docker socket it deploys through."
|
|
ok "docker reachable as $(whoami)"
|
|
|
|
# ------------------------------------------------------------- host config ---
|
|
|
|
info "Resolving this host in targets.json"
|
|
|
|
eval "$("${REPO_ROOT}/bin/cd-target" host-config)"
|
|
ok "host ${CD_HOST}, binding ${CD_BIND}:${CD_PORT}"
|
|
|
|
mapfile -t TARGETS < <("${REPO_ROOT}/bin/cd-target" list)
|
|
[[ ${#TARGETS[@]} -gt 0 ]] || die "no enabled targets for ${CD_HOST} in targets.json"
|
|
for Target in "${TARGETS[@]}"; do
|
|
ok "target ${Target}"
|
|
done
|
|
|
|
# ----------------------------------------------------------------- secrets ---
|
|
|
|
info "Checking the secrets file"
|
|
|
|
mkdir -p "${CONFIG_DIR}"
|
|
chmod 700 "${CONFIG_DIR}"
|
|
|
|
if [[ ! -f "${SECRETS_FILE}" ]]; then
|
|
install -m 0600 "${REPO_ROOT}/secrets.env.example" "${SECRETS_FILE}"
|
|
die "created a template at ${SECRETS_FILE}
|
|
Fill in one secret per repository, then re-run this installer.
|
|
The same value must be set as the Secret on the Gitea webhook."
|
|
fi
|
|
chmod 600 "${SECRETS_FILE}"
|
|
ok "${SECRETS_FILE}"
|
|
|
|
# ------------------------------------------------------------------- hooks ---
|
|
|
|
info "Rendering hooks for ${CD_HOST}"
|
|
"${REPO_ROOT}/bin/cd-render-hooks" --output "${HOOKS_FILE}" --secrets "${SECRETS_FILE}"
|
|
|
|
# ------------------------------------------------------------------ systemd --
|
|
|
|
info "Installing the user service"
|
|
|
|
mkdir -p "${SYSTEMD_DIR}"
|
|
sed -e "s|@WEBHOOK_BIN@|${WEBHOOK_BIN}|g" \
|
|
-e "s|@HOOKS_FILE@|${HOOKS_FILE}|g" \
|
|
-e "s|@BIND@|${CD_BIND}|g" \
|
|
-e "s|@PORT@|${CD_PORT}|g" \
|
|
"${REPO_ROOT}/etc/cd-webhook.service" > "${SYSTEMD_DIR}/${UNIT_NAME}"
|
|
ok "${SYSTEMD_DIR}/${UNIT_NAME}"
|
|
|
|
systemctl --user daemon-reload
|
|
systemctl --user enable "${UNIT_NAME}" >/dev/null
|
|
systemctl --user restart "${UNIT_NAME}"
|
|
ok "enabled and restarted"
|
|
|
|
# Survive logout, same as the other user services in this fleet.
|
|
loginctl enable-linger "$(whoami)" >/dev/null 2>&1 || true
|
|
|
|
sleep 1
|
|
systemctl --user is-active --quiet "${UNIT_NAME}" \
|
|
|| die "the service did not stay running:
|
|
systemctl --user status ${UNIT_NAME}
|
|
journalctl --user -u ${UNIT_NAME} -n 50 --no-pager"
|
|
|
|
# ------------------------------------------------------------------ summary --
|
|
|
|
info "Done. Configure these webhooks in Gitea"
|
|
|
|
echo
|
|
printf ' %-28s %s\n' "Target URL" "http://${CD_BIND}:${CD_PORT}/hooks/<id> (below)"
|
|
printf ' %-28s %s\n' "HTTP Method" "POST"
|
|
printf ' %-28s %s\n' "Content Type" "application/json"
|
|
printf ' %-28s %s\n' "Trigger On" "Push Events"
|
|
printf ' %-28s %s\n' "Secret" "the matching value from ${SECRETS_FILE}"
|
|
echo
|
|
|
|
"${REPO_ROOT}/bin/cd-render-hooks" --list-urls \
|
|
--output "${HOOKS_FILE}" --base-url "http://${CD_BIND}:${CD_PORT}" \
|
|
| sed 's/^/ /'
|
|
|
|
echo
|
|
echo " Logs: journalctl --user -u ${UNIT_NAME} -f"
|
|
echo " Status: ${REPO_ROOT}/bin/cd-status"
|
|
echo
|