stuff
This commit is contained in:
parent
c8754e1bdc
commit
fbbeb59c0e
28 changed files with 907 additions and 995 deletions
363
scripts/setup_layer_8_secondary_services.sh
Executable file
363
scripts/setup_layer_8_secondary_services.sh
Executable file
|
|
@ -0,0 +1,363 @@
|
|||
#!/bin/bash
|
||||
|
||||
###############################################################################
|
||||
# Layer 8: Secondary Services
|
||||
#
|
||||
# This script deploys the ntfy-emergency-app and memos services.
|
||||
# Must be run after Layers 0-7 are complete.
|
||||
###############################################################################
|
||||
|
||||
set -e # Exit on error
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Project directories
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
ANSIBLE_DIR="$PROJECT_ROOT/ansible"
|
||||
|
||||
declare -a LAYER_SUMMARY=()
|
||||
|
||||
print_header() {
|
||||
echo -e "\n${BLUE}========================================${NC}"
|
||||
echo -e "${BLUE}$1${NC}"
|
||||
echo -e "${BLUE}========================================${NC}\n"
|
||||
}
|
||||
|
||||
print_success() {
|
||||
echo -e "${GREEN}✓${NC} $1"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}✗${NC} $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}⚠${NC} $1"
|
||||
}
|
||||
|
||||
print_info() {
|
||||
echo -e "${BLUE}ℹ${NC} $1"
|
||||
}
|
||||
|
||||
confirm_action() {
|
||||
local prompt="$1"
|
||||
local response
|
||||
|
||||
read -p "$(echo -e ${YELLOW}${prompt}${NC} [y/N]: )" response
|
||||
[[ "$response" =~ ^[Yy]$ ]]
|
||||
}
|
||||
|
||||
record_summary() {
|
||||
LAYER_SUMMARY+=("$1")
|
||||
}
|
||||
|
||||
get_hosts_from_inventory() {
|
||||
local group="$1"
|
||||
cd "$ANSIBLE_DIR"
|
||||
ansible-inventory -i inventory.ini --list | \
|
||||
python3 -c "import sys, json; data=json.load(sys.stdin); print(' '.join(data.get('$group', {}).get('hosts', [])))" 2>/dev/null || echo ""
|
||||
}
|
||||
|
||||
get_primary_host_ip() {
|
||||
local group="$1"
|
||||
cd "$ANSIBLE_DIR"
|
||||
ansible-inventory -i inventory.ini --list | \
|
||||
python3 -c "import sys, json; data=json.load(sys.stdin); hosts=data.get('$group', {}).get('hosts', []); print(hosts[0] if hosts else '')" 2>/dev/null || echo ""
|
||||
}
|
||||
|
||||
check_prerequisites() {
|
||||
print_header "Verifying Prerequisites"
|
||||
|
||||
local errors=0
|
||||
|
||||
if [ -z "$VIRTUAL_ENV" ]; then
|
||||
print_error "Virtual environment not activated"
|
||||
echo "Run: source venv/bin/activate"
|
||||
((errors++))
|
||||
else
|
||||
print_success "Virtual environment activated"
|
||||
fi
|
||||
|
||||
if ! command -v ansible &> /dev/null; then
|
||||
print_error "Ansible not found"
|
||||
((errors++))
|
||||
else
|
||||
print_success "Ansible found"
|
||||
fi
|
||||
|
||||
if [ ! -f "$ANSIBLE_DIR/inventory.ini" ]; then
|
||||
print_error "inventory.ini not found"
|
||||
((errors++))
|
||||
else
|
||||
print_success "inventory.ini exists"
|
||||
fi
|
||||
|
||||
if [ ! -f "$ANSIBLE_DIR/infra_vars.yml" ]; then
|
||||
print_error "infra_vars.yml not found"
|
||||
((errors++))
|
||||
else
|
||||
print_success "infra_vars.yml exists"
|
||||
fi
|
||||
|
||||
if [ ! -f "$ANSIBLE_DIR/services_config.yml" ]; then
|
||||
print_error "services_config.yml not found"
|
||||
((errors++))
|
||||
else
|
||||
print_success "services_config.yml exists"
|
||||
fi
|
||||
|
||||
if ! grep -q "^\[vipy\]" "$ANSIBLE_DIR/inventory.ini"; then
|
||||
print_error "vipy not configured in inventory.ini"
|
||||
((errors++))
|
||||
else
|
||||
print_success "vipy configured in inventory"
|
||||
fi
|
||||
|
||||
if ! grep -q "^\[memos-box\]" "$ANSIBLE_DIR/inventory.ini"; then
|
||||
print_warning "memos-box not configured in inventory.ini (memos deployment will be skipped)"
|
||||
else
|
||||
print_success "memos-box configured in inventory"
|
||||
fi
|
||||
|
||||
if [ $errors -gt 0 ]; then
|
||||
print_error "Prerequisites not met. Resolve the issues above and re-run the script."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_success "Prerequisites verified"
|
||||
|
||||
# Display configured subdomains
|
||||
local emergency_subdomain=$(grep "^ ntfy_emergency_app:" "$ANSIBLE_DIR/services_config.yml" | awk '{print $2}' 2>/dev/null || echo "emergency")
|
||||
local memos_subdomain=$(grep "^ memos:" "$ANSIBLE_DIR/services_config.yml" | awk '{print $2}' 2>/dev/null || echo "memos")
|
||||
|
||||
print_info "Configured subdomains:"
|
||||
echo " • ntfy_emergency_app: $emergency_subdomain"
|
||||
echo " • memos: $memos_subdomain"
|
||||
echo ""
|
||||
}
|
||||
|
||||
check_dns_configuration() {
|
||||
print_header "Validating DNS Configuration"
|
||||
|
||||
if ! command -v dig &> /dev/null; then
|
||||
print_warning "dig command not found. Skipping DNS validation."
|
||||
print_info "Install dnsutils/bind-tools to enable DNS validation."
|
||||
return 0
|
||||
fi
|
||||
|
||||
cd "$ANSIBLE_DIR"
|
||||
|
||||
local root_domain
|
||||
root_domain=$(grep "^root_domain:" "$ANSIBLE_DIR/infra_vars.yml" | awk '{print $2}' 2>/dev/null)
|
||||
|
||||
if [ -z "$root_domain" ]; then
|
||||
print_error "Could not determine root_domain from infra_vars.yml"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local emergency_subdomain=$(grep "^ ntfy_emergency_app:" "$ANSIBLE_DIR/services_config.yml" | awk '{print $2}' 2>/dev/null || echo "emergency")
|
||||
local memos_subdomain=$(grep "^ memos:" "$ANSIBLE_DIR/services_config.yml" | awk '{print $2}' 2>/dev/null || echo "memos")
|
||||
|
||||
local vipy_ip
|
||||
vipy_ip=$(get_primary_host_ip "vipy")
|
||||
|
||||
if [ -z "$vipy_ip" ]; then
|
||||
print_error "Unable to determine vipy IP from inventory"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local memos_ip=""
|
||||
if grep -q "^\[memos-box\]" "$ANSIBLE_DIR/inventory.ini"; then
|
||||
memos_ip=$(get_primary_host_ip "memos-box")
|
||||
fi
|
||||
|
||||
local dns_ok=true
|
||||
|
||||
local emergency_fqdn="${emergency_subdomain}.${root_domain}"
|
||||
local memos_fqdn="${memos_subdomain}.${root_domain}"
|
||||
|
||||
print_info "Expected DNS:"
|
||||
echo " • $emergency_fqdn → $vipy_ip"
|
||||
if [ -n "$memos_ip" ]; then
|
||||
echo " • $memos_fqdn → $memos_ip"
|
||||
else
|
||||
echo " • $memos_fqdn → (skipped - memos-box not in inventory)"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
local resolved
|
||||
|
||||
print_info "Checking $emergency_fqdn..."
|
||||
resolved=$(dig +short "$emergency_fqdn" | head -n1)
|
||||
if [ "$resolved" = "$vipy_ip" ]; then
|
||||
print_success "$emergency_fqdn resolves to $resolved"
|
||||
elif [ -n "$resolved" ]; then
|
||||
print_error "$emergency_fqdn resolves to $resolved (expected $vipy_ip)"
|
||||
dns_ok=false
|
||||
else
|
||||
print_error "$emergency_fqdn does not resolve"
|
||||
dns_ok=false
|
||||
fi
|
||||
|
||||
if [ -n "$memos_ip" ]; then
|
||||
print_info "Checking $memos_fqdn..."
|
||||
resolved=$(dig +short "$memos_fqdn" | head -n1)
|
||||
if [ "$resolved" = "$memos_ip" ]; then
|
||||
print_success "$memos_fqdn resolves to $resolved"
|
||||
elif [ -n "$resolved" ]; then
|
||||
print_error "$memos_fqdn resolves to $resolved (expected $memos_ip)"
|
||||
dns_ok=false
|
||||
else
|
||||
print_error "$memos_fqdn does not resolve"
|
||||
dns_ok=false
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
if [ "$dns_ok" = false ]; then
|
||||
print_error "DNS validation failed."
|
||||
print_info "Update DNS records as shown above and wait for propagation."
|
||||
echo ""
|
||||
if ! confirm_action "Continue anyway? (SSL certificates will fail without correct DNS)"; then
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
print_success "DNS validation passed"
|
||||
fi
|
||||
}
|
||||
|
||||
deploy_ntfy_emergency_app() {
|
||||
print_header "Deploying ntfy-emergency-app"
|
||||
|
||||
cd "$ANSIBLE_DIR"
|
||||
|
||||
print_info "This deploys the emergency notification interface pointing at ntfy."
|
||||
echo ""
|
||||
|
||||
if ! confirm_action "Deploy / update the ntfy-emergency-app?"; then
|
||||
print_warning "Skipped ntfy-emergency-app deployment"
|
||||
record_summary "${YELLOW}• ntfy-emergency-app${NC}: skipped"
|
||||
return 0
|
||||
fi
|
||||
|
||||
print_info "Running: ansible-playbook -i inventory.ini services/ntfy-emergency-app/deploy_ntfy_emergency_app_playbook.yml"
|
||||
echo ""
|
||||
|
||||
if ansible-playbook -i inventory.ini services/ntfy-emergency-app/deploy_ntfy_emergency_app_playbook.yml; then
|
||||
print_success "ntfy-emergency-app deployed successfully"
|
||||
record_summary "${GREEN}• ntfy-emergency-app${NC}: deployed"
|
||||
else
|
||||
print_error "ntfy-emergency-app deployment failed"
|
||||
record_summary "${RED}• ntfy-emergency-app${NC}: failed"
|
||||
fi
|
||||
}
|
||||
|
||||
deploy_memos() {
|
||||
print_header "Deploying Memos"
|
||||
|
||||
if ! grep -q "^\[memos-box\]" "$ANSIBLE_DIR/inventory.ini"; then
|
||||
print_warning "memos-box not in inventory. Skipping memos deployment."
|
||||
record_summary "${YELLOW}• memos${NC}: skipped (memos-box missing)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
cd "$ANSIBLE_DIR"
|
||||
|
||||
if ! confirm_action "Deploy / update memos on memos-box?"; then
|
||||
print_warning "Skipped memos deployment"
|
||||
record_summary "${YELLOW}• memos${NC}: skipped"
|
||||
return 0
|
||||
fi
|
||||
|
||||
print_info "Running: ansible-playbook -i inventory.ini services/memos/deploy_memos_playbook.yml"
|
||||
echo ""
|
||||
|
||||
if ansible-playbook -i inventory.ini services/memos/deploy_memos_playbook.yml; then
|
||||
print_success "Memos deployed successfully"
|
||||
record_summary "${GREEN}• memos${NC}: deployed"
|
||||
else
|
||||
print_error "Memos deployment failed"
|
||||
record_summary "${RED}• memos${NC}: failed"
|
||||
fi
|
||||
}
|
||||
|
||||
verify_services() {
|
||||
print_header "Verifying Deployments"
|
||||
|
||||
cd "$ANSIBLE_DIR"
|
||||
|
||||
local ssh_key=$(grep "ansible_ssh_private_key_file" "$ANSIBLE_DIR/inventory.ini" | head -n1 | sed 's/.*ansible_ssh_private_key_file=\([^ ]*\).*/\1/')
|
||||
ssh_key="${ssh_key/#\~/$HOME}"
|
||||
|
||||
local vipy_host
|
||||
vipy_host=$(get_hosts_from_inventory "vipy")
|
||||
|
||||
if [ -n "$vipy_host" ]; then
|
||||
print_info "Checking services on vipy ($vipy_host)..."
|
||||
|
||||
if timeout 5 ssh -i "$ssh_key" -o StrictHostKeyChecking=no -o BatchMode=yes counterweight@$vipy_host "docker ps | grep ntfy-emergency-app" &>/dev/null; then
|
||||
print_success "ntfy-emergency-app container running"
|
||||
else
|
||||
print_warning "ntfy-emergency-app container not running"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if grep -q "^\[memos-box\]" "$ANSIBLE_DIR/inventory.ini"; then
|
||||
local memos_host
|
||||
memos_host=$(get_hosts_from_inventory "memos-box")
|
||||
|
||||
if [ -n "$memos_host" ]; then
|
||||
print_info "Checking memos on memos-box ($memos_host)..."
|
||||
if timeout 5 ssh -i "$ssh_key" -o StrictHostKeyChecking=no -o BatchMode=yes counterweight@$memos_host "systemctl is-active memos" &>/dev/null; then
|
||||
print_success "memos systemd service running"
|
||||
else
|
||||
print_warning "memos systemd service not running"
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
print_summary() {
|
||||
print_header "Layer 8 Summary"
|
||||
|
||||
if [ ${#LAYER_SUMMARY[@]} -eq 0 ]; then
|
||||
print_info "No actions were performed."
|
||||
return
|
||||
fi
|
||||
|
||||
for entry in "${LAYER_SUMMARY[@]}"; do
|
||||
echo -e "$entry"
|
||||
done
|
||||
|
||||
echo ""
|
||||
print_info "Next steps:"
|
||||
echo " • Visit each service's subdomain to complete any manual setup."
|
||||
echo " • Configure backups for new services if applicable."
|
||||
echo " • Update Uptime Kuma monitors if additional endpoints are desired."
|
||||
}
|
||||
|
||||
main() {
|
||||
print_header "Layer 8: Secondary Services"
|
||||
|
||||
check_prerequisites
|
||||
check_dns_configuration
|
||||
|
||||
deploy_ntfy_emergency_app
|
||||
deploy_memos
|
||||
|
||||
verify_services
|
||||
print_summary
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue