provisioning/bootstrap/install.sh
2026-01-08 21:22:57 +00:00

343 lines
13 KiB
Bash
Executable File

#!/usr/bin/env bash
# provisioning/bootstrap/install.sh
# Bootstrap script for provisioning platform (POSIX Bash + Nushell)
# Pure Bash implementation to avoid Nushell IR mode limitations
set -e
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
WORKSPACE_NAME="workspace_librecloud"
WORKSPACE_PATH="$PROJECT_ROOT/$WORKSPACE_NAME"
# Helper functions
print_header() {
echo -e "${GREEN}╔════════════════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║ PROVISIONING BOOTSTRAP (Bash) ║${NC}"
echo -e "${GREEN}╚════════════════════════════════════════════════════════════════╝${NC}"
}
print_stage() {
local stage="$1"
local description="$2"
echo ""
echo "$stage $description"
echo "─────────────────────────────────────────────────────────────────"
}
print_success() {
echo "$1"
}
print_warning() {
echo " ⚠️ $1"
}
print_error() {
echo "$1"
}
check_command() {
command -v "$1" &> /dev/null
}
# Main bootstrap logic
print_header
echo ""
# ════════════════════════════════════════════════════════════════════════
# STAGE 1: SYSTEM DETECTION
# ════════════════════════════════════════════════════════════════════════
print_stage "📊" "Stage 1: System Detection"
OS=$(uname -s)
ARCH=$(uname -m)
CPU_COUNT=$(sysctl -n hw.physicalcpu 2>/dev/null || nproc 2>/dev/null || echo "unknown")
# Get RAM in GB
if [[ "$OS" == "Darwin" ]]; then
MEM_GB=$(($(sysctl -n hw.memsize) / 1024 / 1024 / 1024))
else
MEM_GB=$(($(grep MemTotal /proc/meminfo | awk '{print $2}') / 1024 / 1024))
fi
echo " OS: $OS"
echo " Architecture: $ARCH"
echo " CPU Cores: $CPU_COUNT"
echo " Memory: ${MEM_GB} GB"
# Validate minimum requirements
MIN_RAM=2
if [[ $MEM_GB -lt $MIN_RAM ]]; then
print_error "Requires at least $MIN_RAM GB RAM (have $MEM_GB GB)"
exit 1
fi
print_success "System requirements met"
# ════════════════════════════════════════════════════════════════════════
# STAGE 2: DEPENDENCY CHECK
# ════════════════════════════════════════════════════════════════════════
print_stage "📦" "Stage 2: Checking Dependencies"
REQUIRED_TOOLS=("git" "docker" "rustc" "cargo" "nu")
MISSING_TOOLS=()
for tool in "${REQUIRED_TOOLS[@]}"; do
if ! check_command "$tool"; then
MISSING_TOOLS+=("$tool")
fi
done
if [[ ${#MISSING_TOOLS[@]} -gt 0 ]]; then
print_warning "Missing tools:"
for tool in "${MISSING_TOOLS[@]}"; do
echo " - $tool"
done
if [[ " ${MISSING_TOOLS[*]} " =~ " docker " ]]; then
echo ""
echo " 📥 Docker is required. Install from: https://docs.docker.com/get-docker/"
fi
if [[ " ${MISSING_TOOLS[*]} " =~ " rustc " ]]; then
echo ""
echo " 📥 Rust is required. Install from: https://rustup.rs/"
echo " Then run: rustup default stable"
fi
echo ""
print_error "Please install missing dependencies and run again"
exit 1
fi
print_success "All dependencies found"
# Show versions
echo ""
echo " Versions:"
echo " Docker: $(docker --version)"
echo " Rust: $(rustc --version)"
echo " Nushell: $(nu --version)"
# ════════════════════════════════════════════════════════════════════════
# STAGE 3: INSTALL TYPEDIALOG (Configuration Forms & Tools)
# ════════════════════════════════════════════════════════════════════════
print_stage "🎨" "Stage 3: Installing TypeDialog (Forms & Tools)"
TYPEDIALOG_INSTALLER="$PROJECT_ROOT/provisioning/scripts/install-typedialog.sh"
# Check if TypeDialog is already installed
if check_command "typedialog"; then
TYPEDIALOG_VERSION=$(typedialog --version 2>/dev/null | head -1)
print_success "TypeDialog already installed ($TYPEDIALOG_VERSION)"
else
print_warning "TypeDialog not found - installing..."
if [[ ! -f "$TYPEDIALOG_INSTALLER" ]]; then
print_error "TypeDialog installer not found at $TYPEDIALOG_INSTALLER"
exit 1
fi
# Install TypeDialog with all components (backends + tools)
if bash "$TYPEDIALOG_INSTALLER" --components all --skip-validation; then
print_success "TypeDialog installed successfully"
# Verify installation
if check_command "typedialog"; then
TYPEDIALOG_VERSION=$(typedialog --version 2>/dev/null | head -1)
echo " Installed: $TYPEDIALOG_VERSION"
fi
else
print_error "Failed to install TypeDialog"
exit 1
fi
fi
# ════════════════════════════════════════════════════════════════════════
# STAGE 4: CREATE DIRECTORY STRUCTURE
# ════════════════════════════════════════════════════════════════════════
print_stage "📁" "Stage 4: Creating Directory Structure"
mkdir -p "$WORKSPACE_PATH/config/generated/providers"
mkdir -p "$WORKSPACE_PATH/config/generated/platform"
mkdir -p "$WORKSPACE_PATH/.orchestrator/data/queue"
mkdir -p "$WORKSPACE_PATH/.kms"
mkdir -p "$WORKSPACE_PATH/.providers"
mkdir -p "$WORKSPACE_PATH/.taskservs"
mkdir -p "$WORKSPACE_PATH/.clusters"
print_success "Directory structure created"
# ════════════════════════════════════════════════════════════════════════
# STAGE 5: VALIDATE CONFIGURATION
# ════════════════════════════════════════════════════════════════════════
print_stage "⚙️ " "Stage 5: Validating Configuration"
CONFIG_NCL="$WORKSPACE_PATH/config/config.ncl"
if [[ ! -f "$CONFIG_NCL" ]]; then
print_warning "config.ncl not found at $CONFIG_NCL"
echo " Creating default config..."
TEMPLATE="$PROJECT_ROOT/workspace_librecloud/config/config.ncl"
if [[ -f "$TEMPLATE" ]]; then
cp "$TEMPLATE" "$CONFIG_NCL"
print_success "Copied from template"
else
print_error "Cannot find config template"
exit 1
fi
fi
# Validate Nickel syntax
if ! nickel typecheck "$CONFIG_NCL" > /dev/null 2>&1; then
print_error "Nickel configuration validation failed"
nickel typecheck "$CONFIG_NCL"
exit 1
fi
print_success "Configuration syntax valid"
# ════════════════════════════════════════════════════════════════════════
# STAGE 6: EXPORT CONFIGURATION
# ════════════════════════════════════════════════════════════════════════
print_stage "📤" "Stage 6: Exporting Configuration to TOML"
cd "$PROJECT_ROOT"
# Use Nushell for config export (IT requires module imports)
if nu -c "
use provisioning/core/nulib/lib_provisioning/config/export.nu *
export-all-configs '$WORKSPACE_PATH'
" 2>/dev/null; then
print_success "Configuration exported"
else
print_warning "Configuration export encountered issues (may continue)"
fi
# ════════════════════════════════════════════════════════════════════════
# STAGE 7: INITIALIZE ORCHESTRATOR
# ════════════════════════════════════════════════════════════════════════
print_stage "🚀" "Stage 7: Initializing Orchestrator Service"
ORCHESTRATOR_PATH="$PROJECT_ROOT/provisioning/platform/orchestrator"
if [[ -d "$ORCHESTRATOR_PATH" ]]; then
echo " Starting orchestrator service in background..."
if cd "$ORCHESTRATOR_PATH" && \
./scripts/start-orchestrator.nu --background \
--provisioning-path "$PROJECT_ROOT/provisioning/core/cli/provisioning" 2>/dev/null; then
print_success "Orchestrator started"
echo " 📝 Check logs: tail -f $ORCHESTRATOR_PATH/data/orchestrator.log"
else
print_warning "Orchestrator may not have started (check logs)"
fi
else
print_warning "Orchestrator not found at $ORCHESTRATOR_PATH"
fi
# ════════════════════════════════════════════════════════════════════════
# STAGE 8: VERIFY INSTALLATION
# ════════════════════════════════════════════════════════════════════════
print_stage "✅" "Stage 8: Verification"
FILES_CHECK=(
"config/generated/workspace.toml"
"config/generated/providers/upcloud.toml"
"config/generated/platform/orchestrator.toml"
)
MISSING_FILES=()
for file in "${FILES_CHECK[@]}"; do
if [[ ! -f "$WORKSPACE_PATH/$file" ]]; then
MISSING_FILES+=("$file")
fi
done
if [[ ${#MISSING_FILES[@]} -gt 0 ]]; then
print_warning "Missing generated files:"
for file in "${MISSING_FILES[@]}"; do
echo " - $file"
done
else
print_success "All configuration files generated"
fi
DIRECTORIES_CHECK=(
".orchestrator/data/queue"
".kms"
".providers"
".taskservs"
".clusters"
)
ALL_DIRS_EXIST=true
for dir in "${DIRECTORIES_CHECK[@]}"; do
if [[ ! -d "$WORKSPACE_PATH/$dir" ]]; then
ALL_DIRS_EXIST=false
break
fi
done
if $ALL_DIRS_EXIST; then
print_success "All required directories created"
else
print_warning "Some directories missing"
fi
# ════════════════════════════════════════════════════════════════════════
# FINAL STATUS
# ════════════════════════════════════════════════════════════════════════
echo ""
echo -e "${GREEN}╔════════════════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║ BOOTSTRAP COMPLETE ✅ ║${NC}"
echo -e "${GREEN}╚════════════════════════════════════════════════════════════════╝${NC}"
echo ""
echo "📍 Next Steps:"
echo ""
echo "1. Verify TypeDialog is available:"
echo " typedialog --version && typedialog-web --version"
echo ""
echo "2. Configure platform services:"
echo " $PROJECT_ROOT/provisioning/scripts/setup-platform-config.sh"
echo ""
echo "3. Verify configuration:"
echo " cat $WORKSPACE_PATH/config/config.ncl"
echo ""
echo "4. Check orchestrator is running:"
echo " curl http://localhost:9090/health"
echo ""
echo "5. Start provisioning:"
echo " provisioning server create --infra sgoyol --name web-01"
echo ""
echo "6. Monitor workflow:"
echo " provisioning workflow monitor <workflow_id>"
echo ""
echo "📚 Documentation:"
echo " - TypeDialog Forms: $PROJECT_ROOT/provisioning/.typedialog/platform/README.md"
echo " - Setup Guide: $PROJECT_ROOT/provisioning/scripts/setup-platform-config.sh --help"
echo " - User Guide: docs/user/TYPEDIALOG_PLATFORM_CONFIG_GUIDE.md"
echo " - Architecture: ARCHITECTURE_CLARIFICATION.md"
echo " - Workflow: PROVISIONING_WORKFLOW.md"
echo ""