aboutsummaryrefslogtreecommitdiff
path: root/cmd/dnsupdate/main.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/dnsupdate/main.go')
-rw-r--r--cmd/dnsupdate/main.go125
1 files changed, 125 insertions, 0 deletions
diff --git a/cmd/dnsupdate/main.go b/cmd/dnsupdate/main.go
new file mode 100644
index 0000000..59ed67a
--- /dev/null
+++ b/cmd/dnsupdate/main.go
@@ -0,0 +1,125 @@
+package main
+
+import (
+ "context"
+ "fmt"
+ "log"
+
+ dns "google.golang.org/api/dns/v1"
+)
+
+const (
+ GCP_PROJECT_NAME = "fcuny-homelab"
+ GCP_MANAGED_ZONE = "fcuny-xyz"
+ TS_DEVICE_NAME = "tahoe"
+ TTL = 300
+)
+
+var desiredRecords = []string{
+ "bt",
+ "dash",
+ "drone",
+ "music",
+ "unifi",
+}
+
+func main() {
+ ctx := context.Background()
+
+ // we only care about IPv4 for now
+ tsIpV4Addresses, _, err := getTsIpsDevice(ctx, TS_DEVICE_NAME)
+ if err != nil {
+ log.Fatalf("failed to get the IP addresses for %s: %v", TS_DEVICE_NAME, err)
+ }
+
+ svc, err := dns.NewService(ctx)
+ if err != nil {
+ log.Fatalf("failed to create the client for Google Cloud DNS: %v", err)
+ }
+
+ zone, err := svc.ManagedZones.Get(GCP_PROJECT_NAME, GCP_MANAGED_ZONE).Context(ctx).Do()
+ if err != nil {
+ log.Fatalf("failed to get information about the managed zone %s: %+v", GCP_MANAGED_ZONE, err)
+ }
+
+ recordSets, err := svc.ResourceRecordSets.List(GCP_PROJECT_NAME, GCP_MANAGED_ZONE).Context(ctx).Do()
+ if err != nil {
+ log.Fatalf("failed to get the list of records: %+v", err)
+ }
+
+ var (
+ existingRecordSets = []*dns.ResourceRecordSet{}
+ recordSetsToAdd = []*dns.ResourceRecordSet{}
+ recordSetsToDelete = []*dns.ResourceRecordSet{}
+ )
+
+ for _, record := range recordSets.Rrsets {
+ if record.Type == "A" {
+ existingRecordSets = append(existingRecordSets, record)
+ }
+ }
+
+ // first pass: create what's missing
+ for _, subdomain := range desiredRecords {
+ found := false
+ subdomain = fmt.Sprintf("%s.%s", subdomain, zone.DnsName)
+ for _, r := range existingRecordSets {
+ if subdomain == r.Name && r.Type == "A" {
+ // check that the IP addresses are correct
+ ipsFound := 0
+ for _, rr := range r.Rrdatas {
+ for _, ip := range tsIpV4Addresses {
+ if rr == ip {
+ ipsFound += 1
+ continue
+ }
+ }
+ }
+ // while we found the subdomain with the correct type,
+ // we also need to make sure the list of IPs is
+ // correct. If they are not, we delete the record and
+ // add it again with the correct values.
+ if ipsFound == len(tsIpV4Addresses) {
+ found = true
+ continue
+ } else {
+ log.Printf("will delete %s (incorrect IPv4 addresses)\n", subdomain)
+ recordSetsToDelete = append(recordSetsToDelete, r)
+ }
+ }
+ }
+ if !found {
+ log.Printf("will add %s\n", subdomain)
+ r := &dns.ResourceRecordSet{
+ Name: subdomain,
+ Type: "A",
+ Ttl: TTL,
+ Rrdatas: tsIpV4Addresses,
+ }
+ recordSetsToAdd = append(recordSetsToAdd, r)
+ }
+ }
+
+ // second pass: delete what's not needed
+ for _, r := range existingRecordSets {
+ found := false
+ for _, subdomain := range desiredRecords {
+ subdomain = fmt.Sprintf("%s.%s", subdomain, zone.DnsName)
+ if subdomain == r.Name && r.Type == "A" {
+ found = true
+ continue
+ }
+ }
+ if !found {
+ log.Printf("will delete %s\n", r.Name)
+ recordSetsToDelete = append(recordSetsToDelete, r)
+ }
+ }
+
+ if len(recordSetsToAdd) > 0 || len(recordSetsToDelete) > 0 {
+ change := &dns.Change{Additions: recordSetsToAdd, Deletions: recordSetsToDelete}
+ if _, err = svc.Changes.Create(GCP_PROJECT_NAME, GCP_MANAGED_ZONE, change).Context(ctx).Do(); err != nil {
+ log.Fatalf("failed to apply the change: %+v", err)
+ }
+ }
+}