Reduce requests to the GCP dns backend

Update use of the google API to current practices

The reduction in requests is achieved by adding a limiter and returning
a cached response if the limiter will not allow a request.
This commit is contained in:
lordwelch 2020-05-27 19:01:28 -07:00
parent 214c548fba
commit 4d1351c52a
2 changed files with 38 additions and 35 deletions

View File

@ -80,6 +80,7 @@ func getConfig(pathToJSON string) (Config, error) {
if err != nil {
return cfg, fmt.Errorf("Could not load %s: %v", pathToJSON, err)
}
backends := make(map[string]backend.DNSBackend, len(cfg.Domains))
for _, d := range cfg.Domains {
if d.Provider == "gcp" {
@ -101,9 +102,13 @@ func getConfig(pathToJSON string) (Config, error) {
return cfg, fmt.Errorf("\"managed_zone\" must be a string")
}
b, err := gcp.NewCloudDNSBackend(project, zone)
if err != nil {
return cfg, fmt.Errorf("Could not create Cloud DNS backend: %v", err)
b, ok := backends[project+"-"+zone]
if !ok {
b, err = gcp.NewCloudDNSBackend(project, zone)
if err != nil {
return cfg, fmt.Errorf("Could not create Cloud DNS backend: %v", err)
}
backends[project+"-"+zone] = b
}
d.Backend = b
} else {

View File

@ -17,38 +17,32 @@ package gcp
import (
"context"
"fmt"
"sync"
"time"
"golang.org/x/oauth2/google"
"golang.org/x/time/rate"
dns "google.golang.org/api/dns/v1"
"github.com/lordwelch/cloud-dyndns-client/pkg/backend"
)
var cloudDnsScopes = []string{
dns.CloudPlatformScope,
dns.CloudPlatformReadOnlyScope,
dns.NdevClouddnsReadonlyScope,
dns.NdevClouddnsReadwriteScope,
}
type cloudDNSRecord struct {
dns.ResourceRecordSet
}
func (c *cloudDNSRecord) Name() string {
func (c cloudDNSRecord) Name() string {
return c.ResourceRecordSet.Name
}
func (c *cloudDNSRecord) Type() string {
func (c cloudDNSRecord) Type() string {
return c.ResourceRecordSet.Type
}
func (c *cloudDNSRecord) Ttl() int64 {
func (c cloudDNSRecord) Ttl() int64 {
return c.ResourceRecordSet.Ttl
}
func (c *cloudDNSRecord) Data() []string {
func (c cloudDNSRecord) Data() []string {
return c.ResourceRecordSet.Rrdatas
}
@ -59,12 +53,15 @@ type cloudDNSBackend struct {
project string
zone string
timeout time.Duration
limiter *rate.Limiter
cache map[string]cloudDNSRecord
mutex *sync.RWMutex
}
func NewCloudDNSBackend(project, zone string) (backend.DNSBackend, error) {
client, err := getDNSClient()
client, err := dns.NewService(context.Background())
if err != nil {
return nil, err
return nil, fmt.Errorf("Could not create Google Cloud DNS client: %v", err)
}
return &cloudDNSBackend{
@ -72,29 +69,44 @@ func NewCloudDNSBackend(project, zone string) (backend.DNSBackend, error) {
project: project,
zone: zone,
timeout: 5 * time.Second,
limiter: rate.NewLimiter(rate.Every(5*time.Second), 1),
cache: make(map[string]cloudDNSRecord),
mutex: &sync.RWMutex{},
}, nil
}
func (b *cloudDNSBackend) GetRecord(ctx context.Context, dnsName, dnsType string) (backend.DNSRecord, error) {
var record *dns.ResourceRecordSet
if !b.limiter.Allow() {
b.mutex.RLock()
record := b.cache[dnsName+"-"+dnsType]
b.mutex.RUnlock()
return record, nil
}
fmt.Println("run GetRecord")
b.mutex.Lock()
b.cache = make(map[string]cloudDNSRecord, len(b.cache))
call := b.client.ResourceRecordSets.List(b.project, b.zone)
err := call.Pages(ctx, func(page *dns.ResourceRecordSetsListResponse) error {
for _, v := range page.Rrsets {
if v == nil {
continue
}
if v.Name == dnsName && v.Type == dnsType {
record = v
}
b.cache[dnsName+"-"+dnsType] = cloudDNSRecord{*v}
}
return nil // NOTE: returning a non-nil error stops pagination.
})
b.mutex.Unlock()
if err != nil {
return nil, err
}
if record == nil {
return nil, nil
}
return &cloudDNSRecord{*record}, nil
return cloudDNSRecord{*record}, nil
}
func (b *cloudDNSBackend) UpdateRecords(ctx context.Context, additions []backend.DNSRecord, deletions []backend.DNSRecord) error {
@ -131,17 +143,3 @@ func (b *cloudDNSBackend) UpdateRecords(ctx context.Context, additions []backend
return nil
}
func getDNSClient() (*dns.Service, error) {
client, err := google.DefaultClient(context.Background(), cloudDnsScopes...)
if err != nil {
return nil, fmt.Errorf("Could not create Google Cloud DNS client: %v", err)
}
service, err := dns.New(client)
if err != nil {
return nil, fmt.Errorf("Could not create Google Cloud DNS client: %v", err)
}
return service, nil
}