diff --git a/providers/hetzner/api.go b/providers/hetzner/api.go index ce5039ceb5..02f6470bf4 100644 --- a/providers/hetzner/api.go +++ b/providers/hetzner/api.go @@ -11,6 +11,7 @@ import ( "time" "github.com/StackExchange/dnscontrol/v4/pkg/printer" + "github.com/StackExchange/dnscontrol/v4/pkg/zoneCache" ) const ( @@ -19,8 +20,7 @@ const ( type hetznerProvider struct { apiKey string - mu sync.Mutex - cachedZones map[string]zone + zoneCache zoneCache.ZoneCache[zone] requestRateLimiter requestRateLimiter } @@ -62,7 +62,13 @@ func (api *hetznerProvider) createZone(name string) error { request := createZoneRequest{ Name: name, } - return api.request("/zones", "POST", request, nil, nil) + response := createZoneResponse{} + err := api.request("/zones", "POST", request, &response, nil) + if err != nil { + return err + } + api.zoneCache.SetZone(name, response.Zone) + return nil } func (api *hetznerProvider) deleteRecord(record *record) error { @@ -71,7 +77,7 @@ func (api *hetznerProvider) deleteRecord(record *record) error { } func (api *hetznerProvider) getAllRecords(domain string) ([]record, error) { - z, err := api.getZone(domain) + z, err := api.zoneCache.GetZone(domain) if err != nil { return nil, err } @@ -105,18 +111,7 @@ func (api *hetznerProvider) getAllRecords(domain string) ([]record, error) { return records, nil } -func (api *hetznerProvider) resetZoneCache() { - api.mu.Lock() - defer api.mu.Unlock() - api.cachedZones = nil -} - -func (api *hetznerProvider) getAllZones() (map[string]zone, error) { - api.mu.Lock() - defer api.mu.Unlock() - if api.cachedZones != nil { - return api.cachedZones, nil - } +func (api *hetznerProvider) fetchAllZones() (map[string]zone, error) { var zones map[string]zone page := 1 statusOK := func(code int) bool { @@ -148,22 +143,9 @@ func (api *hetznerProvider) getAllZones() (map[string]zone, error) { } page++ } - api.cachedZones = zones return zones, nil } -func (api *hetznerProvider) getZone(name string) (*zone, error) { - zones, err := api.getAllZones() - if err != nil { - return nil, err - } - z, ok := zones[name] - if !ok { - return nil, fmt.Errorf("%q is not a zone in this HETZNER account", name) - } - return &z, nil -} - func (api *hetznerProvider) request(endpoint string, method string, request interface{}, target interface{}, statusOK func(code int) bool) error { if statusOK == nil { statusOK = func(code int) bool { diff --git a/providers/hetzner/hetznerProvider.go b/providers/hetzner/hetznerProvider.go index b92db3f5bd..62b443105c 100644 --- a/providers/hetzner/hetznerProvider.go +++ b/providers/hetzner/hetznerProvider.go @@ -7,6 +7,7 @@ import ( "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/diff" + "github.com/StackExchange/dnscontrol/v4/pkg/zoneCache" "github.com/StackExchange/dnscontrol/v4/providers" ) @@ -50,28 +51,20 @@ func New(settings map[string]string, _ json.RawMessage) (providers.DNSServicePro return nil, errors.New("missing HETZNER api_key") } - return &hetznerProvider{ - apiKey: apiKey, - }, nil + api := &hetznerProvider{apiKey: apiKey} + api.zoneCache = zoneCache.New(api.fetchAllZones) + return api, nil } // EnsureZoneExists creates a zone if it does not exist func (api *hetznerProvider) EnsureZoneExists(domain string) error { - domains, err := api.ListZones() - if err != nil { + if ok, err := api.zoneCache.HasZone(domain); err != nil || ok { return err } - for _, d := range domains { - if d == domain { - return nil - } - } - - if err = api.createZone(domain); err != nil { + if err := api.createZone(domain); err != nil { return err } - api.resetZoneCache() return nil } @@ -86,7 +79,7 @@ func (api *hetznerProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, e // Start corrections with the reports corrections := diff.GenerateMessageCorrections(toReport) - z, err := api.getZone(domain) + z, err := api.zoneCache.GetZone(domain) if err != nil { return nil, 0, err } @@ -143,7 +136,7 @@ func (api *hetznerProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, e // GetNameservers returns the nameservers for a domain. func (api *hetznerProvider) GetNameservers(domain string) ([]*models.Nameserver, error) { - z, err := api.getZone(domain) + z, err := api.zoneCache.GetZone(domain) if err != nil { return nil, err } @@ -169,13 +162,5 @@ func (api *hetznerProvider) GetZoneRecords(domain string, meta map[string]string // ListZones lists the zones on this account. func (api *hetznerProvider) ListZones() ([]string, error) { - zones, err := api.getAllZones() - if err != nil { - return nil, err - } - domains := make([]string, 0, len(zones)) - for domain := range zones { - domains = append(domains, domain) - } - return domains, nil + return api.zoneCache.GetZoneNames() } diff --git a/providers/hetzner/types.go b/providers/hetzner/types.go index 61125a5d99..40b17ad436 100644 --- a/providers/hetzner/types.go +++ b/providers/hetzner/types.go @@ -17,6 +17,10 @@ type createZoneRequest struct { Name string `json:"name"` } +type createZoneResponse struct { + Zone zone `json:"zone"` +} + type getAllRecordsResponse struct { Records []record `json:"records"` Meta struct { @@ -53,7 +57,7 @@ type zone struct { TTL uint32 `json:"ttl"` } -func fromRecordConfig(in *models.RecordConfig, zone *zone) record { +func fromRecordConfig(in *models.RecordConfig, zone zone) record { r := record{ Name: in.GetLabel(), Type: in.Type,