#!/usr/bin/env bash # install.sh — one-shot installer for the vetting orchestrator on a # Proxmox LXC (or any Debian/Ubuntu host). # # What it does: # 1. apt-installs runtime dependencies (dnsmasq, iperf3, ca-certs). # 2. Creates the `vetting` system user with /var/lib/vetting homedir. # 3. Copies the pre-built `vetting` binary into /usr/local/bin. # 4. Drops the systemd unit and example config into /etc/vetting. # 5. Reminds the operator to edit the config before enabling # the service — we don't auto-start because the default bind # is loopback-only and needs at least a tweak to be useful. # # What it deliberately does NOT do: # - Build the orchestrator (this script assumes you ran # `make orchestrator-linux` beforehand and that bin/vetting-linux-amd64 # exists alongside this script, or pass --binary to locate it). # - Fetch TFTP iPXE payloads (that's pxe-setup.sh's job — it also # writes the pxe: block of vetting.yaml with first-time args). # # When a live-image/{vmlinuz,initrd.img} is present next to this script # (release bundle) or under ../live-image/build/ (repo checkout), it's # staged into --live-dir automatically. This makes the one-liner # upgrade loop work end-to-end for PXE-enabled installs. # # Usage: # sudo ./install.sh [--binary PATH] [--config-dir /etc/vetting] # set -euo pipefail BINARY="" AGENT_BINARY="" CONFIG_DIR="/etc/vetting" STATE_DIR="/var/lib/vetting" LOG_DIR="/var/log/vetting" ASSET_DIR="/var/lib/vetting/assets" LIVE_DIR="/var/lib/vetting/live" LIVE_IMAGE_SRC="" SERVICE_USER="vetting" usage() { cat <&2; usage; exit 2 ;; esac done if [[ $EUID -ne 0 ]]; then echo "install.sh must be run as root (try: sudo $0)" >&2 exit 1 fi SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" if [[ -z "${BINARY}" ]]; then for cand in \ "${REPO_ROOT}/bin/vetting-linux-amd64" \ "${REPO_ROOT}/bin/vetting" \ "${SCRIPT_DIR}/vetting"; do if [[ -x "${cand}" ]]; then BINARY="${cand}"; break; fi done fi if [[ -z "${BINARY}" || ! -x "${BINARY}" ]]; then echo "could not find a vetting binary to install; pass --binary PATH or run 'make orchestrator-linux' first" >&2 exit 1 fi if [[ -z "${AGENT_BINARY}" ]]; then for cand in \ "${REPO_ROOT}/bin/vetting-agent.linux-amd64" \ "${REPO_ROOT}/bin/vetting-agent-linux-amd64" \ "${SCRIPT_DIR}/vetting-agent-linux-amd64"; do if [[ -x "${cand}" ]]; then AGENT_BINARY="${cand}"; break; fi done fi if [[ -z "${AGENT_BINARY}" || ! -x "${AGENT_BINARY}" ]]; then echo "could not find a vetting-agent binary; pass --agent-binary PATH or run 'make agent-linux' first" >&2 exit 1 fi echo "==> installing runtime dependencies" export DEBIAN_FRONTEND=noninteractive apt-get update -qq apt-get install -y --no-install-recommends \ ca-certificates dnsmasq iperf3 echo "==> creating ${SERVICE_USER} user" if ! id -u "${SERVICE_USER}" >/dev/null 2>&1; then useradd --system \ --home-dir "${STATE_DIR}" \ --shell /usr/sbin/nologin \ "${SERVICE_USER}" fi echo "==> preparing directories" install -d -m 0755 -o "${SERVICE_USER}" -g "${SERVICE_USER}" "${STATE_DIR}" install -d -m 0755 -o "${SERVICE_USER}" -g "${SERVICE_USER}" "${LOG_DIR}" install -d -m 0755 -o "${SERVICE_USER}" -g "${SERVICE_USER}" "${ASSET_DIR}" install -d -m 0755 "${CONFIG_DIR}" echo "==> installing binary" install -m 0755 "${BINARY}" /usr/local/bin/vetting install -m 0755 "${AGENT_BINARY}" "${ASSET_DIR}/vetting-agent-linux-amd64" echo "==> installing config and systemd unit" # vetting.production.yaml uses absolute /var/lib/vetting + /var/log/vetting # paths that match the systemd unit's ReadWritePaths. vetting.example.yaml # uses ./var/... relatives and is only correct for `make run` in a dev tree. if [[ ! -f "${CONFIG_DIR}/vetting.yaml" ]]; then install -m 0640 -o root -g "${SERVICE_USER}" \ "${SCRIPT_DIR}/vetting.production.yaml" \ "${CONFIG_DIR}/vetting.yaml" echo " -> installed default config at ${CONFIG_DIR}/vetting.yaml" else echo " -> preserving existing ${CONFIG_DIR}/vetting.yaml" fi install -m 0644 "${SCRIPT_DIR}/vetting.service" /etc/systemd/system/vetting.service # Install pxe-setup.sh + its pinned iPXE SHAs into a stable path so the # operator can run `vetting-pxe-setup ...` after the one-liner install. # The bundle's tempdir gets wiped by proxmox-install.sh on exit, so # without this the script would be inaccessible. if [[ -f "${SCRIPT_DIR}/pxe-setup.sh" && -f "${SCRIPT_DIR}/ipxe-shas.txt" ]]; then echo "==> installing pxe-setup.sh and ipxe-shas.txt" install -d -m 0755 /usr/local/share/vetting install -m 0755 "${SCRIPT_DIR}/pxe-setup.sh" /usr/local/share/vetting/pxe-setup.sh install -m 0644 "${SCRIPT_DIR}/ipxe-shas.txt" /usr/local/share/vetting/ipxe-shas.txt ln -sfn /usr/local/share/vetting/pxe-setup.sh /usr/local/sbin/vetting-pxe-setup fi # Stage the live image into LIVE_DIR if we can find one. Two layouts: # - release bundle: ${SCRIPT_DIR}/live-image/{vmlinuz,initrd.img} # - repo-tree dev run: ${REPO_ROOT}/live-image/build/{vmlinuz,initrd.img} # Silently skipped when no source is found — operators without PXE # don't need it, and dev checkouts that haven't run `make live-image` # shouldn't fail the install. if [[ -z "${LIVE_IMAGE_SRC}" ]]; then for cand in \ "${SCRIPT_DIR}/live-image" \ "${REPO_ROOT}/live-image/build"; do if [[ -f "${cand}/vmlinuz" && -f "${cand}/initrd.img" ]]; then LIVE_IMAGE_SRC="${cand}" break fi done fi if [[ -n "${LIVE_IMAGE_SRC}" ]]; then echo "==> staging live image from ${LIVE_IMAGE_SRC} into ${LIVE_DIR}" install -d -m 0755 -o "${SERVICE_USER}" -g "${SERVICE_USER}" "${LIVE_DIR}" install -m 0644 -o "${SERVICE_USER}" -g "${SERVICE_USER}" \ "${LIVE_IMAGE_SRC}/vmlinuz" "${LIVE_DIR}/vmlinuz" install -m 0644 -o "${SERVICE_USER}" -g "${SERVICE_USER}" \ "${LIVE_IMAGE_SRC}/initrd.img" "${LIVE_DIR}/initrd.img" else echo "==> no live image found (bundle/live-image or ../live-image/build); skipping live-dir staging" fi # Disable the distro's dnsmasq so only the orchestrator-supervised # instance owns DHCP/TFTP. Operators who want to keep dnsmasq for # something else can re-enable it after configuring a disjoint listen # address. if systemctl is-enabled --quiet dnsmasq 2>/dev/null; then echo "==> disabling distro dnsmasq (orchestrator supervises its own)" systemctl disable --now dnsmasq fi systemctl daemon-reload # Upgrade path: if vetting.service is already enabled, restart it so the # new binary + live image take effect without an explicit second # command. First-install path (service not enabled yet) leaves the # service alone so the operator can edit the config before starting. if systemctl is-enabled --quiet vetting.service 2>/dev/null; then echo "==> restarting vetting.service (upgrade path)" systemctl reset-failed vetting.service 2>/dev/null || true systemctl restart vetting.service cat <