PSA/ee/appliance/tests/kubernetes-hosted-fresh-install-smoke.sh
Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

140 lines
6.2 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'EOF'
Usage:
kubernetes-hosted-fresh-install-smoke.sh preflight --overlay-root <path>
kubernetes-hosted-fresh-install-smoke.sh verify --node-ip <ip> --token <token> --kubeconfig <path>
Preflight validates that a built ISO overlay contains the offline control-plane
assets needed before any registry/GitHub dependency.
Verify runs after booting a fresh ISO VM. It checks that the Kubernetes-hosted
setup UI/status API are reachable, the control-plane namespace is independent,
setup can be submitted, login-ready status is reached, and fallback reapply is
safe to run.
EOF
}
require_cmd() {
command -v "$1" >/dev/null 2>&1 || {
echo "missing required command: $1" >&2
exit 1
}
}
preflight() {
local overlay_root=""
while [ "$#" -gt 0 ]; do
case "$1" in
--overlay-root) overlay_root="$2"; shift 2 ;;
*) echo "unknown arg: $1" >&2; usage; exit 2 ;;
esac
done
[ -n "$overlay_root" ] || { echo "--overlay-root is required" >&2; exit 2; }
test -f "$overlay_root/opt/alga-appliance/control-plane/bundle.json"
test -f "$overlay_root/opt/alga-appliance/control-plane/manifests/kustomization.yaml"
test -f "$overlay_root/opt/alga-appliance/control-plane/manifests/workload.yaml"
test -f "$overlay_root/opt/alga-appliance/manifests/local-path-storage.yaml"
test -x "$overlay_root/opt/alga-appliance/bin/alga-control-plane-reapply"
test -x "$overlay_root/opt/alga-appliance/bin/k3s"
test -x "$overlay_root/opt/alga-appliance/scripts/bootstrap-control-plane.sh"
test -x "$overlay_root/opt/alga-appliance/scripts/install-storage.sh"
test -f "$overlay_root/etc/systemd/system/alga-appliance-bootstrap.service"
test -f "$overlay_root/etc/systemd/system/alga-host-agent.service"
test -f "$overlay_root/etc/sysusers.d/alga-appliance.conf"
grep -q 'After=local-fs.target cloud-final.service' "$overlay_root/etc/systemd/system/alga-appliance-console.service"
grep -q 'ALGA_APPLIANCE_CONSOLE_TTYS=/dev/tty1,/dev/console' "$overlay_root/etc/systemd/system/alga-appliance-console.service"
grep -q 'StandardOutput=journal' "$overlay_root/etc/systemd/system/alga-appliance-console.service"
! grep -q 'network-online.target' "$overlay_root/etc/systemd/system/alga-appliance-console.service"
! grep -q 'TTYReset=' "$overlay_root/etc/systemd/system/alga-appliance-console.service"
! grep -q 'TTYPath=' "$overlay_root/etc/systemd/system/alga-appliance-console.service"
! grep -q 'ExecStartPre=/usr/bin/env node /opt/alga-appliance/host-service/console.mjs' "$overlay_root/etc/systemd/system/alga-appliance-bootstrap.service"
grep -q 'ExecStartPost=/usr/bin/env node /opt/alga-appliance/host-service/console.mjs' "$overlay_root/etc/systemd/system/alga-appliance-bootstrap.service"
test -L "$overlay_root/etc/systemd/system/multi-user.target.wants/alga-appliance-bootstrap.service"
test -L "$overlay_root/etc/systemd/system/multi-user.target.wants/alga-host-agent.service"
test -L "$overlay_root/etc/systemd/system/alga-appliance.service"
compgen -G "$overlay_root/opt/alga-appliance/control-plane/images/*.tar" >/dev/null
echo "PASS: ISO overlay contains Kubernetes-hosted control-plane bootstrap assets"
}
http_code() {
local url="$1"
curl -sS -o /dev/null -w '%{http_code}' "$url" || true
}
verify() {
local node_ip=""
local token=""
local kubeconfig=""
local timeout_seconds=3600
while [ "$#" -gt 0 ]; do
case "$1" in
--node-ip) node_ip="$2"; shift 2 ;;
--token) token="$2"; shift 2 ;;
--kubeconfig) kubeconfig="$2"; shift 2 ;;
--timeout-seconds) timeout_seconds="$2"; shift 2 ;;
*) echo "unknown arg: $1" >&2; usage; exit 2 ;;
esac
done
[ -n "$node_ip" ] || { echo "--node-ip is required" >&2; exit 2; }
[ -n "$token" ] || { echo "--token is required" >&2; exit 2; }
[ -n "$kubeconfig" ] || { echo "--kubeconfig is required" >&2; exit 2; }
require_cmd curl
require_cmd kubectl
require_cmd jq
local kube=(kubectl --kubeconfig "$kubeconfig")
local base="http://${node_ip}:8080"
local health_url="${base}/healthz"
local setup_api_url="${base}/api/setup"
local status_url="${base}/api/status"
local cookie_jar; cookie_jar="$(mktemp)"
local mgmt_password="Str0ng!Pass"
local deadline=$((SECONDS + timeout_seconds))
# Readiness: /healthz is open (no session required).
until [ "$(http_code "$health_url")" = "200" ]; do
[ "$SECONDS" -lt "$deadline" ] || { echo "setup UI did not become reachable" >&2; exit 1; }
sleep 5
done
"${kube[@]}" -n alga-appliance-control-plane get deploy appliance-control-plane
"${kube[@]}" -n alga-appliance-control-plane get svc appliance-control-plane
"${kube[@]}" -n msp get deploy >/dev/null 2>&1 || true
# Authenticate: redeem the one-time setup token, then set the management
# password. The session cookie is stored in the jar and reused below.
curl -fsS -c "$cookie_jar" -X POST "${base}/api/auth/redeem-token" \
-H 'content-type: application/json' \
--data '{"token":"'"$token"'"}' >/dev/null
curl -fsS -c "$cookie_jar" -b "$cookie_jar" -X POST "${base}/api/auth/set-password" \
-H 'content-type: application/json' \
--data '{"token":"'"$token"'","password":"'"$mgmt_password"'"}' >/dev/null
curl -fsS -b "$cookie_jar" -X POST "$setup_api_url" \
-H 'content-type: application/json' \
--data '{"channel":"stable","appHostname":"http://'"$node_ip"':3000","dnsMode":"system","tenantName":"Acme MSP","adminFirstName":"Ava","adminLastName":"Admin","adminEmail":"ava@example.com","adminPassword":"Str0ng!Pass","adminPasswordConfirm":"Str0ng!Pass"}' >/dev/null
until curl -fsS -b "$cookie_jar" "$status_url" | jq -e '.rollup.state == "ready_to_log_in" or .rollup.state == "ready_with_background_issues"' >/dev/null; do
[ "$SECONDS" -lt "$deadline" ] || { echo "login-ready status was not reached" >&2; exit 1; }
sleep 10
done
"${kube[@]}" -n msp get secret appliance-initial-tenant
ssh "root@${node_ip}" /opt/alga-appliance/bin/alga-control-plane-reapply
curl -fsS -b "$cookie_jar" "$status_url" >/dev/null
echo "PASS: fresh ISO install reached Kubernetes-hosted setup and login-ready status"
}
case "${1:-}" in
preflight) shift; preflight "$@" ;;
verify) shift; verify "$@" ;;
-h|--help) usage ;;
*) usage; exit 2 ;;
esac