provisioning-core/nulib/platform/setup/provctl_integration.nu

545 lines
17 KiB
Text
Raw Permalink Normal View History

# 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
}
)
}
}