prvng_core/nulib/workflows/server_create.nu
Jesús Pérez 85ce530733
feat: update provisioning core CLI, libraries, and plugins
Update core components including CLI, Nushell libraries, plugins system,
and utility scripts for the provisioning system.

CLI Updates:
- Command implementations
- CLI utilities and dispatching
- Help system improvements
- Command validation

Library Updates:
- Configuration management system
- Infrastructure validation
- Extension system improvements
- Secrets management
- Workspace operations
- Cache management system

Plugin System:
- Interactive form plugin (inquire)
- KCL integration plugin
- Performance optimization plugins
- Plugin registration system

Utilities:
- Build and distribution scripts
- Installation procedures
- Testing utilities
- Development tools

Documentation:
- Library module documentation
- Extension API guides
- Plugin usage guides
- Service management documentation

All changes are backward compatible. No breaking changes.
2025-12-11 21:57:05 +00:00

251 lines
8.1 KiB
Plaintext

use std
use ../lib_provisioning *
use ../lib_provisioning/platform *
use ../servers/utils.nu *
# Workflow definition for server creation
# Get orchestrator endpoint from platform configuration or use provided default
def get-orchestrator-url [--orchestrator: string = ""] {
if ($orchestrator | is-not-empty) {
$orchestrator
} else {
"http://localhost:9090"
}
}
# Detect if orchestrator URL is local (for plugin usage)
def use-local-plugin [orchestrator_url: string] {
# Check if it's a local endpoint
(detect-platform-mode $orchestrator_url) == "local"
}
export def server_create_workflow [
infra: string # Infrastructure target
settings?: string # Settings file path
servers?: list # Specific servers to create (empty = all)
--check (-c) # Check mode only
--wait (-w) # Wait for completion
--orchestrator: string = "" # Orchestrator URL (optional, uses platform config if not provided)
] {
let orch_url = (get-orchestrator-url --orchestrator=$orchestrator)
let workflow_data = {
infra: $infra,
settings: ($settings | default ""),
servers: ($servers | default []),
check_mode: $check,
wait: $wait
}
# Submit to orchestrator
let response = (http post $"($orch_url)/workflows/servers/create" --content-type "application/json" ($workflow_data | to json))
if not ($response | get success) {
return { status: "error", message: ($response | get error) }
}
let task_id = ($response | get data)
_print $"Server creation workflow submitted: ($task_id)"
if $wait {
wait_for_workflow_completion $orch_url $task_id
} else {
{ status: "submitted", task_id: $task_id }
}
}
def wait_for_workflow_completion [orchestrator: string, task_id: string]: nothing -> record {
_print "Waiting for workflow completion..."
mut result = { status: "pending" }
while true {
# Use plugin for local orchestrator (<5ms vs ~50ms with HTTP)
let task = if (use-local-plugin $orchestrator) {
let all_tasks = (orch tasks)
let found = ($all_tasks | where id == $task_id | first)
if ($found | is-empty) {
return { status: "error", message: "Task not found" }
}
$found
} else {
# Fall back to HTTP for remote orchestrators
let status_response = (http get $"($orchestrator)/tasks/($task_id)")
if not ($status_response | get success) {
return { status: "error", message: "Failed to get task status" }
}
($status_response | get data)
}
let task_status = ($task | get status)
match $task_status {
"Completed" => {
_print $"✅ Workflow completed successfully"
if ($task | get output | is-not-empty) {
_print "Output:"
_print ($task | get output)
}
$result = { status: "completed", task: $task }
break
},
"Failed" => {
_print $"❌ Workflow failed"
if ($task | get error | is-not-empty) {
_print "Error:"
_print ($task | get error)
}
$result = { status: "failed", task: $task }
break
},
"Running" => {
_print $"🔄 Workflow is running..."
},
_ => {
_print $"⏳ Workflow status: ($task_status)"
}
}
sleep 2sec
}
return $result
}
# Bridge function to convert legacy server create calls to workflow
export def on_create_servers_workflow [
settings: record # Settings record
check: bool # Only check mode no servers will be created
wait: bool # Wait for creation
outfile?: string # Out file for creation
hostname?: string # Server hostname in settings
serverpos?: int # Server position in settings
--orchestrator: string = "http://localhost:8080" # Orchestrator URL
]: nothing -> record {
# Convert legacy parameters to workflow format
let servers_list = if $hostname != null {
[$hostname]
} else if $serverpos != null {
let total = ($settings.data.servers | length)
if $serverpos <= $total and $serverpos > 0 {
let target_server = ($settings.data.servers | get ($serverpos - 1))
[$target_server.hostname]
} else {
[]
}
} else {
[]
}
# Extract infra and settings paths from settings record
let infra_path = ($settings | get infra? | default "")
let settings_path = ($settings | get src? | default "")
# Submit workflow to orchestrator
let workflow_result = (server_create_workflow $infra_path $settings_path $servers_list --check=$check --wait=$wait --orchestrator $orchestrator)
match ($workflow_result | get status) {
"completed" => { status: true, error: "" },
"submitted" => {
status: true,
error: "",
task_id: ($workflow_result | get task_id)
},
"error" | "failed" => {
status: false,
error: ($workflow_result | get message? | default "Workflow failed")
},
_ => { status: false, error: "Unknown workflow status" }
}
}
# Workflow status check command
export def "workflow status" [
task_id: string # Task ID to check
--orchestrator: string = "http://localhost:8080" # Orchestrator URL
]: nothing -> record {
# Use plugin for local orchestrator (~5ms vs ~50ms with HTTP)
if (use-local-plugin $orchestrator) {
let all_tasks = (orch tasks)
let task = ($all_tasks | where id == $task_id | first)
if ($task | is-empty) {
return { error: $"Task ($task_id) not found" }
}
return {
id: ($task | get id),
status: ($task | get status),
priority: ($task | get priority),
created_at: ($task | get created_at),
workflow_id: ($task | get workflow_id)
}
}
# Fall back to HTTP for remote orchestrators
let response = (http get $"($orchestrator)/tasks/($task_id)")
if not ($response | get success) {
return { error: ($response | get error) }
}
let task = ($response | get data)
{
id: ($task | get id),
name: ($task | get name),
status: ($task | get status),
created_at: ($task | get created_at),
started_at: ($task | get started_at? | default null),
completed_at: ($task | get completed_at? | default null),
output: ($task | get output? | default null),
error: ($task | get error? | default null)
}
}
# List all workflows
export def "workflow list" [
--orchestrator: string = "http://localhost:8080" # Orchestrator URL
]: nothing -> list<record> {
# Use plugin for local orchestrator (<10ms vs ~50ms with HTTP)
if (use-local-plugin $orchestrator) {
return (orch tasks)
}
# Fall back to HTTP for remote orchestrators
let response = (http get $"($orchestrator)/tasks")
if not ($response | get success) {
_print $"Error: (($response | get error))"
return []
}
($response | get data)
}
# Workflow health check
export def "workflow health" [
--orchestrator: string = "http://localhost:8080" # Orchestrator URL
]: nothing -> record {
# Use plugin for local orchestrator (<5ms vs ~50ms with HTTP)
if (use-local-plugin $orchestrator) {
let status = (orch status)
return {
status: (if $status.running { "healthy" } else { "stopped" }),
message: $"Orchestrator running: ($status.running)",
plugin_mode: true
}
}
# Fall back to HTTP for remote orchestrators
let response = (http get $"($orchestrator)/health")
if ($response | get success) {
{ status: "healthy", message: ($response | get data) }
} else {
{ status: "unhealthy", message: "Orchestrator returned error" }
}
}