chore: sync installers from triton v1.0.0-rc.1

This commit is contained in:
github-actions[bot] 2026-05-20 15:01:09 +00:00
parent 1d635a9338
commit 4057cebb27
5 changed files with 35 additions and 124 deletions

View file

@ -64,7 +64,6 @@ services:
volumes: volumes:
- triton-manage-bins:/bins - triton-manage-bins:/bins
- ${TLS_CERT_HOST_DIR:-/etc/triton/tls}:/etc/triton/tls:ro - ${TLS_CERT_HOST_DIR:-/etc/triton/tls}:/etc/triton/tls:ro
- /etc/machine-id:/etc/machine-id:ro
ports: ports:
- "${TRITON_MANAGE_HOST_PORT:-8082}:8082" - "${TRITON_MANAGE_HOST_PORT:-8082}:8082"
- "${TRITON_MANAGE_GATEWAY_HOST_PORT:-8443}:8443" - "${TRITON_MANAGE_GATEWAY_HOST_PORT:-8443}:8443"

View file

@ -54,18 +54,5 @@ TLS_CERT_HOST_DIR=/etc/triton/tls
# ─── Sessions ──────────────────────────────────────────────────────────── # ─── Sessions ────────────────────────────────────────────────────────────
TRITON_MANAGE_SESSION_TTL=24h TRITON_MANAGE_SESSION_TTL=24h
# ─── Licence ─────────────────────────────────────────────────────────────
# Offline licence token from your vendor bundle (license.lic). Set by
# install.sh automatically — do not edit manually.
TRITON_LICENSE_KEY=
# Vendor's Ed25519 public key (64 hex chars). Baked into the image at
# build time — leave empty unless you need to override the compiled-in key.
TRITON_MANAGE_LICENSE_SERVER_PUBKEY=
# Vendor's License Server URL. Optional — enables ongoing heartbeats and
# binary sync. Leave empty for fully air-gapped deployments.
TRITON_LICENSE_SERVER_URL=
# ─── Image ─────────────────────────────────────────────────────────────── # ─── Image ───────────────────────────────────────────────────────────────
TRITON_MANAGE_IMAGE=ghcr.io/primatekuntech/triton-manage-server:latest TRITON_MANAGE_IMAGE=ghcr.io/primatekuntech/triton-manage-server:latest

View file

