diff --git a/handler/handler.go b/handler/handler.go index c071307..0056bcf 100644 --- a/handler/handler.go +++ b/handler/handler.go @@ -14,6 +14,7 @@ import ( v0 "github.com/m-lab/autojoin/api/v0" "github.com/m-lab/autojoin/iata" + "github.com/m-lab/autojoin/internal/dnsname" "github.com/m-lab/autojoin/internal/dnsx" "github.com/m-lab/autojoin/internal/dnsx/dnsiface" "github.com/m-lab/autojoin/internal/register" @@ -239,7 +240,7 @@ func (s *Server) Register(rw http.ResponseWriter, req *http.Request) { } // Register the hostname under the organization zone. - m := dnsx.NewManager(s.DNS, s.Project, register.OrgZone(param.Org, s.Project)) + m := dnsx.NewManager(s.DNS, s.Project, dnsname.OrgZone(param.Org, s.Project)) _, err = m.Register(req.Context(), r.Registration.Hostname+".", param.IPv4, param.IPv6) if err != nil { resp.Error = &v2.Error{ @@ -293,7 +294,7 @@ func (s *Server) Delete(rw http.ResponseWriter, req *http.Request) { return } - m := dnsx.NewManager(s.DNS, s.Project, register.OrgZone(name.Org, s.Project)) + m := dnsx.NewManager(s.DNS, s.Project, dnsname.OrgZone(name.Org, s.Project)) _, err = m.Delete(req.Context(), name.StringAll()+".") if err != nil { resp.Error = &v2.Error{ diff --git a/handler/handler_test.go b/handler/handler_test.go index 0ebac0a..55fed02 100644 --- a/handler/handler_test.go +++ b/handler/handler_test.go @@ -76,6 +76,12 @@ func (f *fakeDNS) ResourceRecordSetsGet(ctx context.Context, project string, zon func (f *fakeDNS) ChangeCreate(ctx context.Context, project string, zone string, change *dns.Change) (*dns.Change, error) { return nil, f.chgErr } +func (f *fakeDNS) CreateManagedZone(ctx context.Context, project string, zone *dns.ManagedZone) (*dns.ManagedZone, error) { + return nil, nil +} +func (f *fakeDNS) GetManagedZone(ctx context.Context, project, zoneName string) (*dns.ManagedZone, error) { + return nil, nil +} type fakeStatusTracker struct { updateErr error diff --git a/internal/dnsname/names.go b/internal/dnsname/names.go new file mode 100644 index 0000000..30d46a7 --- /dev/null +++ b/internal/dnsname/names.go @@ -0,0 +1,20 @@ +package dnsname + +import "strings" + +// ProjectZone returns the project zone name, e.g. "autojoin-sandbox-measurement-lab-org". +func ProjectZone(project string) string { + return "autojoin-" + strings.TrimPrefix(project, "mlab-") + "-measurement-lab-org" +} + +// OrgZone returns the organization zone name based on the given organization and +// project, e.g. "autojoin-foo-sandbox-measurement-lab-org". +func OrgZone(org, project string) string { + // NOTE: prefix prevents name collision with existing zones when the org is "mlab". + return "autojoin-" + org + "-" + strings.TrimPrefix(project, "mlab-") + "-measurement-lab-org" +} + +// OrgDNS returns the DNS name for the given org and project, e.g. "foo.autojoin.measurement-lab.org." +func OrgDNS(org, project string) string { + return org + "." + strings.TrimPrefix(project, "mlab-") + ".measurement-lab.org." +} diff --git a/internal/dnsname/names_test.go b/internal/dnsname/names_test.go new file mode 100644 index 0000000..5dc8e0e --- /dev/null +++ b/internal/dnsname/names_test.go @@ -0,0 +1,87 @@ +package dnsname + +import "testing" + +func TestProjectZone(t *testing.T) { + tests := []struct { + name string + project string + want string + }{ + { + name: "success", + project: "mlab-sandbox", + want: "autojoin-sandbox-measurement-lab-org", + }, + { + name: "success", + project: "mlab-autojoin", + want: "autojoin-autojoin-measurement-lab-org", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := ProjectZone(tt.project); got != tt.want { + t.Errorf("ProjectZone() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestOrgZone(t *testing.T) { + tests := []struct { + name string + org string + project string + want string + }{ + { + name: "success", + org: "mlab", + project: "mlab-sandbox", + want: "autojoin-mlab-sandbox-measurement-lab-org", + }, + { + name: "success", + org: "rnp", + project: "mlab-autojoin", + want: "autojoin-rnp-autojoin-measurement-lab-org", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := OrgZone(tt.org, tt.project); got != tt.want { + t.Errorf("OrgZone() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestOrgDNS(t *testing.T) { + tests := []struct { + name string + org string + project string + want string + }{ + { + name: "success", + org: "foo", + project: "mlab-sandbox", + want: "foo.sandbox.measurement-lab.org.", + }, + { + name: "success", + org: "mlab", + project: "mlab-autojoin", + want: "mlab.autojoin.measurement-lab.org.", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := OrgDNS(tt.org, tt.project); got != tt.want { + t.Errorf("OrgDNS() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/internal/dnsx/dnsiface/dns.go b/internal/dnsx/dnsiface/dns.go index 563b86c..763413a 100644 --- a/internal/dnsx/dnsiface/dns.go +++ b/internal/dnsx/dnsiface/dns.go @@ -10,6 +10,8 @@ import ( type Service interface { ResourceRecordSetsGet(ctx context.Context, project string, zone string, name string, type_ string) (*dns.ResourceRecordSet, error) ChangeCreate(ctx context.Context, project string, zone string, change *dns.Change) (*dns.Change, error) + GetManagedZone(ctx context.Context, project, zoneName string) (*dns.ManagedZone, error) + CreateManagedZone(ctx context.Context, project string, z *dns.ManagedZone) (*dns.ManagedZone, error) } // CloudDNSService implements the DNS Service interface. @@ -17,6 +19,11 @@ type CloudDNSService struct { Service *dns.Service } +// NewCloudDNSService creates a new instance of the CloudDNSService. +func NewCloudDNSService(s *dns.Service) *CloudDNSService { + return &CloudDNSService{Service: s} +} + // ResourceRecordSetsGet gets an existing resource record set, if present. func (c *CloudDNSService) ResourceRecordSetsGet(ctx context.Context, project string, zone string, name string, rtype string) (*dns.ResourceRecordSet, error) { return c.Service.ResourceRecordSets.Get(project, zone, name, rtype).Context(ctx).Do() @@ -26,3 +33,13 @@ func (c *CloudDNSService) ResourceRecordSetsGet(ctx context.Context, project str func (c *CloudDNSService) ChangeCreate(ctx context.Context, project string, zone string, change *dns.Change) (*dns.Change, error) { return c.Service.Changes.Create(project, zone, change).Context(ctx).Do() } + +// GetManagedZone gets the named zone. +func (c *CloudDNSService) GetManagedZone(ctx context.Context, project, zoneName string) (*dns.ManagedZone, error) { + return c.Service.ManagedZones.Get(project, zoneName).Context(ctx).Do() +} + +// CreateManagedZone creates the given zone. +func (c *CloudDNSService) CreateManagedZone(ctx context.Context, project string, zone *dns.ManagedZone) (*dns.ManagedZone, error) { + return c.Service.ManagedZones.Create(project, zone).Context(ctx).Do() +} diff --git a/internal/dnsx/register_test.go b/internal/dnsx/register_test.go index a5fee72..6e6c636 100644 --- a/internal/dnsx/register_test.go +++ b/internal/dnsx/register_test.go @@ -38,6 +38,13 @@ func (f *fakeDNS) ChangeCreate(ctx context.Context, project string, zone string, return change, nil } +func (f *fakeDNS) CreateManagedZone(ctx context.Context, project string, zone *dns.ManagedZone) (*dns.ManagedZone, error) { + return nil, nil +} +func (f *fakeDNS) GetManagedZone(ctx context.Context, project, zoneName string) (*dns.ManagedZone, error) { + return nil, nil +} + func TestManager_Register(t *testing.T) { tests := []struct { name string diff --git a/internal/register/register.go b/internal/register/register.go index a366b12..7e98e14 100644 --- a/internal/register/register.go +++ b/internal/register/register.go @@ -19,23 +19,17 @@ var ( // Params is used internally to collect multiple parameters. type Params struct { - Project string - Service string - Org string - IPv4 string - IPv6 string - Geo *geoip2.City - Metro iata.Row - Network *annotator.Network + Project string + Service string + Org string + IPv4 string + IPv6 string + Geo *geoip2.City + Metro iata.Row + Network *annotator.Network Probability float64 } -// OrgZone generates the organization zone name based the organization and project. -func OrgZone(org, project string) string { - // NOTE: prefix prevents name collision with existing zones when the org is "mlab". - return "autojoin-" + org + "-" + strings.TrimPrefix(project, "mlab-") + "-measurement-lab-org" -} - // CreateRegisterResponse generates a RegisterResponse from the given // parameters. As an internal package, the caller is required to validate all // input parameters. diff --git a/internal/register/register_test.go b/internal/register/register_test.go index 555798b..e2b82f4 100644 --- a/internal/register/register_test.go +++ b/internal/register/register_test.go @@ -117,26 +117,3 @@ func TestCreateRegisterResponse(t *testing.T) { }) } } - -func TestOrgZone(t *testing.T) { - tests := []struct { - name string - org string - project string - want string - }{ - { - name: "success", - org: "mlab", - project: "mlab-sandbox", - want: "autojoin-mlab-sandbox-measurement-lab-org", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := OrgZone(tt.org, tt.project); got != tt.want { - t.Errorf("OrgZone() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/internal/tracker/gc.go b/internal/tracker/gc.go index c337ebf..aab37ee 100644 --- a/internal/tracker/gc.go +++ b/internal/tracker/gc.go @@ -6,9 +6,9 @@ import ( "time" "github.com/gomodule/redigo/redis" + "github.com/m-lab/autojoin/internal/dnsname" "github.com/m-lab/autojoin/internal/dnsx" "github.com/m-lab/autojoin/internal/dnsx/dnsiface" - "github.com/m-lab/autojoin/internal/register" "github.com/m-lab/go/host" "github.com/m-lab/locate/memorystore" ) @@ -133,7 +133,7 @@ func (gc *GarbageCollector) checkAndRemoveExpired() ([]string, [][]string, error // TODO(rd): count errors with a Prometheus metric } - m := dnsx.NewManager(gc.dns, gc.project, register.OrgZone(name.Org, gc.project)) + m := dnsx.NewManager(gc.dns, gc.project, dnsname.OrgZone(name.Org, gc.project)) _, err = m.Delete(context.Background(), name.StringAll()+".") if err != nil { log.Printf("Failed to delete DNS entry for %s: %v", name, err) diff --git a/internal/tracker/gc_test.go b/internal/tracker/gc_test.go index 2f9660c..22c2751 100644 --- a/internal/tracker/gc_test.go +++ b/internal/tracker/gc_test.go @@ -24,6 +24,12 @@ func (f *fakeDNS) ResourceRecordSetsGet(ctx context.Context, project string, zon func (f *fakeDNS) ChangeCreate(ctx context.Context, project string, zone string, change *dns.Change) (*dns.Change, error) { return nil, f.chgErr } +func (f *fakeDNS) CreateManagedZone(ctx context.Context, project string, zone *dns.ManagedZone) (*dns.ManagedZone, error) { + return nil, nil +} +func (f *fakeDNS) GetManagedZone(ctx context.Context, project, zoneName string) (*dns.ManagedZone, error) { + return nil, nil +} type fakeMemorystoreClient[V any] struct { putErr error diff --git a/main.go b/main.go index 85b908b..5ba3180 100644 --- a/main.go +++ b/main.go @@ -80,7 +80,7 @@ func main() { // Setup DNS service. ds, err := dns.NewService(mainCtx) rtx.Must(err, "failed to create new dns service") - d := &dnsiface.CloudDNSService{Service: ds} + d := dnsiface.NewCloudDNSService(ds) // Setup IATA, maxmind, and asn sources. i, err := iata.New(mainCtx, iataSrc.URL)