flake-update-20260505
  1#!/usr/bin/env bash
  2# Display DNS zone entries generated from Nix configuration
  3
  4set -euo pipefail
  5
  6# Color codes for output
  7BOLD='\033[1m'
  8DIM='\033[2m'
  9GREEN='\033[0;32m'
 10BLUE='\033[0;34m'
 11YELLOW='\033[0;33m'
 12CYAN='\033[0;36m'
 13MAGENTA='\033[0;35m'
 14RED='\033[0;31m'
 15RESET='\033[0m'
 16
 17# Parse arguments
 18VERBOSE=0
 19HOST="${1:-demeter}"
 20
 21if [[ "${1:-}" == "--verbose" ]] || [[ "${2:-}" == "--verbose" ]]; then
 22    VERBOSE=1
 23    HOST="${2:-${1:-demeter}}"
 24    if [[ "$HOST" == "--verbose" ]]; then
 25        HOST="demeter"
 26    fi
 27fi
 28
 29# Define zones
 30ZONES=(
 31    "sbr.pm"
 32    "home"
 33    "vpn"
 34    "192.168.1.in-addr.arpa"
 35    "10.100.0.in-addr.arpa"
 36)
 37
 38# Function to colorize DNS record type
 39colorize_type() {
 40    local type="$1"
 41    case "$type" in
 42        SOA) echo -e "${MAGENTA}${type}${RESET}" ;;
 43        NS) echo -e "${CYAN}${type}${RESET}" ;;
 44        A) echo -e "${GREEN}${type}${RESET}" ;;
 45        AAAA) echo -e "${GREEN}${type}${RESET}" ;;
 46        CNAME) echo -e "${YELLOW}${type}${RESET}" ;;
 47        MX) echo -e "${BLUE}${type}${RESET}" ;;
 48        TXT) echo -e "${DIM}${type}${RESET}" ;;
 49        PTR) echo -e "${CYAN}${type}${RESET}" ;;
 50        *) echo -e "${type}" ;;
 51    esac
 52}
 53
 54# Function to parse and display zone in compact format
 55show_zone_compact() {
 56    local zone_name="$1"
 57    local zone_content="$2"
 58
 59    echo -e "${BOLD}${BLUE}━━━ ${zone_name} ━━━${RESET}"
 60
 61    # Count records by type
 62    local soa_count
 63    local ns_count
 64    local a_count
 65    local cname_count
 66    local ptr_count
 67    soa_count=$(echo "$zone_content" | grep -c " IN SOA " || true)
 68    ns_count=$(echo "$zone_content" | grep -c " IN NS " || true)
 69    a_count=$(echo "$zone_content" | grep -c " IN A " || true)
 70    cname_count=$(echo "$zone_content" | grep -c " IN CNAME " || true)
 71    ptr_count=$(echo "$zone_content" | grep -c " IN PTR " || true)
 72
 73    # Show summary
 74    echo -e "${DIM}Records: SOA:${soa_count} NS:${ns_count} A:${a_count} CNAME:${cname_count} PTR:${ptr_count}${RESET}"
 75    echo
 76
 77    # Parse and display records in organized format
 78    local record_type=""
 79    local prev_type=""
 80
 81    while IFS= read -r line; do
 82        # Skip empty lines and TTL
 83        [[ -z "$line" || "$line" =~ ^\$TTL ]] && continue
 84
 85        # Parse record type
 86        if [[ "$line" =~ IN\ (SOA|NS|A|AAAA|CNAME|MX|TXT|PTR) ]]; then
 87            record_type="${BASH_REMATCH[1]}"
 88
 89            # Add spacing between different record types
 90            if [[ -n "$prev_type" && "$prev_type" != "$record_type" ]]; then
 91                echo
 92            fi
 93            prev_type="$record_type"
 94
 95            # Format the line based on type
 96            if [[ "$record_type" == "SOA" ]]; then
 97                # SOA records - just show they exist
 98                echo -e "  $(colorize_type SOA) ${DIM}${line}${RESET}"
 99                continue
100            elif [[ "$record_type" == "NS" ]]; then
101                # NS records
102                local name
103                local target
104                name=$(echo "$line" | awk '{print $1}')
105                target=$(echo "$line" | awk '{print $NF}')
106                printf "  %-30s $(colorize_type NS)  → %s\n" "$name" "$target"
107            elif [[ "$record_type" == "A" ]]; then
108                # A records - show name and IP
109                local name
110                local ip
111                local ttl
112                name=$(echo "$line" | awk '{print $1}')
113                ip=$(echo "$line" | awk '{print $NF}')
114                ttl=""
115
116                # Check if there's a TTL
117                if [[ "$line" =~ [0-9]+\ IN\ A ]]; then
118                    ttl=$(echo "$line" | awk '{print $2}')
119                    printf "  %-30s $(colorize_type A)    %s ${DIM}(TTL: %s)${RESET}\n" "$name" "$ip" "$ttl"
120                else
121                    printf "  %-30s $(colorize_type A)    %s\n" "$name" "$ip"
122                fi
123            elif [[ "$record_type" == "PTR" ]]; then
124                # PTR records - reverse lookup
125                local name
126                local target
127                name=$(echo "$line" | awk '{print $1}')
128                target=$(echo "$line" | awk '{print $NF}')
129                printf "  %-30s $(colorize_type PTR) → %s\n" "$name" "$target"
130            elif [[ "$record_type" == "CNAME" ]]; then
131                # CNAME records
132                local name
133                local target
134                name=$(echo "$line" | awk '{print $1}')
135                target=$(echo "$line" | awk '{print $NF}')
136                printf "  %-30s $(colorize_type CNAME) → %s\n" "$name" "$target"
137            fi
138        fi
139    done <<< "$zone_content"
140
141    echo
142}
143
144# Function to show full zone
145show_zone_verbose() {
146    local zone_name="$1"
147    local zone_content="$2"
148
149    echo -e "${BOLD}${GREEN}═══ Zone: ${zone_name} ═══${RESET}"
150    echo
151    echo "$zone_content" | while IFS= read -r line; do
152        if [[ "$line" =~ IN\ SOA ]]; then
153            echo -e "${MAGENTA}${line}${RESET}"
154        elif [[ "$line" =~ IN\ NS ]]; then
155            echo -e "${CYAN}${line}${RESET}"
156        elif [[ "$line" =~ IN\ A ]]; then
157            echo -e "${GREEN}${line}${RESET}"
158        elif [[ "$line" =~ IN\ CNAME ]]; then
159            echo -e "${YELLOW}${line}${RESET}"
160        elif [[ "$line" =~ IN\ PTR ]]; then
161            echo -e "${CYAN}${line}${RESET}"
162        elif [[ "$line" =~ IN\ (SRV|MX|TXT) ]]; then
163            echo -e "${BLUE}${line}${RESET}"
164        elif [[ "$line" =~ ^\$TTL ]]; then
165            echo -e "${DIM}${line}${RESET}"
166        else
167            echo "$line"
168        fi
169    done
170    echo
171}
172
173# Header
174echo -e "${BOLD}${CYAN}DNS Zones for ${HOST}${RESET}"
175echo -e "${DIM}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
176echo
177
178# Process each zone
179total_zones=0
180failed_zones=0
181
182for zone_name in "${ZONES[@]}"; do
183    # Get the zone file content directly
184    zone_content=$(nix eval --raw ".#nixosConfigurations.${HOST}.config.services.bind.zones.\"${zone_name}\".file" --apply 'path: builtins.readFile path' 2>&1 | grep -v "^warning:" | grep -v "^Using saved setting" | grep -v "^building " || true)
185
186    if [[ -n "$zone_content" ]] && [[ "$zone_content" != *"error"* ]]; then
187        total_zones=$((total_zones + 1))
188
189        if [[ $VERBOSE -eq 1 ]]; then
190            show_zone_verbose "$zone_name" "$zone_content"
191        else
192            show_zone_compact "$zone_name" "$zone_content"
193        fi
194    else
195        failed_zones=$((failed_zones + 1))
196        echo -e "${YELLOW}⚠ Could not generate zone ${zone_name}${RESET}"
197        echo
198    fi
199done
200
201# Summary
202echo -e "${DIM}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
203echo -e "${BOLD}Summary:${RESET} Generated ${GREEN}${total_zones}${RESET} zones successfully"
204[[ $failed_zones -gt 0 ]] && echo -e "         Failed to generate ${RED}${failed_zones}${RESET} zones"
205echo
206
207# Usage info
208if [[ $VERBOSE -eq 0 ]]; then
209    echo -e "${DIM}Tip: Use --verbose flag to see full zone files${RESET}"
210fi
211echo -e "${DIM}Usage: $0 [--verbose] [hostname]${RESET}"