dns.go
package gcp
import (
"fmt"
"strings"
"github.com/readysite/readysite/pkg/platform"
"google.golang.org/api/dns/v1"
)
// CreateDNSZone creates a Cloud DNS managed zone
func (b *backend) CreateDNSZone(domain string) (*platform.DNSZone, error) {
// Zone name must be lowercase alphanumeric with dashes
zoneName := strings.ReplaceAll(domain, ".", "-")
zone := &dns.ManagedZone{
Name: zoneName,
DnsName: domain + ".",
Description: "Managed by ReadySite",
}
created, err := b.dns.ManagedZones.Create(b.project, zone).Context(b.ctx).Do()
if err != nil {
return nil, fmt.Errorf("create managed zone: %w", err)
}
return &platform.DNSZone{
Name: strings.TrimSuffix(created.DnsName, "."),
TTL: 300,
}, nil
}
// GetDNSZone retrieves a Cloud DNS managed zone
func (b *backend) GetDNSZone(domain string) (*platform.DNSZone, error) {
zoneName := strings.ReplaceAll(domain, ".", "-")
zone, err := b.dns.ManagedZones.Get(b.project, zoneName).Context(b.ctx).Do()
if err != nil {
if strings.Contains(err.Error(), "not found") || strings.Contains(err.Error(), "404") {
return nil, platform.ErrNotFound
}
return nil, fmt.Errorf("get managed zone: %w", err)
}
return &platform.DNSZone{
Name: strings.TrimSuffix(zone.DnsName, "."),
TTL: 300,
}, nil
}
// AddDNSRecord adds a Cloud DNS record
func (b *backend) AddDNSRecord(zone string, record platform.DNSRecord) error {
zoneName := strings.ReplaceAll(zone, ".", "-")
name := record.Name
if name == "@" {
name = zone + "."
} else {
name = record.Name + "." + zone + "."
}
rrset := &dns.ResourceRecordSet{
Name: name,
Type: record.Type,
Ttl: int64(record.TTL),
Rrdatas: []string{record.Value},
}
change := &dns.Change{
Additions: []*dns.ResourceRecordSet{rrset},
}
_, err := b.dns.Changes.Create(b.project, zoneName, change).Context(b.ctx).Do()
if err != nil {
return fmt.Errorf("create record: %w", err)
}
return nil
}
// DeleteDNSRecord removes a Cloud DNS record
func (b *backend) DeleteDNSRecord(zone, recordID string) error {
zoneName := strings.ReplaceAll(zone, ".", "-")
// recordID format: "TYPE:NAME:VALUE"
parts := strings.SplitN(recordID, ":", 3)
if len(parts) != 3 {
return fmt.Errorf("invalid record ID format (expected TYPE:NAME:VALUE)")
}
rrset := &dns.ResourceRecordSet{
Name: parts[1],
Type: parts[0],
Ttl: 300,
Rrdatas: []string{parts[2]},
}
change := &dns.Change{
Deletions: []*dns.ResourceRecordSet{rrset},
}
_, err := b.dns.Changes.Create(b.project, zoneName, change).Context(b.ctx).Do()
if err != nil {
return fmt.Errorf("delete record: %w", err)
}
return nil
}