homelab infrastructure services
at main 229 lines 8.9 kB view raw
1#!/bin/bash 2# tin service deploy - Deploy service from catalog 3 4set -euo pipefail 5 6# Get tinsnip root and source libraries 7SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 8TINSNIP_ROOT="$(dirname "$(dirname "$SCRIPT_DIR")")" 9source "$TINSNIP_ROOT/lib/core.sh" 10source "$TINSNIP_ROOT/lib/uid.sh" 11source "$TINSNIP_ROOT/lib/metadata.sh" 12 13# Helper function to calculate port numbers 14get_service_port() { 15 local service_name="$1" 16 local service_env="$2" 17 local port_index="${3:-0}" 18 19 local service_uid=$(calculate_service_uid "$service_name" "$service_env") 20 echo $((service_uid + port_index)) 21} 22 23# Deploy service from catalog 24deploy_service() { 25 local service_env="$1" 26 local catalog_service="$2" 27 28 # Parse service-environment 29 local parsed_output 30 if ! parsed_output=$(parse_machine_name "$service_env" 2>/dev/null); then 31 error_with_prefix "Service Deploy" "Invalid machine environment format: '$service_env'" 32 echo "Expected: <service>-<environment> (e.g., gazette-prod, bsky-pds-dev)" >&2 33 exit 1 34 fi 35 36 local machine_service=$(echo "$parsed_output" | sed -n '1p') 37 local environment=$(echo "$parsed_output" | sed -n '2p') 38 local service_user="$service_env" 39 40 log_with_prefix "Service Deploy" "Deploying service: $catalog_service$service_env" 41 echo 42 43 # Debug: Show current TIN_SHEET 44 log_with_prefix "Service Deploy" "Using sheet: ${TIN_SHEET:-topsheet}" 45 46 # Verify machine environment exists 47 local service_uid 48 if ! service_uid=$(calculate_service_uid "$machine_service" "$environment" 2>/dev/null); then 49 error_with_prefix "Service Deploy" "Cannot calculate UID for machine environment" 50 exit 1 51 fi 52 53 log_with_prefix "Service Deploy" "Calculated UID: $service_uid" 54 55 if ! getent passwd "$service_uid" >/dev/null 2>&1; then 56 error_with_prefix "Service Deploy" "Machine environment '$service_env' not found" 57 echo "Create with: tin machine create $machine_service $environment" >&2 58 exit 1 59 fi 60 61 # Check if service catalog exists 62 local service_catalog_path="$HOME/.local/opt/dynamicalsystem.service" 63 if [[ ! -d "$service_catalog_path/$catalog_service" ]]; then 64 error_with_prefix "Service Deploy" "Service '$catalog_service' not found in catalog" 65 echo "Available services:" >&2 66 if [[ -d "$service_catalog_path" ]]; then 67 ls -1 "$service_catalog_path" | grep -v README | head -10 >&2 68 fi 69 exit 1 70 fi 71 72 log_with_prefix "Service Deploy" "Machine environment verified: $service_env" 73 log_with_prefix "Service Deploy" "Service catalog found: $catalog_service" 74 75 # Show deployment plan 76 echo "Deployment Plan:" 77 echo " Machine: $service_env" 78 echo " Service: $catalog_service" 79 echo " User: $service_user" 80 echo " UID: $service_uid" 81 echo " Source: $service_catalog_path/$catalog_service" 82 echo " Target: /mnt/$service_env/service/$catalog_service" 83 echo 84 85 # Confirm deployment 86 read -p "Deploy $catalog_service to $service_env? [Y/n]: " confirm 87 case "${confirm:-y}" in 88 [Yy]*|"") 89 log_with_prefix "Service Deploy" "Starting deployment..." 90 ;; 91 [Nn]*) 92 log_with_prefix "Service Deploy" "Deployment cancelled" 93 exit 1 94 ;; 95 *) 96 error_with_prefix "Service Deploy" "Invalid input. Deployment cancelled" 97 exit 1 98 ;; 99 esac 100 101 # Copy service files 102 log_with_prefix "Service Deploy" "Copying service files..." 103 sudo -u "$service_user" mkdir -p "/mnt/$service_env/service" 104 105 # Copy as current user (to avoid permission issues reading from home directory) 106 # then fix ownership for the service user 107 if cp -r "$service_catalog_path/$catalog_service" "/mnt/$service_env/service/"; then 108 # Fix ownership to service user (NFS all_squash will handle actual ownership) 109 sudo chown -R "$service_uid:$service_uid" "/mnt/$service_env/service/$catalog_service" 2>/dev/null || true 110 log_with_prefix "Service Deploy" "Service files copied successfully" 111 else 112 error_with_prefix "Service Deploy" "Failed to copy service files" 113 exit 1 114 fi 115 116 # Allocate ports and generate service .env 117 log_with_prefix "Service Deploy" "Allocating ports..." 118 local compose_file="/mnt/$service_env/service/$catalog_service/docker-compose.yml" 119 local port_count 120 port_count=$(get_service_port_count "$compose_file") 121 122 local start_port 123 if ! start_port=$(allocate_service_ports "$machine_service" "$environment" "$catalog_service" "$port_count"); then 124 error_with_prefix "Service Deploy" "Port allocation failed" 125 # Clean up copied files 126 sudo rm -rf "/mnt/$service_env/service/$catalog_service" 127 exit 1 128 fi 129 130 if ! generate_service_env "$service_env" "$catalog_service" "$start_port" "$port_count"; then 131 error_with_prefix "Service Deploy" "Failed to generate service .env" 132 # Clean up 133 sudo rm -rf "/mnt/$service_env/service/$catalog_service" 134 exit 1 135 fi 136 137 local end_port=$((start_port + port_count - 1)) 138 log_with_prefix "Service Deploy" "✓ Ports allocated: $start_port-$end_port ($port_count ports)" 139 140 # Run service setup if it exists 141 local setup_script="/mnt/$service_env/service/$catalog_service/setup.sh" 142 if [[ -f "$setup_script" ]]; then 143 log_with_prefix "Service Deploy" "Running service setup script..." 144 # Ensure script is executable 145 chmod +x "$setup_script" 146 # Run as service user with machine and service env sourced 147 if sudo -u "$service_user" bash -c "source /mnt/$service_env/.machine/machine.env && source /mnt/$service_env/service/$catalog_service/.env && bash $setup_script"; then 148 log_with_prefix "Service Deploy" "Service setup completed" 149 else 150 warn_with_prefix "Service Deploy" "Service setup script failed" 151 fi 152 fi 153 154 # Start services 155 local compose_file="/mnt/$service_env/service/$catalog_service/docker-compose.yml" 156 if [[ -f "$compose_file" ]]; then 157 log_with_prefix "Service Deploy" "Starting services..." 158 159 # Change to service directory and start 160 # Source env files with auto-export for Docker Compose YAML interpolation, but unset XDG vars that break rootless Docker 161 # Containers get all vars via env_file directive in docker-compose.yml 162 if sudo -u "$service_user" bash -c "set -a && source /mnt/$service_env/.machine/machine.env && source /mnt/$service_env/service/$catalog_service/.env && set +a && unset XDG_DATA_HOME XDG_CONFIG_HOME XDG_STATE_HOME && cd /mnt/$service_env/service/$catalog_service && docker compose up -d"; then 163 log_with_prefix "Service Deploy" "✅ Service '$catalog_service' deployed successfully to '$service_env'" 164 else 165 error_with_prefix "Service Deploy" "Failed to start services" 166 exit 1 167 fi 168 else 169 warn_with_prefix "Service Deploy" "No docker-compose.yml found - service copied but not started" 170 fi 171 172 echo 173 log_with_prefix "Service Deploy" "Deployment complete!" 174 echo " Service: $catalog_service" 175 echo " Ports: $start_port-$end_port" 176 echo "" 177 echo "Check status with: tin service status $service_env" 178 echo "View logs with: tin service logs $service_env $catalog_service" 179} 180 181show_help() { 182 cat << EOF 183tin service deploy - Deploy service from catalog 184 185USAGE: 186 tin service deploy <service-env> <catalog-service> 187 tin service <service-env> <catalog-service> # Shorthand 188 189DESCRIPTION: 190 Deploy a service from the catalog to a prepared machine environment. 191 The service is copied from the catalog and configured for the target 192 environment with proper UID mapping and port allocation. 193 194ARGUMENTS: 195 <service-env> Target machine environment (e.g., gazette-prod) 196 <catalog-service> Service name from catalog to deploy 197 198EXAMPLES: 199 tin service deploy gazette-prod lldap # Deploy LLDAP to gazette-prod 200 tin service lldap-test redis # Deploy Redis to lldap-test 201 tin service station-prod prometheus # Deploy Prometheus to station 202 203NOTES: 204 - The target machine environment must exist (created with tin machine) 205 - The catalog service must be available in the service catalog 206 - Services are deployed as the service user with proper UID/port mapping 207 208EOF 209} 210 211# Handle help flags 212case "${1:-}" in 213 --help|-h|help) 214 show_help 215 exit 0 216 ;; 217esac 218 219# Main execution 220if [[ $# -lt 2 ]]; then 221 error_with_prefix "Service Deploy" "Service environment and catalog service required" 222 echo "Usage: tin service deploy <service-env> <catalog-service>" >&2 223 exit 1 224fi 225 226service_env="$1" 227catalog_service="$2" 228 229deploy_service "$service_env" "$catalog_service"