#!/bin/bash # Shared library functions for tinsnip machine setup # Color constants RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # Shared logging functions with customizable prefix log_with_prefix() { local prefix="$1" shift echo -e "${GREEN}[$prefix]${NC} $*" } error_with_prefix() { local prefix="$1" shift echo -e "${RED}[ERROR]${NC} $*" >&2 exit 1 } warn_with_prefix() { local prefix="$1" shift echo -e "${YELLOW}[WARNING]${NC} $*" } # Get namespace number from namespace name (1-9 range) # Uses deterministic hash that maps "dynamicalsystem" to 1 for backward compatibility get_namespace_number() { local namespace="${1:-dynamicalsystem}" # Hash namespace to 1-9 range echo "$namespace" | md5sum | cut -c1-1 | { read hex printf "%d\n" "0x$hex" | awk '{n=($1 % 9) + 1; print n}' } } # Find the next available service number from a registry file find_next_service_number() { local registry_path="$1" if [[ ! -f "$registry_path" ]]; then echo "1" return fi # Extract all service numbers from registry, find the highest local max_num=0 while IFS='=' read -r service_name service_num; do # Skip comments and empty lines [[ "$service_name" =~ ^#.*$ ]] || [[ -z "$service_name" ]] && continue if [[ "$service_num" =~ ^[0-9]+$ ]] && [[ "$service_num" -gt "$max_num" ]]; then max_num="$service_num" fi done < "$registry_path" # Return next available number (max + 1) echo $((max_num + 1)) } # Calculate service UID using TNSEP convention # T=1 (Docker), N=namespace number, S=service, E=environment, P=0 calculate_service_uid() { local service_name="$1" local service_env="$2" # Get namespace from environment or file local namespace="${TIN_NAMESPACE:-}" if [[ -z "$namespace" ]] && [[ -f "/etc/tinsnip-namespace" ]]; then namespace=$(cat /etc/tinsnip-namespace) fi namespace="${namespace:-dynamicalsystem}" # Get namespace number (1-9) local namespace_num=$(get_namespace_number "$namespace") # Service number mapping local service_num # Special case for station (namespace infrastructure) if [[ "$service_name" == "station" ]]; then service_num=0 else # Try to read from service registry local registry_path="/volume1/${namespace}/station/prod/service-registry" if [[ -f "$registry_path" ]]; then service_num=$(grep "^${service_name}=" "$registry_path" | cut -d= -f2) if [[ -z "$service_num" ]]; then # Service not in registry - auto-assign next available number service_num=$(find_next_service_number "$registry_path") warn_with_prefix "UID Calculation" "Service '$service_name' not in registry, auto-assigning service number $service_num" fi else # Registry doesn't exist - use fallback mapping or auto-assign case "$service_name" in gazette) service_num=1 ;; lldap) service_num=2 ;; gateway) service_num=3 ;; *) # Auto-assign starting from service number 4 service_num=4 warn_with_prefix "UID Calculation" "No registry found, auto-assigning service number $service_num for '$service_name'" ;; esac fi fi # Environment number mapping local env_num case "$service_env" in prod) env_num=0 ;; test) env_num=1 ;; *) echo "ERROR: Unknown environment: $service_env" >&2 return 1 ;; esac # Return TNSEP UID echo "1${namespace_num}${service_num}${env_num}0" } # Calculate service ports based on UID calculate_service_ports() { local service_uid="$1" local port_count="${2:-3}" local base_port=$service_uid for ((i=0; i ~/${config_file}.tmp 2>/dev/null && mv ~/${config_file}.tmp ~/$config_file || touch ~/$config_file # Add environment variables cat >> ~/$config_file << 'CONFIG_EOF' # Environment variables managed by tinsnip $(printf "export %s\n" "${env_vars[@]}") CONFIG_EOF EOF } # Create service environment file on NFS mount with all variables needed by service create_service_env_file() { local service_name="$1" local service_env="$2" local service_uid="$3" local mount_point="/mnt/${service_name}-${service_env}" local namespace="${TIN_NAMESPACE:-dynamicalsystem}" local env_file="$mount_point/.env" log_with_prefix "Service Env" "Creating $env_file" # Create the .env file with all service variables sudo -u "${service_name}-${service_env}" tee "$env_file" > /dev/null << EOF # Tinsnip service environment variables # Generated automatically - do not edit manually TIN_SERVICE_NAME=$service_name TIN_SERVICE_ENVIRONMENT=$service_env TIN_SERVICE_UID=$service_uid TIN_NAMESPACE=$namespace # XDG Base Directory variables (NFS-backed) XDG_DATA_HOME=$mount_point/data XDG_CONFIG_HOME=$mount_point/config XDG_STATE_HOME=$mount_point/state XDG_CACHE_HOME=$mount_point/cache # Docker environment (set by install_docker.sh if applicable) # These will be added by Docker setup process EOF log_with_prefix "Service Env" "Created service environment file" } # Generate shell environment loading code for .bashrc/.profile # This creates the code that loads service env with cache fallback generate_service_env_loader() { cat << 'EOF' # Tinsnip service environment loading with NFS resilience # Set XDG_CACHE_HOME first (host-based, not NFS) export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}" # Load service environment variables if [[ "\$(whoami)" =~ ^[^-]+-[^-]+\$ ]]; then # This is a service user (format: service-environment) SERVICE_ENV_FILE="/mnt/\$(whoami)/.env" TIN_SERVICE_ENV_CACHE="\$XDG_CACHE_HOME/tinsnip/\$(whoami).env" if [[ -f "$SERVICE_ENV_FILE" ]]; then # NFS available - source primary file and update cache source "$SERVICE_ENV_FILE" mkdir -p "$(dirname "$TIN_SERVICE_ENV_CACHE")" cp "$SERVICE_ENV_FILE" "$TIN_SERVICE_ENV_CACHE" 2>/dev/null || true elif [[ -f "$TIN_SERVICE_ENV_CACHE" ]]; then # NFS unavailable - use cached version source "$TIN_SERVICE_ENV_CACHE" fi fi EOF }