#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" BUILD_DIR="$ROOT_DIR/deployment/build" ART_ROOT="$ROOT_DIR/deployment/artifact" . "$BUILD_DIR/common.sh" usage() { cat <<'EOF' Build Argus Server Offline Package Usage: build_server_package.sh [--version YYYYMMDD] [--out DIR] [--resave-image] Outputs into deployment/artifact/server// by default. EOF } VERSION="$(today_version)" OUT_DIR="" RESAVE_IMAGE=false while [[ $# -gt 0 ]]; do case "$1" in --version) VERSION="$2"; shift 2;; --out) OUT_DIR="$2"; shift 2;; --resave-image) RESAVE_IMAGE=true; shift;; -h|--help) usage; exit 0;; *) err "unknown arg: $1"; usage; exit 1;; esac done PKG_DIR="${OUT_DIR:-$ART_ROOT/server/$VERSION}" STAGE="$(mktemp -d)" trap 'rm -rf "$STAGE"' EXIT log "Version: $VERSION" log "Staging: $STAGE" # 1) Layout make_dir "$STAGE/images" make_dir "$STAGE/compose" make_dir "$STAGE/scripts" make_dir "$STAGE/docs" make_dir "$STAGE/private/argus" # 2) Compose: derive from sys/tests by removing test-only services SRC_COMPOSE="$ROOT_DIR/src/sys/tests/docker-compose.yml" [[ -f "$SRC_COMPOSE" ]] || { err "missing $SRC_COMPOSE"; exit 1; } awk -f "$BUILD_DIR/templates/docker-compose.filter.awk" -v remove="node-a,node-b,test-node,test-gpu-node" "$SRC_COMPOSE" > "$STAGE/compose/docker-compose.yml" cp "$BUILD_DIR/templates/.env.example" "$STAGE/compose/.env.example" # fix relative private path to match package layout (compose/ and private/ are siblings) sed -i 's#\./private/#../private/#g' "$STAGE/compose/docker-compose.yml" # also handle bind mount form without trailing slash sed -i -E 's#- \./private:/private#- ../private:/private#g' "$STAGE/compose/docker-compose.yml" # drop timezone file bind which may not exist on target distros (e.g. NixOS) sed -i '/\/etc\/timezone:\/etc\/timezone:ro/d' "$STAGE/compose/docker-compose.yml" # sanity-check: ensure test services are absent if grep -E '^(\s{2})(node-a|node-b|test-node|test-gpu-node):\s*$' -n "$STAGE/compose/docker-compose.yml" >/dev/null; then err "compose filter failed: test services still present"; exit 1; fi # 3) Images (reuse if already exported unless --resave-image) existing_images_tar="$PKG_DIR/images/all-images.tar.gz" if [[ "$RESAVE_IMAGE" == false && -f "$existing_images_tar" ]]; then log "Reusing existing images tar: $existing_images_tar" cp "$existing_images_tar" "$STAGE/images/" else require_cmd docker gzip images=( argus-bind9:latest argus-master:latest argus-elasticsearch:latest argus-kibana:latest argus-metric-ftp:latest argus-metric-prometheus:latest argus-metric-grafana:latest argus-alertmanager:latest argus-web-frontend:latest argus-web-proxy:latest ) log "Saving images: ${#images[@]}" tarfile="$STAGE/images/all-images.tar" docker save -o "$tarfile" "${images[@]}" gzip -f "$tarfile" fi # 4) Scripts & Docs copy_tree "$BUILD_DIR/templates/scripts" "$STAGE/scripts" copy_tree "$BUILD_DIR/templates/docs" "$STAGE/docs" # 5) Manifests gen_manifest "$STAGE" "$STAGE/manifest.txt" checksum_dir "$STAGE" "$STAGE/checksums.txt" # 6) Move to artifact make_dir "$PKG_DIR" rsync -a "$STAGE/" "$PKG_DIR/" 2>/dev/null || cp -r "$STAGE/." "$PKG_DIR/" log "Server package ready: $PKG_DIR" echo "$VERSION" > "$PKG_DIR/version.json" # 7) Create distributable tarball OUT_TAR_DIR="$(dirname "$PKG_DIR")" OUT_TAR="$OUT_TAR_DIR/server_${VERSION}.tar.gz" log "Creating tarball: $OUT_TAR" (cd "$PKG_DIR/.." && tar -czf "$OUT_TAR" "$(basename "$PKG_DIR")") log "Tarball ready: $OUT_TAR" exit 0