diff --git a/docs/tutorials/exoscale.md b/docs/tutorials/exoscale.md index 6f7dd3fbc..ba3e7b546 100644 --- a/docs/tutorials/exoscale.md +++ b/docs/tutorials/exoscale.md @@ -13,7 +13,6 @@ Additionally you will have to provide the Exoscale...: * API Key * API Secret -* API Endpoint * Elastic IP address, to access the workers ## Deployment @@ -48,11 +47,15 @@ spec: - --domain-filter={{ my-domain }} - --policy=sync # if you want DNS entries to get deleted as well - --txt-owner-id={{ owner-id-for-this-external-dns }} - - --exoscale-endpoint={{ endpoint }} # usually https://api.exoscale.ch/dns - --exoscale-apikey={{ api-key}} - --exoscale-apisecret={{ api-secret }} + # - --exoscale-apizone={{ api-zone }} + # - --exoscale-apienv={{ api-env }} ``` +Optional arguments `--exoscale-apizone` and `--exoscale-apienv` define [Exoscale API Zone](https://community.exoscale.com/documentation/platform/exoscale-datacenter-zones/) +(default `ch-gva-2`) and Exoscale API environment (default `api`, can be used to target non-production API server) respectively. + ## RBAC If your cluster is RBAC enabled, you also need to setup the following, before you can run external-dns: @@ -121,6 +124,7 @@ spec: name: "nginx" port: number: 80 + path: / pathType: Prefix --- diff --git a/go.mod b/go.mod index 45b5d3236..0e2e540ce 100644 --- a/go.mod +++ b/go.mod @@ -30,6 +30,7 @@ require ( github.com/ffledgling/pdns-go v0.0.0-20180219074714-524e7daccd99 github.com/go-gandi/go-gandi v0.6.0 github.com/google/go-cmp v0.5.9 + github.com/google/uuid v1.3.0 github.com/gophercloud/gophercloud v1.5.0 github.com/hooklift/gowsdl v0.5.0 github.com/infobloxopen/infoblox-go-client/v2 v2.3.0 @@ -123,7 +124,6 @@ require ( github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/s2a-go v0.1.4 // indirect - github.com/google/uuid v1.3.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect diff --git a/main.go b/main.go index a6652cfd2..00416957b 100644 --- a/main.go +++ b/main.go @@ -309,7 +309,15 @@ func main() { }, ) case "exoscale": - p, err = exoscale.NewExoscaleProvider(cfg.ExoscaleEndpoint, cfg.ExoscaleAPIKey, cfg.ExoscaleAPISecret, cfg.DryRun, exoscale.ExoscaleWithDomain(domainFilter), exoscale.ExoscaleWithLogging()), nil + p, err = exoscale.NewExoscaleProvider( + cfg.ExoscaleAPIEnvironment, + cfg.ExoscaleAPIZone, + cfg.ExoscaleAPIKey, + cfg.ExoscaleAPISecret, + cfg.DryRun, + exoscale.ExoscaleWithDomain(domainFilter), + exoscale.ExoscaleWithLogging(), + ) case "inmemory": p, err = inmemory.NewInMemoryProvider(inmemory.InMemoryInitZones(cfg.InMemoryZones), inmemory.InMemoryWithDomain(domainFilter), inmemory.InMemoryWithLogging()), nil case "designate": diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index 4abb83d4f..5026dd5fa 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -164,6 +164,8 @@ type Config struct { ExoscaleEndpoint string ExoscaleAPIKey string `secure:"yes"` ExoscaleAPISecret string `secure:"yes"` + ExoscaleAPIEnvironment string + ExoscaleAPIZone string CRDSourceAPIVersion string CRDSourceKind string ServiceTypeFilter []string @@ -310,7 +312,8 @@ var defaultConfig = &Config{ LogFormat: "text", MetricsAddress: ":7979", LogLevel: logrus.InfoLevel.String(), - ExoscaleEndpoint: "https://api.exoscale.ch/dns", + ExoscaleAPIEnvironment: "api", + ExoscaleAPIZone: "ch-gva-2", ExoscaleAPIKey: "", ExoscaleAPISecret: "", CRDSourceAPIVersion: "externaldns.k8s.io/v1alpha1", @@ -534,7 +537,9 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("tls-client-cert", "When using TLS communication, the path to the certificate to present as a client (not required for TLS)").Default(defaultConfig.TLSClientCert).StringVar(&cfg.TLSClientCert) app.Flag("tls-client-cert-key", "When using TLS communication, the path to the certificate key to use with the client certificate (not required for TLS)").Default(defaultConfig.TLSClientCertKey).StringVar(&cfg.TLSClientCertKey) - app.Flag("exoscale-endpoint", "Provide the endpoint for the Exoscale provider").Default(defaultConfig.ExoscaleEndpoint).StringVar(&cfg.ExoscaleEndpoint) + // Flags related to Exoscale provider + app.Flag("exoscale-apienv", "When using Exoscale provider, specify the API environment (optional)").Default(defaultConfig.ExoscaleAPIEnvironment).StringVar(&cfg.ExoscaleAPIEnvironment) + app.Flag("exoscale-apizone", "When using Exoscale provider, specify the API Zone (optional)").Default(defaultConfig.ExoscaleAPIZone).StringVar(&cfg.ExoscaleAPIZone) app.Flag("exoscale-apikey", "Provide your API Key for the Exoscale provider").Default(defaultConfig.ExoscaleAPIKey).StringVar(&cfg.ExoscaleAPIKey) app.Flag("exoscale-apisecret", "Provide your API Secret for the Exoscale provider").Default(defaultConfig.ExoscaleAPISecret).StringVar(&cfg.ExoscaleAPISecret) diff --git a/pkg/apis/externaldns/types_test.go b/pkg/apis/externaldns/types_test.go index 12dc62130..b15398895 100644 --- a/pkg/apis/externaldns/types_test.go +++ b/pkg/apis/externaldns/types_test.go @@ -113,7 +113,8 @@ var ( MetricsAddress: ":7979", LogLevel: logrus.InfoLevel.String(), ConnectorSourceServer: "localhost:8080", - ExoscaleEndpoint: "https://api.exoscale.ch/dns", + ExoscaleAPIEnvironment: "api", + ExoscaleAPIZone: "ch-gva-2", ExoscaleAPIKey: "", ExoscaleAPISecret: "", CRDSourceAPIVersion: "externaldns.k8s.io/v1alpha1", @@ -222,7 +223,8 @@ var ( MetricsAddress: "127.0.0.1:9099", LogLevel: logrus.DebugLevel.String(), ConnectorSourceServer: "localhost:8081", - ExoscaleEndpoint: "https://api.foo.ch/dns", + ExoscaleAPIEnvironment: "api1", + ExoscaleAPIZone: "zone1", ExoscaleAPIKey: "1", ExoscaleAPISecret: "2", CRDSourceAPIVersion: "test.k8s.io/v1alpha1", @@ -360,7 +362,8 @@ func TestParseFlags(t *testing.T) { "--metrics-address=127.0.0.1:9099", "--log-level=debug", "--connector-source-server=localhost:8081", - "--exoscale-endpoint=https://api.foo.ch/dns", + "--exoscale-apienv=api1", + "--exoscale-apizone=zone1", "--exoscale-apikey=1", "--exoscale-apisecret=2", "--crd-source-apiversion=test.k8s.io/v1alpha1", @@ -479,7 +482,8 @@ func TestParseFlags(t *testing.T) { "EXTERNAL_DNS_METRICS_ADDRESS": "127.0.0.1:9099", "EXTERNAL_DNS_LOG_LEVEL": "debug", "EXTERNAL_DNS_CONNECTOR_SOURCE_SERVER": "localhost:8081", - "EXTERNAL_DNS_EXOSCALE_ENDPOINT": "https://api.foo.ch/dns", + "EXTERNAL_DNS_EXOSCALE_APIENV": "api1", + "EXTERNAL_DNS_EXOSCALE_APIZONE": "zone1", "EXTERNAL_DNS_EXOSCALE_APIKEY": "1", "EXTERNAL_DNS_EXOSCALE_APISECRET": "2", "EXTERNAL_DNS_CRD_SOURCE_APIVERSION": "test.k8s.io/v1alpha1", diff --git a/provider/exoscale/exoscale.go b/provider/exoscale/exoscale.go index 1c3c89f5a..87a9caef0 100644 --- a/provider/exoscale/exoscale.go +++ b/provider/exoscale/exoscale.go @@ -20,7 +20,8 @@ import ( "context" "strings" - "github.com/exoscale/egoscale" + egoscale "github.com/exoscale/egoscale/v2" + exoapi "github.com/exoscale/egoscale/v2/api" log "github.com/sirupsen/logrus" "sigs.k8s.io/external-dns/endpoint" @@ -30,11 +31,12 @@ import ( // EgoscaleClientI for replaceable implementation type EgoscaleClientI interface { - GetRecords(context.Context, string) ([]egoscale.DNSRecord, error) - GetDomains(context.Context) ([]egoscale.DNSDomain, error) - CreateRecord(context.Context, string, egoscale.DNSRecord) (*egoscale.DNSRecord, error) - DeleteRecord(context.Context, string, int64) error - UpdateRecord(context.Context, string, egoscale.UpdateDNSRecord) (*egoscale.DNSRecord, error) + ListDNSDomainRecords(context.Context, string, string) ([]egoscale.DNSDomainRecord, error) + ListDNSDomains(context.Context, string) ([]egoscale.DNSDomain, error) + GetDNSDomainRecord(context.Context, string, string, string) (*egoscale.DNSDomainRecord, error) + CreateDNSDomainRecord(context.Context, string, string, *egoscale.DNSDomainRecord) (*egoscale.DNSDomainRecord, error) + DeleteDNSDomainRecord(context.Context, string, string, *egoscale.DNSDomainRecord) error + UpdateDNSDomainRecord(context.Context, string, string, *egoscale.DNSDomainRecord) error } // ExoscaleProvider initialized as dns provider with no records @@ -42,6 +44,8 @@ type ExoscaleProvider struct { provider.BaseProvider domain endpoint.DomainFilter client EgoscaleClientI + apiEnv string + apiZone string filter *zoneFilter OnApplyChanges func(changes *plan.Changes) dryRun bool @@ -51,18 +55,27 @@ type ExoscaleProvider struct { type ExoscaleOption func(*ExoscaleProvider) // NewExoscaleProvider returns ExoscaleProvider DNS provider interface implementation -func NewExoscaleProvider(endpoint, apiKey, apiSecret string, dryRun bool, opts ...ExoscaleOption) *ExoscaleProvider { - client := egoscale.NewClient(endpoint, apiKey, apiSecret) - return NewExoscaleProviderWithClient(endpoint, apiKey, apiSecret, client, dryRun, opts...) +func NewExoscaleProvider(env, zone, key, secret string, dryRun bool, opts ...ExoscaleOption) (*ExoscaleProvider, error) { + client, err := egoscale.NewClient( + key, + secret, + ) + if err != nil { + return nil, err + } + + return NewExoscaleProviderWithClient(client, env, zone, dryRun, opts...), nil } // NewExoscaleProviderWithClient returns ExoscaleProvider DNS provider interface implementation (Client provided) -func NewExoscaleProviderWithClient(_, apiKey, apiSecret string, client EgoscaleClientI, dryRun bool, opts ...ExoscaleOption) *ExoscaleProvider { +func NewExoscaleProviderWithClient(client EgoscaleClientI, env, zone string, dryRun bool, opts ...ExoscaleOption) *ExoscaleProvider { ep := &ExoscaleProvider{ filter: &zoneFilter{}, OnApplyChanges: func(changes *plan.Changes) {}, domain: endpoint.NewDomainFilter([]string{""}), client: client, + apiEnv: env, + apiZone: zone, dryRun: dryRun, } for _, opt := range opts { @@ -71,16 +84,18 @@ func NewExoscaleProviderWithClient(_, apiKey, apiSecret string, client EgoscaleC return ep } -func (ep *ExoscaleProvider) getZones(ctx context.Context) (map[int64]string, error) { - dom, err := ep.client.GetDomains(ctx) +func (ep *ExoscaleProvider) getZones(ctx context.Context) (map[string]string, error) { + ctx = exoapi.WithEndpoint(ctx, exoapi.NewReqEndpoint(ep.apiEnv, ep.apiZone)) + domains, err := ep.client.ListDNSDomains(ctx, ep.apiZone) if err != nil { return nil, err } - zones := map[int64]string{} - for _, d := range dom { - zones[d.ID] = d.Name + zones := map[string]string{} + for _, domain := range domains { + zones[*domain.ID] = *domain.UnicodeName } + return zones, nil } @@ -95,52 +110,79 @@ func (ep *ExoscaleProvider) ApplyChanges(ctx context.Context, changes *plan.Chan return nil } + ctx = exoapi.WithEndpoint(ctx, exoapi.NewReqEndpoint(ep.apiEnv, ep.apiZone)) + zones, err := ep.getZones(ctx) if err != nil { return err } for _, epoint := range changes.Create { - if ep.domain.Match(epoint.DNSName) { - if zoneID, name := ep.filter.EndpointZoneID(epoint, zones); zoneID != 0 { - rec := egoscale.DNSRecord{ - Name: name, - RecordType: epoint.RecordType, - TTL: int(epoint.RecordTTL), - Content: epoint.Targets[0], - } - _, err := ep.client.CreateRecord(ctx, zones[zoneID], rec) - if err != nil { - return err - } - } + if !ep.domain.Match(epoint.DNSName) { + continue + } + + zoneID, name := ep.filter.EndpointZoneID(epoint, zones) + if zoneID == "" { + continue + } + + // API does not accept 0 as default TTL but wants nil pointer instead + var ttl *int64 + if epoint.RecordTTL != 0 { + t := int64(epoint.RecordTTL) + ttl = &t + } + record := egoscale.DNSDomainRecord{ + Name: &name, + Type: &epoint.RecordType, + TTL: ttl, + Content: &epoint.Targets[0], + } + _, err := ep.client.CreateDNSDomainRecord(ctx, ep.apiZone, zoneID, &record) + if err != nil { + return err } } + for _, epoint := range changes.UpdateNew { - if ep.domain.Match(epoint.DNSName) { - if zoneID, name := ep.filter.EndpointZoneID(epoint, zones); zoneID != 0 { - records, err := ep.client.GetRecords(ctx, zones[zoneID]) - if err != nil { - return err - } - for _, r := range records { - if r.Name == name { - rec := egoscale.UpdateDNSRecord{ - ID: r.ID, - DomainID: r.DomainID, - Name: name, - RecordType: epoint.RecordType, - TTL: int(epoint.RecordTTL), - Content: epoint.Targets[0], - Prio: r.Prio, - } - if _, err := ep.client.UpdateRecord(ctx, zones[zoneID], rec); err != nil { - return err - } - break - } - } + if !ep.domain.Match(epoint.DNSName) { + continue + } + + zoneID, name := ep.filter.EndpointZoneID(epoint, zones) + if zoneID == "" { + continue + } + + records, err := ep.client.ListDNSDomainRecords(ctx, ep.apiZone, zoneID) + if err != nil { + return err + } + + for _, r := range records { + if *r.Name != name { + continue } + + record, err := ep.client.GetDNSDomainRecord(ctx, ep.apiZone, zoneID, *r.ID) + if err != nil { + return err + } + + record.Type = &epoint.RecordType + record.Content = &epoint.Targets[0] + if epoint.RecordTTL != 0 { + ttl := int64(epoint.RecordTTL) + record.TTL = &ttl + } + + err = ep.client.UpdateDNSDomainRecord(ctx, ep.apiZone, zoneID, record) + if err != nil { + return err + } + + break } } @@ -151,22 +193,31 @@ func (ep *ExoscaleProvider) ApplyChanges(ctx context.Context, changes *plan.Chan } for _, epoint := range changes.Delete { - if ep.domain.Match(epoint.DNSName) { - if zoneID, name := ep.filter.EndpointZoneID(epoint, zones); zoneID != 0 { - records, err := ep.client.GetRecords(ctx, zones[zoneID]) - if err != nil { - return err - } + if !ep.domain.Match(epoint.DNSName) { + continue + } - for _, r := range records { - if r.Name == name { - if err := ep.client.DeleteRecord(ctx, zones[zoneID], r.ID); err != nil { - return err - } - break - } - } + zoneID, name := ep.filter.EndpointZoneID(epoint, zones) + if zoneID == "" { + continue + } + + records, err := ep.client.ListDNSDomainRecords(ctx, ep.apiZone, zoneID) + if err != nil { + return err + } + + for _, record := range records { + if *record.Name != name { + continue } + + err = ep.client.DeleteDNSDomainRecord(ctx, ep.apiZone, zoneID, &egoscale.DNSDomainRecord{ID: record.ID}) + if err != nil { + return err + } + + break } } @@ -175,27 +226,34 @@ func (ep *ExoscaleProvider) ApplyChanges(ctx context.Context, changes *plan.Chan // Records returns the list of endpoints func (ep *ExoscaleProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error) { + ctx = exoapi.WithEndpoint(ctx, exoapi.NewReqEndpoint(ep.apiEnv, ep.apiZone)) endpoints := make([]*endpoint.Endpoint, 0) - domains, err := ep.client.GetDomains(ctx) + domains, err := ep.client.ListDNSDomains(ctx, ep.apiZone) if err != nil { return nil, err } - for _, d := range domains { - record, err := ep.client.GetRecords(ctx, d.Name) + for _, domain := range domains { + records, err := ep.client.ListDNSDomainRecords(ctx, ep.apiZone, *domain.ID) if err != nil { return nil, err } - for _, r := range record { - switch r.RecordType { - case egoscale.A.String(), egoscale.CNAME.String(), egoscale.TXT.String(): + + for _, r := range records { + record, err := ep.client.GetDNSDomainRecord(ctx, ep.apiZone, *domain.ID, *r.ID) + if err != nil { + return nil, err + } + switch *record.Type { + case "A", "CNAME", "TXT": break default: continue } - ep := endpoint.NewEndpointWithTTL(r.Name+"."+d.Name, r.RecordType, endpoint.TTL(r.TTL), r.Content) - endpoints = append(endpoints, ep) + + e := endpoint.NewEndpointWithTTL((*record.Name)+"."+(*domain.UnicodeName), *record.Type, endpoint.TTL(*r.TTL), *record.Content) + endpoints = append(endpoints, e) } } @@ -235,8 +293,8 @@ type zoneFilter struct { } // Zones filters map[zoneID]zoneName for names having f.domain as suffix -func (f *zoneFilter) Zones(zones map[int64]string) map[int64]string { - result := map[int64]string{} +func (f *zoneFilter) Zones(zones map[string]string) map[string]string { + result := map[string]string{} for zoneID, zoneName := range zones { if strings.HasSuffix(zoneName, f.domain) { result[zoneID] = zoneName @@ -246,9 +304,9 @@ func (f *zoneFilter) Zones(zones map[int64]string) map[int64]string { } // EndpointZoneID determines zoneID for endpoint from map[zoneID]zoneName by taking longest suffix zoneName match in endpoint DNSName -// returns 0 if no matches are found -func (f *zoneFilter) EndpointZoneID(endpoint *endpoint.Endpoint, zones map[int64]string) (zoneID int64, name string) { - var matchZoneID int64 +// returns empty string if no matches are found +func (f *zoneFilter) EndpointZoneID(endpoint *endpoint.Endpoint, zones map[string]string) (zoneID string, name string) { + var matchZoneID string var matchZoneName string for zoneID, zoneName := range zones { if strings.HasSuffix(endpoint.DNSName, "."+zoneName) && len(zoneName) > len(matchZoneName) { diff --git a/provider/exoscale/exoscale_test.go b/provider/exoscale/exoscale_test.go index b4ac332ab..2e7f142c4 100644 --- a/provider/exoscale/exoscale_test.go +++ b/provider/exoscale/exoscale_test.go @@ -18,29 +18,31 @@ package exoscale import ( "context" - "strings" + "errors" "testing" - "github.com/exoscale/egoscale" + egoscale "github.com/exoscale/egoscale/v2" "github.com/stretchr/testify/assert" "sigs.k8s.io/external-dns/endpoint" "sigs.k8s.io/external-dns/plan" + + "github.com/google/uuid" ) type createRecordExoscale struct { - name string - rec egoscale.DNSRecord + domainID string + record *egoscale.DNSDomainRecord } type deleteRecordExoscale struct { - name string - recordID int64 + domainID string + recordID string } type updateRecordExoscale struct { - name string - updateDNSRecord egoscale.UpdateDNSRecord + domainID string + record *egoscale.DNSDomainRecord } var ( @@ -49,6 +51,29 @@ var ( updateExoscale []updateRecordExoscale ) +var defaultTTL int64 = 3600 +var domainIDs = []string{uuid.New().String(), uuid.New().String(), uuid.New().String(), uuid.New().String()} +var groups = map[string][]egoscale.DNSDomainRecord{ + domainIDs[0]: { + {ID: strPtr(uuid.New().String()), Name: strPtr("v1"), Type: strPtr("TXT"), Content: strPtr("test"), TTL: &defaultTTL}, + {ID: strPtr(uuid.New().String()), Name: strPtr("v2"), Type: strPtr("CNAME"), Content: strPtr("test"), TTL: &defaultTTL}, + }, + domainIDs[1]: { + {ID: strPtr(uuid.New().String()), Name: strPtr("v2"), Type: strPtr("A"), Content: strPtr("test"), TTL: &defaultTTL}, + {ID: strPtr(uuid.New().String()), Name: strPtr("v3"), Type: strPtr("ALIAS"), Content: strPtr("test"), TTL: &defaultTTL}, + }, + domainIDs[2]: { + {ID: strPtr(uuid.New().String()), Name: strPtr("v1"), Type: strPtr("TXT"), Content: strPtr("test"), TTL: &defaultTTL}, + }, + domainIDs[3]: { + {ID: strPtr(uuid.New().String()), Name: strPtr("v4"), Type: strPtr("ALIAS"), Content: strPtr("test"), TTL: &defaultTTL}, + }, +} + +func strPtr(s string) *string { + return &s +} + type ExoscaleClientStub struct{} func NewExoscaleClientStub() EgoscaleClientI { @@ -56,48 +81,42 @@ func NewExoscaleClientStub() EgoscaleClientI { return ep } -func (ep *ExoscaleClientStub) DeleteRecord(ctx context.Context, name string, recordID int64) error { - deleteExoscale = append(deleteExoscale, deleteRecordExoscale{name: name, recordID: recordID}) - return nil +func (ep *ExoscaleClientStub) ListDNSDomains(ctx context.Context, _ string) ([]egoscale.DNSDomain, error) { + domains := []egoscale.DNSDomain{ + {ID: &domainIDs[0], UnicodeName: strPtr("foo.com")}, + {ID: &domainIDs[1], UnicodeName: strPtr("bar.com")}, + } + return domains, nil } -func (ep *ExoscaleClientStub) GetRecords(ctx context.Context, name string) ([]egoscale.DNSRecord, error) { - init := []egoscale.DNSRecord{ - {ID: 0, Name: "v4.barfoo.com", RecordType: "ALIAS"}, - {ID: 1, Name: "v1.foo.com", RecordType: "TXT"}, - {ID: 2, Name: "v2.bar.com", RecordType: "A"}, - {ID: 3, Name: "v3.bar.com", RecordType: "ALIAS"}, - {ID: 4, Name: "v2.foo.com", RecordType: "CNAME"}, - {ID: 5, Name: "v1.foobar.com", RecordType: "TXT"}, - } +func (ep *ExoscaleClientStub) ListDNSDomainRecords(ctx context.Context, _, domainID string) ([]egoscale.DNSDomainRecord, error) { + return groups[domainID], nil +} - rec := make([]egoscale.DNSRecord, 0) - for _, r := range init { - if strings.HasSuffix(r.Name, "."+name) { - r.Name = strings.TrimSuffix(r.Name, "."+name) - rec = append(rec, r) +func (ep *ExoscaleClientStub) GetDNSDomainRecord(ctx context.Context, _, domainID, recordID string) (*egoscale.DNSDomainRecord, error) { + group := groups[domainID] + for _, record := range group { + if *record.ID == recordID { + return &record, nil } } - return rec, nil + return nil, errors.New("not found") } -func (ep *ExoscaleClientStub) UpdateRecord(ctx context.Context, name string, rec egoscale.UpdateDNSRecord) (*egoscale.DNSRecord, error) { - updateExoscale = append(updateExoscale, updateRecordExoscale{name: name, updateDNSRecord: rec}) - return nil, nil +func (ep *ExoscaleClientStub) CreateDNSDomainRecord(ctx context.Context, _, domainID string, record *egoscale.DNSDomainRecord) (*egoscale.DNSDomainRecord, error) { + createExoscale = append(createExoscale, createRecordExoscale{domainID: domainID, record: record}) + return record, nil } -func (ep *ExoscaleClientStub) CreateRecord(ctx context.Context, name string, rec egoscale.DNSRecord) (*egoscale.DNSRecord, error) { - createExoscale = append(createExoscale, createRecordExoscale{name: name, rec: rec}) - return nil, nil +func (ep *ExoscaleClientStub) DeleteDNSDomainRecord(ctx context.Context, _, domainID string, record *egoscale.DNSDomainRecord) error { + deleteExoscale = append(deleteExoscale, deleteRecordExoscale{domainID: domainID, recordID: *record.ID}) + return nil } -func (ep *ExoscaleClientStub) GetDomains(ctx context.Context) ([]egoscale.DNSDomain, error) { - dom := []egoscale.DNSDomain{ - {ID: 1, Name: "foo.com"}, - {ID: 2, Name: "bar.com"}, - } - return dom, nil +func (ep *ExoscaleClientStub) UpdateDNSDomainRecord(ctx context.Context, _, domainID string, record *egoscale.DNSDomainRecord) error { + updateExoscale = append(updateExoscale, updateRecordExoscale{domainID: domainID, record: record}) + return nil } func contains(arr []*endpoint.Endpoint, name string) bool { @@ -110,9 +129,10 @@ func contains(arr []*endpoint.Endpoint, name string) bool { } func TestExoscaleGetRecords(t *testing.T) { - provider := NewExoscaleProviderWithClient("", "", "", NewExoscaleClientStub(), false) + provider := NewExoscaleProviderWithClient(NewExoscaleClientStub(), "", "", false) - if recs, err := provider.Records(context.Background()); err == nil { + recs, err := provider.Records(context.Background()) + if err == nil { assert.Equal(t, 3, len(recs)) assert.True(t, contains(recs, "v1.foo.com")) assert.True(t, contains(recs, "v2.bar.com")) @@ -125,7 +145,7 @@ func TestExoscaleGetRecords(t *testing.T) { } func TestExoscaleApplyChanges(t *testing.T) { - provider := NewExoscaleProviderWithClient("", "", "", NewExoscaleClientStub(), false) + provider := NewExoscaleProviderWithClient(NewExoscaleClientStub(), "", "", false) plan := &plan.Changes{ Create: []*endpoint.Endpoint{ @@ -183,16 +203,16 @@ func TestExoscaleApplyChanges(t *testing.T) { provider.ApplyChanges(context.Background(), plan) assert.Equal(t, 1, len(createExoscale)) - assert.Equal(t, "foo.com", createExoscale[0].name) - assert.Equal(t, "v1", createExoscale[0].rec.Name) + assert.Equal(t, domainIDs[0], createExoscale[0].domainID) + assert.Equal(t, "v1", *createExoscale[0].record.Name) assert.Equal(t, 1, len(deleteExoscale)) - assert.Equal(t, "foo.com", deleteExoscale[0].name) - assert.Equal(t, int64(1), deleteExoscale[0].recordID) + assert.Equal(t, domainIDs[0], deleteExoscale[0].domainID) + assert.Equal(t, *groups[domainIDs[0]][0].ID, deleteExoscale[0].recordID) assert.Equal(t, 1, len(updateExoscale)) - assert.Equal(t, "foo.com", updateExoscale[0].name) - assert.Equal(t, int64(1), updateExoscale[0].updateDNSRecord.ID) + assert.Equal(t, domainIDs[0], updateExoscale[0].domainID) + assert.Equal(t, *groups[domainIDs[0]][0].ID, *updateExoscale[0].record.ID) } func TestExoscaleMerge_NoUpdateOnTTL0Changes(t *testing.T) {