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

544 lines
17 KiB
Text
Raw Permalink 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.

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