Add comprehensive client registry for tracking all deployed infrastructure: Registry System: - Single source of truth in clients/registry.yml - Tracks status, server specs, versions, maintenance history - Supports canary deployment workflow - Automatic updates via deployment scripts New Scripts: - scripts/list-clients.sh: List/filter clients (table/json/csv/summary) - scripts/client-status.sh: Detailed client info with health checks - scripts/update-registry.sh: Manual registry updates Updated Scripts: - scripts/deploy-client.sh: Auto-updates registry on deploy - scripts/rebuild-client.sh: Auto-updates registry on rebuild - scripts/destroy-client.sh: Marks clients as destroyed Documentation: - docs/client-registry.md: Complete registry reference - clients/README.md: Quick start guide Status tracking: pending → deployed → maintenance → destroyed Role support: canary (dev) and production clients 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
237 lines
8.1 KiB
Bash
Executable file
237 lines
8.1 KiB
Bash
Executable file
#!/usr/bin/env bash
|
||
#
|
||
# Show detailed status for a specific client
|
||
#
|
||
# Usage: ./scripts/client-status.sh <client_name>
|
||
#
|
||
# Displays:
|
||
# - Deployment status and metadata
|
||
# - Server information
|
||
# - Application versions
|
||
# - Maintenance history
|
||
# - URLs and access information
|
||
# - Live health checks (optional)
|
||
|
||
set -euo pipefail
|
||
|
||
# Colors for output
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
CYAN='\033[0;36m'
|
||
NC='\033[0m' # No Color
|
||
|
||
# Script directory
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||
REGISTRY_FILE="$PROJECT_ROOT/clients/registry.yml"
|
||
|
||
# Check arguments
|
||
if [ $# -ne 1 ]; then
|
||
echo -e "${RED}Error: Client name required${NC}"
|
||
echo "Usage: $0 <client_name>"
|
||
echo ""
|
||
echo "Example: $0 dev"
|
||
exit 1
|
||
fi
|
||
|
||
CLIENT_NAME="$1"
|
||
|
||
# Check if yq is available
|
||
if ! command -v yq &> /dev/null; then
|
||
echo -e "${RED}Error: 'yq' not found. Install with: brew install yq${NC}"
|
||
exit 1
|
||
fi
|
||
|
||
# Check if registry exists
|
||
if [ ! -f "$REGISTRY_FILE" ]; then
|
||
echo -e "${RED}Error: Registry file not found: $REGISTRY_FILE${NC}"
|
||
exit 1
|
||
fi
|
||
|
||
# Check if client exists
|
||
if yq eval ".clients.\"$CLIENT_NAME\"" "$REGISTRY_FILE" | grep -q "null"; then
|
||
echo -e "${RED}Error: Client '$CLIENT_NAME' not found in registry${NC}"
|
||
echo ""
|
||
echo "Available clients:"
|
||
yq eval '.clients | keys | .[]' "$REGISTRY_FILE"
|
||
exit 1
|
||
fi
|
||
|
||
# Extract client information
|
||
STATUS=$(yq eval ".clients.\"$CLIENT_NAME\".status" "$REGISTRY_FILE")
|
||
ROLE=$(yq eval ".clients.\"$CLIENT_NAME\".role" "$REGISTRY_FILE")
|
||
DEPLOYED_DATE=$(yq eval ".clients.\"$CLIENT_NAME\".deployed_date" "$REGISTRY_FILE")
|
||
DESTROYED_DATE=$(yq eval ".clients.\"$CLIENT_NAME\".destroyed_date" "$REGISTRY_FILE")
|
||
|
||
SERVER_TYPE=$(yq eval ".clients.\"$CLIENT_NAME\".server.type" "$REGISTRY_FILE")
|
||
SERVER_LOCATION=$(yq eval ".clients.\"$CLIENT_NAME\".server.location" "$REGISTRY_FILE")
|
||
SERVER_IP=$(yq eval ".clients.\"$CLIENT_NAME\".server.ip" "$REGISTRY_FILE")
|
||
SERVER_ID=$(yq eval ".clients.\"$CLIENT_NAME\".server.id" "$REGISTRY_FILE")
|
||
|
||
APPS=$(yq eval ".clients.\"$CLIENT_NAME\".apps | join(\", \")" "$REGISTRY_FILE")
|
||
|
||
AUTHENTIK_VERSION=$(yq eval ".clients.\"$CLIENT_NAME\".versions.authentik" "$REGISTRY_FILE")
|
||
NEXTCLOUD_VERSION=$(yq eval ".clients.\"$CLIENT_NAME\".versions.nextcloud" "$REGISTRY_FILE")
|
||
TRAEFIK_VERSION=$(yq eval ".clients.\"$CLIENT_NAME\".versions.traefik" "$REGISTRY_FILE")
|
||
UBUNTU_VERSION=$(yq eval ".clients.\"$CLIENT_NAME\".versions.ubuntu" "$REGISTRY_FILE")
|
||
|
||
LAST_FULL_UPDATE=$(yq eval ".clients.\"$CLIENT_NAME\".maintenance.last_full_update" "$REGISTRY_FILE")
|
||
LAST_SECURITY_PATCH=$(yq eval ".clients.\"$CLIENT_NAME\".maintenance.last_security_patch" "$REGISTRY_FILE")
|
||
LAST_OS_UPDATE=$(yq eval ".clients.\"$CLIENT_NAME\".maintenance.last_os_update" "$REGISTRY_FILE")
|
||
LAST_BACKUP_VERIFIED=$(yq eval ".clients.\"$CLIENT_NAME\".maintenance.last_backup_verified" "$REGISTRY_FILE")
|
||
|
||
AUTHENTIK_URL=$(yq eval ".clients.\"$CLIENT_NAME\".urls.authentik" "$REGISTRY_FILE")
|
||
NEXTCLOUD_URL=$(yq eval ".clients.\"$CLIENT_NAME\".urls.nextcloud" "$REGISTRY_FILE")
|
||
|
||
NOTES=$(yq eval ".clients.\"$CLIENT_NAME\".notes" "$REGISTRY_FILE")
|
||
|
||
# Display header
|
||
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}"
|
||
echo -e "${BLUE} CLIENT STATUS: $CLIENT_NAME${NC}"
|
||
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}"
|
||
echo ""
|
||
|
||
# Status section
|
||
echo -e "${CYAN}━━━ Deployment Status ━━━${NC}"
|
||
echo ""
|
||
|
||
# Color status
|
||
STATUS_COLOR=$NC
|
||
case $STATUS in
|
||
deployed) STATUS_COLOR=$GREEN ;;
|
||
pending) STATUS_COLOR=$YELLOW ;;
|
||
maintenance) STATUS_COLOR=$CYAN ;;
|
||
offboarding) STATUS_COLOR=$RED ;;
|
||
destroyed) STATUS_COLOR=$RED ;;
|
||
esac
|
||
|
||
# Color role
|
||
ROLE_COLOR=$NC
|
||
case $ROLE in
|
||
canary) ROLE_COLOR=$YELLOW ;;
|
||
production) ROLE_COLOR=$GREEN ;;
|
||
esac
|
||
|
||
echo -e "Status: ${STATUS_COLOR}$STATUS${NC}"
|
||
echo -e "Role: ${ROLE_COLOR}$ROLE${NC}"
|
||
echo -e "Deployed: $DEPLOYED_DATE"
|
||
if [ "$DESTROYED_DATE" != "null" ]; then
|
||
echo -e "Destroyed: ${RED}$DESTROYED_DATE${NC}"
|
||
fi
|
||
echo ""
|
||
|
||
# Server section
|
||
echo -e "${CYAN}━━━ Server Information ━━━${NC}"
|
||
echo ""
|
||
echo -e "Server Type: $SERVER_TYPE"
|
||
echo -e "Location: $SERVER_LOCATION"
|
||
echo -e "IP Address: $SERVER_IP"
|
||
echo -e "Server ID: $SERVER_ID"
|
||
echo ""
|
||
|
||
# Applications section
|
||
echo -e "${CYAN}━━━ Applications ━━━${NC}"
|
||
echo ""
|
||
echo -e "Installed: $APPS"
|
||
echo ""
|
||
|
||
# Versions section
|
||
echo -e "${CYAN}━━━ Versions ━━━${NC}"
|
||
echo ""
|
||
echo -e "Authentik: $AUTHENTIK_VERSION"
|
||
echo -e "Nextcloud: $NEXTCLOUD_VERSION"
|
||
echo -e "Traefik: $TRAEFIK_VERSION"
|
||
echo -e "Ubuntu: $UBUNTU_VERSION"
|
||
echo ""
|
||
|
||
# Maintenance section
|
||
echo -e "${CYAN}━━━ Maintenance History ━━━${NC}"
|
||
echo ""
|
||
echo -e "Last Full Update: $LAST_FULL_UPDATE"
|
||
echo -e "Last Security Patch: $LAST_SECURITY_PATCH"
|
||
echo -e "Last OS Update: $LAST_OS_UPDATE"
|
||
if [ "$LAST_BACKUP_VERIFIED" != "null" ]; then
|
||
echo -e "Last Backup Verified: $LAST_BACKUP_VERIFIED"
|
||
else
|
||
echo -e "Last Backup Verified: ${YELLOW}Never${NC}"
|
||
fi
|
||
echo ""
|
||
|
||
# URLs section
|
||
echo -e "${CYAN}━━━ Access URLs ━━━${NC}"
|
||
echo ""
|
||
echo -e "Authentik: $AUTHENTIK_URL"
|
||
echo -e "Nextcloud: $NEXTCLOUD_URL"
|
||
echo ""
|
||
|
||
# Notes section
|
||
if [ "$NOTES" != "null" ] && [ -n "$NOTES" ]; then
|
||
echo -e "${CYAN}━━━ Notes ━━━${NC}"
|
||
echo ""
|
||
echo "$NOTES" | sed 's/^/ /'
|
||
echo ""
|
||
fi
|
||
|
||
# Live health check (if server is deployed and reachable)
|
||
if [ "$STATUS" = "deployed" ]; then
|
||
echo -e "${CYAN}━━━ Live Health Check ━━━${NC}"
|
||
echo ""
|
||
|
||
# Check if server is reachable via SSH (if Ansible is configured)
|
||
if command -v ansible &> /dev/null && [ -n "${HCLOUD_TOKEN:-}" ]; then
|
||
cd "$PROJECT_ROOT/ansible"
|
||
if timeout 10 ~/.local/bin/ansible -i hcloud.yml "$CLIENT_NAME" -m ping -o &>/dev/null; then
|
||
echo -e "SSH Access: ${GREEN}✓ Reachable${NC}"
|
||
|
||
# Get Docker status
|
||
DOCKER_STATUS=$(~/.local/bin/ansible -i hcloud.yml "$CLIENT_NAME" -m shell -a "docker ps --format '{{.Names}}' 2>/dev/null | wc -l" -o 2>/dev/null | tail -1 | awk '{print $NF}' || echo "0")
|
||
if [ "$DOCKER_STATUS" != "0" ]; then
|
||
echo -e "Docker: ${GREEN}✓ Running ($DOCKER_STATUS containers)${NC}"
|
||
else
|
||
echo -e "Docker: ${RED}✗ No containers running${NC}"
|
||
fi
|
||
else
|
||
echo -e "SSH Access: ${RED}✗ Not reachable${NC}"
|
||
fi
|
||
else
|
||
echo -e "${YELLOW}Note: Install Ansible and set HCLOUD_TOKEN for live health checks${NC}"
|
||
fi
|
||
|
||
echo ""
|
||
|
||
# Check HTTPS endpoints
|
||
echo -e "HTTPS Endpoints:"
|
||
|
||
# Check Authentik
|
||
if command -v curl &> /dev/null; then
|
||
if timeout 10 curl -sSf -o /dev/null "$AUTHENTIK_URL" 2>/dev/null; then
|
||
echo -e " Authentik: ${GREEN}✓ Responding${NC}"
|
||
else
|
||
echo -e " Authentik: ${RED}<EFBFBD><EFBFBD> Not responding${NC}"
|
||
fi
|
||
|
||
# Check Nextcloud
|
||
if timeout 10 curl -sSf -o /dev/null "$NEXTCLOUD_URL" 2>/dev/null; then
|
||
echo -e " Nextcloud: ${GREEN}✓ Responding${NC}"
|
||
else
|
||
echo -e " Nextcloud: ${RED}✗ Not responding${NC}"
|
||
fi
|
||
else
|
||
echo -e " ${YELLOW}Install curl for endpoint checks${NC}"
|
||
fi
|
||
|
||
echo ""
|
||
fi
|
||
|
||
# Management commands section
|
||
echo -e "${CYAN}━━━ Management Commands ━━━${NC}"
|
||
echo ""
|
||
echo -e "View secrets: ${BLUE}sops secrets/clients/${CLIENT_NAME}.sops.yaml${NC}"
|
||
echo -e "Rebuild server: ${BLUE}./scripts/rebuild-client.sh $CLIENT_NAME${NC}"
|
||
echo -e "Destroy server: ${BLUE}./scripts/destroy-client.sh $CLIENT_NAME${NC}"
|
||
echo -e "List all: ${BLUE}./scripts/list-clients.sh${NC}"
|
||
echo ""
|
||
|
||
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}"
|