#!/bin/bash # UID and port calculation functions for tinsnip SMEP scheme # Source core functions LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$LIB_DIR/core.sh" source "$LIB_DIR/registry.sh" # Parse machine environment name into service and environment components # Handles service names with hyphens (e.g., bsky-pds-dev → service=bsky-pds, env=dev) # Outputs two lines: service name, then environment name parse_machine_name() { local machine_name="$1" # Known environments (must match calculate_machine_uid) local environments="prod|test|dev|staging|demo|qa|uat|preview|canary|local" # Match the last occurrence of - if [[ "$machine_name" =~ ^(.+)-(${environments})$ ]]; then echo "${BASH_REMATCH[1]}" # service name echo "${BASH_REMATCH[2]}" # environment return 0 else return 1 fi } # Get sheet number from registry get_sheet_number() { local sheet="${1:-${TIN_SHEET:-topsheet}}" # Reserve sheet 5 for the tinsnip topsheet if [[ "$sheet" == "topsheet" ]]; then echo "5" return fi # Look up sheet in registry local registry_path=$(get_sheet_registry_path) if [[ -f "$registry_path" ]]; then local number=$(grep "^${sheet}=" "$registry_path" | cut -d= -f2) if [[ -n "$number" ]]; then echo "$number" return fi fi # Sheet not in registry - error error_with_prefix "Sheet" "Sheet '$sheet' not registered" error_with_prefix "Sheet" "Register with: tin sheet add $sheet " return 1 } # Get sheet name from UID (reverse lookup) get_sheet_from_uid() { local uid="$1" # Extract sheet number from UID (first digit of 5-digit UID) local sheet_num="${uid:0:1}" # Special case for topsheet (sheet number 5) if [[ "$sheet_num" == "5" ]]; then echo "topsheet" return 0 fi # Look up sheet name in registry local registry_path=$(get_sheet_registry_path) if [[ -f "$registry_path" ]]; then local sheet_name=$(grep "=${sheet_num}$" "$registry_path" | cut -d= -f1) if [[ -n "$sheet_name" ]]; then echo "$sheet_name" return 0 fi fi # Sheet not found - default to topsheet as fallback warn_with_prefix "UID" "Could not find sheet for UID $uid (sheet number $sheet_num)" echo "topsheet" return 1 } # Get path to global sheet registry get_sheet_registry_path() { echo "/mnt/station-prod/data/sheets" } # Find the next available sheet number from the registry (1-4 range, 5 reserved) find_next_sheet_number() { local registry_path=$(get_sheet_registry_path) if [[ ! -f "$registry_path" ]]; then echo "1" # First available if no registry return fi # Find highest assigned number local max_num=0 while IFS='=' read -r sheet_name sheet_num; do # Skip comments and empty lines [[ "$sheet_name" =~ ^#.*$ ]] || [[ -z "$sheet_name" ]] && continue # Skip topsheet (reserved at 5) [[ "$sheet_name" == "topsheet" ]] && continue # Convert to integer and track max (handle invalid numbers) if [[ "$sheet_num" =~ ^[0-9]+$ ]]; then local num_int=$((10#$sheet_num)) if [[ "$num_int" -gt "$max_num" && "$num_int" -le 4 ]]; then max_num="$num_int" fi fi done < "$registry_path" # Return next available number (max + 1), capped at 4 local next_num=$((max_num + 1)) if [[ "$next_num" -gt 4 ]]; then echo "ERROR: Sheet registry full (range 1-4, 5 reserved)" >&2 return 1 fi echo "$next_num" } # Find the next available machine number from a registry file (now supports 2-digit format) find_next_machine_number() { local registry_path="$1" if [[ ! -f "$registry_path" ]]; then echo "1" # Will be formatted as "01" by caller return fi # Extract all machine numbers from registry, find the highest local max_num=0 while IFS='=' read -r machine_name machine_num; do # Skip comments and empty lines [[ "$machine_name" =~ ^#.*$ ]] || [[ -z "$machine_name" ]] && continue # Convert machine_num to integer (handles both "1" and "01" formats) local num_int if [[ -n "$machine_num" ]] && num_int=$((10#$machine_num)) 2>/dev/null; then : # Success else continue fi if [[ "$num_int" -gt "$max_num" ]]; then max_num="$num_int" fi done < "$registry_path" # Return next available number (max + 1), capped at 99 local next_num=$((max_num + 1)) if [[ "$next_num" -gt 99 ]]; then return 1 fi echo "$next_num" } # Calculate machine UID using SMEP convention # S=sheet number, M=machine (2-digit), E=environment, P=port index calculate_machine_uid() { local machine_name="$1" local machine_env="$2" local port_index="${3:-0}" # Optional port index, defaults to 0 # Get sheet from environment or file local sheet="${TIN_SHEET:-}" if [[ -z "$sheet" ]] && [[ -f "/etc/tinsnip-sheet" ]]; then sheet=$(cat /etc/tinsnip-sheet) fi sheet="${sheet:-${TIN_SHEET:-topsheet}}" # Get sheet number (1-9) local sheet_num=$(get_sheet_number "$sheet") # Machine number mapping (now 2-digit) local machine_num # Special case for station (sheet infrastructure) if [[ "$machine_name" == "station" ]]; then machine_num=0 else # Try to read from sheet-specific machine registry local registry_path="/mnt/station-prod/data/machines/$sheet/registry" if [[ -f "$registry_path" ]]; then machine_num=$(grep "^${machine_name}=" "$registry_path" | head -1 | cut -d= -f2) if [[ -n "$machine_num" ]]; then # Convert to decimal to avoid octal interpretation issues machine_num=$((10#$machine_num)) else # Machine not in registry - auto-assign next available number local next_num=$(find_next_machine_number "$registry_path") machine_num=$next_num warn_with_prefix "UID Calculation" "Machine '$machine_name' not in registry, auto-assigning machine number $machine_num" # Auto-register the machine if register_machine "$machine_name" "$(printf "%02d" "$machine_num")" "$sheet" 2>/dev/null; then log_with_prefix "UID Calculation" "Auto-registered $machine_name=$machine_num in sheet '$sheet'" fi fi else # Registry doesn't exist - sheet not registered error_with_prefix "UID Calculation" "Machine registry not found: $registry_path" error_with_prefix "UID Calculation" "Register sheet first: tin sheet create $sheet" return 1 fi fi # Environment number mapping (expanded to 0-9) local env_num case "$machine_env" in prod) env_num=0 ;; test) env_num=1 ;; dev) env_num=2 ;; staging) env_num=3 ;; demo) env_num=4 ;; qa) env_num=5 ;; uat) env_num=6 ;; preview) env_num=7 ;; canary) env_num=8 ;; local) env_num=9 ;; *) echo "ERROR: Unknown environment: $machine_env (supported: prod,test,dev,staging,demo,qa,uat,preview,canary,local)" >&2 return 1 ;; esac # Validate port index (0-9) if [[ ! "$port_index" =~ ^[0-9]$ ]]; then echo "ERROR: Port index must be 0-9, got: $port_index" >&2 return 1 fi # Return SMEP UID: S-M-E-P format printf "%d%02d%d%d\n" "$sheet_num" "$machine_num" "$env_num" "$port_index" } # Calculate machine ports based on UID calculate_machine_ports() { local machine_uid="$1" local port_count="${2:-3}" local base_port=$machine_uid for ((i=0; i