fix: initialize dns provider just once at startup

This commit is contained in:
2025-04-25 21:30:28 +02:00
parent 4819f92569
commit a77e96be6e
2 changed files with 55 additions and 42 deletions

View File

@@ -47,9 +47,7 @@ type updateRequest struct {
}
// NewRouter constructs the HTTP handler with routes, middleware, logging and metrics.
func NewRouter(cfg *config.Config) *gin.Engine {
logger, _ := zap.NewProduction()
func NewRouter(cfg *config.Config, logger *zap.Logger, prov pvd.Provider) *gin.Engine {
r := gin.New()
r.Use(gin.Recovery())
r.Use(func(c *gin.Context) {
@@ -106,12 +104,7 @@ func NewRouter(cfg *config.Config) *gin.Engine {
c.JSON(http.StatusForbidden, gin.H{"status": "error", "message": "host not authorized"})
return
}
prov, err := selectProvider(cfg)
if err != nil {
logger.Error("provider selection failed", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"status": "error", "message": "provider configuration error"})
return
}
// Provider is now initialized at startup and passed in
if err := prov.UpdateRecord(c.Request.Context(), req.Host, ip); err != nil {
failedUpdates.Inc()
logger.Error("update record failed", zap.Error(err))
@@ -127,39 +120,29 @@ func NewRouter(cfg *config.Config) *gin.Engine {
// StartServer initializes Provider and starts the HTTP server.
func StartServer(cfg *config.Config) error {
// Provider selection happens within the request handler now to handle potential config errors per request
// We could pre-validate the provider config here, but deferring allows checking file existence/permissions closer to use.
// A simple check that the provider *name* is supported is still useful.
if _, supported := configToProviderName(cfg.Upstream.Provider); !supported {
return fmt.Errorf("unsupported provider name in config: %q", cfg.Upstream.Provider)
}
logger, _ := zap.NewProduction() // Initialize logger once
router := NewRouter(cfg)
// Initialize provider at startup
prov, err := selectProvider(cfg)
if err != nil {
logger.Error("failed to initialize provider", zap.Error(err))
return fmt.Errorf("provider initialization failed: %w", err)
}
logger.Info("provider initialized successfully", zap.String("provider", cfg.Upstream.Provider))
router := NewRouter(cfg, logger, prov) // Pass logger and provider
if cfg.Server.TLS.Enabled {
logger.Info("starting TLS server", zap.String("address", cfg.Server.BindAddress))
return router.RunTLS(cfg.Server.BindAddress, cfg.Server.TLS.CertFile, cfg.Server.TLS.KeyFile)
}
logger.Info("starting HTTP server", zap.String("address", cfg.Server.BindAddress))
return router.Run(cfg.Server.BindAddress)
}
// configToProviderName checks if a provider name from the config is known.
// This is a simple check before attempting full provider initialization.
func configToProviderName(providerName string) (string, bool) {
switch providerName {
case "hetzner":
return "hetzner", true
default:
return "", false
}
}
// selectProvider returns the configured Provider or an error if initialization fails.
func selectProvider(cfg *config.Config) (pvd.Provider, error) {
providerName, supported := configToProviderName(cfg.Upstream.Provider)
if !supported {
return nil, fmt.Errorf("unsupported provider: %s", cfg.Upstream.Provider)
}
switch providerName {
// configToProviderName logic is effectively duplicated here, safe to remove the separate function if only used here.
switch cfg.Upstream.Provider {
case "hetzner":
prov, err := hetzner.NewProvider(cfg.Upstream.Hetzner)
if err != nil {
@@ -168,6 +151,6 @@ func selectProvider(cfg *config.Config) (pvd.Provider, error) {
return prov, nil
default:
// This case should technically be unreachable due to the check above
return nil, fmt.Errorf("internal error: unsupported provider %s passed initial check", providerName)
return nil, fmt.Errorf("internal error: unsupported provider %s passed initial check", cfg.Upstream.Provider)
}
}