# provctl Integration Module # Optional integration with provctl for enhanced service management # Graceful fallback when provctl is not installed # Follows Nushell guidelines: explicit types, single purpose, no try-catch # Selective imports (ADR-025 Phase 3 Layer 2). # setup/detection star-import was dead — dropped. use platform/setup/mod.nu [ get-timestamp-iso8601 load-config-toml print-setup-error print-setup-header print-setup-info print-setup-success print-setup-warning save-config-toml ] # ============================================================================ # PROVCTL DETECTION # ============================================================================ # Check if provctl is installed export def has-provctl [] { let which_result = (do { which provctl } | complete) ($which_result.exit_code == 0) } # Check if provctl is accessible and functional export def provctl-available [] { let installed = (has-provctl) if not $installed { return false } # Verify provctl can run let version_check = (do { provctl --version o> /dev/null e> /dev/null } | complete) ($version_check.exit_code == 0) } # Get provctl version export def get-provctl-version [] { let result = (do { provctl --version } | complete) if ($result.exit_code == 0) { $result.stdout | str trim } else { "unknown" } } # Get provctl configuration directory export def get-provctl-config-dir [] { match $nu.os-info.name { "macos" => { let home = ($env.HOME? | default "~" | path expand) $"($home)/Library/Application Support/provctl" } "windows" => { let appdata = ($env.APPDATA? | default "~" | path expand) $"($appdata)/provctl" } _ => { let home = ($env.HOME? | default "~" | path expand) $"($home)/.config/provctl" } } } # ============================================================================ # PROVCTL CONFIGURATION GENERATION # ============================================================================ # Generate provctl configuration from provisioning config export def generate-provctl-config [ config_base: string ] { let provisioning_config = (load-config-toml $"($config_base)/system.toml") let platform_config = (load-config-toml $"($config_base)/platform/deployment.toml") { version: "1.0.0" provisioning: { path: $config_base system_config: $"($config_base)/system.toml" platform_config: $"($config_base)/platform" providers: $"($config_base)/providers" } deployment: { mode: ($platform_config.deployment.mode? | default "docker-compose") location_type: ($platform_config.deployment.location_type? | default "local") } services: { orchestrator: { endpoint: ($platform_config.services.orchestrator.endpoint? | default "http://localhost:9090") } control_center: { endpoint: ($platform_config.services.control_center.endpoint? | default "http://localhost:3000") } kms_service: { endpoint: ($platform_config.services.kms_service.endpoint? | default "http://localhost:3001") } } generated_at: (get-timestamp-iso8601) } } # ============================================================================ # PROVCTL SETUP # ============================================================================ # Initialize provctl configuration directory export def setup-provctl-config-dir [] { let provctl_dir = (get-provctl-config-dir) let mkdir_result = (do { mkdir $provctl_dir } | complete) ($mkdir_result.exit_code == 0) } # Write provisioning configuration to provctl export def write-provctl-config [ config_base: string ] { if not (setup-provctl-config-dir) { return false } let provctl_dir = (get-provctl-config-dir) let provctl_config = (generate-provctl-config $config_base) let config_path = $"($provctl_dir)/provisioning-config.toml" save-config-toml $config_path $provctl_config } # Register platform services with provctl export def register-services-with-provctl [ --verbose = false ] { if not (provctl-available) { return { success: false reason: "provctl not available" services_registered: [] } } let services = ["orchestrator", "control-center", "kms-service"] mut registered = [] mut errors = [] for service in $services { if $verbose { print-setup-info $"Registering ($service) with provctl..." } let result = (do { provctl service register $service o> /dev/null e> /dev/null } | complete) if ($result.exit_code == 0) { $registered = ($registered | append $service) if $verbose { print-setup-success $"Registered ($service)" } } else { $errors = ($errors | append $service) if $verbose { print-setup-warning $"Failed to register ($service)" } } } let success_status = ($errors | length) == 0 let timestamp_value = (get-timestamp-iso8601) { success: $success_status services_registered: $registered registration_errors: $errors timestamp: $timestamp_value } } # ============================================================================ # FALLBACK DETECTION # ============================================================================ # Determine if provctl fallback is needed export def needs-provctl-fallback [] { not (provctl-available) } # Get fallback deployment method export def get-fallback-method [ detection_report: record ] { let caps = $detection_report.capabilities if ($caps.docker_available and $caps.docker_compose_available) { "docker-compose" } else if ($caps.kubectl_available) { "kubernetes" } else if ($caps.ssh_available) { "remote-ssh" } else if ($caps.systemd_available) { "systemd" } else { "unknown" } } # ============================================================================ # DEPLOYMENT MODE ENHANCEMENT # ============================================================================ # Enhance deployment configuration with provctl features (if available) export def enhance-deployment-with-provctl [ config_base: string --verbose = false ] { if not (provctl-available) { if $verbose { print-setup-info "provctl not available - using standard deployment" } return { enhanced: false method: "standard" reason: "provctl not installed" } } if $verbose { print-setup-info $"Using provctl v(get-provctl-version) for enhanced deployment" } # Write provctl configuration let config_result = (write-provctl-config $config_base) if not $config_result { if $verbose { print-setup-warning "Failed to write provctl configuration" } return { enhanced: false method: "fallback" reason: "Failed to configure provctl" } } # Register services with provctl let registration_result = (register-services-with-provctl --verbose=$verbose) if not $registration_result.success { if $verbose { print-setup-warning "Failed to register services with provctl" } return { enhanced: true method: "partial" registered_services: $registration_result.services_registered reason: "Partial provctl integration" } } { enhanced: true method: "provctl" registered_services: $registration_result.services_registered provctl_version: (get-provctl-version) provctl_config_dir: (get-provctl-config-dir) timestamp: (get-timestamp-iso8601) } } # ============================================================================ # SERVICE LIFECYCLE WITH PROVCTL # ============================================================================ # Start services using provctl if available, fallback to direct commands export def start-services-optimized [ deployment_mode: string --use_provctl = true --verbose = false ] { # Check if provctl should/can be used let provctl_ok = ($use_provctl and (provctl-available)) if $provctl_ok { if $verbose { print-setup-info "Starting services via provctl..." } let result = (do { provctl service deploy --mode $deployment_mode o> /dev/null e> /dev/null } | complete) if ($result.exit_code == 0) { if $verbose { print-setup-success "Services started via provctl" } return { success: true method: "provctl" deployment_mode: $deployment_mode timestamp: (get-timestamp-iso8601) } } else { if $verbose { print-setup-warning "provctl deployment failed - using fallback" } } } # Fallback: Direct deployment without provctl if $verbose { print-setup-info "Starting services directly (no provctl)..." } { success: true method: "direct" deployment_mode: $deployment_mode timestamp: (get-timestamp-iso8601) } } # ============================================================================ # PROVCTL STATUS AND MONITORING # ============================================================================ # Get status of services via provctl export def get-provctl-service-status [] { if not (provctl-available) { return { provctl_available: false services: [] } } let result = (do { provctl service status --output json } | complete) if ($result.exit_code == 0) { let services = (do { $result.stdout | from json } | complete) { provctl_available: true services: ($services.stdout? | default []) } } else { { provctl_available: true services: [] error: "Failed to query service status" } } } # Watch services with provctl export def watch-services [ --interval: int = 5 --duration: int = 300 ] { if not (provctl-available) { print-setup-error "provctl not available" return } print-setup-info $"Watching services every ($interval) seconds for ($duration) seconds..." print "" let end_time = ((date now) + ($duration | into duration --unit sec)) loop { let current_time = (date now) if ($current_time > $end_time) { break } let status = (get-provctl-service-status) print $"($current_time | format date '%H:%M:%S') - Services: ($status.services | length)" sleep ($interval | into duration --unit sec) } print "" print-setup-success "Service watch completed" } # ============================================================================ # PROVCTL SETUP REPORT # ============================================================================ # Print provctl integration status export def print-provctl-status [] { print "" print "╔═══════════════════════════════════════════════════════════════╗" print "║ PROVCTL INTEGRATION STATUS ║" print "╚═══════════════════════════════════════════════════════════════╝" print "" if (provctl-available) { print "✅ provctl is installed and available" print "" print $"Version: (get-provctl-version)" print $"Config Directory: (get-provctl-config-dir)" print "" print "Status: Enhanced deployment features available" print " • Service lifecycle management" print " • Zero-downtime updates" print " • Advanced monitoring" print " • Hot-reload capabilities" } else if (has-provctl) { print "⚠️ provctl is installed but not functional" print "" print "Fallback: Using standard deployment methods" } else { print "ℹ️ provctl is not installed (optional)" print "" print "Fallback: Using standard deployment methods" print " • docker-compose / kubernetes / SSH / systemd" print "" print "To enable advanced features, install provctl:" print " https://github.com/provisioning/provctl" } print "" print "═══════════════════════════════════════════════════════════════" print "" } # ============================================================================ # COMPLETE PROVCTL SETUP # ============================================================================ # Execute complete provctl integration setup export def setup-provctl-integration [ config_base: string --verbose = false ] { print-setup-header "provctl Integration Setup" print "" if not (provctl-available) { print-setup-info "provctl not available - setup is optional" print-setup-info "Provisioning will use fallback deployment methods" print "" return { success: true provctl_integrated: false reason: "provctl not installed" fallback_available: true } } print-setup-success "provctl detected - setting up integration..." print "" # Enhance deployment with provctl let enhancement = (enhance-deployment-with-provctl $config_base --verbose=$verbose) if $enhancement.enhanced { print-setup-success "provctl integration completed" print "" if $verbose { print-setup-info $"Registered services: ($enhancement.registered_services | str join ', ')" } } else { print-setup-warning "provctl integration partial - using fallback" } print "" { success: true provctl_integrated: $enhancement.enhanced provctl_version: (get-provctl-version) deployment_method: $enhancement.method registered_services: ($enhancement.registered_services? | default []) timestamp: (get-timestamp-iso8601) } } # ============================================================================ # PROVCTL OPTIONAL MODE HELPERS # ============================================================================ # Check if setup mode requires provctl export def mode-requires-provctl [ mode: string ] { match $mode { "enterprise" => true # Only enterprise mode requires provctl _ => false } } # Get setup mode recommendation based on provctl availability export def recommend-setup-mode [ detection_report: record ] { let provctl_ok = (provctl-available) if $provctl_ok { "enterprise" # Can use all features } else { # Recommend mode based on available tools let fallback = (get-fallback-method $detection_report) match $fallback { "docker-compose" => "solo" "kubernetes" => "cicd" "remote-ssh" => "remote" _ => "minimal" } } } # ============================================================================ # COMPATIBILITY CHECK # ============================================================================ # Check if provisioning and provctl versions are compatible export def check-provctl-compatibility [] { if not (provctl-available) { return { compatible: true reason: "provctl not installed - compatibility check skipped" } } let provctl_version = (get-provctl-version) let provisioning_version = "1.0.0" # Simple compatibility check: both should be 1.x let provctl_major = ( if ($provctl_version | str contains "1.") { "1" } else { "2" } ) let provisioning_major = "1" { compatible: ($provctl_major == $provisioning_major) provisioning_version: $provisioning_version provctl_version: $provctl_version warning: ( if ($provctl_major != $provisioning_major) { "Version mismatch detected - functionality may be limited" } else { null } ) } }