diff --git a/cmd/bucket-handlers.go b/cmd/bucket-handlers.go index 72f82526a..64af70aad 100644 --- a/cmd/bucket-handlers.go +++ b/cmd/bucket-handlers.go @@ -22,6 +22,7 @@ import ( "encoding/xml" "fmt" "io" + "net" "net/http" "net/url" "path" @@ -51,15 +52,27 @@ import ( // -- If yes, check if the IP of entry matches local IP. This means entry is for this instance. // -- If IP of the entry doesn't match, this means entry is for another instance. Log an error to console. func initFederatorBackend(objLayer ObjectLayer) { + // Get buckets in the backend b, err := objLayer.ListBuckets(context.Background()) if err != nil { logger.LogIf(context.Background(), err) return } + // Get buckets in the DNS + dnsBuckets, err := globalDNSConfig.List() + if err != nil && err != dns.ErrNoEntriesFound { + logger.LogIf(context.Background(), err) + return + } + + bucketSet := set.NewStringSet() + + // Add buckets that are not registered with the DNS g := errgroup.WithNErrs(len(b)) for index := range b { index := index + bucketSet.Add(b[index].Name) g.Go(func() error { r, gerr := globalDNSConfig.Get(b[index].Name) if gerr != nil { @@ -79,7 +92,38 @@ func initFederatorBackend(objLayer ObjectLayer) { for _, err := range g.Wait() { if err != nil { logger.LogIf(context.Background(), err) - return + } + } + + g = errgroup.WithNErrs(len(dnsBuckets)) + // Remove buckets that are in DNS for this server, but aren't local + for index := range dnsBuckets { + index := index + + g.Go(func() error { + // This is a local bucket that exists, so we can continue + if bucketSet.Contains(dnsBuckets[index].Key) { + return nil + } + + // This is not for our server, so we can continue + hostPort := net.JoinHostPort(dnsBuckets[index].Host, fmt.Sprintf("%d", dnsBuckets[index].Port)) + if globalDomainIPs.Intersection(set.CreateStringSet(hostPort)).IsEmpty() { + return nil + } + + // We go to here, so we know the bucket no longer exists, but is registered in DNS to this server + if err := globalDNSConfig.DeleteRecord(dnsBuckets[index]); err != nil { + return fmt.Errorf("Failed to remove DNS entry for %s due to %v", dnsBuckets[index].Key, err) + } + + return nil + }, index) + } + + for _, err := range g.Wait() { + if err != nil { + logger.LogIf(context.Background(), err) } } } diff --git a/pkg/dns/etcd_dns.go b/pkg/dns/etcd_dns.go index 91e1ea90d..5ae5935ee 100644 --- a/pkg/dns/etcd_dns.go +++ b/pkg/dns/etcd_dns.go @@ -197,6 +197,21 @@ func (c *coreDNS) Delete(bucket string) error { return nil } +// Removes a specific DNS entry +func (c *coreDNS) DeleteRecord(record SrvRecord) error { + for _, domainName := range c.domainNames { + key := msg.Path(fmt.Sprintf("%s.%s.", record.Key, domainName), defaultPrefixPath) + + dctx, dcancel := context.WithTimeout(context.Background(), defaultContextTimeout) + if _, err := c.etcdClient.Delete(dctx, key+etcdPathSeparator+record.Host); err != nil { + dcancel() + return err + } + dcancel() + } + return nil +} + // CoreDNS - represents dns config for coredns server. type coreDNS struct { domainNames []string diff --git a/pkg/dns/types.go b/pkg/dns/types.go index fadc8d1d8..87ffdab5f 100644 --- a/pkg/dns/types.go +++ b/pkg/dns/types.go @@ -62,4 +62,5 @@ type Config interface { List() ([]SrvRecord, error) Get(key string) ([]SrvRecord, error) Delete(key string) error + DeleteRecord(record SrvRecord) error }