422 lines
12 KiB
Plaintext
422 lines
12 KiB
Plaintext
|
|
# Settings Validation Module
|
||
|
|
# Validates configuration settings, paths, and user inputs
|
||
|
|
# Follows Nushell guidelines: explicit types, single purpose, no try-catch
|
||
|
|
|
||
|
|
use ./mod.nu *
|
||
|
|
|
||
|
|
# ============================================================================
|
||
|
|
# PATH VALIDATION
|
||
|
|
# ============================================================================
|
||
|
|
|
||
|
|
# Validate configuration base path
|
||
|
|
export def validate-config-path [
|
||
|
|
path: string
|
||
|
|
]: nothing -> record {
|
||
|
|
let path_exists = ($path | path exists)
|
||
|
|
let path_is_dir = (if $path_exists { ($path | path type) == "dir" } else { false })
|
||
|
|
let path_writable = ((do { mkdir $path } | complete) | get exit_code) == 0
|
||
|
|
let is_valid = ($path_exists and $path_is_dir)
|
||
|
|
|
||
|
|
{
|
||
|
|
path: $path
|
||
|
|
exists: $path_exists
|
||
|
|
is_directory: $path_is_dir
|
||
|
|
writable: $path_writable
|
||
|
|
valid: $is_valid
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Validate workspace path
|
||
|
|
export def validate-workspace-path [
|
||
|
|
workspace_name: string
|
||
|
|
workspace_path: string
|
||
|
|
]: nothing -> record {
|
||
|
|
let config_base = (get-config-base-path)
|
||
|
|
let required_dirs = ["config", "infra"]
|
||
|
|
|
||
|
|
mut missing_dirs = []
|
||
|
|
for dir in $required_dirs {
|
||
|
|
let dir_path = $"($workspace_path)/($dir)"
|
||
|
|
if not ($dir_path | path exists) {
|
||
|
|
$missing_dirs = ($missing_dirs | append $dir)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
let workspace_exists = ($workspace_path | path exists)
|
||
|
|
let is_dir = (if $workspace_exists { ($workspace_path | path type) == "dir" } else { false })
|
||
|
|
let has_config_file = ($"($workspace_path)/config/provisioning.k" | path exists)
|
||
|
|
let is_valid = ($workspace_exists and ($missing_dirs | length) == 0)
|
||
|
|
|
||
|
|
{
|
||
|
|
workspace_name: $workspace_name
|
||
|
|
path: $workspace_path
|
||
|
|
exists: $workspace_exists
|
||
|
|
is_directory: $is_dir
|
||
|
|
has_config: $has_config_file
|
||
|
|
missing_directories: $missing_dirs
|
||
|
|
valid: $is_valid
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# ============================================================================
|
||
|
|
# CONFIGURATION VALUE VALIDATION
|
||
|
|
# ============================================================================
|
||
|
|
|
||
|
|
# Validate OS name
|
||
|
|
export def validate-os-name [
|
||
|
|
os_name: string
|
||
|
|
]: nothing -> record {
|
||
|
|
let valid_os = ["linux", "macos", "windows"]
|
||
|
|
let is_valid = ($os_name in $valid_os)
|
||
|
|
let error_msg = (if not $is_valid { $"Invalid OS: ($os_name)" } else { null })
|
||
|
|
|
||
|
|
{
|
||
|
|
value: $os_name
|
||
|
|
valid_values: $valid_os
|
||
|
|
valid: $is_valid
|
||
|
|
error: $error_msg
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Validate port number
|
||
|
|
export def validate-port-number [
|
||
|
|
port: int
|
||
|
|
]: nothing -> record {
|
||
|
|
let is_valid = ($port >= 1 and $port <= 65535)
|
||
|
|
let error_msg = (if not $is_valid { "Port must be between 1 and 65535" } else { null })
|
||
|
|
|
||
|
|
{
|
||
|
|
port: $port
|
||
|
|
valid: $is_valid
|
||
|
|
error: $error_msg
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Validate port is available
|
||
|
|
export def validate-port-available [
|
||
|
|
port: int
|
||
|
|
]: nothing -> record {
|
||
|
|
let port_valid = (validate-port-number $port)
|
||
|
|
if not $port_valid.valid {
|
||
|
|
return $port_valid
|
||
|
|
}
|
||
|
|
|
||
|
|
let available = (is-port-available $port)
|
||
|
|
let error_msg = (if not $available { $"Port ($port) is already in use" } else { null })
|
||
|
|
|
||
|
|
{
|
||
|
|
port: $port
|
||
|
|
valid: $available
|
||
|
|
available: $available
|
||
|
|
error: $error_msg
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Validate provider name
|
||
|
|
export def validate-provider-name [
|
||
|
|
provider_name: string
|
||
|
|
]: nothing -> record {
|
||
|
|
let valid_providers = ["upcloud", "aws", "hetzner", "local"]
|
||
|
|
let is_valid = ($provider_name in $valid_providers)
|
||
|
|
let error_msg = (if not $is_valid { $"Unknown provider: ($provider_name)" } else { null })
|
||
|
|
|
||
|
|
{
|
||
|
|
provider: $provider_name
|
||
|
|
valid_providers: $valid_providers
|
||
|
|
valid: $is_valid
|
||
|
|
error: $error_msg
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Validate email address format
|
||
|
|
export def validate-email [
|
||
|
|
email: string
|
||
|
|
]: nothing -> record {
|
||
|
|
let email_pattern = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
|
||
|
|
let is_valid = ($email | str contains "@")
|
||
|
|
let error_msg = (if not $is_valid { "Invalid email format" } else { null })
|
||
|
|
|
||
|
|
{
|
||
|
|
email: $email
|
||
|
|
valid: $is_valid
|
||
|
|
error: $error_msg
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# ============================================================================
|
||
|
|
# SYSTEM RESOURCE VALIDATION
|
||
|
|
# ============================================================================
|
||
|
|
|
||
|
|
# Validate CPU count
|
||
|
|
export def validate-cpu-count [
|
||
|
|
cpu_count: int
|
||
|
|
]: nothing -> record {
|
||
|
|
let is_valid = ($cpu_count >= 1 and $cpu_count <= 1024)
|
||
|
|
let error_msg = (if not $is_valid { "CPU count must be between 1 and 1024" } else { null })
|
||
|
|
|
||
|
|
{
|
||
|
|
cpu_count: $cpu_count
|
||
|
|
valid: $is_valid
|
||
|
|
valid_range: "1-1024"
|
||
|
|
error: $error_msg
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Validate memory allocation in GB
|
||
|
|
export def validate-memory-gb [
|
||
|
|
memory_gb: int
|
||
|
|
]: nothing -> record {
|
||
|
|
let is_valid = ($memory_gb >= 1 and $memory_gb <= 4096)
|
||
|
|
let error_msg = (if not $is_valid { "Memory must be between 1 and 4096 GB" } else { null })
|
||
|
|
|
||
|
|
{
|
||
|
|
memory_gb: $memory_gb
|
||
|
|
valid: $is_valid
|
||
|
|
valid_range: "1-4096 GB"
|
||
|
|
error: $error_msg
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Validate disk space in GB
|
||
|
|
export def validate-disk-gb [
|
||
|
|
disk_gb: int
|
||
|
|
]: nothing -> record {
|
||
|
|
let is_valid = ($disk_gb >= 10 and $disk_gb <= 100000)
|
||
|
|
let error_msg = (if not $is_valid { "Disk space must be between 10 and 100000 GB" } else { null })
|
||
|
|
|
||
|
|
{
|
||
|
|
disk_gb: $disk_gb
|
||
|
|
valid: $is_valid
|
||
|
|
valid_range: "10-100000 GB"
|
||
|
|
error: $error_msg
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# ============================================================================
|
||
|
|
# COMPLEX VALIDATION
|
||
|
|
# ============================================================================
|
||
|
|
|
||
|
|
# Validate complete system configuration
|
||
|
|
export def validate-system-config [
|
||
|
|
config: record
|
||
|
|
]: nothing -> record {
|
||
|
|
mut errors = []
|
||
|
|
mut warnings = []
|
||
|
|
|
||
|
|
# Validate OS name
|
||
|
|
let os_validation = (validate-os-name ($config.os_name? | default "linux"))
|
||
|
|
if not $os_validation.valid {
|
||
|
|
$errors = ($errors | append $os_validation.error)
|
||
|
|
}
|
||
|
|
|
||
|
|
# Validate paths
|
||
|
|
if ($config.install_path? != null) {
|
||
|
|
let path_validation = (validate-config-path $config.install_path)
|
||
|
|
if not $path_validation.valid {
|
||
|
|
$errors = ($errors | append $"Invalid install_path: ($config.install_path)")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Validate CPU count
|
||
|
|
if ($config.cpu_count? != null) {
|
||
|
|
let cpu_validation = (validate-cpu-count $config.cpu_count)
|
||
|
|
if not $cpu_validation.valid {
|
||
|
|
$errors = ($errors | append $cpu_validation.error)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Validate memory
|
||
|
|
if ($config.memory_gb? != null) {
|
||
|
|
let mem_validation = (validate-memory-gb $config.memory_gb)
|
||
|
|
if not $mem_validation.valid {
|
||
|
|
$errors = ($errors | append $mem_validation.error)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Validate disk
|
||
|
|
if ($config.disk_gb? != null) {
|
||
|
|
let disk_validation = (validate-disk-gb $config.disk_gb)
|
||
|
|
if not $disk_validation.valid {
|
||
|
|
$errors = ($errors | append $disk_validation.error)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
let is_valid = ($errors | length) == 0
|
||
|
|
let error_count = ($errors | length)
|
||
|
|
let warning_count = ($warnings | length)
|
||
|
|
|
||
|
|
{
|
||
|
|
valid: $is_valid
|
||
|
|
errors: $errors
|
||
|
|
warnings: $warnings
|
||
|
|
error_count: $error_count
|
||
|
|
warning_count: $warning_count
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Validate workspace configuration
|
||
|
|
export def validate-workspace-config [
|
||
|
|
workspace_name: string
|
||
|
|
workspace_path: string
|
||
|
|
config: record
|
||
|
|
]: nothing -> record {
|
||
|
|
mut errors = []
|
||
|
|
mut warnings = []
|
||
|
|
|
||
|
|
# Validate workspace name
|
||
|
|
if ($workspace_name | str length) == 0 {
|
||
|
|
$errors = ($errors | append "Workspace name cannot be empty")
|
||
|
|
}
|
||
|
|
|
||
|
|
# Validate workspace path
|
||
|
|
let path_validation = (validate-workspace-path $workspace_name $workspace_path)
|
||
|
|
if not $path_validation.valid {
|
||
|
|
$errors = ($errors | append $"Invalid workspace path: ($workspace_path)")
|
||
|
|
if ($path_validation.missing_directories | length) > 0 {
|
||
|
|
$warnings = ($warnings | append $"Missing directories: ($path_validation.missing_directories | str join ', ')")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Validate active providers if specified
|
||
|
|
if ($config.active_providers? != null) {
|
||
|
|
for provider in $config.active_providers {
|
||
|
|
let provider_validation = (validate-provider-name $provider)
|
||
|
|
if not $provider_validation.valid {
|
||
|
|
$errors = ($errors | append $provider_validation.error)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
let is_valid = ($errors | length) == 0
|
||
|
|
let error_count = ($errors | length)
|
||
|
|
let warning_count = ($warnings | length)
|
||
|
|
|
||
|
|
{
|
||
|
|
workspace_name: $workspace_name
|
||
|
|
valid: $is_valid
|
||
|
|
errors: $errors
|
||
|
|
warnings: $warnings
|
||
|
|
error_count: $error_count
|
||
|
|
warning_count: $warning_count
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Validate platform services configuration
|
||
|
|
export def validate-platform-config [
|
||
|
|
config: record
|
||
|
|
]: nothing -> record {
|
||
|
|
mut errors = []
|
||
|
|
mut warnings = []
|
||
|
|
|
||
|
|
# Validate orchestrator port
|
||
|
|
if ($config.orchestrator_port? != null) {
|
||
|
|
let port_validation = (validate-port-number $config.orchestrator_port)
|
||
|
|
if not $port_validation.valid {
|
||
|
|
$errors = ($errors | append $port_validation.error)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Validate control center port
|
||
|
|
if ($config.control_center_port? != null) {
|
||
|
|
let port_validation = (validate-port-number $config.control_center_port)
|
||
|
|
if not $port_validation.valid {
|
||
|
|
$errors = ($errors | append $port_validation.error)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Validate KMS port
|
||
|
|
if ($config.kms_port? != null) {
|
||
|
|
let port_validation = (validate-port-number $config.kms_port)
|
||
|
|
if not $port_validation.valid {
|
||
|
|
$errors = ($errors | append $port_validation.error)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Check for port conflicts
|
||
|
|
let ports = [
|
||
|
|
($config.orchestrator_port? | default 9090),
|
||
|
|
($config.control_center_port? | default 3000),
|
||
|
|
($config.kms_port? | default 3001)
|
||
|
|
]
|
||
|
|
|
||
|
|
for port in $ports {
|
||
|
|
if not (is-port-available $port) {
|
||
|
|
$warnings = ($warnings | append $"Port ($port) is already in use")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
let is_valid = ($errors | length) == 0
|
||
|
|
let error_count = ($errors | length)
|
||
|
|
let warning_count = ($warnings | length)
|
||
|
|
|
||
|
|
{
|
||
|
|
valid: $is_valid
|
||
|
|
errors: $errors
|
||
|
|
warnings: $warnings
|
||
|
|
error_count: $error_count
|
||
|
|
warning_count: $warning_count
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# ============================================================================
|
||
|
|
# VALIDATION REPORT
|
||
|
|
# ============================================================================
|
||
|
|
|
||
|
|
# Print validation report
|
||
|
|
export def print-validation-report [
|
||
|
|
report: record
|
||
|
|
]: nothing -> nothing {
|
||
|
|
print ""
|
||
|
|
print "═══════════════════════════════════════════════════════════════"
|
||
|
|
print " VALIDATION REPORT"
|
||
|
|
print "═══════════════════════════════════════════════════════════════"
|
||
|
|
print ""
|
||
|
|
|
||
|
|
if $report.valid {
|
||
|
|
print "✅ All validation checks passed!"
|
||
|
|
} else {
|
||
|
|
print "❌ Validation failed with errors"
|
||
|
|
}
|
||
|
|
|
||
|
|
print ""
|
||
|
|
|
||
|
|
if ($report.error_count? | default 0) > 0 {
|
||
|
|
print "ERRORS:"
|
||
|
|
for error in ($report.errors? | default []) {
|
||
|
|
print $" ❌ ($error)"
|
||
|
|
}
|
||
|
|
print ""
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($report.warning_count? | default 0) > 0 {
|
||
|
|
print "WARNINGS:"
|
||
|
|
for warning in ($report.warnings? | default []) {
|
||
|
|
print $" ⚠️ ($warning)"
|
||
|
|
}
|
||
|
|
print ""
|
||
|
|
}
|
||
|
|
|
||
|
|
print "═══════════════════════════════════════════════════════════════"
|
||
|
|
print ""
|
||
|
|
}
|
||
|
|
|
||
|
|
# Validate all system requirements are met
|
||
|
|
export def validate-requirements [
|
||
|
|
detection_report: record
|
||
|
|
]: nothing -> record {
|
||
|
|
let missing_tools = (get-missing-required-tools $detection_report)
|
||
|
|
let all_requirements_met = ($missing_tools | length) == 0
|
||
|
|
|
||
|
|
{
|
||
|
|
all_requirements_met: $all_requirements_met
|
||
|
|
missing_tools: $missing_tools
|
||
|
|
internet_available: $detection_report.network.internet_connected
|
||
|
|
recommended_tools: [
|
||
|
|
"kcl",
|
||
|
|
"sops",
|
||
|
|
"age",
|
||
|
|
"docker" # or kubernetes or ssh
|
||
|
|
]
|
||
|
|
}
|
||
|
|
}
|