@ -5,40 +5,30 @@
# Container-based via Podman or Docker (auto-detected). # Container-based via Podman or Docker (auto-detected).
# #
# Usage: # Usage:
# sudo bash install.sh --license-file /path/to/bundle/license.lic # sudo bash install.sh
# #
# The license bundle (provided by your vendor) is a single file: # Flags (all optional):
# license.lic — signed offline licence token
# The vendor's public key is baked into the image at build time.
#
# Flags:
# --license-file PATH Path to license.lic from your vendor bundle. Required.
# --gateway-hostname HOST Agent mTLS hostname (defaults to current FQDN). # --gateway-hostname HOST Agent mTLS hostname (defaults to current FQDN).
# --manage-host-ip IP Host LAN IP — used for "+ This machine". # --manage-host-ip IP Host LAN IP — used for "+ This machine".
# --port PORT Host port for the web UI (default: 8082).
# --image TAG Pin a specific manage-server image tag. # --image TAG Pin a specific manage-server image tag.
# --no-tls Skip the TLS-required sanity check (dev). # --no-tls Skip the TLS-required sanity check (dev).
set -euo pipefail set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]:-$0}")" &>/dev/null && pwd)" SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
cd "$SCRIPT_DIR" cd "$SCRIPT_DIR"
info() { printf '[manage-server] %s\n' "$*"; } info() { printf '[manage-server] %s\n' "$*"; }
die() { printf '[manage-server] error: %s\n' "$*" >&2; exit 1; } die() { printf '[manage-server] error: %s\n' "$*" >&2; exit 1; }
# ── arg parsing ────────────────────────────────────────────────────────── # ── arg parsing ──────────────────────────────────────────────────────────
LICENSE_FILE=""
GATEWAY_HOST="" GATEWAY_HOST=""
HOST_IP="" HOST_IP=""
PORT=""
IMAGE="" IMAGE=""
NO_TLS=0 NO_TLS=0
while [[ $# -gt 0 ]]; do while [[ $# -gt 0 ]]; do
case "$1" in case "$1" in
--license-file) LICENSE_FILE="$2"; shift 2 ;;
--gateway-hostname) GATEWAY_HOST="$2"; shift 2 ;; --gateway-hostname) GATEWAY_HOST="$2"; shift 2 ;;
--manage-host-ip) HOST_IP="$2"; shift 2 ;; --manage-host-ip) HOST_IP="$2"; shift 2 ;;
--port) PORT="$2"; shift 2 ;;
--image) IMAGE="$2"; shift 2 ;; --image) IMAGE="$2"; shift 2 ;;
--no-tls) NO_TLS=1; shift ;; --no-tls) NO_TLS=1; shift ;;
-h|--help) grep '^#' "$0" | sed 's/^# //;s/^#//'; exit 0 ;; -h|--help) grep '^#' "$0" | sed 's/^# //;s/^#//'; exit 0 ;;
@ -48,12 +38,6 @@ done
[[ $EUID -eq 0 ]] || die "must run as root" [[ $EUID -eq 0 ]] || die "must run as root"
# ── validate license bundle ──────────────────────────────────────────────
[[ -n "$LICENSE_FILE" ]] || die "--license-file is required (path to license.lic from your vendor bundle)"
[[ -f "$LICENSE_FILE" ]] || die "license file not found: $LICENSE_FILE"
LICENSE_TOKEN="$(cat "$LICENSE_FILE")"
# ── runtime detection ──────────────────────────────────────────────────── # ── runtime detection ────────────────────────────────────────────────────
if command -v podman-compose >/dev/null 2>&1; then if command -v podman-compose >/dev/null 2>&1; then
COMPOSE=(podman-compose) COMPOSE=(podman-compose)
@ -87,14 +71,10 @@ if [[ ! -f "$ENV_FILE" ]]; then
-e "s|^TRITON_MANAGE_WORKER_KEY=.*|TRITON_MANAGE_WORKER_KEY=$WORKER_KEY|" \ -e "s|^TRITON_MANAGE_WORKER_KEY=.*|TRITON_MANAGE_WORKER_KEY=$WORKER_KEY|" \
-e "s|^TRITON_VAULT_KEY=.*|TRITON_VAULT_KEY=$VAULT_KEY|" \ -e "s|^TRITON_VAULT_KEY=.*|TRITON_VAULT_KEY=$VAULT_KEY|" \
"$ENV_FILE" "$ENV_FILE"
info "secrets generated" info "vault key generated (PostgreSQL AES-256-GCM)"
sed -i "s|^TRITON_LICENSE_KEY=.*|TRITON_LICENSE_KEY=$LICENSE_TOKEN|" "$ENV_FILE"
info "licence configured"
[[ -n "$GATEWAY_HOST" ]] && sed -i "s|^TRITON_MANAGE_GATEWAY_HOSTNAME=.*|TRITON_MANAGE_GATEWAY_HOSTNAME=$GATEWAY_HOST|" "$ENV_FILE" [[ -n "$GATEWAY_HOST" ]] && sed -i "s|^TRITON_MANAGE_GATEWAY_HOSTNAME=.*|TRITON_MANAGE_GATEWAY_HOSTNAME=$GATEWAY_HOST|" "$ENV_FILE"
[[ -n "$HOST_IP" ]] && sed -i "s|^TRITON_MANAGE_HOST_IP=.*|TRITON_MANAGE_HOST_IP=$HOST_IP|" "$ENV_FILE" [[ -n "$HOST_IP" ]] && sed -i "s|^TRITON_MANAGE_HOST_IP=.*|TRITON_MANAGE_HOST_IP=$HOST_IP|" "$ENV_FILE"
[[ -n "$PORT" ]] && sed -i "s|^TRITON_MANAGE_HOST_PORT=.*|TRITON_MANAGE_HOST_PORT=$PORT|" "$ENV_FILE"
[[ -n "$IMAGE" ]] && sed -i "s|^TRITON_MANAGE_IMAGE=.*|TRITON_MANAGE_IMAGE=$IMAGE|" "$ENV_FILE" [[ -n "$IMAGE" ]] && sed -i "s|^TRITON_MANAGE_IMAGE=.*|TRITON_MANAGE_IMAGE=$IMAGE|" "$ENV_FILE"
info ".env created at $ENV_FILE" info ".env created at $ENV_FILE"
@ -103,10 +83,6 @@ else
info "reusing existing .env at $ENV_FILE" info "reusing existing .env at $ENV_FILE"
fi fi
# ── pull latest image ────────────────────────────────────────────────────
info "pulling latest image..."
"${COMPOSE[@]}" --env-file "$ENV_FILE" pull manage-server
# ── start ──────────────────────────────────────────────────────────────── # ── start ────────────────────────────────────────────────────────────────
info "starting containers..." info "starting containers..."
"${COMPOSE[@]}" --env-file "$ENV_FILE" up -d "${COMPOSE[@]}" --env-file "$ENV_FILE" up -d
@ -118,6 +94,7 @@ HOST_PORT=${HOST_PORT:-8082}
info "waiting for manage server to become healthy on :${HOST_PORT}..." info "waiting for manage server to become healthy on :${HOST_PORT}..."
for i in $(seq 1 30); do for i in $(seq 1 30); do
CODE=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:${HOST_PORT}/" || echo "000") CODE=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:${HOST_PORT}/" || echo "000")
# 302 (redirect to setup or login) means the server is up.
if [[ "$CODE" == "302" || "$CODE" == "200" ]]; then if [[ "$CODE" == "302" || "$CODE" == "200" ]]; then
info "manage server is up" info "manage server is up"
break break
@ -128,29 +105,9 @@ done
info "" info ""
info "Installation complete. Next steps:" info "Installation complete. Next steps:"
info " 1. Open http://localhost:${HOST_PORT} (or your public URL)" info " 1. Open http://localhost:${HOST_PORT} (or your public URL)"
info " 2. Complete the setup wizard" info " 2. Complete the setup wizard:"
info " - Set your manage server name"
info " - Enter your Triton licence server URL and licence ID"
info " - Or upload an air-gap licence file"
info " 3. Configure TLS via reverse proxy (see docs)" info " 3. Configure TLS via reverse proxy (see docs)"
info "" info ""
# ── machine ID ───────────────────────────────────────────────────────────
# Print the SHA-3-256 hash of /etc/machine-id so the customer can share
# it with the vendor when requesting an offline .lic bound to this host.
# The hash is stable: /etc/machine-id never changes after OS installation.
if [[ -f /etc/machine-id ]]; then
MACHINE_ID_RAW=$(cat /etc/machine-id | tr -d '[:space:]')
if command -v python3 >/dev/null 2>&1; then
MACHINE_ID_HASH=$(python3 -c "import hashlib; print(hashlib.sha3_256('${MACHINE_ID_RAW}'.encode()).hexdigest())")
elif command -v sha3sum >/dev/null 2>&1; then
MACHINE_ID_HASH=$(echo -n "$MACHINE_ID_RAW" | sha3sum -a 256 | awk '{print $1}')
elif command -v openssl >/dev/null 2>&1; then
MACHINE_ID_HASH=$(printf '%s' "${MACHINE_ID_RAW}" | openssl dgst -sha3-256 -hex 2>/dev/null | awk '{print $2}')
else
MACHINE_ID_HASH=""
fi
if [[ -n "$MACHINE_ID_HASH" ]]; then
info "── Host Machine ID ──────────────────────────────────────────────────────"
info " Provide this value to your vendor when requesting a host-bound .lic file."
info " Machine ID (SHA-3-256): $MACHINE_ID_HASH"
info "────────────────────────────────────────────────────────────────────────"
fi
fi

