// Copyright 2017 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package gcp import ( "context" "fmt" "time" "golang.org/x/oauth2/google" dns "google.golang.org/api/dns/v1" "github.com/IanLewis/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 { return c.ResourceRecordSet.Name } func (c *cloudDNSRecord) Type() string { return c.ResourceRecordSet.Type } func (c *cloudDNSRecord) Ttl() int64 { return c.ResourceRecordSet.Ttl } func (c *cloudDNSRecord) Data() []string { return c.ResourceRecordSet.Rrdatas } // TODO: New backend type cloudDNSBackend struct { client *dns.Service project string zone string timeout time.Duration } func NewCloudDNSBackend(project, zone string) (backend.DNSBackend, error) { client, err := getDNSClient() if err != nil { return nil, err } return &cloudDNSBackend{ client: client, project: project, zone: zone, timeout: 5 * time.Second, }, nil } func (b *cloudDNSBackend) GetRecord(ctx context.Context, dnsName, dnsType string) (backend.DNSRecord, error) { var record *dns.ResourceRecordSet 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.Name == dnsName && v.Type == dnsType { record = v } } return nil // NOTE: returning a non-nil error stops pagination. }) if err != nil { return nil, err } if record == nil { return nil, nil } return &cloudDNSRecord{*record}, nil } func (b *cloudDNSBackend) UpdateRecords(ctx context.Context, additions []backend.DNSRecord, deletions []backend.DNSRecord) error { a := []*dns.ResourceRecordSet{} d := []*dns.ResourceRecordSet{} for _, r := range additions { a = append(a, &dns.ResourceRecordSet{ Name: r.Name(), Type: r.Type(), Ttl: r.Ttl(), Rrdatas: r.Data(), }) } for _, r := range deletions { d = append(d, &dns.ResourceRecordSet{ Name: r.Name(), Type: r.Type(), Ttl: r.Ttl(), Rrdatas: r.Data(), }) } change := &dns.Change{ Additions: a, Deletions: d, } _, err := b.client.Changes.Create(b.project, b.zone, change).Context(ctx).Do() if err != nil { return err } 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 }