prvng_core/cli/providers
2025-10-07 10:32:04 +01:00

288 lines
8.9 KiB
Plaintext
Executable File

#!/usr/bin/env nu
# Provider Management CLI
# Manages cloud providers for infrastructures with KCL integration
# Author: JesusPerezLorenzo
# Date: 2025-09-29
use ../nulib/lib_provisioning/kcl_module_loader.nu *
# Main providers command
def main [] {
print_help
}
# List all available providers
export def "main list" [
--kcl # Show KCL module information (always enabled)
--format: string = "table" # Output format: table, json, yaml
] {
# Always use KCL module loader
let providers = (discover-kcl-modules "providers")
match $format {
"json" => ($providers | to json)
"yaml" => ($providers | to yaml)
_ => ($providers | table)
}
}
# Show detailed information about a provider
export def "main info" [
provider: string # Provider name
--kcl # Show KCL schema information
] {
print $"📋 Provider Information: ($provider)"
print ""
let providers = (discover-kcl-modules "providers")
let provider_info = ($providers | where name == $provider)
if ($provider_info | is-empty) {
print $"❌ Provider not found: ($provider)"
return
}
let info = ($provider_info | first)
print $" Name: ($info.name)"
print $" Type: ($info.type)"
print $" Path: ($info.path)"
print $" Has KCL: ($info.has_kcl)"
if $kcl and $info.has_kcl {
print ""
print " KCL Module:"
print $" Module Name: ($info.kcl_module_name)"
print $" KCL Path: ($info.kcl_path)"
print $" Version: ($info.version)"
print $" Edition: ($info.edition)"
# Check for kcl.mod file
let kcl_mod = ($info.kcl_path | path join "kcl.mod")
if ($kcl_mod | path exists) {
print ""
print $" kcl.mod content:"
open $kcl_mod | lines | each {|line| print $" ($line)"}
}
}
}
# Install a provider for an infrastructure
export def "main install" [
provider: string, # Provider name (e.g., upcloud, aws, local)
infra: string, # Infrastructure name or path
--version: string = "0.0.1", # Provider version
--manifest: string = "providers.manifest.yaml" # Manifest file name
] {
# Resolve infrastructure path
let infra_path = resolve-infra-path $infra
if ($infra_path | is-empty) {
print $"❌ Infrastructure not found: ($infra)"
return
}
# Use library function to install provider
install-provider $provider $infra_path --version $version
print ""
print $"💡 Next steps:"
print $" 1. Check the manifest: ($infra_path)/($manifest)"
print $" 2. Update server definitions to use ($provider)"
print $" 3. Run: kcl run defs/servers.k"
}
# Remove a provider from an infrastructure
export def "main remove" [
provider: string, # Provider name
infra: string, # Infrastructure name or path
--force # Force removal without confirmation
] {
# Resolve infrastructure path
let infra_path = resolve-infra-path $infra
if ($infra_path | is-empty) {
print $"❌ Infrastructure not found: ($infra)"
return
}
# Confirmation unless forced
if not $force {
print $"⚠️ This will remove provider ($provider) from ($infra)"
print " KCL dependencies will be updated."
let response = (input "Continue? (y/N): ")
if ($response | str downcase) != "y" {
print "❌ Cancelled"
return
}
}
# Use library function to remove provider
remove-provider $provider $infra_path
}
# List installed providers for an infrastructure
export def "main installed" [
infra: string, # Infrastructure name or path
--format: string = "table" # Output format
] {
# Resolve infrastructure path
let infra_path = resolve-infra-path $infra
if ($infra_path | is-empty) {
print $"❌ Infrastructure not found: ($infra)"
return
}
let manifest_path = ($infra_path | path join "providers.manifest.yaml")
if not ($manifest_path | path exists) {
print $"❌ No providers.manifest.yaml found in ($infra)"
return
}
let manifest = (open $manifest_path)
let providers = if ($manifest | get providers? | is-not-empty) {
$manifest | get providers
} else if ($manifest | get loaded_providers? | is-not-empty) {
$manifest | get loaded_providers
} else {
[]
}
print $"📦 Installed providers for ($infra):"
print ""
match $format {
"json" => ($providers | to json)
"yaml" => ($providers | to yaml)
_ => ($providers | table)
}
}
# Validate provider installation for an infrastructure
export def "main validate" [
infra: string # Infrastructure name or path
] {
print $"🔍 Validating providers for ($infra)..."
print ""
# Resolve infrastructure path
let infra_path = resolve-infra-path $infra
if ($infra_path | is-empty) {
print $"❌ Infrastructure not found: ($infra)"
return
}
mut validation_errors = []
# Check manifest exists
let manifest_path = ($infra_path | path join "providers.manifest.yaml")
if not ($manifest_path | path exists) {
$validation_errors = ($validation_errors | append "providers.manifest.yaml not found")
} else {
# Check each provider in manifest
let manifest = (open $manifest_path)
let providers = ($manifest | get providers)
for provider in $providers {
print $" Checking ($provider.name)..."
# Check if provider exists
let available = (discover-kcl-modules "providers" | where name == $provider.name)
if ($available | is-empty) {
$validation_errors = ($validation_errors | append $"Provider not found: ($provider.name)")
print $" ❌ Not found in extensions"
} else {
let provider_info = ($available | first)
# Check if symlink exists
let modules_dir = ($infra_path | path join ".kcl-modules")
let link_path = ($modules_dir | path join $provider_info.kcl_module_name)
if not ($link_path | path exists) {
$validation_errors = ($validation_errors | append $"Symlink missing: ($link_path)")
print $" ❌ Symlink not found"
} else {
print $" ✓ OK"
}
}
}
}
# Check kcl.mod
let kcl_mod_path = ($infra_path | path join "kcl.mod")
if not ($kcl_mod_path | path exists) {
$validation_errors = ($validation_errors | append "kcl.mod not found")
}
print ""
# Report results
if ($validation_errors | is-empty) {
print "✅ Validation passed - all providers correctly installed"
return true
} else {
print "❌ Validation failed:"
for error in $validation_errors {
print $" • ($error)"
}
return false
}
}
# Helper: Resolve infrastructure path
def resolve-infra-path [infra: string]: nothing -> string {
if ($infra | path exists) {
return $infra
}
# Try workspace/infra path
let workspace_path = $"workspace/infra/($infra)"
if ($workspace_path | path exists) {
return $workspace_path
}
# Try absolute workspace path
let abs_workspace_path = $"/Users/Akasha/project-provisioning/workspace/infra/($infra)"
if ($abs_workspace_path | path exists) {
return $abs_workspace_path
}
return ""
}
# Helper: Print help
def print_help [] {
print "Provider Management CLI"
print ""
print "Usage: providers <command> [options]"
print ""
print "COMMANDS:"
print " list [--kcl] [--format <fmt>] - List all available providers"
print " info <provider> [--kcl] - Show detailed provider information"
print " install <provider> <infra> [--version <v>] - Install provider for infrastructure"
print " remove <provider> <infra> [--force] - Remove provider from infrastructure"
print " installed <infra> [--format <fmt>] - List installed providers"
print " validate <infra> - Validate provider installation"
print ""
print "OPTIONS:"
print " --kcl Show KCL module information"
print " --format <fmt> Output format: table, json, yaml"
print " --force Skip confirmation prompts"
print " --version <v> Specify provider version (default: 0.0.1)"
print ""
print "EXAMPLES:"
print " providers list --kcl"
print " providers info upcloud --kcl"
print " providers install upcloud wuji"
print " providers installed wuji"
print " providers validate wuji"
print " providers remove aws wuji --force"
print ""
print "See also: module-loader sync-kcl"
}