From fe17c55bd0d35f78200d1253114b192d2ec7a370 Mon Sep 17 00:00:00 2001 From: Slawek Koszewski Date: Wed, 13 Aug 2025 22:28:17 +0200 Subject: [PATCH] Reengineered code. --- netbox-dns-updater.go | 142 ++++++++++++++++++++++++++++++------------ 1 file changed, 101 insertions(+), 41 deletions(-) diff --git a/netbox-dns-updater.go b/netbox-dns-updater.go index 99d8ad8..ac1d627 100644 --- a/netbox-dns-updater.go +++ b/netbox-dns-updater.go @@ -61,7 +61,94 @@ func FetchNetboxIPAddresses(apiBaseURL, token string) ([]IPAddress, error) { return filtered, nil } -func CreateDnsMasqConfig(writeConfig bool) { +var apiBaseURL string + +func main() { + if len(os.Args) < 2 { + fmt.Fprintf(os.Stderr, "Usage: %s [flags]\n", os.Args[0]) + os.Exit(1) + } + + subCmd := os.Args[1] + // Prepare a FlagSet for subcommands, sharing the same flags + flags := flag.NewFlagSet(subCmd, flag.ExitOnError) + + var apiURL string + var outputFormat string + var outputFile string + var outputDir string + var dryRun bool + var listenAddr string + + flags.StringVar(&apiURL, "api-url", "https://netbox.koszewscy.waw.pl/api", "NetBox API URL to fetch IP addresses") + flags.StringVar(&outputFormat, "output-format", "hosts", "output format: config or hosts") + flags.StringVar(&outputFile, "output-file", "", "output file name (overrides default)") + flags.StringVar(&outputDir, "output-dir", "", "output base directory (overrides default)") + flags.BoolVar(&dryRun, "dry-run", false, "if set, do not write to dnsmasq config file, just print the output") + flags.StringVar(&listenAddr, "listen", ":8080", "address and port to listen on (e.g. :8080 or 127.0.0.1:8080)") + + flags.Parse(os.Args[2:]) + apiBaseURL = apiURL + + // Set defaults based on output format + var defaultDir, defaultFile string + switch outputFormat { + case "hosts": + defaultDir = "/etc" + defaultFile = "hosts.netbox" + case "config": + defaultDir = "/etc/dnsmasq.d" + defaultFile = "netbox.conf" + default: + log.Fatalf("Unknown output format: %s", outputFormat) + } + dir := defaultDir + file := defaultFile + if outputDir != "" { + dir = outputDir + } + if outputFile != "" { + file = outputFile + } + + switch subCmd { + case "run": + if listenAddr != ":8080" && listenAddr != "" { + log.Fatalf("The --listen flag is only valid with the 'serve' subcommand.") + } + if dryRun { + log.Println("Dry run mode enabled, not writing to dnsmasq config file.") + CreateDnsMasqConfig(true, outputFormat, dir, file) + } else { + CreateDnsMasqConfig(false, outputFormat, dir, file) + } + case "serve": + http.HandleFunc("/update-dnsmasq", func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + w.WriteHeader(http.StatusMethodNotAllowed) + w.Write([]byte("Method not allowed")) + return + } + CreateDnsMasqConfig(false, outputFormat, dir, file) + cmd := exec.Command("systemctl", "restart", "dnsmasq.service") + if err := cmd.Run(); err != nil { + log.Printf("Failed to restart dnsmasq.service: %v", err) + w.Write([]byte("\nWarning: Failed to restart dnsmasq.service.\n")) + } + w.Write([]byte("DNSMasq config updated.")) + }) + log.Printf("Starting web service on %s...", listenAddr) + if err := http.ListenAndServe(listenAddr, nil); err != nil { + log.Fatalf("Failed to start server: %v", err) + } + default: + fmt.Fprintf(os.Stderr, "Unknown subcommand: %s\n", subCmd) + os.Exit(1) + } +} + +// Update CreateDnsMasqConfig to accept new parameters +func CreateDnsMasqConfig(writeConfig bool, outputFormat, dir, file string) { token := os.Getenv("NETBOX_TOKEN") if token == "" { home := os.Getenv("HOME") @@ -86,53 +173,26 @@ func CreateDnsMasqConfig(writeConfig bool) { log.Fatalf("Error fetching IP addresses: %v", err) } - dir := "/etc/dnsmasq.d" if stat, err := os.Stat(dir); err == nil && stat.IsDir() && !writeConfig { - file, err := os.Create(dir + "/netbox.conf") + f, err := os.Create(path.Join(dir, file)) if err != nil { - log.Fatalf("Failed to create netbox.conf: %v", err) + log.Fatalf("Failed to create %s: %v", file, err) } - defer file.Close() + defer f.Close() for _, ip := range ips { - fmt.Fprintf(file, "address=/%s/%s\n", ip.DNSName, ip.Address) + if outputFormat == "hosts" { + fmt.Fprintf(f, "%s\t%s\n", ip.Address, ip.DNSName) + } else { + fmt.Fprintf(f, "address=/%s/%s\n", ip.DNSName, ip.Address) + } } } else { for _, ip := range ips { - fmt.Printf("address=/%s/%s\n", ip.DNSName, ip.Address) + if outputFormat == "hosts" { + fmt.Printf("%s\t%s\n", ip.Address, ip.DNSName) + } else { + fmt.Printf("address=/%s/%s\n", ip.DNSName, ip.Address) + } } } } - -var apiBaseURL string - -func main() { - listenAddr := flag.String("listen", ":8080", "address and port to listen on (e.g. :8080 or 127.0.0.1:8080)") - flag.StringVar(&apiBaseURL, "api-url", "https://netbox.koszewscy.waw.pl/api", "NetBox API URL to fetch IP addresses") - dryRun := flag.Bool("dry-run", false, "if set, do not write to dnsmasq config file, just print the output") - flag.Parse() - - if *dryRun { - log.Println("Dry run mode enabled, not writing to dnsmasq config file.") - CreateDnsMasqConfig(true) - return - } - - http.HandleFunc("/update-dnsmasq", func(w http.ResponseWriter, r *http.Request) { - if r.Method != http.MethodGet { - w.WriteHeader(http.StatusMethodNotAllowed) - w.Write([]byte("Method not allowed")) - return - } - CreateDnsMasqConfig(false) - cmd := exec.Command("systemctl", "restart", "dnsmasq.service") - if err := cmd.Run(); err != nil { - log.Printf("Failed to restart dnsmasq.service: %v", err) - w.Write([]byte("\nWarning: Failed to restart dnsmasq.service.\n")) - } - w.Write([]byte("DNSMasq config updated.")) - }) - log.Printf("Starting web service on %s...", *listenAddr) - if err := http.ListenAndServe(*listenAddr, nil); err != nil { - log.Fatalf("Failed to start server: %v", err) - } -}