2026-01-14 02:00:23 +00:00
|
|
|
# Hetzner Cloud caching operations
|
|
|
|
|
use env.nu *
|
2025-10-07 10:32:04 +01:00
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
# Initialize cache directory
|
|
|
|
|
export def hetzner_start_cache_info [settings: record, server: string]: nothing -> null {
|
|
|
|
|
if not ($settings | has provider) or not ($settings.provider | has paths) {
|
|
|
|
|
return null
|
|
|
|
|
}
|
2025-10-07 10:32:04 +01:00
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
let cache_dir = $"($settings.provider.paths.cache)"
|
2025-10-07 10:32:04 +01:00
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
if not ($cache_dir | path exists) {
|
|
|
|
|
mkdir $cache_dir
|
2025-10-07 10:32:04 +01:00
|
|
|
}
|
|
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
null
|
2025-10-07 10:32:04 +01:00
|
|
|
}
|
|
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
# Create cache entry for server
|
|
|
|
|
export def hetzner_create_cache [settings: record, server: string, error_exit: bool = true]: nothing -> null {
|
|
|
|
|
try {
|
|
|
|
|
hetzner_start_cache_info $settings $server
|
2025-10-07 10:32:04 +01:00
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
let cache_dir = $"($settings.provider.paths.cache)"
|
|
|
|
|
let cache_file = $"($cache_dir)/($server).json"
|
2025-10-07 10:32:04 +01:00
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
let cache_data = {
|
|
|
|
|
server: $server
|
|
|
|
|
timestamp: (now)
|
|
|
|
|
cached_at: (date now | date to-record)
|
2025-10-07 10:32:04 +01:00
|
|
|
}
|
|
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
$cache_data | to json | save --force $cache_file
|
|
|
|
|
} catch {|err|
|
|
|
|
|
if $error_exit {
|
|
|
|
|
error make {msg: $"Failed to create cache: ($err.msg)"}
|
|
|
|
|
}
|
2025-10-07 10:32:04 +01:00
|
|
|
}
|
|
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
null
|
2025-10-07 10:32:04 +01:00
|
|
|
}
|
|
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
# Read cache entry
|
|
|
|
|
export def hetzner_read_cache [settings: record, server: string, error_exit: bool = true]: nothing -> record {
|
|
|
|
|
try {
|
|
|
|
|
let cache_dir = $"($settings.provider.paths.cache)"
|
|
|
|
|
let cache_file = $"($cache_dir)/($server).json"
|
2025-10-07 10:32:04 +01:00
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
if not ($cache_file | path exists) {
|
|
|
|
|
if $error_exit {
|
|
|
|
|
error make {msg: $"Cache file not found: ($cache_file)"}
|
2025-10-07 10:32:04 +01:00
|
|
|
}
|
2026-01-14 02:00:23 +00:00
|
|
|
return {}
|
2025-10-07 10:32:04 +01:00
|
|
|
}
|
|
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
open $cache_file | from json
|
|
|
|
|
} catch {|err|
|
|
|
|
|
if $error_exit {
|
|
|
|
|
error make {msg: $"Failed to read cache: ($err.msg)"}
|
|
|
|
|
}
|
|
|
|
|
{}
|
2025-10-07 10:32:04 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
# Clean cache entry
|
|
|
|
|
export def hetzner_clean_cache [settings: record, server: string, error_exit: bool = true]: nothing -> null {
|
|
|
|
|
try {
|
|
|
|
|
let cache_dir = $"($settings.provider.paths.cache)"
|
|
|
|
|
let cache_file = $"($cache_dir)/($server).json"
|
2025-10-07 10:32:04 +01:00
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
if ($cache_file | path exists) {
|
|
|
|
|
rm $cache_file
|
2025-10-07 10:32:04 +01:00
|
|
|
}
|
2026-01-14 02:00:23 +00:00
|
|
|
} catch {|err|
|
|
|
|
|
if $error_exit {
|
|
|
|
|
error make {msg: $"Failed to clean cache: ($err.msg)"}
|
2025-10-07 10:32:04 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
null
|
2025-10-07 10:32:04 +01:00
|
|
|
}
|
|
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
# Get IP from cache
|
|
|
|
|
export def hetzner_ip_from_cache [settings: record, server: string, error_exit: bool = true]: nothing -> string {
|
|
|
|
|
try {
|
|
|
|
|
let cache = (hetzner_read_cache $settings $server false)
|
2025-10-07 10:32:04 +01:00
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
if ($cache | has ip) {
|
|
|
|
|
$cache.ip
|
|
|
|
|
} else {
|
|
|
|
|
""
|
2025-10-07 10:32:04 +01:00
|
|
|
}
|
2026-01-14 02:00:23 +00:00
|
|
|
} catch {
|
|
|
|
|
""
|
2025-10-07 10:32:04 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
# Update cache with server data
|
|
|
|
|
export def hetzner_update_cache [settings: record, server: record, error_exit: bool = true]: nothing -> null {
|
|
|
|
|
try {
|
|
|
|
|
hetzner_start_cache_info $settings $server.hostname
|
2025-10-07 10:32:04 +01:00
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
let cache_dir = $"($settings.provider.paths.cache)"
|
|
|
|
|
let cache_file = $"($cache_dir)/($server.hostname).json"
|
2025-10-07 10:32:04 +01:00
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
let cache_data = {
|
|
|
|
|
server: $server.hostname
|
|
|
|
|
server_id: ($server.id | default "")
|
|
|
|
|
ipv4: ($server.public_net.ipv4.ip | default "")
|
|
|
|
|
ipv6: ($server.public_net.ipv6.ip | default "")
|
|
|
|
|
status: ($server.status | default "")
|
|
|
|
|
location: ($server.location.name | default "")
|
|
|
|
|
server_type: ($server.server_type.name | default "")
|
|
|
|
|
timestamp: (now)
|
|
|
|
|
cached_at: (date now | date to-record)
|
2025-10-07 10:32:04 +01:00
|
|
|
}
|
|
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
$cache_data | to json | save --force $cache_file
|
|
|
|
|
} catch {|err|
|
|
|
|
|
if $error_exit {
|
|
|
|
|
error make {msg: $"Failed to update cache: ($err.msg)"}
|
2025-10-07 10:32:04 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
null
|
2025-10-07 10:32:04 +01:00
|
|
|
}
|
|
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
# Clean all cache
|
|
|
|
|
export def hetzner_clean_all_cache [settings: record, error_exit: bool = true]: nothing -> null {
|
|
|
|
|
try {
|
|
|
|
|
let cache_dir = $"($settings.provider.paths.cache)"
|
2025-10-07 10:32:04 +01:00
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
if ($cache_dir | path exists) {
|
|
|
|
|
rm -r $cache_dir
|
2025-10-07 10:32:04 +01:00
|
|
|
}
|
|
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
mkdir $cache_dir
|
|
|
|
|
} catch {|err|
|
|
|
|
|
if $error_exit {
|
|
|
|
|
error make {msg: $"Failed to clean all cache: ($err.msg)"}
|
|
|
|
|
}
|
2025-10-07 10:32:04 +01:00
|
|
|
}
|
|
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
null
|
2025-10-07 10:32:04 +01:00
|
|
|
}
|
|
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
# Get cache age in seconds
|
|
|
|
|
export def hetzner_cache_age [cache_data: record]: nothing -> int {
|
|
|
|
|
if not ($cache_data | has timestamp) {
|
|
|
|
|
return -1
|
2025-10-07 10:32:04 +01:00
|
|
|
}
|
|
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
let cached_ts = ($cache_data.timestamp | into int)
|
|
|
|
|
let now_ts = (now | into int)
|
|
|
|
|
$now_ts - $cached_ts
|
2025-10-07 10:32:04 +01:00
|
|
|
}
|
|
|
|
|
|
2026-01-14 02:00:23 +00:00
|
|
|
# Check if cache is still valid
|
|
|
|
|
export def hetzner_cache_valid [cache_data: record, ttl_seconds: int = 3600]: nothing -> bool {
|
|
|
|
|
let age = (hetzner_cache_age $cache_data)
|
|
|
|
|
if $age < 0 {return false}
|
|
|
|
|
$age < $ttl_seconds
|
chore: complete KCL to Nickel migration cleanup and setup pre-commit
Clean up 404 KCL references (99.75% complete):
- Rename kcl_* variables to schema_*/nickel_* (kcl_path→schema_path, etc.)
- Update functions: parse_kcl_file→parse_nickel_file
- Update env vars: KCL_MOD_PATH→NICKEL_IMPORT_PATH
- Fix cli/providers-install: add has_nickel and nickel_version variables
- Correct import syntax: .nickel.→.ncl.
- Update 57 files across core, CLI, config, and utilities
Configure pre-commit hooks:
- Activate: nushell-check, nickel-typecheck, markdownlint
- Comment out: Rust hooks (fmt, clippy, test), check-yaml
Testing:
- Module discovery: 9 modules (6 providers, 1 taskserv, 2 clusters) ✅
- Syntax validation: 15 core files ✅
- Pre-commit hooks: all passing ✅
2026-01-08 20:08:46 +00:00
|
|
|
}
|