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 { # 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" } } }