271 lines
8.6 KiB
Plaintext
271 lines
8.6 KiB
Plaintext
|
|
#!/usr/bin/env nu
|
||
|
|
|
||
|
|
# Provider Loader System
|
||
|
|
# Loads selected providers into workspace or infrastructure (Layer 2 or Layer 3)
|
||
|
|
|
||
|
|
use discover.nu *
|
||
|
|
use ../lib_provisioning/layers/resolver.nu *
|
||
|
|
|
||
|
|
# Load providers into workspace or infrastructure
|
||
|
|
export def load-providers [
|
||
|
|
target_path: string,
|
||
|
|
providers: list<string>,
|
||
|
|
--force = false # Overwrite existing
|
||
|
|
--level: string = "auto" # "workspace", "infra", or "auto"
|
||
|
|
]: nothing -> record {
|
||
|
|
# Determine target layer
|
||
|
|
let layer_info = (determine-layer --workspace $target_path --infra $target_path --level $level)
|
||
|
|
let load_path = $layer_info.path
|
||
|
|
|
||
|
|
print $"Loading providers into ($layer_info.layer) layer: ($load_path)"
|
||
|
|
|
||
|
|
# Validate target path
|
||
|
|
if not ($load_path | path exists) {
|
||
|
|
error make { msg: $"Target path not found: ($load_path)" }
|
||
|
|
}
|
||
|
|
|
||
|
|
# Validate providers exist in system
|
||
|
|
let validation = (validate-providers $providers)
|
||
|
|
if not $validation.valid {
|
||
|
|
error make { msg: $"Missing providers: ($validation.missing)" }
|
||
|
|
}
|
||
|
|
|
||
|
|
# Create providers directory at target layer
|
||
|
|
let providers_dir = ($load_path | path join ".providers")
|
||
|
|
mkdir $providers_dir
|
||
|
|
|
||
|
|
# Load each provider
|
||
|
|
let results = ($providers | each { |name|
|
||
|
|
load-single-provider $load_path $name $force $layer_info.layer
|
||
|
|
})
|
||
|
|
|
||
|
|
# Generate imports file
|
||
|
|
generate-providers-imports $load_path $providers $layer_info.layer
|
||
|
|
|
||
|
|
# Create/update manifest
|
||
|
|
update-providers-manifest $load_path $providers $layer_info.layer
|
||
|
|
|
||
|
|
{
|
||
|
|
target: $load_path
|
||
|
|
layer: $layer_info.layer
|
||
|
|
loaded: ($results | where status == "success" | get name)
|
||
|
|
failed: ($results | where status == "error" | get name)
|
||
|
|
summary: $"Loaded (($results | where status == 'success' | length)) of (($providers | length)) providers at ($layer_info.layer) layer"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Load a single provider
|
||
|
|
def load-single-provider [target_path: string, name: string, force: bool, layer: string]: nothing -> record {
|
||
|
|
let result = (do {
|
||
|
|
let provider_info = (get-provider-info $name)
|
||
|
|
let target_dir = ($target_path | path join ".providers" $name)
|
||
|
|
|
||
|
|
# Check if already exists
|
||
|
|
if ($target_dir | path exists) and (not $force) {
|
||
|
|
print $"⚠️ Provider ($name) already loaded at ($layer) layer (add --force flag to overwrite)"
|
||
|
|
return {
|
||
|
|
name: $name
|
||
|
|
status: "skipped"
|
||
|
|
message: "already exists"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Copy KCL files and directories
|
||
|
|
mkdir $target_dir
|
||
|
|
let source_items = (ls $provider_info.kcl_path | get name)
|
||
|
|
for $item in $source_items {
|
||
|
|
cp -r $item $target_dir
|
||
|
|
}
|
||
|
|
|
||
|
|
print $"✅ Loaded provider: ($name)"
|
||
|
|
{
|
||
|
|
name: $name
|
||
|
|
status: "success"
|
||
|
|
path: $target_dir
|
||
|
|
version: $provider_info.version
|
||
|
|
type: $provider_info.provider_type
|
||
|
|
}
|
||
|
|
} | complete)
|
||
|
|
|
||
|
|
if $result.exit_code != 0 {
|
||
|
|
print $"❌ Failed to load provider ($name): ($result.stderr)"
|
||
|
|
{
|
||
|
|
name: $name
|
||
|
|
status: "error"
|
||
|
|
error: $result.stderr
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
$result.stdout | from json
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Generate providers.k import file
|
||
|
|
def generate-providers-imports [target_path: string, providers: list<string>, layer: string] {
|
||
|
|
# Generate individual imports for each provider
|
||
|
|
let imports = ($providers | each { |name|
|
||
|
|
# Check provider structure and import appropriately
|
||
|
|
let main_files = [
|
||
|
|
($target_path | path join ".providers" $name ($"provision_($name).k"))
|
||
|
|
($target_path | path join ".providers" $name ($"server_($name).k"))
|
||
|
|
($target_path | path join ".providers" $name ($"defaults_($name).k"))
|
||
|
|
($target_path | path join ".providers" $name ($name + ".k"))
|
||
|
|
]
|
||
|
|
|
||
|
|
# Find the main provider file
|
||
|
|
let main_file = ($main_files | where { |file| $file | path exists } | first)
|
||
|
|
if ($main_file | is-empty) {
|
||
|
|
$"import .providers.($name) as ($name)_provider"
|
||
|
|
} else {
|
||
|
|
let file_stem = ($main_file | path basename | str replace '.k' '')
|
||
|
|
$"import .providers.($name).($file_stem) as ($name)_provider"
|
||
|
|
}
|
||
|
|
} | str join "\n")
|
||
|
|
|
||
|
|
# Generate schema exports
|
||
|
|
let exports = ($providers | each { |name|
|
||
|
|
$" ($name): ($name)_provider"
|
||
|
|
} | str join ",\n")
|
||
|
|
|
||
|
|
# Create the complete imports file
|
||
|
|
let content = $"# Auto-generated provider imports ($layer) layer
|
||
|
|
# Generated: (date now | format date '%Y-%m-%d %H:%M:%S')
|
||
|
|
# Loaded providers: ($providers | str join ', ')
|
||
|
|
|
||
|
|
($imports)
|
||
|
|
|
||
|
|
# Export all loaded provider schemas
|
||
|
|
providers = {
|
||
|
|
($exports)
|
||
|
|
}
|
||
|
|
|
||
|
|
providers"
|
||
|
|
|
||
|
|
# Save the imports file
|
||
|
|
$content | save -f ($target_path | path join "providers.k")
|
||
|
|
|
||
|
|
# Also create individual alias files for easier direct imports
|
||
|
|
for $name in $providers {
|
||
|
|
let alias_content = $"# Provider alias for ($name)
|
||
|
|
# Generated: (date now | format date '%Y-%m-%d %H:%M:%S')
|
||
|
|
# Layer: ($layer)
|
||
|
|
|
||
|
|
import .providers.($name) as ($name)
|
||
|
|
|
||
|
|
# Re-export for convenience
|
||
|
|
($name)"
|
||
|
|
$alias_content | save -f ($target_path | path join $"provider_($name).k")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Update providers manifest
|
||
|
|
def update-providers-manifest [target_path: string, providers: list<string>, layer: string] {
|
||
|
|
let manifest_dir = ($target_path | path join ".manifest")
|
||
|
|
mkdir $manifest_dir
|
||
|
|
let manifest_path = ($manifest_dir | path join "providers.yaml")
|
||
|
|
let existing = if ($manifest_path | path exists) {
|
||
|
|
open $manifest_path
|
||
|
|
} else {
|
||
|
|
{}
|
||
|
|
}
|
||
|
|
|
||
|
|
let provider_entries = ($providers | each { |name|
|
||
|
|
let info = (get-provider-info $name)
|
||
|
|
{
|
||
|
|
name: $name
|
||
|
|
version: $info.version
|
||
|
|
type: $info.provider_type
|
||
|
|
layer: $layer
|
||
|
|
loaded_at: (date now | format date '%Y-%m-%d %H:%M:%S')
|
||
|
|
source_path: $info.kcl_path
|
||
|
|
}
|
||
|
|
})
|
||
|
|
|
||
|
|
let manifest = {
|
||
|
|
loaded_providers: $provider_entries
|
||
|
|
last_updated: (date now | format date '%Y-%m-%d %H:%M:%S')
|
||
|
|
target_path: $target_path
|
||
|
|
layer: $layer
|
||
|
|
}
|
||
|
|
|
||
|
|
$manifest | to yaml | save -f $manifest_path
|
||
|
|
}
|
||
|
|
|
||
|
|
# Remove provider from workspace
|
||
|
|
export def unload-provider [workspace: string, name: string]: nothing -> record {
|
||
|
|
let target_dir = ($workspace | path join ".providers" $name)
|
||
|
|
|
||
|
|
if not ($target_dir | path exists) {
|
||
|
|
error make { msg: $"Provider ($name) not loaded in workspace" }
|
||
|
|
}
|
||
|
|
|
||
|
|
rm -rf $target_dir
|
||
|
|
|
||
|
|
# Update manifest and imports
|
||
|
|
let manifest_path = ($workspace | path join "providers.manifest.yaml")
|
||
|
|
if ($manifest_path | path exists) {
|
||
|
|
let manifest = (open $manifest_path)
|
||
|
|
let updated_providers = ($manifest.loaded_providers | where name != $name)
|
||
|
|
|
||
|
|
if ($updated_providers | is-empty) {
|
||
|
|
rm $manifest_path
|
||
|
|
rm ($workspace | path join "providers.k")
|
||
|
|
} else {
|
||
|
|
let updated_manifest = ($manifest | update loaded_providers $updated_providers)
|
||
|
|
$updated_manifest | to yaml | save $manifest_path
|
||
|
|
|
||
|
|
# Regenerate imports
|
||
|
|
let names = ($updated_providers | get name)
|
||
|
|
# Determine layer from manifest or default to workspace
|
||
|
|
let layer = ($manifest.layer? | default "workspace")
|
||
|
|
generate-providers-imports $workspace $names $layer
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
print $"✅ Unloaded provider: ($name)"
|
||
|
|
{
|
||
|
|
name: $name
|
||
|
|
status: "unloaded"
|
||
|
|
workspace: $workspace
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# List loaded providers in workspace
|
||
|
|
export def list-loaded-providers [workspace: string]: nothing -> list<record> {
|
||
|
|
let manifest_path = ($workspace | path join "providers.manifest.yaml")
|
||
|
|
|
||
|
|
if not ($manifest_path | path exists) {
|
||
|
|
return []
|
||
|
|
}
|
||
|
|
|
||
|
|
let manifest = (open $manifest_path)
|
||
|
|
$manifest.loaded_providers? | default []
|
||
|
|
}
|
||
|
|
|
||
|
|
# Set default provider for workspace
|
||
|
|
export def set-default-provider [workspace: string, name: string]: nothing -> record {
|
||
|
|
# Validate provider is loaded
|
||
|
|
let loaded = (list-loaded-providers $workspace)
|
||
|
|
let provider_loaded = ($loaded | where name == $name | length) > 0
|
||
|
|
|
||
|
|
if not $provider_loaded {
|
||
|
|
error make { msg: $"Provider ($name) not loaded in workspace. Load it first." }
|
||
|
|
}
|
||
|
|
|
||
|
|
# Update workspace configuration
|
||
|
|
let config_path = ($workspace | path join "workspace.config.toml")
|
||
|
|
let config = if ($config_path | path exists) {
|
||
|
|
open $config_path | from toml
|
||
|
|
} else {
|
||
|
|
{}
|
||
|
|
}
|
||
|
|
|
||
|
|
let updated_config = ($config | upsert default_provider $name)
|
||
|
|
$updated_config | to toml | save $config_path
|
||
|
|
|
||
|
|
print $"✅ Set default provider: ($name)"
|
||
|
|
{
|
||
|
|
workspace: $workspace
|
||
|
|
default_provider: $name
|
||
|
|
status: "updated"
|
||
|
|
}
|
||
|
|
}
|