542 lines
14 KiB
Text
542 lines
14 KiB
Text
# 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
|
|
}
|
|
}
|