homelab infrastructure services
at fix-docker-install 219 lines 7.0 kB view raw
1#!/bin/bash 2# Shared library functions for tinsnip machine setup 3 4# Color constants 5RED='\033[0;31m' 6GREEN='\033[0;32m' 7YELLOW='\033[1;33m' 8NC='\033[0m' 9 10# Shared logging functions with customizable prefix 11log_with_prefix() { 12 local prefix="$1" 13 shift 14 echo -e "${GREEN}[$prefix]${NC} $*" 15} 16 17error_with_prefix() { 18 local prefix="$1" 19 shift 20 echo -e "${RED}[ERROR]${NC} $*" >&2 21 exit 1 22} 23 24warn_with_prefix() { 25 local prefix="$1" 26 shift 27 echo -e "${YELLOW}[WARNING]${NC} $*" 28} 29 30# Get namespace number from namespace name (1-9 range) 31# Uses deterministic hash that maps "dynamicalsystem" to 1 for backward compatibility 32get_namespace_number() { 33 local namespace="${1:-dynamicalsystem}" 34 35 # Hash namespace to 1-9 range 36 echo "$namespace" | md5sum | cut -c1-1 | { 37 read hex 38 printf "%d\n" "0x$hex" | awk '{n=($1 % 9) + 1; print n}' 39 } 40} 41 42# Find the next available service number from a registry file 43find_next_service_number() { 44 local registry_path="$1" 45 46 if [[ ! -f "$registry_path" ]]; then 47 echo "1" 48 return 49 fi 50 51 # Extract all service numbers from registry, find the highest 52 local max_num=0 53 while IFS='=' read -r service_name service_num; do 54 # Skip comments and empty lines 55 [[ "$service_name" =~ ^#.*$ ]] || [[ -z "$service_name" ]] && continue 56 57 if [[ "$service_num" =~ ^[0-9]+$ ]] && [[ "$service_num" -gt "$max_num" ]]; then 58 max_num="$service_num" 59 fi 60 done < "$registry_path" 61 62 # Return next available number (max + 1) 63 echo $((max_num + 1)) 64} 65 66# Calculate service UID using TNSEP convention 67# T=1 (Docker), N=namespace number, S=service, E=environment, P=0 68calculate_service_uid() { 69 local service_name="$1" 70 local service_env="$2" 71 72 # Get namespace from environment or file 73 local namespace="${TIN_NAMESPACE:-}" 74 if [[ -z "$namespace" ]] && [[ -f "/etc/tinsnip-namespace" ]]; then 75 namespace=$(cat /etc/tinsnip-namespace) 76 fi 77 namespace="${namespace:-dynamicalsystem}" 78 79 # Get namespace number (1-9) 80 local namespace_num=$(get_namespace_number "$namespace") 81 82 # Service number mapping 83 local service_num 84 85 # Special case for station (namespace infrastructure) 86 if [[ "$service_name" == "station" ]]; then 87 service_num=0 88 else 89 # Try to read from service registry 90 local registry_path="/volume1/${namespace}/station/prod/service-registry" 91 if [[ -f "$registry_path" ]]; then 92 service_num=$(grep "^${service_name}=" "$registry_path" | cut -d= -f2) 93 if [[ -z "$service_num" ]]; then 94 # Service not in registry - auto-assign next available number 95 service_num=$(find_next_service_number "$registry_path") 96 warn_with_prefix "UID Calculation" "Service '$service_name' not in registry, auto-assigning service number $service_num" 97 fi 98 else 99 # Registry doesn't exist - use fallback mapping or auto-assign 100 case "$service_name" in 101 gazette) service_num=1 ;; 102 lldap) service_num=2 ;; 103 gateway) service_num=3 ;; 104 *) 105 # Auto-assign starting from service number 4 106 service_num=4 107 warn_with_prefix "UID Calculation" "No registry found, auto-assigning service number $service_num for '$service_name'" 108 ;; 109 esac 110 fi 111 fi 112 113 # Environment number mapping 114 local env_num 115 case "$service_env" in 116 prod) env_num=0 ;; 117 test) env_num=1 ;; 118 *) 119 echo "ERROR: Unknown environment: $service_env" >&2 120 return 1 121 ;; 122 esac 123 124 # Return TNSEP UID 125 echo "1${namespace_num}${service_num}${env_num}0" 126} 127 128# Calculate service ports based on UID 129calculate_service_ports() { 130 local service_uid="$1" 131 local port_count="${2:-3}" 132 133 local base_port=$service_uid 134 for ((i=0; i<port_count; i++)); do 135 echo $((base_port + i)) 136 done 137} 138 139# Update shell configuration files (.bashrc or .profile) with environment variables 140# Usage: update_shell_config username config_file "VAR1=value1" "VAR2=value2" ... 141update_shell_config() { 142 local username="$1" 143 local config_file="$2" 144 shift 2 145 local env_vars=("$@") 146 147 sudo -u "$username" -i bash << EOF 148# Remove any existing environment variables to avoid duplicates 149grep -v "$(printf "%s\\\\|" "${env_vars[@]}" | sed 's/=.*/=/g' | sed 's/\\\\|$//')" ~/$config_file > ~/${config_file}.tmp 2>/dev/null && mv ~/${config_file}.tmp ~/$config_file || touch ~/$config_file 150 151# Add environment variables 152cat >> ~/$config_file << 'CONFIG_EOF' 153 154# Environment variables managed by tinsnip 155$(printf "export %s\n" "${env_vars[@]}") 156CONFIG_EOF 157EOF 158} 159 160# Create service environment file on NFS mount with all variables needed by service 161create_service_env_file() { 162 local service_name="$1" 163 local service_env="$2" 164 local service_uid="$3" 165 local mount_point="/mnt/${service_name}-${service_env}" 166 local namespace="${TIN_NAMESPACE:-dynamicalsystem}" 167 168 local env_file="$mount_point/.env" 169 170 log_with_prefix "Service Env" "Creating $env_file" 171 172 # Create the .env file with all service variables 173 sudo -u "${service_name}-${service_env}" tee "$env_file" > /dev/null << EOF 174# Tinsnip service environment variables 175# Generated automatically - do not edit manually 176TIN_SERVICE_NAME=$service_name 177TIN_SERVICE_ENVIRONMENT=$service_env 178TIN_SERVICE_UID=$service_uid 179TIN_NAMESPACE=$namespace 180 181# XDG Base Directory variables (NFS-backed) 182XDG_DATA_HOME=$mount_point/data 183XDG_CONFIG_HOME=$mount_point/config 184XDG_STATE_HOME=$mount_point/state 185XDG_CACHE_HOME=$mount_point/cache 186 187# Docker environment (set by install_docker.sh if applicable) 188# These will be added by Docker setup process 189EOF 190 191 log_with_prefix "Service Env" "Created service environment file" 192} 193 194# Generate shell environment loading code for .bashrc/.profile 195# This creates the code that loads service env with cache fallback 196generate_service_env_loader() { 197 cat << 'EOF' 198# Tinsnip service environment loading with NFS resilience 199# Set XDG_CACHE_HOME first (host-based, not NFS) 200export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}" 201 202# Load service environment variables 203if [[ "\$(whoami)" =~ ^[^-]+-[^-]+\$ ]]; then 204 # This is a service user (format: service-environment) 205 SERVICE_ENV_FILE="/mnt/\$(whoami)/.env" 206 TIN_SERVICE_ENV_CACHE="\$XDG_CACHE_HOME/tinsnip/\$(whoami).env" 207 208 if [[ -f "$SERVICE_ENV_FILE" ]]; then 209 # NFS available - source primary file and update cache 210 source "$SERVICE_ENV_FILE" 211 mkdir -p "$(dirname "$TIN_SERVICE_ENV_CACHE")" 212 cp "$SERVICE_ENV_FILE" "$TIN_SERVICE_ENV_CACHE" 2>/dev/null || true 213 elif [[ -f "$TIN_SERVICE_ENV_CACHE" ]]; then 214 # NFS unavailable - use cached version 215 source "$TIN_SERVICE_ENV_CACHE" 216 fi 217fi 218EOF 219}