diff --git a/avahi/publisher.go b/avahi/publisher.go index cb6f7e8..2589419 100644 --- a/avahi/publisher.go +++ b/avahi/publisher.go @@ -16,10 +16,11 @@ const ( ) type Publisher struct { - dbusConn *dbus.Conn - avahiServer *avahi.Server - fqdn string - rdataField []byte + dbusConn *dbus.Conn + avahiServer *avahi.Server + avahiEntryGroup *avahi.EntryGroup + fqdn string + rdataField []byte } // NewPublisher creates a new service for Publisher. @@ -39,6 +40,11 @@ func NewPublisher() (*Publisher, error) { return nil, fmt.Errorf("failed to get FQDN from Avahi: %v", err) } + group, err := server.EntryGroupNew() + if err != nil { + return nil, fmt.Errorf("failed to create entry group: %v", err) + } + fqdn := dns.Fqdn(avahiFqdn) // RDATA: a variable length string of octets that describes the resource. CNAME in our case @@ -50,10 +56,11 @@ func NewPublisher() (*Publisher, error) { } return &Publisher{ - dbusConn: conn, - avahiServer: server, - fqdn: fqdn, - rdataField: rdataField, + dbusConn: conn, + avahiServer: server, + avahiEntryGroup: group, + fqdn: fqdn, + rdataField: rdataField, }, nil } @@ -64,13 +71,14 @@ func (p *Publisher) Fqdn() string { // PublishCNAMES send via Avahi-daemon CNAME records with the provided TTL. func (p *Publisher) PublishCNAMES(cnames []string, ttl uint32) error { - group, err := p.avahiServer.EntryGroupNew() - if err != nil { - return fmt.Errorf("failed to create entry group: %v", err) + // Reset the entry group to remove all records. + // Because we can't update records without it after the `Commit`. + if err := p.avahiEntryGroup.Reset(); err != nil { + return fmt.Errorf("failed to reset entry group: %v", err) } for _, cname := range cnames { - err := group.AddRecord( + err := p.avahiEntryGroup.AddRecord( avahi.InterfaceUnspec, avahi.ProtoUnspec, uint32(0), // From Avahi Python bindings https://gist.github.com/gdamjan/3168336#file-avahi-alias-py-L42 @@ -85,7 +93,7 @@ func (p *Publisher) PublishCNAMES(cnames []string, ttl uint32) error { } } - if err := group.Commit(); err != nil { + if err := p.avahiEntryGroup.Commit(); err != nil { return fmt.Errorf("failed to commit entry group: %v", err) } @@ -94,5 +102,5 @@ func (p *Publisher) PublishCNAMES(cnames []string, ttl uint32) error { // Close associated resources. func (p *Publisher) Close() { - p.avahiServer.Close() // It also close the DBus connection + p.avahiServer.Close() // It also closes the DBus connection and free the entry group } diff --git a/cmd/subdomain.go b/cmd/subdomain.go index 7c0aa44..44a9655 100644 --- a/cmd/subdomain.go +++ b/cmd/subdomain.go @@ -117,8 +117,7 @@ func runSubdomain(ctx context.Context, publisher *avahi.Publisher, fqdn string, if len(found) > 0 { if err := publisher.PublishCNAMES(found, ttl); err != nil { - log.Printf("Failed to publish CNAMEs: %v", err) - continue + return fmt.Errorf("failed to publish CNAMEs: %w", err) } } } diff --git a/main.go b/main.go index 4cef947..dac9357 100644 --- a/main.go +++ b/main.go @@ -3,8 +3,10 @@ package main import ( "context" "fmt" + "log" "os" "os/signal" + "time" "github.com/carlmjohnson/versioninfo" "github.com/urfave/cli/v2" @@ -16,6 +18,15 @@ func main() { ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill) defer stop() + // Add a handler for force exiting if we don't exit gracefully (stuck) + go func() { + <-ctx.Done() + time.Sleep(3 * time.Second) + + log.Print("Force exit") + os.Exit(1) + }() + app := &cli.App{ Name: "go-avahi-cname", Usage: "A tool for publishing CNAME records with Avahi",