View file

@ -1,15 +1,15 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# uninstall.sh — stop and remove Manage Server containers and image. # uninstall.sh — stop and remove Manage Server containers.
# #
# By default, KEEPS the PostgreSQL volume (scan history, hosts, users). # By default, KEEPS the PostgreSQL volume (scan history, hosts, users).
# Pass --purge-data to delete the volumes as well — irreversible. # Pass --purge-data to delete the volumes as well — irreversible.
# #
# Usage: # Usage:
# sudo bash uninstall.sh # stop + remove containers + image, keep DB # sudo bash uninstall.sh # stop + remove containers, keep DB
# sudo bash uninstall.sh --purge-data # also delete DB + binaries volume # sudo bash uninstall.sh --purge-data # also delete DB + binaries volume
set -euo pipefail set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]:-$0}")" &>/dev/null && pwd)" SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
cd "$SCRIPT_DIR" cd "$SCRIPT_DIR"
info() { printf '[manage-server] %s\n' "$*"; } info() { printf '[manage-server] %s\n' "$*"; }
@ -39,15 +39,11 @@ else
podman rm -f triton-manageserver triton-manage-db 2>/dev/null || true podman rm -f triton-manageserver triton-manage-db 2>/dev/null || true
fi fi
# ── remove image ──────────────────────────────────────────────────────────
IMAGE=$(grep -E '^TRITON_MANAGE_IMAGE=' .env 2>/dev/null | cut -d= -f2)
IMAGE=${IMAGE:-ghcr.io/primatekuntech/triton-manage-server:latest}
info "removing image ${IMAGE}..."
podman rmi "$IMAGE" 2>/dev/null || docker rmi "$IMAGE" 2>/dev/null || true
if [[ $PURGE -eq 1 ]]; then if [[ $PURGE -eq 1 ]]; then
info "DESTRUCTIVE: removing manage server volumes..." info "DESTRUCTIVE: removing manage server volumes..."
info " this deletes: scan history, hosts, users, worker binaries" info " this deletes: scan history, hosts, users, worker binaries"
read -r -p " Are you sure? Type 'yes' to confirm: " CONFIRM
[[ "$CONFIRM" == "yes" ]] || die "aborted"
for vol in triton-manage-db-data triton-manage-bins; do for vol in triton-manage-db-data triton-manage-bins; do
podman volume rm -f "$vol" 2>/dev/null \ podman volume rm -f "$vol" 2>/dev/null \
|| docker volume rm -f "$vol" 2>/dev/null \ || docker volume rm -f "$vol" 2>/dev/null \

