homelab infrastructure services
at main 232 lines 8.8 kB view raw
1#!/bin/bash 2 3# Setup a complete service environment with NFS and rootless Docker 4# Implements DEPLOYMENT_STRATEGY.md conventions 5 6set -euo pipefail 7 8# Parse parameters and flags 9TIN_SERVICE_NAME="${1:-}" 10TIN_SERVICE_ENVIRONMENT="${2:-}" 11NAS_SERVER="${3:-}" 12PROVIDED_UID="${4:-}" # Optional pre-calculated UID to avoid duplicate warnings 13SKIP_NAS=false 14 15# Check for --skip-nas flag in fourth or fifth parameter 16if [[ "${4:-}" == "--skip-nas" || "${5:-}" == "--skip-nas" ]]; then 17 SKIP_NAS=true 18fi 19 20SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 21TINSNIP_ROOT="$(dirname "$SCRIPT_DIR")" 22 23# Source new library modules 24source "$TINSNIP_ROOT/lib/core.sh" 25source "$TINSNIP_ROOT/lib/uid.sh" 26source "$TINSNIP_ROOT/lib/nfs.sh" 27source "$TINSNIP_ROOT/lib/docker.sh" 28source "$TINSNIP_ROOT/lib/metadata.sh" 29 30log() { 31 log_with_prefix "Service Setup" "$@" 32} 33 34error() { 35 error_with_prefix "Service Setup" "$@" 36} 37 38usage() { 39 echo "Usage: $0 <service_name> <service_env> <nas_server> [uid] [--skip-nas]" 40 echo "" 41 echo "Sets up a complete service environment with:" 42 echo " - Service user with UID convention" 43 echo " - NFS mount to /mnt/<service>-<environment> (with automatic NAS setup)" 44 echo " - XDG directory integration" 45 echo " - Rootless Docker with privileged ports" 46 echo "" 47 echo "Parameters:" 48 echo " service_name: tinsnip, gazette, etc." 49 echo " service_env: prod, test, dev, staging" 50 echo " nas_server: NAS hostname or IP" 51 echo " uid: Optional pre-calculated UID (to avoid duplicate warnings)" 52 echo " --skip-nas: Skip automated NAS setup (requires manual configuration)" 53 echo "" 54 echo "Examples:" 55 echo " $0 tinsnip test DS412plus # With automated NAS setup" 56 echo " $0 lldap prod 192.168.1.100 --skip-nas # Manual NAS setup required" 57 echo " $0 gateway prod 192.168.1.100 50500 # With pre-calculated UID" 58 exit 1 59} 60 61# calculate_service_uid is now provided by lib.sh 62 63check_prerequisites() { 64 # Check Ubuntu 65 if [[ ! -f /etc/os-release ]] || ! grep -q "Ubuntu" /etc/os-release; then 66 error "This script requires Ubuntu" 67 fi 68 69 # Check sudo access 70 if ! groups | grep -q sudo; then 71 error "Current user must have sudo access" 72 fi 73 74 # Check not running as root or service user 75 if [[ $EUID -eq 0 ]]; then 76 error "Do not run as root. Run as a regular user with sudo access." 77 fi 78 79 local service_user="${TIN_SERVICE_NAME}-${TIN_SERVICE_ENVIRONMENT}" 80 if [[ "$USER" == "$service_user" ]]; then 81 error "Do not run as the service user ($service_user). Run as a regular admin user." 82 fi 83} 84 85main() { 86 # Validate parameters 87 if [[ -z "$TIN_SERVICE_NAME" || -z "$TIN_SERVICE_ENVIRONMENT" || -z "$NAS_SERVER" ]]; then 88 usage 89 fi 90 91 # Guard against explicit station creation 92 if [[ "$TIN_SERVICE_NAME" == "station" ]]; then 93 error "Station is infrastructure and cannot be created as a service. It will be automatically created when needed." 94 fi 95 96 # Calculate service details (use provided UID if available to avoid duplicate warning) 97 if [[ -n "$PROVIDED_UID" && "$PROVIDED_UID" =~ ^[0-9]+$ ]]; then 98 TIN_SERVICE_UID="$PROVIDED_UID" 99 else 100 TIN_SERVICE_UID=$(calculate_service_uid "$TIN_SERVICE_NAME" "$TIN_SERVICE_ENVIRONMENT") 101 fi 102 SERVICE_USER="${TIN_SERVICE_NAME}-${TIN_SERVICE_ENVIRONMENT}" 103 104 log "Service Environment Setup" 105 log "=========================" 106 log "Service: $TIN_SERVICE_NAME" 107 log "Environment: $TIN_SERVICE_ENVIRONMENT" 108 log "User: $SERVICE_USER (UID: $TIN_SERVICE_UID)" 109 log "NAS: $NAS_SERVER" 110 if [[ "$SKIP_NAS" == "true" ]]; then 111 log "NAS Setup: Manual (--skip-nas flag used)" 112 else 113 log "NAS Setup: Automated (if SSH keys available)" 114 fi 115 echo 116 117 # Check prerequisites 118 check_prerequisites 119 120 # Check for username collision (idempotent - allow if UID matches) 121 if id "$SERVICE_USER" &>/dev/null 2>&1; then 122 local existing_uid=$(id -u "$SERVICE_USER") 123 124 if [[ "$existing_uid" == "$TIN_SERVICE_UID" ]]; then 125 log "User '$SERVICE_USER' already exists with correct UID $existing_uid (idempotent)" 126 # User exists with correct UID - continue with setup 127 else 128 # UID mismatch - this is a real conflict 129 error "User '$SERVICE_USER' already exists with conflicting UID $existing_uid (expected: $TIN_SERVICE_UID)" 130 echo "" >&2 131 echo "This may be from:" >&2 132 echo " - A different sheet using the same service/environment name" >&2 133 echo " - A previous deployment with different UID" >&2 134 echo "" >&2 135 echo "To avoid collision, choose a unique service name:" >&2 136 echo " tin machine ${TIN_SERVICE_NAME}-${TIN_SHEET} ${TIN_SERVICE_ENVIRONMENT}" >&2 137 local sheet_num=$(get_sheet_number "${TIN_SHEET:-topsheet}" 2>/dev/null || echo "X") 138 echo " tin machine ${TIN_SERVICE_NAME}-${sheet_num} ${TIN_SERVICE_ENVIRONMENT}" >&2 139 echo " tin machine $(echo ${TIN_SHEET:-topsheet} | cut -d. -f1)-${TIN_SERVICE_NAME} ${TIN_SERVICE_ENVIRONMENT}" >&2 140 echo "" >&2 141 echo "Or remove the existing user:" >&2 142 echo " sudo userdel -r $SERVICE_USER" >&2 143 exit 1 144 fi 145 fi 146 147 # Ensure station exists first 148 local sheet="${TIN_SHEET:-topsheet}" 149 log "Checking $sheet station..." 150 if ! "$SCRIPT_DIR/setup_station.sh" "$NAS_SERVER"; then 151 error "Failed to setup sheet station" 152 fi 153 154 # Proceeding with setup 155 156 # Step 1: Mount NFS and create service user 157 log "Step 1: Setting up NFS mount and service user..." 158 159 # Create service user 160 if ! create_service_user "$SERVICE_USER" "$TIN_SERVICE_UID"; then 161 error "Failed to create service user $SERVICE_USER" 162 fi 163 164 # Setup NFS mount (unless skipping NAS setup) 165 if [[ "$SKIP_NAS" != "true" ]]; then 166 if ! setup_nfs_mount "$TIN_SERVICE_NAME" "$TIN_SERVICE_ENVIRONMENT" "$TIN_SERVICE_UID" "$NAS_SERVER" "$sheet"; then 167 error "Failed to setup NFS mount" 168 fi 169 170 # Setup XDG integration 171 if ! setup_xdg_integration "$TIN_SERVICE_NAME" "$TIN_SERVICE_ENVIRONMENT" "$sheet"; then 172 error "Failed to setup XDG integration" 173 fi 174 175 # Create machine metadata in station-prod 176 log "Creating machine metadata in station-prod..." 177 if ! create_machine_metadata "$TIN_SERVICE_NAME" "$TIN_SERVICE_ENVIRONMENT" "$TIN_SERVICE_UID"; then 178 error "Failed to create machine metadata" 179 fi 180 181 # Create .machine symlink from mount to station-prod 182 log "Creating .machine symlink..." 183 if ! create_machine_symlink "$TIN_SERVICE_NAME" "$TIN_SERVICE_ENVIRONMENT"; then 184 error "Failed to create .machine symlink" 185 fi 186 187 # Create environment loader script for automatic sourcing on login 188 log "Creating environment loader script..." 189 if ! create_service_env_loader_script "$SERVICE_USER"; then 190 warn "Failed to create environment loader script" 191 fi 192 fi 193 194 # Step 2: Install rootless Docker 195 log "Step 2: Installing rootless Docker..." 196 if ! install_docker_for_user "$SERVICE_USER"; then 197 error "Failed to install Docker" 198 fi 199 200 log "" 201 log "Machine setup complete!" 202 log "" 203 log "Machine environment details:" 204 log " Machine: ${TIN_SERVICE_NAME}-${TIN_SERVICE_ENVIRONMENT}" 205 log " User: $SERVICE_USER (UID: $TIN_SERVICE_UID)" 206 log " NFS mount: /mnt/${TIN_SERVICE_NAME}-${TIN_SERVICE_ENVIRONMENT}" 207 log " XDG integration: ~/.local/{state,share,config}/$sheet/@$TIN_SERVICE_NAME" 208 if [[ "$SKIP_NAS" == "false" ]]; then 209 log " NAS exports: Automatically configured (if SSH keys available)" 210 else 211 log " NAS exports: Manual configuration required (--skip-nas used)" 212 fi 213 log "" 214 log "To use this environment:" 215 log " sudo -u $SERVICE_USER -i" 216 log " cd /mnt/${TIN_SERVICE_NAME}-${TIN_SERVICE_ENVIRONMENT}" 217 log " docker run hello-world" 218 log "" 219 log "To deploy services to this machine:" 220 log " # Using modern CLI (recommended):" 221 log " tin service deploy ${TIN_SERVICE_NAME}-${TIN_SERVICE_ENVIRONMENT} <service-name>" 222 log " # Examples:" 223 log " tin service deploy ${TIN_SERVICE_NAME}-${TIN_SERVICE_ENVIRONMENT} lldap" 224 log " tin service deploy ${TIN_SERVICE_NAME}-${TIN_SERVICE_ENVIRONMENT} caddy" 225 log "" 226 log " # Or manually as service user:" 227 log " sudo -u $SERVICE_USER -i" 228 log " cd /mnt/${TIN_SERVICE_NAME}-${TIN_SERVICE_ENVIRONMENT}/service/<service-name>" 229 log " docker compose up -d" 230} 231 232main "$@"