From 8003a3f00b59512cbc28e1b82d377a188d95e645 Mon Sep 17 00:00:00 2001 From: Christopher Schmidt Date: Wed, 4 Jul 2018 12:31:48 +0200 Subject: [PATCH 01/13] initial Exoscale Provider --- main.go | 2 + pkg/apis/externaldns/types.go | 9 +- provider/exoscale.go | 201 ++++++++++++++++++++++++++++++++++ provider/exoscale_test.go | 174 +++++++++++++++++++++++++++++ 4 files changed, 385 insertions(+), 1 deletion(-) create mode 100644 provider/exoscale.go create mode 100644 provider/exoscale_test.go diff --git a/main.go b/main.go index 0036930d3f..b3a691f3a2 100644 --- a/main.go +++ b/main.go @@ -142,6 +142,8 @@ func main() { ) case "coredns", "skydns": p, err = provider.NewCoreDNSProvider(domainFilter, cfg.DryRun) + case "exoscale": + p, err = provider.NewExoscaleProvider(cfg.ExoEndpoint, cfg.ExoAPIKey, cfg.ExoAPISecret, provider.ExoWithDomain(domainFilter), provider.ExoWithLogging()), nil case "inmemory": p, err = provider.NewInMemoryProvider(provider.InMemoryInitZones(cfg.InMemoryZones), provider.InMemoryWithDomain(domainFilter), provider.InMemoryWithLogging()), nil case "designate": diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index 73604d4387..bb6bb1472a 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -79,6 +79,9 @@ type Config struct { MetricsAddress string LogLevel string TXTCacheInterval time.Duration + ExoEndpoint string + ExoAPIKey string + ExoAPISecret string } var defaultConfig = &Config{ @@ -170,7 +173,7 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("connector-source-server", "The server to connect for connector source, valid only when using connector source").Default(defaultConfig.ConnectorSourceServer).StringVar(&cfg.ConnectorSourceServer) // Flags related to providers - app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: aws, aws-sd, google, azure, cloudflare, digitalocean, dnsimple, infoblox, dyn, designate, coredns, skydns, inmemory, pdns)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "aws-sd", "google", "azure", "cloudflare", "digitalocean", "dnsimple", "infoblox", "dyn", "designate", "coredns", "skydns", "inmemory", "pdns") + app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: aws, aws-sd, google, azure, cloudflare, digitalocean, dnsimple, infoblox, dyn, designate, coredns, skydns, inmemory, pdns)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "aws-sd", "google", "azure", "cloudflare", "digitalocean", "dnsimple", "infoblox", "dyn", "designate", "coredns", "skydns", "exoscale", "inmemory", "pdns") app.Flag("domain-filter", "Limit possible target zones by a domain suffix; specify multiple times for multiple domains (optional)").Default("").StringsVar(&cfg.DomainFilter) app.Flag("zone-id-filter", "Filter target zones by hosted zone id; specify multiple times for multiple zones (optional)").Default("").StringsVar(&cfg.ZoneIDFilter) app.Flag("google-project", "When using the Google provider, current project is auto-detected, when running on GCP. Specify other project with this. Must be specified when running outside GCP.").Default(defaultConfig.GoogleProject).StringVar(&cfg.GoogleProject) @@ -194,6 +197,10 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("pdns-server", "When using the PowerDNS/PDNS provider, specify the URL to the pdns server (required when --provider=pdns)").Default(defaultConfig.PDNSServer).StringVar(&cfg.PDNSServer) app.Flag("pdns-api-key", "When using the PowerDNS/PDNS provider, specify the URL to the pdns server (required when --provider=pdns)").Default(defaultConfig.PDNSAPIKey).StringVar(&cfg.PDNSAPIKey) + app.Flag("exo-endpoint", "Provide the endpoint for the Exoscale provider").Default("").StringVar(&cfg.ExoEndpoint) + app.Flag("exo-apikey", "Provide your API Key for the Exoscale provider").Default("").StringVar(&cfg.ExoAPIKey) + app.Flag("exo-apisecret", "Provide your API Secret for the Exoscale provider").Default("").StringVar(&cfg.ExoAPISecret) + // Flags related to policies app.Flag("policy", "Modify how DNS records are sychronized between sources and providers (default: sync, options: sync, upsert-only)").Default(defaultConfig.Policy).EnumVar(&cfg.Policy, "sync", "upsert-only") diff --git a/provider/exoscale.go b/provider/exoscale.go new file mode 100644 index 0000000000..70fe6102e8 --- /dev/null +++ b/provider/exoscale.go @@ -0,0 +1,201 @@ +package provider + +import ( + "strings" + + "github.com/exoscale/egoscale" + "github.com/kubernetes-incubator/external-dns/endpoint" + "github.com/kubernetes-incubator/external-dns/plan" + log "github.com/sirupsen/logrus" +) + +// EgoscaleClientI for replaceable implementation +type EgoscaleClientI interface { + GetRecords(string) ([]egoscale.DNSRecord, error) + GetDomains() ([]egoscale.DNSDomain, error) + CreateRecord(string, egoscale.DNSRecord) (*egoscale.DNSRecord, error) + DeleteRecord(string, int64) error +} + +// ExoscaleProvider initialized as dns provider with no records +type ExoscaleProvider struct { + domain DomainFilter + client EgoscaleClientI + filter *zoneFilter + OnApplyChanges func(changes *plan.Changes) +} + +// ExoscaleOption for Provider options +type ExoscaleOption func(*ExoscaleProvider) + +// NewExoscaleProvider returns ExoscaleProvider DNS provider interface implementation +func NewExoscaleProvider(endpoint, apiKey, apiSecret string, opts ...ExoscaleOption) *ExoscaleProvider { + client := egoscale.NewClient(endpoint, apiKey, apiSecret) + return NewExoscaleProviderWithClient(endpoint, apiKey, apiSecret, client, opts...) +} + +// NewExoscaleProviderWithClient returns ExoscaleProvider DNS provider interface implementation (Client provided) +func NewExoscaleProviderWithClient(endpoint, apiKey, apiSecret string, client EgoscaleClientI, opts ...ExoscaleOption) *ExoscaleProvider { + ep := &ExoscaleProvider{ + filter: &zoneFilter{}, + OnApplyChanges: func(changes *plan.Changes) {}, + domain: NewDomainFilter([]string{""}), + client: client, + } + for _, opt := range opts { + opt(ep) + } + return ep +} + +func (ep *ExoscaleProvider) getZones() (map[int64]string, error) { + dom, err := ep.client.GetDomains() + if err != nil { + return nil, err + } + + zones := map[int64]string{} + for _, d := range dom { + zones[d.ID] = d.Name + } + return zones, nil +} + +// ApplyChanges simply modifies DNS via exoscale API +func (ep *ExoscaleProvider) ApplyChanges(changes *plan.Changes) error { + ep.OnApplyChanges(changes) + + zones, err := ep.getZones() + 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(zones[zoneID], rec) + if err != nil { + return err + } + } + } + } + for _, epoint := range changes.UpdateNew { + log.Debugf("UPDATE-NEW (ignored) for epoint: %+v", epoint) + } + for _, epoint := range changes.UpdateOld { + log.Debugf("UPDATE-OLD (ignored) for epoint: %+v", epoint) + } + for _, epoint := range changes.Delete { + if zoneID, name := ep.filter.EndpointZoneID(epoint, zones); zoneID != 0 { + records, err := ep.client.GetRecords(zones[zoneID]) + if err != nil { + return err + } + + for _, r := range records { + if r.Name == name { + if err := ep.client.DeleteRecord(zones[zoneID], r.ID); err != nil { + return err + } + break + } + } + } + } + + return nil +} + +// Records returns the list of endpoints +func (ep *ExoscaleProvider) Records() ([]*endpoint.Endpoint, error) { + endpoints := make([]*endpoint.Endpoint, 0) + + dom, err := ep.client.GetDomains() + if err != nil { + return nil, err + } + + for _, d := range dom { + record, err := ep.client.GetRecords(d.Name) + if err != nil { + return nil, err + } + for _, r := range record { + switch r.RecordType { + 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) + } + } + + log.Infof("called Records() with %d items", len(endpoints)) + return endpoints, nil +} + +// ExoWithDomain modifies the domain on which dns zones are filtered +func ExoWithDomain(domainFilter DomainFilter) ExoscaleOption { + return func(p *ExoscaleProvider) { + p.domain = domainFilter + } +} + +// ExoWithLogging injects logging when ApplyChanges is called +func ExoWithLogging() ExoscaleOption { + return func(p *ExoscaleProvider) { + p.OnApplyChanges = func(changes *plan.Changes) { + for _, v := range changes.Create { + log.Infof("CREATE: %v", v) + } + for _, v := range changes.UpdateOld { + log.Infof("UPDATE (old): %v", v) + } + for _, v := range changes.UpdateNew { + log.Infof("UPDATE (new): %v", v) + } + for _, v := range changes.Delete { + log.Infof("DELETE: %v", v) + } + } + } +} + +type zoneFilter struct { + domain string +} + +// 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{} + for zoneID, zoneName := range zones { + if strings.HasSuffix(zoneName, f.domain) { + result[zoneID] = zoneName + } + } + return result +} + +// EndpointZoneID determines zoneID for endpoint from map[zoneID]zoneName by taking longest suffix zoneName match in endpoint DNSName +// returns 0 if no match found +func (f *zoneFilter) EndpointZoneID(endpoint *endpoint.Endpoint, zones map[int64]string) (zoneID int64, name string) { + var matchZoneID int64 + var matchZoneName string + for zoneID, zoneName := range zones { + if strings.HasSuffix(endpoint.DNSName, "."+zoneName) && len(zoneName) > len(matchZoneName) { + matchZoneName = zoneName + matchZoneID = zoneID + name = strings.TrimSuffix(endpoint.DNSName, "."+zoneName) + } + } + return matchZoneID, name +} diff --git a/provider/exoscale_test.go b/provider/exoscale_test.go new file mode 100644 index 0000000000..06114e0823 --- /dev/null +++ b/provider/exoscale_test.go @@ -0,0 +1,174 @@ +/* +Copyright 2017 The Kubernetes Authors. + +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 provider + +import ( + "strings" + "testing" + + "github.com/exoscale/egoscale" + "github.com/kubernetes-incubator/external-dns/endpoint" + "github.com/kubernetes-incubator/external-dns/plan" + "github.com/stretchr/testify/assert" +) + +type createRecordExoscale struct { + name string + rec egoscale.DNSRecord +} + +type deleteRecordExoscale struct { + name string + recordID int64 +} + +var createExoscale []createRecordExoscale +var deleteExoscale []deleteRecordExoscale + +type ExoscaleClientStub struct { +} + +func NewExoscaleClientStub() EgoscaleClientI { + ep := &ExoscaleClientStub{} + return ep +} + +func (ep *ExoscaleClientStub) DeleteRecord(name string, recordID int64) error { + deleteExoscale = append(deleteExoscale, deleteRecordExoscale{name: name, recordID: recordID}) + return nil +} +func (ep *ExoscaleClientStub) GetRecords(name string) ([]egoscale.DNSRecord, error) { + init := []egoscale.DNSRecord{ + {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"}, + } + + 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) + } + } + + return rec, nil +} +func (ep *ExoscaleClientStub) CreateRecord(name string, rec egoscale.DNSRecord) (*egoscale.DNSRecord, error) { + createExoscale = append(createExoscale, createRecordExoscale{name: name, rec: rec}) + return nil, nil +} +func (ep *ExoscaleClientStub) GetDomains() ([]egoscale.DNSDomain, error) { + dom := []egoscale.DNSDomain{ + {ID: 1, Name: "foo.com"}, + {ID: 2, Name: "bar.com"}, + } + return dom, nil +} + +func contains(arr []*endpoint.Endpoint, name string) bool { + for _, a := range arr { + if a.DNSName == name { + return true + } + } + return false +} + +func TestExoscaleGetRecords(t *testing.T) { + provider := NewExoscaleProviderWithClient("", "", "", NewExoscaleClientStub()) + + if recs, err := provider.Records(); err == nil { + assert.Equal(t, 3, len(recs)) + assert.True(t, contains(recs, "v1.foo.com")) + assert.True(t, contains(recs, "v2.bar.com")) + assert.True(t, contains(recs, "v2.foo.com")) + assert.False(t, contains(recs, "v3.bar.com")) + assert.False(t, contains(recs, "v1.foobar.com")) + } else { + assert.Error(t, err) + } +} + +func TestExoscaleApplyChanges(t *testing.T) { + provider := NewExoscaleProviderWithClient("", "", "", NewExoscaleClientStub()) + + plan := &plan.Changes{ + Create: []*endpoint.Endpoint{ + { + DNSName: "v1.foo.com", + RecordType: "A", + Targets: []string{""}, + }, + { + DNSName: "v1.foobar.com", + RecordType: "TXT", + Targets: []string{""}, + }, + }, + Delete: []*endpoint.Endpoint{ + { + DNSName: "v1.foo.com", + RecordType: "A", + Targets: []string{""}, + }, + { + DNSName: "v1.foobar.com", + RecordType: "TXT", + Targets: []string{""}, + }, + }, + UpdateOld: []*endpoint.Endpoint{ + { + DNSName: "v1.foo.com", + RecordType: "A", + Targets: []string{""}, + }, + { + DNSName: "v1.foobar.com", + RecordType: "TXT", + Targets: []string{""}, + }, + }, + UpdateNew: []*endpoint.Endpoint{ + { + DNSName: "v1.foo.com", + RecordType: "A", + Targets: []string{""}, + }, + { + DNSName: "v1.foobar.com", + RecordType: "TXT", + Targets: []string{""}, + }, + }, + } + createExoscale = make([]createRecordExoscale, 0) + deleteExoscale = make([]deleteRecordExoscale, 0) + + provider.ApplyChanges(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, 1, len(deleteExoscale)) + assert.Equal(t, "foo.com", deleteExoscale[0].name) + assert.Equal(t, int64(1), deleteExoscale[0].recordID) +} From a487d3878fabe052d08b28d4634ffc324dfc9fcf Mon Sep 17 00:00:00 2001 From: Yoan Blanc Date: Wed, 4 Jul 2018 08:08:41 +0200 Subject: [PATCH 02/13] exoscale: rename exo into exoscale Signed-off-by: Yoan Blanc --- Gopkg.lock | 14 +++++++++++++- Gopkg.toml | 4 ++++ README.md | 1 + main.go | 2 +- pkg/apis/externaldns/types.go | 12 ++++++------ provider/exoscale.go | 10 +++++----- 6 files changed, 30 insertions(+), 13 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 5bec243174..76304ae1ac 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -189,6 +189,12 @@ ] revision = "09691a3b6378b740595c1002f40c34dd5f218a22" +[[projects]] + name = "github.com/exoscale/egoscale" + packages = ["."] + revision = "631ee6ea16ccb48a0c98054fdbf0f6e94d8f4a8c" + version = "v0.9.31" + [[projects]] branch = "master" name = "github.com/ffledgling/pdns-go" @@ -287,6 +293,12 @@ packages = ["."] revision = "e2811d86bed7bb487eeb0806337b6f9e9d93d5e7" +[[projects]] + branch = "master" + name = "github.com/jinzhu/copier" + packages = ["."] + revision = "7e38e58719c33e0d44d585c4ab477a30f8cb82dd" + [[projects]] name = "github.com/jmespath/go-jmespath" packages = ["."] @@ -666,6 +678,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "8d8869be9b64013c9670a0ba7f6a6eeaf31941fcfbdfc13f0fa57626e767c517" + inputs-digest = "ae5cbe56f98ce3856d7794059b6ca81993a6ad1b7ed4c2af3a9d6b4d33f81a6c" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 106171ae0d..a10f445b4f 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -67,3 +67,7 @@ ignored = ["github.com/kubernetes/repo-infra/kazel"] [[constraint]] name = "github.com/nesv/go-dynect" version = "0.6.0" + +[[constraint]] + name = "github.com/exoscale/egoscale" + version = "~0.9.31" diff --git a/README.md b/README.md index ac810f12a1..304811942e 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ ExternalDNS' current release is `v0.5`. This version allows you to keep selected * [OpenStack Designate](https://docs.openstack.org/designate/latest/) * [PowerDNS](https://www.powerdns.com/) * [CoreDNS](https://coredns.io/) +* [Exoscale](https://www.exoscale.com/dns/) From this release, ExternalDNS can become aware of the records it is managing (enabled via `--registry=txt`), therefore ExternalDNS can safely manage non-empty hosted zones. We strongly encourage you to use `v0.5` (or greater) with `--registry=txt` enabled and `--txt-owner-id` set to a unique value that doesn't change for the lifetime of your cluster. You might also want to run ExternalDNS in a dry run mode (`--dry-run` flag) to see the changes to be submitted to your DNS Provider API. diff --git a/main.go b/main.go index b3a691f3a2..4db0532bc2 100644 --- a/main.go +++ b/main.go @@ -143,7 +143,7 @@ func main() { case "coredns", "skydns": p, err = provider.NewCoreDNSProvider(domainFilter, cfg.DryRun) case "exoscale": - p, err = provider.NewExoscaleProvider(cfg.ExoEndpoint, cfg.ExoAPIKey, cfg.ExoAPISecret, provider.ExoWithDomain(domainFilter), provider.ExoWithLogging()), nil + p, err = provider.NewExoscaleProvider(cfg.ExoscaleEndpoint, cfg.ExoscaleAPIKey, cfg.ExoscaleAPISecret, provider.ExoscaleWithDomain(domainFilter), provider.ExoscaleWithLogging()), nil case "inmemory": p, err = provider.NewInMemoryProvider(provider.InMemoryInitZones(cfg.InMemoryZones), provider.InMemoryWithDomain(domainFilter), provider.InMemoryWithLogging()), nil case "designate": diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index bb6bb1472a..1b7ef0e0aa 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -79,9 +79,9 @@ type Config struct { MetricsAddress string LogLevel string TXTCacheInterval time.Duration - ExoEndpoint string - ExoAPIKey string - ExoAPISecret string + ExoscaleEndpoint string + ExoscaleAPIKey string + ExoscaleAPISecret string } var defaultConfig = &Config{ @@ -197,9 +197,9 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("pdns-server", "When using the PowerDNS/PDNS provider, specify the URL to the pdns server (required when --provider=pdns)").Default(defaultConfig.PDNSServer).StringVar(&cfg.PDNSServer) app.Flag("pdns-api-key", "When using the PowerDNS/PDNS provider, specify the URL to the pdns server (required when --provider=pdns)").Default(defaultConfig.PDNSAPIKey).StringVar(&cfg.PDNSAPIKey) - app.Flag("exo-endpoint", "Provide the endpoint for the Exoscale provider").Default("").StringVar(&cfg.ExoEndpoint) - app.Flag("exo-apikey", "Provide your API Key for the Exoscale provider").Default("").StringVar(&cfg.ExoAPIKey) - app.Flag("exo-apisecret", "Provide your API Secret for the Exoscale provider").Default("").StringVar(&cfg.ExoAPISecret) + app.Flag("exoscale-endpoint", "Provide the endpoint for the Exoscale provider").Default("https://api.exoscale.ch/dns").StringVar(&cfg.ExoscaleEndpoint) + app.Flag("exoscale-apikey", "Provide your API Key for the Exoscale provider").Default("").StringVar(&cfg.ExoscaleAPIKey) + app.Flag("exoscale-apisecret", "Provide your API Secret for the Exoscale provider").Default("").StringVar(&cfg.ExoscaleAPISecret) // Flags related to policies app.Flag("policy", "Modify how DNS records are sychronized between sources and providers (default: sync, options: sync, upsert-only)").Default(defaultConfig.Policy).EnumVar(&cfg.Policy, "sync", "upsert-only") diff --git a/provider/exoscale.go b/provider/exoscale.go index 70fe6102e8..f7412d9259 100644 --- a/provider/exoscale.go +++ b/provider/exoscale.go @@ -129,7 +129,7 @@ func (ep *ExoscaleProvider) Records() ([]*endpoint.Endpoint, error) { } for _, r := range record { switch r.RecordType { - case "A", "CNAME", "TXT": + case "A", "AAAA", "CNAME", "TXT": break default: continue @@ -143,15 +143,15 @@ func (ep *ExoscaleProvider) Records() ([]*endpoint.Endpoint, error) { return endpoints, nil } -// ExoWithDomain modifies the domain on which dns zones are filtered -func ExoWithDomain(domainFilter DomainFilter) ExoscaleOption { +// ExoscaleWithDomain modifies the domain on which dns zones are filtered +func ExoscaleWithDomain(domainFilter DomainFilter) ExoscaleOption { return func(p *ExoscaleProvider) { p.domain = domainFilter } } -// ExoWithLogging injects logging when ApplyChanges is called -func ExoWithLogging() ExoscaleOption { +// ExoscaleWithLogging injects logging when ApplyChanges is called +func ExoscaleWithLogging() ExoscaleOption { return func(p *ExoscaleProvider) { p.OnApplyChanges = func(changes *plan.Changes) { for _, v := range changes.Create { From 07e7103afe3676c921697f4eb0c6c9376341b836 Mon Sep 17 00:00:00 2001 From: Christopher Schmidt Date: Fri, 6 Jul 2018 07:17:07 +0200 Subject: [PATCH 03/13] implemented dryRun --- main.go | 2 +- provider/exoscale.go | 15 ++++++++++++--- provider/exoscale_test.go | 4 ++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/main.go b/main.go index 4db0532bc2..f1cde902bb 100644 --- a/main.go +++ b/main.go @@ -143,7 +143,7 @@ func main() { case "coredns", "skydns": p, err = provider.NewCoreDNSProvider(domainFilter, cfg.DryRun) case "exoscale": - p, err = provider.NewExoscaleProvider(cfg.ExoscaleEndpoint, cfg.ExoscaleAPIKey, cfg.ExoscaleAPISecret, provider.ExoscaleWithDomain(domainFilter), provider.ExoscaleWithLogging()), nil + p, err = provider.NewExoscaleProvider(cfg.ExoscaleEndpoint, cfg.ExoscaleAPIKey, cfg.ExoscaleAPISecret, cfg.DryRun, provider.ExoscaleWithDomain(domainFilter), provider.ExoscaleWithLogging()), nil case "inmemory": p, err = provider.NewInMemoryProvider(provider.InMemoryInitZones(cfg.InMemoryZones), provider.InMemoryWithDomain(domainFilter), provider.InMemoryWithLogging()), nil case "designate": diff --git a/provider/exoscale.go b/provider/exoscale.go index f7412d9259..b68c35ea2c 100644 --- a/provider/exoscale.go +++ b/provider/exoscale.go @@ -23,24 +23,26 @@ type ExoscaleProvider struct { client EgoscaleClientI filter *zoneFilter OnApplyChanges func(changes *plan.Changes) + dryRun bool } // ExoscaleOption for Provider options type ExoscaleOption func(*ExoscaleProvider) // NewExoscaleProvider returns ExoscaleProvider DNS provider interface implementation -func NewExoscaleProvider(endpoint, apiKey, apiSecret string, opts ...ExoscaleOption) *ExoscaleProvider { +func NewExoscaleProvider(endpoint, apiKey, apiSecret string, dryRun bool, opts ...ExoscaleOption) *ExoscaleProvider { client := egoscale.NewClient(endpoint, apiKey, apiSecret) - return NewExoscaleProviderWithClient(endpoint, apiKey, apiSecret, client, opts...) + return NewExoscaleProviderWithClient(endpoint, apiKey, apiSecret, client, dryRun, opts...) } // NewExoscaleProviderWithClient returns ExoscaleProvider DNS provider interface implementation (Client provided) -func NewExoscaleProviderWithClient(endpoint, apiKey, apiSecret string, client EgoscaleClientI, opts ...ExoscaleOption) *ExoscaleProvider { +func NewExoscaleProviderWithClient(endpoint, apiKey, apiSecret string, client EgoscaleClientI, dryRun bool, opts ...ExoscaleOption) *ExoscaleProvider { ep := &ExoscaleProvider{ filter: &zoneFilter{}, OnApplyChanges: func(changes *plan.Changes) {}, domain: NewDomainFilter([]string{""}), client: client, + dryRun: dryRun, } for _, opt := range opts { opt(ep) @@ -65,6 +67,13 @@ func (ep *ExoscaleProvider) getZones() (map[int64]string, error) { func (ep *ExoscaleProvider) ApplyChanges(changes *plan.Changes) error { ep.OnApplyChanges(changes) + if ep.dryRun { + log.Infof("Will NOT delete these records: %+v", changes.Delete) + log.Infof("Will NOT create these records: %+v", changes.Create) + log.Infof("Will NOT update these records: %+v", merge(changes.UpdateOld, changes.UpdateNew)) + return nil + } + zones, err := ep.getZones() if err != nil { return err diff --git a/provider/exoscale_test.go b/provider/exoscale_test.go index 06114e0823..3ca3b96db1 100644 --- a/provider/exoscale_test.go +++ b/provider/exoscale_test.go @@ -92,7 +92,7 @@ func contains(arr []*endpoint.Endpoint, name string) bool { } func TestExoscaleGetRecords(t *testing.T) { - provider := NewExoscaleProviderWithClient("", "", "", NewExoscaleClientStub()) + provider := NewExoscaleProviderWithClient("", "", "", NewExoscaleClientStub(), false) if recs, err := provider.Records(); err == nil { assert.Equal(t, 3, len(recs)) @@ -107,7 +107,7 @@ func TestExoscaleGetRecords(t *testing.T) { } func TestExoscaleApplyChanges(t *testing.T) { - provider := NewExoscaleProviderWithClient("", "", "", NewExoscaleClientStub()) + provider := NewExoscaleProviderWithClient("", "", "", NewExoscaleClientStub(), false) plan := &plan.Changes{ Create: []*endpoint.Endpoint{ From 635427f52822a575d48f40c3ee4762766c9e2a71 Mon Sep 17 00:00:00 2001 From: Christopher Schmidt Date: Fri, 6 Jul 2018 07:35:08 +0200 Subject: [PATCH 04/13] did not match domains --- provider/exoscale.go | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/provider/exoscale.go b/provider/exoscale.go index b68c35ea2c..324c73c356 100644 --- a/provider/exoscale.go +++ b/provider/exoscale.go @@ -102,18 +102,20 @@ func (ep *ExoscaleProvider) ApplyChanges(changes *plan.Changes) error { log.Debugf("UPDATE-OLD (ignored) for epoint: %+v", epoint) } for _, epoint := range changes.Delete { - if zoneID, name := ep.filter.EndpointZoneID(epoint, zones); zoneID != 0 { - records, err := ep.client.GetRecords(zones[zoneID]) - if err != nil { - return err - } + if ep.domain.Match(epoint.DNSName) { + if zoneID, name := ep.filter.EndpointZoneID(epoint, zones); zoneID != 0 { + records, err := ep.client.GetRecords(zones[zoneID]) + if err != nil { + return err + } - for _, r := range records { - if r.Name == name { - if err := ep.client.DeleteRecord(zones[zoneID], r.ID); err != nil { - return err + for _, r := range records { + if r.Name == name { + if err := ep.client.DeleteRecord(zones[zoneID], r.ID); err != nil { + return err + } + break } - break } } } From 14cefa07170cde38c3f58a6984efcd58d04b40e0 Mon Sep 17 00:00:00 2001 From: Christopher Schmidt Date: Fri, 6 Jul 2018 07:49:48 +0200 Subject: [PATCH 05/13] added UpdateNew --- provider/exoscale.go | 29 ++++++++++++++++++++++++++++- provider/exoscale_test.go | 14 ++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/provider/exoscale.go b/provider/exoscale.go index 324c73c356..49c6cad68e 100644 --- a/provider/exoscale.go +++ b/provider/exoscale.go @@ -15,6 +15,7 @@ type EgoscaleClientI interface { GetDomains() ([]egoscale.DNSDomain, error) CreateRecord(string, egoscale.DNSRecord) (*egoscale.DNSRecord, error) DeleteRecord(string, int64) error + UpdateRecord(string, egoscale.UpdateDNSRecord) (*egoscale.DNSRecord, error) } // ExoscaleProvider initialized as dns provider with no records @@ -96,9 +97,35 @@ func (ep *ExoscaleProvider) ApplyChanges(changes *plan.Changes) error { } } for _, epoint := range changes.UpdateNew { - log.Debugf("UPDATE-NEW (ignored) for epoint: %+v", epoint) + if ep.domain.Match(epoint.DNSName) { + if zoneID, name := ep.filter.EndpointZoneID(epoint, zones); zoneID != 0 { + records, err := ep.client.GetRecords(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(zones[zoneID], rec); err != nil { + return err + } + break + } + } + } + } } for _, epoint := range changes.UpdateOld { + // Since Exoscale "Patches", we ignore UpdateOld + // We leave this logging here for information log.Debugf("UPDATE-OLD (ignored) for epoint: %+v", epoint) } for _, epoint := range changes.Delete { diff --git a/provider/exoscale_test.go b/provider/exoscale_test.go index 3ca3b96db1..7e151ddc1e 100644 --- a/provider/exoscale_test.go +++ b/provider/exoscale_test.go @@ -36,8 +36,14 @@ type deleteRecordExoscale struct { recordID int64 } +type updateRecordExoscale struct { + name string + updateDNSRecord egoscale.UpdateDNSRecord +} + var createExoscale []createRecordExoscale var deleteExoscale []deleteRecordExoscale +var updateExoscale []updateRecordExoscale type ExoscaleClientStub struct { } @@ -70,6 +76,10 @@ func (ep *ExoscaleClientStub) GetRecords(name string) ([]egoscale.DNSRecord, err return rec, nil } +func (ep *ExoscaleClientStub) UpdateRecord(name string, rec egoscale.UpdateDNSRecord) (*egoscale.DNSRecord, error) { + updateExoscale = append(updateExoscale, updateRecordExoscale{name: name, updateDNSRecord: rec}) + return nil, nil +} func (ep *ExoscaleClientStub) CreateRecord(name string, rec egoscale.DNSRecord) (*egoscale.DNSRecord, error) { createExoscale = append(createExoscale, createRecordExoscale{name: name, rec: rec}) return nil, nil @@ -171,4 +181,8 @@ func TestExoscaleApplyChanges(t *testing.T) { 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, 1, len(updateExoscale)) + assert.Equal(t, "foo.com", updateExoscale[0].name) + assert.Equal(t, int64(1), updateExoscale[0].updateDNSRecord.ID) } From 56e4fe82db27a128b45d926a7922d6cce41c458c Mon Sep 17 00:00:00 2001 From: Christopher Schmidt Date: Tue, 10 Jul 2018 15:25:48 +0200 Subject: [PATCH 06/13] added an Exoscale tutorial --- README.md | 1 + docs/tutorials/exoscale.md | 155 +++++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 docs/tutorials/exoscale.md diff --git a/README.md b/README.md index 304811942e..d4f8f7e5de 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,7 @@ The following tutorials are provided: * Google Container Engine * [Using Google's Default Ingress Controller](docs/tutorials/gke.md) * [Using the Nginx Ingress Controller](docs/tutorials/nginx-ingress.md) +* [Exoscale](docs/tutorials/exoscale.md) ## Running Locally diff --git a/docs/tutorials/exoscale.md b/docs/tutorials/exoscale.md new file mode 100644 index 0000000000..bab9c9e5a0 --- /dev/null +++ b/docs/tutorials/exoscale.md @@ -0,0 +1,155 @@ +# Setting up ExternalDNS for Exoscale + +## Prerequisites + +Exoscale provider support was added via [this PR](https://github.com/kubernetes-incubator/external-dns/pull/625), thus you need to use external-dns with this PR merged. + +The Exoscale provider expects that your Exoscale zones, you wish to add records to, already exists +and are configured correctly. It does not add, remove or configure new zones in anyway. + +To do this pease refer to the [Exoscale DNS documentation](https://community.exoscale.com/documentation/dns/). + +Additionally you will have to provide the Exoscale...: + +* API Key +* API Secret +* API Endpoint +* Elastic IP address, to access the workers + +## Deployment + +Deploying external DNS for Exoscale is actually nearly identical to deploying +it for other providers. This is what a sample `deployment.yaml` looks like: + +```yaml +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: external-dns +spec: + strategy: + type: Recreate + template: + metadata: + labels: + app: external-dns + spec: + # Only use if you're also using RBAC + # serviceAccountName: external-dns + containers: + - name: external-dns + image: registry.opensource.zalan.do/teapot/external-dns + args: + - --source=ingress # or service or both + - --provider=exoscale + - --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 }} +``` + +## RBAC + +If your cluster is RBAC enabled, you also need to setup the following, before you can run external-dns: + +```yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: external-dns + namespace: default + +--- + +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: external-dns +rules: +- apiGroups: [""] + resources: ["services"] + verbs: ["get","watch","list"] +- apiGroups: [""] + resources: ["pods"] + verbs: ["get","watch","list"] +- apiGroups: ["extensions"] + resources: ["ingresses"] + verbs: ["get","watch","list"] + +--- + +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: external-dns-viewer +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: external-dns +subjects: +- kind: ServiceAccount + name: external-dns + namespace: default +``` + +## Testing and Verification + +**Important!**: Remember to change `example.com` with your own domain throughout the following text. + +Spin up a simple nginx HTTP server with the following spec (`kubectl apply -f`): + +```yaml +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: nginx + annotations: + kubernetes.io/ingress.class: nginx + external-dns.alpha.kubernetes.io/target: {{ Elastic-IP-address }} +spec: + rules: + - host: via-ingress.example.com + http: + paths: + - backend: + serviceName: nginx + servicePort: 80 + +--- + +apiVersion: v1 +kind: Service +metadata: + name: nginx +spec: + ports: + - port: 80 + targetPort: 80 + selector: + app: nginx + +--- + +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: nginx +spec: + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: nginx + name: nginx + ports: + - containerPort: 80 +``` + +**Important!**: Don't run dig, nslookup or similar immediately (until you've +confirmed the record exists). You'll get hit by [negative DNS caching](https://tools.ietf.org/html/rfc2308), which is hard to flush. + +Wait about 30s-1m (interval for external-dns to kick in), then check Exoscales [portal](https://portal.exoscale.com/dns/example.com)... via-ingress.example.com should appear as a A and TXT record with your Elastic-IP-address. \ No newline at end of file From df03cb81075bbe7a074c4ad6d6a76a3775e9622d Mon Sep 17 00:00:00 2001 From: Christopher Schmidt Date: Wed, 11 Jul 2018 07:09:34 +0200 Subject: [PATCH 07/13] added version tag --- docs/tutorials/exoscale.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/tutorials/exoscale.md b/docs/tutorials/exoscale.md index bab9c9e5a0..c4cbd58832 100644 --- a/docs/tutorials/exoscale.md +++ b/docs/tutorials/exoscale.md @@ -2,7 +2,7 @@ ## Prerequisites -Exoscale provider support was added via [this PR](https://github.com/kubernetes-incubator/external-dns/pull/625), thus you need to use external-dns with this PR merged. +Exoscale provider support was added via [this PR](https://github.com/kubernetes-incubator/external-dns/pull/625), thus you need to use external-dns v0.5.5. The Exoscale provider expects that your Exoscale zones, you wish to add records to, already exists and are configured correctly. It does not add, remove or configure new zones in anyway. @@ -38,7 +38,7 @@ spec: # serviceAccountName: external-dns containers: - name: external-dns - image: registry.opensource.zalan.do/teapot/external-dns + image: registry.opensource.zalan.do/teapot/external-dns:v0.5.5 args: - --source=ingress # or service or both - --provider=exoscale From 6ed7b8d3ba6c9c3729c461a9d02701019e3caa12 Mon Sep 17 00:00:00 2001 From: Yoan Blanc Date: Thu, 12 Jul 2018 13:30:08 +0200 Subject: [PATCH 08/13] exoscale: fix boilerplate header Signed-off-by: Yoan Blanc --- Gopkg.lock | 2 +- provider/exoscale.go | 23 +++++++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index c674453892..6ba5fc6e50 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -691,6 +691,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "ae5cbe56f98ce3856d7794059b6ca81993a6ad1b7ed4c2af3a9d6b4d33f81a6c" + inputs-digest = "d704eb6432ef9b41338900e647421a195366f87134918f9feb023fc377064f57" solver-name = "gps-cdcl" solver-version = 1 diff --git a/provider/exoscale.go b/provider/exoscale.go index 49c6cad68e..624cdb9aa1 100644 --- a/provider/exoscale.go +++ b/provider/exoscale.go @@ -1,3 +1,19 @@ +/* +Copyright 2017 The Kubernetes Authors. + +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 provider import ( @@ -165,12 +181,15 @@ func (ep *ExoscaleProvider) Records() ([]*endpoint.Endpoint, error) { if err != nil { return nil, err } + loop: for _, r := range record { switch r.RecordType { - case "A", "AAAA", "CNAME", "TXT": + case egoscale.A.String(): + case egoscale.CNAME.String(): + case egoscale.TXT.String(): break default: - continue + break loop } ep := endpoint.NewEndpointWithTTL(r.Name+"."+d.Name, r.RecordType, endpoint.TTL(r.TTL), r.Content) endpoints = append(endpoints, ep) From a78b20916e000d210de4a95818e2d18f268a5df7 Mon Sep 17 00:00:00 2001 From: Christopher Schmidt Date: Thu, 12 Jul 2018 19:26:21 +0200 Subject: [PATCH 09/13] using defaultConfig n ow --- pkg/apis/externaldns/types.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index 1355780d16..dc8cdd7983 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -137,6 +137,9 @@ var defaultConfig = &Config{ LogFormat: "text", MetricsAddress: ":7979", LogLevel: logrus.InfoLevel.String(), + ExoscaleEndpoint: "https://api.exoscale.ch/dns", + ExoscaleAPIKey: "", + ExoscaleAPISecret: "", } // NewConfig returns new Config object @@ -223,9 +226,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("https://api.exoscale.ch/dns").StringVar(&cfg.ExoscaleEndpoint) - app.Flag("exoscale-apikey", "Provide your API Key for the Exoscale provider").Default("").StringVar(&cfg.ExoscaleAPIKey) - app.Flag("exoscale-apisecret", "Provide your API Secret for the Exoscale provider").Default("").StringVar(&cfg.ExoscaleAPISecret) + app.Flag("exoscale-endpoint", "Provide the endpoint for the Exoscale provider").Default(defaultConfig.ExoscaleEndpoint).StringVar(&cfg.ExoscaleEndpoint) + 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) // Flags related to policies app.Flag("policy", "Modify how DNS records are sychronized between sources and providers (default: sync, options: sync, upsert-only)").Default(defaultConfig.Policy).EnumVar(&cfg.Policy, "sync", "upsert-only") From 42ff664af643c06ac1e57f04b588b3a0aed30682 Mon Sep 17 00:00:00 2001 From: Christopher Schmidt Date: Thu, 12 Jul 2018 19:26:36 +0200 Subject: [PATCH 10/13] fix tests --- pkg/apis/externaldns/types_test.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pkg/apis/externaldns/types_test.go b/pkg/apis/externaldns/types_test.go index a5dfa2fbcd..1edacff18b 100644 --- a/pkg/apis/externaldns/types_test.go +++ b/pkg/apis/externaldns/types_test.go @@ -68,6 +68,9 @@ var ( MetricsAddress: ":7979", LogLevel: logrus.InfoLevel.String(), ConnectorSourceServer: "localhost:8080", + ExoscaleEndpoint: "https://api.exoscale.ch/dns", + ExoscaleAPIKey: "", + ExoscaleAPISecret: "", } overriddenConfig = &Config{ @@ -114,6 +117,9 @@ var ( MetricsAddress: "127.0.0.1:9099", LogLevel: logrus.DebugLevel.String(), ConnectorSourceServer: "localhost:8081", + ExoscaleEndpoint: "https://api.foo.ch/dns", + ExoscaleAPIKey: "1", + ExoscaleAPISecret: "2", } ) @@ -184,6 +190,9 @@ 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-apikey=1", + "--exoscale-apisecret=2", }, envVars: map[string]string{}, expected: overriddenConfig, @@ -235,6 +244,9 @@ 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_APIKEY": "1", + "EXTERNAL_DNS_EXOSCALE_APISECRET": "2", }, expected: overriddenConfig, }, From 5cf6ce905c2ba708900ca2d866bb4ba729bc9589 Mon Sep 17 00:00:00 2001 From: Christopher Schmidt Date: Fri, 13 Jul 2018 06:43:16 +0200 Subject: [PATCH 11/13] better test --- provider/exoscale_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/provider/exoscale_test.go b/provider/exoscale_test.go index 7e151ddc1e..4c0c5bcbd7 100644 --- a/provider/exoscale_test.go +++ b/provider/exoscale_test.go @@ -59,6 +59,7 @@ func (ep *ExoscaleClientStub) DeleteRecord(name string, recordID int64) error { } func (ep *ExoscaleClientStub) GetRecords(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"}, From 11df25dc8680ce49740b4fd0b8deb6784ee39e45 Mon Sep 17 00:00:00 2001 From: Christopher Schmidt Date: Fri, 13 Jul 2018 06:43:29 +0200 Subject: [PATCH 12/13] revert commit --- provider/exoscale.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/provider/exoscale.go b/provider/exoscale.go index 624cdb9aa1..f4e7866ca2 100644 --- a/provider/exoscale.go +++ b/provider/exoscale.go @@ -181,15 +181,12 @@ func (ep *ExoscaleProvider) Records() ([]*endpoint.Endpoint, error) { if err != nil { return nil, err } - loop: for _, r := range record { switch r.RecordType { - case egoscale.A.String(): - case egoscale.CNAME.String(): - case egoscale.TXT.String(): + case "A", "CNAME", "TXT": break default: - break loop + continue } ep := endpoint.NewEndpointWithTTL(r.Name+"."+d.Name, r.RecordType, endpoint.TTL(r.TTL), r.Content) endpoints = append(endpoints, ep) From 0fd3a7afb1aa0318564faff9b8eb9fd3b0f21367 Mon Sep 17 00:00:00 2001 From: Christopher Schmidt Date: Fri, 13 Jul 2018 12:52:16 +0200 Subject: [PATCH 13/13] added list nodes --- docs/tutorials/exoscale.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/tutorials/exoscale.md b/docs/tutorials/exoscale.md index c4cbd58832..c05c7c639e 100644 --- a/docs/tutorials/exoscale.md +++ b/docs/tutorials/exoscale.md @@ -77,6 +77,9 @@ rules: - apiGroups: ["extensions"] resources: ["ingresses"] verbs: ["get","watch","list"] +- apiGroups: [""] + resources: ["nodes"] + verbs: ["list"] ---