homelab infrastructure services
at main 240 lines 8.8 kB view raw
1#!/bin/bash 2# Core tinsnip shared library functions 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} $*" >&2 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} $*" >&2 28} 29 30# Get current sheet (from environment, file, or default) 31get_sheet() { 32 # Use sheet from environment, file, or default 33 if [[ -n "${TIN_SHEET:-}" ]]; then 34 echo "$TIN_SHEET" 35 elif [[ -f "/etc/tinsnip-sheet" ]]; then 36 cat "/etc/tinsnip-sheet" 37 else 38 echo "topsheet" 39 fi 40} 41 42# Update shell configuration files (.bashrc or .profile) with environment variables 43# Usage: update_shell_config username config_file "VAR1=value1" "VAR2=value2" ... 44update_shell_config() { 45 local username="$1" 46 local config_file="$2" 47 shift 2 48 local env_vars=("$@") 49 50 sudo -u "$username" -i bash << EOF 51# Remove any existing environment variables to avoid duplicates 52grep -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 53 54# Add environment variables 55cat >> ~/$config_file << 'CONFIG_EOF' 56 57# Environment variables managed by tinsnip 58$(printf "export %s\n" "${env_vars[@]}") 59CONFIG_EOF 60EOF 61} 62 63# Create service environment file on NFS mount with all variables needed by service 64create_service_env_file() { 65 local service_name="$1" 66 local service_env="$2" 67 local service_uid="$3" 68 local mount_point="/mnt/${service_name}-${service_env}" 69 local sheet="${TIN_SHEET:-topsheet}" 70 71 local env_file="$mount_point/.env" 72 73 log_with_prefix "Service Env" "Creating $env_file" 74 75 # Create the .env file with all service variables 76 sudo -u "${service_name}-${service_env}" tee "$env_file" > /dev/null << EOF 77# Tinsnip service environment variables 78# Generated automatically - do not edit manually 79TIN_SERVICE_NAME=$service_name 80TIN_SERVICE_ENVIRONMENT=$service_env 81TIN_SERVICE_UID=$service_uid 82TIN_SHEET=$sheet 83 84# XDG Base Directory variables (NFS-backed) 85XDG_DATA_HOME=$mount_point/data 86XDG_CONFIG_HOME=$mount_point/config 87XDG_STATE_HOME=$mount_point/state 88 89# Docker environment (set by install_docker.sh if applicable) 90# These will be added by Docker setup process 91EOF 92 93 log_with_prefix "Service Env" "Created service environment file" 94} 95 96# Create service environment loader script and integrate with shell configs 97# This creates a standalone script file to avoid shell expansion issues 98create_service_env_loader_script() { 99 local service_user="$1" 100 local script_path="/home/$service_user/.tinsnip-env-loader.sh" 101 102 log_with_prefix "Env Loader" "Creating environment loader script: $script_path" 103 104 # Create environment loader for machine metadata (post-ACT-2) 105 sudo bash -c "cat > '$script_path'" << 'EOF' 106#!/bin/bash 107# Tinsnip machine environment loader (ACT-2: centralized metadata) 108export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}" 109 110# Load machine environment variables from centralized metadata 111# Pattern: ^.+-[^-]+$ matches machinename-env (machine can have dashes, env cannot) 112if [[ "$(whoami)" =~ ^.+-[^-]+$ ]]; then 113 TIN_MACHINE_ENV_FILE="/mnt/$(whoami)/.machine/machine.env" 114 TIN_MACHINE_ENV_CACHE="$XDG_CACHE_HOME/tinsnip/$(whoami).env" 115 116 if [[ -f "$TIN_MACHINE_ENV_FILE" ]]; then 117 source "$TIN_MACHINE_ENV_FILE" 118 mkdir -p "$(dirname "$TIN_MACHINE_ENV_CACHE")" 119 cp "$TIN_MACHINE_ENV_FILE" "$TIN_MACHINE_ENV_CACHE" 2>/dev/null || true 120 elif [[ -f "$TIN_MACHINE_ENV_CACHE" ]]; then 121 source "$TIN_MACHINE_ENV_CACHE" 122 fi 123 124 # Export essential variables for Docker and tinsnip 125 if [[ -n "${TIN_MACHINE_NAME:-}" ]]; then 126 export TIN_MACHINE_NAME TIN_MACHINE_ENVIRONMENT TIN_SERVICE_UID TIN_SHEET 127 export DOCKER_HOST 128 129 # Set XDG_RUNTIME_DIR if not already set (needed for Docker socket access) 130 if [[ -z "${XDG_RUNTIME_DIR:-}" ]]; then 131 export XDG_RUNTIME_DIR="/run/user/${TIN_SERVICE_UID}" 132 fi 133 fi 134fi 135EOF 136 137 # Fix ownership and permissions 138 sudo chown "$service_user:$service_user" "$script_path" 139 sudo chmod 755 "$script_path" 140 141 # Debug: Check what the actual permissions are 142 log_with_prefix "Debug" "File permissions after setting:" 143 sudo ls -la "$script_path" || true 144 145 # Validate the loader script syntax (using root to avoid permission issues) 146 if ! sudo bash -n "$script_path" 2>/tmp/syntax_error.log; then 147 warn_with_prefix "Env Loader" "⚠️ Syntax error in loader script!" 148 log_with_prefix "Debug" "Syntax error details:" 149 sudo cat /tmp/syntax_error.log 2>/dev/null || true 150 log_with_prefix "Debug" "Script content:" 151 sudo head -10 "$script_path" 2>/dev/null || true 152 return 1 153 else 154 log_with_prefix "Env Loader" "Loader script syntax validated successfully" 155 fi 156 157 log_with_prefix "Env Loader" "Adding script to shell configurations" 158 159 # Add source line to both shell configs using sudo with explicit paths 160 log_with_prefix "Env Loader" "Updating .bashrc" 161 # Check if already added to avoid duplicates 162 if ! sudo grep -q "tinsnip-env-loader" "/home/$service_user/.bashrc" 2>/dev/null; then 163 if echo "source ~/.tinsnip-env-loader.sh" | sudo tee -a "/home/$service_user/.bashrc" > /dev/null 2>&1; then 164 sudo chown "$service_user:$service_user" "/home/$service_user/.bashrc" 165 log_with_prefix "Env Loader" "Added to .bashrc" 166 else 167 warn_with_prefix "Env Loader" "⚠️ Failed to update .bashrc" 168 fi 169 else 170 log_with_prefix "Env Loader" ".bashrc already configured" 171 fi 172 173 log_with_prefix "Env Loader" "Updating .profile" 174 # Check if already added to avoid duplicates 175 if ! sudo grep -q "tinsnip-env-loader" "/home/$service_user/.profile" 2>/dev/null; then 176 if echo "source ~/.tinsnip-env-loader.sh" | sudo tee -a "/home/$service_user/.profile" > /dev/null 2>&1; then 177 sudo chown "$service_user:$service_user" "/home/$service_user/.profile" 178 log_with_prefix "Env Loader" "Added to .profile" 179 else 180 warn_with_prefix "Env Loader" "⚠️ Failed to update .profile" 181 fi 182 else 183 log_with_prefix "Env Loader" ".profile already configured" 184 fi 185 186 # Test if the shell configs can be sourced without errors (with better debugging) 187 log_with_prefix "Env Loader" "Validating shell configurations" 188 189 # Check .bashrc 190 if ! sudo -u "$service_user" bash -n "/home/$service_user/.bashrc" 2>/dev/null; then 191 warn_with_prefix "Env Loader" "⚠️ Syntax error in .bashrc - checking content" 192 # Show last few lines for debugging 193 sudo tail -5 "/home/$service_user/.bashrc" | while read -r line; do 194 log_with_prefix "Debug" ".bashrc: $line" 195 done 2>/dev/null || true 196 fi 197 198 # Check .profile 199 if ! sudo -u "$service_user" bash -n "/home/$service_user/.profile" 2>/dev/null; then 200 warn_with_prefix "Env Loader" "⚠️ Syntax error in .profile - checking content" 201 # Show last few lines for debugging 202 sudo tail -5 "/home/$service_user/.profile" | while read -r line; do 203 log_with_prefix "Debug" ".profile: $line" 204 done 2>/dev/null || true 205 fi 206 207 log_with_prefix "Env Loader" "Environment loader script configured" 208} 209 210# Auto-discover NAS server for current sheet 211discover_nas_for_sheet() { 212 local sheet 213 sheet=$(get_sheet) 214 215 # Check if topsheet.station-prod registry is available 216 local registry_path="/mnt/station-prod/data/nas-credentials/nas-servers" 217 if [[ -f "$registry_path" ]]; then 218 # First check if explicitly registered for this sheet 219 local nas_server=$(grep "^${sheet}=" "$registry_path" 2>/dev/null | cut -d= -f2) 220 if [[ -n "$nas_server" ]]; then 221 echo "$nas_server" 222 return 0 223 fi 224 225 # Only fall back to default for registered sheets 226 # Check if this sheet exists in the sheet registry 227 local sheet_registry="/mnt/station-prod/data/sheets" 228 if [[ -f "$sheet_registry" ]] && grep -q "^${sheet}=" "$sheet_registry" 2>/dev/null; then 229 nas_server=$(grep "^default=" "$registry_path" 2>/dev/null | cut -d= -f2) 230 if [[ -n "$nas_server" ]]; then 231 echo "$nas_server" 232 return 0 233 fi 234 fi 235 fi 236 237 # Registry not available or no server found 238 return 1 239} 240