- DAG architecture: `dag show/validate/export` (nulib/main_provisioning/dag.nu),
config loader (lib_provisioning/config/loader/dag.nu), taskserv dag-executor.
Backed by schemas/lib/dag/*.ncl; orchestrator emits NATS events via
WorkspaceComposition::into_workflow. See ADR-020, ADR-021.
- Unified Component Architecture: components/mod.nu, main_provisioning/
{components,workflow,extensions,ontoref-queries}.nu. Full workflow engine with
topological sort and NATS subject emission. Blocks A-H complete (libre-daoshi).
- Commands-registry: nulib/commands-registry.ncl (Nickel source, 314 lines) +
JSON cache at ~/.cache/provisioning/commands-registry.json rebuilt on source
change. cli/provisioning fast-path alias expansion avoids cold Nu startup.
ADDING_COMMANDS.md documents new-command workflow.
- Platform service manager: service-manager.nu (+573), startup.nu (+611),
service-check.nu (+255); autostart/bootstrap/health/target refactored.
- Nushell 0.112.2 migration: removed all try/catch and bash redirections;
external commands prefixed with ^; type signatures enforced. Driven by
scripts/refactor-try-catch{,-simplified}.nu.
- TTY stack: removed shlib/*-tty.sh; replaced by cli/tty-dispatch.sh,
tty-filter.sh, tty-commands.conf.
- New domain modules: images/ (golden image lifecycle), workspace/{state,sync}.nu,
main_provisioning/{bootstrap,cluster-deploy,fip,state}.nu, commands/{state,
build,integrations/auth,utilities/alias}.nu, platform.nu expanded (+874).
- Config loader overhaul: loader/core.nu slimmed (-759), cache/core.nu
refactored (-454), removed legacy loaders/file_loader.nu (-330).
- Thirteen new provisioning-<domain>.nu top-level modules for bash dispatcher.
- Tests: test_workspace_state.nu (+351); updates to test_oci_registry,
test_services.
- README + CHANGELOG updated.
165 lines
7 KiB
Text
165 lines
7 KiB
Text
#!/usr/bin/env nu
|
|
# Thin entry for batch workflow commands.
|
|
# Loads ONLY workflows/batch.nu (~95ms vs ~12s for the full double-load).
|
|
|
|
export-env {
|
|
let lib_dirs_raw = ($env.NU_LIB_DIRS? | default "")
|
|
let current_lib_dirs = if ($lib_dirs_raw | type) == "string" {
|
|
if ($lib_dirs_raw | is-empty) { [] } else { ($lib_dirs_raw | split row ":") }
|
|
} else {
|
|
$lib_dirs_raw
|
|
}
|
|
let dynamic = ($env.PROVISIONING? | default "" | path join "core" "nulib")
|
|
$env.NU_LIB_DIRS = ([
|
|
"/opt/provisioning/core/nulib"
|
|
"/usr/local/provisioning/core/nulib"
|
|
] | append $current_lib_dirs | append (if ($dynamic | is-not-empty) { [$dynamic] } else { [] }))
|
|
}
|
|
|
|
use workflows/batch.nu *
|
|
|
|
def main [
|
|
...args: string
|
|
--status: string = ""
|
|
--environment: string = ""
|
|
--name: string = ""
|
|
--limit: int = 50
|
|
--format: string = "table"
|
|
--priority: int = 5
|
|
--interval: duration = 3sec
|
|
--timeout: duration = 30min
|
|
--checkpoint: string = ""
|
|
--reason: string = ""
|
|
--period: string = "24h"
|
|
--from-file: string = ""
|
|
--description: string = ""
|
|
--check-syntax (-s)
|
|
--check-dependencies (-d)
|
|
--wait (-w)
|
|
--force (-f)
|
|
--quiet (-q)
|
|
--detailed
|
|
--debug (-x)
|
|
--out: string
|
|
]: nothing -> nothing {
|
|
if $debug { $env.PROVISIONING_DEBUG = true }
|
|
|
|
# CMD_ARGS from the bash wrapper includes the command name as arg[0] ("batch"/"bat").
|
|
# Strip it so arg[0] becomes the subcommand.
|
|
let first = ($args | get 0? | default "")
|
|
let sub_args = if $first in ["batch", "bat"] { $args | skip 1 } else { $args }
|
|
|
|
let task = ($sub_args | get 0? | default "")
|
|
let ops = ($sub_args | skip 1)
|
|
let workflow_param = ($ops | get 0? | default "")
|
|
|
|
match $task {
|
|
"list" => {
|
|
let result = (batch list --status $status --environment $environment --name $name --limit $limit --format $format)
|
|
if ($out | is-not-empty) and $out == "json" { print ($result | to json) } else { print ($result | table) }
|
|
}
|
|
"status" => {
|
|
if ($workflow_param | is-empty) { print "❌ Workflow ID required"; exit 1 }
|
|
batch status $workflow_param --format $format
|
|
}
|
|
"submit" => {
|
|
if ($workflow_param | is-empty) { print "❌ Workflow file path required"; exit 1 }
|
|
let result = if $wait {
|
|
batch submit $workflow_param --name $name --priority $priority --environment $environment --wait --timeout $timeout
|
|
} else {
|
|
batch submit $workflow_param --name $name --priority $priority --environment $environment
|
|
}
|
|
if ($out | is-not-empty) and $out == "json" { print ($result | to json) }
|
|
}
|
|
"validate" => {
|
|
if ($workflow_param | is-empty) { print "❌ Workflow file path required"; exit 1 }
|
|
let result = if $check_syntax and $check_dependencies {
|
|
batch validate $workflow_param --check-syntax --check-dependencies
|
|
} else if $check_syntax {
|
|
batch validate $workflow_param --check-syntax
|
|
} else if $check_dependencies {
|
|
batch validate $workflow_param --check-dependencies
|
|
} else {
|
|
batch validate $workflow_param
|
|
}
|
|
if $result.valid { print "✅ Workflow is valid" } else {
|
|
print "❌ Workflow validation failed"
|
|
print $"Errors: ($result.errors | str join '\n ')"
|
|
}
|
|
}
|
|
"monitor" => {
|
|
if ($workflow_param | is-empty) { print "❌ Workflow ID required"; exit 1 }
|
|
if $quiet {
|
|
batch monitor $workflow_param --interval $interval --timeout $timeout --quiet
|
|
} else {
|
|
batch monitor $workflow_param --interval $interval --timeout $timeout
|
|
}
|
|
}
|
|
"rollback" => {
|
|
if ($workflow_param | is-empty) { print "❌ Workflow ID required"; exit 1 }
|
|
let result = if ($checkpoint | is-not-empty) {
|
|
batch rollback $workflow_param --checkpoint $checkpoint --force
|
|
} else if $force {
|
|
batch rollback $workflow_param --force
|
|
} else {
|
|
batch rollback $workflow_param
|
|
}
|
|
if ($out | is-not-empty) and $out == "json" { print ($result | to json) }
|
|
}
|
|
"cancel" => {
|
|
if ($workflow_param | is-empty) { print "❌ Workflow ID required"; exit 1 }
|
|
let result = if ($reason | is-not-empty) and $force {
|
|
batch cancel $workflow_param --reason $reason --force
|
|
} else if ($reason | is-not-empty) {
|
|
batch cancel $workflow_param --reason $reason
|
|
} else if $force {
|
|
batch cancel $workflow_param --force
|
|
} else {
|
|
batch cancel $workflow_param
|
|
}
|
|
if ($out | is-not-empty) and $out == "json" { print ($result | to json) }
|
|
}
|
|
"template" => {
|
|
let action = if ($workflow_param | is-not-empty) { $workflow_param } else { "list" }
|
|
let tpl_name = ($ops | get 1? | default "")
|
|
let result = match $action {
|
|
"list" => { batch template "list" }
|
|
"show" => { if ($tpl_name | is-empty) { print "❌ Template name required"; exit 1 }; batch template "show" $tpl_name }
|
|
"delete" => { if ($tpl_name | is-empty) { print "❌ Template name required"; exit 1 }; batch template "delete" $tpl_name }
|
|
"create" => {
|
|
if ($tpl_name | is-empty) or ($from_file | is-empty) { print "❌ Name and --from-file required"; exit 1 }
|
|
batch template "create" $tpl_name --from-file $from_file --description $description
|
|
}
|
|
_ => { print $"❌ Unknown template action: ($action)"; exit 1 }
|
|
}
|
|
if ($out | is-not-empty) and $out == "json" { print ($result | to json) } else { print ($result | table) }
|
|
}
|
|
"stats" => {
|
|
let result = if $detailed {
|
|
batch stats --period $period --environment $environment --detailed
|
|
} else {
|
|
batch stats --period $period --environment $environment
|
|
}
|
|
if ($out | is-not-empty) and $out == "json" { print ($result | to json) }
|
|
}
|
|
"health" => {
|
|
batch health
|
|
}
|
|
"help" | "h" => {
|
|
print "Batch Workflow Management"
|
|
print "Usage: provisioning batch <command> [args]"
|
|
print ""
|
|
print "Commands: list, status, submit, validate, monitor, rollback, cancel, template, stats, health"
|
|
}
|
|
"" => {
|
|
print "❌ Batch subcommand required"
|
|
print "Commands: list, status, submit, validate, monitor, rollback, cancel, template, stats, health"
|
|
exit 1
|
|
}
|
|
_ => {
|
|
print $"❌ Unknown batch command: ($task)"
|
|
print "Commands: list, status, submit, validate, monitor, rollback, cancel, template, stats, health"
|
|
exit 1
|
|
}
|
|
}
|
|
}
|