From 77d7dea5563a0e9fde2223fac4d3798fd55f8ed8 Mon Sep 17 00:00:00 2001 From: Simone Carletti Date: Mon, 27 Apr 2020 18:33:36 +0200 Subject: [PATCH 01/13] Update TTL docs to confirm DNSimple support It was added in #477 --- docs/ttl.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/ttl.md b/docs/ttl.md index 8e5df4e0f..00af8767c 100644 --- a/docs/ttl.md +++ b/docs/ttl.md @@ -39,6 +39,7 @@ Providers - [ ] Azure - [ ] Cloudflare - [x] DigitalOcean +- [x] DNSimple - [x] Google - [ ] InMemory - [x] Linode @@ -60,6 +61,9 @@ This value is a constant in the provider code. The DigitalOcean Provider overrides the value to 300s when the TTL is 0. This value is a constant in the provider code. +### DNSimple Provider +The DNSimple Provider default TTL is used when the TTL is 0. The default TTL is 3600s. + ### Google Provider Previously with the Google Provider, TTL's were hard-coded to 300s. For safety, the Google Provider overrides the value to 300s when the TTL is 0. From a0b6b2724ed76405ba3c0af80c24669a30e37c33 Mon Sep 17 00:00:00 2001 From: David Dymko Date: Thu, 18 Jun 2020 11:04:09 -0400 Subject: [PATCH 02/13] bump govultr + changes to support version --- go.mod | 3 +-- go.sum | 10 ++++------ provider/vultr/vultr.go | 13 ++++++++++++- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 59025b32c..c6718bd9a 100644 --- a/go.mod +++ b/go.mod @@ -49,7 +49,7 @@ require ( github.com/stretchr/testify v1.5.1 github.com/transip/gotransip v5.8.2+incompatible github.com/vinyldns/go-vinyldns v0.0.0-20190611170422-7119fe55ed92 - github.com/vultr/govultr v0.3.2 + github.com/vultr/govultr v0.4.2 go.etcd.io/etcd v0.5.0-alpha.5.0.20200401174654-e694b7bb0875 golang.org/x/net v0.0.0-20200202094626-16171245cfb2 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 @@ -61,7 +61,6 @@ require ( k8s.io/api v0.17.5 k8s.io/apimachinery v0.17.5 k8s.io/client-go v0.17.5 - k8s.io/klog v1.0.0 ) replace ( diff --git a/go.sum b/go.sum index a4af0ab59..713553f4c 100644 --- a/go.sum +++ b/go.sum @@ -293,8 +293,8 @@ github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVo github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-retryablehttp v0.6.4 h1:BbgctKO892xEyOXnGiaAwIoSq1QZ/SS4AhjoAh9DnfY= -github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM= +github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= @@ -310,8 +310,6 @@ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NH github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/infobloxopen/infoblox-go-client v0.0.0-20180606155407-61dc5f9b0a65 h1:FP5rOFP4ifbtFIjFHJmwhFrsbDyONILK/FNntl/Pou8= github.com/infobloxopen/infoblox-go-client v0.0.0-20180606155407-61dc5f9b0a65/go.mod h1:BXiw7S2b9qJoM8MS40vfgCNB2NLHGusk1DtO16BD9zI= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= @@ -527,8 +525,8 @@ github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijb github.com/urfave/cli v1.21.0/go.mod h1:lxDj6qX9Q6lWQxIrbrT0nwecwUtRnhVZAJjJZrVUZZQ= github.com/vinyldns/go-vinyldns v0.0.0-20190611170422-7119fe55ed92 h1:Q76MzqJu++vAfhj0mVf7t0F4xHUbg+V/d/Uk5PBQjRU= github.com/vinyldns/go-vinyldns v0.0.0-20190611170422-7119fe55ed92/go.mod h1:AZuEfReFWdvtU0LatbLpo70t3lqdLvph2D5mqFP0bkA= -github.com/vultr/govultr v0.3.2 h1:1tV/88jkm+4Y345qAXBe3peNbnmvCY/VAIZApklbKkI= -github.com/vultr/govultr v0.3.2/go.mod h1:81RwK1wAmb08alkFDJiZmu9gdv+IO+UamzaF0+PIieE= +github.com/vultr/govultr v0.4.2 h1:9i8xKZ+xp6vwZ9raqHoBLzhB4wCnMj7nOQTj5YIRLWY= +github.com/vultr/govultr v0.4.2/go.mod h1:TUuUizMOFc7z+PNMssb6iGjKjQfpw5arIaOLfocVudQ= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= diff --git a/provider/vultr/vultr.go b/provider/vultr/vultr.go index 5de422421..dcaee57c5 100644 --- a/provider/vultr/vultr.go +++ b/provider/vultr/vultr.go @@ -160,13 +160,15 @@ func (p *VultrProvider) submitChanges(ctx context.Context, changes []*VultrChang "record": change.ResourceRecordSet.Name, "type": change.ResourceRecordSet.Type, "ttl": change.ResourceRecordSet.TTL, + "priority": change.ResourceRecordSet.Priority, "action": change.Action, "zone": zoneName, }).Info("Changing record.") switch change.Action { case vultrCreate: - err = p.client.DNSRecord.Create(ctx, zoneName, change.ResourceRecordSet.Type, change.ResourceRecordSet.Name, change.ResourceRecordSet.Data, change.ResourceRecordSet.TTL, change.ResourceRecordSet.Priority) + priority := getPriority(change.ResourceRecordSet.Priority) + err = p.client.DNSRecord.Create(ctx, zoneName, change.ResourceRecordSet.Type, change.ResourceRecordSet.Name, change.ResourceRecordSet.Data, change.ResourceRecordSet.TTL, priority) if err != nil { return err } @@ -192,6 +194,7 @@ func (p *VultrProvider) submitChanges(ctx context.Context, changes []*VultrChang Name: change.ResourceRecordSet.Name, Data: change.ResourceRecordSet.Data, TTL: change.ResourceRecordSet.TTL, + Priority: change.ResourceRecordSet.Priority, } err = p.client.DNSRecord.Update(ctx, zoneName, record) @@ -276,3 +279,11 @@ func (p *VultrProvider) getRecordID(ctx context.Context, zone string, record gov return 0, fmt.Errorf("no record was found") } + +func getPriority(priority *int) int { + p := 0 + if priority != nil{ + p = *priority + } + return p +} \ No newline at end of file From 539284ff93df104c6637354440be5ff5c693df83 Mon Sep 17 00:00:00 2001 From: David Dymko Date: Thu, 18 Jun 2020 11:44:43 -0400 Subject: [PATCH 03/13] uneeded priority declaration --- provider/vultr/vultr.go | 1 - 1 file changed, 1 deletion(-) diff --git a/provider/vultr/vultr.go b/provider/vultr/vultr.go index dcaee57c5..89cf36651 100644 --- a/provider/vultr/vultr.go +++ b/provider/vultr/vultr.go @@ -194,7 +194,6 @@ func (p *VultrProvider) submitChanges(ctx context.Context, changes []*VultrChang Name: change.ResourceRecordSet.Name, Data: change.ResourceRecordSet.Data, TTL: change.ResourceRecordSet.TTL, - Priority: change.ResourceRecordSet.Priority, } err = p.client.DNSRecord.Update(ctx, zoneName, record) From d53d9dc2e572bfdd071300c0734eb015abb4cbd3 Mon Sep 17 00:00:00 2001 From: Tom Dyas Date: Sun, 17 May 2020 12:46:07 -0700 Subject: [PATCH 04/13] digitalocean: support multiple targets per endpoint --- Dockerfile | 4 +- go.mod | 3 +- go.sum | 19 +- provider/digitalocean/digital_ocean.go | 595 ++++++++++++++------ provider/digitalocean/digital_ocean_test.go | 369 +++++++++++- 5 files changed, 805 insertions(+), 185 deletions(-) diff --git a/Dockerfile b/Dockerfile index 57ddb572e..3330c429a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,8 +20,8 @@ ARG VERSION WORKDIR /sigs.k8s.io/external-dns COPY . . -RUN go mod vendor && \ - make test && \ +RUN go mod vendor +RUN make test && \ make build # final image diff --git a/go.mod b/go.mod index f3a4300ae..6103b4c5e 100644 --- a/go.mod +++ b/go.mod @@ -20,12 +20,13 @@ require ( github.com/cloudflare/cloudflare-go v0.10.1 github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381 github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba - github.com/digitalocean/godo v1.34.0 + github.com/digitalocean/godo v1.36.0 github.com/dnsimple/dnsimple-go v0.60.0 github.com/exoscale/egoscale v0.18.1 github.com/ffledgling/pdns-go v0.0.0-20180219074714-524e7daccd99 github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b // indirect github.com/golang/sync v0.0.0-20180314180146-1d60e4601c6f + github.com/google/go-cmp v0.4.1 github.com/gophercloud/gophercloud v0.1.0 github.com/gorilla/mux v1.7.4 // indirect github.com/infobloxopen/infoblox-go-client v0.0.0-20180606155407-61dc5f9b0a65 diff --git a/go.sum b/go.sum index e8d7aa68d..74451961f 100644 --- a/go.sum +++ b/go.sum @@ -83,7 +83,6 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -91,7 +90,6 @@ github.com/cloudflare/cloudflare-go v0.10.1 h1:d2CL6F9k2O0Ux0w27LgogJ5UOzZRj6a/h github.com/cloudflare/cloudflare-go v0.10.1/go.mod h1:C0Y6eWnTJPMK2ceuOxx2pjh78UUHihcXeTTHb8r7QjU= github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381 h1:rdRS5BT13Iae9ssvcslol66gfOOXjaLYwqerEn/cl9s= github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381/go.mod h1:e5+USP2j8Le2M0Jo3qKPFnNhuo1wueU4nWHCXBOfQ14= -github.com/cncf/udpa/go v0.0.0-20200313221541-5f7e5dd04533 h1:8wZizuKuZVu5COB7EsBYxBQz8nRcXXn5d4Gt91eJLvU= github.com/cncf/udpa/go v0.0.0-20200313221541-5f7e5dd04533/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= @@ -122,8 +120,8 @@ github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba h1:p6poVbjHDkK github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/digitalocean/godo v1.34.0 h1:OXJhLLJS2VTB5SziTyCq8valKVZ0uBHCFQsDW3/HF78= -github.com/digitalocean/godo v1.34.0/go.mod h1:gfLm3JSupWD9V/ibQygXWW3IVz7hranzckH5UimhZsI= +github.com/digitalocean/godo v1.36.0 h1:eRF8wNzHZyU7/wI3De/MQgiVSWdseDaf27bXj2gnOO0= +github.com/digitalocean/godo v1.36.0/go.mod h1:p7dOjjtSBqCTUksqtA5Fd3uaKs9kyTq2xcz76ulEJRU= github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY= @@ -139,9 +137,7 @@ github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:Htrtb github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/envoyproxy/go-control-plane v0.9.0 h1:67WMNTvGrl7V1dWdKCeTwxDr7nio9clKoTlLhwIPnT4= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.5 h1:lRJIqDD8yjV1YyPRqecMdytjDLs2fTXq363aCib5xPU= github.com/envoyproxy/go-control-plane v0.9.5/go.mod h1:OXl5to++W0ctG+EHWTFUjiypVxC/Y4VLc/KFU+al13s= github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= @@ -241,6 +237,8 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/sync v0.0.0-20180314180146-1d60e4601c6f h1:kSqKc8ouCLIBHqdj9a9xxhtxlZhNqbePClixA4HoM44= github.com/golang/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:YCHYtYb9c8Q7XgYVYjmJBPtFPKx5QvOcPxHZWjldabE= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -251,6 +249,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1 h1:/exdXoGamhu5ONeUJH0deniYLWYvQwW66yvlfiiKTu0= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= @@ -626,12 +626,15 @@ golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8ou golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190130055435-99b60b757ec1/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -668,6 +671,8 @@ golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd h1:3x5uuvBgE6oaXJjCOvpCC1IpgJogqQ+PqGGU3ZxAgII= golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20171227012246-e19ae1496984/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/provider/digitalocean/digital_ocean.go b/provider/digitalocean/digital_ocean.go index 30af3eed2..e26f76a27 100644 --- a/provider/digitalocean/digital_ocean.go +++ b/provider/digitalocean/digital_ocean.go @@ -32,13 +32,6 @@ import ( ) const ( - // DigitalOceanCreate is a ChangeAction enum value - DigitalOceanCreate = "CREATE" - // DigitalOceanDelete is a ChangeAction enum value - DigitalOceanDelete = "DELETE" - // DigitalOceanUpdate is a ChangeAction enum value - DigitalOceanUpdate = "UPDATE" - // digitalOceanRecordTTL is the default TTL value digitalOceanRecordTTL = 300 ) @@ -54,10 +47,31 @@ type DigitalOceanProvider struct { DryRun bool } -// DigitalOceanChange differentiates between ChangActions -type DigitalOceanChange struct { - Action string - ResourceRecordSet godo.DomainRecord +type digitalOceanChangeCreate struct { + Domain string + Options *godo.DomainRecordEditRequest +} + +type digitalOceanChangeUpdate struct { + Domain string + DomainRecord godo.DomainRecord + Options *godo.DomainRecordEditRequest +} + +type digitalOceanChangeDelete struct { + Domain string + RecordID int +} + +// DigitalOceanChange contains all changes to apply to DNS +type digitalOceanChanges struct { + Creates []*digitalOceanChangeCreate + Updates []*digitalOceanChangeUpdate + Deletes []*digitalOceanChangeDelete +} + +func (c *digitalOceanChanges) Empty() bool { + return len(c.Creates) == 0 && len(c.Updates) == 0 && len(c.Deletes) == 0 } // NewDigitalOceanProvider initializes a new DigitalOcean DNS based Provider. @@ -71,13 +85,13 @@ func NewDigitalOceanProvider(ctx context.Context, domainFilter endpoint.DomainFi })) client := godo.NewClient(oauthClient) - provider := &DigitalOceanProvider{ + p := &DigitalOceanProvider{ Client: client.Domains, domainFilter: domainFilter, apiPageSize: apiPageSize, DryRun: dryRun, } - return provider, nil + return p, nil } // Zones returns the list of hosted zones. @@ -98,12 +112,45 @@ func (p *DigitalOceanProvider) Zones(ctx context.Context) ([]godo.Domain, error) return result, nil } +// Merge Endpoints with the same Name and Type into a single endpoint with multiple Targets. +func mergeEndpointsByNameType(endpoints []*endpoint.Endpoint) []*endpoint.Endpoint { + endpointsByNameType := map[string][]*endpoint.Endpoint{} + + for _, e := range endpoints { + key := fmt.Sprintf("%s-%s", e.DNSName, e.RecordType) + endpointsByNameType[key] = append(endpointsByNameType[key], e) + } + + // If no merge occurred, just return the existing endpoints. + if len(endpointsByNameType) == len(endpoints) { + return endpoints + } + + // Otherwise, construct a new list of endpoints with the endpoints merged. + var result []*endpoint.Endpoint + for _, endpoints := range endpointsByNameType { + dnsName := endpoints[0].DNSName + recordType := endpoints[0].RecordType + + targets := make([]string, len(endpoints)) + for i, e := range endpoints { + targets[i] = e.Targets[0] + } + + e := endpoint.NewEndpoint(dnsName, recordType, targets...) + result = append(result, e) + } + + return result +} + // Records returns the list of records in a given zone. func (p *DigitalOceanProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error) { zones, err := p.Zones(ctx) if err != nil { return nil, err } + endpoints := []*endpoint.Endpoint{} for _, zone := range zones { records, err := p.fetchRecords(ctx, zone.Name) @@ -121,11 +168,21 @@ func (p *DigitalOceanProvider) Records(ctx context.Context) ([]*endpoint.Endpoin name = zone.Name } - endpoints = append(endpoints, endpoint.NewEndpoint(name, r.Type, r.Data)) + ep := endpoint.NewEndpoint(name, r.Type, r.Data) + endpoints = append(endpoints, ep) } } } + // Merge endpoints with the same name and type (e.g., multiple A records for a single + // DNS name) into one endpoint with multiple targets. + endpoints = mergeEndpointsByNameType(endpoints) + + // Log the endpoints that were found. + log.WithFields(log.Fields{ + "endpoints": endpoints, + }).Debug("Endpoints generated from DigitalOcean DNS") + return endpoints, nil } @@ -179,160 +236,380 @@ func (p *DigitalOceanProvider) fetchZones(ctx context.Context) ([]godo.Domain, e return allZones, nil } -// submitChanges takes a zone and a collection of Changes and sends them as a single transaction. -func (p *DigitalOceanProvider) submitChanges(ctx context.Context, changes []*DigitalOceanChange) error { +func (p *DigitalOceanProvider) getRecordsByDomain(ctx context.Context) (map[string][]godo.DomainRecord, provider.ZoneIDName, error) { + recordsByDomain := map[string][]godo.DomainRecord{} + + zones, err := p.Zones(ctx) + if err != nil { + return nil, nil, err + } + + zonesByDomain := make(map[string]godo.Domain) + zoneNameIDMapper := provider.ZoneIDName{} + for _, z := range zones { + zoneNameIDMapper.Add(z.Name, z.Name) + zonesByDomain[z.Name] = z + } + + // Fetch records for each zone + for _, zone := range zones { + records, err := p.fetchRecords(ctx, zone.Name) + if err != nil { + return nil, nil, err + } + + recordsByDomain[zone.Name] = append(recordsByDomain[zone.Name], records...) + } + + return recordsByDomain, zoneNameIDMapper, nil +} + +// Make a DomainRecordEditRequest that conforms to DigitalOcean API requirements: +// - Records at root of the zone have `@` as the name +// - CNAME records must end in a `.` +func makeDomainEditRequest(domain, name, recordType, data string, ttl int) *godo.DomainRecordEditRequest { + // Trim the domain off the name if present. + adjustedName := strings.TrimSuffix(name, "."+domain) + + // Record at the root should be defined as @ instead of the full domain name. + if adjustedName == domain { + adjustedName = "@" + } + + // For some reason the DO API requires the '.' at the end of "data" in case of CNAME request. + // Example: {"type":"CNAME","name":"hello","data":"www.example.com."} + if recordType == endpoint.RecordTypeCNAME && !strings.HasSuffix(data, ".") { + data += "." + } + + return &godo.DomainRecordEditRequest{ + Name: adjustedName, + Type: recordType, + Data: data, + TTL: ttl, + } +} + +// submitChanges applies an instance of `digitalOceanChanges` to the DigitalOcean API. +func (p *DigitalOceanProvider) submitChanges(ctx context.Context, changes *digitalOceanChanges) error { // return early if there is nothing to change - if len(changes) == 0 { + if changes.Empty() { return nil } - zones, err := p.Zones(ctx) + for _, c := range changes.Creates { + log.WithFields(log.Fields{ + "domain": c.Domain, + "dnsName": c.Options.Name, + "recordType": c.Options.Type, + "data": c.Options.Data, + "ttl": c.Options.TTL, + }).Debug("Creating domain record") + + if p.DryRun { + continue + } + + _, _, err := p.Client.CreateRecord(ctx, c.Domain, c.Options) + if err != nil { + return err + } + } + + for _, u := range changes.Updates { + log.WithFields(log.Fields{ + "domain": u.Domain, + "dnsName": u.Options.Name, + "recordType": u.Options.Type, + "data": u.Options.Data, + "ttl": u.Options.TTL, + }).Debug("Updating domain record") + + if p.DryRun { + continue + } + + _, _, err := p.Client.EditRecord(ctx, u.Domain, u.DomainRecord.ID, u.Options) + if err != nil { + return err + } + } + + for _, d := range changes.Deletes { + log.WithFields(log.Fields{ + "domain": d.Domain, + "recordId": d.RecordID, + }).Debug("Deleting domain record") + + if p.DryRun { + continue + } + + _, err := p.Client.DeleteRecord(ctx, d.Domain, d.RecordID) + if err != nil { + return err + } + } + + return nil +} + +func getTTLFromEndpoint(ep *endpoint.Endpoint) int { + if ep.RecordTTL.IsConfigured() { + return int(ep.RecordTTL) + } + return digitalOceanRecordTTL +} + +func endpointsByZone(zoneNameIDMapper provider.ZoneIDName, endpoints []*endpoint.Endpoint) map[string][]*endpoint.Endpoint { + endpointsByZone := make(map[string][]*endpoint.Endpoint) + + for _, ep := range endpoints { + zoneID, _ := zoneNameIDMapper.FindZone(ep.DNSName) + if zoneID == "" { + log.Debugf("Skipping record %s because no hosted zone matching record DNS Name was detected", ep.DNSName) + continue + } + endpointsByZone[zoneID] = append(endpointsByZone[zoneID], ep) + } + + return endpointsByZone +} + +func getMatchingDomainRecords(records []godo.DomainRecord, domain string, ep *endpoint.Endpoint) []godo.DomainRecord { + var name string + if ep.DNSName != domain { + name = strings.TrimSuffix(ep.DNSName, "."+domain) + } else { + name = "@" + } + + var result []godo.DomainRecord + for _, r := range records { + if r.Name == name && r.Type == ep.RecordType { + result = append(result, r) + } + } + return result +} + +func processCreateActions( + recordsByDomain map[string][]godo.DomainRecord, + createsByDomain map[string][]*endpoint.Endpoint, + changes *digitalOceanChanges, +) error { + // Process endpoints that need to be created. + for domain, endpoints := range createsByDomain { + if len(endpoints) == 0 { + log.WithFields(log.Fields{ + "domain": domain, + }).Debug("Skipping domain, no creates found.") + continue + } + + records := recordsByDomain[domain] + + for _, ep := range endpoints { + // Warn if there are existing records since we expect to create only new records. + matchingRecords := getMatchingDomainRecords(records, domain, ep) + if len(matchingRecords) > 0 { + log.WithFields(log.Fields{ + "domain": domain, + "dnsName": ep.DNSName, + "recordType": ep.RecordType, + }).Warn("Preexisting records exist which should not exist for creation actions.") + } + + ttl := getTTLFromEndpoint(ep) + + for _, target := range ep.Targets { + changes.Creates = append(changes.Creates, &digitalOceanChangeCreate{ + Domain: domain, + Options: makeDomainEditRequest(domain, ep.DNSName, ep.RecordType, target, ttl), + }) + } + } + } + + return nil +} + +func processUpdateActions( + recordsByDomain map[string][]godo.DomainRecord, + updatesByDomain map[string][]*endpoint.Endpoint, + changes *digitalOceanChanges, +) error { + // Generate creates and updates based on existing + for domain, updates := range updatesByDomain { + if len(updates) == 0 { + log.WithFields(log.Fields{ + "domain": domain, + }).Debug("Skipping Zone, no updates found.") + continue + } + + records := recordsByDomain[domain] + log.WithFields(log.Fields{ + "domain": domain, + "records": records, + }).Debug("Records for domain") + + for _, ep := range updates { + matchingRecords := getMatchingDomainRecords(records, domain, ep) + + log.WithFields(log.Fields{ + "endpoint": ep, + "matchingRecords": matchingRecords, + }).Debug("matching records") + + if len(matchingRecords) == 0 { + log.WithFields(log.Fields{ + "domain": domain, + "dnsName": ep.DNSName, + "recordType": ep.RecordType, + }).Warn("Planning an update but no existing records found.") + } + + matchingRecordsByTarget := map[string]godo.DomainRecord{} + for _, r := range matchingRecords { + matchingRecordsByTarget[r.Data] = r + } + + ttl := getTTLFromEndpoint(ep) + + // Generate create and delete actions based on existence of a record for each target. + for _, target := range ep.Targets { + if record, ok := matchingRecordsByTarget[target]; ok { + log.WithFields(log.Fields{ + "domain": domain, + "dnsName": ep.DNSName, + "recordType": ep.RecordType, + "target": target, + }).Warn("Updating existing target") + + changes.Updates = append(changes.Updates, &digitalOceanChangeUpdate{ + Domain: domain, + DomainRecord: record, + Options: makeDomainEditRequest(domain, ep.DNSName, ep.RecordType, target, ttl), + }) + + delete(matchingRecordsByTarget, target) + } else { + // Record did not previously exist, create new 'target' + log.WithFields(log.Fields{ + "domain": domain, + "dnsName": ep.DNSName, + "recordType": ep.RecordType, + "target": target, + }).Warn("Creating new target") + + changes.Creates = append(changes.Creates, &digitalOceanChangeCreate{ + Domain: domain, + Options: makeDomainEditRequest(domain, ep.DNSName, ep.RecordType, target, ttl), + }) + } + } + + // Any remaining records have been removed, delete them + for _, record := range matchingRecordsByTarget { + log.WithFields(log.Fields{ + "domain": domain, + "dnsName": ep.DNSName, + "recordType": ep.RecordType, + "target": record.Data, + }).Warn("Deleting target") + + changes.Deletes = append(changes.Deletes, &digitalOceanChangeDelete{ + Domain: domain, + RecordID: record.ID, + }) + } + } + + } + + return nil +} + +func processDeleteActions( + recordsByDomain map[string][]godo.DomainRecord, + deletesByDomain map[string][]*endpoint.Endpoint, + changes *digitalOceanChanges, +) error { + // Generate delete actions for each deleted endpoint. + for domain, deletes := range deletesByDomain { + if len(deletes) == 0 { + log.WithFields(log.Fields{ + "domain": domain, + }).Debug("Skipping Zone, no deletes found.") + continue + } + + records := recordsByDomain[domain] + + for _, ep := range deletes { + matchingRecords := getMatchingDomainRecords(records, domain, ep) + + if len(matchingRecords) == 0 { + log.WithFields(log.Fields{ + "domain": domain, + "dnsName": ep.DNSName, + "recordType": ep.RecordType, + }).Warn("Records to delete not found.") + } + + for _, record := range matchingRecords { + doDelete := false + for _, t := range ep.Targets { + v1 := t + v2 := record.Data + if ep.RecordType == endpoint.RecordTypeCNAME { + v1 = strings.TrimSuffix(t, ".") + v2 = strings.TrimSuffix(t, ".") + } + if v1 == v2 { + doDelete = true + } + } + + if doDelete { + changes.Deletes = append(changes.Deletes, &digitalOceanChangeDelete{ + Domain: domain, + RecordID: record.ID, + }) + } + } + } + } + + return nil +} + +// ApplyChanges applies the given set of generic changes to the provider. +func (p *DigitalOceanProvider) ApplyChanges(ctx context.Context, planChanges *plan.Changes) error { + // TODO: This should only retrieve zones affected by the given `planChanges`. + recordsByDomain, zoneNameIDMapper, err := p.getRecordsByDomain(ctx) if err != nil { return err } - // separate into per-zone change sets to be passed to the API. - changesByZone := digitalOceanChangesByZone(zones, changes) - for zoneName, changes := range changesByZone { - records, err := p.fetchRecords(ctx, zoneName) - if err != nil { - log.Errorf("Failed to list records in the zone: %s", zoneName) - continue - } - for _, change := range changes { - logFields := log.Fields{ - "record": change.ResourceRecordSet.Name, - "type": change.ResourceRecordSet.Type, - "ttl": change.ResourceRecordSet.TTL, - "action": change.Action, - "zone": zoneName, - } + createsByDomain := endpointsByZone(zoneNameIDMapper, planChanges.Create) + updatesByDomain := endpointsByZone(zoneNameIDMapper, planChanges.UpdateNew) + deletesByDomain := endpointsByZone(zoneNameIDMapper, planChanges.Delete) - log.WithFields(logFields).Info("Changing record.") + var changes digitalOceanChanges - if p.DryRun { - continue - } - - change.ResourceRecordSet.Name = strings.TrimSuffix(change.ResourceRecordSet.Name, "."+zoneName) - - // record at the root should be defined as @ instead of - // the full domain name - if change.ResourceRecordSet.Name == zoneName { - change.ResourceRecordSet.Name = "@" - } - - // for some reason the DO API requires the '.' at the end of "data" in case of CNAME request - // Example: {"type":"CNAME","name":"hello","data":"www.example.com."} - if change.ResourceRecordSet.Type == endpoint.RecordTypeCNAME { - change.ResourceRecordSet.Data += "." - } - - switch change.Action { - case DigitalOceanCreate: - _, _, err = p.Client.CreateRecord(ctx, zoneName, - &godo.DomainRecordEditRequest{ - Data: change.ResourceRecordSet.Data, - Name: change.ResourceRecordSet.Name, - Type: change.ResourceRecordSet.Type, - TTL: change.ResourceRecordSet.TTL, - }) - if err != nil { - return err - } - case DigitalOceanDelete: - recordID := p.getRecordID(records, change.ResourceRecordSet) - _, err = p.Client.DeleteRecord(ctx, zoneName, recordID) - if err != nil { - return err - } - case DigitalOceanUpdate: - recordID := p.getRecordID(records, change.ResourceRecordSet) - _, _, err = p.Client.EditRecord(ctx, zoneName, recordID, - &godo.DomainRecordEditRequest{ - Data: change.ResourceRecordSet.Data, - Name: change.ResourceRecordSet.Name, - Type: change.ResourceRecordSet.Type, - TTL: change.ResourceRecordSet.TTL, - }) - if err != nil { - return err - } - } - } + if err := processCreateActions(recordsByDomain, createsByDomain, &changes); err != nil { + return err } - return nil -} - -// ApplyChanges applies a given set of changes in a given zone. -func (p *DigitalOceanProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error { - combinedChanges := make([]*DigitalOceanChange, 0, len(changes.Create)+len(changes.UpdateNew)+len(changes.Delete)) - - combinedChanges = append(combinedChanges, newDigitalOceanChanges(DigitalOceanCreate, changes.Create)...) - combinedChanges = append(combinedChanges, newDigitalOceanChanges(DigitalOceanUpdate, changes.UpdateNew)...) - combinedChanges = append(combinedChanges, newDigitalOceanChanges(DigitalOceanDelete, changes.Delete)...) - - return p.submitChanges(ctx, combinedChanges) -} - -// newDigitalOceanChanges returns a collection of Changes based on the given records and action. -func newDigitalOceanChanges(action string, endpoints []*endpoint.Endpoint) []*DigitalOceanChange { - changes := make([]*DigitalOceanChange, 0, len(endpoints)) - - for _, endpoint := range endpoints { - changes = append(changes, newDigitalOceanChange(action, endpoint)) - } - - return changes -} - -func newDigitalOceanChange(action string, endpoint *endpoint.Endpoint) *DigitalOceanChange { - // no annotation results in a TTL of 0, default to 300 for consistency with other providers - var ttl = digitalOceanRecordTTL - if endpoint.RecordTTL.IsConfigured() { - ttl = int(endpoint.RecordTTL) - } - - change := &DigitalOceanChange{ - Action: action, - ResourceRecordSet: godo.DomainRecord{ - Name: endpoint.DNSName, - Type: endpoint.RecordType, - Data: endpoint.Targets[0], - TTL: ttl, - }, - } - return change -} - -// getRecordID returns the ID from a record. -// the ID is mandatory to update and delete records -func (p *DigitalOceanProvider) getRecordID(records []godo.DomainRecord, record godo.DomainRecord) int { - for _, zoneRecord := range records { - if zoneRecord.Name == record.Name && zoneRecord.Type == record.Type { - return zoneRecord.ID - } - } - return 0 -} - -// digitalOceanchangesByZone separates a multi-zone change into a single change per zone. -func digitalOceanChangesByZone(zones []godo.Domain, changeSet []*DigitalOceanChange) map[string][]*DigitalOceanChange { - changes := make(map[string][]*DigitalOceanChange) - zoneNameIDMapper := provider.ZoneIDName{} - for _, z := range zones { - zoneNameIDMapper.Add(z.Name, z.Name) - changes[z.Name] = []*DigitalOceanChange{} - } - - for _, c := range changeSet { - zone, _ := zoneNameIDMapper.FindZone(c.ResourceRecordSet.Name) - if zone == "" { - log.Debugf("Skipping record %s because no hosted zone matching record DNS Name was detected", c.ResourceRecordSet.Name) - continue - } - changes[zone] = append(changes[zone], c) - } - - return changes + + if err := processUpdateActions(recordsByDomain, updatesByDomain, &changes); err != nil { + return err + } + + if err := processDeleteActions(recordsByDomain, deletesByDomain, &changes); err != nil { + return err + } + + return p.submitChanges(ctx, &changes) } diff --git a/provider/digitalocean/digital_ocean_test.go b/provider/digitalocean/digital_ocean_test.go index 421b46fe3..687f0e1d1 100644 --- a/provider/digitalocean/digital_ocean_test.go +++ b/provider/digitalocean/digital_ocean_test.go @@ -20,9 +20,12 @@ import ( "context" "fmt" "os" + "reflect" + "sort" "testing" "github.com/digitalocean/godo" + "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -143,10 +146,54 @@ func (m *mockDigitalOceanRecordsFail) Records(ctx context.Context, domain string return []godo.DomainRecord{}, nil, fmt.Errorf("Failed to get records") } -func TestNewDigitalOceanChanges(t *testing.T) { - action := DigitalOceanCreate - endpoints := []*endpoint.Endpoint{{DNSName: "new", Targets: endpoint.Targets{"target"}}} - _ = newDigitalOceanChanges(action, endpoints) +// This function is an adapted copy of the testify package's ElementsMatch function with the +// call to ObjectsAreEqual replaced with cmp.Equal which better handles struct's with pointers to +// other structs. +// +// TODO: Upstream a change to testify package to allow custom matchers. +func elementsMatch(t *testing.T, listA, listB interface{}, msgAndArgs ...interface{}) (ok bool) { + aKind := reflect.TypeOf(listA).Kind() + bKind := reflect.TypeOf(listB).Kind() + + if aKind != reflect.Array && aKind != reflect.Slice { + return assert.Fail(t, fmt.Sprintf("%q has an unsupported type %s", listA, aKind), msgAndArgs...) + } + + if bKind != reflect.Array && bKind != reflect.Slice { + return assert.Fail(t, fmt.Sprintf("%q has an unsupported type %s", listB, bKind), msgAndArgs...) + } + + aValue := reflect.ValueOf(listA) + bValue := reflect.ValueOf(listB) + + aLen := aValue.Len() + bLen := bValue.Len() + + if aLen != bLen { + return assert.Fail(t, fmt.Sprintf("lengths don't match: %d != %d", aLen, bLen), msgAndArgs...) + } + + // Mark indexes in bValue that we already used + visited := make([]bool, bLen) + for i := 0; i < aLen; i++ { + element := aValue.Index(i).Interface() + found := false + for j := 0; j < bLen; j++ { + if visited[j] { + continue + } + if cmp.Equal(bValue.Index(j).Interface(), element) { + visited[j] = true + found = true + break + } + } + if !found { + return assert.Fail(t, fmt.Sprintf("element %s appears more times in %s than in %s", element, aValue, bValue), msgAndArgs...) + } + } + + return true } func TestDigitalOceanZones(t *testing.T) { @@ -165,6 +212,38 @@ func TestDigitalOceanZones(t *testing.T) { }) } +func TestDigitalOceanMakeDomainEditRequest(t *testing.T) { + // Ensure that records at the root of the zone get `@` as the name. + r1 := makeDomainEditRequest("example.com", "example.com", endpoint.RecordTypeA, + "1.2.3.4", digitalOceanRecordTTL) + assert.Equal(t, &godo.DomainRecordEditRequest{ + Type: endpoint.RecordTypeA, + Name: "@", + Data: "1.2.3.4", + TTL: digitalOceanRecordTTL, + }, r1) + + // Ensure the CNAME records have a `.` appended. + r2 := makeDomainEditRequest("example.com", "foo.example.com", endpoint.RecordTypeCNAME, + "bar.example.com", digitalOceanRecordTTL) + assert.Equal(t, &godo.DomainRecordEditRequest{ + Type: endpoint.RecordTypeCNAME, + Name: "foo", + Data: "bar.example.com.", + TTL: digitalOceanRecordTTL, + }, r2) + + // Ensure that CNAME records do not have an extra `.` appended if they already have a `.` + r3 := makeDomainEditRequest("example.com", "foo.example.com", endpoint.RecordTypeCNAME, + "bar.example.com.", digitalOceanRecordTTL) + assert.Equal(t, &godo.DomainRecordEditRequest{ + Type: endpoint.RecordTypeCNAME, + Name: "foo", + Data: "bar.example.com.", + TTL: digitalOceanRecordTTL, + }, r3) +} + func TestDigitalOceanApplyChanges(t *testing.T) { changes := &plan.Changes{} provider := &DigitalOceanProvider{ @@ -185,6 +264,198 @@ func TestDigitalOceanApplyChanges(t *testing.T) { } } +func TestDigitalOceanProcessCreateActions(t *testing.T) { + recordsByDomain := map[string][]godo.DomainRecord{ + "example.com": nil, + } + + createsByDomain := map[string][]*endpoint.Endpoint{ + "example.com": { + endpoint.NewEndpoint("foo.example.com", endpoint.RecordTypeA, "1.2.3.4"), + endpoint.NewEndpoint("example.com", endpoint.RecordTypeCNAME, "foo.example.com"), + }, + } + + var changes digitalOceanChanges + err := processCreateActions(recordsByDomain, createsByDomain, &changes) + require.NoError(t, err) + + assert.Equal(t, 2, len(changes.Creates)) + assert.Equal(t, 0, len(changes.Updates)) + assert.Equal(t, 0, len(changes.Deletes)) + + expectedCreates := []*digitalOceanChangeCreate{ + { + Domain: "example.com", + Options: &godo.DomainRecordEditRequest{ + Name: "foo", + Type: endpoint.RecordTypeA, + Data: "1.2.3.4", + TTL: digitalOceanRecordTTL, + }, + }, + { + Domain: "example.com", + Options: &godo.DomainRecordEditRequest{ + Name: "@", + Type: endpoint.RecordTypeCNAME, + Data: "foo.example.com.", + TTL: digitalOceanRecordTTL, + }, + }, + } + + if !elementsMatch(t, expectedCreates, changes.Creates) { + assert.Failf(t, "diff: %s", cmp.Diff(expectedCreates, changes.Creates)) + } +} + +func TestDigitalOceanProcessUpdateActions(t *testing.T) { + recordsByDomain := map[string][]godo.DomainRecord{ + "example.com": { + { + ID: 1, + Name: "foo", + Type: endpoint.RecordTypeA, + Data: "1.2.3.4", + TTL: digitalOceanRecordTTL, + }, + { + ID: 2, + Name: "foo", + Type: endpoint.RecordTypeA, + Data: "5.6.7.8", + TTL: digitalOceanRecordTTL, + }, + { + ID: 3, + Name: "@", + Type: endpoint.RecordTypeCNAME, + Data: "foo.example.com.", + TTL: digitalOceanRecordTTL, + }, + }, + } + + updatesByDomain := map[string][]*endpoint.Endpoint{ + "example.com": { + endpoint.NewEndpoint("foo.example.com", endpoint.RecordTypeA, "10.11.12.13"), + endpoint.NewEndpoint("example.com", endpoint.RecordTypeCNAME, "bar.example.com"), + }, + } + + var changes digitalOceanChanges + err := processUpdateActions(recordsByDomain, updatesByDomain, &changes) + require.NoError(t, err) + + assert.Equal(t, 2, len(changes.Creates)) + assert.Equal(t, 0, len(changes.Updates)) + assert.Equal(t, 3, len(changes.Deletes)) + + expectedCreates := []*digitalOceanChangeCreate{ + { + Domain: "example.com", + Options: &godo.DomainRecordEditRequest{ + Name: "foo", + Type: endpoint.RecordTypeA, + Data: "10.11.12.13", + TTL: digitalOceanRecordTTL, + }, + }, + { + Domain: "example.com", + Options: &godo.DomainRecordEditRequest{ + Name: "@", + Type: endpoint.RecordTypeCNAME, + Data: "bar.example.com.", + TTL: digitalOceanRecordTTL, + }, + }, + } + + if !elementsMatch(t, expectedCreates, changes.Creates) { + assert.Failf(t, "diff: %s", cmp.Diff(expectedCreates, changes.Creates)) + } + + expectedDeletes := []*digitalOceanChangeDelete{ + { + Domain: "example.com", + RecordID: 1, + }, + { + Domain: "example.com", + RecordID: 2, + }, + { + Domain: "example.com", + RecordID: 3, + }, + } + + if !elementsMatch(t, expectedDeletes, changes.Deletes) { + assert.Failf(t, "diff: %s", cmp.Diff(expectedDeletes, changes.Deletes)) + } +} + +func TestDigitalOceanProcessDeleteActions(t *testing.T) { + recordsByDomain := map[string][]godo.DomainRecord{ + "example.com": { + { + ID: 1, + Name: "foo", + Type: endpoint.RecordTypeA, + Data: "1.2.3.4", + TTL: digitalOceanRecordTTL, + }, + // This record will not be deleted because it represents a target not specified to be deleted. + { + ID: 2, + Name: "foo", + Type: endpoint.RecordTypeA, + Data: "5.6.7.8", + TTL: digitalOceanRecordTTL, + }, + { + ID: 3, + Name: "@", + Type: endpoint.RecordTypeCNAME, + Data: "foo.example.com.", + TTL: digitalOceanRecordTTL, + }, + }, + } + + deletesByDomain := map[string][]*endpoint.Endpoint{ + "example.com": { + endpoint.NewEndpoint("foo.example.com", endpoint.RecordTypeA, "1.2.3.4"), + endpoint.NewEndpoint("example.com", endpoint.RecordTypeCNAME, "foo.example.com"), + }, + } + + var changes digitalOceanChanges + err := processDeleteActions(recordsByDomain, deletesByDomain, &changes) + require.NoError(t, err) + + assert.Equal(t, 0, len(changes.Creates)) + assert.Equal(t, 0, len(changes.Updates)) + assert.Equal(t, 2, len(changes.Deletes)) + + expectedDeletes := []*digitalOceanChangeDelete{ + { + Domain: "example.com", + RecordID: 1, + }, + { + Domain: "example.com", + RecordID: 3, + }, + } + + if !elementsMatch(t, expectedDeletes, changes.Deletes) { + assert.Failf(t, "diff: %s", cmp.Diff(expectedDeletes, changes.Deletes)) + } +} + func TestNewDigitalOceanProvider(t *testing.T) { _ = os.Setenv("DO_TOKEN", "xxxxxxxxxxxxxxxxx") _, err := NewDigitalOceanProvider(context.Background(), endpoint.NewDomainFilter([]string{"ext-dns-test.zalando.to."}), true, 50) @@ -198,29 +469,62 @@ func TestNewDigitalOceanProvider(t *testing.T) { } } -func TestDigitalOceanGetRecordID(t *testing.T) { - p := &DigitalOceanProvider{} +func TestDigitalOceanGetMatchingDomainRecords(t *testing.T) { records := []godo.DomainRecord{ { ID: 1, - Name: "foo.com", + Name: "foo", Type: endpoint.RecordTypeCNAME, + Data: "baz.org.", }, { ID: 2, - Name: "baz.de", + Name: "baz", Type: endpoint.RecordTypeA, + Data: "1.2.3.4", + }, + { + ID: 3, + Name: "baz", + Type: endpoint.RecordTypeA, + Data: "5.6.7.8", + }, + { + ID: 4, + Name: "@", + Type: endpoint.RecordTypeA, + Data: "9.10.11.12", }, } - assert.Equal(t, 1, p.getRecordID(records, godo.DomainRecord{ - Name: "foo.com", - Type: endpoint.RecordTypeCNAME, - })) - assert.Equal(t, 0, p.getRecordID(records, godo.DomainRecord{ - Name: "foo.com", - Type: endpoint.RecordTypeA, - })) + ep1 := endpoint.NewEndpoint("foo.com", endpoint.RecordTypeCNAME) + assert.Equal(t, 1, len(getMatchingDomainRecords(records, "com", ep1))) + + ep2 := endpoint.NewEndpoint("foo.com", endpoint.RecordTypeA) + assert.Equal(t, 0, len(getMatchingDomainRecords(records, "com", ep2))) + + ep3 := endpoint.NewEndpoint("baz.org", endpoint.RecordTypeA) + r := getMatchingDomainRecords(records, "org", ep3) + assert.Equal(t, 2, len(r)) + assert.ElementsMatch(t, r, []godo.DomainRecord{ + { + ID: 2, + Name: "baz", + Type: endpoint.RecordTypeA, + Data: "1.2.3.4", + }, + { + ID: 3, + Name: "baz", + Type: endpoint.RecordTypeA, + Data: "5.6.7.8", + }, + }) + + ep4 := endpoint.NewEndpoint("example.com", endpoint.RecordTypeA) + r2 := getMatchingDomainRecords(records, "example.com", ep4) + assert.Equal(t, 1, len(r2)) + assert.Equal(t, "9.10.11.12", r2[0].Data) } func validateDigitalOceanZones(t *testing.T, zones []godo.Domain, expected []godo.Domain) { @@ -265,3 +569,36 @@ func TestDigitalOceanAllRecords(t *testing.T) { t.Errorf("expected to fail, %s", err) } } + +func TestDigitalOceanMergeRecordsByNameType(t *testing.T) { + xs := []*endpoint.Endpoint{ + endpoint.NewEndpoint("foo.example.com", "A", "1.2.3.4"), + endpoint.NewEndpoint("bar.example.com", "A", "1.2.3.4"), + endpoint.NewEndpoint("foo.example.com", "A", "5.6.7.8"), + endpoint.NewEndpoint("foo.example.com", "CNAME", "somewhere.out.there.com"), + } + + merged := mergeEndpointsByNameType(xs) + + assert.Equal(t, 3, len(merged)) + sort.SliceStable(merged, func(i, j int) bool { + if merged[i].DNSName != merged[j].DNSName { + return merged[i].DNSName < merged[j].DNSName + } + return merged[i].RecordType < merged[j].RecordType + }) + assert.Equal(t, "bar.example.com", merged[0].DNSName) + assert.Equal(t, "A", merged[0].RecordType) + assert.Equal(t, 1, len(merged[0].Targets)) + assert.Equal(t, "1.2.3.4", merged[0].Targets[0]) + + assert.Equal(t, "foo.example.com", merged[1].DNSName) + assert.Equal(t, "A", merged[1].RecordType) + assert.Equal(t, 2, len(merged[1].Targets)) + assert.ElementsMatch(t, []string{"1.2.3.4", "5.6.7.8"}, merged[1].Targets) + + assert.Equal(t, "foo.example.com", merged[2].DNSName) + assert.Equal(t, "CNAME", merged[2].RecordType) + assert.Equal(t, 1, len(merged[2].Targets)) + assert.Equal(t, "somewhere.out.there.com", merged[2].Targets[0]) +} From 035d48411f1a6580f7fc32ff118b56c1032ff587 Mon Sep 17 00:00:00 2001 From: Tom Dyas Date: Tue, 9 Jun 2020 16:26:22 -0700 Subject: [PATCH 05/13] remove change from Dockerfile --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 3330c429a..57ddb572e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,8 +20,8 @@ ARG VERSION WORKDIR /sigs.k8s.io/external-dns COPY . . -RUN go mod vendor -RUN make test && \ +RUN go mod vendor && \ + make test && \ make build # final image From 726d343cc67d8ca50d5b0effa315ebde85c6bde2 Mon Sep 17 00:00:00 2001 From: Tom Dyas Date: Wed, 10 Jun 2020 10:12:43 -0700 Subject: [PATCH 06/13] fix golangcii-lint issue --- provider/digitalocean/digital_ocean.go | 1 - 1 file changed, 1 deletion(-) diff --git a/provider/digitalocean/digital_ocean.go b/provider/digitalocean/digital_ocean.go index e26f76a27..5e63c0559 100644 --- a/provider/digitalocean/digital_ocean.go +++ b/provider/digitalocean/digital_ocean.go @@ -525,7 +525,6 @@ func processUpdateActions( }) } } - } return nil From e3c0e6d943570b34bdb010b54e22d4c9311ee441 Mon Sep 17 00:00:00 2001 From: Tom Dyas Date: Sun, 14 Jun 2020 22:11:31 -0700 Subject: [PATCH 07/13] remove TODO --- provider/digitalocean/digital_ocean_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/provider/digitalocean/digital_ocean_test.go b/provider/digitalocean/digital_ocean_test.go index 687f0e1d1..84b7c1926 100644 --- a/provider/digitalocean/digital_ocean_test.go +++ b/provider/digitalocean/digital_ocean_test.go @@ -149,8 +149,6 @@ func (m *mockDigitalOceanRecordsFail) Records(ctx context.Context, domain string // This function is an adapted copy of the testify package's ElementsMatch function with the // call to ObjectsAreEqual replaced with cmp.Equal which better handles struct's with pointers to // other structs. -// -// TODO: Upstream a change to testify package to allow custom matchers. func elementsMatch(t *testing.T, listA, listB interface{}, msgAndArgs ...interface{}) (ok bool) { aKind := reflect.TypeOf(listA).Kind() bKind := reflect.TypeOf(listB).Kind() From 84e514b3be804dbf2d52b07451a8edb512363fda Mon Sep 17 00:00:00 2001 From: Tom Dyas Date: Mon, 15 Jun 2020 00:15:25 -0700 Subject: [PATCH 08/13] add test for elementsMatch plus fix for nil --- provider/digitalocean/digital_ocean_test.go | 61 ++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/provider/digitalocean/digital_ocean_test.go b/provider/digitalocean/digital_ocean_test.go index 84b7c1926..939a38fe0 100644 --- a/provider/digitalocean/digital_ocean_test.go +++ b/provider/digitalocean/digital_ocean_test.go @@ -146,10 +146,26 @@ func (m *mockDigitalOceanRecordsFail) Records(ctx context.Context, domain string return []godo.DomainRecord{}, nil, fmt.Errorf("Failed to get records") } +func isEmpty(xs interface{}) bool { + if xs != nil { + objValue := reflect.ValueOf(xs) + return objValue.Len() == 0 + } + return true +} + // This function is an adapted copy of the testify package's ElementsMatch function with the // call to ObjectsAreEqual replaced with cmp.Equal which better handles struct's with pointers to -// other structs. +// other structs. It also ignores ordering when comparing unlike cmp.Equal. func elementsMatch(t *testing.T, listA, listB interface{}, msgAndArgs ...interface{}) (ok bool) { + if listA == nil && listB == nil { + return true + } else if listA == nil { + return isEmpty(listB) + } else if listB == nil { + return isEmpty(listA) + } + aKind := reflect.TypeOf(listA).Kind() bKind := reflect.TypeOf(listB).Kind() @@ -194,6 +210,49 @@ func elementsMatch(t *testing.T, listA, listB interface{}, msgAndArgs ...interfa return true } +// Test adapted from test in testify library. +// https://github.com/stretchr/testify/blob/b8f7d52a4a7c581d5ed42333572e7fb857c687c2/assert/assertions_test.go#L768-L796 +func TestElementsMatch(t *testing.T) { + mockT := new(testing.T) + + cases := []struct { + expected interface{} + actual interface{} + result bool + }{ + // matching + {nil, nil, true}, + + {nil, nil, true}, + {[]int{}, []int{}, true}, + {[]int{1}, []int{1}, true}, + {[]int{1, 1}, []int{1, 1}, true}, + {[]int{1, 2}, []int{1, 2}, true}, + {[]int{1, 2}, []int{2, 1}, true}, + {[2]int{1, 2}, [2]int{2, 1}, true}, + {[]string{"hello", "world"}, []string{"world", "hello"}, true}, + {[]string{"hello", "hello"}, []string{"hello", "hello"}, true}, + {[]string{"hello", "hello", "world"}, []string{"hello", "world", "hello"}, true}, + {[3]string{"hello", "hello", "world"}, [3]string{"hello", "world", "hello"}, true}, + {[]int{}, nil, true}, + + // not matching + {[]int{1}, []int{1, 1}, false}, + {[]int{1, 2}, []int{2, 2}, false}, + {[]string{"hello", "hello"}, []string{"hello"}, false}, + } + + for _, c := range cases { + t.Run(fmt.Sprintf("ElementsMatch(%#v, %#v)", c.expected, c.actual), func(t *testing.T) { + res := elementsMatch(mockT, c.actual, c.expected) + + if res != c.result { + t.Errorf("elementsMatch(%#v, %#v) should return %v", c.actual, c.expected, c.result) + } + }) + } +} + func TestDigitalOceanZones(t *testing.T) { provider := &DigitalOceanProvider{ Client: &mockDigitalOceanClient{}, From c32e40b046d6c01e5b6fadee9aa40575154991c6 Mon Sep 17 00:00:00 2001 From: Tom Dyas Date: Fri, 19 Jun 2020 00:38:05 -0700 Subject: [PATCH 09/13] versions got bumped after rebase --- go.mod | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 6103b4c5e..42e6a1428 100644 --- a/go.mod +++ b/go.mod @@ -54,8 +54,8 @@ require ( github.com/vultr/govultr v0.3.2 go.etcd.io/etcd v0.5.0-alpha.5.0.20200401174654-e694b7bb0875 go.uber.org/ratelimit v0.1.0 - golang.org/x/net v0.0.0-20200202094626-16171245cfb2 - golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 + golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e + golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d google.golang.org/api v0.15.0 gopkg.in/ns1/ns1-go.v2 v2.0.0-20190322154155-0dafb5275fd1 gopkg.in/yaml.v2 v2.2.8 From bc068913d07a9a4d10a8941256a32f744d69ebef Mon Sep 17 00:00:00 2001 From: David Dymko Date: Fri, 19 Jun 2020 09:05:30 -0400 Subject: [PATCH 10/13] linted --- provider/vultr/vultr.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/provider/vultr/vultr.go b/provider/vultr/vultr.go index 89cf36651..cc7a04211 100644 --- a/provider/vultr/vultr.go +++ b/provider/vultr/vultr.go @@ -157,17 +157,17 @@ func (p *VultrProvider) submitChanges(ctx context.Context, changes []*VultrChang for zoneName, changes := range zoneChanges { for _, change := range changes { log.WithFields(log.Fields{ - "record": change.ResourceRecordSet.Name, - "type": change.ResourceRecordSet.Type, - "ttl": change.ResourceRecordSet.TTL, + "record": change.ResourceRecordSet.Name, + "type": change.ResourceRecordSet.Type, + "ttl": change.ResourceRecordSet.TTL, "priority": change.ResourceRecordSet.Priority, - "action": change.Action, - "zone": zoneName, + "action": change.Action, + "zone": zoneName, }).Info("Changing record.") switch change.Action { case vultrCreate: - priority := getPriority(change.ResourceRecordSet.Priority) + priority := getPriority(change.ResourceRecordSet.Priority) err = p.client.DNSRecord.Create(ctx, zoneName, change.ResourceRecordSet.Type, change.ResourceRecordSet.Name, change.ResourceRecordSet.Data, change.ResourceRecordSet.TTL, priority) if err != nil { return err @@ -281,8 +281,8 @@ func (p *VultrProvider) getRecordID(ctx context.Context, zone string, record gov func getPriority(priority *int) int { p := 0 - if priority != nil{ + if priority != nil { p = *priority } return p -} \ No newline at end of file +} From 4210f0afcdd11fb57f2da7fd73bb924529cd0b48 Mon Sep 17 00:00:00 2001 From: Raffaele Di Fazio Date: Sat, 20 Jun 2020 18:10:49 +0000 Subject: [PATCH 11/13] added endpoints to kustomize base Signed-off-by: Raffaele Di Fazio --- kustomize/external-dns-clusterrole.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kustomize/external-dns-clusterrole.yaml b/kustomize/external-dns-clusterrole.yaml index 0470770ef..6dfc98c4e 100644 --- a/kustomize/external-dns-clusterrole.yaml +++ b/kustomize/external-dns-clusterrole.yaml @@ -15,3 +15,6 @@ rules: - apiGroups: [""] resources: ["nodes"] verbs: ["list"] +- apiGroups: [""] + resources: ["endpoints"] + verbs: ["get","watch","list"] From a54aa72303c5a9f20d3f9bd46bac3ba249599598 Mon Sep 17 00:00:00 2001 From: ikovnatskymiacar <67179033+ikovnatskymiacar@users.noreply.github.com> Date: Mon, 22 Jun 2020 11:08:23 +0300 Subject: [PATCH 12/13] Upgrade istio httpbin from 1.0 to 1.6 version --- docs/tutorials/istio.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/tutorials/istio.md b/docs/tutorials/istio.md index 4f9495f9b..16f992020 100644 --- a/docs/tutorials/istio.md +++ b/docs/tutorials/istio.md @@ -139,12 +139,12 @@ The following are relevant snippets from that tutorial. #### Install a sample service With automatic sidecar injection: ```bash -$ kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.0/samples/httpbin/httpbin.yaml +$ kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.6/samples/httpbin/httpbin.yaml ``` Otherwise: ```bash -$ kubectl apply -f <(istioctl kube-inject -f https://raw.githubusercontent.com/istio/istio/release-1.0/samples/httpbin/httpbin.yaml) +$ kubectl apply -f <(istioctl kube-inject -f https://raw.githubusercontent.com/istio/istio/release-1.6/samples/httpbin/httpbin.yaml) ``` #### Create an Istio Gateway: From 96cffaff93a09e9afffa678802e4d19454521b6e Mon Sep 17 00:00:00 2001 From: Tariq Ibrahim Date: Fri, 26 Jun 2020 17:13:26 -0700 Subject: [PATCH 13/13] rm unused flag param istio-ingressgateways --- main.go | 1 - pkg/apis/externaldns/types.go | 2 -- source/store.go | 1 - source/store_test.go | 1 - 4 files changed, 5 deletions(-) diff --git a/main.go b/main.go index f02a9f293..549c6c5f8 100644 --- a/main.go +++ b/main.go @@ -112,7 +112,6 @@ func main() { KubeConfig: cfg.KubeConfig, KubeMaster: cfg.Master, ServiceTypeFilter: cfg.ServiceTypeFilter, - IstioIngressGatewayServices: cfg.IstioIngressGatewayServices, CFAPIEndpoint: cfg.CFAPIEndpoint, CFUsername: cfg.CFUsername, CFPassword: cfg.CFPassword, diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index 80b734c2e..1a62a0fb4 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -41,7 +41,6 @@ type Config struct { Master string KubeConfig string RequestTimeout time.Duration - IstioIngressGatewayServices []string ContourLoadBalancerService string SkipperRouteGroupVersion string Sources []string @@ -148,7 +147,6 @@ var defaultConfig = &Config{ Master: "", KubeConfig: "", RequestTimeout: time.Second * 30, - IstioIngressGatewayServices: []string{"istio-system/istio-ingressgateway"}, ContourLoadBalancerService: "heptio-contour/contour", SkipperRouteGroupVersion: "zalando.org/v1", Sources: nil, diff --git a/source/store.go b/source/store.go index 070ef9725..92bb7dd87 100644 --- a/source/store.go +++ b/source/store.go @@ -55,7 +55,6 @@ type Config struct { KubeConfig string KubeMaster string ServiceTypeFilter []string - IstioIngressGatewayServices []string CFAPIEndpoint string CFUsername string CFPassword string diff --git a/source/store_test.go b/source/store_test.go index 15652ddcd..8b6792f7c 100644 --- a/source/store_test.go +++ b/source/store_test.go @@ -155,6 +155,5 @@ func TestByNames(t *testing.T) { } var minimalConfig = &Config{ - IstioIngressGatewayServices: []string{"istio-system/istio-ingressgateway"}, ContourLoadBalancerService: "heptio-contour/contour", }