1 Commits

Author SHA1 Message Date
75e527737c feat: introduce logger to config
All checks were successful
CI / test (pull_request) Successful in 37s
2024-12-27 17:09:57 +01:00
6 changed files with 24 additions and 146 deletions

View File

@@ -1,23 +0,0 @@
name: CodeQL Analysis
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
codeql-analysis:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: "go"
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3

View File

@@ -38,7 +38,6 @@ domains:
- www - www
check_interval: 0 0 0/6 * * * * check_interval: 0 0 0/6 * * * *
mode: Scheduled mode: Scheduled
log_level: info
``` ```
The config file is expected to be in the same directory as the binary and called `config.yaml`. For the OCR image, the root directory is `/app`. The config file is expected to be in the same directory as the binary and called `config.yaml`. For the OCR image, the root directory is `/app`.

View File

@@ -21,4 +21,3 @@ domains:
- www - www
check_interval: 0 0 0/6 * * * * check_interval: 0 0 0/6 * * * *
mode: Scheduled mode: Scheduled
log_level: info

48
main.go
View File

@@ -25,7 +25,8 @@ func main() {
configClient := config.Config{} configClient := config.Config{}
err := configClient.Load("config.yaml") err := configClient.Load("config.yaml")
if err != nil { if err != nil {
logger.Error("Failed to load config file", slog.String("error", err.Error())) logger.Error("Failed to load config file",
slog.String("error", err.Error()))
panic(err) panic(err)
} }
@@ -38,64 +39,39 @@ func main() {
var externalIpProvider externalIpProvider.ExternalIpProvider var externalIpProvider externalIpProvider.ExternalIpProvider
switch configClient.ExternalIPProvider.Type { switch configClient.ExternalIPProvider.Type {
case "plain": case "plain":
logger.Info("Using plain external IP provider", slog.String("external_ip_provider", "plain"))
var plainConfig plainExternalIpProvider.PlainExternalIpProviderConfig var plainConfig plainExternalIpProvider.PlainExternalIpProviderConfig
err := configClient.ExternalIPProvider.ProviderConfig.Decode(&plainConfig) err := configClient.ExternalIPProvider.ProviderConfig.Decode(&plainConfig)
if err != nil { if err != nil {
logger.Error("Failed to create config",
slog.String("external_ip_provider", "plain"),
slog.String("error", err.Error()),
)
panic(err) panic(err)
} }
externalIpProvider, err = plainExternalIpProvider.New(plainConfig) externalIpProvider, err = plainExternalIpProvider.New(plainConfig)
if err != nil { if err != nil {
logger.Error("Failed to create plain external IP provider",
slog.String("external_ip_provider", "plain"),
slog.String("error", err.Error()),
)
panic(err) panic(err)
} }
default: default:
logger.Error("Unknown external IP provider", slog.String("external_ip_provider", configClient.ExternalIPProvider.Type))
panic(fmt.Errorf("unknown external IP provider: %s", configClient.ExternalIPProvider.Type)) panic(fmt.Errorf("unknown external IP provider: %s", configClient.ExternalIPProvider.Type))
} }
var dnsProvider dnsProvider.DNSProvider var dnsProvider dnsProvider.DNSProvider
switch configClient.DNSProvider.Type { switch configClient.DNSProvider.Type {
case "ionos": case "ionos":
logger.Info("Using IONOS DNS provider", slog.String("dns_provider", "ionos"))
var ionosConfig ionos.IONOSConfig var ionosConfig ionos.IONOSConfig
err := configClient.DNSProvider.ProviderConfig.Decode(&ionosConfig) err := configClient.DNSProvider.ProviderConfig.Decode(&ionosConfig)
if err != nil { if err != nil {
logger.Error("Failed to create IONOS DNS provider",
slog.String("dns_provider", "ionos"),
slog.String("error", err.Error()),
)
panic(err) panic(err)
} }
dnsProvider, err = ionos.NewIonos(&ionosConfig) dnsProvider, err = ionos.NewIonos(&ionosConfig)
if err != nil { if err != nil {
logger.Error("Failed to create IONOS DNS provider",
slog.String("dns_provider", "ionos"),
slog.String("error", err.Error()),
)
panic(err) panic(err)
} }
default: default:
logger.Error("Unknown DNS provider", slog.String("dns_provider", configClient.DNSProvider.Type))
panic(fmt.Errorf("unknown DNS provider: %s", configClient.DNSProvider.Type)) panic(fmt.Errorf("unknown DNS provider: %s", configClient.DNSProvider.Type))
} }
var notificationProvider notificationProvider.NotificationProvider var notificationProvider notificationProvider.NotificationProvider
switch configClient.NotificationProvider.Type { switch configClient.NotificationProvider.Type {
case "gotify": case "gotify":
logger.Info("Using Gotify notification provider", slog.String("notification_provider", "gotify"))
var gotifyConfig gotify.NotificationProviderImplGotifyConfig var gotifyConfig gotify.NotificationProviderImplGotifyConfig
err := configClient.NotificationProvider.ProviderConfig.Decode(&gotifyConfig) err := configClient.NotificationProvider.ProviderConfig.Decode(&gotifyConfig)
if err != nil { if err != nil {
@@ -104,39 +80,29 @@ func main() {
notificationProvider, err = gotify.New(gotifyConfig) notificationProvider, err = gotify.New(gotifyConfig)
if err != nil { if err != nil {
logger.Error("Failed to create Gotify notification provider",
slog.String("notification_provider", "gotify"),
slog.String("error", err.Error()),
)
panic(err) panic(err)
} }
default: default:
logger.Info("Using console notification provider", slog.String("notification_provider", "console"))
notificationProvider = notificationProviderConsole.New() notificationProvider = notificationProviderConsole.New()
} }
rdd := realDynDns.New(externalIpProvider, dnsProvider, notificationProvider, configClient.Domains, logger.With(slog.String("service", "realDynDns"))) rdd := realDynDns.New(externalIpProvider, dnsProvider, notificationProvider, configClient.Domains)
switch configClient.Mode { switch configClient.Mode {
case config.ScheduledMode: case config.ScheduledMode:
logger.Info("Running in scheduled mode", slog.String("interval", configClient.CheckInterval))
schedule, job, err := rdd.RunWithSchedule(configClient.CheckInterval) schedule, job, err := rdd.RunWithSchedule(configClient.CheckInterval)
if err != nil { if err != nil {
logger.Error("Failed to create scheduler", slog.String("error", err.Error()))
panic(err) panic(err)
} }
logger.Info("Next run:", slog.String("time", job.NextRun().String())) fmt.Println("Starting scheduler")
fmt.Println("Next run:", job.NextRun())
schedule.StartBlocking() schedule.StartBlocking()
case config.RunOnceMode: case config.RunOnceMode:
logger.Info("Running in run once mode") numberOfChanges, err := rdd.RunOnce()
_, err := rdd.RunOnce()
if err != nil { if err != nil {
logger.Error("Failed to run once", slog.String("error", err.Error()))
panic(err) panic(err)
} }
fmt.Println("Number of changes:", numberOfChanges)
} }
} }

View File

@@ -2,8 +2,6 @@ package realDynDns
import ( import (
"fmt" "fmt"
"log/slog"
"sync"
"time" "time"
"realdnydns/pkg/config" "realdnydns/pkg/config"
@@ -19,7 +17,6 @@ type ChangeDetector struct {
dnsProvider dnsProvider.DNSProvider dnsProvider dnsProvider.DNSProvider
notificationProvider notificationProvider.NotificationProvider notificationProvider notificationProvider.NotificationProvider
domains []config.DomainConfig domains []config.DomainConfig
logger *slog.Logger
} }
func New( func New(
@@ -27,14 +24,12 @@ func New(
dnsProvider dnsProvider.DNSProvider, dnsProvider dnsProvider.DNSProvider,
notificationProvider notificationProvider.NotificationProvider, notificationProvider notificationProvider.NotificationProvider,
domains []config.DomainConfig, domains []config.DomainConfig,
logger *slog.Logger,
) ChangeDetector { ) ChangeDetector {
return ChangeDetector{ return ChangeDetector{
externalIpProvider: externalIpProvider, externalIpProvider: externalIpProvider,
dnsProvider: dnsProvider, dnsProvider: dnsProvider,
notificationProvider: notificationProvider, notificationProvider: notificationProvider,
domains: domains, domains: domains,
logger: logger,
} }
} }
@@ -63,90 +58,37 @@ func (c *ChangeDetector) RunOnce() (int, error) {
} }
func (c *ChangeDetector) detectAndApplyChanges() (int, error) { func (c *ChangeDetector) detectAndApplyChanges() (int, error) {
c.logger.Info("Detecting and applying changes")
externalIp, err := c.externalIpProvider.GetExternalIp() externalIp, err := c.externalIpProvider.GetExternalIp()
if err != nil { if err != nil {
c.logger.Error("Failed to retrieve external IP", slog.String("error", err.Error()))
return 0, err return 0, err
} }
var wg sync.WaitGroup var numberUpdated int
numberUpdatedChannel := make(chan int)
for _, domain := range c.domains { for _, domain := range c.domains {
for _, subdomain := range domain.Subdomains { for _, subdomain := range domain.Subdomains {
wg.Add(1)
go func(domain config.DomainConfig, subdomain string) {
defer wg.Done()
c.logger.Info("Checking record",
slog.String("tld", domain.TLD),
slog.String("subdomain", subdomain),
)
currentRecord, err := c.dnsProvider.GetRecord(domain.TLD, subdomain) currentRecord, err := c.dnsProvider.GetRecord(domain.TLD, subdomain)
if err != nil { if err != nil {
c.logger.Error("Failed to retrieve record", return numberUpdated, err
slog.String("error", err.Error()),
slog.String("tld", domain.TLD),
slog.String("subdomain", subdomain),
)
return
} }
if currentRecord.IP != externalIp.String() { if currentRecord.IP != externalIp.String() {
c.logger.Info("Record has changed",
slog.String("tld", domain.TLD),
slog.String("subdomain", subdomain),
slog.String("current_ip", currentRecord.IP),
slog.String("external_ip", externalIp.String()),
)
err = c.notificationProvider.SendNotification( err = c.notificationProvider.SendNotification(
fmt.Sprintf("Update %s.%s", subdomain, domain.TLD), fmt.Sprintf("Update %s.%s", subdomain, domain.TLD),
fmt.Sprintf("The IP of %s has changed from %s to %s", domain.TLD, currentRecord.IP, externalIp.String()), fmt.Sprintf("The IP of %s has changed from %s to %s", domain.TLD, currentRecord.IP, externalIp.String()),
) )
if err != nil { if err != nil {
c.logger.Warn("Failed to send notification", return numberUpdated, err
slog.String("error", err.Error()),
)
return
} }
c.logger.Info("Updating record",
slog.String("tld", domain.TLD),
slog.String("subdomain", subdomain),
slog.String("current_ip", currentRecord.IP),
slog.String("external_ip", externalIp.String()),
)
_, err = c.dnsProvider.UpdateRecord(domain.TLD, subdomain, externalIp, currentRecord.TTL, currentRecord.Prio, currentRecord.Disabled) _, err = c.dnsProvider.UpdateRecord(domain.TLD, subdomain, externalIp, currentRecord.TTL, currentRecord.Prio, currentRecord.Disabled)
numberUpdated++
if err != nil { if err != nil {
c.logger.Error("Failed to update record", return numberUpdated, err
slog.String("error", err.Error()),
slog.String("tld", domain.TLD),
slog.String("subdomain", subdomain),
)
return
} }
numberUpdatedChannel <- 1
} }
}(domain, subdomain)
} }
} }
go func() {
wg.Wait()
close(numberUpdatedChannel)
}()
numberUpdated := 0
for v := range numberUpdatedChannel {
numberUpdated += v
}
c.logger.Info("Run completed", slog.Int("number_of_changes", numberUpdated))
return numberUpdated, nil return numberUpdated, nil
} }

View File

@@ -1,7 +1,6 @@
package realDynDns package realDynDns
import ( import (
"log/slog"
"net" "net"
"realdnydns/model/common" "realdnydns/model/common"
"realdnydns/pkg/config" "realdnydns/pkg/config"
@@ -73,9 +72,7 @@ func testDetectAndApplyChangesWithChanges() func(t *testing.T) {
"@", "@",
}, },
}, },
}, })
slog.Default(),
)
numberUpdated, err := changeDetector.RunOnce() numberUpdated, err := changeDetector.RunOnce()
if err != nil { if err != nil {
@@ -104,9 +101,7 @@ func testDetectAndApplyChangesWithoutChanges() func(t *testing.T) {
"@", "@",
}, },
}, },
}, })
slog.Default(),
)
numberUpdated, err := changeDetector.RunOnce() numberUpdated, err := changeDetector.RunOnce()
if err != nil { if err != nil {