diff --git a/cmd/cloud-dyndns-client/main.go b/cmd/cloud-dyndns-client/main.go index 4903adc..97ea980 100644 --- a/cmd/cloud-dyndns-client/main.go +++ b/cmd/cloud-dyndns-client/main.go @@ -36,7 +36,7 @@ import ( ) // VERSION is the current version of the application. -var VERSION = "0.1.4" +var VERSION = "0.1.5" // Domain is a single domain listed in the configuration file. type Domain struct { @@ -113,7 +113,7 @@ func getConfig(pathToJSON string) (Config, error) { } // Main is the main function for the cloud-dyndns-client command. It returns the OS exit code. -func Main() int { +func main() { addr := flag.String("addr", ":8080", "Address to listen on for health checks.") version := flag.Bool("version", false, "Print the version and exit.") config := flag.String("config", "/etc/cloud-dyndns-client/config.json", "The path to the JSON config file.") @@ -122,12 +122,12 @@ func Main() int { if *version { fmt.Println(VERSION) - return 0 + return } cfg, err := getConfig(*config) if err != nil { - log.Fatalf("Error reading config: %#v", err) + log.Fatalf("Error reading config: %v", err) } // Convert config to sync records @@ -160,6 +160,7 @@ func Main() int { ctx, cancel := context.WithCancel(context.Background()) wg, ctx := errgroup.WithContext(ctx) + // TODO: Refactor and move this code to it's own package wg.Go(func() error { return syncer.Run(ctx.Done()) }) wg.Go(func() error { return poller.Run(ctx.Done()) }) wg.Go(func() error { @@ -182,6 +183,7 @@ func Main() int { } } }) + // TODO: Refactor and move to it's own package wg.Go(func() error { // This goroutine sets up health checks on an HTTP endpoint. // It's a bit complicated as it is necessary to gracefully @@ -221,19 +223,13 @@ func Main() int { signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM) select { case s := <-signals: - log.Printf("Received signal %#v, exiting...", s) + log.Printf("Received signal %v, exiting...", s) case <-ctx.Done(): } cancel() if err := wg.Wait(); err != nil { - log.Printf("Unhandled error received. Exiting: %s %#v", err.Error(), err) - return 1 + log.Fatalf("Unhandled error received. Exiting: %v", err) + os.Exit(1) } - - return 0 -} - -func main() { - os.Exit(Main()) } diff --git a/pkg/sync/ipaddress.go b/pkg/sync/ipaddress.go index 226b6c7..347199f 100644 --- a/pkg/sync/ipaddress.go +++ b/pkg/sync/ipaddress.go @@ -83,7 +83,7 @@ func (p *IPAddressPoller) poll() error { return nil } - return fmt.Errorf("Could not obtain IP address: %s %#v", lastErr.Error(), lastErr) + return fmt.Errorf("Could not obtain IP address: %v", lastErr) } // request() makes a request to a URL to get the internet IP address. @@ -102,7 +102,7 @@ func request(url string) (string, error) { return "", err } if resp.StatusCode != http.StatusOK { - return "", fmt.Errorf("Got status code from %s: %s", url, resp.StatusCode) + return "", fmt.Errorf("Got status code from %q: %d", url, resp.StatusCode) } z := html.NewTokenizer(resp.Body) @@ -122,24 +122,21 @@ func request(url string) (string, error) { } } } - - return "", fmt.Errorf("Could not obtain IP address from html body") } // Run() starts the main loop for the poller. func (i *IPAddressPoller) Run(stopCh <-chan struct{}) error { if err := i.poll(); err != nil { - log.Printf("Error polling for IP: %s %#v", err.Error(), err) + log.Printf("Error polling for IP: %v", err) } for { select { case <-time.After(i.pollInterval): if err := i.poll(); err != nil { - log.Printf("Error polling for IP: %s %#v", err.Error(), err) + log.Printf("Error polling for IP: %v", err) } case <-stopCh: return nil } } - return nil } diff --git a/pkg/sync/sync.go b/pkg/sync/sync.go index 25e2f92..c145f24 100644 --- a/pkg/sync/sync.go +++ b/pkg/sync/sync.go @@ -112,10 +112,10 @@ func (s *Syncer) UpdateRecord(dnsName, dnsType string, ttl int64, data []string) return fmt.Errorf("Domain %s not registered.", dnsName) } -// needsUpdate() returns true if the first DNSRecord needs to be -// updated with the remote backend as compared to the remote -// version of the DNSRecord. -func needsUpdate(l backend.DNSRecord, r backend.DNSRecord) bool { +// needsUpdate() compares the left/local DNSRecord against the right/remote +// DNSRecord and returns true if the record needs to be updated in the remote +// backend. +func needsUpdate(l, r backend.DNSRecord) bool { if l == nil { return false } @@ -175,14 +175,16 @@ func (s *Syncer) pollSingle(d *domainObj) error { // poll() runs a loop to poll the backend and update the remote cache. func (s *Syncer) poll(d *domainObj, stopCh <-chan struct{}) { + // Start by polling the domain to initialize the remote value and local cache + // TODO: Implement some exponential retry backoff logic in case poll interval is long if err := s.pollSingle(d); err != nil { - log.Printf("Error polling DNS record %s %#v %#v %s", err.Error(), d, err) + log.Printf("Error polling DNS record %q: %v", d.managed.Name(), err) } for { select { case <-time.After(s.pollInterval): if err := s.pollSingle(d); err != nil { - log.Printf("Error polling DNS record: %s %#v %#v", err.Error(), d, err) + log.Printf("Error polling DNS record %q: %v", d.managed.Name(), err) } case <-stopCh: return @@ -210,7 +212,7 @@ func (s *Syncer) syncSingle(d *domainObj) error { if d.remote != nil { deletions = []backend.DNSRecord{d.remote} } - log.Printf("Updating record: %#v", d.managed) + log.Printf("Updating record %v", d.managed.Name()) err := d.backend.UpdateRecords(ctx, additions, deletions) if err != nil { return err @@ -246,6 +248,8 @@ func (s *Syncer) sync(d *domainObj, stopCh <-chan struct{}) { // Run() starts the sync and poll loops func (s *Syncer) Run(stopCh <-chan struct{}) error { + // Run a sync and poll loop for each domain. Sync and poll loops are + // separated so that polling and syncing do not block on each other. for _, d := range s.domains { go s.poll(d, stopCh) go s.sync(d, stopCh)