demo-stack.sh: - Add ensure_env() to create demo.env from template if missing - Add envsubst prerequisite check - Fix wait_healthy() to use docker inspect instead of fragile sed/awk parsing of docker ps output - Fix smoke_test() to use env vars instead of hardcoded ports - Remove fix_env() which overwrote TA_HOST with wrong value - Add MailHog SMTP port to display_summary() - Add service names to smoke test output demo-test.sh: - Fix security compliance test to expect only 1 socket mount (proxy only, now that Dockhand uses DOCKER_HOST) - Add Dockhand proxy routing check - Fix arithmetic increment operators for set -e compatibility - Remove scripts/fix-and-ship.sh (was identical copy of demo-stack.sh) 💘 Generated with Crush Assisted-by: GLM-5.1 via Crush <crush@charm.land>
245 lines
7.2 KiB
Bash
Executable File
245 lines
7.2 KiB
Bash
Executable File
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
DEMO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
ENV_FILE="$DEMO_DIR/demo.env"
|
|
ENV_TEMPLATE="$DEMO_DIR/demo.env.template"
|
|
TEMPLATE_FILE="$DEMO_DIR/docker-compose.yml.template"
|
|
COMPOSE_FILE="$DEMO_DIR/docker-compose.yml"
|
|
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m'
|
|
|
|
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
|
log_success() { echo -e "${GREEN}[OK]${NC} $1"; }
|
|
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
|
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
|
|
|
ensure_env() {
|
|
if [[ ! -f "$ENV_FILE" ]]; then
|
|
if [[ -f "$ENV_TEMPLATE" ]]; then
|
|
log_info "Creating demo.env from template..."
|
|
cp "$ENV_TEMPLATE" "$ENV_FILE"
|
|
else
|
|
log_error "No demo.env or demo.env.template found"
|
|
exit 1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
detect_user() {
|
|
log_info "Detecting user IDs..."
|
|
local uid gid docker_gid
|
|
uid=$(id -u)
|
|
gid=$(id -g)
|
|
docker_gid=$(getent group docker | cut -d: -f3)
|
|
sed -i "s/^DEMO_UID=.*/DEMO_UID=$uid/" "$ENV_FILE"
|
|
sed -i "s/^DEMO_GID=.*/DEMO_GID=$gid/" "$ENV_FILE"
|
|
sed -i "s/^DEMO_DOCKER_GID=.*/DEMO_DOCKER_GID=$docker_gid/" "$ENV_FILE"
|
|
log_success "UID=$uid GID=$gid DockerGID=$docker_gid"
|
|
}
|
|
|
|
check_prerequisites() {
|
|
log_info "Checking prerequisites..."
|
|
if ! docker info >/dev/null 2>&1; then
|
|
log_error "Docker is not running"
|
|
exit 1
|
|
fi
|
|
if ! command -v envsubst >/dev/null 2>&1; then
|
|
log_error "envsubst not found (install gettext package)"
|
|
exit 1
|
|
fi
|
|
local max_map_count
|
|
max_map_count=$(sysctl -n vm.max_map_count 2>/dev/null || echo "0")
|
|
if [[ "$max_map_count" -lt 262144 ]]; then
|
|
log_warn "Setting vm.max_map_count=262144 for Elasticsearch..."
|
|
if sudo sysctl -w vm.max_map_count=262144 2>/dev/null; then
|
|
log_success "vm.max_map_count set"
|
|
else
|
|
log_warn "Could not set vm.max_map_count (TubeArchivist ES may fail)"
|
|
fi
|
|
fi
|
|
log_success "Prerequisites OK"
|
|
}
|
|
|
|
generate_compose() {
|
|
log_info "Generating docker-compose.yml from template..."
|
|
set -a; source "$ENV_FILE"; set +a
|
|
envsubst < "$TEMPLATE_FILE" > "$COMPOSE_FILE"
|
|
log_success "docker-compose.yml generated"
|
|
}
|
|
|
|
deploy_stack() {
|
|
log_info "Deploying TSYS Developer Support Stack..."
|
|
cd "$DEMO_DIR"
|
|
docker compose up -d 2>&1
|
|
log_success "Stack deployment initiated"
|
|
}
|
|
|
|
wait_healthy() {
|
|
log_info "Waiting for services to become healthy (max 5 min)..."
|
|
local elapsed=0 interval=15
|
|
while [[ $elapsed -lt 300 ]]; do
|
|
local unhealthy=0
|
|
while IFS= read -r name; do
|
|
local health
|
|
health=$(docker inspect --format='{{.State.Health.Status}}' "$name" 2>/dev/null || echo "unknown")
|
|
if [[ "$health" != "healthy" ]]; then
|
|
unhealthy=$((unhealthy + 1))
|
|
fi
|
|
done < <(docker ps --filter "name=${COMPOSE_PROJECT_NAME:-kneldevstack}" --format '{{.Names}}' 2>/dev/null)
|
|
|
|
if [[ $unhealthy -eq 0 ]]; then
|
|
log_success "All services healthy"
|
|
return 0
|
|
fi
|
|
log_info " $unhealthy services not yet healthy (${elapsed}s elapsed)"
|
|
sleep $interval
|
|
elapsed=$((elapsed + interval))
|
|
done
|
|
log_warn "Timeout - some services may not be fully healthy"
|
|
cd "$DEMO_DIR" && docker compose ps
|
|
}
|
|
|
|
display_summary() {
|
|
set -a; source "$ENV_FILE"; set +a
|
|
echo ""
|
|
echo "========================================================"
|
|
echo " TSYS Developer Support Stack - Deployment Summary"
|
|
echo "========================================================"
|
|
echo ""
|
|
echo " Infrastructure:"
|
|
echo " Homepage Dashboard http://localhost:${HOMEPAGE_PORT}"
|
|
echo " Pi-hole (DNS) http://localhost:${PIHOLE_PORT}"
|
|
echo " Dockhand (Docker) http://localhost:${DOCKHAND_PORT}"
|
|
echo ""
|
|
echo " Monitoring:"
|
|
echo " InfluxDB http://localhost:${INFLUXDB_PORT}"
|
|
echo " Grafana http://localhost:${GRAFANA_PORT}"
|
|
echo ""
|
|
echo " Documentation:"
|
|
echo " Draw.io http://localhost:${DRAWIO_PORT}"
|
|
echo " Kroki http://localhost:${KROKI_PORT}"
|
|
echo ""
|
|
echo " Developer Tools:"
|
|
echo " Atomic Tracker http://localhost:${ATOMIC_TRACKER_PORT}"
|
|
echo " ArchiveBox http://localhost:${ARCHIVEBOX_PORT}"
|
|
echo " Tube Archivist http://localhost:${TUBE_ARCHIVIST_PORT}"
|
|
echo " Wakapi http://localhost:${WAKAPI_PORT}"
|
|
echo " MailHog (Web) http://localhost:${MAILHOG_PORT}"
|
|
echo " MailHog (SMTP) localhost:${MAILHOG_SMTP_PORT}"
|
|
echo " Atuin http://localhost:${ATUIN_PORT}"
|
|
echo ""
|
|
echo " Credentials: admin / demo_password"
|
|
echo " FOR DEMONSTRATION PURPOSES ONLY"
|
|
echo "========================================================"
|
|
}
|
|
|
|
smoke_test() {
|
|
log_info "Running smoke tests..."
|
|
set -a; source "$ENV_FILE"; set +a
|
|
local ports=(
|
|
"${HOMEPAGE_PORT}:Homepage"
|
|
"${PIHOLE_PORT}:Pi-hole"
|
|
"${DOCKHAND_PORT}:Dockhand"
|
|
"${INFLUXDB_PORT}:InfluxDB"
|
|
"${GRAFANA_PORT}:Grafana"
|
|
"${DRAWIO_PORT}:Draw.io"
|
|
"${KROKI_PORT}:Kroki"
|
|
"${ATOMIC_TRACKER_PORT}:AtomicTracker"
|
|
"${ARCHIVEBOX_PORT}:ArchiveBox"
|
|
"${TUBE_ARCHIVIST_PORT}:TubeArchivist"
|
|
"${WAKAPI_PORT}:Wakapi"
|
|
"${MAILHOG_PORT}:MailHog"
|
|
"${ATUIN_PORT}:Atuin"
|
|
)
|
|
local pass=0 fail=0
|
|
for pt in "${ports[@]}"; do
|
|
local port="${pt%:*}"
|
|
local svc="${pt#*:}"
|
|
if timeout 5 bash -c "echo > /dev/tcp/localhost/$port" 2>/dev/null; then
|
|
log_success "$svc (:$port)"
|
|
((pass++)) || true
|
|
else
|
|
log_error "$svc (:$port) NOT accessible"
|
|
((fail++)) || true
|
|
fi
|
|
done
|
|
echo ""
|
|
echo "SMOKE TEST: $pass passed, $fail failed"
|
|
}
|
|
|
|
stop_stack() {
|
|
log_info "Stopping stack..."
|
|
cd "$DEMO_DIR"
|
|
docker compose down 2>&1
|
|
log_success "Stack stopped"
|
|
}
|
|
|
|
show_status() {
|
|
cd "$DEMO_DIR"
|
|
docker compose ps
|
|
}
|
|
|
|
show_usage() {
|
|
echo "TSYS Developer Support Stack"
|
|
echo ""
|
|
echo "Usage: $0 {deploy|stop|restart|status|smoke|summary|help}"
|
|
echo ""
|
|
echo "Commands:"
|
|
echo " deploy Deploy the complete stack"
|
|
echo " stop Stop all services"
|
|
echo " restart Stop and redeploy"
|
|
echo " status Show service status"
|
|
echo " smoke Run port accessibility tests"
|
|
echo " summary Show service URLs"
|
|
echo " help Show this help"
|
|
}
|
|
|
|
ensure_env
|
|
|
|
case "${1:-deploy}" in
|
|
deploy)
|
|
detect_user
|
|
check_prerequisites
|
|
generate_compose
|
|
deploy_stack
|
|
wait_healthy
|
|
display_summary
|
|
smoke_test
|
|
;;
|
|
stop)
|
|
stop_stack
|
|
;;
|
|
restart)
|
|
stop_stack
|
|
sleep 5
|
|
detect_user
|
|
check_prerequisites
|
|
generate_compose
|
|
deploy_stack
|
|
wait_healthy
|
|
display_summary
|
|
;;
|
|
status)
|
|
show_status
|
|
;;
|
|
smoke)
|
|
smoke_test
|
|
;;
|
|
summary)
|
|
display_summary
|
|
;;
|
|
help|--help|-h)
|
|
show_usage
|
|
;;
|
|
*)
|
|
log_error "Unknown command: $1"
|
|
show_usage
|
|
exit 1
|
|
;;
|
|
esac
|