initial commit
This commit is contained in:
1 parent
5b935301e5
commit
85453852d5
105 files changed
+24846
No files matched your search
@@ -0,0 +1,126 @@
|
||||
// Command fancy-dns is a caching, blocklist-aware recursive DNS server with
|
||||
// DNS-over-TLS, DNS-over-HTTPS and an embedded admin console.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"git.k8s-git-k6n.net/mats/fancy-dns/internal/app"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
configPath = flag.String("config", envOr("FANCYDNS_CONFIG", "/etc/fancy-dns/config.yaml"), "path to the configuration file")
|
||||
showVersion = flag.Bool("version", false, "print the version and exit")
|
||||
checkOnly = flag.Bool("check", false, "validate the configuration and exit")
|
||||
logLevel = flag.String("log-level", os.Getenv("FANCYDNS_LOG_LEVEL"), "override log level (debug, info, warn, error)")
|
||||
logFormat = flag.String("log-format", os.Getenv("FANCYDNS_LOG_FORMAT"), "override log format (text, json)")
|
||||
adminAddr = flag.String("admin-addr", os.Getenv("FANCYDNS_ADMIN_ADDR"), "override the admin API listen address")
|
||||
)
|
||||
flag.Parse()
|
||||
|
||||
if *showVersion {
|
||||
fmt.Println("fancy-dns", app.Version)
|
||||
return
|
||||
}
|
||||
|
||||
if err := run(runOptions{
|
||||
configPath: *configPath,
|
||||
logLevel: *logLevel,
|
||||
logFormat: *logFormat,
|
||||
adminAddr: *adminAddr,
|
||||
checkOnly: *checkOnly,
|
||||
}); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "fancy-dns:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
type runOptions struct {
|
||||
configPath string
|
||||
logLevel string
|
||||
logFormat string
|
||||
adminAddr string
|
||||
checkOnly bool
|
||||
}
|
||||
|
||||
func run(o runOptions) error {
|
||||
a, err := app.New(app.Options{
|
||||
ConfigPath: o.configPath,
|
||||
Version: app.Version,
|
||||
LogLevel: o.logLevel,
|
||||
LogFormat: o.logFormat,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if o.checkOnly {
|
||||
fmt.Println("configuration is valid:", o.configPath)
|
||||
return nil
|
||||
}
|
||||
if o.adminAddr != "" {
|
||||
// Bind the admin API elsewhere without touching the config file, which
|
||||
// is what a container platform wants.
|
||||
if err := a.SetAdminAddr(o.adminAddr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// SIGINT/SIGTERM start a graceful shutdown; SIGHUP reloads the config.
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
sig := make(chan os.Signal, 4)
|
||||
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
|
||||
defer signal.Stop(sig)
|
||||
|
||||
if err := a.Start(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
reloadErr := make(chan error, 1)
|
||||
go func() {
|
||||
for s := range sig {
|
||||
switch s {
|
||||
case syscall.SIGHUP:
|
||||
a.Log().Info("SIGHUP received, reloading configuration")
|
||||
if err := a.Reload(); err != nil {
|
||||
// A failed reload must not kill the server: the previous
|
||||
// configuration keeps serving and the error shows in /api.
|
||||
a.Log().Error("reload failed, keeping the running configuration", "error", err)
|
||||
}
|
||||
default:
|
||||
a.Log().Info("signal received, shutting down", "signal", s.String())
|
||||
cancel()
|
||||
select {
|
||||
case reloadErr <- nil:
|
||||
default:
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
<-ctx.Done()
|
||||
|
||||
// Give in-flight queries a moment to finish before tearing listeners down.
|
||||
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||
defer shutdownCancel()
|
||||
if err := a.Stop(shutdownCtx); err != nil {
|
||||
return err
|
||||
}
|
||||
return <-reloadErr
|
||||
}
|
||||
|
||||
func envOr(key, def string) string {
|
||||
if v := os.Getenv(key); v != "" {
|
||||
return v
|
||||
}
|
||||
return def
|
||||
}
|
||||
Reference in new issue
Block a user