platform-deployments/provisioning/modules/apricot.sh

237 lines
7.3 KiB
Bash
Executable file

#!/usr/bin/env bash
#
# apricot.sh — apricot-specific provisioning (10.0.0.13, Fedora Atomic/Bluefin)
#
# Apricot is the GPU dev workstation. This module verifies/configures:
# - DNS client (→ 10.0.0.11 via resolved)
# - CA certificate
# - NPM registry (→ npm.black.local)
# - Feature databases (docker: analytics, i18n, seo, conv-assistant)
# - Dev nginx (podman: *.apricot.local)
# - CUDA/ML tools
# - Restic backups (systemd timer → black:8000)
# - WireGuard VPN (wg0)
# - host-status-monitor (systemd)
#
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Feature database containers
FEATURE_DBS=(
"analytics-postgres:5433"
"i18n-postgres:5434"
"seo-postgres:5435"
"conv-assistant-postgres:5436"
"analytics-redis:6381"
"i18n-redis:6382"
"seo-redis:6383"
"conv-assistant-redis:6384"
"conv-assistant-chromadb:6385"
"conv-assistant-qdrant:6386"
)
# ============================================================================
# Feature Databases
# ============================================================================
_apricot_feature_dbs() {
log_section "Feature Databases (Docker/Podman)"
local container_cmd="docker"
if command -v podman &>/dev/null && ! command -v docker &>/dev/null; then
container_cmd="podman"
fi
local running
running=$($container_cmd ps --format '{{.Names}}' 2>/dev/null)
for db_entry in "${FEATURE_DBS[@]}"; do
local name="${db_entry%%:*}"
local port="${db_entry##*:}"
if echo "$running" | grep -q "^${name}$"; then
log_info "Container: $name (:$port)"
else
log_warn "Container NOT running: $name (:$port)"
fi
done
}
# ============================================================================
# Dev nginx (podman)
# ============================================================================
_apricot_dev_nginx() {
log_section "Dev Nginx (*.apricot.local)"
local compose_file
compose_file="$(cd "$SCRIPT_DIR/../.." && pwd)/nginx/docker-compose.apricot.yml"
local container_name="apricot-dev-proxy"
local container_cmd="docker"
if command -v podman &>/dev/null && ! command -v docker &>/dev/null; then
container_cmd="podman"
fi
local running
running=$($container_cmd ps --filter "name=${container_name}" --filter "status=running" --format '{{.Names}}' 2>/dev/null || true)
if [[ -n "$running" ]]; then
log_info "Dev proxy container running ($container_name)"
# Validate nginx config
if $container_cmd exec "$container_name" nginx -t &>/dev/null; then
log_info "nginx config valid"
else
log_warn "nginx config INVALID"
$container_cmd exec "$container_name" nginx -t 2>&1 | sed 's/^/ /'
fi
# List configured vhosts
local vhosts
vhosts=$($container_cmd exec "$container_name" nginx -T 2>/dev/null \
| grep -oP 'server_name\s+\K[^;]+' \
| grep -v '^_$' \
| sort -u)
if [[ -n "$vhosts" ]]; then
log_info "Configured vhosts:"
echo "$vhosts" | sed 's/^/ /'
fi
else
log_warn "Dev proxy container not running"
if [[ -f "$compose_file" ]]; then
echo " Start with: docker compose -f $compose_file up -d"
else
echo " Compose file not found: $compose_file"
echo " Deploy from ~/Code/deployments/nginx/"
fi
fi
}
# ============================================================================
# CUDA / ML tools
# ============================================================================
_apricot_cuda() {
log_section "CUDA & ML Tools"
if command -v nvcc &>/dev/null; then
local cuda_version
cuda_version=$(nvcc --version 2>/dev/null | grep "release" | awk '{print $6}' | cut -d',' -f1 || echo "unknown")
log_info "CUDA toolkit: $cuda_version"
else
log_warn "CUDA toolkit not found (nvcc missing)"
fi
if command -v nvidia-smi &>/dev/null; then
local gpu_info
gpu_info=$(nvidia-smi --query-gpu=name,memory.total --format=csv,noheader 2>/dev/null | head -1)
log_info "GPU: $gpu_info"
else
log_warn "nvidia-smi not found"
fi
if python3 -c "import torch; print(f'PyTorch {torch.__version__}, CUDA {torch.version.cuda}')" 2>/dev/null; then
log_info "PyTorch with CUDA available"
else
log_warn "PyTorch not available or no CUDA support"
fi
}
# ============================================================================
# Restic backups
# ============================================================================
_apricot_restic() {
log_section "Restic Backups"
# Check systemd timers
local timers
timers=$(systemctl --user list-timers --no-pager 2>/dev/null || echo "")
if echo "$timers" | grep -q "restic-backup-code"; then
log_info "Code backup timer active"
else
log_warn "Code backup timer not found"
echo " Run setup-workstation.sh to configure restic backups"
fi
if echo "$timers" | grep -q "restic-backup-dotfiles"; then
log_info "Dotfiles backup timer active"
else
log_warn "Dotfiles backup timer not found"
fi
# Verify restic server reachable
if curl -sf "http://10.0.0.11:8000/" &>/dev/null; then
log_info "Restic REST server reachable"
else
log_warn "Restic REST server not reachable at http://10.0.0.11:8000/"
fi
}
# ============================================================================
# WireGuard VPN
# ============================================================================
_apricot_vpn() {
log_section "WireGuard VPN"
if ip addr show wg0 &>/dev/null 2>&1; then
log_info "WireGuard wg0 interface up"
if ping -c 1 -W 2 10.0.0.11 &>/dev/null; then
log_info "Can reach black (10.0.0.11) over VPN"
else
log_warn "wg0 up but cannot reach 10.0.0.11"
fi
elif nmcli con show --active 2>/dev/null | grep -qi wireguard; then
log_info "WireGuard active via NetworkManager"
else
log_warn "WireGuard not active"
fi
}
# ============================================================================
# Status monitor
# ============================================================================
_apricot_status_agent() {
log_section "Host Status Monitor"
if systemctl --user is-active host-status-monitor &>/dev/null 2>&1; then
log_info "host-status-monitor active (user service)"
elif systemctl is-active host-status-monitor &>/dev/null 2>&1; then
log_info "host-status-monitor active (system service)"
else
log_warn "host-status-monitor not active"
fi
}
# ============================================================================
# Public API
# ============================================================================
host_dns_setup() {
dns_client_setup
}
host_services_setup() {
_apricot_feature_dbs
_apricot_dev_nginx
_apricot_cuda
_apricot_restic
_apricot_vpn
_apricot_status_agent
}
host_verify() {
CHECK_ONLY=true
dns_client_verify || true
_apricot_feature_dbs
_apricot_dev_nginx
_apricot_cuda
_apricot_restic
_apricot_vpn
_apricot_status_agent
}