provisioning-core/nulib/domain/coredns/service.nu

543 lines
14 KiB
Text
Raw Permalink Normal View History

# CoreDNS Service Manager
# Start, stop, and manage CoreDNS service
# ../utils/log.nu does not exist — dangling import removed (ADR-025 L2).
use domain/coredns/corefile.nu [generate-corefile write-corefile]
use zones.nu create-zone-file
# Start CoreDNS service
export def start-coredns [
config: record # CoreDNS configuration
--foreground (-f) # Run in foreground
--check # Check mode (don't actually start)
] -> bool {
log info "Starting CoreDNS service"
if $check {
log info "Check mode: Would start CoreDNS"
return true
}
let mode = $config.mode? | default "local"
if $mode == "disabled" {
log warn "CoreDNS is disabled in configuration"
return false
}
if $mode != "local" {
log warn $"Cannot start CoreDNS in ($mode) mode"
return false
}
let local_config = $config.local? | default {}
let deployment_type = $local_config.deployment_type? | default "binary"
match $deployment_type {
"binary" => { start-coredns-binary $config $foreground }
"docker" => { start-coredns-docker $config }
_ => {
log error $"Unknown deployment type: ($deployment_type)"
false
}
}
}
# Start CoreDNS as binary
def start-coredns-binary [
config: record
foreground: bool
] -> bool {
let local_config = $config.local? | default {}
let binary_path = $local_config.binary_path? | default "~/.provisioning/bin/coredns" | path expand
let config_path = $local_config.config_path? | default "~/.provisioning/coredns/Corefile" | path expand
let zones_path = $local_config.zones_path? | default "~/.provisioning/coredns/zones" | path expand
let pid_file = $local_config.pid_file? | default "~/.provisioning/coredns/coredns.pid" | path expand
let log_file = $local_config.log_file? | default "~/.provisioning/coredns/coredns.log" | path expand
# Check if CoreDNS binary exists
if not ($binary_path | path exists) {
log error $"CoreDNS binary not found at ($binary_path)"
log info "Install CoreDNS with: provisioning dns install"
return false
}
# Check if already running
if is-coredns-running {
log warn "CoreDNS is already running"
return false
}
# Ensure directories exist
let config_dir = $config_path | path dirname
let zones_dir = $zones_path
let log_dir = $log_file | path dirname
mkdir $config_dir
mkdir $zones_dir
mkdir $log_dir
# Generate Corefile
log info "Generating Corefile"
let corefile_content = generate-corefile $config
write-corefile $config_path $corefile_content
# Create zone files if they don't exist
let zones = $local_config.zones? | default ["provisioning.local"]
for zone in $zones {
let zone_file = $"($zones_path)/($zone).zone"
if not ($zone_file | path exists) {
log info $"Creating zone file for ($zone)"
create-zone-file $zone $zones_path --config $config
}
}
# Start CoreDNS
if $foreground {
log info "Starting CoreDNS in foreground"
let result = (do {
^$binary_path -conf $config_path
} | complete)
if $result.exit_code == 0 {
true
} else {
log error "Failed to start CoreDNS"
false
}
} else {
log info "Starting CoreDNS in background"
let result = (do {
# Start in background and capture PID
nu -c $"^($binary_path) -conf ($config_path) > ($log_file) 2>&1 & echo $\"($env.LAST_EXIT_CODE)\""
} | complete)
if $result.exit_code != 0 {
log error "Failed to start CoreDNS"
return false
}
# Give it a moment to start
sleep 1sec
# Check if process is running
if is-coredns-running {
log info "CoreDNS started successfully"
true
} else {
log error "CoreDNS failed to start, check logs"
false
}
}
}
# Start CoreDNS in Docker
def start-coredns-docker [
config: record
] -> bool {
log info "Starting CoreDNS in Docker"
let local_config = $config.local? | default {}
let docker_config = $local_config.docker? | default {}
let image = $docker_config.image? | default "coredns/coredns:1.11.1"
let container_name = $docker_config.container_name? | default "provisioning-coredns"
let config_path = $local_config.config_path? | default "~/.provisioning/coredns/Corefile" | path expand
let zones_path = $local_config.zones_path? | default "~/.provisioning/coredns/zones" | path expand
let port = $local_config.port? | default 5353
# Check if container already running
let running = (docker ps --filter $"name=($container_name)" --format "{{.Names}}" | complete | get stdout | str trim)
if ($running | str contains $container_name) {
log warn "CoreDNS container is already running"
return false
}
# Generate Corefile
let corefile_content = generate-corefile $config
write-corefile $config_path $corefile_content
# Create zone files
let zones = $local_config.zones? | default ["provisioning.local"]
for zone in $zones {
let zone_file = $"($zones_path)/($zone).zone"
if not ($zone_file | path exists) {
create-zone-file $zone $zones_path --config $config
}
}
# Start Docker container
let result = (do {
docker run -d \
--name $container_name \
-p $"($port):53/udp" \
-p $"($port):53/tcp" \
-v $"($config_path):/Corefile:ro" \
-v $"($zones_path):/zones:ro" \
--restart unless-stopped \
$image -conf /Corefile
} | complete)
if $result.exit_code == 0 {
log info $"CoreDNS Docker container started: [$container_name]"
true
} else {
log error "Failed to start CoreDNS Docker container"
false
}
}
# Stop CoreDNS service
export def stop-coredns [
--config: record = {}
--check
] -> bool {
log info "Stopping CoreDNS service"
if $check {
log info "Check mode: Would stop CoreDNS"
return true
}
let local_config = $config.local? | default {}
let deployment_type = $local_config.deployment_type? | default "binary"
match $deployment_type {
"binary" => { stop-coredns-binary }
"docker" => { stop-coredns-docker $config }
_ => {
log error $"Unknown deployment type: ($deployment_type)"
false
}
}
}
# Stop CoreDNS binary
def stop-coredns-binary [] -> bool {
if not (is-coredns-running) {
log warn "CoreDNS is not running"
return false
}
let pid = get-coredns-pid
if $pid == null {
log error "Cannot determine CoreDNS PID"
return false
}
let result = (do {
kill $pid
} | complete)
if $result.exit_code == 0 {
log info "CoreDNS stopped"
true
} else {
log error "Failed to stop CoreDNS"
false
}
}
# Stop CoreDNS Docker container
def stop-coredns-docker [
config: record
] -> bool {
let local_config = $config.local? | default {}
let docker_config = $local_config.docker? | default {}
let container_name = $docker_config.container_name? | default "provisioning-coredns"
let result = (do {
docker stop $container_name
docker rm $container_name
} | complete)
if $result.exit_code == 0 {
log info $"CoreDNS Docker container stopped: [$container_name]"
true
} else {
log error "Failed to stop CoreDNS Docker container"
false
}
}
# Reload CoreDNS configuration
export def reload-coredns [
--config: record = {}
] -> bool {
log info "Reloading CoreDNS configuration"
let local_config = $config.local? | default {}
let deployment_type = $local_config.deployment_type? | default "binary"
match $deployment_type {
"binary" => { reload-coredns-binary }
"docker" => { reload-coredns-docker $config }
_ => {
log error $"Unknown deployment type: ($deployment_type)"
false
}
}
}
# Reload CoreDNS binary (SIGUSR1)
def reload-coredns-binary [] -> bool {
if not (is-coredns-running) {
log error "CoreDNS is not running"
return false
}
let pid = get-coredns-pid
if $pid == null {
log error "Cannot determine CoreDNS PID"
return false
}
let result = (do {
kill -s USR1 $pid
} | complete)
if $result.exit_code == 0 {
log info "CoreDNS reload signal sent"
true
} else {
log error "Failed to reload CoreDNS"
false
}
}
# Reload CoreDNS Docker container
def reload-coredns-docker [
config: record
] -> bool {
let local_config = $config.local? | default {}
let docker_config = $local_config.docker? | default {}
let container_name = $docker_config.container_name? | default "provisioning-coredns"
let result = (do {
# Send SIGUSR1 to CoreDNS process inside container
docker exec $container_name kill -USR1 1
} | complete)
if $result.exit_code == 0 {
log info "CoreDNS Docker container reloaded"
true
} else {
log error "Failed to reload CoreDNS Docker container"
false
}
}
# Get CoreDNS status
export def get-coredns-status [
--config: record = {}
] -> record {
let local_config = $config.local? | default {}
let deployment_type = $local_config.deployment_type? | default "binary"
let running = is-coredns-running
let pid = if $running { get-coredns-pid } else { null }
let health = if $running {
check-coredns-health $config
} else {
false
}
{
running: $running
deployment_type: $deployment_type
pid: $pid
healthy: $health
mode: ($config.mode? | default "local")
}
}
# Check if CoreDNS is running
def is-coredns-running [] -> bool {
let pid_file = "~/.provisioning/coredns/coredns.pid" | path expand
# Check via PID file
if ($pid_file | path exists) {
let pid = open $pid_file | into int
let ps_result = ps | where pid == $pid
if ($ps_result | is-not-empty) {
return true
}
}
# Check via process name
let ps_result = ps | where name =~ "coredns"
($ps_result | is-not-empty)
}
# Get CoreDNS PID
def get-coredns-pid [] -> int {
let pid_file = "~/.provisioning/coredns/coredns.pid" | path expand
if ($pid_file | path exists) {
open $pid_file | into int
} else {
let ps_result = ps | where name =~ "coredns"
if ($ps_result | is-not-empty) {
$ps_result | get 0.pid
} else {
null
}
}
}
# Check CoreDNS health
export def check-coredns-health [
config: record
] -> bool {
log debug "Checking CoreDNS health"
let local_config = $config.local? | default {}
let port = $local_config.port? | default 5353
# Try to query DNS
let result = (do {
dig @127.0.0.1 -p $port provisioning.local
} | complete)
if $result.exit_code == 0 {
log debug "CoreDNS health check passed"
true
} else {
log warn "CoreDNS health check failed"
false
}
}
# Install CoreDNS binary
export def install-coredns [
version?: string = "latest" # Version to install
--check
] -> bool {
log info $"Installing CoreDNS ($version)"
if $check {
log info "Check mode: Would install CoreDNS"
return true
}
let binary_path = "~/.provisioning/bin/coredns" | path expand
let bin_dir = $binary_path | path dirname
# Create bin directory
mkdir $bin_dir
# Determine latest version if needed
let install_version = if $version == "latest" {
get-latest-coredns-version
} else {
$version
}
log info $"Installing CoreDNS version ($install_version)"
# Detect OS and architecture
let os = if (sys host | get name) =~ "Darwin" { "darwin" } else { "linux" }
let arch = uname -m | complete | get stdout | str trim
let arch_name = if $arch == "x86_64" {
"amd64"
} else if $arch == "aarch64" or $arch == "arm64" {
"arm64"
} else {
$arch
}
# Download URL
let download_url = $"https://github.com/coredns/coredns/releases/download/v($install_version)/coredns_($install_version)_($os)_($arch_name).tgz"
log info $"Downloading from ($download_url)"
let temp_dir = mktemp -d
let result = (do {
cd $temp_dir
http get $download_url | save coredns.tgz
tar xzf coredns.tgz
mv coredns $binary_path
chmod +x $binary_path
} | complete)
if $result.exit_code == 0 {
log info $"CoreDNS installed to [$binary_path]"
# Cleanup
rm -rf $temp_dir
true
} else {
log error "Failed to install CoreDNS"
rm -rf $temp_dir
false
}
}
# Get latest CoreDNS version from GitHub
def get-latest-coredns-version [] -> string {
let result = (do {
http get "https://api.github.com/repos/coredns/coredns/releases/latest" | from json
} | complete)
if $result.exit_code == 0 {
let release_info = $result.stdout | from json
$release_info.tag_name | str replace "v" ""
} else {
log warn "Failed to get latest version, using default"
"1.11.1"
}
}
# Restart CoreDNS service
export def restart-coredns [
config: record
--check
] -> bool {
log info "Restarting CoreDNS service"
if $check {
log info "Check mode: Would restart CoreDNS"
return true
}
stop-coredns --config $config
sleep 1sec
start-coredns $config
}
# Show CoreDNS logs
export def show-coredns-logs [
--lines: int = 50
--follow (-f)
] -> nothing {
let log_file = "~/.provisioning/coredns/coredns.log" | path expand
if not ($log_file | path exists) {
log error "CoreDNS log file not found"
return
}
if $follow {
tail -f -n $lines $log_file
} else {
tail -n $lines $log_file
}
}