homelab infrastructure services
at main 277 lines 9.2 kB view raw
1#!/bin/bash 2 3# Setup sheet station - the infrastructure machine for a sheet 4# Handles machine registry and shared configuration 5 6set -euo pipefail 7 8SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 9TINSNIP_ROOT="$(dirname "$SCRIPT_DIR")" 10source "$TINSNIP_ROOT/lib/core.sh" 11source "$TINSNIP_ROOT/lib/uid.sh" 12source "$TINSNIP_ROOT/lib/registry.sh" 13source "$TINSNIP_ROOT/lib/nfs.sh" 14 15# Parameters 16NAS_SERVER="${1:-}" 17TIN_SHEET="${TIN_SHEET:-topsheet}" 18 19# Setup logging functions using shared lib 20log() { 21 log_with_prefix "Station Setup" "$@" 22} 23 24error() { 25 error_with_prefix "Station Setup" "$@" 26} 27 28warn() { 29 warn_with_prefix "Station Setup" "$@" 30} 31 32 33# Discover existing machines by scanning system UIDs (SMEP scheme) 34discover_existing_machines() { 35 local sheet_num=$(get_sheet_number "$TIN_SHEET") 36 local machines=() 37 38 log "Discovering existing machines in sheet '$TIN_SHEET'..." >&2 39 40 # Scan for users matching SMEP UID pattern 41 # SMEP Pattern: ${sheet_num}${machine_num_2digit}${env_num}${port} 42 for machine_num in {01..99}; do 43 for env_num in {0..9}; do 44 local smep_uid="${sheet_num}${machine_num}${env_num}0" 45 46 if getent passwd "$smep_uid" >/dev/null 2>&1; then 47 local username=$(getent passwd "$smep_uid" | cut -d: -f1) 48 local env_name 49 50 # Map environment numbers to names (expanded mapping) 51 case "$env_num" in 52 0) env_name="prod" ;; 53 1) env_name="test" ;; 54 2) env_name="dev" ;; 55 3) env_name="staging" ;; 56 4) env_name="demo" ;; 57 5) env_name="qa" ;; 58 6) env_name="uat" ;; 59 7) env_name="preview" ;; 60 8) env_name="canary" ;; 61 9) env_name="local" ;; 62 esac 63 64 # Extract machine name from username pattern: machine-env 65 if [[ "$username" =~ ^([^-]+)-${env_name}$ ]]; then 66 local machine_name="${BASH_REMATCH[1]}" 67 log "Found: $machine_name ($env_name) - UID $smep_uid (user: $username)" >&2 68 machines+=("$machine_name=$machine_num") 69 else 70 log "Found UID $smep_uid but couldn't parse machine name from username: $username" >&2 71 fi 72 fi 73 done 74 done 75 76 # Return unique machine mappings 77 printf '%s\n' "${machines[@]}" | sort -u 78} 79 80# Create machine registry from discovered machines 81create_machine_registry() { 82 local mount_point="/mnt/station-prod" 83 local sheet="${TIN_SHEET:-topsheet}" 84 85 # Create machines directory for per-sheet registries 86 sudo -u station-prod mkdir -p "$mount_point/data/machines" 87 88 # Create backward compatibility symlink (services → machines) 89 if [[ ! -e "$mount_point/data/services" ]]; then 90 log "Creating backward compatibility symlink: services → machines" 91 sudo -u station-prod ln -s machines "$mount_point/data/services" 92 fi 93 94 local registry_file="$mount_point/data/machines/$sheet/registry" 95 96 # Create sheet directory if needed 97 sudo -u station-prod mkdir -p "$mount_point/data/machines/$sheet" 98 99 # Only create registry if it doesn't exist (preserve existing registrations) 100 if [[ ! -f "$registry_file" ]]; then 101 log "Creating new machine registry for sheet '$sheet'" 102 103 # Discover machines 104 local machines=$(discover_existing_machines) 105 106 # Create per-sheet registry file with only station (other machines register themselves) 107 cat << EOF | sudo -u station-prod tee "$registry_file" > /dev/null 108# Machine Registry for $sheet sheet 109# Format: machine_name=machine_number (2-digit format) 110# Machine 00 is reserved for station (sheet infrastructure) 111 112station=00 113EOF 114 115 # Add discovered machines 116 if [[ -n "$machines" ]]; then 117 echo "$machines" | sudo -u station-prod tee -a "$registry_file" > /dev/null 118 fi 119 120 log "Machine registry created for sheet '$sheet' at $registry_file with $(wc -l < "$registry_file") entries" 121 else 122 log "Machine registry already exists for sheet '$sheet', preserving existing entries" 123 fi 124} 125 126# Create global sheet registry (only for topsheet sheet) 127create_sheet_registry() { 128 local mount_point="/mnt/station-prod" 129 local sheet_registry="$mount_point/data/sheets" 130 131 # Only create sheet registry for topsheet sheet 132 if [[ "$TIN_SHEET" != "topsheet" ]]; then 133 return 0 134 fi 135 136 log "Creating global sheet registry..." 137 138 # Create data directory 139 sudo -u station-prod mkdir -p "$mount_point/data" 140 141 # Create sheet registry file with a topsheet entry 142 cat << EOF | sudo -u station-prod tee "$sheet_registry" > /dev/null 143# Global Sheet Registry 144# Format: sheet_name=sheet_number 145# This registry prevents sheet number collisions 146# Only tinsnip.station-prod maintains this registry 147 148topsheet=5 149EOF 150 151 log "Global sheet registry created: $sheet_registry" 152} 153 154# Create NAS credentials storage (only for topsheet sheet) 155setup_nas_credentials() { 156 local mount_point="/mnt/station-prod" 157 local nas_creds_dir="$mount_point/data/nas-credentials" 158 159 # Only create NAS credentials storage for topsheet sheet 160 if [[ "$TIN_SHEET" != "topsheet" ]]; then 161 return 0 162 fi 163 164 log "Setting up NAS credentials storage..." 165 166 # Create credentials directory with restricted permissions 167 sudo -u station-prod mkdir -p "$nas_creds_dir" 168 sudo -u station-prod chmod 700 "$nas_creds_dir" 169 170 # Create placeholder files 171 sudo -u station-prod touch "$nas_creds_dir/README.md" 172 cat << EOF | sudo -u station-prod tee "$nas_creds_dir/README.md" > /dev/null 173# NAS Credentials Storage 174 175This directory stores SSH keys and credentials for NAS access. 176 177Structure: 178- \`<nas-server>.key\` - Private SSH keys for each NAS server 179- \`authorized_keys\` - Public keys for distribution to NAS servers 180- \`nas-servers\` - Registry of NAS servers per sheet 181 182Security: 183- Directory permissions: 700 (station-prod user only) 184- Key file permissions: 600 (when added) 185EOF 186 187 # Create NAS server registry with the server used for bootstrap 188 if [[ -n "$NAS_SERVER" ]]; then 189 local nas_registry="$nas_creds_dir/nas-servers" 190 cat << EOF | sudo -u station-prod tee "$nas_registry" > /dev/null 191# NAS Server Registry 192# Format: sheet=nas_server 193# This tracks which NAS servers are used by each sheet 194 195${TIN_SHEET}=$NAS_SERVER 196EOF 197 log "NAS server registry created: $NAS_SERVER registered" 198 fi 199 200 log "NAS credentials storage ready: $nas_creds_dir" 201} 202 203# Deploy catalog and scripts to station 204deploy_station_artifacts() { 205 local mount_point="/mnt/station-prod" 206 local tinsnip_root="$HOME/.local/opt/$TIN_SHEET.tinsnip" 207 208 log "Deploying station artifacts..." 209 210 # Create directory structure for scripts 211 sudo -u station-prod mkdir -p "$mount_point/opt/scripts" 212 213 # Note: Service catalog is maintained in separate repository 214 # at ~/.local/opt/{sheet}.service/ (e.g., dynamicalsystem.service) 215 216 log "Station artifacts deployed" 217} 218 219# Setup station user and mount using library functions 220setup_station_mount() { 221 local service_name="station" 222 local service_env="prod" 223 local service_uid="$(calculate_service_uid "$service_name" "$service_env")" 224 local service_user="${service_name}-${service_env}" 225 226 # Create service user 227 if ! create_service_user "$service_user" "$service_uid"; then 228 error "Failed to create service user $service_user" 229 fi 230 231 # Setup NFS mount 232 if ! setup_nfs_mount "$service_name" "$service_env" "$service_uid" "$NAS_SERVER" "$TIN_SHEET"; then 233 error "Failed to setup station NFS mount" 234 fi 235 236 # Setup XDG integration 237 if ! setup_xdg_integration "$service_name" "$service_env" "$TIN_SHEET"; then 238 error "Failed to setup XDG integration for station" 239 fi 240} 241 242# Main setup flow 243main() { 244 if [[ -z "$NAS_SERVER" ]]; then 245 echo "Usage: $0 <nas_server>" 246 echo "" 247 echo "Sets up the sheet station for machine registry and shared config" 248 exit 1 249 fi 250 251 local station_uid=$(calculate_service_uid "station" "prod") 252 log "Setting up station:" 253 log " Sheet: $TIN_SHEET" 254 log " NFS mount: /mnt/station-prod" 255 log " User: station-prod (UID: $station_uid)" 256 257 # Setup station mount and user (mount_nas.sh handles existence check and creation guidance) 258 setup_station_mount 259 260 # Create registries 261 create_machine_registry 262 create_sheet_registry # Only for topsheet sheet 263 setup_nas_credentials # Only for topsheet sheet 264 265 # Deploy catalog and scripts 266 deploy_station_artifacts 267 268 log "Station setup complete!" 269 if [[ "$TIN_SHEET" == "topsheet" ]]; then 270 log " Global sheet registry: /mnt/station-prod/data/sheets" 271 log " NAS credentials: /mnt/station-prod/data/nas-credentials/" 272 fi 273 log " Machine registry: /mnt/station-prod/data/machines" 274 log " Scripts: /mnt/station-prod/opt/scripts/" 275} 276 277main "$@"