provisioning/scripts/setup-platform-config.sh
2026-01-08 21:22:57 +00:00

640 lines
19 KiB
Bash
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# Platform Services Configuration Setup Script
# Generates and manages platform service configurations in provisioning/config/runtime/
#
# Usage: ./setup-platform-config.sh [options]
# ./setup-platform-config.sh --service orchestrator --mode solo
# ./setup-platform-config.sh --mode multiuser --backend web
# ./setup-platform-config.sh --list-modes
#
# Features:
# - Interactive TypeDialog configuration via provisioning/.typedialog/platform/scripts/configure.nu
# - Quick mode setup (solo, multiuser, cicd, enterprise) from defaults
# - Automatic TOML export for Rust service consumption
# - Runtime config detection and management (clean, update, preserve)
set -euo pipefail
# Ensure TypeDialog is installed
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/ensure-typedialog.sh" || true
# Check TypeDialog availability
if ! command -v typedialog &> /dev/null; then
echo -e "\033[1;33m⚠ TypeDialog not found. Attempting installation...\033[0m"
ensure_typedialog_installed true || {
echo -e "\033[0;31m❌ Failed to install TypeDialog\033[0m"
exit 1
}
fi
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Script paths
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
TYPEDIALOG_SCRIPTS="${PROJECT_ROOT}/.typedialog/platform/scripts"
SCHEMAS_PLATFORM="${PROJECT_ROOT}/schemas/platform"
CONFIG_RUNTIME="${PROJECT_ROOT}/config/runtime"
CONFIG_GENERATED="${CONFIG_RUNTIME}/generated"
# Available services and modes
SERVICES=("orchestrator" "control-center" "mcp-server" "vault-service" "extension-registry" "rag" "ai-service" "provisioning-daemon")
MODES=("solo" "multiuser" "cicd" "enterprise")
# Default values
BACKEND="${BACKEND:-web}"
SERVICE=""
MODE=""
ACTION=""
FORCE=false
# ============================================================================
# Helper Functions
# ============================================================================
print_header() {
echo -e "${BLUE}════════════════════════════════════════════════════════════${NC}"
echo -e "${BLUE}$1${NC}"
echo -e "${BLUE}════════════════════════════════════════════════════════════${NC}"
}
print_info() {
echo -e "${BLUE} $1${NC}"
}
print_success() {
echo -e "${GREEN}$1${NC}"
}
print_warning() {
echo -e "${YELLOW}⚠️ $1${NC}"
}
print_error() {
echo -e "${RED}$1${NC}" >&2
}
# Check if directory/file exists
check_exists() {
if [[ ! -e "$1" ]]; then
print_error "Not found: $1"
return 1
fi
}
# ============================================================================
# Service/Mode Validation
# ============================================================================
validate_service() {
local service="$1"
if [[ ! " ${SERVICES[*]} " =~ " ${service} " ]]; then
print_error "Invalid service: $service"
echo "Valid services: ${SERVICES[*]}"
return 1
fi
}
validate_mode() {
local mode="$1"
if [[ ! " ${MODES[*]} " =~ " ${mode} " ]]; then
print_error "Invalid mode: $mode"
echo "Valid modes: ${MODES[*]}"
return 1
fi
}
# ============================================================================
# Directory Setup
# ============================================================================
ensure_runtime_dir() {
if [[ ! -d "$CONFIG_RUNTIME" ]]; then
print_info "Creating runtime config directory: $CONFIG_RUNTIME"
mkdir -p "$CONFIG_RUNTIME" "$CONFIG_GENERATED"
fi
# Create .gitignore if not present
if [[ ! -f "$CONFIG_RUNTIME/.gitignore" ]]; then
cat > "$CONFIG_RUNTIME/.gitignore" <<EOF
# Runtime configurations (private/deployment-specific)
*.ncl
*.toml
# Generated artifacts
generated/
# Backup files
*.bak
*.backup
EOF
print_info "Created .gitignore in $CONFIG_RUNTIME"
fi
}
# ============================================================================
# Config Detection & Management
# ============================================================================
detect_runtime_config() {
# Check if any runtime config exists
if ls "$CONFIG_RUNTIME"/*.ncl 1>/dev/null 2>&1; then
echo "existing"
return 0
fi
echo "empty"
return 0
}
list_runtime_services() {
local services=()
for file in "$CONFIG_RUNTIME"/*.ncl; do
if [[ -f "$file" ]]; then
local basename=$(basename "$file" .ncl)
services+=("$basename")
fi
done
if [[ ${#services[@]} -gt 0 ]]; then
printf '%s\n' "${services[@]}"
fi
}
# ============================================================================
# Interactive Prompts
# ============================================================================
prompt_action_existing_config() {
echo ""
print_warning "Runtime configuration already exists in: $CONFIG_RUNTIME"
echo ""
echo "Choose action:"
echo " 1) Clean up and start fresh (removes all .ncl and .toml files)"
echo " 2) Use TypeDialog to update configuration"
echo " 3) Setup quick mode (solo/multiuser/cicd/enterprise)"
echo " 4) List existing configurations"
echo " 5) Cancel"
echo ""
read -rp "Enter choice [1-5]: " choice
case "$choice" in
1) ACTION="clean-start" ;;
2) ACTION="typedialog" ;;
3) ACTION="quick-mode" ;;
4) ACTION="list" ;;
5) print_info "Cancelled."; exit 0 ;;
*) print_error "Invalid choice"; exit 1 ;;
esac
}
prompt_action_empty_config() {
echo ""
echo "Choose how to setup platform configuration:"
echo " 1) Interactive TypeDialog (recommended, with UI form)"
echo " 2) Quick mode setup (choose solo/multiuser/cicd/enterprise)"
echo " 3) Cancel"
echo ""
read -rp "Enter choice [1-3]: " choice
case "$choice" in
1) ACTION="typedialog" ;;
2) ACTION="quick-mode" ;;
3) print_info "Cancelled."; exit 0 ;;
*) print_error "Invalid choice"; exit 1 ;;
esac
}
prompt_for_service() {
echo ""
echo "Select service to configure:"
for i in "${!SERVICES[@]}"; do
echo " $((i+1))) ${SERVICES[$i]}"
done
echo " $((${#SERVICES[@]}+1))) Configure all services"
echo ""
read -rp "Enter choice [1-$((${#SERVICES[@]}+1))]: " choice
if [[ "$choice" == "$((${#SERVICES[@]}+1))" ]]; then
SERVICE="all"
else
SERVICE="${SERVICES[$((choice-1))]}"
fi
}
prompt_for_mode() {
echo ""
echo "Select deployment mode:"
for i in "${!MODES[@]}"; do
echo " $((i+1))) ${MODES[$i]}"
done
echo ""
read -rp "Enter choice [1-${#MODES[@]}]: " choice
MODE="${MODES[$((choice-1))]}"
}
prompt_for_backend() {
echo ""
echo "Select TypeDialog backend:"
echo " 1) web (browser-based, recommended)"
echo " 2) tui (terminal UI)"
echo " 3) cli (command-line)"
echo ""
read -rp "Enter choice [1-3]: " choice
case "$choice" in
1) BACKEND="web" ;;
2) BACKEND="tui" ;;
3) BACKEND="cli" ;;
*) print_error "Invalid choice"; exit 1 ;;
esac
}
# ============================================================================
# Configuration Generation
# ============================================================================
generate_toml_for_service() {
local service="$1"
local mode="$2"
local ncl_file="${CONFIG_RUNTIME}/${service}.${mode}.ncl"
if [[ ! -f "$ncl_file" ]]; then
print_warning "Nickel config not found: $ncl_file"
return 1
fi
print_info "Exporting TOML for $service ($mode)..."
local toml_file="${CONFIG_GENERATED}/${service}.${mode}.toml"
# Generate TOML from Nickel
if nickel export --format toml "$ncl_file" > "$toml_file" 2>/dev/null; then
print_success "Generated: $toml_file"
return 0
else
print_error "Failed to generate TOML for $service ($mode)"
return 1
fi
}
generate_all_tomls() {
echo ""
print_header "Generating TOML Exports"
local generated_count=0
local failed_count=0
# Scan for all .ncl files in runtime
for ncl_file in "$CONFIG_RUNTIME"/*.ncl; do
if [[ -f "$ncl_file" ]]; then
local basename=$(basename "$ncl_file" .ncl)
local service="${basename%.*}" # Remove mode suffix
local mode="${basename##*.}" # Extract mode
if generate_toml_for_service "$service" "$mode"; then
((generated_count++))
else
((failed_count++))
fi
fi
done
echo ""
print_success "Generated $generated_count TOML files"
if [[ $failed_count -gt 0 ]]; then
print_warning "$failed_count files failed"
fi
}
# ============================================================================
# TypeDialog Configuration
# ============================================================================
configure_via_typedialog() {
check_exists "$TYPEDIALOG_SCRIPTS/configure.nu" || return 1
echo ""
print_header "TypeDialog Configuration"
# Prompt for service if not provided
if [[ -z "$SERVICE" ]]; then
prompt_for_service
else
validate_service "$SERVICE" || return 1
fi
# Prompt for mode if not provided
if [[ -z "$MODE" ]]; then
prompt_for_mode
else
validate_mode "$MODE" || return 1
fi
# Prompt for backend if using web
if [[ "$BACKEND" == "default" ]]; then
prompt_for_backend
fi
print_info "Launching TypeDialog ($BACKEND backend) for $SERVICE ($MODE)..."
echo ""
# Run TypeDialog via Nushell script
if nu "$TYPEDIALOG_SCRIPTS/configure.nu" "$SERVICE" "$MODE" --backend "$BACKEND"; then
print_success "Configuration completed for $SERVICE"
# Auto-generate TOML
generate_toml_for_service "$SERVICE" "$MODE"
print_info ""
print_info "Next steps:"
print_info " - Review config: cat $CONFIG_RUNTIME/$SERVICE.$MODE.ncl"
print_info " - Export TOML: $TYPEDIALOG_SCRIPTS/generate-configs.nu $SERVICE $MODE"
print_info " - Run service: ORCHESTRATOR_MODE=$MODE cargo run -p $SERVICE"
return 0
else
print_error "TypeDialog configuration cancelled or failed"
return 1
fi
}
# ============================================================================
# Quick Mode Setup (from defaults)
# ============================================================================
setup_quick_mode() {
echo ""
print_header "Quick Mode Setup"
# Prompt for mode if not provided
if [[ -z "$MODE" ]]; then
prompt_for_mode
else
validate_mode "$MODE" || return 1
fi
print_info "Setting up all services for mode: $MODE"
echo ""
local created_count=0
local failed_count=0
# Create config for each service by composing defaults + mode overlay
for service in "${SERVICES[@]}"; do
local ncl_file="$CONFIG_RUNTIME/${service}.${MODE}.ncl"
local schema_file="$SCHEMAS_PLATFORM/schemas/${service}.ncl"
local defaults_file="$SCHEMAS_PLATFORM/defaults/${service}-defaults.ncl"
local mode_defaults="$SCHEMAS_PLATFORM/defaults/deployment/${MODE}-defaults.ncl"
if [[ ! -f "$schema_file" ]] || [[ ! -f "$defaults_file" ]]; then
print_warning "Schema or defaults not found for $service (skipping)"
((failed_count++))
continue
fi
# Create Nickel config that composes: schema + defaults + mode overlay
cat > "$ncl_file" <<'EOF'
# Generated configuration for SERVICE (MODE mode)
# Generated: $(date -u +"%Y-%m-%dT%H:%M:%SZ")
# DO NOT EDIT MANUALLY - Re-run setup-platform-config.sh to update
#
# This configuration is composed from:
# - Schema: provisioning/schemas/platform/schemas/SERVICE.ncl
# - Defaults: provisioning/schemas/platform/defaults/SERVICE-defaults.ncl
# - Mode: provisioning/schemas/platform/defaults/deployment/MODE-defaults.ncl
let helpers = import "provisioning/schemas/platform/common/helpers.ncl"
let schema = import "provisioning/schemas/platform/schemas/SERVICE.ncl"
let defaults = import "provisioning/schemas/platform/defaults/SERVICE-defaults.ncl"
let mode_config = import "provisioning/schemas/platform/defaults/deployment/MODE-defaults.ncl"
# Compose: base defaults + mode overlay + validators
helpers.compose_config defaults mode_config {}
EOF
# Replace placeholders with actual values
sed -i.bak "s|SERVICE|$service|g" "$ncl_file"
sed -i.bak "s|MODE|$MODE|g" "$ncl_file"
rm -f "${ncl_file}.bak"
if [[ -f "$ncl_file" ]]; then
print_success "Created config: $service ($MODE)"
# Generate TOML
if generate_toml_for_service "$service" "$MODE"; then
((created_count++))
else
((failed_count++))
fi
fi
done
echo ""
print_success "Setup complete: $created_count services configured"
if [[ $failed_count -gt 0 ]]; then
print_warning "$failed_count services failed"
fi
}
# ============================================================================
# Cleanup Operations
# ============================================================================
cleanup_runtime_config() {
echo ""
print_warning "This will delete all runtime configurations"
read -rp "Are you sure? (yes/no): " confirm
if [[ "$confirm" != "yes" ]]; then
print_info "Cancelled"
return 0
fi
print_info "Removing runtime configurations..."
rm -f "$CONFIG_RUNTIME"/*.ncl "$CONFIG_GENERATED"/*.toml
print_success "Cleanup complete"
}
# ============================================================================
# Listing Operations
# ============================================================================
list_deployment_modes() {
echo ""
print_info "Available deployment modes:"
for mode in "${MODES[@]}"; do
echo " - $mode"
done
}
list_available_services() {
echo ""
print_info "Available services:"
for service in "${SERVICES[@]}"; do
echo " - $service"
done
}
list_runtime_configs() {
echo ""
print_header "Runtime Configurations"
local status=$(detect_runtime_config)
if [[ "$status" == "empty" ]]; then
print_info "No runtime configurations found"
return 0
fi
echo "Configured services:"
list_runtime_services | while read -r service; do
echo "$service"
done
echo ""
echo "Location: $CONFIG_RUNTIME"
}
# ============================================================================
# Help Text
# ============================================================================
show_help() {
cat <<EOF
${BLUE}Platform Services Configuration Setup${NC}
Usage: $(basename "$0") [OPTIONS]
Options:
-s, --service SERVICE Configure specific service (orchestrator, control-center, etc.)
-m, --mode MODE Set deployment mode (solo, multiuser, cicd, enterprise)
-b, --backend BACKEND TypeDialog backend: web (default), tui, cli
--typedialog Use TypeDialog for configuration
--quick-mode Use quick mode setup from defaults
--list-modes List available deployment modes
--list-services List available services
--list-configs List existing runtime configurations
--clean Remove all runtime configurations
--generate-toml Generate TOML files from Nickel configs
-h, --help Show this help message
Examples:
# Interactive setup (prompts for choices)
$(basename "$0")
# Configure specific service via TypeDialog
$(basename "$0") --service orchestrator --mode solo --backend web
# Quick setup for all services in solo mode
$(basename "$0") --quick-mode --mode solo
# List available modes
$(basename "$0") --list-modes
# Regenerate TOML files
$(basename "$0") --generate-toml
Environment Variables:
TYPEDIALOG_BACKEND Override TypeDialog backend (web, tui, cli)
EOF
}
# ============================================================================
# Main Entry Point
# ============================================================================
main() {
# Parse command-line arguments
while [[ $# -gt 0 ]]; do
case "$1" in
-s|--service) SERVICE="$2"; shift 2 ;;
-m|--mode) MODE="$2"; shift 2 ;;
-b|--backend) BACKEND="$2"; shift 2 ;;
--typedialog) ACTION="typedialog"; shift ;;
--quick-mode) ACTION="quick-mode"; shift ;;
--list-modes) ACTION="list-modes"; shift ;;
--list-services) ACTION="list-services"; shift ;;
--list-configs) ACTION="list"; shift ;;
--clean) ACTION="clean"; shift ;;
--generate-toml) ACTION="generate-toml"; shift ;;
--force) FORCE=true; shift ;;
-h|--help) show_help; exit 0 ;;
*) print_error "Unknown option: $1"; show_help; exit 1 ;;
esac
done
# Ensure directories exist
ensure_runtime_dir
# Check for required tools
if ! command -v nickel &>/dev/null; then
print_error "Nickel not found. Please install Nickel (https://nickel-lang.org/)"
exit 1
fi
if ! command -v nu &>/dev/null; then
print_error "Nushell not found. Please install Nushell"
exit 1
fi
# Execute requested action
case "${ACTION:-}" in
typedialog)
configure_via_typedialog || exit 1
;;
quick-mode)
setup_quick_mode || exit 1
;;
clean)
cleanup_runtime_config
;;
list)
list_runtime_configs
;;
list-modes)
list_deployment_modes
;;
list-services)
list_available_services
;;
generate-toml)
generate_all_tomls
;;
*)
# No action specified - interactive mode
print_header "Platform Services Configuration Setup"
local runtime_status=$(detect_runtime_config)
if [[ "$runtime_status" == "existing" ]]; then
prompt_action_existing_config
else
prompt_action_empty_config
fi
# Execute chosen action
case "$ACTION" in
typedialog) configure_via_typedialog || exit 1 ;;
quick-mode) setup_quick_mode || exit 1 ;;
clean) cleanup_runtime_config ;;
list) list_runtime_configs ;;
*) print_error "No action selected"; exit 1 ;;
esac
;;
esac
echo ""
print_success "Done!"
}
# Run main function
main "$@"