diff --git a/cmd/devp2p/dns_cloudflare.go b/cmd/devp2p/dns_cloudflare.go index 903d754dd7..903a21b009 100644 --- a/cmd/devp2p/dns_cloudflare.go +++ b/cmd/devp2p/dns_cloudflare.go @@ -125,16 +125,41 @@ func (c *cloudflareClient) uploadRecords(name string, records map[string]string) } existing[strings.ToLower(entry.Name)] = entry } + // if the record exists on cloudflare, but is not in our local records, it is stale + stales := make(map[string]cloudflare.DNSRecord) + for path, entry := range existing { + if _, ok := records[path]; !ok { + stales[path] = entry + } + } + // firstCloudflareRecord is a helper function returning the first path:record value from a path:DNSRecord map. + firstCloudflareRecord := func(cfPathRecordMap map[string]cloudflare.DNSRecord) (string, cloudflare.DNSRecord) { + for path, entry := range cfPathRecordMap { + return path, entry + } + return "", cloudflare.DNSRecord{} + } // Iterate over the new records and inject anything missing. log.Info("Updating DNS entries") created := 0 updated := 0 skipped := 0 + deleted := 0 for path, val := range records { old, exists := existing[path] if !exists { - // Entry is unknown, push a new one to Cloudflare. + // Entry is unknown, push a new one to Cloudflare after removing first stale record, if any. + // We delete any one stale record before creating a new one to avoid exceeding the Cloudflare + // record quota. + if path, entry := firstCloudflareRecord(stales); path != "" { + log.Debug(fmt.Sprintf("Deleting %s = %q", path, entry.Content)) + deleted++ + if err := c.DeleteDNSRecord(context.Background(), c.zoneID, entry.ID); err != nil { + return fmt.Errorf("failed to delete %s: %v", path, err) + } + delete(stales, path) + } log.Debug(fmt.Sprintf("Creating %s = %q", path, val)) created++ ttl := rootTTL @@ -157,21 +182,17 @@ func (c *cloudflareClient) uploadRecords(name string, records map[string]string) return fmt.Errorf("failed to publish %s: %v", path, err) } } - log.Info("Updated DNS entries", "new", created, "updated", updated, "untouched", skipped) - // Iterate over the old records and delete anything stale. - deleted := 0 + log.Info("Updated DNS entries", "new", created, "updated", updated, "untouched", skipped, "deleted", deleted) + // Iterate over the old records and delete anything left stale. + deleted = 0 log.Info("Deleting stale DNS entries") - for path, entry := range existing { - if _, ok := records[path]; ok { - continue - } - // Stale entry, nuke it. + for path, entry := range stales { log.Debug(fmt.Sprintf("Deleting %s = %q", path, entry.Content)) deleted++ if err := c.DeleteDNSRecord(context.Background(), c.zoneID, entry.ID); err != nil { return fmt.Errorf("failed to delete %s: %v", path, err) } } - log.Info("Deleted stale DNS entries", "count", deleted) + log.Info("Deleted remaining stale DNS entries", "count", deleted) return nil }