View file

@ -1,16 +1,14 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# upgrade.sh — pull the latest manage-server image and restart. # upgrade.sh — pull the latest manage-server image and restart.
# #
# Takes a pre-upgrade pg_dump backup. DB schema migrations run automatically # Takes a pre-upgrade pg_dump. DB schema migrations run on startup.
# on container startup — no manual migration step required.
# #
# Usage: # Usage:
# sudo bash upgrade.sh # latest from ghcr.io # sudo bash upgrade.sh # latest from ghcr.io
# sudo bash upgrade.sh --image TAG # pin a specific image tag # sudo bash upgrade.sh --image TAG # pin a specific image
# sudo bash upgrade.sh --port PORT # change the web UI host port
set -euo pipefail set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]:-$0}")" &>/dev/null && pwd)" SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
cd "$SCRIPT_DIR" cd "$SCRIPT_DIR"
info() { printf '[manage-server] %s\n' "$*"; } info() { printf '[manage-server] %s\n' "$*"; }
@ -19,74 +17,48 @@ die() { printf '[manage-server] error: %s\n' "$*" >&2; exit 1; }
[[ $EUID -eq 0 ]] || die "must run as root" [[ $EUID -eq 0 ]] || die "must run as root"
[[ -f .env ]] || die ".env not found — run install.sh first" [[ -f .env ]] || die ".env not found — run install.sh first"
# ── arg parsing ───────────────────────────────────────────────────────────
IMAGE="" IMAGE=""
PORT=""
while [[ $# -gt 0 ]]; do while [[ $# -gt 0 ]]; do
case "$1" in case "$1" in
--image) IMAGE="$2"; shift 2 ;; --image) IMAGE="$2"; shift 2 ;;
--port) PORT="$2"; shift 2 ;;
-h|--help) grep '^#' "$0" | sed 's/^# //;s/^#//'; exit 0 ;; -h|--help) grep '^#' "$0" | sed 's/^# //;s/^#//'; exit 0 ;;
*) die "unknown flag: $1" ;; *) die "unknown flag: $1" ;;
esac esac
done done
# ── runtime detection ─────────────────────────────────────────────────────
if command -v podman-compose >/dev/null 2>&1; then COMPOSE=(podman-compose); RUNTIME=podman
elif podman compose version >/dev/null 2>&1; then COMPOSE=(podman compose); RUNTIME=podman
elif docker compose version >/dev/null 2>&1; then COMPOSE=(docker compose); RUNTIME=docker
else die "no compose runtime found"; fi
# ── pin image if requested ────────────────────────────────────────────────
if [[ -n "$IMAGE" ]]; then if [[ -n "$IMAGE" ]]; then
sed -i "s|^TRITON_MANAGE_IMAGE=.*|TRITON_MANAGE_IMAGE=$IMAGE|" .env sed -i "s|^TRITON_MANAGE_IMAGE=.*|TRITON_MANAGE_IMAGE=$IMAGE|" .env
info "pinned image to $IMAGE" info "pinned image to $IMAGE"
fi fi
if [[ -n "$PORT" ]]; then
sed -i "s|^TRITON_MANAGE_HOST_PORT=.*|TRITON_MANAGE_HOST_PORT=$PORT|" .env
info "host port set to $PORT"
fi
# ── pre-upgrade DB backup ───────────────────────────────────────────────── if command -v podman-compose >/dev/null 2>&1; then COMPOSE=(podman-compose)
case "$(uname -s)" in elif podman compose version >/dev/null 2>&1; then COMPOSE=(podman compose)
Linux) BACKUP_DIR="/var/backups/triton" ;; elif docker compose version >/dev/null 2>&1; then COMPOSE=(docker compose)
Darwin) BACKUP_DIR="${HOME}/Library/Application Support/triton/backups" ;; else die "no compose runtime found"; fi
*) BACKUP_DIR="$SCRIPT_DIR/backups" ;;
esac
mkdir -p "$BACKUP_DIR"
DUMP_FILE="${BACKUP_DIR}/manage-pre-upgrade-$(date +%F-%H%M%S).sql.gz"
info "pre-upgrade DB backup..." info "pre-upgrade DB backup..."
PG_USER=$(grep -E '^POSTGRES_USER=' .env | cut -d= -f2) mkdir -p /var/backups/triton
PG_USER=${PG_USER:-triton} DUMP_FILE="/var/backups/triton/manage-pre-upgrade-$(date +%F-%H%M%S).sql.gz"
PG_DB=$(grep -E '^POSTGRES_DB=' .env | cut -d= -f2) podman exec triton-manage-db pg_dump -U triton triton_manage 2>/dev/null \
PG_DB=${PG_DB:-triton_manage} | gzip > "$DUMP_FILE" || die "pg_dump failed — aborting upgrade"
info " saved: $DUMP_FILE"
"$RUNTIME" exec triton-manage-db pg_dump -U "$PG_USER" "$PG_DB" 2>/dev/null \
| gzip > "$DUMP_FILE" || die "pg_dump failed — aborting upgrade (DB container may not be running)"
info " backup saved: $DUMP_FILE"
# ── pull new image ────────────────────────────────────────────────────────
info "pulling latest image..." info "pulling latest image..."
"${COMPOSE[@]}" --env-file .env pull manage-server "${COMPOSE[@]}" --env-file .env pull manage-server
# ── recreate container (DB migrations run on startup) ─────────────────────
info "recreating manage-server container..." info "recreating manage-server container..."
info " DB schema migrations will run automatically on startup"
"${COMPOSE[@]}" --env-file .env up -d --no-deps manage-server "${COMPOSE[@]}" --env-file .env up -d --no-deps manage-server
# ── wait for healthy (confirms migrations succeeded) ──────────────────────
HOST_PORT=$(grep -E '^TRITON_MANAGE_HOST_PORT=' .env | cut -d= -f2) HOST_PORT=$(grep -E '^TRITON_MANAGE_HOST_PORT=' .env | cut -d= -f2)
HOST_PORT=${HOST_PORT:-8082} HOST_PORT=${HOST_PORT:-8082}
info "waiting for server to become healthy on :${HOST_PORT}..." info "waiting for new container to become healthy..."
for i in $(seq 1 30); do for i in $(seq 1 30); do
CODE=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:${HOST_PORT}/" || echo "000") CODE=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:${HOST_PORT}/" || echo "000")
if [[ "$CODE" == "302" || "$CODE" == "200" ]]; then if [[ "$CODE" == "302" || "$CODE" == "200" ]]; then
info "upgrade complete — server is healthy (migrations applied)" info "upgrade complete"
info " rollback if needed: gunzip -c ${DUMP_FILE} | $RUNTIME exec -i triton-manage-db psql -U ${PG_USER} ${PG_DB}"
exit 0 exit 0
fi fi
sleep 2 sleep 2
done done
die "server did not become healthy in 60s — check logs: $RUNTIME logs triton-manageserver" die "new container did not become healthy in 60s — check logs"