platform-deployments/provisioning/modules/black.sh
2026-03-05 18:57:06 -08:00

279 lines
7.7 KiB
Bash
Executable file

#!/usr/bin/env bash
#
# black.sh — black-specific provisioning (10.0.0.11, Ubuntu 24.04)
#
# Black is the devops + staging host. This module verifies/configures:
# - dnsmasq (systemd, DNS server)
# - nginx (docker reverse proxy)
# - Docker stack (forgejo, verdaccio, runner, restic, serpbear, sso)
# - PM2 services (landing-api, status-dashboard)
# - systemd services (marketplace-api, messenger-imessage, host-status-monitor)
# - PostgreSQL
# - NFS
# - Self-DNS (resolved drop-in pointing to 127.0.0.1)
#
BIGDISK="/bigdisk/forgejo"
COMPOSE_FILE="$BIGDISK/docker-compose.yml"
# Expected docker containers from the compose stack
EXPECTED_CONTAINERS=(
forgejo
forgejo-nginx
forgejo-runner
verdaccio
restic-rest-server
serpbear
sso-api
sso-postgres
sso-redis
)
# Expected PM2 processes
EXPECTED_PM2=(
landing-api
webmap-router
status-dashboard-api
status-dashboard-frontend
)
# Expected systemd services
EXPECTED_SYSTEMD=(
dnsmasq
postgresql
nfs-server
marketplace-api
messenger-imessage
host-status-monitor
)
# ============================================================================
# Self-DNS (black IS the DNS server)
# ============================================================================
_black_self_dns() {
log_section "Self-DNS (resolved → 127.0.0.1)"
local conf_dir="/etc/systemd/resolved.conf.d"
local conf_file="$conf_dir/lan.conf"
if [[ -f "$conf_file" ]] && grep -q "DNS=127.0.0.1" "$conf_file" 2>/dev/null; then
log_info "Self-DNS already configured (127.0.0.1)"
return 0
fi
if [[ "${CHECK_ONLY:-false}" == "true" ]]; then
log_warn "Self-DNS not configured"
return 1
fi
log_step "Configuring resolved to use local dnsmasq..."
sudo mkdir -p "$conf_dir"
sudo tee "$conf_file" >/dev/null <<EOF
[Resolve]
DNS=127.0.0.1
Domains=~nasty.sh ~black.local ~apricot.local
EOF
sudo systemctl restart systemd-resolved
log_info "Self-DNS configured"
}
# ============================================================================
# dnsmasq
# ============================================================================
_black_dnsmasq() {
log_section "dnsmasq (DNS Server)"
local dnsmasq_conf="/etc/dnsmasq.d/lan.conf"
if systemctl is-active dnsmasq &>/dev/null; then
log_info "dnsmasq is active"
else
log_error "dnsmasq is NOT active"
if [[ "${CHECK_ONLY:-false}" != "true" ]]; then
log_step "Starting dnsmasq..."
sudo systemctl enable --now dnsmasq
fi
fi
if [[ -f "$dnsmasq_conf" ]]; then
log_info "dnsmasq config exists: $dnsmasq_conf"
else
log_warn "dnsmasq config missing: $dnsmasq_conf"
fi
# Verify DNS is answering
if command -v dig &>/dev/null; then
if dig +short forge.black.local @127.0.0.1 2>/dev/null | grep -q "10.0.0.11"; then
log_info "dnsmasq resolving forge.black.local correctly"
else
log_warn "dnsmasq not resolving forge.black.local"
fi
fi
}
# ============================================================================
# nginx (docker)
# ============================================================================
_black_nginx() {
log_section "nginx (Docker Reverse Proxy)"
if docker ps --format '{{.Names}}' 2>/dev/null | grep -q "forgejo-nginx"; then
log_info "nginx container running"
# Test config
local test_result
test_result=$(docker exec forgejo-nginx nginx -t 2>&1)
if echo "$test_result" | grep -q "successful"; then
log_info "nginx config valid"
else
log_error "nginx config invalid:"
echo "$test_result"
fi
# List vhosts
log_step "Active vhost configs:"
docker exec forgejo-nginx ls /etc/nginx/conf.d/ 2>/dev/null | while read -r f; do
echo " $f"
done
else
log_error "nginx container NOT running"
fi
}
# ============================================================================
# Docker stack
# ============================================================================
_black_docker_stack() {
log_section "Docker Stack"
if [[ ! -f "$COMPOSE_FILE" ]]; then
log_error "docker-compose.yml not found: $COMPOSE_FILE"
return 1
fi
local running
running=$(docker ps --format '{{.Names}}' 2>/dev/null)
for container in "${EXPECTED_CONTAINERS[@]}"; do
if echo "$running" | grep -q "^${container}$"; then
log_info "Container: $container"
else
log_error "Container NOT running: $container"
if [[ "${CHECK_ONLY:-false}" != "true" ]]; then
log_step "Attempting to start docker stack..."
(cd "$BIGDISK" && docker compose up -d)
break
fi
fi
done
}
# ============================================================================
# PM2 services
# ============================================================================
_black_pm2() {
log_section "PM2 Services"
if ! command -v pm2 &>/dev/null; then
log_error "pm2 not found"
return 1
fi
local pm2_list
pm2_list=$(pm2 jlist 2>/dev/null || echo "[]")
for proc in "${EXPECTED_PM2[@]}"; do
local status
status=$(echo "$pm2_list" | python3 -c "
import json, sys
data = json.load(sys.stdin)
for p in data:
if p.get('name') == '$proc':
print(p.get('pm2_env', {}).get('status', 'unknown'))
break
else:
print('missing')
" 2>/dev/null || echo "error")
case "$status" in
online) log_info "PM2: $proc (online)" ;;
stopped) log_warn "PM2: $proc (stopped)" ;;
missing) log_error "PM2: $proc (not registered)" ;;
*) log_warn "PM2: $proc ($status)" ;;
esac
done
}
# ============================================================================
# systemd services
# ============================================================================
_black_systemd() {
log_section "Systemd Services"
for svc in "${EXPECTED_SYSTEMD[@]}"; do
if systemctl is-active "$svc" &>/dev/null; then
log_info "systemd: $svc (active)"
elif systemctl is-enabled "$svc" &>/dev/null; then
log_warn "systemd: $svc (enabled but inactive)"
if [[ "${CHECK_ONLY:-false}" != "true" ]]; then
log_step "Starting $svc..."
sudo systemctl start "$svc"
fi
else
log_error "systemd: $svc (not found or disabled)"
fi
done
}
# ============================================================================
# CA cert + NPM (black still needs the CA cert locally)
# ============================================================================
_black_local_config() {
log_section "Local Configuration"
# NPM registry
if grep -q "registry=http://npm.black.local" ~/.npmrc 2>/dev/null; then
log_info "NPM registry configured"
else
log_warn "NPM registry not configured in ~/.npmrc"
if [[ "${CHECK_ONLY:-false}" != "true" ]]; then
_configure_npm_registry
fi
fi
}
# ============================================================================
# Public API: called by provision.sh
# ============================================================================
host_dns_setup() {
_black_self_dns
}
host_services_setup() {
_black_dnsmasq
_black_nginx
_black_docker_stack
_black_pm2
_black_systemd
_black_local_config
}
host_verify() {
CHECK_ONLY=true
_black_self_dns
_black_dnsmasq
_black_nginx
_black_docker_stack
_black_pm2
_black_systemd
_black_local_config
}