prvng_core/nulib/lib_provisioning/vm/preparer.nu
Jesús Pérez 844f6f9297
refactor(17 files final batch): selective imports — drive to 94% elimination (ADR-025 L2/L3)
Final large batch of single-star conversions.

Orchestrator facades (Layer 3, expanded to explicit symbol lists):
  config/accessor.nu          18 symbols (bridges accessor/mod)
  config/accessor_generated.nu 18 symbols (consumer of accessor)
  utils/version.nu            35 symbols (bridges version/mod)
  dependencies/mod.nu         7 symbols from resolver.nu
  oci_registry/mod.nu         12 multi-word "oci-registry X" subcommands
  oci/commands.nu             12 symbols from oci/client.nu

Selective imports (Layer 2):
  platform/discovery.nu       target.nu [5 symbols]
  platform/health.nu          target.nu [2 symbols]
  platform/connection.nu      user/config [get-active-workspace]
  vm/preparer.nu              vm/detector [check-vm-capability]
  vm/backend_libvirt.nu       result.nu [7 symbols]
  extensions/tests/test_versions.nu  versions [5 symbols]
  utils/version/loader.nu     utils/nickel_processor [ncl-eval ncl-eval-soft]

Dead imports dropped:
  platform/credentials.nu     user/config
  platform/activation.nu      target
  config/cache/core.nu        cache/metadata
  config/interpolation/core.nu helpers/environment
  utils/version/loader.nu     version/core (kept nickel_processor)

Validation: all 17 files match pre-existing baselines (or 0 errors for clean
ones). Pre-existing noise in vm/, dependencies/, oci_registry/, oci/commands
is known transitive — unrelated to this work.

MILESTONE: 94% of star-imports eliminated (370 → 21).

Remaining 21 star-lines in 6 files are intentional exceptions:
- integrations/mod.nu      (2 stars, re-exports already-selective children;
                            acceptable bounded scope)
- cmd/environment.nu       (3 stars, contains ~7 undefined function calls —
                            needs Blocker-1 style cleanup in follow-up commit)
- providers/loader.nu      (1 dynamic `use ($entry_point) *` — runtime dispatch)
- vm/cleanup_scheduler.nu  (1 in string template — not a real import)
- lib_provisioning/mod.nu  (13 stars — root facade; empties in ADR-025 Phase 4)

Refs: ADR-025
2026-04-17 17:08:10 +01:00

214 lines
5.4 KiB
Text

# VM Host Preparation System
#
# Prepares hosts for VM management by installing necessary hypervisors.
# Supports three modes: explicit, automatic, and auto-detect.
# Selective imports (ADR-025 Phase 3 Layer 2).
use lib_provisioning/vm/detector.nu [check-vm-capability]
export def "prepare-host-for-vms" [
host: string # Host identifier ("local" or remote hostname)
--auto-install # Auto-install missing hypervisors
--check-only # Only check, don't modify
]: record {
"""
Prepare a host for virtual machine management.
Detects available hypervisors and optionally installs missing ones.
Examples:
# Check local host capability
prepare-host-for-vms "local" --check-only
# Prepare local host with auto-install
prepare-host-for-vms "local" --auto-install
# Check remote host
prepare-host-for-vms "upcloud-server-01" --check-only
"""
let capabilities = (check-vm-capability $host)
if $check_only {
return $capabilities
}
if not $auto_install {
return $capabilities
}
# Auto-install hypervisors
prepare-host-install $host $capabilities
}
def prepare-host-install [host: string, capabilities: record]: record {
"""Install hypervisors on host"""
let needs_installation = (
($capabilities.primary_backend == "none")
)
if not $needs_installation {
return {
host: $host
status: "ready"
message: $"Host has ($capabilities.primary_backend) hypervisor available"
}
}
print $"Preparing host ($host) for VM support..."
# Determine what to install
let to_install = [
"kvm",
"libvirt",
"qemu",
]
# Install each hypervisor
let results = (
$to_install
| each {|taskserv|
install-hypervisor-taskserv $host $taskserv
}
)
# Check results
let failures = ($results | where success == false)
if ($failures | length) > 0 {
return {
host: $host
status: "partial"
message: $"Installed successfully but ($failures | length) failed"
failed_taskservs: ($failures | each {|x| $x.taskserv})
}
}
{
host: $host
status: "success"
message: "Host prepared successfully for VM management"
installed_taskservs: $to_install
}
}
def install-hypervisor-taskserv [host: string, taskserv: string]: record {
"""Install a hypervisor taskserv on host"""
print $" Installing ($taskserv)..."
let cmd = (
if $host == "local" {
$"provisioning taskserv create ($taskserv)"
} else {
$"provisioning taskserv create ($taskserv) --on-host ($host)"
}
)
# Execute command (no try-catch)
let exec_result = (do { shell-exec-safe $cmd } | complete)
let result = (
if $exec_result.exit_code == 0 {
$exec_result.stdout
} else {
{
taskserv: $taskserv
success: false
error: $exec_result.stderr
}
}
)
if ($result | type) == "record" and ("success" in $result) {
return $result
}
{
taskserv: $taskserv
success: true
message: $"Installed successfully"
}
}
def shell-exec-safe [cmd: string]: record {
"""Execute shell command safely"""
# Execute command (no try-catch)
let result = (do { bash -c $cmd } | complete)
if $result.exit_code != 0 {
return {success: false, error: $result.stderr}
}
{success: true, stdout: $result.stdout}
}
export def "get-host-hypervisor-status" [host: string]: table {
"""Get detailed hypervisor status for a host"""
let capabilities = (check-vm-capability $host)
$capabilities.available_hypervisors
| map {|h|
{
host: $host
hypervisor: $h.name
status: $h.available
description: $h.description
ready: ($h.available == "ready")
}
}
}
export def "list-vm-capable-hosts" []: table {
"""List all hosts that can run VMs"""
# Get local host capability
let local_status = (check-vm-capability "local")
[
{
name: "local"
can_run_vms: $local_status.can_run_vms
primary_hypervisor: $local_status.primary_backend
}
]
# In future, could add remote hosts from infrastructure config
}
export def "ensure-vm-support" [host: string]: record {
"""
Ensure host has VM support, installing if necessary.
Returns success only when VM support is confirmed ready.
"""
let status1 = (check-vm-capability $host)
if $status1.primary_backend != "none" {
return {
host: $host
status: "ready"
message: $"Host already has VM support via ($status1.primary_backend)"
}
}
# Need to install
print $"Host ($host) needs VM hypervisor installation"
let install_result = (prepare-host-install $host $status1)
if $install_result.status != "success" {
return $install_result
}
# Verify installation
let status2 = (check-vm-capability $host)
{
host: $host
status: "ready"
message: $"VM support installed and verified"
primary_hypervisor: $status2.primary_backend
}
}