Refactored main and some error messages

This commit is contained in:
Ian Lewis 2018-10-22 12:43:40 +09:00
parent ba9379dfb8
commit 7755300638
3 changed files with 24 additions and 27 deletions

View File

@ -36,7 +36,7 @@ import (
) )
// VERSION is the current version of the application. // 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. // Domain is a single domain listed in the configuration file.
type Domain struct { 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. // 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.") addr := flag.String("addr", ":8080", "Address to listen on for health checks.")
version := flag.Bool("version", false, "Print the version and exit.") 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.") 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 { if *version {
fmt.Println(VERSION) fmt.Println(VERSION)
return 0 return
} }
cfg, err := getConfig(*config) cfg, err := getConfig(*config)
if err != nil { if err != nil {
log.Fatalf("Error reading config: %#v", err) log.Fatalf("Error reading config: %v", err)
} }
// Convert config to sync records // Convert config to sync records
@ -160,6 +160,7 @@ func Main() int {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
wg, ctx := errgroup.WithContext(ctx) 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 syncer.Run(ctx.Done()) })
wg.Go(func() error { return poller.Run(ctx.Done()) }) wg.Go(func() error { return poller.Run(ctx.Done()) })
wg.Go(func() error { wg.Go(func() error {
@ -182,6 +183,7 @@ func Main() int {
} }
} }
}) })
// TODO: Refactor and move to it's own package
wg.Go(func() error { wg.Go(func() error {
// This goroutine sets up health checks on an HTTP endpoint. // This goroutine sets up health checks on an HTTP endpoint.
// It's a bit complicated as it is necessary to gracefully // 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) signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
select { select {
case s := <-signals: case s := <-signals:
log.Printf("Received signal %#v, exiting...", s) log.Printf("Received signal %v, exiting...", s)
case <-ctx.Done(): case <-ctx.Done():
} }
cancel() cancel()
if err := wg.Wait(); err != nil { if err := wg.Wait(); err != nil {
log.Printf("Unhandled error received. Exiting: %s %#v", err.Error(), err) log.Fatalf("Unhandled error received. Exiting: %v", err)
return 1 os.Exit(1)
} }
return 0
}
func main() {
os.Exit(Main())
} }

View File

@ -83,7 +83,7 @@ func (p *IPAddressPoller) poll() error {
return nil 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. // 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 return "", err
} }
if resp.StatusCode != http.StatusOK { 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) 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. // Run() starts the main loop for the poller.
func (i *IPAddressPoller) Run(stopCh <-chan struct{}) error { func (i *IPAddressPoller) Run(stopCh <-chan struct{}) error {
if err := i.poll(); err != nil { 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 { for {
select { select {
case <-time.After(i.pollInterval): case <-time.After(i.pollInterval):
if err := i.poll(); err != nil { 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: case <-stopCh:
return nil return nil
} }
} }
return nil
} }

View File

@ -112,10 +112,10 @@ func (s *Syncer) UpdateRecord(dnsName, dnsType string, ttl int64, data []string)
return fmt.Errorf("Domain %s not registered.", dnsName) return fmt.Errorf("Domain %s not registered.", dnsName)
} }
// needsUpdate() returns true if the first DNSRecord needs to be // needsUpdate() compares the left/local DNSRecord against the right/remote
// updated with the remote backend as compared to the remote // DNSRecord and returns true if the record needs to be updated in the remote
// version of the DNSRecord. // backend.
func needsUpdate(l backend.DNSRecord, r backend.DNSRecord) bool { func needsUpdate(l, r backend.DNSRecord) bool {
if l == nil { if l == nil {
return false 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. // poll() runs a loop to poll the backend and update the remote cache.
func (s *Syncer) poll(d *domainObj, stopCh <-chan struct{}) { 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 { 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 { for {
select { select {
case <-time.After(s.pollInterval): case <-time.After(s.pollInterval):
if err := s.pollSingle(d); err != nil { 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: case <-stopCh:
return return
@ -210,7 +212,7 @@ func (s *Syncer) syncSingle(d *domainObj) error {
if d.remote != nil { if d.remote != nil {
deletions = []backend.DNSRecord{d.remote} 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) err := d.backend.UpdateRecords(ctx, additions, deletions)
if err != nil { if err != nil {
return err return err
@ -246,6 +248,8 @@ func (s *Syncer) sync(d *domainObj, stopCh <-chan struct{}) {
// Run() starts the sync and poll loops // Run() starts the sync and poll loops
func (s *Syncer) Run(stopCh <-chan struct{}) error { 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 { for _, d := range s.domains {
go s.poll(d, stopCh) go s.poll(d, stopCh)
go s.sync(d, stopCh) go s.sync(d, stopCh)