prvng_core/nulib/taskservs/deps_validator.nu
2025-10-07 10:32:04 +01:00

262 lines
8.0 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Taskserv Dependency Validator
# Validates taskserv dependencies, conflicts, and requirements
use lib_provisioning *
use utils.nu *
use ../lib_provisioning/config/accessor.nu *
# Validate taskserv dependencies from KCL definition
export def validate-dependencies [
taskserv_name: string
settings: record
--verbose (-v)
]: nothing -> record {
let taskservs_path = (get-taskservs-path)
let taskserv_kcl_path = ($taskservs_path | path join $taskserv_name "kcl")
# Check if taskserv has dependencies.k
let deps_file = ($taskserv_kcl_path | path join "dependencies.k")
if not ($deps_file | path exists) {
return {
valid: true
taskserv: $taskserv_name
has_dependencies: false
warnings: []
errors: []
}
}
if $verbose {
_print $"Validating dependencies for (_ansi yellow_bold)($taskserv_name)(_ansi reset)..."
}
# Run KCL to extract dependency information
let result = try {
kcl run $deps_file --format json | from json
} catch {
return {
valid: false
taskserv: $taskserv_name
has_dependencies: true
warnings: []
errors: [$"Failed to parse dependencies.k: ($in)"]
}
}
# Extract dependency information
let deps = ($result | get -o _dependencies)
if $deps == null {
return {
valid: true
taskserv: $taskserv_name
has_dependencies: false
warnings: ["dependencies.k exists but no _dependencies defined"]
errors: []
}
}
let requires = ($deps | get -o requires | default [])
let optional = ($deps | get -o optional | default [])
let conflicts = ($deps | get -o conflicts | default [])
mut warnings = []
mut errors = []
# Validate required dependencies
for req in $requires {
let req_path = ($taskservs_path | path join $req)
if not ($req_path | path exists) {
$errors = ($errors | append $"Required dependency not found: ($req)")
} else if $verbose {
_print $" ✓ Required: ($req)"
}
}
# Check optional dependencies
for opt in $optional {
let opt_path = ($taskservs_path | path join $opt)
if not ($opt_path | path exists) {
$warnings = ($warnings | append $"Optional dependency not available: ($opt)")
} else if $verbose {
_print $" Optional: ($opt)"
}
}
# Validate conflicts
for conf in $conflicts {
let conf_path = ($taskservs_path | path join $conf)
if ($conf_path | path exists) {
$warnings = ($warnings | append $"Conflicting taskserv installed: ($conf)")
} else if $verbose {
_print $" ✓ No conflict: ($conf)"
}
}
# Validate resource requirements
let resource_req = ($deps | get -o resource_requirements)
if $resource_req != null {
let min_memory = ($resource_req | get -o min_memory | default 0)
let min_cores = ($resource_req | get -o min_cores | default 0)
let min_disk = ($resource_req | get -o min_disk | default 0)
if $verbose {
_print $" Resource requirements:"
_print $" Memory: ($min_memory) MB"
_print $" Cores: ($min_cores)"
_print $" Disk: ($min_disk) GB"
}
# TODO: Could validate against server specs if available in settings
}
# Validate health check configuration
let health_check = ($deps | get -o health_check)
if $health_check != null {
let endpoint = ($health_check | get -o endpoint | default "")
let timeout = ($health_check | get -o timeout | default 30)
if $endpoint == "" {
$warnings = ($warnings | append "Health check defined but no endpoint specified")
} else if $verbose {
_print $" Health check: ($endpoint) (timeout: ($timeout)s)"
}
}
return {
valid: (($errors | length) == 0)
taskserv: $taskserv_name
has_dependencies: true
requires: $requires
optional: $optional
conflicts: $conflicts
resource_requirements: $resource_req
health_check: $health_check
warnings: $warnings
errors: $errors
}
}
# Validate dependencies for taskserv in infrastructure context
export def validate-infra-dependencies [
taskserv_name: string
settings: record
--verbose (-v)
]: nothing -> record {
let validation = (validate-dependencies $taskserv_name $settings --verbose=$verbose)
if not $validation.has_dependencies {
return $validation
}
# Check against installed taskservs in infrastructure
let installed_taskservs = try {
$settings.data.servers
| each {|srv| $srv.taskservs | get name}
| flatten
| uniq
} catch {
[]
}
mut infra_errors = []
mut infra_warnings = []
# Check if required dependencies are in infrastructure
for req in ($validation.requires | default []) {
if $req not-in $installed_taskservs {
$infra_errors = ($infra_errors | append $"Required dependency '($req)' not in infrastructure")
}
}
# Check for conflicts in infrastructure
for conf in ($validation.conflicts | default []) {
if $conf in $installed_taskservs {
$infra_errors = ($infra_errors | append $"Conflicting taskserv '($conf)' found in infrastructure")
}
}
return ($validation | merge {
infra_validation: true
installed_taskservs: $installed_taskservs
errors: (($validation.errors | default []) | append $infra_errors)
warnings: (($validation.warnings | default []) | append $infra_warnings)
valid: ((($validation.errors | default []) | append $infra_errors | length) == 0)
})
}
# Check dependencies for all taskservs
export def check-all-dependencies [
settings: record
--verbose (-v)
]: nothing -> table {
let taskservs_path = (get-taskservs-path)
# Find all taskservs with dependencies.k
let all_taskservs = (
ls ($taskservs_path | path join "**/kcl/dependencies.k")
| get name
| each {|path|
$path | path dirname | path dirname | path basename
}
)
if $verbose {
_print $"Found ($all_taskservs | length) taskservs with dependencies"
}
$all_taskservs | each {|ts|
validate-dependencies $ts $settings --verbose=$verbose
}
}
# Print dependency validation report
export def print-validation-report [
validation: record
]: nothing -> nothing {
_print $"\n(_ansi cyan_bold)Dependency Validation Report(_ansi reset)"
_print $"Taskserv: (_ansi yellow_bold)($validation.taskserv)(_ansi reset)"
if not $validation.has_dependencies {
_print $" (_ansi green)No dependencies defined(_ansi reset)"
return
}
_print $"\nStatus: (if $validation.valid { (_ansi green_bold)VALID(_ansi reset) } else { (_ansi red_bold)INVALID(_ansi reset) })"
if ($validation.requires | default [] | length) > 0 {
_print $"\n(_ansi cyan)Required Dependencies:(_ansi reset)"
for req in $validation.requires {
_print $" • ($req)"
}
}
if ($validation.optional | default [] | length) > 0 {
_print $"\n(_ansi cyan)Optional Dependencies:(_ansi reset)"
for opt in $validation.optional {
_print $" • ($opt)"
}
}
if ($validation.conflicts | default [] | length) > 0 {
_print $"\n(_ansi cyan)Conflicts:(_ansi reset)"
for conf in $validation.conflicts {
_print $" • ($conf)"
}
}
if ($validation.warnings | length) > 0 {
_print $"\n(_ansi yellow_bold)Warnings:(_ansi reset)"
for warn in $validation.warnings {
_print $" ⚠ ($warn)"
}
}
if ($validation.errors | length) > 0 {
_print $"\n(_ansi red_bold)Errors:(_ansi reset)"
for err in $validation.errors {
_print $" ✗ ($err)"
}
}
}