From b7879ccbd2dba2489570d81e08851a5a496cdb5c Mon Sep 17 00:00:00 2001 From: ivan katliarchuk Date: Fri, 11 Apr 2025 08:48:41 +0100 Subject: [PATCH 01/42] fix(log testing): fix logs Signed-off-by: ivan katliarchuk --- internal/testutils/log.go | 9 --------- source/gateway_httproute_test.go | 7 ++----- source/node_test.go | 5 +---- 3 files changed, 3 insertions(+), 18 deletions(-) diff --git a/internal/testutils/log.go b/internal/testutils/log.go index 232ac78f5..25b7a4270 100644 --- a/internal/testutils/log.go +++ b/internal/testutils/log.go @@ -18,11 +18,9 @@ package testutils import ( "bytes" - "flag" "testing" log "github.com/sirupsen/logrus" - "k8s.io/klog/v2" ) // LogsToBuffer redirects log(s) output to a buffer for testing purposes @@ -38,12 +36,5 @@ func LogsToBuffer(level log.Level, t *testing.T) *bytes.Buffer { buf := new(bytes.Buffer) log.SetOutput(buf) log.SetLevel(level) - klog.SetOutput(buf) - flags := &flag.FlagSet{} - klog.InitFlags(flags) - // make sure klog doesn't write to stderr by default in tests - _ = flags.Set("logtostderr", "false") - _ = flags.Set("alsologtostderr", "false") - _ = flags.Set("stderrthreshold", "4") return buf } diff --git a/source/gateway_httproute_test.go b/source/gateway_httproute_test.go index a09f25bc4..19f009fb7 100644 --- a/source/gateway_httproute_test.go +++ b/source/gateway_httproute_test.go @@ -17,7 +17,6 @@ limitations under the License. package source import ( - "bytes" "context" "testing" @@ -1506,10 +1505,8 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) { src, err := NewGatewayHTTPRouteSource(clients, &tt.config) require.NoError(t, err, "failed to create Gateway HTTPRoute Source") - var b *bytes.Buffer - if len(tt.logExpectations) > 0 { - b = testutils.LogsToBuffer(log.DebugLevel, t) - } + b := testutils.LogsToBuffer(log.DebugLevel, t) + endpoints, err := src.Endpoints(ctx) require.NoError(t, err, "failed to get Endpoints") validateEndpoints(t, endpoints, tt.endpoints) diff --git a/source/node_test.go b/source/node_test.go index a3ad0a600..4e05cde31 100644 --- a/source/node_test.go +++ b/source/node_test.go @@ -394,10 +394,7 @@ func testNodeSourceEndpoints(t *testing.T) { } { tc := tc t.Run(tc.title, func(t *testing.T) { - var buf *bytes.Buffer - if len(tc.expectedLogs) != 0 || len(tc.expectedAbsentLogs) != 0 { - buf = testutils.LogsToBuffer(log.DebugLevel, t) - } + buf := testutils.LogsToBuffer(log.DebugLevel, t) labelSelector := labels.Everything() if tc.labelSelector != "" { From 64f798962871b1d68242815d2c4434f5e68b326b Mon Sep 17 00:00:00 2001 From: Arthur Le Roux Date: Sun, 13 Apr 2025 10:32:22 +0200 Subject: [PATCH 02/42] fix(zonefinder): handle underscores in dns records Signed-off-by: Arthur Le Roux --- provider/zonefinder.go | 30 ++++++++++++++++++++++++++---- provider/zonefinder_test.go | 8 ++++++-- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/provider/zonefinder.go b/provider/zonefinder.go index 6a07646c1..a81f997b3 100644 --- a/provider/zonefinder.go +++ b/provider/zonefinder.go @@ -29,12 +29,34 @@ func (z ZoneIDName) Add(zoneID, zoneName string) { z[zoneID] = zoneName } +// FindZone identifies the most suitable DNS zone for a given hostname. +// It returns the zone ID and name that best match the hostname. +// +// The function processes the hostname by splitting it into labels and +// converting each label to its Unicode form using IDNA (Internationalized +// Domain Names for Applications) standards. +// +// Labels containing underscores ('_') are skipped during Unicode conversion. +// This is because underscores are often used in special DNS records (e.g., +// SRV records as per RFC 2782, or TXT record for services) that are not +// IDNA-aware and cannot represent non-ASCII labels. Skipping these labels +// ensures compatibility with such use cases. func (z ZoneIDName) FindZone(hostname string) (suitableZoneID, suitableZoneName string) { - name, err := idna.Lookup.ToUnicode(hostname) - if err != nil { - log.Warnf("Failed to convert hostname '%s' to its Unicode form: %v", hostname, err) - name = hostname + var name string + domain_labels := strings.Split(hostname, ".") + for i, label := range domain_labels { + if strings.Contains(label, "_") { + continue + } + convertedLabel, err := idna.Lookup.ToUnicode(label) + if err != nil { + log.Warnf("Failed to convert label '%s' of hostname '%s' to its Unicode form: %v", label, hostname, err) + convertedLabel = label + } + domain_labels[i] = convertedLabel } + name = strings.Join(domain_labels, ".") + for zoneID, zoneName := range z { if name == zoneName || strings.HasSuffix(name, "."+zoneName) { if suitableZoneName == "" || len(zoneName) > len(suitableZoneName) { diff --git a/provider/zonefinder_test.go b/provider/zonefinder_test.go index 0037edadd..8b33f566f 100644 --- a/provider/zonefinder_test.go +++ b/provider/zonefinder_test.go @@ -30,11 +30,15 @@ func TestZoneIDName(t *testing.T) { z.Add("123456", "qux.baz") z.Add("654321", "foo.qux.baz") z.Add("987654", "エイミー.みんな") + z.Add("123123", "_metadata.example.com") + z.Add("456456", "_metadata.エイミー.みんな") assert.Equal(t, ZoneIDName{ "123456": "qux.baz", "654321": "foo.qux.baz", "987654": "エイミー.みんな", + "123123": "_metadata.example.com", + "456456": "_metadata.エイミー.みんな", }, z) // simple entry in a domain @@ -73,6 +77,6 @@ func TestZoneIDName(t *testing.T) { assert.Equal(t, "987654", zoneID) b := testutils.LogsToBuffer(log.WarnLevel, t) - zoneID, zoneName = z.FindZone("???") - assert.Contains(t, b.String(), "level=warning msg=\"Failed to convert hostname '???' to its Unicode form: idna: disallowed rune U+003F\"") + _, _ = z.FindZone("???") + assert.Contains(t, b.String(), "level=warning msg=\"Failed to convert label '???' of hostname '???' to its Unicode form: idna: disallowed rune U+003F\"") } From bb1db695724b1f124265e0543782b5961fe95cf2 Mon Sep 17 00:00:00 2001 From: Michel Loiseleur Date: Wed, 16 Apr 2025 21:12:31 +0200 Subject: [PATCH 03/42] chore(go): build with go 1.24.2 --- go.mod | 2 ++ 1 file changed, 2 insertions(+) diff --git a/go.mod b/go.mod index 235c4bc7d..5e9a221ab 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,8 @@ module sigs.k8s.io/external-dns go 1.24.0 +toolchain go1.24.2 + require ( cloud.google.com/go/compute/metadata v0.6.0 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 From ad7dbb49aefe8bf87e2be9e9cfaaf00322197881 Mon Sep 17 00:00:00 2001 From: semnell Date: Thu, 17 Apr 2025 13:49:14 +0200 Subject: [PATCH 04/42] fix(helm): update helm schema (#5297) * fix(helm): update helm schema * chore(helm): fix values file and update schema * test(helm): add tests for null livenessProbe and readinessProbe * docs(helm): update README with default readinessProbe configuration for webhook container * fix(helm): update livenessProbe and readinessProbe schema types in values.yaml * chore(helm): update livenessProbe and readinessProbe schema types in values.yaml * fix(helm): correct type definitions for webhook probes and update CHANGELOG * chore(changelog): fix typo * fix(lint): fix linter * fix(changelog): Fix location of change * docs(helm): update to reference default values for readinessProbe configuration --- charts/external-dns/CHANGELOG.md | 4 ++ .../external-dns/tests/json-schema_test.yaml | 12 ++++ charts/external-dns/values.schema.json | 70 +++++++++++++++---- charts/external-dns/values.yaml | 28 ++++---- 4 files changed, 86 insertions(+), 28 deletions(-) diff --git a/charts/external-dns/CHANGELOG.md b/charts/external-dns/CHANGELOG.md index f21a35f7c..a08aa1758 100644 --- a/charts/external-dns/CHANGELOG.md +++ b/charts/external-dns/CHANGELOG.md @@ -18,6 +18,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [UNRELEASED] +### Fixed + +- Fixed wrong type definitions for webhook probes. ([#5297](https://github.com/kubernetes-sigs/external-dns/pull/5297)) _@semnell_ + ## [v1.16.1] - 2025-04-10 ### Changed diff --git a/charts/external-dns/tests/json-schema_test.yaml b/charts/external-dns/tests/json-schema_test.yaml index 694e59d5c..68b9b6ba3 100644 --- a/charts/external-dns/tests/json-schema_test.yaml +++ b/charts/external-dns/tests/json-schema_test.yaml @@ -50,3 +50,15 @@ tests: labelFilter: "mydomain.io/enable-dns-record in (true)" asserts: - notFailedTemplate: {} + + - it: should not fail when livenessProbe is null + set: + livenessProbe: null + asserts: + - notFailedTemplate: {} + + - it: should not fail when readinessProbe is null + set: + readinessProbe: null + asserts: + - notFailedTemplate: {} diff --git a/charts/external-dns/values.schema.json b/charts/external-dns/values.schema.json index d5e64143e..bbd36ada8 100644 --- a/charts/external-dns/values.schema.json +++ b/charts/external-dns/values.schema.json @@ -308,30 +308,51 @@ "livenessProbe": { "properties": { "failureThreshold": { - "type": "integer" + "type": [ + "integer", + "null" + ] }, "httpGet": { "properties": { "path": { - "type": "string" + "type": [ + "string", + "null" + ] }, "port": { - "type": "string" + "type": [ + "integer", + "string" + ] } }, "type": "object" }, "initialDelaySeconds": { - "type": "integer" + "type": [ + "integer", + "null" + ] }, "periodSeconds": { - "type": "integer" + "type": [ + "integer", + "null" + ] }, "successThreshold": { - "type": "integer" + "type": [ + "integer", + "null" + ] }, "timeoutSeconds": { - "type": "integer" + "type": [ + "integer", + "null" + ] } }, "type": "object" @@ -339,30 +360,51 @@ "readinessProbe": { "properties": { "failureThreshold": { - "type": "integer" + "type": [ + "integer", + "null" + ] }, "httpGet": { "properties": { "path": { - "type": "string" + "type": [ + "string", + "null" + ] }, "port": { - "type": "string" + "type": [ + "integer", + "string" + ] } }, "type": "object" }, "initialDelaySeconds": { - "type": "integer" + "type": [ + "integer", + "null" + ] }, "periodSeconds": { - "type": "integer" + "type": [ + "integer", + "null" + ] }, "successThreshold": { - "type": "integer" + "type": [ + "integer", + "null" + ] }, "timeoutSeconds": { - "type": "integer" + "type": [ + "integer", + "null" + ] } }, "type": "object" diff --git a/charts/external-dns/values.yaml b/charts/external-dns/values.yaml index c1acf0c4c..c1d9be879 100644 --- a/charts/external-dns/values.yaml +++ b/charts/external-dns/values.yaml @@ -263,24 +263,24 @@ provider: # @schema type: [object, string]; # @default -- See _values.yaml_ livenessProbe: httpGet: - path: /healthz - port: http-webhook - initialDelaySeconds: 10 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 2 - successThreshold: 1 + path: /healthz # @schema type:[string, null]; default: null + port: http-webhook # @schema type:[integer,string]; default: string + initialDelaySeconds: 10 # @schema type:[integer, null]; default: null + periodSeconds: 10 # @schema type:[integer, null]; default: null + timeoutSeconds: 5 # @schema type:[integer, null]; default: null + failureThreshold: 2 # @schema type:[integer, null]; default: null + successThreshold: 1 # @schema type:[integer, null]; default: null # -- [Readiness probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) configuration for the `webhook` container. # @default -- See _values.yaml_ readinessProbe: httpGet: - path: /healthz - port: http-webhook - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 6 - successThreshold: 1 + path: /healthz # @schema type:[string, null]; default: null + port: http-webhook # @schema type:[integer,string]; default: string + initialDelaySeconds: 5 # @schema type:[integer, null]; default: null + periodSeconds: 10 # @schema type:[integer, null]; default: null + timeoutSeconds: 5 # @schema type:[integer, null]; default: null + failureThreshold: 6 # @schema type:[integer, null]; default: null + successThreshold: 1 # @schema type:[integer, null]; default: null service: # -- Webhook exposed HTTP port for the service. port: 8080 From bfabe7a81ff20e07a18eb502bff1f516083bbd0c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 18 Apr 2025 03:44:38 +0000 Subject: [PATCH 05/42] chore(deps): bump the dev-dependencies group across 1 directory with 2 updates Bumps the dev-dependencies group with 2 updates in the / directory: [renovatebot/github-action](https://github.com/renovatebot/github-action) and [GrantBirki/json-yaml-validate](https://github.com/grantbirki/json-yaml-validate). Updates `renovatebot/github-action` from 41.0.18 to 41.0.20 - [Release notes](https://github.com/renovatebot/github-action/releases) - [Changelog](https://github.com/renovatebot/github-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/renovatebot/github-action/compare/v41.0.18...v41.0.20) Updates `GrantBirki/json-yaml-validate` from 3.2.1 to 3.3.0 - [Release notes](https://github.com/grantbirki/json-yaml-validate/releases) - [Commits](https://github.com/grantbirki/json-yaml-validate/compare/v3.2.1...v3.3.0) --- updated-dependencies: - dependency-name: renovatebot/github-action dependency-version: 41.0.20 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: GrantBirki/json-yaml-validate dependency-version: 3.3.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dev-dependencies ... Signed-off-by: dependabot[bot] --- .github/workflows/dependency-update.yaml | 2 +- .github/workflows/json-yaml-validate.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dependency-update.yaml b/.github/workflows/dependency-update.yaml index e43a86dd5..095331b08 100644 --- a/.github/workflows/dependency-update.yaml +++ b/.github/workflows/dependency-update.yaml @@ -17,7 +17,7 @@ jobs: uses: actions/checkout@v4.2.2 # https://github.com/renovatebot/github-action - name: self-hosted renovate - uses: renovatebot/github-action@v41.0.18 + uses: renovatebot/github-action@v41.0.20 with: # https://docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/json-yaml-validate.yml b/.github/workflows/json-yaml-validate.yml index 8aeb600c6..7cf8d2503 100644 --- a/.github/workflows/json-yaml-validate.yml +++ b/.github/workflows/json-yaml-validate.yml @@ -17,7 +17,7 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: json-yaml-validate - uses: GrantBirki/json-yaml-validate@v3.2.1 + uses: GrantBirki/json-yaml-validate@v3.3.0 with: comment: "true" # enable comment mode yaml_exclude_regex: "(charts/external-dns/templates.*|mkdocs.yml)" From 8e695e68b1b25bb84ce6a84da8b43205ee00de93 Mon Sep 17 00:00:00 2001 From: Michel Loiseleur <97035654+mloiseleur@users.noreply.github.com> Date: Mon, 21 Apr 2025 23:19:41 +0200 Subject: [PATCH 06/42] chore(deps): bump the dev-dependencies group across 1 directory with 21 updates (#5313) * chore(deps): bump the dev-dependencies group across 1 directory with 21 updates Bumps the dev-dependencies group with 18 updates in the / directory: | Package | From | To | | --- | --- | --- | | [github.com/Azure/azure-sdk-for-go/sdk/azidentity](https://github.com/Azure/azure-sdk-for-go) | `1.8.2` | `1.9.0` | | [github.com/IBM-Cloud/ibm-cloud-cli-sdk](https://github.com/IBM-Cloud/ibm-cloud-cli-sdk) | `1.7.0` | `1.7.1` | | [github.com/IBM/go-sdk-core/v5](https://github.com/IBM/go-sdk-core) | `5.19.0` | `5.19.1` | | [github.com/IBM/networking-go-sdk](https://github.com/IBM/networking-go-sdk) | `0.51.3` | `0.51.4` | | [github.com/Yamashou/gqlgenc](https://github.com/Yamashou/gqlgenc) | `0.31.0` | `0.32.0` | | [github.com/aliyun/alibaba-cloud-sdk-go](https://github.com/aliyun/alibaba-cloud-sdk-go) | `1.63.104` | `1.63.105` | | [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2) | `1.29.13` | `1.29.14` | | [github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue](https://github.com/aws/aws-sdk-go-v2) | `1.18.9` | `1.18.12` | | [github.com/aws/aws-sdk-go-v2/service/route53](https://github.com/aws/aws-sdk-go-v2) | `1.51.0` | `1.51.1` | | [github.com/aws/aws-sdk-go-v2/service/servicediscovery](https://github.com/aws/aws-sdk-go-v2) | `1.35.2` | `1.35.3` | | [github.com/civo/civogo](https://github.com/civo/civogo) | `0.3.96` | `0.3.98` | | [github.com/oracle/oci-go-sdk/v65](https://github.com/oracle/oci-go-sdk) | `65.88.1` | `65.89.1` | | [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) | `1.21.1` | `1.22.0` | | [github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common](https://github.com/tencentcloud/tencentcloud-sdk-go) | `1.0.1140` | `1.0.1146` | | [github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns](https://github.com/tencentcloud/tencentcloud-sdk-go) | `1.0.1132` | `1.0.1145` | | [google.golang.org/api](https://github.com/googleapis/google-api-go-client) | `0.228.0` | `0.229.0` | | [istio.io/api](https://github.com/istio/api) | `1.25.1` | `1.25.2` | | [istio.io/client-go](https://github.com/istio/client-go) | `1.25.1` | `1.25.2` | Updates `github.com/Azure/azure-sdk-for-go/sdk/azidentity` from 1.8.2 to 1.9.0 - [Release notes](https://github.com/Azure/azure-sdk-for-go/releases) - [Changelog](https://github.com/Azure/azure-sdk-for-go/blob/main/documentation/release.md) - [Commits](https://github.com/Azure/azure-sdk-for-go/compare/sdk/azidentity/v1.8.2...sdk/azcore/v1.9.0) Updates `github.com/IBM-Cloud/ibm-cloud-cli-sdk` from 1.7.0 to 1.7.1 - [Release notes](https://github.com/IBM-Cloud/ibm-cloud-cli-sdk/releases) - [Commits](https://github.com/IBM-Cloud/ibm-cloud-cli-sdk/compare/v1.7.0...v1.7.1) Updates `github.com/IBM/go-sdk-core/v5` from 5.19.0 to 5.19.1 - [Release notes](https://github.com/IBM/go-sdk-core/releases) - [Changelog](https://github.com/IBM/go-sdk-core/blob/main/CHANGELOG.md) - [Commits](https://github.com/IBM/go-sdk-core/compare/v5.19.0...v5.19.1) Updates `github.com/IBM/networking-go-sdk` from 0.51.3 to 0.51.4 - [Release notes](https://github.com/IBM/networking-go-sdk/releases) - [Changelog](https://github.com/IBM/networking-go-sdk/blob/master/CHANGELOG.md) - [Commits](https://github.com/IBM/networking-go-sdk/compare/v0.51.3...v0.51.4) Updates `github.com/Yamashou/gqlgenc` from 0.31.0 to 0.32.0 - [Release notes](https://github.com/Yamashou/gqlgenc/releases) - [Commits](https://github.com/Yamashou/gqlgenc/compare/v0.31.0...v0.32.0) Updates `github.com/aliyun/alibaba-cloud-sdk-go` from 1.63.104 to 1.63.105 - [Release notes](https://github.com/aliyun/alibaba-cloud-sdk-go/releases) - [Changelog](https://github.com/aliyun/alibaba-cloud-sdk-go/blob/master/ChangeLog.txt) - [Commits](https://github.com/aliyun/alibaba-cloud-sdk-go/compare/v1.63.104...v1.63.105) Updates `github.com/aws/aws-sdk-go-v2/config` from 1.29.13 to 1.29.14 - [Release notes](https://github.com/aws/aws-sdk-go-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json) - [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.29.13...config/v1.29.14) Updates `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.66 to 1.17.67 - [Release notes](https://github.com/aws/aws-sdk-go-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json) - [Commits](https://github.com/aws/aws-sdk-go-v2/compare/credentials/v1.17.66...credentials/v1.17.67) Updates `github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue` from 1.18.9 to 1.18.12 - [Release notes](https://github.com/aws/aws-sdk-go-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json) - [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.18.9...config/v1.18.12) Updates `github.com/aws/aws-sdk-go-v2/service/dynamodb` from 1.42.1 to 1.42.4 - [Release notes](https://github.com/aws/aws-sdk-go-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json) - [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/s3/v1.42.1...service/ivs/v1.42.4) Updates `github.com/aws/aws-sdk-go-v2/service/route53` from 1.51.0 to 1.51.1 - [Release notes](https://github.com/aws/aws-sdk-go-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json) - [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/s3/v1.51.0...service/s3/v1.51.1) Updates `github.com/aws/aws-sdk-go-v2/service/servicediscovery` from 1.35.2 to 1.35.3 - [Release notes](https://github.com/aws/aws-sdk-go-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json) - [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/ecr/v1.35.2...service/ivs/v1.35.3) Updates `github.com/aws/aws-sdk-go-v2/service/sts` from 1.33.18 to 1.33.19 - [Release notes](https://github.com/aws/aws-sdk-go-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json) - [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/sns/v1.33.18...service/sns/v1.33.19) Updates `github.com/civo/civogo` from 0.3.96 to 0.3.98 - [Release notes](https://github.com/civo/civogo/releases) - [Changelog](https://github.com/civo/civogo/blob/master/changelog.yml) - [Commits](https://github.com/civo/civogo/compare/v0.3.96...v0.3.98) Updates `github.com/oracle/oci-go-sdk/v65` from 65.88.1 to 65.89.1 - [Release notes](https://github.com/oracle/oci-go-sdk/releases) - [Changelog](https://github.com/oracle/oci-go-sdk/blob/master/CHANGELOG.md) - [Commits](https://github.com/oracle/oci-go-sdk/compare/v65.88.1...v65.89.1) Updates `github.com/prometheus/client_golang` from 1.21.1 to 1.22.0 - [Release notes](https://github.com/prometheus/client_golang/releases) - [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md) - [Commits](https://github.com/prometheus/client_golang/compare/v1.21.1...v1.22.0) Updates `github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common` from 1.0.1140 to 1.0.1146 - [Changelog](https://github.com/TencentCloud/tencentcloud-sdk-go/blob/master/SERVICE_CHANGELOG.md) - [Commits](https://github.com/tencentcloud/tencentcloud-sdk-go/compare/v1.0.1140...v1.0.1146) Updates `github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns` from 1.0.1132 to 1.0.1145 - [Changelog](https://github.com/TencentCloud/tencentcloud-sdk-go/blob/v1.0.1145/SERVICE_CHANGELOG.md) - [Commits](https://github.com/tencentcloud/tencentcloud-sdk-go/compare/v1.0.1132...v1.0.1145) Updates `google.golang.org/api` from 0.228.0 to 0.229.0 - [Release notes](https://github.com/googleapis/google-api-go-client/releases) - [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md) - [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.228.0...v0.229.0) Updates `istio.io/api` from 1.25.1 to 1.25.2 - [Commits](https://github.com/istio/api/compare/1.25.1...1.25.2) Updates `istio.io/client-go` from 1.25.1 to 1.25.2 - [Commits](https://github.com/istio/client-go/compare/1.25.1...1.25.2) --- updated-dependencies: - dependency-name: github.com/Azure/azure-sdk-for-go/sdk/azidentity dependency-version: 1.9.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dev-dependencies - dependency-name: github.com/IBM-Cloud/ibm-cloud-cli-sdk dependency-version: 1.7.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: github.com/IBM/go-sdk-core/v5 dependency-version: 5.19.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: github.com/IBM/networking-go-sdk dependency-version: 0.51.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: github.com/Yamashou/gqlgenc dependency-version: 0.32.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dev-dependencies - dependency-name: github.com/aliyun/alibaba-cloud-sdk-go dependency-version: 1.63.105 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: github.com/aws/aws-sdk-go-v2/config dependency-version: 1.29.14 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: github.com/aws/aws-sdk-go-v2/credentials dependency-version: 1.17.67 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue dependency-version: 1.18.12 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: github.com/aws/aws-sdk-go-v2/service/dynamodb dependency-version: 1.42.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: github.com/aws/aws-sdk-go-v2/service/route53 dependency-version: 1.51.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: github.com/aws/aws-sdk-go-v2/service/servicediscovery dependency-version: 1.35.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: github.com/aws/aws-sdk-go-v2/service/sts dependency-version: 1.33.19 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: github.com/civo/civogo dependency-version: 0.3.98 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: github.com/oracle/oci-go-sdk/v65 dependency-version: 65.89.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dev-dependencies - dependency-name: github.com/prometheus/client_golang dependency-version: 1.22.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dev-dependencies - dependency-name: github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common dependency-version: 1.0.1146 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns dependency-version: 1.0.1145 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: google.golang.org/api dependency-version: 0.229.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dev-dependencies - dependency-name: istio.io/api dependency-version: 1.25.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: istio.io/client-go dependency-version: 1.25.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dev-dependencies ... Signed-off-by: dependabot[bot] * fix: ci --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yaml | 1 + go.mod | 75 ++++++++-------- go.sum | 176 +++++++++++++++++++------------------- 3 files changed, 126 insertions(+), 126 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 777270ffe..73f0c926a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -27,6 +27,7 @@ jobs: uses: actions/setup-go@v5 with: go-version-file: go.mod + check-latest: true id: go - name: Install CI diff --git a/go.mod b/go.mod index 5e9a221ab..0dc59e851 100644 --- a/go.mod +++ b/go.mod @@ -1,34 +1,32 @@ module sigs.k8s.io/external-dns -go 1.24.0 - -toolchain go1.24.2 +go 1.24.2 require ( cloud.google.com/go/compute/metadata v0.6.0 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.3.0 github.com/F5Networks/k8s-bigip-ctlr/v2 v2.19.1 - github.com/IBM-Cloud/ibm-cloud-cli-sdk v1.7.0 - github.com/IBM/go-sdk-core/v5 v5.19.0 - github.com/IBM/networking-go-sdk v0.51.3 - github.com/Yamashou/gqlgenc v0.31.0 + github.com/IBM-Cloud/ibm-cloud-cli-sdk v1.7.1 + github.com/IBM/go-sdk-core/v5 v5.19.1 + github.com/IBM/networking-go-sdk v0.51.4 + github.com/Yamashou/gqlgenc v0.32.0 github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 github.com/alecthomas/kingpin/v2 v2.4.0 - github.com/aliyun/alibaba-cloud-sdk-go v1.63.104 + github.com/aliyun/alibaba-cloud-sdk-go v1.63.106 github.com/aws/aws-sdk-go-v2 v1.36.3 - github.com/aws/aws-sdk-go-v2/config v1.29.13 - github.com/aws/aws-sdk-go-v2/credentials v1.17.66 - github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.18.9 - github.com/aws/aws-sdk-go-v2/service/dynamodb v1.42.1 - github.com/aws/aws-sdk-go-v2/service/route53 v1.51.0 - github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.35.2 - github.com/aws/aws-sdk-go-v2/service/sts v1.33.18 + github.com/aws/aws-sdk-go-v2/config v1.29.14 + github.com/aws/aws-sdk-go-v2/credentials v1.17.67 + github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.18.12 + github.com/aws/aws-sdk-go-v2/service/dynamodb v1.42.4 + github.com/aws/aws-sdk-go-v2/service/route53 v1.51.1 + github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.35.4 + github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 github.com/bodgit/tsig v1.2.2 github.com/cenkalti/backoff/v4 v4.3.0 - github.com/civo/civogo v0.3.96 + github.com/civo/civogo v0.3.98 github.com/cloudflare/cloudflare-go v0.115.0 github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381 github.com/datawire/ambassador v1.12.4 @@ -49,19 +47,19 @@ require ( github.com/onsi/ginkgo v1.16.5 github.com/openshift/api v0.0.0-20230607130528-611114dca681 github.com/openshift/client-go v0.0.0-20230607134213-3cd0021bbee3 - github.com/oracle/oci-go-sdk/v65 v65.88.1 + github.com/oracle/oci-go-sdk/v65 v65.89.1 github.com/ovh/go-ovh v1.7.0 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pkg/errors v0.9.1 github.com/pluralsh/gqlclient v1.12.2 github.com/projectcontour/contour v1.30.3 - github.com/prometheus/client_golang v1.21.1 + github.com/prometheus/client_golang v1.22.0 github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.10.0 - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1140 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1146 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1136 - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns v1.0.1132 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns v1.0.1145 github.com/transip/gotransip/v6 v6.26.0 github.com/ultradns/ultradns-sdk-go v1.3.7 go.etcd.io/etcd/client/v3 v3.5.21 @@ -71,10 +69,10 @@ require ( golang.org/x/sync v0.13.0 golang.org/x/text v0.24.0 golang.org/x/time v0.11.0 - google.golang.org/api v0.228.0 + google.golang.org/api v0.229.0 gopkg.in/ns1/ns1-go.v2 v2.14.2 - istio.io/api v1.25.1 - istio.io/client-go v1.25.1 + istio.io/api v1.25.2 + istio.io/client-go v1.25.2 k8s.io/api v0.32.3 k8s.io/apimachinery v0.32.3 k8s.io/client-go v0.32.3 @@ -83,11 +81,11 @@ require ( ) require ( - cloud.google.com/go/auth v0.15.0 // indirect + cloud.google.com/go/auth v0.16.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f // indirect - github.com/99designs/gqlgen v0.17.61 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.0 // indirect + github.com/99designs/gqlgen v0.17.70 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect github.com/Masterminds/semver v1.4.2 // indirect github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect @@ -97,7 +95,7 @@ require ( github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect - github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.25.2 // indirect + github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.25.3 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.15 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect @@ -125,7 +123,7 @@ require ( github.com/go-openapi/swag v0.23.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.24.0 // indirect + github.com/go-playground/validator/v10 v10.26.0 // indirect github.com/go-resty/resty/v2 v2.16.5 // indirect github.com/goccy/go-json v0.10.5 // indirect github.com/gofrs/flock v0.8.1 // indirect @@ -156,7 +154,6 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.11 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect @@ -185,7 +182,7 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/terra-farm/udnssdk v1.3.5 // indirect - github.com/vektah/gqlparser/v2 v2.5.20 // indirect + github.com/vektah/gqlparser/v2 v2.5.24 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect @@ -193,21 +190,21 @@ require ( go.etcd.io/etcd/client/pkg/v3 v3.5.21 // indirect go.mongodb.org/mongo-driver v1.17.2 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect - go.opentelemetry.io/otel v1.34.0 // indirect - go.opentelemetry.io/otel/metric v1.34.0 // indirect - go.opentelemetry.io/otel/trace v1.34.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect + go.opentelemetry.io/otel v1.35.0 // indirect + go.opentelemetry.io/otel/metric v1.35.0 // indirect + go.opentelemetry.io/otel/trace v1.35.0 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect golang.org/x/crypto v0.37.0 // indirect - golang.org/x/mod v0.23.0 // indirect + golang.org/x/mod v0.24.0 // indirect golang.org/x/sys v0.32.0 // indirect golang.org/x/term v0.31.0 // indirect - golang.org/x/tools v0.30.0 // indirect + golang.org/x/tools v0.32.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 // indirect - google.golang.org/grpc v1.71.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e // indirect + google.golang.org/grpc v1.71.1 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/go.sum b/go.sum index 4f7be2509..762a4b0f0 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxo cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go/auth v0.15.0 h1:Ly0u4aA5vG/fsSsxu98qCQBemXtAtJf+95z9HK+cxps= -cloud.google.com/go/auth v0.15.0/go.mod h1:WJDGqZ1o9E9wKIL+IwStfyn/+s59zl4Bi+1KQNVXLZ8= +cloud.google.com/go/auth v0.16.0 h1:Pd8P1s9WkcrBE2n/PhAwKsdrR35V3Sg2II9B+ndM3CU= +cloud.google.com/go/auth v0.16.0/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= @@ -12,18 +12,18 @@ code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f h1:UrKzEwTg code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f/go.mod h1:sk5LnIjB/nIEU7yP5sDQExVm62wu0pBh3yrElngUisI= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= git.lukeshu.com/go/libsystemd v0.5.3/go.mod h1:FfDoP0i92r4p5Vn4NCLxvjkd7rCOe6otPa4L6hZg9WM= -github.com/99designs/gqlgen v0.17.61 h1:vE7xLRC066n9wehgjeplILOWtwz75zbzcV2/Iv9i3pw= -github.com/99designs/gqlgen v0.17.61/go.mod h1:rFU1T3lhv/tPeAlww/DJ4ol2YxT/pPpue+xxPbkd3r4= +github.com/99designs/gqlgen v0.17.70 h1:xgLIgQuG+Q2L/AE9cW595CT7xCWCe/bpPIFGSfsGSGs= +github.com/99designs/gqlgen v0.17.70/go.mod h1:fvCiqQAu2VLhKXez2xFvLmE47QgAPf/KTPN5XQ4rsHQ= github.com/Azure/azure-sdk-for-go v16.2.1+incompatible h1:KnPIugL51v3N3WwvaSmZbxukD1WuWXOiE9fRdu32f2I= github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 h1:Gt0j3wceWMwPmiazCa8MzMA0MfhmPIz0Qp0FJ6qcM0U= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 h1:F0gBpfdPLGsw+nsgk6aqqkZS1jiixa5WwFe3fk/T3Ys= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2/go.mod h1:SqINnQ9lVVdRlyC8cd1lCI0SdX4n2paeABd2K8ggfnE= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0 h1:OVoM452qUFBrX+URdH3VpR299ma4kfom0yB0URYky9g= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0/go.mod h1:kUjrAo8bgEwLeZ/CmHqNl3Z/kPm7y6FKfxxK0izYUg4= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.0 h1:Bg8m3nq/X1DeePkAbCfb6ml6F3F0IunEhE8TMh+lY48= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.0/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 h1:FPKJS1T+clwv+OLGt13a8UjqeRuh0O4SJ3lUriThc+4= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 h1:lpOxwrQ919lCZoNCd69rVt8u1eLZuMORrGXqy8sNf3c= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0/go.mod h1:fSvRkb8d26z9dbL40Uf/OO6Vo9iExtZK3D0ulRV+8M0= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v3 v3.1.0 h1:2qsIIvxVT+uE6yrNldntJKlLRgxGbZ85kgtz5SNBhMw= @@ -51,12 +51,12 @@ github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q github.com/F5Networks/k8s-bigip-ctlr/v2 v2.19.1 h1:NHWjSBeXbL8mlx+0QyCl4OrUvytCZ3nkEIRqX7t97wQ= github.com/F5Networks/k8s-bigip-ctlr/v2 v2.19.1/go.mod h1:JwdtGjHFTmUM1zjzvvCotCCyP55S146IuVPOJZ7D/Jw= github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= -github.com/IBM-Cloud/ibm-cloud-cli-sdk v1.7.0 h1:VMMr9Yu2QkIdXtQfi3v/+qoqlnzUuFx7vfU+GDfuhh0= -github.com/IBM-Cloud/ibm-cloud-cli-sdk v1.7.0/go.mod h1:+fXHt9ZUw/AlSAHvQXkTcEMKXLVwSBvA7uReQXqDwmU= -github.com/IBM/go-sdk-core/v5 v5.19.0 h1:YN2S5JUvq/EwYulmcNFwgyYBxZhVWl9nkY22H7Hpghw= -github.com/IBM/go-sdk-core/v5 v5.19.0/go.mod h1:deZO1J5TSlU69bCnl/YV7nPxFZA2UEaup7cq/7ZTOgw= -github.com/IBM/networking-go-sdk v0.51.3 h1:GW2VLP7XVcAHin6eWnCNA9l3gsv5tnyjf5UgGwMA7hk= -github.com/IBM/networking-go-sdk v0.51.3/go.mod h1:T27XI2gtPjT7tW9nkHgrpBUNbmAc9OR41Z78Y493PoA= +github.com/IBM-Cloud/ibm-cloud-cli-sdk v1.7.1 h1:O9CXYO4upLrGlxFTZBW91yFdpWkHblezhbuKS/JjaVg= +github.com/IBM-Cloud/ibm-cloud-cli-sdk v1.7.1/go.mod h1:L1O3/tOKGedJ8db8i0KAgGBUHp8Fb0/00Lc8ebnj0DM= +github.com/IBM/go-sdk-core/v5 v5.19.1 h1:sleVks1O4XjgF4YEGvyDh6PZbP6iZhlTPeDkQc8nWDs= +github.com/IBM/go-sdk-core/v5 v5.19.1/go.mod h1:Q3BYO6iDA2zweQPDGbNTtqft5tDcEpm6RTuqMlPcvbw= +github.com/IBM/networking-go-sdk v0.51.4 h1:rkbR+gUkksLKjNYL5YEWEAMv3qddR0mUkxObDMa4l/s= +github.com/IBM/networking-go-sdk v0.51.4/go.mod h1:gjCFEp+UVP7FUlcq2C1RaoZAXFcD39CQdlUk7uVKko4= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= @@ -81,8 +81,8 @@ github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:H github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/Yamashou/gqlgenc v0.31.0 h1:t54Gi6Zx9Ub1oa/RvJ+DkOC1c2wdK1R4n7wyRBuQkyc= -github.com/Yamashou/gqlgenc v0.31.0/go.mod h1:0VNZtzXhyDofkNNZXXPw8LSLvi3vyG6LXo7XvcWv2X4= +github.com/Yamashou/gqlgenc v0.32.0 h1:f5Ebm9RG5jCL1iXxUN5X6e7Fgo/p3eQIDEaf0JO0GgQ= +github.com/Yamashou/gqlgenc v0.32.0/go.mod h1:DExQmcD8yilMdtLdLWLofPrbWuxKjaf6HFZdG49i3EA= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= @@ -98,8 +98,8 @@ github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAu github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5 h1:P5U+E4x5OkVEKQDklVPmzs71WM56RTTRqV4OrDC//Y4= github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5/go.mod h1:976q2ETgjT2snVCf2ZaBnyBbVoPERGjUz+0sofzEfro= -github.com/aliyun/alibaba-cloud-sdk-go v1.63.104 h1:/6jF6rhmKZzvZZhzFXWqATazSKL5OSv7p+8PfoT6MG0= -github.com/aliyun/alibaba-cloud-sdk-go v1.63.104/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ= +github.com/aliyun/alibaba-cloud-sdk-go v1.63.106 h1:+YPfQheppCKOPJxhWDmStF1UMJrxnA1iiwBH12t6Fa4= +github.com/aliyun/alibaba-cloud-sdk-go v1.63.106/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/andybalholm/brotli v0.0.0-20190621154722-5f990b63d2d6/go.mod h1:+lx6/Aqd1kLJ1GQfkvOnaZ1WGmLpMpbprPuIOOZX30U= @@ -123,12 +123,12 @@ github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM= github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg= -github.com/aws/aws-sdk-go-v2/config v1.29.13 h1:RgdPqWoE8nPpIekpVpDJsBckbqT4Liiaq9f35pbTh1Y= -github.com/aws/aws-sdk-go-v2/config v1.29.13/go.mod h1:NI28qs/IOUIRhsR7GQ/JdexoqRN9tDxkIrYZq0SOF44= -github.com/aws/aws-sdk-go-v2/credentials v1.17.66 h1:aKpEKaTy6n4CEJeYI1MNj97oSDLi4xro3UzQfwf5RWE= -github.com/aws/aws-sdk-go-v2/credentials v1.17.66/go.mod h1:xQ5SusDmHb/fy55wU0QqTy0yNfLqxzec59YcsRZB+rI= -github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.18.9 h1:EU6VkY8G4N+IFl0D2Cd9LcUeJHyNdLJAbHfMD9v5GHQ= -github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.18.9/go.mod h1:JlH7zEPanxEEBLAAnKBRNZz+nrxTTMVKO40P5+umoUQ= +github.com/aws/aws-sdk-go-v2/config v1.29.14 h1:f+eEi/2cKCg9pqKBoAIwRGzVb70MRKqWX4dg1BDcSJM= +github.com/aws/aws-sdk-go-v2/config v1.29.14/go.mod h1:wVPHWcIFv3WO89w0rE10gzf17ZYy+UVS1Geq8Iei34g= +github.com/aws/aws-sdk-go-v2/credentials v1.17.67 h1:9KxtdcIA/5xPNQyZRgUSpYOE6j9Bc4+D7nZua0KGYOM= +github.com/aws/aws-sdk-go-v2/credentials v1.17.67/go.mod h1:p3C44m+cfnbv763s52gCqrjaqyPikj9Sg47kUVaNZQQ= +github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.18.12 h1:mwAIR3fhxhSzXFj530LNCBe0JocYVQx6GuJpQiA+QOs= +github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.18.12/go.mod h1:9cWrNL8q7ApFmZzKhnb63ub4zrdMzOGQVn/kxvagfeE= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 h1:x793wxmUWVDhshP8WW2mlnXuFrO4cOd3HLBroh1paFw= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30/go.mod h1:Jpne2tDnYiFascUEs2AWHJL9Yp7A5ZVy3TNyxaAjD6M= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q= @@ -137,26 +137,26 @@ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0io github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= -github.com/aws/aws-sdk-go-v2/service/dynamodb v1.42.1 h1:67oYHlAdIoWS65kdTKatf9o1eDNkR2wan6TlBdP3oe4= -github.com/aws/aws-sdk-go-v2/service/dynamodb v1.42.1/go.mod h1:yYaWRnVSPyAmexW5t7G3TcuYoalYfT+xQwzWsvtUQ7M= -github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.25.2 h1:D1Af/NlGfG2/8S3EY/hCUlvPcfu2UrX4+XaGeiFzJQM= -github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.25.2/go.mod h1:lUqWdw5/esjPTkITXhN4C66o1ltwDq2qQ12j3SOzhVg= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.42.4 h1:5GjCSGIpndYU/tVABz+4XnAcluU6wrjlPzAAgFUDG98= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.42.4/go.mod h1:yYaWRnVSPyAmexW5t7G3TcuYoalYfT+xQwzWsvtUQ7M= +github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.25.3 h1:GHC1WTF3ZBZy+gvz2qtYB6ttALVx35hlwc4IzOIUY7g= +github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.25.3/go.mod h1:lUqWdw5/esjPTkITXhN4C66o1ltwDq2qQ12j3SOzhVg= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.15 h1:M1R1rud7HzDrfCdlBQ7NjnRsDNEhXO/vGhuD189Ggmk= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.15/go.mod h1:uvFKBSq9yMPV4LGAi7N4awn4tLY+hKE35f8THes2mzQ= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2F1JbDaGooxTq18wmmFzbJRfXfVfy96/1CXM= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15/go.mod h1:SwFBy2vjtA0vZbjjaFtfN045boopadnoVPhu4Fv66vY= -github.com/aws/aws-sdk-go-v2/service/route53 v1.51.0 h1:pK3YJIgOzYqctprqQ67kGSjeL+77r9Ue/4/gBonsGNc= -github.com/aws/aws-sdk-go-v2/service/route53 v1.51.0/go.mod h1:kGYOjvTa0Vw0qxrqrOLut1vMnui6qLxqv/SX3vYeM8Y= -github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.35.2 h1:KDXGFjFqMc31WyGljYA1Jb6yMH+YS22iC32NcYR8mZ8= -github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.35.2/go.mod h1:IbC8X3WZvsN+w48OrHBDUKcVnhhzO1YpXkCkFlr0qs8= +github.com/aws/aws-sdk-go-v2/service/route53 v1.51.1 h1:41HrH51fydStW2Tah74zkqZlJfyx4gXeuGOdsIFuckY= +github.com/aws/aws-sdk-go-v2/service/route53 v1.51.1/go.mod h1:kGYOjvTa0Vw0qxrqrOLut1vMnui6qLxqv/SX3vYeM8Y= +github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.35.4 h1:zZvziql5vgfDs2hTfF8fRF4pySG7A28/qNJQihJvpwc= +github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.35.4/go.mod h1:IbC8X3WZvsN+w48OrHBDUKcVnhhzO1YpXkCkFlr0qs8= github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 h1:1Gw+9ajCV1jogloEv1RRnvfRFia2cL6c9cuKV2Ps+G8= github.com/aws/aws-sdk-go-v2/service/sso v1.25.3/go.mod h1:qs4a9T5EMLl/Cajiw2TcbNt2UNo/Hqlyp+GiuG4CFDI= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 h1:hXmVKytPfTy5axZ+fYbR5d0cFmC3JvwLm5kM83luako= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1/go.mod h1:MlYRNmYu/fGPoxBQVvBYr9nyr948aY/WLUvwBMBJubs= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.18 h1:xz7WvTMfSStb9Y8NpCT82FXLNC3QasqBfuAFHY4Pk5g= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.18/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 h1:1XuUZ8mYJw9B6lzAkXhqHlJd/XvaX32evhproijJEZY= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.19/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4= github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ= github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= @@ -187,8 +187,8 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= -github.com/civo/civogo v0.3.96 h1:9R3yZS3B8B0oAqIlNDnMvsONk0mqZUkHREd0EH6HRIc= -github.com/civo/civogo v0.3.96/go.mod h1:LaEbkszc+9nXSh4YNG0sYXFGYqdQFmXXzQg0gESs2hc= +github.com/civo/civogo v0.3.98 h1:FEbB5oxCcHeHUK3fJODxVoMQzhpLV9Jtb7bezANTY5c= +github.com/civo/civogo v0.3.98/go.mod h1:LaEbkszc+9nXSh4YNG0sYXFGYqdQFmXXzQg0gESs2hc= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.115.0 h1:84/dxeeXweCc0PN5Cto44iTA8AkG1fyT11yPO5ZB7sM= @@ -418,8 +418,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-playground/validator/v10 v10.9.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= -github.com/go-playground/validator/v10 v10.24.0 h1:KHQckvo8G6hlWnrPX4NJJ+aBfWNAE/HH+qdL2cBpCmg= -github.com/go-playground/validator/v10 v10.24.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus= +github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= +github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM= github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -650,16 +650,16 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= -github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs= -github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw= +github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU= +github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= -github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/pgzip v1.2.1/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -724,8 +724,8 @@ github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIG github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= @@ -810,16 +810,16 @@ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.23.0 h1:FA1xjp8ieYDzlgS5ABTpdUDB7wtngggONc8a7ku2NqQ= -github.com/onsi/ginkgo/v2 v2.23.0/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM= +github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus= +github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= -github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= +github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= +github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -848,8 +848,8 @@ github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxS github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/oracle/oci-go-sdk/v65 v65.88.1 h1:Y9Y5jlQX8oVDe3UN+O4IcQnLN/aQmi4jR1/2RsXMN3M= -github.com/oracle/oci-go-sdk/v65 v65.88.1/go.mod h1:u6XRPsw9tPziBh76K7GrrRXPa8P8W3BQeqJ6ZZt9VLA= +github.com/oracle/oci-go-sdk/v65 v65.89.1 h1:8sVjxYPNQ83yqUgZKkdeUA0CnSodmL1Bme2oxq8gyKg= +github.com/oracle/oci-go-sdk/v65 v65.89.1/go.mod h1:u6XRPsw9tPziBh76K7GrrRXPa8P8W3BQeqJ6ZZt9VLA= github.com/ovh/go-ovh v1.7.0 h1:V14nF7FwDjQrZt9g7jzcvAAQ3HN6DNShRFRMC3jLoPw= github.com/ovh/go-ovh v1.7.0/go.mod h1:cTVDnl94z4tl8pP1uZ/8jlVxntjSIf09bNcQ5TJSC7c= github.com/oxtoacart/bpool v0.0.0-20150712133111-4e1c5567d7c2 h1:CXwSGu/LYmbjEab5aMCs5usQRVBGThelUKBNnoSOuso= @@ -893,8 +893,8 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= -github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= -github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= +github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -925,8 +925,8 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E= -github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw= +github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM= +github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= @@ -1018,14 +1018,14 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1132/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1136/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1140 h1:F/vuesfLQmJhBZTHYOktz8IVWTs1nHwZYh74/H64uEs= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1140/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1145/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1146 h1:PMhgU4BETyTiikegps6gDtLamNWUiLMEx4fv16UWspY= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1146/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1136 h1:kMIdSU5IvpOROh27ToVQ3hlm6ym3lCRs9tnGCOBoZqk= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1136/go.mod h1:FpyIz3mymKaExVs6Fz27kxDBS42jqZn7vbACtxdeEH4= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns v1.0.1132 h1:YjVToKgm2V8aUxiDahVEFOvXYgswXiROUhrfSc3jamE= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns v1.0.1132/go.mod h1:2xDMNe2ohV2hRBldVgv++eByAhj3vSMnh0xl9jRFiEU= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns v1.0.1145 h1:K5N0Uxqm9kM7KU6DFBekCTKbldlXq6UD1ekOyXn4zEc= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns v1.0.1145/go.mod h1:mgwxarWzLxIylWtHmkoMg0dX8aqhO5lwfrHkK4IGLKE= github.com/terra-farm/udnssdk v1.3.5 h1:MNR3adfuuEK/l04+jzo8WW/0fnorY+nW515qb3vEr6I= github.com/terra-farm/udnssdk v1.3.5/go.mod h1:8RnM56yZTR7mYyUIvrDgXzdRaEyFIzqdEi7+um26Sv8= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= @@ -1052,8 +1052,8 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= -github.com/vektah/gqlparser/v2 v2.5.20 h1:kPaWbhBntxoZPaNdBaIPT1Kh0i1b/onb5kXgEdP5JCo= -github.com/vektah/gqlparser/v2 v2.5.20/go.mod h1:xMl+ta8a5M1Yo1A1Iwt/k7gSpscwSnHZdw7tfhEGfTM= +github.com/vektah/gqlparser/v2 v2.5.24 h1:Dnip1ilW+nnXmaXL6s6f1w4IaXpAFDLLE1f9SqMegpI= +github.com/vektah/gqlparser/v2 v2.5.24/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -1098,24 +1098,26 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I= -go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= -go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= -go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= -go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= -go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= -go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= -go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= -go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= -go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= -go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ= +go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= +go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= +go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= +go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= +go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= +go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= +go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o= +go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= +go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= +go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= +go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= @@ -1182,8 +1184,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= +golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1366,8 +1368,8 @@ golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= +golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU= +golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1380,8 +1382,8 @@ gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZ google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.228.0 h1:X2DJ/uoWGnY5obVjewbp8icSL5U4FzuCfy9OjbLSnLs= -google.golang.org/api v0.228.0/go.mod h1:wNvRS1Pbe8r4+IfBIniV8fwCpGwTrYa+kMUDiC5z5a4= +google.golang.org/api v0.229.0 h1:p98ymMtqeJ5i3lIBMj5MpR9kzIIgzpHHh8vQ+vgAzx8= +google.golang.org/api v0.229.0/go.mod h1:wyDfmq5g1wYJWn29O22FDWN48P7Xcz0xz+LBpptYvB0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1397,8 +1399,8 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 h1:GVIKPyP/kLIyVOgOnTwFOrvQaQUzOzGMCxgFUOEmm24= google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422/go.mod h1:b6h1vNKhxaSoEI+5jc3PJUCustfli/mRab7295pY7rw= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 h1:iK2jbkWL86DXjEx0qiHcRE9dE4/Ahua5k6V8OWFb//c= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e h1:ztQaXfzEXTmCBvbtWYRhJxW+0iJcz2qXfd38/e9l7bA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1412,8 +1414,8 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg= -google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= +google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI= +google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1480,10 +1482,10 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -istio.io/api v1.25.1 h1:l3JS6Rh4bH+6ox84hRvtsJsr7gMJLsoJG2BQZGbXRyc= -istio.io/api v1.25.1/go.mod h1:QFzEXv/IT582T0FHZVp1QoolvE4ws0zz/vVO55blmlE= -istio.io/client-go v1.25.1 h1:1Asibz5v2NBA6w4Sqa85NS7TkpEolZcPKAT5oUAXWi8= -istio.io/client-go v1.25.1/go.mod h1:Vap9OyHJMvvDegYoZczcNybS4wbPaTk+4bZcWMb8+vE= +istio.io/api v1.25.2 h1:FCRQy7iaTreKJdLemlQ1vRJEsf1soCHoTAuSf68w5I8= +istio.io/api v1.25.2/go.mod h1:QFzEXv/IT582T0FHZVp1QoolvE4ws0zz/vVO55blmlE= +istio.io/client-go v1.25.2 h1:faupTqeMD0PkuNTZdFlpxxT35jBSQapK5k+MNAkXvqA= +istio.io/client-go v1.25.2/go.mod h1:E2LTxTcCVe4cqpKy4/9Y4VmwSoLiH6ff9MEG7EhfSDo= k8s.io/api v0.18.0/go.mod h1:q2HRQkfDzHMBZL9l/y9rH63PkQl4vae0xRT+8prbrK8= k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= k8s.io/api v0.18.4/go.mod h1:lOIQAKYgai1+vz9J7YcDZwC26Z0zQewYOGWdyIPUUQ4= From abdf8bbc028655d6f931082663865f6efc301bc2 Mon Sep 17 00:00:00 2001 From: ivan katliarchuk Date: Wed, 23 Apr 2025 08:22:43 +0100 Subject: [PATCH 07/42] chore(refactore): added lint checks Signed-off-by: ivan katliarchuk --- .golangci.yml | 6 ++- plan/conflict.go | 10 ++--- provider/akamai/akamai.go | 10 +---- provider/alibabacloud/alibaba_cloud_test.go | 40 ++++++++----------- provider/aws/aws.go | 36 ++++++++--------- provider/azure/config_test.go | 2 +- .../azure/{ => fixtures}/config_test.json | 14 +++---- provider/exoscale/exoscale.go | 10 ++--- provider/godaddy/godaddy.go | 23 +++-------- provider/oci/oci.go | 12 +++--- registry/dynamodb.go | 20 +++++----- source/crd.go | 2 +- 12 files changed, 81 insertions(+), 104 deletions(-) rename provider/azure/{ => fixtures}/config_test.json (95%) diff --git a/.golangci.yml b/.golangci.yml index 99b3dde04..17669081a 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,7 +1,8 @@ +# https://golangci-lint.run/usage/configuration/ version: "2" linters: default: none - enable: + enable: # golangci-lint help linters - dogsled - goprintffuncname - govet @@ -13,6 +14,9 @@ linters: - unconvert - unused - whitespace + - predeclared # Find code that shadows one of Go's predeclared identifiers + - sloglint # Ensure consistent code style when using log/slog + - asciicheck # Checks that all code identifiers does not have non-ASCII symbols in the name settings: exhaustive: default-signifies-exhaustive: false diff --git a/plan/conflict.go b/plan/conflict.go index 3044059b7..bf153dcfc 100644 --- a/plan/conflict.go +++ b/plan/conflict.go @@ -25,7 +25,7 @@ import ( ) // ConflictResolver is used to make a decision in case of two or more different kubernetes resources -// are trying to acquire same DNS name +// are trying to acquire the same DNS name type ConflictResolver interface { ResolveCreate(candidates []*endpoint.Endpoint) *endpoint.Endpoint ResolveUpdate(current *endpoint.Endpoint, candidates []*endpoint.Endpoint) *endpoint.Endpoint @@ -38,13 +38,13 @@ type PerResource struct{} // ResolveCreate is invoked when dns name is not owned by any resource // ResolveCreate takes "minimal" (string comparison of Target) endpoint to acquire the DNS record func (s PerResource) ResolveCreate(candidates []*endpoint.Endpoint) *endpoint.Endpoint { - var min *endpoint.Endpoint + var minE *endpoint.Endpoint for _, ep := range candidates { - if min == nil || s.less(ep, min) { - min = ep + if minE == nil || s.less(ep, minE) { + minE = ep } } - return min + return minE } // ResolveUpdate is invoked when dns name is already owned by "current" endpoint diff --git a/provider/akamai/akamai.go b/provider/akamai/akamai.go index bd36fd663..36ac0a194 100644 --- a/provider/akamai/akamai.go +++ b/provider/akamai/akamai.go @@ -90,14 +90,6 @@ type akamaiZone struct { func NewAkamaiProvider(akamaiConfig AkamaiConfig, akaService AkamaiDNSService) (provider.Provider, error) { var edgeGridConfig edgegrid.Config - /* - log.Debugf("Host: %s", akamaiConfig.ServiceConsumerDomain) - log.Debugf("ClientToken: %s", akamaiConfig.ClientToken) - log.Debugf("ClientSecret: %s", akamaiConfig.ClientSecret) - log.Debugf("AccessToken: %s", akamaiConfig.AccessToken) - log.Debugf("EdgePath: %s", akamaiConfig.EdgercPath) - log.Debugf("EdgeSection: %s", akamaiConfig.EdgercSection) - */ // environment overrides edgerc file but config needs to be complete if akamaiConfig.ServiceConsumerDomain == "" || akamaiConfig.ClientToken == "" || akamaiConfig.ClientSecret == "" || akamaiConfig.AccessToken == "" { // Kubernetes config incomplete or non existent. Can't mix and match. @@ -106,7 +98,7 @@ func NewAkamaiProvider(akamaiConfig AkamaiConfig, akaService AkamaiDNSService) ( edgeGridConfig, err = edgegrid.Init(akamaiConfig.EdgercPath, akamaiConfig.EdgercSection) // use default .edgerc location and section if err != nil { log.Errorf("Edgegrid Init Failed") - return &AkamaiProvider{}, err // return empty provider for backward compatibility + return &AkamaiProvider{}, err // return an empty provider for backward compatibility } edgeGridConfig.HeaderToSign = append(edgeGridConfig.HeaderToSign, "X-External-DNS") } else { diff --git a/provider/alibabacloud/alibaba_cloud_test.go b/provider/alibabacloud/alibaba_cloud_test.go index 8d4b47464..5bdb77a42 100644 --- a/provider/alibabacloud/alibaba_cloud_test.go +++ b/provider/alibabacloud/alibaba_cloud_test.go @@ -22,6 +22,7 @@ import ( "github.com/aliyun/alibaba-cloud-sdk-go/services/alidns" "github.com/aliyun/alibaba-cloud-sdk-go/services/pvtz" + "github.com/stretchr/testify/assert" "sigs.k8s.io/external-dns/endpoint" "sigs.k8s.io/external-dns/plan" @@ -223,18 +224,7 @@ func newTestAlibabaCloudProvider(private bool) *AlibabaCloudProvider { cfg := alibabaCloudConfig{ VPCID: "vpc-xxxxxx", } - // - //dnsClient, _ := alidns.NewClientWithAccessKey( - // cfg.RegionID, - // cfg.AccessKeyID, - // cfg.AccessKeySecret, - //) - // - //pvtzClient, _ := pvtz.NewClientWithAccessKey( - // "cn-hangzhou", - // cfg.AccessKeyID, - // cfg.AccessKeySecret, - //) + domainFilterTest := endpoint.NewDomainFilter([]string{"container-service.top.", "example.org"}) return &AlibabaCloudProvider{ @@ -256,8 +246,8 @@ func TestAlibabaCloudPrivateProvider_Records(t *testing.T) { if len(endpoints) != 2 { t.Errorf("Incorrect number of records: %d", len(endpoints)) } - for _, endpoint := range endpoints { - t.Logf("Endpoint for %++v", *endpoint) + for _, ep := range endpoints { + t.Logf("Endpoint for %++v", *ep) } } } @@ -271,8 +261,8 @@ func TestAlibabaCloudProvider_Records(t *testing.T) { if len(endpoints) != 2 { t.Errorf("Incorrect number of records: %d", len(endpoints)) } - for _, endpoint := range endpoints { - t.Logf("Endpoint for %++v", *endpoint) + for _, ep := range endpoints { + t.Logf("Endpoint for %++v", *ep) } } } @@ -313,7 +303,8 @@ func TestAlibabaCloudProvider_ApplyChanges(t *testing.T) { }, } ctx := context.Background() - p.ApplyChanges(ctx, &changes) + err := p.ApplyChanges(ctx, &changes) + assert.NoError(t, err) endpoints, err := p.Records(ctx) if err != nil { t.Errorf("Failed to get records: %v", err) @@ -321,8 +312,8 @@ func TestAlibabaCloudProvider_ApplyChanges(t *testing.T) { if len(endpoints) != 3 { t.Errorf("Incorrect number of records: %d", len(endpoints)) } - for _, endpoint := range endpoints { - t.Logf("Endpoint for %++v", *endpoint) + for _, ep := range endpoints { + t.Logf("Endpoint for %++v", *ep) } } for _, ep := range endpoints { @@ -343,8 +334,8 @@ func TestAlibabaCloudProvider_Records_PrivateZone(t *testing.T) { if len(endpoints) != 2 { t.Errorf("Incorrect number of records: %d", len(endpoints)) } - for _, endpoint := range endpoints { - t.Logf("Endpoint for %++v", *endpoint) + for _, ep := range endpoints { + t.Logf("Endpoint for %++v", *ep) } } } @@ -378,7 +369,8 @@ func TestAlibabaCloudProvider_ApplyChanges_PrivateZone(t *testing.T) { }, } ctx := context.Background() - p.ApplyChanges(ctx, &changes) + err := p.ApplyChanges(ctx, &changes) + assert.NoError(t, err) endpoints, err := p.Records(ctx) if err != nil { t.Errorf("Failed to get records: %v", err) @@ -386,8 +378,8 @@ func TestAlibabaCloudProvider_ApplyChanges_PrivateZone(t *testing.T) { if len(endpoints) != 2 { t.Errorf("Incorrect number of records: %d", len(endpoints)) } - for _, endpoint := range endpoints { - t.Logf("Endpoint for %++v", *endpoint) + for _, ep := range endpoints { + t.Logf("Endpoint for %++v", *ep) } } } diff --git a/provider/aws/aws.go b/provider/aws/aws.go index c11977433..97f35b509 100644 --- a/provider/aws/aws.go +++ b/provider/aws/aws.go @@ -232,7 +232,7 @@ type profiledZone struct { } func (cs Route53Changes) Route53Changes() []route53types.Change { - ret := []route53types.Change{} + var ret []route53types.Change for _, c := range cs { ret = append(ret, c.Change) } @@ -313,7 +313,7 @@ type AWSConfig struct { // NewAWSProvider initializes a new AWS Route53 based Provider. func NewAWSProvider(awsConfig AWSConfig, clients map[string]Route53API) (*AWSProvider, error) { - provider := &AWSProvider{ + pr := &AWSProvider{ clients: clients, domainFilter: awsConfig.DomainFilter, zoneIDFilter: awsConfig.ZoneIDFilter, @@ -331,7 +331,7 @@ func NewAWSProvider(awsConfig AWSConfig, clients map[string]Route53API) (*AWSPro failedChangesQueue: make(map[string]Route53Changes), } - return provider, nil + return pr, nil } // Zones returns the list of hosted zones. @@ -561,33 +561,33 @@ func (p *AWSProvider) records(ctx context.Context, zones map[string]*profiledZon } // Identify if old and new endpoints require DELETE/CREATE instead of UPDATE. -func (p *AWSProvider) requiresDeleteCreate(old *endpoint.Endpoint, new *endpoint.Endpoint) bool { - // a change of record type - if old.RecordType != new.RecordType { +func (p *AWSProvider) requiresDeleteCreate(old *endpoint.Endpoint, newE *endpoint.Endpoint) bool { + // a change of a record type + if old.RecordType != newE.RecordType { return true } // an ALIAS record change to/from an A if old.RecordType == endpoint.RecordTypeA { oldAlias, _ := old.GetProviderSpecificProperty(providerSpecificAlias) - newAlias, _ := new.GetProviderSpecificProperty(providerSpecificAlias) + newAlias, _ := newE.GetProviderSpecificProperty(providerSpecificAlias) if oldAlias != newAlias { return true } } // a set identifier change - if old.SetIdentifier != new.SetIdentifier { + if old.SetIdentifier != newE.SetIdentifier { return true } // a change of routing policy - // default to true for geolocation properties if any geolocation property exists in old/new but not the other + // defaults to true for geolocation properties if any geolocation property exists in old/new but not the other for _, propType := range [7]string{providerSpecificWeight, providerSpecificRegion, providerSpecificFailover, providerSpecificFailover, providerSpecificGeolocationContinentCode, providerSpecificGeolocationCountryCode, providerSpecificGeolocationSubdivisionCode} { _, oldPolicy := old.GetProviderSpecificProperty(propType) - _, newPolicy := new.GetProviderSpecificProperty(propType) + _, newPolicy := newE.GetProviderSpecificProperty(propType) if oldPolicy != newPolicy { return true } @@ -601,14 +601,14 @@ func (p *AWSProvider) createUpdateChanges(newEndpoints, oldEndpoints []*endpoint var creates []*endpoint.Endpoint var updates []*endpoint.Endpoint - for i, new := range newEndpoints { - old := oldEndpoints[i] - if p.requiresDeleteCreate(old, new) { - deletes = append(deletes, old) - creates = append(creates, new) + for i, newE := range newEndpoints { + oldE := oldEndpoints[i] + if p.requiresDeleteCreate(oldE, newE) { + deletes = append(deletes, oldE) + creates = append(creates, newE) } else { // Safe to perform an UPSERT. - updates = append(updates, new) + updates = append(updates, newE) } } @@ -760,8 +760,8 @@ func (p *AWSProvider) submitChanges(ctx context.Context, changes Route53Changes, func (p *AWSProvider) newChanges(action route53types.ChangeAction, endpoints []*endpoint.Endpoint) Route53Changes { changes := make(Route53Changes, 0, len(endpoints)) - for _, endpoint := range endpoints { - change := p.newChange(action, endpoint) + for _, ep := range endpoints { + change := p.newChange(action, ep) changes = append(changes, change) } diff --git a/provider/azure/config_test.go b/provider/azure/config_test.go index 1099515d3..956599a90 100644 --- a/provider/azure/config_test.go +++ b/provider/azure/config_test.go @@ -50,7 +50,7 @@ func TestGetCloudConfiguration(t *testing.T) { func TestOverrideConfiguration(t *testing.T) { _, filename, _, _ := runtime.Caller(0) - configFile := path.Join(path.Dir(filename), "config_test.json") + configFile := path.Join(path.Dir(filename), "fixtures/config_test.json") cfg, err := getConfig(configFile, "subscription-override", "rg-override", "", "aad-endpoint-override") if err != nil { t.Errorf("got unexpected err %v", err) diff --git a/provider/azure/config_test.json b/provider/azure/fixtures/config_test.json similarity index 95% rename from provider/azure/config_test.json rename to provider/azure/fixtures/config_test.json index ddcaa7695..36863ed7e 100644 --- a/provider/azure/config_test.json +++ b/provider/azure/fixtures/config_test.json @@ -1,7 +1,7 @@ -{ - "tenantId": "tenant", - "subscriptionId": "subscription", - "resourceGroup": "rg", - "aadClientId": "clientId", - "aadClientSecret": "clientSecret" -} +{ + "tenantId": "tenant", + "subscriptionId": "subscription", + "resourceGroup": "rg", + "aadClientId": "clientId", + "aadClientSecret": "clientSecret" +} diff --git a/provider/exoscale/exoscale.go b/provider/exoscale/exoscale.go index 6e13f14f2..ff83e82b7 100644 --- a/provider/exoscale/exoscale.go +++ b/provider/exoscale/exoscale.go @@ -310,10 +310,10 @@ func (f *zoneFilter) EndpointZoneID(endpoint *endpoint.Endpoint, zones map[strin func merge(updateOld, updateNew []*endpoint.Endpoint) []*endpoint.Endpoint { findMatch := func(template *endpoint.Endpoint) *endpoint.Endpoint { - for _, new := range updateNew { - if template.DNSName == new.DNSName && - template.RecordType == new.RecordType { - return new + for _, record := range updateNew { + if template.DNSName == record.DNSName && + template.RecordType == record.RecordType { + return record } } return nil @@ -323,7 +323,7 @@ func merge(updateOld, updateNew []*endpoint.Endpoint) []*endpoint.Endpoint { for _, old := range updateOld { matchingNew := findMatch(old) if matchingNew == nil { - // no match, shouldn't happen + // no match shouldn't happen continue } diff --git a/provider/godaddy/godaddy.go b/provider/godaddy/godaddy.go index ede7bf154..58e5465fa 100644 --- a/provider/godaddy/godaddy.go +++ b/provider/godaddy/godaddy.go @@ -19,8 +19,8 @@ package godaddy import ( "context" "encoding/json" - "errors" "fmt" + "slices" "strings" log "github.com/sirupsen/logrus" @@ -46,9 +46,6 @@ var actionNames = []string{ const domainsURI = "/v1/domains?statuses=ACTIVE,PENDING_DNS_ACTIVE" -// ErrRecordToMutateNotFound when ApplyChange has to update/delete and didn't found the record in the existing zone (Change with no record ID) -var ErrRecordToMutateNotFound = errors.New("record to mutate not found in current zone") - type gdClient interface { Patch(string, interface{}, interface{}) error Post(string, interface{}, interface{}) error @@ -294,14 +291,14 @@ func (p *GDProvider) groupByNameAndType(zoneRecords []gdRecords) []*endpoint.End recordName = strings.TrimPrefix(fmt.Sprintf("%s.%s", records[0].Name, zoneName), ".") } - endpoint := endpoint.NewEndpointWithTTL( + ep := endpoint.NewEndpointWithTTL( recordName, records[0].Type, endpoint.TTL(records[0].TTL), targets..., ) - endpoints = append(endpoints, endpoint) + endpoints = append(endpoints, ep) } } @@ -584,8 +581,8 @@ func countTargets(p *plan.Changes) int { count := 0 for _, endpoints := range changes { - for _, endpoint := range endpoints { - count += len(endpoint.Targets) + for _, ep := range endpoints { + count += len(ep.Targets) } } @@ -593,15 +590,7 @@ func countTargets(p *plan.Changes) int { } func maxOf(vars ...int64) int64 { - max := vars[0] - - for _, i := range vars { - if max < i { - max = i - } - } - - return max + return slices.Max(vars) } func toString(obj interface{}) string { diff --git a/provider/oci/oci.go b/provider/oci/oci.go index 87f57f78a..e56cbe3e0 100644 --- a/provider/oci/oci.go +++ b/provider/oci/oci.go @@ -23,7 +23,7 @@ import ( "strings" "time" - yaml "github.com/goccy/go-yaml" + "github.com/goccy/go-yaml" "github.com/oracle/oci-go-sdk/v65/common" "github.com/oracle/oci-go-sdk/v65/common/auth" "github.com/oracle/oci-go-sdk/v65/dns" @@ -153,7 +153,7 @@ func (p *OCIProvider) zones(ctx context.Context) (map[string]dns.ZoneSummary, er } zones := make(map[string]dns.ZoneSummary) scopes := []dns.GetZoneScopeEnum{dns.GetZoneScopeEnum(p.zoneScope)} - // If zone scope is empty, list all zones types. + // If the zone scope is empty, list all zones types. if p.zoneScope == "" { scopes = dns.GetGetZoneScopeEnumValues() } @@ -232,7 +232,7 @@ func (p *OCIProvider) addPaginatedZones(ctx context.Context, zones map[string]dn } func (p *OCIProvider) newFilteredRecordOperations(endpoints []*endpoint.Endpoint, opType dns.RecordOperationOperationEnum) []dns.RecordOperation { - ops := []dns.RecordOperation{} + var ops []dns.RecordOperation for _, ep := range endpoints { if ep == nil { continue @@ -261,7 +261,7 @@ func (p *OCIProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error) return nil, provider.NewSoftError(fmt.Errorf("getting zones: %w", err)) } - endpoints := []*endpoint.Endpoint{} + var endpoints []*endpoint.Endpoint for _, zone := range zones { var page *string for { @@ -303,7 +303,7 @@ func (p *OCIProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error) func (p *OCIProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error { log.Debugf("Processing changes: %+v", changes) - ops := []dns.RecordOperation{} + var ops []dns.RecordOperation ops = append(ops, p.newFilteredRecordOperations(changes.Create, dns.RecordOperationOperationAdd)...) ops = append(ops, p.newFilteredRecordOperations(changes.UpdateNew, dns.RecordOperationOperationAdd)...) @@ -349,7 +349,7 @@ func (p *OCIProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) e // AdjustEndpoints modifies the endpoints as needed by the specific provider func (p *OCIProvider) AdjustEndpoints(endpoints []*endpoint.Endpoint) ([]*endpoint.Endpoint, error) { - adjustedEndpoints := []*endpoint.Endpoint{} + var adjustedEndpoints []*endpoint.Endpoint for _, e := range endpoints { // OCI DNS does not support the set-identifier attribute, so we remove it to avoid plan failure if e.SetIdentifier != "" { diff --git a/registry/dynamodb.go b/registry/dynamodb.go index 2088fda50..5b83ceeb0 100644 --- a/registry/dynamodb.go +++ b/registry/dynamodb.go @@ -300,12 +300,12 @@ func (im *DynamoDBRegistry) ApplyChanges(ctx context.Context, changes *plan.Chan if err != nil { return err } - for i, endpoint := range filteredChanges.Create { - if endpoint.Key() == key { - log.Infof("Skipping endpoint %v because owner does not match", endpoint) + for i, ep := range filteredChanges.Create { + if ep.Key() == key { + log.Infof("Skipping endpoint %v because owner does not match", ep) filteredChanges.Create = append(filteredChanges.Create[:i], filteredChanges.Create[i+1:]...) // The dynamodb insertion failed; remove from our cache. - im.removeFromCache(endpoint) + im.removeFromCache(ep) delete(im.labels, key) return nil } @@ -466,7 +466,7 @@ func toDynamoLabels(labels endpoint.Labels) dynamodbtypes.AttributeValue { return &dynamodbtypes.AttributeValueMemberM{Value: labelMap} } -func (im *DynamoDBRegistry) appendInsert(statements []dynamodbtypes.BatchStatementRequest, key endpoint.EndpointKey, new endpoint.Labels) []dynamodbtypes.BatchStatementRequest { +func (im *DynamoDBRegistry) appendInsert(statements []dynamodbtypes.BatchStatementRequest, key endpoint.EndpointKey, newL endpoint.Labels) []dynamodbtypes.BatchStatementRequest { return append(statements, dynamodbtypes.BatchStatementRequest{ Statement: aws.String(fmt.Sprintf("INSERT INTO %q VALUE {'k':?, 'o':?, 'l':?}", im.table)), ConsistentRead: aws.Bool(true), @@ -475,16 +475,16 @@ func (im *DynamoDBRegistry) appendInsert(statements []dynamodbtypes.BatchStateme &dynamodbtypes.AttributeValueMemberS{ Value: im.ownerID, }, - toDynamoLabels(new), + toDynamoLabels(newL), }, }) } -func (im *DynamoDBRegistry) appendUpdate(statements []dynamodbtypes.BatchStatementRequest, key endpoint.EndpointKey, old endpoint.Labels, new endpoint.Labels) []dynamodbtypes.BatchStatementRequest { - if len(old) == len(new) { +func (im *DynamoDBRegistry) appendUpdate(statements []dynamodbtypes.BatchStatementRequest, key endpoint.EndpointKey, old endpoint.Labels, newE endpoint.Labels) []dynamodbtypes.BatchStatementRequest { + if len(old) == len(newE) { equal := true for k, v := range old { - if newV, exists := new[k]; !exists || v != newV { + if newV, exists := newE[k]; !exists || v != newV { equal = false break } @@ -497,7 +497,7 @@ func (im *DynamoDBRegistry) appendUpdate(statements []dynamodbtypes.BatchStateme return append(statements, dynamodbtypes.BatchStatementRequest{ Statement: aws.String(fmt.Sprintf("UPDATE %q SET \"l\"=? WHERE \"k\"=?", im.table)), Parameters: []dynamodbtypes.AttributeValue{ - toDynamoLabels(new), + toDynamoLabels(newE), toDynamoKey(key), }, }) diff --git a/source/crd.go b/source/crd.go index 70a724073..31a775b06 100644 --- a/source/crd.go +++ b/source/crd.go @@ -148,7 +148,7 @@ func (cs *crdSource) AddEventHandler(ctx context.Context, handler func()) { AddFunc: func(obj interface{}) { handler() }, - UpdateFunc: func(old interface{}, new interface{}) { + UpdateFunc: func(old interface{}, newI interface{}) { handler() }, DeleteFunc: func(obj interface{}) { From c49322f7eefe65f76e1f47e019dec5d01ff7074c Mon Sep 17 00:00:00 2001 From: tJouve Date: Wed, 23 Apr 2025 14:43:42 +0200 Subject: [PATCH 08/42] feat(pihole): add support for IPv6 Dual format (#5253) * Add support of ipv6 dual on pihole provider * PiHoleV6 : Switch from instrumented_http to httpClient * Add support of ipv6 dual on pihole provider - extends tests cases * Switch to net/netip to check ipV6 * Fix linter * ListRecords should not log filtered records Should not log records reject by filter on listRecords because PiHole return A and AAAA records. It is normal to filter some records * Update provider/pihole/clientV6.go Co-authored-by: Michel Loiseleur <97035654+mloiseleur@users.noreply.github.com> --------- Co-authored-by: Michel Loiseleur <97035654+mloiseleur@users.noreply.github.com> --- provider/pihole/clientV6.go | 59 ++++++++++++---- provider/pihole/clientV6_test.go | 116 ++++++++++++++++++++++++------- 2 files changed, 136 insertions(+), 39 deletions(-) diff --git a/provider/pihole/clientV6.go b/provider/pihole/clientV6.go index ae6ae399b..ebaaabd6a 100644 --- a/provider/pihole/clientV6.go +++ b/provider/pihole/clientV6.go @@ -25,6 +25,7 @@ import ( "fmt" "io" "net/http" + "net/netip" "net/url" "strconv" "strings" @@ -63,6 +64,7 @@ func newPiholeClientV6(cfg PiholeConfig) (piholeAPI, error) { }, }, } + cl := instrumented_http.NewClient(httpClient, &instrumented_http.Callbacks{}) p := &piholeClientV6{ @@ -114,6 +116,32 @@ func (p *piholeClientV6) getConfigValue(ctx context.Context, rtype string) ([]st return results, nil } +/** + * isValidIPv4 checks if the given IP address is a valid IPv4 address. + * It returns true if the IP address is valid, false otherwise. + * If the IP address is in IPv6 format, it will return false. + */ +func isValidIPv4(ip string) bool { + addr, err := netip.ParseAddr(ip) + if err != nil { + return false + } + return addr.Is4() +} + +/** + * isValidIPv6 checks if the given IP address is a valid IPv6 address. + * It returns true if the IP address is valid, false otherwise. + * If the IP address is in IPv6 with dual format y:y:y:y:y:y:x.x.x.x. , it will return true. + */ +func isValidIPv6(ip string) bool { + addr, err := netip.ParseAddr(ip) + if err != nil { + return false + } + return addr.Is6() +} + func (p *piholeClientV6) listRecords(ctx context.Context, rtype string) ([]*endpoint.Endpoint, error) { out := make([]*endpoint.Endpoint, 0) results, err := p.getConfigValue(ctx, rtype) @@ -126,42 +154,39 @@ func (p *piholeClientV6) listRecords(ctx context.Context, rtype string) ([]*endp return r == ' ' || r == ',' }) if len(recs) < 2 { - log.Warnf("skipping record %s: invalid format", rec) + log.Warnf("skipping record %s: invalid format received from PiHole", rec) continue } var DNSName, Target string - var Ttl endpoint.TTL = 0 + var Ttl = endpoint.TTL(0) // A/AAAA record format is target(IP) DNSName DNSName, Target = recs[1], recs[0] - switch rtype { case endpoint.RecordTypeA: - if strings.Contains(Target, ":") { + //PiHole return A and AAAA records. Filter to only keep the A records + if !isValidIPv4(Target) { continue } case endpoint.RecordTypeAAAA: - if strings.Contains(Target, ".") { + //PiHole return A and AAAA records. Filter to only keep the AAAA records + if !isValidIPv6(Target) { continue } case endpoint.RecordTypeCNAME: - // CNAME format is DNSName,target + //PiHole return only CNAME records. + // CNAME format is DNSName,target, ttl? DNSName, Target = recs[0], recs[1] if len(recs) == 3 { // TTL is present // Parse string to int64 first if ttlInt, err := strconv.ParseInt(recs[2], 10, 64); err == nil { Ttl = endpoint.TTL(ttlInt) } else { - log.Warnf("failed to parse TTL value '%s': %v; using a TTL of %d", recs[2], err, Ttl) + log.Warnf("failed to parse TTL value received from PiHole '%s': %v; using a TTL of %d", recs[2], err, Ttl) } } } - out = append(out, &endpoint.Endpoint{ - DNSName: DNSName, - Targets: []string{Target}, - RecordTTL: Ttl, - RecordType: rtype, - }) + out = append(out, endpoint.NewEndpointWithTTL(DNSName, rtype, Ttl, Target)) } return out, nil } @@ -375,7 +400,13 @@ func (p *piholeClientV6) do(req *http.Request) ([]byte, error) { if err := json.Unmarshal(jRes, &apiError); err != nil { return nil, fmt.Errorf("failed to unmarshal error response: %w", err) } - log.Debugf("Error on request %s", req.Body) + if log.IsLevelEnabled(log.DebugLevel) { + log.Debugf("Error on request %s", req.URL) + if req.Body != nil { + log.Debugf("Body of the request %s", req.Body) + } + } + if res.StatusCode == http.StatusUnauthorized && p.token != "" { tryCount := 1 maxRetries := 3 diff --git a/provider/pihole/clientV6_test.go b/provider/pihole/clientV6_test.go index 664d88aa1..697571792 100644 --- a/provider/pihole/clientV6_test.go +++ b/provider/pihole/clientV6_test.go @@ -29,6 +29,62 @@ import ( "sigs.k8s.io/external-dns/endpoint" ) +func TestIsValidIPv4(t *testing.T) { + tests := []struct { + ip string + expected bool + }{ + {"192.168.1.1", true}, + {"255.255.255.255", true}, + {"0.0.0.0", true}, + {"", false}, + {"256.256.256.256", false}, + {"192.168.0.1/22", false}, + {"192.168.1", false}, + {"abc.def.ghi.jkl", false}, + {"::ffff:192.168.20.3", false}, + } + + for _, test := range tests { + t.Run(test.ip, func(t *testing.T) { + if got := isValidIPv4(test.ip); got != test.expected { + t.Errorf("isValidIPv4(%s) = %v; want %v", test.ip, got, test.expected) + } + }) + } +} + +func TestIsValidIPv6(t *testing.T) { + tests := []struct { + ip string + expected bool + }{ + {"2001:0db8:85a3:0000:0000:8a2e:0370:7334", true}, + {"2001:db8:85a3::8a2e:370:7334", true}, + //IPV6 dual, the format is y:y:y:y:y:y:x.x.x.x. + {"::ffff:192.168.20.3", true}, + {"::1", true}, + {"::", true}, + {"2001:db8::", true}, + {"", false}, + {":", false}, + {"::ffff:", false}, + {"192.168.20.3", false}, + {"2001:db8:85a3:0:0:8a2e:370:7334:1234", false}, + {"2001:db8:85a3::8a2e:370g:7334", false}, + {"2001:db8:85a3::8a2e:370:7334::", false}, + {"2001:db8:85a3::8a2e:370:7334::1", false}, + } + + for _, test := range tests { + t.Run(test.ip, func(t *testing.T) { + if got := isValidIPv6(test.ip); got != test.expected { + t.Errorf("isValidIPv6(%s) = %v; want %v", test.ip, got, test.expected) + } + }) + } +} + func newTestServerV6(t *testing.T, hdlr http.HandlerFunc) *httptest.Server { t.Helper() svr := httptest.NewServer(hdlr) @@ -137,7 +193,9 @@ func TestListRecordsV6(t *testing.T) { "192.168.178.34 service3.example.com", "fc00::1:192:168:1:1 service4.example.com", "fc00::1:192:168:1:2 service5.example.com", - "fc00::1:192:168:1:3 service6.example.com" + "fc00::1:192:168:1:3 service6.example.com", + "::ffff:192.168.20.3 service7.example.com", + "192.168.20.3 service7.example.com" ] } }, @@ -177,20 +235,22 @@ func TestListRecordsV6(t *testing.T) { t.Fatal(err) } + // Ensure A records were parsed correctly + expected := [][]string{ + {"service1.example.com", "192.168.178.33"}, + {"service2.example.com", "192.168.178.34"}, + {"service3.example.com", "192.168.178.34"}, + {"service7.example.com", "192.168.20.3"}, + } // Test retrieve A records unfiltered arecs, err := cl.listRecords(context.Background(), endpoint.RecordTypeA) if err != nil { t.Fatal(err) } - if len(arecs) != 3 { - t.Fatal("Expected 3 A records returned, got:", len(arecs)) - } - // Ensure records were parsed correctly - expected := [][]string{ - {"service1.example.com", "192.168.178.33"}, - {"service2.example.com", "192.168.178.34"}, - {"service3.example.com", "192.168.178.34"}, + if len(arecs) != len(expected) { + t.Fatalf("Expected %d A records returned, got: %d", len(expected), len(arecs)) } + for idx, rec := range arecs { if rec.DNSName != expected[idx][0] { t.Error("Got invalid DNS Name:", rec.DNSName, "expected:", expected[idx][0]) @@ -200,20 +260,23 @@ func TestListRecordsV6(t *testing.T) { } } + // Ensure AAAA records were parsed correctly + expected = [][]string{ + {"service4.example.com", "fc00::1:192:168:1:1"}, + {"service5.example.com", "fc00::1:192:168:1:2"}, + {"service6.example.com", "fc00::1:192:168:1:3"}, + {"service7.example.com", "::ffff:192.168.20.3"}, + } // Test retrieve AAAA records unfiltered arecs, err = cl.listRecords(context.Background(), endpoint.RecordTypeAAAA) if err != nil { t.Fatal(err) } - if len(arecs) != 3 { - t.Fatal("Expected 3 AAAA records returned, got:", len(arecs)) - } - // Ensure records were parsed correctly - expected = [][]string{ - {"service4.example.com", "fc00::1:192:168:1:1"}, - {"service5.example.com", "fc00::1:192:168:1:2"}, - {"service6.example.com", "fc00::1:192:168:1:3"}, + + if len(arecs) != len(expected) { + t.Fatalf("Expected %d AAAA records returned, got: %d", len(expected), len(arecs)) } + for idx, rec := range arecs { if rec.DNSName != expected[idx][0] { t.Error("Got invalid DNS Name:", rec.DNSName, "expected:", expected[idx][0]) @@ -223,20 +286,22 @@ func TestListRecordsV6(t *testing.T) { } } + // Ensure CNAME records were parsed correctly + expected = [][]string{ + {"source1.example.com", "target1.domain.com", "1000"}, + {"source2.example.com", "target2.domain.com", "50"}, + {"source3.example.com", "target3.domain.com"}, + } + // Test retrieve CNAME records unfiltered cnamerecs, err := cl.listRecords(context.Background(), endpoint.RecordTypeCNAME) if err != nil { t.Fatal(err) } - if len(cnamerecs) != 3 { - t.Fatal("Expected 3 CAME records returned, got:", len(cnamerecs)) - } - // Ensure records were parsed correctly - expected = [][]string{ - {"source1.example.com", "target1.domain.com", "1000"}, - {"source2.example.com", "target2.domain.com", "50"}, - {"source3.example.com", "target3.domain.com"}, + if len(cnamerecs) != len(expected) { + t.Fatalf("Expected %d CAME records returned, got: %d", len(expected), len(cnamerecs)) } + for idx, rec := range cnamerecs { if rec.DNSName != expected[idx][0] { t.Error("Got invalid DNS Name:", rec.DNSName, "expected:", expected[idx][0]) @@ -261,6 +326,7 @@ func TestListRecordsV6(t *testing.T) { t.Fatal("Expected error for using unsupported record type") } } + func TestErrorsV6(t *testing.T) { //Error test cases From 5eaf814b9420f88152a5f76aa0e48991eaead9ee Mon Sep 17 00:00:00 2001 From: Christian Rohmann Date: Wed, 23 Apr 2025 18:49:42 +0200 Subject: [PATCH 09/42] feat(helm): allow extraArgs to also be a map enabling overrides of individual values (#5293) --- charts/external-dns/CHANGELOG.md | 4 ++ charts/external-dns/README.md | 2 +- charts/external-dns/templates/deployment.yaml | 21 ++++++- .../tests/deployment-flags_test.yaml | 55 +++++++++++++++++++ charts/external-dns/values.schema.json | 4 +- charts/external-dns/values.yaml | 3 +- 6 files changed, 84 insertions(+), 5 deletions(-) diff --git a/charts/external-dns/CHANGELOG.md b/charts/external-dns/CHANGELOG.md index a08aa1758..2f909eb80 100644 --- a/charts/external-dns/CHANGELOG.md +++ b/charts/external-dns/CHANGELOG.md @@ -18,6 +18,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [UNRELEASED] +### Changed + +- Allow extraArgs to also be a map enabling overrides of individual values ([#5293](https://github.com/kubernetes-sigs/external-dns/pull/5293)) _@frittentheke + ### Fixed - Fixed wrong type definitions for webhook probes. ([#5297](https://github.com/kubernetes-sigs/external-dns/pull/5297)) _@semnell_ diff --git a/charts/external-dns/README.md b/charts/external-dns/README.md index f23a25467..6126679bb 100644 --- a/charts/external-dns/README.md +++ b/charts/external-dns/README.md @@ -104,7 +104,7 @@ If `namespaced` is set to `true`, please ensure that `sources` my only contains | enabled | bool | `nil` | No effect - reserved for use in sub-charting. | | env | list | `[]` | [Environment variables](https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/) for the `external-dns` container. | | excludeDomains | list | `[]` | Intentionally exclude domains from being managed. | -| extraArgs | list | `[]` | Extra arguments to provide to _ExternalDNS_. | +| extraArgs | object | `{}` | Extra arguments to provide to _ExternalDNS_. An array or map can be used, with maps allowing for value overrides; maps also support slice values to use the same arg multiple times. | | extraContainers | object | `{}` | Extra containers to add to the `Deployment`. | | extraVolumeMounts | list | `[]` | Extra [volume mounts](https://kubernetes.io/docs/concepts/storage/volumes/) for the `external-dns` container. | | extraVolumes | list | `[]` | Extra [volumes](https://kubernetes.io/docs/concepts/storage/volumes/) for the `Pod`. | diff --git a/charts/external-dns/templates/deployment.yaml b/charts/external-dns/templates/deployment.yaml index 7a1ec8c72..f0c967a33 100644 --- a/charts/external-dns/templates/deployment.yaml +++ b/charts/external-dns/templates/deployment.yaml @@ -124,9 +124,26 @@ spec: - --managed-record-types={{ . }} {{- end }} - --provider={{ $providerName }} - {{- range .Values.extraArgs }} + {{- if kindIs "map" .Values.extraArgs }} + {{- range $key, $value := .Values.extraArgs }} + {{- if not (kindIs "invalid" $value) }} + {{- if kindIs "slice" $value }} + {{- range $value }} + - --{{ $key }}={{ tpl (. | toString) $ }} + {{- end }} + {{- else }} + - --{{ $key }}={{ tpl ($value | toString) $ }} + {{- end }} + {{- else }} + - --{{ $key }} + {{- end }} + {{- end }} + {{- end }} + {{- if kindIs "slice" .Values.extraArgs }} + {{- range .Values.extraArgs }} - {{ tpl . $ }} - {{- end }} + {{- end }} + {{- end }} ports: - name: http protocol: TCP diff --git a/charts/external-dns/tests/deployment-flags_test.yaml b/charts/external-dns/tests/deployment-flags_test.yaml index 44ae176c3..97e89a451 100644 --- a/charts/external-dns/tests/deployment-flags_test.yaml +++ b/charts/external-dns/tests/deployment-flags_test.yaml @@ -103,6 +103,60 @@ tests: - --zone-id-filter=/hostedzone/Z00004 - --zone-id-filter=/hostedzone/Z00005 + + - it: should allow 'extraArgs' to be a slice + set: + extraArgs: + - --extraArgA=valueA + - --extraArgB=valueB + - --extraArgC=valueC-1 + - --extraArgC=valueC-2 + + asserts: + - equal: + path: spec.template.spec.containers[?(@.name == "external-dns")].args + value: + - --log-level=info + - --log-format=text + - --interval=1m + - --source=service + - --source=ingress + - --policy=upsert-only + - --registry=txt + - --provider=aws + - --extraArgA=valueA + - --extraArgB=valueB + - --extraArgC=valueC-1 + - --extraArgC=valueC-2 + + + - it: should allow 'extraArgs' to be a map with its entries potentially being slices (lists) themselves + set: + extraArgs: + extraArgA: valueA + extraArgB: valueB + extraArgC: + - valueC-1 + - valueC-2 + + asserts: + - equal: + path: spec.template.spec.containers[?(@.name == "external-dns")].args + value: + - --log-level=info + - --log-format=text + - --interval=1m + - --source=service + - --source=ingress + - --policy=upsert-only + - --registry=txt + - --provider=aws + - --extraArgA=valueA + - --extraArgB=valueB + - --extraArgC=valueC-1 + - --extraArgC=valueC-2 + + - it: should throw error when txtPrefix and txtSuffix are set set: txtPrefix: "test-prefix" @@ -110,3 +164,4 @@ tests: asserts: - failedTemplate: errorMessage: "'txtPrefix' and 'txtSuffix' are mutually exclusive" + diff --git a/charts/external-dns/values.schema.json b/charts/external-dns/values.schema.json index bbd36ada8..72143d644 100644 --- a/charts/external-dns/values.schema.json +++ b/charts/external-dns/values.schema.json @@ -64,9 +64,11 @@ "items": { "type": "string" }, + "properties": {}, "type": [ "array", - "null" + "null", + "object" ], "uniqueItems": true }, diff --git a/charts/external-dns/values.yaml b/charts/external-dns/values.yaml index c1d9be879..0e85050a3 100644 --- a/charts/external-dns/values.yaml +++ b/charts/external-dns/values.yaml @@ -296,7 +296,8 @@ provider: # @schema type: [object, string]; relabelings: [] # -- Extra arguments to provide to _ExternalDNS_. -extraArgs: [] # @schema type: [array, null]; item: string; uniqueItems: true; +# An array or map can be used, with maps allowing for value overrides; maps also support slice values to use the same arg multiple times. +extraArgs: {} # @schema type: [array, null, object]; item: string; uniqueItems: true; secretConfiguration: # -- If `true`, create a `Secret` to store sensitive provider configuration (**DEPRECATED**). From 757a57609f14f5fb99004b369c43440ae07f6d9c Mon Sep 17 00:00:00 2001 From: ivan katliarchuk Date: Wed, 23 Apr 2025 22:03:00 +0100 Subject: [PATCH 10/42] chore(code-quality): linter warnings fixes Signed-off-by: ivan katliarchuk --- provider/cloudflare/cloudflare.go | 34 ++++++++++----------- provider/coredns/coredns.go | 2 +- provider/dnsimple/dnsimple.go | 16 +++++----- provider/exoscale/exoscale.go | 2 +- provider/godaddy/client.go | 6 ++-- provider/godaddy/godaddy.go | 4 +-- provider/google/google.go | 16 +++++----- provider/ibmcloud/ibmcloud.go | 14 ++++----- provider/linode/linode.go | 7 ++--- provider/ns1/ns1.go | 11 +++---- provider/oci/oci.go | 12 ++++---- provider/ovh/ovh.go | 22 ++++++------- provider/plural/plural.go | 17 +++++------ provider/tencentcloud/tencent_cloud_test.go | 2 -- provider/ultradns/ultradns.go | 27 +++++++--------- 15 files changed, 88 insertions(+), 104 deletions(-) diff --git a/provider/cloudflare/cloudflare.go b/provider/cloudflare/cloudflare.go index 0bac3f89b..69dd22e6e 100644 --- a/provider/cloudflare/cloudflare.go +++ b/provider/cloudflare/cloudflare.go @@ -51,11 +51,12 @@ const ( // We have to use pointers to bools now, as the upstream cloudflare-go library requires them // see: https://github.com/cloudflare/cloudflare-go/pull/595 -// proxyEnabled is a pointer to a bool true showing the record should be proxied through cloudflare -var proxyEnabled *bool = boolPtr(true) - -// proxyDisabled is a pointer to a bool false showing the record should not be proxied through cloudflare -var proxyDisabled *bool = boolPtr(false) +var ( + // proxyEnabled is a pointer to a bool true showing the record should be proxied through cloudflare + proxyEnabled *bool = boolPtr(true) + // proxyDisabled is a pointer to a bool false showing the record should not be proxied through cloudflare + proxyDisabled *bool = boolPtr(false) +) // for faster getRecordID() lookup type DNSRecordIndex struct { @@ -279,8 +280,8 @@ func NewCloudFlareProvider(domainFilter endpoint.DomainFilter, zoneIDFilter prov if err != nil { return nil, fmt.Errorf("failed to initialize cloudflare provider: %w", err) } - provider := &CloudFlareProvider{ - // Client: config, + + return &CloudFlareProvider{ Client: zoneService{config}, domainFilter: domainFilter, zoneIDFilter: zoneIDFilter, @@ -289,13 +290,12 @@ func NewCloudFlareProvider(domainFilter endpoint.DomainFilter, zoneIDFilter prov DryRun: dryRun, DNSRecordsPerPage: dnsRecordsPerPage, RegionKey: regionKey, - } - return provider, nil + }, nil } // Zones returns the list of hosted zones. func (p *CloudFlareProvider) Zones(ctx context.Context) ([]cloudflare.Zone, error) { - result := []cloudflare.Zone{} + var result []cloudflare.Zone // if there is a zoneIDfilter configured // && if the filter isn't just a blank string (used in tests) @@ -349,7 +349,7 @@ func (p *CloudFlareProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, return nil, err } - endpoints := []*endpoint.Endpoint{} + var endpoints []*endpoint.Endpoint for _, zone := range zones { records, err := p.listDNSRecordsWithAutoPagination(ctx, zone.ID) if err != nil { @@ -373,7 +373,7 @@ func (p *CloudFlareProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, // ApplyChanges applies a given set of changes in a given zone. func (p *CloudFlareProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error { - cloudflareChanges := []*cloudFlareChange{} + var cloudflareChanges []*cloudFlareChange // if custom hostnames are enabled, deleting first allows to avoid conflicts with the new ones if p.CustomHostnamesConfig.Enabled { @@ -425,7 +425,7 @@ func (p *CloudFlareProvider) submitCustomHostnameChanges(ctx context.Context, zo failedChange := false // return early if disabled if !p.CustomHostnamesConfig.Enabled { - return !failedChange + return true } switch change.Action { @@ -730,7 +730,7 @@ func (p *CloudFlareProvider) submitChanges(ctx context.Context, changes []*cloud // AdjustEndpoints modifies the endpoints as needed by the specific provider func (p *CloudFlareProvider) AdjustEndpoints(endpoints []*endpoint.Endpoint) ([]*endpoint.Endpoint, error) { - adjustedEndpoints := []*endpoint.Endpoint{} + var adjustedEndpoints []*endpoint.Endpoint for _, e := range endpoints { proxied := shouldBeProxied(e, p.proxiedByDefault) if proxied { @@ -969,7 +969,7 @@ func getEndpointCustomHostnames(ep *endpoint.Endpoint) []string { } func groupByNameAndTypeWithCustomHostnames(records DNSRecordsMap, chs CustomHostnamesMap) []*endpoint.Endpoint { - endpoints := []*endpoint.Endpoint{} + var endpoints []*endpoint.Endpoint // group supported records by name and type groups := map[string][]cloudflare.DNSRecord{} @@ -994,7 +994,7 @@ func groupByNameAndTypeWithCustomHostnames(records DNSRecordsMap, chs CustomHost customHostnames[c.CustomOriginServer] = append(customHostnames[c.CustomOriginServer], c.Hostname) } - // create single endpoint with all the targets for each name/type + // create a single endpoint with all the targets for each name/type for _, records := range groups { if len(records) == 0 { return endpoints @@ -1016,7 +1016,7 @@ func groupByNameAndTypeWithCustomHostnames(records DNSRecordsMap, chs CustomHost continue } e = e.WithProviderSpecific(source.CloudflareProxiedKey, strconv.FormatBool(proxied)) - // noop (customHostnames is empty) if custom hostnames feature is not in use + // noop (customHostnames is empty) if the custom hostnames feature is not in use if customHostnames, ok := customHostnames[records[0].Name]; ok { sort.Strings(customHostnames) e = e.WithProviderSpecific(source.CloudflareCustomHostnameKey, strings.Join(customHostnames, ",")) diff --git a/provider/coredns/coredns.go b/provider/coredns/coredns.go index eeb545aea..18dc9cea7 100644 --- a/provider/coredns/coredns.go +++ b/provider/coredns/coredns.go @@ -92,7 +92,7 @@ type etcdClient struct { var _ coreDNSClient = etcdClient{} -// GetService return all Service records stored in etcd stored anywhere under the given key (recursively) +// GetServices GetService return all Service records stored in etcd stored anywhere under the given key (recursively) func (c etcdClient) GetServices(prefix string) ([]*Service, error) { ctx, cancel := context.WithTimeout(c.ctx, etcdTimeout) defer cancel() diff --git a/provider/dnsimple/dnsimple.go b/provider/dnsimple/dnsimple.go index 3a1554e7a..991fda08a 100644 --- a/provider/dnsimple/dnsimple.go +++ b/provider/dnsimple/dnsimple.go @@ -33,7 +33,13 @@ import ( "sigs.k8s.io/external-dns/provider" ) -const dnsimpleRecordTTL = 3600 // Default TTL of 1 hour if not set (DNSimple's default) +const ( + dnsimpleCreate = "CREATE" + dnsimpleDelete = "DELETE" + dnsimpleUpdate = "UPDATE" + + dnsimpleRecordTTL = 3600 // Default TTL of 1 hour if not set (DNSimple's default) +) type dnsimpleIdentityService struct { service *dnsimple.IdentityService @@ -91,12 +97,6 @@ type dnsimpleChange struct { ResourceRecordSet dnsimple.ZoneRecord } -const ( - dnsimpleCreate = "CREATE" - dnsimpleDelete = "DELETE" - dnsimpleUpdate = "UPDATE" -) - // NewDnsimpleProvider initializes a new Dnsimple based provider func NewDnsimpleProvider(domainFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, dryRun bool) (provider.Provider, error) { oauthToken := os.Getenv("DNSIMPLE_OAUTH") @@ -149,7 +149,7 @@ func ZonesFromZoneString(zonestring string) map[string]dnsimple.Zone { return zones } -// Returns a list of filtered Zones +// Zones Return a list of filtered Zones func (p *dnsimpleProvider) Zones(ctx context.Context) (map[string]dnsimple.Zone, error) { zones := make(map[string]dnsimple.Zone) diff --git a/provider/exoscale/exoscale.go b/provider/exoscale/exoscale.go index ff83e82b7..c1404b29e 100644 --- a/provider/exoscale/exoscale.go +++ b/provider/exoscale/exoscale.go @@ -181,7 +181,7 @@ func (ep *ExoscaleProvider) ApplyChanges(ctx context.Context, changes *plan.Chan } for _, epoint := range changes.UpdateOld { - // Since Exoscale "Patches", we ignore UpdateOld + // Since Exoscale "Patches", we've ignored UpdateOld // We leave this logging here for information log.Debugf("UPDATE-OLD (ignored) for epoint: %+v", epoint) } diff --git a/provider/godaddy/client.go b/provider/godaddy/client.go index e84b1feac..c199143cc 100644 --- a/provider/godaddy/client.go +++ b/provider/godaddy/client.go @@ -34,17 +34,15 @@ import ( "sigs.k8s.io/external-dns/pkg/apis/externaldns" ) -// DefaultTimeout api requests after 180s -const DefaultTimeout = 180 * time.Second - // Errors var ( ErrAPIDown = errors.New("godaddy: the GoDaddy API is down") ) -// error codes const ( ErrCodeQuotaExceeded = "QUOTA_EXCEEDED" + // DefaultTimeout api requests after 180s + DefaultTimeout = 180 * time.Second ) // APIError error diff --git a/provider/godaddy/godaddy.go b/provider/godaddy/godaddy.go index 58e5465fa..432fe8303 100644 --- a/provider/godaddy/godaddy.go +++ b/provider/godaddy/godaddy.go @@ -36,6 +36,8 @@ const ( gdCreate = 0 gdReplace = 1 gdDelete = 2 + + domainsURI = "/v1/domains?statuses=ACTIVE,PENDING_DNS_ACTIVE" ) var actionNames = []string{ @@ -44,8 +46,6 @@ var actionNames = []string{ "delete", } -const domainsURI = "/v1/domains?statuses=ACTIVE,PENDING_DNS_ACTIVE" - type gdClient interface { Patch(string, interface{}, interface{}) error Post(string, interface{}, interface{}) error diff --git a/provider/google/google.go b/provider/google/google.go index a3222ad59..148573b88 100644 --- a/provider/google/google.go +++ b/provider/google/google.go @@ -154,7 +154,7 @@ func NewGoogleProvider(ctx context.Context, project string, domainFilter endpoin zoneTypeFilter := provider.NewZoneTypeFilter(zoneVisibility) - provider := &GoogleProvider{ + return &GoogleProvider{ project: project, dryRun: dryRun, batchChangeSize: batchChangeSize, @@ -166,9 +166,7 @@ func NewGoogleProvider(ctx context.Context, project string, domainFilter endpoin managedZonesClient: managedZonesService{dnsClient.ManagedZones}, changesClient: changesService{dnsClient.Changes}, ctx: ctx, - } - - return provider, nil + }, nil } // Zones returns the list of hosted zones. @@ -261,11 +259,11 @@ func (p *GoogleProvider) SupportedRecordType(recordType string) bool { // newFilteredRecords returns a collection of RecordSets based on the given endpoints and domainFilter. func (p *GoogleProvider) newFilteredRecords(endpoints []*endpoint.Endpoint) []*dns.ResourceRecordSet { - records := []*dns.ResourceRecordSet{} + var records []*dns.ResourceRecordSet - for _, endpoint := range endpoints { - if p.domainFilter.Match(endpoint.DNSName) { - records = append(records, newRecord(endpoint)) + for _, ep := range endpoints { + if p.domainFilter.Match(ep.DNSName) { + records = append(records, newRecord(ep)) } } @@ -314,7 +312,7 @@ func (p *GoogleProvider) submitChange(ctx context.Context, change *dns.Change) e // batchChange separates a zone in multiple transaction. func batchChange(change *dns.Change, batchSize int) []*dns.Change { - changes := []*dns.Change{} + var changes []*dns.Change if batchSize == 0 { return append(changes, change) diff --git a/provider/ibmcloud/ibmcloud.go b/provider/ibmcloud/ibmcloud.go index 41fbab62c..c8a16cbdf 100644 --- a/provider/ibmcloud/ibmcloud.go +++ b/provider/ibmcloud/ibmcloud.go @@ -322,7 +322,7 @@ func NewIBMCloudProvider(configFile string, domainFilter endpoint.DomainFilter, return nil, err } - provider := &IBMCloudProvider{ + return &IBMCloudProvider{ Client: client, source: source, domainFilter: domainFilter, @@ -331,8 +331,7 @@ func NewIBMCloudProvider(configFile string, domainFilter endpoint.DomainFilter, privateZone: isPrivate, proxiedByDefault: proxiedByDefault, DryRun: dryRun, - } - return provider, nil + }, nil } // Records gets the current records. @@ -680,8 +679,8 @@ func (p *IBMCloudProvider) privateRecords(ctx context.Context) ([]*endpoint.Endp return nil, err } // Filter VPC annoation for private zone active - for _, source := range sources { - vpc = checkVPCAnnotation(source) + for _, src := range sources { + vpc = checkVPCAnnotation(src) if len(vpc) > 0 { log.Debugf("VPC found: %s", vpc) break @@ -984,7 +983,7 @@ func checkVPCAnnotation(endpoint *endpoint.Endpoint) string { for _, v := range endpoint.ProviderSpecific { if v.Name == vpcFilter { vpcCrn, err := crn.Parse(v.Value) - if vpcCrn.ResourceType != "vpc" || err != nil { + if err != nil || vpcCrn.ResourceType != "vpc" { log.Errorf("Failed to parse vpc [%s]: %v", v.Value, err) } else { vpc = v.Value @@ -1002,6 +1001,7 @@ func isNil(i interface{}) bool { switch reflect.TypeOf(i).Kind() { case reflect.Ptr, reflect.Map, reflect.Array, reflect.Chan, reflect.Slice: return reflect.ValueOf(i).IsNil() + default: + return false } - return false } diff --git a/provider/linode/linode.go b/provider/linode/linode.go index 71b839f19..0688b08d8 100644 --- a/provider/linode/linode.go +++ b/provider/linode/linode.go @@ -96,15 +96,14 @@ func NewLinodeProvider(domainFilter endpoint.DomainFilter, dryRun bool) (*Linode linodeClient := linodego.NewClient(oauth2Client) linodeClient.SetUserAgent(fmt.Sprintf("%s linodego/%s", externaldns.UserAgent(), linodego.Version)) - provider := &LinodeProvider{ + return &LinodeProvider{ Client: &linodeClient, domainFilter: domainFilter, DryRun: dryRun, - } - return provider, nil + }, nil } -// Zones returns the list of hosted zones. +// Zones return the list of hosted zones. func (p *LinodeProvider) Zones(ctx context.Context) ([]linodego.Domain, error) { zones, err := p.fetchZones(ctx) if err != nil { diff --git a/provider/ns1/ns1.go b/provider/ns1/ns1.go index 14f2b3c84..03b673d86 100644 --- a/provider/ns1/ns1.go +++ b/provider/ns1/ns1.go @@ -136,13 +136,12 @@ func newNS1ProviderWithHTTPClient(config NS1Config, client *http.Client) (*NS1Pr apiClient := api.NewClient(client, clientArgs...) - provider := &NS1Provider{ + return &NS1Provider{ client: NS1DomainService{apiClient}, domainFilter: config.DomainFilter, zoneIDFilter: config.ZoneIDFilter, minTTLSeconds: config.MinTTLSeconds, - } - return provider, nil + }, nil } // Records returns the endpoints this provider knows about @@ -257,7 +256,7 @@ func (p *NS1Provider) zonesFiltered() ([]*dns.Zone, error) { return nil, err } - toReturn := []*dns.Zone{} + var toReturn []*dns.Zone for _, z := range zones { if p.domainFilter.Match(z.Zone) && p.zoneIDFilter.Match(z.ID) { @@ -292,10 +291,10 @@ func (p *NS1Provider) ApplyChanges(ctx context.Context, changes *plan.Changes) e func newNS1Changes(action string, endpoints []*endpoint.Endpoint) []*ns1Change { changes := make([]*ns1Change, 0, len(endpoints)) - for _, endpoint := range endpoints { + for _, ep := range endpoints { changes = append(changes, &ns1Change{ Action: action, - Endpoint: endpoint, + Endpoint: ep, }, ) } diff --git a/provider/oci/oci.go b/provider/oci/oci.go index e56cbe3e0..66f291c5d 100644 --- a/provider/oci/oci.go +++ b/provider/oci/oci.go @@ -186,13 +186,13 @@ func mergeEndpointsMultiTargets(endpoints []*endpoint.Endpoint) []*endpoint.Endp // Otherwise, create a new list of endpoints with the consolidated targets. var mergedEndpoints []*endpoint.Endpoint - for _, endpoints := range endpointsByNameType { - dnsName := endpoints[0].DNSName - recordType := endpoints[0].RecordType - recordTTL := endpoints[0].RecordTTL + for _, ep := range endpointsByNameType { + dnsName := ep[0].DNSName + recordType := ep[0].RecordType + recordTTL := ep[0].RecordTTL - targets := make([]string, len(endpoints)) - for i, e := range endpoints { + targets := make([]string, len(ep)) + for i, e := range ep { targets[i] = e.Targets[0] } diff --git a/provider/ovh/ovh.go b/provider/ovh/ovh.go index 5b7eb8ee2..15c745b22 100644 --- a/provider/ovh/ovh.go +++ b/provider/ovh/ovh.go @@ -324,9 +324,9 @@ func (p *OVHProvider) change(ctx context.Context, change ovhChange) error { return nil } return p.client.PutWithContext(ctx, fmt.Sprintf("/domain/zone/%s/record/%d", url.PathEscape(change.Zone), change.ID), change.ovhRecordFieldUpdate, nil) + default: + return nil } - - return nil } func (p *OVHProvider) invalidateCache(zone string) { @@ -357,8 +357,8 @@ func (p *OVHProvider) zonesRecords(ctx context.Context) ([]string, []ovhRecord, } func (p *OVHProvider) zones(ctx context.Context) ([]string, error) { - zones := []string{} - filteredZones := []string{} + var zones []string + var filteredZones []string p.apiRateLimiter.Take() if err := p.client.GetWithContext(ctx, "/domain/zone", &zones); err != nil { @@ -476,25 +476,25 @@ func ovhGroupByNameAndType(records []ovhRecord) []*endpoint.Endpoint { // create single endpoint with all the targets for each name/type for _, records := range groups { - targets := []string{} + var targets []string for _, record := range records { targets = append(targets, record.Target) } - endpoint := endpoint.NewEndpointWithTTL( + ep := endpoint.NewEndpointWithTTL( strings.TrimPrefix(records[0].SubDomain+"."+records[0].Zone, "."), records[0].FieldType, endpoint.TTL(records[0].TTL), targets..., ) - endpoints = append(endpoints, endpoint) + endpoints = append(endpoints, ep) } return endpoints } func (p OVHProvider) newOvhChangeCreateDelete(action int, endpoints []*endpoint.Endpoint, zone string, existingRecords []ovhRecord) ([]ovhChange, []ovhRecord) { - ovhChanges := []ovhChange{} - toDeleteIds := []int{} + var ovhChanges []ovhChange + var toDeleteIds []int for _, e := range endpoints { for _, target := range e.Targets { @@ -579,13 +579,13 @@ func (p OVHProvider) newOvhChangeUpdate(endpointsOld []*endpoint.Endpoint, endpo } } - changes := []ovhChange{} + var changes []ovhChange for id := range oldEndpointByTypeAndName { oldRecords := slices.Clone(oldRecordsInZone[id]) endpointsNew := newEndpointByTypeAndName[id] - toInsertTarget := []string{} + var toInsertTarget []string for _, target := range endpointsNew.Targets { var toDelete = -1 diff --git a/provider/plural/plural.go b/provider/plural/plural.go index 9f5a77152..de6b2e1bb 100644 --- a/provider/plural/plural.go +++ b/provider/plural/plural.go @@ -45,7 +45,6 @@ type RecordChange struct { func NewPluralProvider(cluster, provider string) (*PluralProvider, error) { token := os.Getenv("PLURAL_ACCESS_TOKEN") - endpoint := os.Getenv("PLURAL_ENDPOINT") if token == "" { return nil, fmt.Errorf("no plural access token provided, you must set the PLURAL_ACCESS_TOKEN env var") @@ -53,21 +52,19 @@ func NewPluralProvider(cluster, provider string) (*PluralProvider, error) { config := &Config{ Token: token, - Endpoint: endpoint, + Endpoint: os.Getenv("PLURAL_ENDPOINT"), Cluster: cluster, Provider: provider, } - client, err := NewClient(config) + cl, err := NewClient(config) if err != nil { return nil, err } - prov := &PluralProvider{ - Client: client, - } - - return prov, nil + return &PluralProvider{ + Client: cl, + }, nil } func (p *PluralProvider) Records(_ context.Context) (endpoints []*endpoint.Endpoint, err error) { @@ -89,8 +86,8 @@ func (p *PluralProvider) AdjustEndpoints(endpoints []*endpoint.Endpoint) ([]*end func (p *PluralProvider) ApplyChanges(_ context.Context, diffs *plan.Changes) error { var changes []*RecordChange - for _, endpoint := range diffs.Create { - changes = append(changes, makeChange(CreateAction, endpoint.Targets, endpoint)) + for _, ep := range diffs.Create { + changes = append(changes, makeChange(CreateAction, ep.Targets, ep)) } for _, desired := range diffs.UpdateNew { diff --git a/provider/tencentcloud/tencent_cloud_test.go b/provider/tencentcloud/tencent_cloud_test.go index b9ee48579..06355a391 100644 --- a/provider/tencentcloud/tencent_cloud_test.go +++ b/provider/tencentcloud/tencent_cloud_test.go @@ -32,8 +32,6 @@ import ( func NewMockTencentCloudProvider(domainFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, zoneType string) *TencentCloudProvider { cfg := tencentCloudConfig{ - // SecretId: "", - // SecretKey: "", RegionId: "ap-shanghai", VPCId: "vpc-abcdefg", } diff --git a/provider/ultradns/ultradns.go b/provider/ultradns/ultradns.go index 9303813c8..1b2f2297a 100644 --- a/provider/ultradns/ultradns.go +++ b/provider/ultradns/ultradns.go @@ -39,23 +39,20 @@ const ( rdPoolOrder = "ROUND_ROBIN" ) -// global variables -var sbPoolRunProbes = true - var ( sbPoolActOnProbes = true ultradnsPoolType = "rdpool" accountName string + sbPoolRunProbes = true + // Setting custom headers for ultradns api calls + customHeader = []udnssdk.CustomHeader{ + { + Key: "UltraClient", + Value: "kube-client", + }, + } ) -// Setting custom headers for ultradns api calls -var customHeader = []udnssdk.CustomHeader{ - { - Key: "UltraClient", - Value: "kube-client", - }, -} - // UltraDNSProvider struct type UltraDNSProvider struct { provider.BaseProvider @@ -128,13 +125,11 @@ func NewUltraDNSProvider(domainFilter endpoint.DomainFilter, dryRun bool) (*Ultr return nil, fmt.Errorf("connection cannot be established") } - provider := &UltraDNSProvider{ + return &UltraDNSProvider{ client: *client, domainFilter: domainFilter, dryRun: dryRun, - } - - return provider, nil + }, nil } // Zones returns list of hosted zones @@ -216,7 +211,7 @@ func (p *UltraDNSProvider) fetchRecords(ctx context.Context, k udnssdk.RRSetKey) maxerrs := 5 waittime := 5 * time.Second - rrsets := []udnssdk.RRSet{} + var rrsets []udnssdk.RRSet errcnt := 0 offset := 0 limit := 1000 From f6cd8b9babc3216a57d3dbb4a83f4dad2301f20b Mon Sep 17 00:00:00 2001 From: Bas Janssen Date: Thu, 24 Apr 2025 13:12:40 +0200 Subject: [PATCH 11/42] RFC2136: Update flags documentation to be more clear about multiple zones. --- docs/flags.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/flags.md b/docs/flags.md index 9218ba868..39aee70eb 100644 --- a/docs/flags.md +++ b/docs/flags.md @@ -133,7 +133,7 @@ | `--exoscale-apisecret=""` | Provide your API Secret for the Exoscale provider | | `--rfc2136-host=` | When using the RFC2136 provider, specify the host of the DNS server (optionally specify multiple times when when using --rfc2136-load-balancing-strategy) | | `--rfc2136-port=0` | When using the RFC2136 provider, specify the port of the DNS server | -| `--rfc2136-zone=RFC2136-ZONE` | When using the RFC2136 provider, specify zone entries of the DNS server to use | +| `--rfc2136-zone=RFC2136-ZONE` | When using the RFC2136 provider, specify zone entry of the DNS server to use (can be specified multiple times.) | | `--[no-]rfc2136-create-ptr` | When using the RFC2136 provider, enable PTR management | | `--[no-]rfc2136-insecure` | When using the RFC2136 provider, specify whether to attach TSIG or not (default: false, requires --rfc2136-tsig-keyname and rfc2136-tsig-secret) | | `--rfc2136-tsig-keyname=""` | When using the RFC2136 provider, specify the TSIG key to attached to DNS messages (required when --rfc2136-insecure=false) | From 7d57ac2394476b10d0b44bc7283f876bee564a0f Mon Sep 17 00:00:00 2001 From: Bas Janssen Date: Thu, 24 Apr 2025 13:13:15 +0200 Subject: [PATCH 12/42] RFC2136: Update tutorial to show Helm example with TSIG in secret --- docs/tutorials/rfc2136.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/docs/tutorials/rfc2136.md b/docs/tutorials/rfc2136.md index c14c184bf..5211a6d7c 100644 --- a/docs/tutorials/rfc2136.md +++ b/docs/tutorials/rfc2136.md @@ -497,6 +497,35 @@ external-dns \ --rfc2136-insecure ``` +### Helm + +```yaml +extraArgs: + - --rfc2136-host="dns-host-1.yourdomain.com" + - --rfc2136-port=53 + - --rfc2136-zone=example.com + - --rfc2136-tsig-secret-alg=hmac-sha256 + - --rfc2136-tsig-axfr + +env: + - name: "EXTERNAL_DNS_RDC2136_TSIG_SECRET" + valueFrom: + secretKeyRef: + name: rfc2136-keys + key: rfc2136-tsig-secret + - name: "EXTERNAL_DNS_RDC2136_TSIG_KEYNAME" + valueFrom: + secretKeyRef: + name: rfc2136-keys + key: rfc2136-tsig-keyname +``` + +#### Secret creation + +```shell +kubectl create secret generic rfc2136-keys --from-literal=rfc2136-tsig-secret='xxx' --from-literal=rfc2136-tsig-keyname='k8s-external-dns-key' -n external-dns +``` + ### Benefits - Distributes the load of DNS updates across multiple data centers, preventing any single DC from becoming a bottleneck. From 7a2ba6dec6400c5c602d16cb188f4d83114b868a Mon Sep 17 00:00:00 2001 From: Bas Janssen Date: Thu, 24 Apr 2025 16:19:28 +0200 Subject: [PATCH 13/42] Update flags doc in correct location --- docs/flags.md | 2 +- pkg/apis/externaldns/types.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/flags.md b/docs/flags.md index 39aee70eb..3cf19d4d8 100644 --- a/docs/flags.md +++ b/docs/flags.md @@ -133,7 +133,7 @@ | `--exoscale-apisecret=""` | Provide your API Secret for the Exoscale provider | | `--rfc2136-host=` | When using the RFC2136 provider, specify the host of the DNS server (optionally specify multiple times when when using --rfc2136-load-balancing-strategy) | | `--rfc2136-port=0` | When using the RFC2136 provider, specify the port of the DNS server | -| `--rfc2136-zone=RFC2136-ZONE` | When using the RFC2136 provider, specify zone entry of the DNS server to use (can be specified multiple times.) | +| `--rfc2136-zone=RFC2136-ZONE` | When using the RFC2136 provider, specify zone entry of the DNS server to use (can be specified multiple times) | | `--[no-]rfc2136-create-ptr` | When using the RFC2136 provider, enable PTR management | | `--[no-]rfc2136-insecure` | When using the RFC2136 provider, specify whether to attach TSIG or not (default: false, requires --rfc2136-tsig-keyname and rfc2136-tsig-secret) | | `--rfc2136-tsig-keyname=""` | When using the RFC2136 provider, specify the TSIG key to attached to DNS messages (required when --rfc2136-insecure=false) | diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index 36cd3a9bb..5e9aac21a 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -580,7 +580,7 @@ func App(cfg *Config) *kingpin.Application { // Flags related to RFC2136 provider app.Flag("rfc2136-host", "When using the RFC2136 provider, specify the host of the DNS server (optionally specify multiple times when when using --rfc2136-load-balancing-strategy)").Default(defaultConfig.RFC2136Host[0]).StringsVar(&cfg.RFC2136Host) app.Flag("rfc2136-port", "When using the RFC2136 provider, specify the port of the DNS server").Default(strconv.Itoa(defaultConfig.RFC2136Port)).IntVar(&cfg.RFC2136Port) - app.Flag("rfc2136-zone", "When using the RFC2136 provider, specify zone entries of the DNS server to use").StringsVar(&cfg.RFC2136Zone) + app.Flag("rfc2136-zone", "When using the RFC2136 provider, specify zone entry of the DNS server to use (can be specified multiple times)").StringsVar(&cfg.RFC2136Zone) app.Flag("rfc2136-create-ptr", "When using the RFC2136 provider, enable PTR management").Default(strconv.FormatBool(defaultConfig.RFC2136CreatePTR)).BoolVar(&cfg.RFC2136CreatePTR) app.Flag("rfc2136-insecure", "When using the RFC2136 provider, specify whether to attach TSIG or not (default: false, requires --rfc2136-tsig-keyname and rfc2136-tsig-secret)").Default(strconv.FormatBool(defaultConfig.RFC2136Insecure)).BoolVar(&cfg.RFC2136Insecure) app.Flag("rfc2136-tsig-keyname", "When using the RFC2136 provider, specify the TSIG key to attached to DNS messages (required when --rfc2136-insecure=false)").Default(defaultConfig.RFC2136TSIGKeyName).StringVar(&cfg.RFC2136TSIGKeyName) From 972bdfcadd480f4f6573173c871ef1f42707ef9b Mon Sep 17 00:00:00 2001 From: Michel Loiseleur Date: Sun, 27 Apr 2025 22:03:10 +0200 Subject: [PATCH 14/42] test(source): fix data race on node_test --- source/node_test.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/source/node_test.go b/source/node_test.go index 4e05cde31..9746bbaba 100644 --- a/source/node_test.go +++ b/source/node_test.go @@ -97,8 +97,6 @@ func testNodeSourceNewNodeSource(t *testing.T) { // testNodeSourceEndpoints tests that various node generate the correct endpoints. func testNodeSourceEndpoints(t *testing.T) { - t.Parallel() - for _, tc := range []struct { title string annotationFilter string @@ -392,7 +390,6 @@ func testNodeSourceEndpoints(t *testing.T) { }, }, } { - tc := tc t.Run(tc.title, func(t *testing.T) { buf := testutils.LogsToBuffer(log.DebugLevel, t) From 3c93bcb0768966fa97ce8b120495531eb7f6aa79 Mon Sep 17 00:00:00 2001 From: Michel Loiseleur <97035654+mloiseleur@users.noreply.github.com> Date: Sun, 27 Apr 2025 23:11:24 +0200 Subject: [PATCH 15/42] chore(code): improve some tests + re-order sources flags CLI (#5288) * fix(plan): always use managed records * robust random port in test * use defaultconfig for managed-record-types * be explicit about static variable * fix wait * re-order flags related to sources + dynamic managedrecordtype help * fix flag doc --- controller/execute_test.go | 50 +++-- docs/flags.md | 52 ++--- pkg/apis/externaldns/types.go | 370 +++++++++++++++++----------------- plan/plan.go | 8 +- plan/plan_test.go | 17 +- 5 files changed, 270 insertions(+), 227 deletions(-) diff --git a/controller/execute_test.go b/controller/execute_test.go index 8d761bccb..442e3d7b7 100644 --- a/controller/execute_test.go +++ b/controller/execute_test.go @@ -18,6 +18,7 @@ package controller import ( "bytes" + "context" "fmt" "net" "net/http" @@ -29,10 +30,9 @@ import ( "testing" "time" - "context" - log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "sigs.k8s.io/external-dns/endpoint" "sigs.k8s.io/external-dns/pkg/apis/externaldns" "sigs.k8s.io/external-dns/plan" @@ -219,18 +219,45 @@ func TestHandleSigterm(t *testing.T) { } } -func TestServeMetrics(t *testing.T) { - l, _ := net.Listen("tcp", ":0") - _ = l.Close() - _, port, _ := net.SplitHostPort(l.Addr().String()) +func getRandomPort() (int, error) { + addr, err := net.ResolveTCPAddr("tcp", "localhost:0") + if err != nil { + return 0, err + } - go serveMetrics(fmt.Sprintf(":%s", port)) - resp, err := http.Get(fmt.Sprintf("http://localhost:%s", port) + "/healthz") - assert.NoError(t, err) + l, err := net.ListenTCP("tcp", addr) + if err != nil { + return 0, err + } + defer l.Close() + return l.Addr().(*net.TCPAddr).Port, nil +} + +func TestServeMetrics(t *testing.T) { + t.Parallel() + + port, err := getRandomPort() + require.NoError(t, err) + addresse := fmt.Sprintf("localhost:%d", port) + + go serveMetrics(fmt.Sprintf(":%d", port)) + + // Wait for the TCP socket to be ready + require.Eventually(t, func() bool { + conn, err := net.Dial("tcp", addresse) + if err != nil { + return false + } + _ = conn.Close() + return true + }, 1*time.Second, 5*time.Millisecond, "server not ready with port open in time") + + resp, err := http.Get(fmt.Sprintf("http://%s/healthz", addresse)) + require.NoError(t, err) assert.Equal(t, http.StatusOK, resp.StatusCode) - resp, err = http.Get(fmt.Sprintf("http://localhost:%s", port) + "/metrics") - assert.NoError(t, err) + resp, err = http.Get(fmt.Sprintf("http://%s/metrics", addresse)) + require.NoError(t, err) assert.Equal(t, http.StatusOK, resp.StatusCode) } @@ -308,7 +335,6 @@ func (m *MockProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error } func (p *MockProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error { - return nil } diff --git a/docs/flags.md b/docs/flags.md index 3cf19d4d8..06af52774 100644 --- a/docs/flags.md +++ b/docs/flags.md @@ -17,40 +17,40 @@ | `--cf-password=""` | The password to log into the cloud foundry API | | `--gloo-namespace=gloo-system` | The Gloo Proxy namespace; specify multiple times for multiple namespaces. (default: gloo-system) | | `--skipper-routegroup-groupversion="zalando.org/v1"` | The resource version for skipper routegroup | -| `--source=source` | The resource types that are queried for endpoints; specify multiple times for multiple sources (required, options: service, ingress, node, pod, fake, connector, gateway-httproute, gateway-grpcroute, gateway-tlsroute, gateway-tcproute, gateway-udproute, istio-gateway, istio-virtualservice, cloudfoundry, contour-httpproxy, gloo-proxy, crd, empty, skipper-routegroup, openshift-route, ambassador-host, kong-tcpingress, f5-virtualserver, f5-transportserver, traefik-proxy) | -| `--openshift-router-name=OPENSHIFT-ROUTER-NAME` | if source is openshift-route then you can pass the ingress controller name. Based on this name external-dns will select the respective router from the route status and map that routerCanonicalHostname to the route host while creating a CNAME record. | -| `--namespace=""` | Limit resources queried for endpoints to a specific namespace (default: all namespaces) | -| `--annotation-filter=""` | Filter resources queried for endpoints by annotation, using label selector semantics | -| `--label-filter=""` | Filter resources queried for endpoints by label selector; currently supported by source types crd, gateway-httproute, gateway-grpcroute, gateway-tlsroute, gateway-tcproute, gateway-udproute, ingress, node, openshift-route, service and ambassador-host | -| `--ingress-class=INGRESS-CLASS` | Require an Ingress to have this class name (defaults to any class; specify multiple times to allow more than one class) | -| `--fqdn-template=""` | A templated string that's used to generate DNS names from sources that don't define a hostname themselves, or to add a hostname suffix when paired with the fake source (optional). Accepts comma separated list for multiple global FQDN. | -| `--[no-]combine-fqdn-annotation` | Combine FQDN template and Annotations instead of overwriting | -| `--[no-]ignore-hostname-annotation` | Ignore hostname annotation when generating DNS names, valid only when --fqdn-template is set (default: false) | -| `--[no-]ignore-non-host-network-pods` | Ignore pods not running on host network when using pod source (default: true) | -| `--[no-]ignore-ingress-tls-spec` | Ignore the spec.tls section in Ingress resources (default: false) | -| `--gateway-name=GATEWAY-NAME` | Limit Gateways of Route endpoints to a specific name (default: all names) | -| `--gateway-namespace=GATEWAY-NAMESPACE` | Limit Gateways of Route endpoints to a specific namespace (default: all namespaces) | -| `--gateway-label-filter=GATEWAY-LABEL-FILTER` | Filter Gateways of Route endpoints via label selector (default: all gateways) | -| `--compatibility=` | Process annotation semantics from legacy implementations (optional, options: mate, molecule, kops-dns-controller) | -| `--[no-]ignore-ingress-rules-spec` | Ignore the spec.rules section in Ingress resources (default: false) | -| `--pod-source-domain=""` | Domain to use for pods records (optional) | -| `--[no-]publish-internal-services` | Allow external-dns to publish DNS records for ClusterIP services (optional) | -| `--[no-]publish-host-ip` | Allow external-dns to publish host-ip for headless services (optional) | | `--[no-]always-publish-not-ready-addresses` | Always publish also not ready addresses for headless services (optional) | +| `--annotation-filter=""` | Filter resources queried for endpoints by annotation, using label selector semantics | +| `--[no-]combine-fqdn-annotation` | Combine FQDN template and Annotations instead of overwriting | +| `--compatibility=` | Process annotation semantics from legacy implementations (optional, options: mate, molecule, kops-dns-controller) | | `--connector-source-server="localhost:8080"` | The server to connect for connector source, valid only when using connector source | | `--crd-source-apiversion="externaldns.k8s.io/v1alpha1"` | API version of the CRD for crd source, e.g. `externaldns.k8s.io/v1alpha1`, valid only when using crd source | | `--crd-source-kind="DNSEndpoint"` | Kind of the CRD for the crd source in API group and version specified by crd-source-apiversion | -| `--service-type-filter=SERVICE-TYPE-FILTER` | The service types to take care about (default: all, expected: ClusterIP, NodePort, LoadBalancer or ExternalName) | -| `--managed-record-types=A...` | Record types to manage; specify multiple times to include many; (default: A, AAAA, CNAME) (supported records: A, AAAA, CNAME, NS, SRV, TXT) | -| `--exclude-record-types=EXCLUDE-RECORD-TYPES` | Record types to exclude from management; specify multiple times to exclude many; (optional) | | `--default-targets=DEFAULT-TARGETS` | Set globally default host/IP that will apply as a target instead of source addresses. Specify multiple times for multiple targets (optional) | -| `--target-net-filter=TARGET-NET-FILTER` | Limit possible targets by a net filter; specify multiple times for multiple possible nets (optional) | +| `--exclude-record-types=EXCLUDE-RECORD-TYPES` | Record types to exclude from management; specify multiple times to exclude many; (optional) | | `--exclude-target-net=EXCLUDE-TARGET-NET` | Exclude target nets (optional) | -| `--[no-]traefik-disable-legacy` | Disable listeners on Resources under the traefik.containo.us API Group | -| `--[no-]traefik-disable-new` | Disable listeners on Resources under the traefik.io API Group | -| `--nat64-networks=NAT64-NETWORKS` | Adding an A record for each AAAA record in NAT64-enabled networks; specify multiple times for multiple possible nets (optional) | | `--[no-]exclude-unschedulable` | Exclude nodes that are considered unschedulable (default: true) | | `--[no-]expose-internal-ipv6` | When using the node source, expose internal IPv6 addresses (optional). Default is true. | +| `--fqdn-template=""` | A templated string that's used to generate DNS names from sources that don't define a hostname themselves, or to add a hostname suffix when paired with the fake source (optional). Accepts comma separated list for multiple global FQDN. | +| `--gateway-label-filter=GATEWAY-LABEL-FILTER` | Filter Gateways of Route endpoints via label selector (default: all gateways) | +| `--gateway-name=GATEWAY-NAME` | Limit Gateways of Route endpoints to a specific name (default: all names) | +| `--gateway-namespace=GATEWAY-NAMESPACE` | Limit Gateways of Route endpoints to a specific namespace (default: all namespaces) | +| `--[no-]ignore-hostname-annotation` | Ignore hostname annotation when generating DNS names, valid only when --fqdn-template is set (default: false) | +| `--[no-]ignore-ingress-rules-spec` | Ignore the spec.rules section in Ingress resources (default: false) | +| `--[no-]ignore-ingress-tls-spec` | Ignore the spec.tls section in Ingress resources (default: false) | +| `--[no-]ignore-non-host-network-pods` | Ignore pods not running on host network when using pod source (default: true) | +| `--ingress-class=INGRESS-CLASS` | Require an Ingress to have this class name (defaults to any class; specify multiple times to allow more than one class) | +| `--label-filter=""` | Filter resources queried for endpoints by label selector; currently supported by source types crd, gateway-httproute, gateway-grpcroute, gateway-tlsroute, gateway-tcproute, gateway-udproute, ingress, node, openshift-route, service and ambassador-host | +| `--managed-record-types=A...` | Record types to manage; specify multiple times to include many; (default: A,AAAA,CNAME) (supported records: A, AAAA, CNAME, NS, SRV, TXT) | +| `--namespace=""` | Limit resources queried for endpoints to a specific namespace (default: all namespaces) | +| `--nat64-networks=NAT64-NETWORKS` | Adding an A record for each AAAA record in NAT64-enabled networks; specify multiple times for multiple possible nets (optional) | +| `--openshift-router-name=OPENSHIFT-ROUTER-NAME` | if source is openshift-route then you can pass the ingress controller name. Based on this name external-dns will select the respective router from the route status and map that routerCanonicalHostname to the route host while creating a CNAME record. | +| `--pod-source-domain=""` | Domain to use for pods records (optional) | +| `--[no-]publish-host-ip` | Allow external-dns to publish host-ip for headless services (optional) | +| `--[no-]publish-internal-services` | Allow external-dns to publish DNS records for ClusterIP services (optional) | +| `--service-type-filter=SERVICE-TYPE-FILTER` | The service types to take care about (default: all, expected: ClusterIP, NodePort, LoadBalancer or ExternalName) | +| `--source=source` | The resource types that are queried for endpoints; specify multiple times for multiple sources (required, options: service, ingress, node, pod, fake, connector, gateway-httproute, gateway-grpcroute, gateway-tlsroute, gateway-tcproute, gateway-udproute, istio-gateway, istio-virtualservice, cloudfoundry, contour-httpproxy, gloo-proxy, crd, empty, skipper-routegroup, openshift-route, ambassador-host, kong-tcpingress, f5-virtualserver, f5-transportserver, traefik-proxy) | +| `--target-net-filter=TARGET-NET-FILTER` | Limit possible targets by a net filter; specify multiple times for multiple possible nets (optional) | +| `--[no-]traefik-disable-legacy` | Disable listeners on Resources under the traefik.containo.us API Group | +| `--[no-]traefik-disable-new` | Disable listeners on Resources under the traefik.io API Group | | `--provider=provider` | The DNS provider where the DNS records will be created (required, options: akamai, alibabacloud, aws, aws-sd, azure, azure-dns, azure-private-dns, civo, cloudflare, coredns, digitalocean, dnsimple, exoscale, gandi, godaddy, google, ibmcloud, inmemory, linode, ns1, oci, ovh, pdns, pihole, plural, rfc2136, scaleway, skydns, tencentcloud, transip, ultradns, webhook) | | `--provider-cache-time=0s` | The time to cache the DNS provider record list requests. | | `--domain-filter=` | Limit possible target zones by a domain suffix; specify multiple times for multiple domains (optional) | diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index 5e9aac21a..b8e8d5c9b 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -217,167 +217,168 @@ type Config struct { } var defaultConfig = &Config{ - APIServerURL: "", - KubeConfig: "", - RequestTimeout: time.Second * 30, - DefaultTargets: []string{}, - GlooNamespaces: []string{"gloo-system"}, - SkipperRouteGroupVersion: "zalando.org/v1", - Sources: nil, - Namespace: "", - AnnotationFilter: "", - LabelFilter: labels.Everything().String(), - IngressClassNames: nil, - FQDNTemplate: "", - CombineFQDNAndAnnotation: false, - IgnoreHostnameAnnotation: false, - IgnoreIngressTLSSpec: false, - IgnoreIngressRulesSpec: false, - GatewayName: "", - GatewayNamespace: "", - GatewayLabelFilter: "", - Compatibility: "", - PublishInternal: false, - PublishHostIP: false, - ExposeInternalIPV6: true, - ConnectorSourceServer: "localhost:8080", - Provider: "", - ProviderCacheTime: 0, - GoogleProject: "", - GoogleBatchChangeSize: 1000, - GoogleBatchChangeInterval: time.Second, - GoogleZoneVisibility: "", - DomainFilter: []string{}, - ZoneIDFilter: []string{}, - ExcludeDomains: []string{}, - RegexDomainFilter: regexp.MustCompile(""), - RegexDomainExclusion: regexp.MustCompile(""), - TargetNetFilter: []string{}, - ExcludeTargetNets: []string{}, - AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json", - AWSZoneType: "", - AWSZoneTagFilter: []string{}, - AWSZoneMatchParent: false, - AWSAssumeRole: "", - AWSAssumeRoleExternalID: "", - AWSBatchChangeSize: 1000, - AWSBatchChangeSizeBytes: 32000, - AWSBatchChangeSizeValues: 1000, - AWSBatchChangeInterval: time.Second, - AWSEvaluateTargetHealth: true, - AWSAPIRetries: 3, - AWSPreferCNAME: false, - AWSZoneCacheDuration: 0 * time.Second, - AWSSDServiceCleanup: false, - AWSSDCreateTag: map[string]string{}, - AWSDynamoDBRegion: "", - AWSDynamoDBTable: "external-dns", - AzureConfigFile: "/etc/kubernetes/azure.json", - AzureResourceGroup: "", - AzureSubscriptionID: "", - AzureZonesCacheDuration: 0 * time.Second, - CloudflareProxied: false, - CloudflareCustomHostnames: false, - CloudflareCustomHostnamesMinTLSVersion: "1.0", + AkamaiAccessToken: "", + AkamaiClientSecret: "", + AkamaiClientToken: "", + AkamaiEdgercPath: "", + AkamaiEdgercSection: "", + AkamaiServiceConsumerDomain: "", + AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json", + AnnotationFilter: "", + APIServerURL: "", + AWSAPIRetries: 3, + AWSAssumeRole: "", + AWSAssumeRoleExternalID: "", + AWSBatchChangeInterval: time.Second, + AWSBatchChangeSize: 1000, + AWSBatchChangeSizeBytes: 32000, + AWSBatchChangeSizeValues: 1000, + AWSDynamoDBRegion: "", + AWSDynamoDBTable: "external-dns", + AWSEvaluateTargetHealth: true, + AWSPreferCNAME: false, + AWSSDCreateTag: map[string]string{}, + AWSSDServiceCleanup: false, + AWSZoneCacheDuration: 0 * time.Second, + AWSZoneMatchParent: false, + AWSZoneTagFilter: []string{}, + AWSZoneType: "", + AzureConfigFile: "/etc/kubernetes/azure.json", + AzureResourceGroup: "", + AzureSubscriptionID: "", + AzureZonesCacheDuration: 0 * time.Second, + CFAPIEndpoint: "", + CFPassword: "", + CFUsername: "", CloudflareCustomHostnamesCertificateAuthority: "google", + CloudflareCustomHostnames: false, + CloudflareCustomHostnamesMinTLSVersion: "1.0", CloudflareDNSRecordsPerPage: 100, + CloudflareProxied: false, CloudflareRegionKey: "earth", - CoreDNSPrefix: "/skydns/", - AkamaiServiceConsumerDomain: "", - AkamaiClientToken: "", - AkamaiClientSecret: "", - AkamaiAccessToken: "", - AkamaiEdgercSection: "", - AkamaiEdgercPath: "", - OCIConfigFile: "/etc/kubernetes/oci.yaml", - OCIZoneScope: "GLOBAL", - OCIZoneCacheDuration: 0 * time.Second, - InMemoryZones: []string{}, - OVHEndpoint: "ovh-eu", - OVHApiRateLimit: 20, - OVHEnableCNAMERelative: false, - PDNSServer: "http://localhost:8081", - PDNSServerID: "localhost", - PDNSAPIKey: "", - PDNSSkipTLSVerify: false, - PodSourceDomain: "", - TLSCA: "", - TLSClientCert: "", - TLSClientCertKey: "", - Policy: "sync", - Registry: "txt", - TXTOwnerID: "default", - TXTPrefix: "", - TXTSuffix: "", - TXTCacheInterval: 0, - TXTWildcardReplacement: "", - MinEventSyncInterval: 5 * time.Second, - TXTEncryptEnabled: false, - TXTEncryptAESKey: "", - TXTNewFormatOnly: false, - Interval: time.Minute, - Once: false, - DryRun: false, - UpdateEvents: false, - LogFormat: "text", - MetricsAddress: ":7979", - LogLevel: logrus.InfoLevel.String(), - ExoscaleAPIEnvironment: "api", - ExoscaleAPIZone: "ch-gva-2", - ExoscaleAPIKey: "", - ExoscaleAPISecret: "", - CRDSourceAPIVersion: "externaldns.k8s.io/v1alpha1", - CRDSourceKind: "DNSEndpoint", - ServiceTypeFilter: []string{}, - CFAPIEndpoint: "", - CFUsername: "", - CFPassword: "", - RFC2136Host: []string{""}, - RFC2136Port: 0, - RFC2136Zone: []string{}, - RFC2136Insecure: false, - RFC2136GSSTSIG: false, - RFC2136KerberosRealm: "", - RFC2136KerberosUsername: "", - RFC2136KerberosPassword: "", - RFC2136TSIGKeyName: "", - RFC2136TSIGSecret: "", - RFC2136TSIGSecretAlg: "", - RFC2136TAXFR: true, - RFC2136MinTTL: 0, - RFC2136BatchChangeSize: 50, - RFC2136UseTLS: false, - RFC2136LoadBalancingStrategy: "disabled", - RFC2136SkipTLSVerify: false, - NS1Endpoint: "", - NS1IgnoreSSL: false, - TransIPAccountName: "", - TransIPPrivateKeyFile: "", - DigitalOceanAPIPageSize: 50, - ManagedDNSRecordTypes: []string{endpoint.RecordTypeA, endpoint.RecordTypeAAAA, endpoint.RecordTypeCNAME}, - ExcludeDNSRecordTypes: []string{}, - GoDaddyAPIKey: "", - GoDaddySecretKey: "", - GoDaddyTTL: 600, - GoDaddyOTE: false, - IBMCloudProxied: false, - IBMCloudConfigFile: "/etc/kubernetes/ibmcloud.json", - TencentCloudConfigFile: "/etc/kubernetes/tencent-cloud.json", - TencentCloudZoneType: "", - PiholeServer: "", - PiholePassword: "", - PiholeTLSInsecureSkipVerify: false, - PiholeApiVersion: "5", - PluralCluster: "", - PluralProvider: "", - WebhookProviderURL: "http://localhost:8888", - WebhookProviderReadTimeout: 5 * time.Second, - WebhookProviderWriteTimeout: 10 * time.Second, - WebhookServer: false, - TraefikDisableLegacy: false, - TraefikDisableNew: false, - NAT64Networks: []string{}, - ExcludeUnschedulable: true, + + CombineFQDNAndAnnotation: false, + Compatibility: "", + ConnectorSourceServer: "localhost:8080", + CoreDNSPrefix: "/skydns/", + CRDSourceAPIVersion: "externaldns.k8s.io/v1alpha1", + CRDSourceKind: "DNSEndpoint", + DefaultTargets: []string{}, + DigitalOceanAPIPageSize: 50, + DomainFilter: []string{}, + DryRun: false, + ExcludeDNSRecordTypes: []string{}, + ExcludeDomains: []string{}, + ExcludeTargetNets: []string{}, + ExcludeUnschedulable: true, + ExoscaleAPIEnvironment: "api", + ExoscaleAPIKey: "", + ExoscaleAPISecret: "", + ExoscaleAPIZone: "ch-gva-2", + ExposeInternalIPV6: true, + FQDNTemplate: "", + GatewayLabelFilter: "", + GatewayName: "", + GatewayNamespace: "", + GlooNamespaces: []string{"gloo-system"}, + GoDaddyAPIKey: "", + GoDaddyOTE: false, + GoDaddySecretKey: "", + GoDaddyTTL: 600, + GoogleBatchChangeInterval: time.Second, + GoogleBatchChangeSize: 1000, + GoogleProject: "", + GoogleZoneVisibility: "", + IBMCloudConfigFile: "/etc/kubernetes/ibmcloud.json", + IBMCloudProxied: false, + IgnoreHostnameAnnotation: false, + IgnoreIngressRulesSpec: false, + IgnoreIngressTLSSpec: false, + IngressClassNames: nil, + InMemoryZones: []string{}, + Interval: time.Minute, + KubeConfig: "", + LabelFilter: labels.Everything().String(), + LogFormat: "text", + LogLevel: logrus.InfoLevel.String(), + ManagedDNSRecordTypes: []string{endpoint.RecordTypeA, endpoint.RecordTypeAAAA, endpoint.RecordTypeCNAME}, + MetricsAddress: ":7979", + MinEventSyncInterval: 5 * time.Second, + Namespace: "", + NAT64Networks: []string{}, + NS1Endpoint: "", + NS1IgnoreSSL: false, + OCIConfigFile: "/etc/kubernetes/oci.yaml", + OCIZoneCacheDuration: 0 * time.Second, + OCIZoneScope: "GLOBAL", + Once: false, + OVHApiRateLimit: 20, + OVHEnableCNAMERelative: false, + OVHEndpoint: "ovh-eu", + PDNSAPIKey: "", + PDNSServer: "http://localhost:8081", + PDNSServerID: "localhost", + PDNSSkipTLSVerify: false, + PiholeApiVersion: "5", + PiholePassword: "", + PiholeServer: "", + PiholeTLSInsecureSkipVerify: false, + PluralCluster: "", + PluralProvider: "", + PodSourceDomain: "", + Policy: "sync", + Provider: "", + ProviderCacheTime: 0, + PublishHostIP: false, + PublishInternal: false, + RegexDomainExclusion: regexp.MustCompile(""), + RegexDomainFilter: regexp.MustCompile(""), + Registry: "txt", + RequestTimeout: time.Second * 30, + RFC2136BatchChangeSize: 50, + RFC2136GSSTSIG: false, + RFC2136Host: []string{""}, + RFC2136Insecure: false, + RFC2136KerberosPassword: "", + RFC2136KerberosRealm: "", + RFC2136KerberosUsername: "", + RFC2136LoadBalancingStrategy: "disabled", + RFC2136MinTTL: 0, + RFC2136Port: 0, + RFC2136SkipTLSVerify: false, + RFC2136TAXFR: true, + RFC2136TSIGKeyName: "", + RFC2136TSIGSecret: "", + RFC2136TSIGSecretAlg: "", + RFC2136UseTLS: false, + RFC2136Zone: []string{}, + ServiceTypeFilter: []string{}, + SkipperRouteGroupVersion: "zalando.org/v1", + Sources: nil, + TargetNetFilter: []string{}, + TencentCloudConfigFile: "/etc/kubernetes/tencent-cloud.json", + TencentCloudZoneType: "", + TLSCA: "", + TLSClientCert: "", + TLSClientCertKey: "", + TraefikDisableLegacy: false, + TraefikDisableNew: false, + TransIPAccountName: "", + TransIPPrivateKeyFile: "", + TXTCacheInterval: 0, + TXTEncryptAESKey: "", + TXTEncryptEnabled: false, + TXTNewFormatOnly: false, + TXTOwnerID: "default", + TXTPrefix: "", + TXTSuffix: "", + TXTWildcardReplacement: "", + UpdateEvents: false, + WebhookProviderReadTimeout: 5 * time.Second, + WebhookProviderURL: "http://localhost:8888", + WebhookProviderWriteTimeout: 10 * time.Second, + WebhookServer: false, + ZoneIDFilter: []string{}, } // NewConfig returns new Config object @@ -453,40 +454,41 @@ func App(cfg *Config) *kingpin.Application { app.Flag("skipper-routegroup-groupversion", "The resource version for skipper routegroup").Default(defaultConfig.SkipperRouteGroupVersion).StringVar(&cfg.SkipperRouteGroupVersion) // Flags related to processing source - app.Flag("source", "The resource types that are queried for endpoints; specify multiple times for multiple sources (required, options: service, ingress, node, pod, fake, connector, gateway-httproute, gateway-grpcroute, gateway-tlsroute, gateway-tcproute, gateway-udproute, istio-gateway, istio-virtualservice, cloudfoundry, contour-httpproxy, gloo-proxy, crd, empty, skipper-routegroup, openshift-route, ambassador-host, kong-tcpingress, f5-virtualserver, f5-transportserver, traefik-proxy)").Required().PlaceHolder("source").EnumsVar(&cfg.Sources, "service", "ingress", "node", "pod", "gateway-httproute", "gateway-grpcroute", "gateway-tlsroute", "gateway-tcproute", "gateway-udproute", "istio-gateway", "istio-virtualservice", "cloudfoundry", "contour-httpproxy", "gloo-proxy", "fake", "connector", "crd", "empty", "skipper-routegroup", "openshift-route", "ambassador-host", "kong-tcpingress", "f5-virtualserver", "f5-transportserver", "traefik-proxy") - app.Flag("openshift-router-name", "if source is openshift-route then you can pass the ingress controller name. Based on this name external-dns will select the respective router from the route status and map that routerCanonicalHostname to the route host while creating a CNAME record.").StringVar(&cfg.OCPRouterName) - app.Flag("namespace", "Limit resources queried for endpoints to a specific namespace (default: all namespaces)").Default(defaultConfig.Namespace).StringVar(&cfg.Namespace) - app.Flag("annotation-filter", "Filter resources queried for endpoints by annotation, using label selector semantics").Default(defaultConfig.AnnotationFilter).StringVar(&cfg.AnnotationFilter) - app.Flag("label-filter", "Filter resources queried for endpoints by label selector; currently supported by source types crd, gateway-httproute, gateway-grpcroute, gateway-tlsroute, gateway-tcproute, gateway-udproute, ingress, node, openshift-route, service and ambassador-host").Default(defaultConfig.LabelFilter).StringVar(&cfg.LabelFilter) - app.Flag("ingress-class", "Require an Ingress to have this class name (defaults to any class; specify multiple times to allow more than one class)").StringsVar(&cfg.IngressClassNames) - app.Flag("fqdn-template", "A templated string that's used to generate DNS names from sources that don't define a hostname themselves, or to add a hostname suffix when paired with the fake source (optional). Accepts comma separated list for multiple global FQDN.").Default(defaultConfig.FQDNTemplate).StringVar(&cfg.FQDNTemplate) - app.Flag("combine-fqdn-annotation", "Combine FQDN template and Annotations instead of overwriting").BoolVar(&cfg.CombineFQDNAndAnnotation) - app.Flag("ignore-hostname-annotation", "Ignore hostname annotation when generating DNS names, valid only when --fqdn-template is set (default: false)").BoolVar(&cfg.IgnoreHostnameAnnotation) - app.Flag("ignore-non-host-network-pods", "Ignore pods not running on host network when using pod source (default: true)").BoolVar(&cfg.IgnoreNonHostNetworkPods) - app.Flag("ignore-ingress-tls-spec", "Ignore the spec.tls section in Ingress resources (default: false)").BoolVar(&cfg.IgnoreIngressTLSSpec) - app.Flag("gateway-name", "Limit Gateways of Route endpoints to a specific name (default: all names)").StringVar(&cfg.GatewayName) - app.Flag("gateway-namespace", "Limit Gateways of Route endpoints to a specific namespace (default: all namespaces)").StringVar(&cfg.GatewayNamespace) - app.Flag("gateway-label-filter", "Filter Gateways of Route endpoints via label selector (default: all gateways)").StringVar(&cfg.GatewayLabelFilter) - app.Flag("compatibility", "Process annotation semantics from legacy implementations (optional, options: mate, molecule, kops-dns-controller)").Default(defaultConfig.Compatibility).EnumVar(&cfg.Compatibility, "", "mate", "molecule", "kops-dns-controller") - app.Flag("ignore-ingress-rules-spec", "Ignore the spec.rules section in Ingress resources (default: false)").BoolVar(&cfg.IgnoreIngressRulesSpec) - app.Flag("pod-source-domain", "Domain to use for pods records (optional)").Default(defaultConfig.PodSourceDomain).StringVar(&cfg.PodSourceDomain) - app.Flag("publish-internal-services", "Allow external-dns to publish DNS records for ClusterIP services (optional)").BoolVar(&cfg.PublishInternal) - app.Flag("publish-host-ip", "Allow external-dns to publish host-ip for headless services (optional)").BoolVar(&cfg.PublishHostIP) app.Flag("always-publish-not-ready-addresses", "Always publish also not ready addresses for headless services (optional)").BoolVar(&cfg.AlwaysPublishNotReadyAddresses) + app.Flag("annotation-filter", "Filter resources queried for endpoints by annotation, using label selector semantics").Default(defaultConfig.AnnotationFilter).StringVar(&cfg.AnnotationFilter) + app.Flag("combine-fqdn-annotation", "Combine FQDN template and Annotations instead of overwriting").BoolVar(&cfg.CombineFQDNAndAnnotation) + app.Flag("compatibility", "Process annotation semantics from legacy implementations (optional, options: mate, molecule, kops-dns-controller)").Default(defaultConfig.Compatibility).EnumVar(&cfg.Compatibility, "", "mate", "molecule", "kops-dns-controller") app.Flag("connector-source-server", "The server to connect for connector source, valid only when using connector source").Default(defaultConfig.ConnectorSourceServer).StringVar(&cfg.ConnectorSourceServer) app.Flag("crd-source-apiversion", "API version of the CRD for crd source, e.g. `externaldns.k8s.io/v1alpha1`, valid only when using crd source").Default(defaultConfig.CRDSourceAPIVersion).StringVar(&cfg.CRDSourceAPIVersion) app.Flag("crd-source-kind", "Kind of the CRD for the crd source in API group and version specified by crd-source-apiversion").Default(defaultConfig.CRDSourceKind).StringVar(&cfg.CRDSourceKind) - app.Flag("service-type-filter", "The service types to take care about (default: all, expected: ClusterIP, NodePort, LoadBalancer or ExternalName)").StringsVar(&cfg.ServiceTypeFilter) - app.Flag("managed-record-types", "Record types to manage; specify multiple times to include many; (default: A, AAAA, CNAME) (supported records: A, AAAA, CNAME, NS, SRV, TXT)").Default("A", "AAAA", "CNAME").StringsVar(&cfg.ManagedDNSRecordTypes) - app.Flag("exclude-record-types", "Record types to exclude from management; specify multiple times to exclude many; (optional)").Default().StringsVar(&cfg.ExcludeDNSRecordTypes) app.Flag("default-targets", "Set globally default host/IP that will apply as a target instead of source addresses. Specify multiple times for multiple targets (optional)").StringsVar(&cfg.DefaultTargets) - app.Flag("target-net-filter", "Limit possible targets by a net filter; specify multiple times for multiple possible nets (optional)").StringsVar(&cfg.TargetNetFilter) + app.Flag("exclude-record-types", "Record types to exclude from management; specify multiple times to exclude many; (optional)").Default().StringsVar(&cfg.ExcludeDNSRecordTypes) app.Flag("exclude-target-net", "Exclude target nets (optional)").StringsVar(&cfg.ExcludeTargetNets) - app.Flag("traefik-disable-legacy", "Disable listeners on Resources under the traefik.containo.us API Group").Default(strconv.FormatBool(defaultConfig.TraefikDisableLegacy)).BoolVar(&cfg.TraefikDisableLegacy) - app.Flag("traefik-disable-new", "Disable listeners on Resources under the traefik.io API Group").Default(strconv.FormatBool(defaultConfig.TraefikDisableNew)).BoolVar(&cfg.TraefikDisableNew) - app.Flag("nat64-networks", "Adding an A record for each AAAA record in NAT64-enabled networks; specify multiple times for multiple possible nets (optional)").StringsVar(&cfg.NAT64Networks) app.Flag("exclude-unschedulable", "Exclude nodes that are considered unschedulable (default: true)").Default(strconv.FormatBool(defaultConfig.ExcludeUnschedulable)).BoolVar(&cfg.ExcludeUnschedulable) app.Flag("expose-internal-ipv6", "When using the node source, expose internal IPv6 addresses (optional). Default is true.").BoolVar(&cfg.ExposeInternalIPV6) + app.Flag("fqdn-template", "A templated string that's used to generate DNS names from sources that don't define a hostname themselves, or to add a hostname suffix when paired with the fake source (optional). Accepts comma separated list for multiple global FQDN.").Default(defaultConfig.FQDNTemplate).StringVar(&cfg.FQDNTemplate) + app.Flag("gateway-label-filter", "Filter Gateways of Route endpoints via label selector (default: all gateways)").StringVar(&cfg.GatewayLabelFilter) + app.Flag("gateway-name", "Limit Gateways of Route endpoints to a specific name (default: all names)").StringVar(&cfg.GatewayName) + app.Flag("gateway-namespace", "Limit Gateways of Route endpoints to a specific namespace (default: all namespaces)").StringVar(&cfg.GatewayNamespace) + app.Flag("ignore-hostname-annotation", "Ignore hostname annotation when generating DNS names, valid only when --fqdn-template is set (default: false)").BoolVar(&cfg.IgnoreHostnameAnnotation) + app.Flag("ignore-ingress-rules-spec", "Ignore the spec.rules section in Ingress resources (default: false)").BoolVar(&cfg.IgnoreIngressRulesSpec) + app.Flag("ignore-ingress-tls-spec", "Ignore the spec.tls section in Ingress resources (default: false)").BoolVar(&cfg.IgnoreIngressTLSSpec) + app.Flag("ignore-non-host-network-pods", "Ignore pods not running on host network when using pod source (default: true)").BoolVar(&cfg.IgnoreNonHostNetworkPods) + app.Flag("ingress-class", "Require an Ingress to have this class name (defaults to any class; specify multiple times to allow more than one class)").StringsVar(&cfg.IngressClassNames) + app.Flag("label-filter", "Filter resources queried for endpoints by label selector; currently supported by source types crd, gateway-httproute, gateway-grpcroute, gateway-tlsroute, gateway-tcproute, gateway-udproute, ingress, node, openshift-route, service and ambassador-host").Default(defaultConfig.LabelFilter).StringVar(&cfg.LabelFilter) + managedRecordTypesHelp := fmt.Sprintf("Record types to manage; specify multiple times to include many; (default: %s) (supported records: A, AAAA, CNAME, NS, SRV, TXT)", strings.Join(defaultConfig.ManagedDNSRecordTypes, ",")) + app.Flag("managed-record-types", managedRecordTypesHelp).Default(defaultConfig.ManagedDNSRecordTypes...).StringsVar(&cfg.ManagedDNSRecordTypes) + app.Flag("namespace", "Limit resources queried for endpoints to a specific namespace (default: all namespaces)").Default(defaultConfig.Namespace).StringVar(&cfg.Namespace) + app.Flag("nat64-networks", "Adding an A record for each AAAA record in NAT64-enabled networks; specify multiple times for multiple possible nets (optional)").StringsVar(&cfg.NAT64Networks) + app.Flag("openshift-router-name", "if source is openshift-route then you can pass the ingress controller name. Based on this name external-dns will select the respective router from the route status and map that routerCanonicalHostname to the route host while creating a CNAME record.").StringVar(&cfg.OCPRouterName) + app.Flag("pod-source-domain", "Domain to use for pods records (optional)").Default(defaultConfig.PodSourceDomain).StringVar(&cfg.PodSourceDomain) + app.Flag("publish-host-ip", "Allow external-dns to publish host-ip for headless services (optional)").BoolVar(&cfg.PublishHostIP) + app.Flag("publish-internal-services", "Allow external-dns to publish DNS records for ClusterIP services (optional)").BoolVar(&cfg.PublishInternal) + app.Flag("service-type-filter", "The service types to take care about (default: all, expected: ClusterIP, NodePort, LoadBalancer or ExternalName)").StringsVar(&cfg.ServiceTypeFilter) + app.Flag("source", "The resource types that are queried for endpoints; specify multiple times for multiple sources (required, options: service, ingress, node, pod, fake, connector, gateway-httproute, gateway-grpcroute, gateway-tlsroute, gateway-tcproute, gateway-udproute, istio-gateway, istio-virtualservice, cloudfoundry, contour-httpproxy, gloo-proxy, crd, empty, skipper-routegroup, openshift-route, ambassador-host, kong-tcpingress, f5-virtualserver, f5-transportserver, traefik-proxy)").Required().PlaceHolder("source").EnumsVar(&cfg.Sources, "service", "ingress", "node", "pod", "gateway-httproute", "gateway-grpcroute", "gateway-tlsroute", "gateway-tcproute", "gateway-udproute", "istio-gateway", "istio-virtualservice", "cloudfoundry", "contour-httpproxy", "gloo-proxy", "fake", "connector", "crd", "empty", "skipper-routegroup", "openshift-route", "ambassador-host", "kong-tcpingress", "f5-virtualserver", "f5-transportserver", "traefik-proxy") + app.Flag("target-net-filter", "Limit possible targets by a net filter; specify multiple times for multiple possible nets (optional)").StringsVar(&cfg.TargetNetFilter) + app.Flag("traefik-disable-legacy", "Disable listeners on Resources under the traefik.containo.us API Group").Default(strconv.FormatBool(defaultConfig.TraefikDisableLegacy)).BoolVar(&cfg.TraefikDisableLegacy) + app.Flag("traefik-disable-new", "Disable listeners on Resources under the traefik.io API Group").Default(strconv.FormatBool(defaultConfig.TraefikDisableNew)).BoolVar(&cfg.TraefikDisableNew) // Flags related to providers providers := []string{"akamai", "alibabacloud", "aws", "aws-sd", "azure", "azure-dns", "azure-private-dns", "civo", "cloudflare", "coredns", "digitalocean", "dnsimple", "exoscale", "gandi", "godaddy", "google", "ibmcloud", "inmemory", "linode", "ns1", "oci", "ovh", "pdns", "pihole", "plural", "rfc2136", "scaleway", "skydns", "tencentcloud", "transip", "ultradns", "webhook"} diff --git a/plan/plan.go b/plan/plan.go index 6124b7640..c77f2f2a1 100644 --- a/plan/plan.go +++ b/plan/plan.go @@ -262,9 +262,11 @@ func (p *Plan) Calculate() *Plan { } plan := &Plan{ - Current: p.Current, - Desired: p.Desired, - Changes: changes, + Current: p.Current, + Desired: p.Desired, + Changes: changes, + // The default for ExternalDNS is to always only consider A/AAAA and CNAMEs. + // Everything else is an add on or something to be considered. ManagedRecords: []string{endpoint.RecordTypeA, endpoint.RecordTypeAAAA, endpoint.RecordTypeCNAME}, } diff --git a/plan/plan_test.go b/plan/plan_test.go index 5aecc8632..af1f5c2c0 100644 --- a/plan/plan_test.go +++ b/plan/plan_test.go @@ -367,9 +367,22 @@ func (suite *PlanTestSuite) TestSyncSecondRoundWithProviderSpecificNoChange() { } changes := p.Calculate().Changes - if changes.HasChanges() { - suite.T().Fatal("test should not have changes") + suite.Assert().False(changes.HasChanges()) +} + +func (suite *PlanTestSuite) TestHasChanges() { + current := []*endpoint.Endpoint{suite.bar127AWithProviderSpecificTrue} + desired := []*endpoint.Endpoint{suite.bar127AWithProviderSpecificFalse} + + p := &Plan{ + Policies: []Policy{&SyncPolicy{}}, + Current: current, + Desired: desired, + ManagedRecords: []string{endpoint.RecordTypeA, endpoint.RecordTypeCNAME}, } + + changes := p.Calculate().Changes + suite.Assert().True(changes.HasChanges()) } func (suite *PlanTestSuite) TestSyncSecondRoundWithProviderSpecificRemoval() { From a6243cf6bb5d089735a961a46160e48caebe840e Mon Sep 17 00:00:00 2001 From: Ivan Ka <5395690+ivankatliarchuk@users.noreply.github.com> Date: Sun, 27 Apr 2025 22:59:25 +0100 Subject: [PATCH 16/42] chore(providers): rename custom TTL constants to defaultTTL (#5312) * chore(provider): inline providers Signed-off-by: ivan katliarchuk * chore(provider): inline providers Signed-off-by: ivan katliarchuk * chore(provider): inline providers Signed-off-by: ivan katliarchuk * chore(provider): inline providers Signed-off-by: ivan katliarchuk * chore(provider): inline providers Signed-off-by: ivan katliarchuk --------- Signed-off-by: ivan katliarchuk --- docs/providers.md | 35 +++ provider/akamai/akamai.go | 8 +- provider/alibabacloud/alibaba_cloud.go | 6 +- provider/alibabacloud/alibaba_cloud_test.go | 2 +- provider/aws/aws.go | 10 +- provider/aws/aws_test.go | 240 ++++++++++---------- provider/awssd/aws_sd.go | 6 +- provider/azure/azure.go | 4 +- provider/azure/azure_private_dns.go | 2 +- provider/cloudflare/cloudflare.go | 7 +- provider/cloudflare/cloudflare_test.go | 106 ++++----- provider/digitalocean/digital_ocean.go | 6 +- provider/digitalocean/digital_ocean_test.go | 54 ++--- provider/dnsimple/dnsimple.go | 4 +- provider/gandi/gandi.go | 4 +- provider/godaddy/client.go | 13 +- provider/godaddy/godaddy.go | 12 +- provider/godaddy/godaddy_test.go | 32 +-- provider/google/google.go | 4 +- provider/google/google_test.go | 42 ++-- provider/ibmcloud/ibmcloud.go | 29 +-- provider/ns1/ns1.go | 6 +- provider/oci/oci.go | 4 +- provider/oci/oci_test.go | 106 ++++----- provider/ovh/ovh.go | 12 +- provider/ovh/ovh_test.go | 18 +- provider/plural/plural.go | 1 - provider/rfc2136/rfc2136.go | 20 +- provider/scaleway/scaleway.go | 6 +- provider/transip/transip.go | 10 +- provider/transip/transip_test.go | 10 +- 31 files changed, 427 insertions(+), 392 deletions(-) create mode 100644 docs/providers.md diff --git a/docs/providers.md b/docs/providers.md new file mode 100644 index 000000000..4a9511aa2 --- /dev/null +++ b/docs/providers.md @@ -0,0 +1,35 @@ +# Providers + +Provider supported configurations + +| Provider Name | Zone Cache | Dry Run | Default TTL (seconds) | +|:--------------|:-----------|:--------|:----------------------| +| Akamai | n/a | yes | 600 | +| AlibabaCloud | n/a | yes | 600 | +| AWS | yes | yes | 300 | +| AWSSD | n/a | yes | 300 | +| Azure | yes | yes | 300 | +| Civo | n/a | yes | n/a | +| Cloudflare | n/a | yes | 1 | +| CoreDNS | n/a | yes | n/a | +| DigitalOcean | n/a | yes | 300 | +| DNSSimple | n/a | yes | 3600 | +| Exoscale | n/a | yes | n/a | +| Gandi | n/a | no | 600 | +| GoDaddy | n/a | yes | 600 | +| Google GCP | n/a | yes | 300 | +| IBMCloud | n/a | yes | 1 | +| InMemory | n/a | n/a | n/a | +| Linode | n/a | n/a | n/a | +| NS1 | n/a | yes | 10 | +| OCI | yes | yes | 300 | +| OVH | n/a | yes | 0 | +| PDNS | n/a | yes | 300 | +| PiHole | n/a | yes | n/a | +| Plural | n/a | n/a | n/a | +| RFC2136 | n/a | yes | n/a | +| Scaleway | n/a | n/a | 300 | +| TencentCloud | n/a | n/a | n/a | +| Transip | n/a | yes | 60 | +| Ultradns | n/a | yes | n/a | +| Webhook | n/a | n/a | n/a | diff --git a/provider/akamai/akamai.go b/provider/akamai/akamai.go index 36ac0a194..e553d3ffe 100644 --- a/provider/akamai/akamai.go +++ b/provider/akamai/akamai.go @@ -34,9 +34,9 @@ import ( const ( // Default Record TTL - edgeDNSRecordTTL = 600 - maxUint = ^uint(0) - maxInt = int(maxUint >> 1) + defaultTTL = 600 + maxUint = ^uint(0) + maxInt = int(maxUint >> 1) ) // edgeDNSClient is a proxy interface of the Akamai edgegrid configdns-v2 package that can be stubbed for testing. @@ -352,7 +352,7 @@ func trimTxtRdata(rdata []string, rtype string) []string { func ttlAsInt(src endpoint.TTL) int { var temp interface{} = int64(src) temp64 := temp.(int64) - var ttl = edgeDNSRecordTTL + var ttl = defaultTTL if temp64 > 0 && temp64 <= int64(maxInt) { ttl = int(temp64) } diff --git a/provider/alibabacloud/alibaba_cloud.go b/provider/alibabacloud/alibaba_cloud.go index 32140c772..16318385e 100644 --- a/provider/alibabacloud/alibaba_cloud.go +++ b/provider/alibabacloud/alibaba_cloud.go @@ -38,7 +38,7 @@ import ( ) const ( - defaultAlibabaCloudRecordTTL = 600 + defaultTTL = 600 defaultAlibabaCloudPrivateZoneRecordTTL = 60 defaultAlibabaCloudPageSize = 50 nullHostAlibabaCloud = "@" @@ -606,12 +606,12 @@ func (p *AlibabaCloudProvider) deleteRecords(recordMap map[string][]alidns.Recor func (p *AlibabaCloudProvider) equals(record alidns.Record, endpoint *endpoint.Endpoint) bool { ttl1 := record.TTL - if ttl1 == defaultAlibabaCloudRecordTTL { + if ttl1 == defaultTTL { ttl1 = 0 } ttl2 := int64(endpoint.RecordTTL) - if ttl2 == defaultAlibabaCloudRecordTTL { + if ttl2 == defaultTTL { ttl2 = 0 } diff --git a/provider/alibabacloud/alibaba_cloud_test.go b/provider/alibabacloud/alibaba_cloud_test.go index 5bdb77a42..33774637b 100644 --- a/provider/alibabacloud/alibaba_cloud_test.go +++ b/provider/alibabacloud/alibaba_cloud_test.go @@ -272,7 +272,7 @@ func TestAlibabaCloudProvider_ApplyChanges(t *testing.T) { defaultTtlPlan := &endpoint.Endpoint{ DNSName: "ttl.container-service.top", RecordType: "A", - RecordTTL: defaultAlibabaCloudRecordTTL, + RecordTTL: defaultTTL, Targets: endpoint.NewTargets("4.3.2.1"), } changes := plan.Changes{ diff --git a/provider/aws/aws.go b/provider/aws/aws.go index 97f35b509..89d90a47b 100644 --- a/provider/aws/aws.go +++ b/provider/aws/aws.go @@ -39,7 +39,7 @@ import ( const ( defaultAWSProfile = "default" - recordTTL = 300 + defaultTTL = 300 // From the experiments, it seems that the default MaxItems applied is 100, // and that, on the server side, there is a hard limit of 300 elements per page. // After a discussion with AWS representatives, clients should accept @@ -510,7 +510,7 @@ func (p *AWSProvider) records(ctx context.Context, zones map[string]*profiledZon if r.AliasTarget != nil { // Alias records don't have TTLs so provide the default to match the TXT generation if ttl == 0 { - ttl = recordTTL + ttl = defaultTTL } ep := endpoint. NewEndpointWithTTL(name, string(r.Type), ttl, *r.AliasTarget.DNSName). @@ -804,8 +804,8 @@ func (p *AWSProvider) AdjustEndpoints(endpoints []*endpoint.Endpoint) ([]*endpoi if alias { if ep.RecordTTL.IsConfigured() { - log.Debugf("Modifying endpoint: %v, setting ttl=%v", ep, recordTTL) - ep.RecordTTL = recordTTL + log.Debugf("Modifying endpoint: %v, setting ttl=%v", ep, defaultTTL) + ep.RecordTTL = defaultTTL } if prop, ok := ep.GetProviderSpecificProperty(providerSpecificEvaluateTargetHealth); ok { if prop != "true" && prop != "false" { @@ -866,7 +866,7 @@ func (p *AWSProvider) newChange(action route53types.ChangeAction, ep *endpoint.E change.sizeValues += 1 } else { if !ep.RecordTTL.IsConfigured() { - change.ResourceRecordSet.TTL = aws.Int64(recordTTL) + change.ResourceRecordSet.TTL = aws.Int64(defaultTTL) } else { change.ResourceRecordSet.TTL = aws.Int64(int64(ep.RecordTTL)) } diff --git a/provider/aws/aws_test.go b/provider/aws/aws_test.go index 7305f0648..c1719d174 100644 --- a/provider/aws/aws_test.go +++ b/provider/aws/aws_test.go @@ -400,37 +400,37 @@ func TestAWSRecords(t *testing.T) { { Name: aws.String("list-test.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}}, }, { Name: aws.String("list-test.zone-2.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.8.8")}}, }, { Name: aws.String(wildcardEscape("*.wildcard-test.zone-2.ext-dns-test-2.teapot.zalan.do.")), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.8.8")}}, }, { Name: aws.String(specialCharactersEscape("escape-%!s()-codes.zone-2.ext-dns-test-2.teapot.zalan.do.")), Type: route53types.RRTypeCname, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("example")}}, }, { Name: aws.String(specialCharactersEscape("escape-%!s()-codes-a.zone-2.ext-dns-test-2.teapot.zalan.do.")), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}}, }, { Name: aws.String(specialCharactersEscape("escape-%!s()-codes-alias.zone-2.ext-dns-test-2.teapot.zalan.do.")), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), AliasTarget: &route53types.AliasTarget{ DNSName: aws.String("escape-codes.eu-central-1.elb.amazonaws.com."), EvaluateTargetHealth: false, @@ -440,7 +440,7 @@ func TestAWSRecords(t *testing.T) { { Name: aws.String(specialCharactersEscape("escape-%!s()-codes-alias.zone-2.ext-dns-test-2.teapot.zalan.do.")), Type: route53types.RRTypeAaaa, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), AliasTarget: &route53types.AliasTarget{ DNSName: aws.String("escape-codes.eu-central-1.elb.amazonaws.com."), EvaluateTargetHealth: false, @@ -504,19 +504,19 @@ func TestAWSRecords(t *testing.T) { { Name: aws.String("list-test-multiple.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.8.8")}, {Value: aws.String("8.8.4.4")}}, }, { Name: aws.String("prefix-*.wildcard.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeTxt, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("random")}}, }, { Name: aws.String("weight-test.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}}, SetIdentifier: aws.String("test-set-1"), Weight: aws.Int64(10), @@ -524,7 +524,7 @@ func TestAWSRecords(t *testing.T) { { Name: aws.String("weight-test.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("4.3.2.1")}}, SetIdentifier: aws.String("test-set-2"), Weight: aws.Int64(20), @@ -532,7 +532,7 @@ func TestAWSRecords(t *testing.T) { { Name: aws.String("latency-test.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}}, SetIdentifier: aws.String("test-set"), Region: route53types.ResourceRecordSetRegionUsEast1, @@ -540,7 +540,7 @@ func TestAWSRecords(t *testing.T) { { Name: aws.String("failover-test.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}}, SetIdentifier: aws.String("test-set"), Failover: route53types.ResourceRecordSetFailoverPrimary, @@ -548,7 +548,7 @@ func TestAWSRecords(t *testing.T) { { Name: aws.String("multi-value-answer-test.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}}, SetIdentifier: aws.String("test-set"), MultiValueAnswer: aws.Bool(true), @@ -556,7 +556,7 @@ func TestAWSRecords(t *testing.T) { { Name: aws.String("geolocation-test.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}}, SetIdentifier: aws.String("test-set-1"), GeoLocation: &route53types.GeoLocation{ @@ -566,7 +566,7 @@ func TestAWSRecords(t *testing.T) { { Name: aws.String("geolocation-test.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("4.3.2.1")}}, SetIdentifier: aws.String("test-set-2"), GeoLocation: &route53types.GeoLocation{ @@ -576,7 +576,7 @@ func TestAWSRecords(t *testing.T) { { Name: aws.String("geolocation-subdivision-test.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}}, SetIdentifier: aws.String("test-set-1"), GeoLocation: &route53types.GeoLocation{ @@ -586,7 +586,7 @@ func TestAWSRecords(t *testing.T) { { Name: aws.String("healthcheck-test.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeCname, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("foo.example.com")}}, SetIdentifier: aws.String("test-set-1"), HealthCheckId: aws.String("foo-bar-healthcheck-id"), @@ -595,7 +595,7 @@ func TestAWSRecords(t *testing.T) { { Name: aws.String("healthcheck-test.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("4.3.2.1")}}, SetIdentifier: aws.String("test-set-2"), HealthCheckId: aws.String("abc-def-healthcheck-id"), @@ -604,7 +604,7 @@ func TestAWSRecords(t *testing.T) { { Name: aws.String("mail.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeMx, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("10 mailhost1.example.com")}, {Value: aws.String("20 mailhost2.example.com")}}, }, }) @@ -613,32 +613,32 @@ func TestAWSRecords(t *testing.T) { require.NoError(t, err) validateEndpoints(t, provider, records, []*endpoint.Endpoint{ - endpoint.NewEndpointWithTTL("list-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4"), - endpoint.NewEndpointWithTTL("list-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8"), - endpoint.NewEndpointWithTTL("*.wildcard-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8"), - endpoint.NewEndpointWithTTL("escape-%!s()-codes.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "example").WithProviderSpecific(providerSpecificAlias, "false"), - endpoint.NewEndpointWithTTL("escape-%!s()-codes-a.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4"), - endpoint.NewEndpointWithTTL("escape-%!s()-codes-alias.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "escape-codes.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"), - endpoint.NewEndpointWithTTL("escape-%!s()-codes-alias.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, endpoint.TTL(recordTTL), "escape-codes.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"), - endpoint.NewEndpointWithTTL("list-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"), - endpoint.NewEndpointWithTTL("list-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, endpoint.TTL(recordTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"), - endpoint.NewEndpointWithTTL("*.wildcard-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"), - endpoint.NewEndpointWithTTL("*.wildcard-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, endpoint.TTL(recordTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"), - endpoint.NewEndpointWithTTL("list-test-alias-evaluate.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true").WithProviderSpecific(providerSpecificAlias, "true"), - endpoint.NewEndpointWithTTL("list-test-alias-evaluate.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, endpoint.TTL(recordTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true").WithProviderSpecific(providerSpecificAlias, "true"), - endpoint.NewEndpointWithTTL("list-test-multiple.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8", "8.8.4.4"), - endpoint.NewEndpointWithTTL("prefix-*.wildcard.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeTXT, endpoint.TTL(recordTTL), "random"), - endpoint.NewEndpointWithTTL("weight-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4").WithSetIdentifier("test-set-1").WithProviderSpecific(providerSpecificWeight, "10"), - endpoint.NewEndpointWithTTL("weight-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "4.3.2.1").WithSetIdentifier("test-set-2").WithProviderSpecific(providerSpecificWeight, "20"), - endpoint.NewEndpointWithTTL("latency-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4").WithSetIdentifier("test-set").WithProviderSpecific(providerSpecificRegion, "us-east-1"), - endpoint.NewEndpointWithTTL("failover-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4").WithSetIdentifier("test-set").WithProviderSpecific(providerSpecificFailover, "PRIMARY"), - endpoint.NewEndpointWithTTL("multi-value-answer-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4").WithSetIdentifier("test-set").WithProviderSpecific(providerSpecificMultiValueAnswer, ""), - endpoint.NewEndpointWithTTL("geolocation-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4").WithSetIdentifier("test-set-1").WithProviderSpecific(providerSpecificGeolocationContinentCode, "EU"), - endpoint.NewEndpointWithTTL("geolocation-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "4.3.2.1").WithSetIdentifier("test-set-2").WithProviderSpecific(providerSpecificGeolocationCountryCode, "DE"), - endpoint.NewEndpointWithTTL("geolocation-subdivision-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4").WithSetIdentifier("test-set-1").WithProviderSpecific(providerSpecificGeolocationSubdivisionCode, "NY"), - endpoint.NewEndpointWithTTL("healthcheck-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "foo.example.com").WithSetIdentifier("test-set-1").WithProviderSpecific(providerSpecificWeight, "10").WithProviderSpecific(providerSpecificHealthCheckID, "foo-bar-healthcheck-id").WithProviderSpecific(providerSpecificAlias, "false"), - endpoint.NewEndpointWithTTL("healthcheck-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "4.3.2.1").WithSetIdentifier("test-set-2").WithProviderSpecific(providerSpecificWeight, "20").WithProviderSpecific(providerSpecificHealthCheckID, "abc-def-healthcheck-id"), - endpoint.NewEndpointWithTTL("mail.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeMX, endpoint.TTL(recordTTL), "10 mailhost1.example.com", "20 mailhost2.example.com"), + endpoint.NewEndpointWithTTL("list-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "1.2.3.4"), + endpoint.NewEndpointWithTTL("list-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "8.8.8.8"), + endpoint.NewEndpointWithTTL("*.wildcard-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "8.8.8.8"), + endpoint.NewEndpointWithTTL("escape-%!s()-codes.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(defaultTTL), "example").WithProviderSpecific(providerSpecificAlias, "false"), + endpoint.NewEndpointWithTTL("escape-%!s()-codes-a.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "1.2.3.4"), + endpoint.NewEndpointWithTTL("escape-%!s()-codes-alias.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "escape-codes.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"), + endpoint.NewEndpointWithTTL("escape-%!s()-codes-alias.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, endpoint.TTL(defaultTTL), "escape-codes.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"), + endpoint.NewEndpointWithTTL("list-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"), + endpoint.NewEndpointWithTTL("list-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, endpoint.TTL(defaultTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"), + endpoint.NewEndpointWithTTL("*.wildcard-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"), + endpoint.NewEndpointWithTTL("*.wildcard-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, endpoint.TTL(defaultTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"), + endpoint.NewEndpointWithTTL("list-test-alias-evaluate.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true").WithProviderSpecific(providerSpecificAlias, "true"), + endpoint.NewEndpointWithTTL("list-test-alias-evaluate.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, endpoint.TTL(defaultTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true").WithProviderSpecific(providerSpecificAlias, "true"), + endpoint.NewEndpointWithTTL("list-test-multiple.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "8.8.8.8", "8.8.4.4"), + endpoint.NewEndpointWithTTL("prefix-*.wildcard.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeTXT, endpoint.TTL(defaultTTL), "random"), + endpoint.NewEndpointWithTTL("weight-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "1.2.3.4").WithSetIdentifier("test-set-1").WithProviderSpecific(providerSpecificWeight, "10"), + endpoint.NewEndpointWithTTL("weight-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "4.3.2.1").WithSetIdentifier("test-set-2").WithProviderSpecific(providerSpecificWeight, "20"), + endpoint.NewEndpointWithTTL("latency-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "1.2.3.4").WithSetIdentifier("test-set").WithProviderSpecific(providerSpecificRegion, "us-east-1"), + endpoint.NewEndpointWithTTL("failover-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "1.2.3.4").WithSetIdentifier("test-set").WithProviderSpecific(providerSpecificFailover, "PRIMARY"), + endpoint.NewEndpointWithTTL("multi-value-answer-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "1.2.3.4").WithSetIdentifier("test-set").WithProviderSpecific(providerSpecificMultiValueAnswer, ""), + endpoint.NewEndpointWithTTL("geolocation-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "1.2.3.4").WithSetIdentifier("test-set-1").WithProviderSpecific(providerSpecificGeolocationContinentCode, "EU"), + endpoint.NewEndpointWithTTL("geolocation-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "4.3.2.1").WithSetIdentifier("test-set-2").WithProviderSpecific(providerSpecificGeolocationCountryCode, "DE"), + endpoint.NewEndpointWithTTL("geolocation-subdivision-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "1.2.3.4").WithSetIdentifier("test-set-1").WithProviderSpecific(providerSpecificGeolocationSubdivisionCode, "NY"), + endpoint.NewEndpointWithTTL("healthcheck-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(defaultTTL), "foo.example.com").WithSetIdentifier("test-set-1").WithProviderSpecific(providerSpecificWeight, "10").WithProviderSpecific(providerSpecificHealthCheckID, "foo-bar-healthcheck-id").WithProviderSpecific(providerSpecificAlias, "false"), + endpoint.NewEndpointWithTTL("healthcheck-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "4.3.2.1").WithSetIdentifier("test-set-2").WithProviderSpecific(providerSpecificWeight, "20").WithProviderSpecific(providerSpecificHealthCheckID, "abc-def-healthcheck-id"), + endpoint.NewEndpointWithTTL("mail.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeMX, endpoint.TTL(defaultTTL), "10 mailhost1.example.com", "20 mailhost2.example.com"), }) } @@ -647,7 +647,7 @@ func TestAWSRecordsSoftError(t *testing.T) { { Name: aws.String("list-test.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}}, }, }) @@ -710,55 +710,55 @@ func TestAWSApplyChanges(t *testing.T) { { Name: aws.String("update-test.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.8.8")}}, }, { Name: aws.String("update-test-aaaa.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeAaaa, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("2606:4700:4700::1111")}}, }, { Name: aws.String("delete-test.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.8.8")}}, }, { Name: aws.String("delete-test-aaaa.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeAaaa, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("2606:4700:4700::1111")}}, }, { Name: aws.String("update-test.zone-2.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.4.4")}}, }, { Name: aws.String("update-test-aaaa.zone-2.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeAaaa, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("2606:4700:4700::1001")}}, }, { Name: aws.String("delete-test.zone-2.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.4.4")}}, }, { Name: aws.String("delete-test-aaaa.zone-2.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeAaaa, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("2606:4700:4700::1001")}}, }, { Name: aws.String("update-test-a-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.1.1.1")}}, }, { @@ -782,7 +782,7 @@ func TestAWSApplyChanges(t *testing.T) { { Name: aws.String("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeCname, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("bar.elb.amazonaws.com")}}, }, { @@ -806,7 +806,7 @@ func TestAWSApplyChanges(t *testing.T) { { Name: aws.String("delete-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeCname, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("qux.elb.amazonaws.com")}}, }, { @@ -830,25 +830,25 @@ func TestAWSApplyChanges(t *testing.T) { { Name: aws.String("update-test-multiple.zone-2.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.8.8")}, {Value: aws.String("8.8.4.4")}}, }, { Name: aws.String("delete-test-multiple.zone-2.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}, {Value: aws.String("4.3.2.1")}}, }, { Name: aws.String("delete-test-multiple-aaaa.zone-2.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeAaaa, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("2606:4700:4700::1111")}, {Value: aws.String("2606:4700:4700::1001")}}, }, { Name: aws.String("weighted-to-simple.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}}, SetIdentifier: aws.String("weighted-to-simple"), Weight: aws.Int64(10), @@ -856,13 +856,13 @@ func TestAWSApplyChanges(t *testing.T) { { Name: aws.String("simple-to-weighted.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}}, }, { Name: aws.String("policy-change.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}}, SetIdentifier: aws.String("policy-change"), Weight: aws.Int64(10), @@ -870,7 +870,7 @@ func TestAWSApplyChanges(t *testing.T) { { Name: aws.String("set-identifier-change.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}}, SetIdentifier: aws.String("before"), Weight: aws.Int64(10), @@ -878,7 +878,7 @@ func TestAWSApplyChanges(t *testing.T) { { Name: aws.String("set-identifier-no-change.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}}, SetIdentifier: aws.String("no-change"), Weight: aws.Int64(10), @@ -886,19 +886,19 @@ func TestAWSApplyChanges(t *testing.T) { { Name: aws.String("update-test-mx.zone-2.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeMx, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("10 mailhost2.bar.elb.amazonaws.com")}}, }, { Name: aws.String("delete-test-mx.zone-2.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeMx, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("30 mailhost1.foo.elb.amazonaws.com")}}, }, { Name: aws.String(specialCharactersEscape("escape-%!s()-codes.zone-2.ext-dns-test-2.teapot.zalan.do.")), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}}, SetIdentifier: aws.String("no-change"), Weight: aws.Int64(10), @@ -993,25 +993,25 @@ func TestAWSApplyChanges(t *testing.T) { { Name: aws.String("create-test.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.8.8")}}, }, { Name: aws.String("create-test-aaaa.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeAaaa, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("2606:4700:4700::1111")}}, }, { Name: aws.String("update-test.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}}, }, { Name: aws.String("update-test-aaaa.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeAaaa, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("2606:4700:4700::1001")}}, }, { @@ -1035,25 +1035,25 @@ func TestAWSApplyChanges(t *testing.T) { { Name: aws.String("update-test-alias-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeCname, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("my-internal-host.example.com")}}, }, { Name: aws.String("create-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeCname, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("foo.elb.amazonaws.com")}}, }, { Name: aws.String("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeCname, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("baz.elb.amazonaws.com")}}, }, { Name: aws.String("create-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeCname, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("foo.elb.amazonaws.com")}}, }, { @@ -1077,13 +1077,13 @@ func TestAWSApplyChanges(t *testing.T) { { Name: aws.String("weighted-to-simple.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}}, }, { Name: aws.String("simple-to-weighted.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}}, SetIdentifier: aws.String("simple-to-weighted"), Weight: aws.Int64(10), @@ -1091,7 +1091,7 @@ func TestAWSApplyChanges(t *testing.T) { { Name: aws.String("policy-change.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}}, SetIdentifier: aws.String("policy-change"), Region: route53types.ResourceRecordSetRegionUsEast1, @@ -1099,7 +1099,7 @@ func TestAWSApplyChanges(t *testing.T) { { Name: aws.String("set-identifier-change.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}}, SetIdentifier: aws.String("after"), Weight: aws.Int64(10), @@ -1107,7 +1107,7 @@ func TestAWSApplyChanges(t *testing.T) { { Name: aws.String("set-identifier-no-change.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}}, SetIdentifier: aws.String("no-change"), Weight: aws.Int64(20), @@ -1115,7 +1115,7 @@ func TestAWSApplyChanges(t *testing.T) { { Name: aws.String("create-test-mx.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeMx, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("10 mailhost1.foo.elb.amazonaws.com")}}, }, }) @@ -1123,7 +1123,7 @@ func TestAWSApplyChanges(t *testing.T) { { Name: aws.String("escape-\\045\\041s\\050\\074nil\\076\\051-codes.zone-2.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}}, SetIdentifier: aws.String("no-change"), Weight: aws.Int64(10), @@ -1131,55 +1131,55 @@ func TestAWSApplyChanges(t *testing.T) { { Name: aws.String("create-test.zone-2.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.4.4")}}, }, { Name: aws.String("create-test-aaaa.zone-2.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeAaaa, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("2606:4700:4700::1001")}}, }, { Name: aws.String("update-test.zone-2.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("4.3.2.1")}}, }, { Name: aws.String("update-test-aaaa.zone-2.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeAaaa, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("2606:4700:4700::1111")}}, }, { Name: aws.String("create-test-multiple.zone-2.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.8.8")}, {Value: aws.String("8.8.4.4")}}, }, { Name: aws.String("create-test-multiple-aaaa.zone-2.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeAaaa, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("2606:4700:4700::1111")}, {Value: aws.String("2606:4700:4700::1001")}}, }, { Name: aws.String("update-test-multiple.zone-2.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}, {Value: aws.String("4.3.2.1")}}, }, { Name: aws.String("update-test-multiple-aaaa.zone-2.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeAaaa, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("2606:4700:4700::1001")}, {Value: aws.String("2606:4700:4700::1111")}}, }, { Name: aws.String("update-test-mx.zone-2.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeMx, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("20 mailhost3.foo.elb.amazonaws.com")}}, }, }) @@ -1191,79 +1191,79 @@ func TestAWSApplyChangesDryRun(t *testing.T) { { Name: aws.String("update-test.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.8.8")}}, }, { Name: aws.String("delete-test.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.8.8")}}, }, { Name: aws.String("update-test.zone-2.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.4.4")}}, }, { Name: aws.String("delete-test.zone-2.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.4.4")}}, }, { Name: aws.String("update-test-a-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.1.1.1")}}, }, { Name: aws.String("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeCname, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("bar.elb.amazonaws.com")}}, }, { Name: aws.String("delete-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeCname, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("qux.elb.amazonaws.com")}}, }, { Name: aws.String("update-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeCname, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("bar.elb.amazonaws.com")}}, }, { Name: aws.String("delete-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeCname, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("qux.elb.amazonaws.com")}}, }, { Name: aws.String("update-test-multiple.zone-2.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.8.8")}, {Value: aws.String("8.8.4.4")}}, }, { Name: aws.String("delete-test-multiple.zone-2.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeA, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}, {Value: aws.String("4.3.2.1")}}, }, { Name: aws.String("update-test-mx.zone-1.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeMx, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("20 mail.foo.elb.amazonaws.com")}}, }, { Name: aws.String("delete-test-mx.zone-2.ext-dns-test-2.teapot.zalan.do."), Type: route53types.RRTypeMx, - TTL: aws.Int64(recordTTL), + TTL: aws.Int64(defaultTTL), ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("10 mail.bar.elb.amazonaws.com")}}, }, } @@ -1464,7 +1464,7 @@ func TestAWSsubmitChanges(t *testing.T) { for j := 1; j < (hosts + 1); j++ { hostname := fmt.Sprintf("subnet%dhost%d.zone-1.ext-dns-test-2.teapot.zalan.do", i, j) ip := fmt.Sprintf("1.1.%d.%d", i, j) - ep := endpoint.NewEndpointWithTTL(hostname, endpoint.RecordTypeA, endpoint.TTL(recordTTL), ip) + ep := endpoint.NewEndpointWithTTL(hostname, endpoint.RecordTypeA, endpoint.TTL(defaultTTL), ip) endpoints = append(endpoints, ep) } } @@ -1491,7 +1491,7 @@ func TestAWSsubmitChangesError(t *testing.T) { zones, err := provider.zones(ctx) require.NoError(t, err) - ep := endpoint.NewEndpointWithTTL("fail.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.0.0.1") + ep := endpoint.NewEndpointWithTTL("fail.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "1.0.0.1") cs := provider.newChanges(route53types.ChangeActionCreate, []*endpoint.Endpoint{ep}) require.Error(t, provider.submitChanges(ctx, cs, zones)) @@ -1504,11 +1504,11 @@ func TestAWSsubmitChangesRetryOnError(t *testing.T) { zones, err := provider.zones(ctx) require.NoError(t, err) - ep1 := endpoint.NewEndpointWithTTL("success.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.0.0.1") - ep2 := endpoint.NewEndpointWithTTL("fail.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.0.0.2") - ep3 := endpoint.NewEndpointWithTTL("success2.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.0.0.3") + ep1 := endpoint.NewEndpointWithTTL("success.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "1.0.0.1") + ep2 := endpoint.NewEndpointWithTTL("fail.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "1.0.0.2") + ep3 := endpoint.NewEndpointWithTTL("success2.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "1.0.0.3") - ep2txt := endpoint.NewEndpointWithTTL("fail__edns_housekeeping.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeTXT, endpoint.TTL(recordTTL), "something") // "__edns_housekeeping" is the TXT suffix + ep2txt := endpoint.NewEndpointWithTTL("fail__edns_housekeeping.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeTXT, endpoint.TTL(defaultTTL), "something") // "__edns_housekeeping" is the TXT suffix ep2txt.Labels = map[string]string{ endpoint.OwnedRecordLabelKey: "fail.zone-1.ext-dns-test-2.teapot.zalan.do", } @@ -2315,26 +2315,26 @@ func containsRecordWithDNSName(records []*endpoint.Endpoint, dnsName string) boo func TestRequiresDeleteCreate(t *testing.T) { provider, _ := newAWSProvider(t, endpoint.NewDomainFilter([]string{"foo.bar."}), provider.NewZoneIDFilter([]string{}), provider.NewZoneTypeFilter(""), defaultEvaluateTargetHealth, false, nil) - oldRecordType := endpoint.NewEndpointWithTTL("recordType", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8") - newRecordType := endpoint.NewEndpointWithTTL("recordType", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "bar").WithProviderSpecific(providerSpecificAlias, "false") + oldRecordType := endpoint.NewEndpointWithTTL("recordType", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "8.8.8.8") + newRecordType := endpoint.NewEndpointWithTTL("recordType", endpoint.RecordTypeCNAME, endpoint.TTL(defaultTTL), "bar").WithProviderSpecific(providerSpecificAlias, "false") assert.False(t, provider.requiresDeleteCreate(oldRecordType, oldRecordType), "actual and expected endpoints don't match. %+v:%+v", oldRecordType, oldRecordType) assert.True(t, provider.requiresDeleteCreate(oldRecordType, newRecordType), "actual and expected endpoints don't match. %+v:%+v", oldRecordType, newRecordType) - oldAtoAlias := endpoint.NewEndpointWithTTL("AtoAlias", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.1.1.1") - newAtoAlias := endpoint.NewEndpointWithTTL("AtoAlias", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "bar.us-east-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true") + oldAtoAlias := endpoint.NewEndpointWithTTL("AtoAlias", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "1.1.1.1") + newAtoAlias := endpoint.NewEndpointWithTTL("AtoAlias", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "bar.us-east-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true") assert.False(t, provider.requiresDeleteCreate(oldAtoAlias, oldAtoAlias), "actual and expected endpoints don't match. %+v:%+v", oldAtoAlias, oldAtoAlias.DNSName) assert.True(t, provider.requiresDeleteCreate(oldAtoAlias, newAtoAlias), "actual and expected endpoints don't match. %+v:%+v", oldAtoAlias, newAtoAlias) - oldPolicy := endpoint.NewEndpointWithTTL("policy", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8").WithSetIdentifier("nochange").WithProviderSpecific(providerSpecificRegion, "us-east-1") - newPolicy := endpoint.NewEndpointWithTTL("policy", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8").WithSetIdentifier("nochange").WithProviderSpecific(providerSpecificWeight, "10") + oldPolicy := endpoint.NewEndpointWithTTL("policy", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "8.8.8.8").WithSetIdentifier("nochange").WithProviderSpecific(providerSpecificRegion, "us-east-1") + newPolicy := endpoint.NewEndpointWithTTL("policy", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "8.8.8.8").WithSetIdentifier("nochange").WithProviderSpecific(providerSpecificWeight, "10") assert.False(t, provider.requiresDeleteCreate(oldPolicy, oldPolicy), "actual and expected endpoints don't match. %+v:%+v", oldPolicy, oldPolicy) assert.True(t, provider.requiresDeleteCreate(oldPolicy, newPolicy), "actual and expected endpoints don't match. %+v:%+v", oldPolicy, newPolicy) - oldSetIdentifier := endpoint.NewEndpointWithTTL("setIdentifier", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8").WithSetIdentifier("old") - newSetIdentifier := endpoint.NewEndpointWithTTL("setIdentifier", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8").WithSetIdentifier("new") + oldSetIdentifier := endpoint.NewEndpointWithTTL("setIdentifier", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "8.8.8.8").WithSetIdentifier("old") + newSetIdentifier := endpoint.NewEndpointWithTTL("setIdentifier", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "8.8.8.8").WithSetIdentifier("new") assert.False(t, provider.requiresDeleteCreate(oldSetIdentifier, oldSetIdentifier), "actual and expected endpoints don't match. %+v:%+v", oldSetIdentifier, oldSetIdentifier) assert.True(t, provider.requiresDeleteCreate(oldSetIdentifier, newSetIdentifier), "actual and expected endpoints don't match. %+v:%+v", oldSetIdentifier, newSetIdentifier) diff --git a/provider/awssd/aws_sd.go b/provider/awssd/aws_sd.go index 95ecda406..44511f0b9 100644 --- a/provider/awssd/aws_sd.go +++ b/provider/awssd/aws_sd.go @@ -35,7 +35,7 @@ import ( ) const ( - sdDefaultRecordTTL = 300 + defaultTTL = 300 sdNamespaceTypePublic = "public" sdNamespaceTypePrivate = "private" @@ -407,7 +407,7 @@ func (p *AWSSDProvider) CreateService(ctx context.Context, namespaceID *string, srvType := p.serviceTypeFromEndpoint(ep) routingPolicy := p.routingPolicyFromEndpoint(ep) - ttl := int64(sdDefaultRecordTTL) + ttl := int64(defaultTTL) if ep.RecordTTL.IsConfigured() { ttl = int64(ep.RecordTTL) } @@ -443,7 +443,7 @@ func (p *AWSSDProvider) UpdateService(ctx context.Context, service *sdtypes.Serv srvType := p.serviceTypeFromEndpoint(ep) - ttl := int64(sdDefaultRecordTTL) + ttl := int64(defaultTTL) if ep.RecordTTL.IsConfigured() { ttl = int64(ep.RecordTTL) } diff --git a/provider/azure/azure.go b/provider/azure/azure.go index e80345e6f..c71e638ec 100644 --- a/provider/azure/azure.go +++ b/provider/azure/azure.go @@ -35,7 +35,7 @@ import ( ) const ( - azureRecordTTL = 300 + defaultTTL = 300 ) // ZonesClient is an interface of dns.ZoneClient that can be stubbed for testing. @@ -337,7 +337,7 @@ func (p *AzureProvider) recordSetNameForZone(zone string, endpoint *endpoint.End } func (p *AzureProvider) newRecordSet(endpoint *endpoint.Endpoint) (dns.RecordSet, error) { - var ttl int64 = azureRecordTTL + var ttl int64 = defaultTTL if endpoint.RecordTTL.IsConfigured() { ttl = int64(endpoint.RecordTTL) } diff --git a/provider/azure/azure_private_dns.go b/provider/azure/azure_private_dns.go index 5ca3f5928..d31fa20a5 100644 --- a/provider/azure/azure_private_dns.go +++ b/provider/azure/azure_private_dns.go @@ -344,7 +344,7 @@ func (p *AzurePrivateDNSProvider) recordSetNameForZone(zone string, endpoint *en } func (p *AzurePrivateDNSProvider) newRecordSet(endpoint *endpoint.Endpoint) (privatedns.RecordSet, error) { - var ttl int64 = azureRecordTTL + var ttl int64 = defaultTTL if endpoint.RecordTTL.IsConfigured() { ttl = int64(endpoint.RecordTTL) } diff --git a/provider/cloudflare/cloudflare.go b/provider/cloudflare/cloudflare.go index 69dd22e6e..e89d82cf1 100644 --- a/provider/cloudflare/cloudflare.go +++ b/provider/cloudflare/cloudflare.go @@ -44,8 +44,8 @@ const ( cloudFlareDelete = "DELETE" // cloudFlareUpdate is a ChangeAction enum value cloudFlareUpdate = "UPDATE" - // defaultCloudFlareRecordTTL 1 = automatic - defaultCloudFlareRecordTTL = 1 + // defaultTTL 1 = automatic + defaultTTL = 1 ) // We have to use pointers to bools now, as the upstream cloudflare-go library requires them @@ -58,7 +58,6 @@ var ( proxyDisabled *bool = boolPtr(false) ) -// for faster getRecordID() lookup type DNSRecordIndex struct { Name string Type string @@ -802,7 +801,7 @@ func (p *CloudFlareProvider) newCustomHostname(customHostname string, origin str } func (p *CloudFlareProvider) newCloudFlareChange(action string, ep *endpoint.Endpoint, target string, current *endpoint.Endpoint) *cloudFlareChange { - ttl := defaultCloudFlareRecordTTL + ttl := defaultTTL proxied := shouldBeProxied(ep, p.proxiedByDefault) if ep.RecordTTL.IsConfigured() { diff --git a/provider/cloudflare/cloudflare_test.go b/provider/cloudflare/cloudflare_test.go index fd3a97d06..4d841776c 100644 --- a/provider/cloudflare/cloudflare_test.go +++ b/provider/cloudflare/cloudflare_test.go @@ -1217,7 +1217,7 @@ func TestCloudflareGroupByNameAndType(t *testing.T) { Name: "foo.com", Type: endpoint.RecordTypeA, Content: "10.10.10.1", - TTL: defaultCloudFlareRecordTTL, + TTL: defaultTTL, Proxied: proxyDisabled, }, }, @@ -1226,7 +1226,7 @@ func TestCloudflareGroupByNameAndType(t *testing.T) { DNSName: "foo.com", Targets: endpoint.Targets{"10.10.10.1"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -1244,14 +1244,14 @@ func TestCloudflareGroupByNameAndType(t *testing.T) { Name: "foo.com", Type: endpoint.RecordTypeA, Content: "10.10.10.1", - TTL: defaultCloudFlareRecordTTL, + TTL: defaultTTL, Proxied: proxyDisabled, }, { Name: "foo.com", Type: endpoint.RecordTypeA, Content: "10.10.10.2", - TTL: defaultCloudFlareRecordTTL, + TTL: defaultTTL, Proxied: proxyDisabled, }, }, @@ -1260,7 +1260,7 @@ func TestCloudflareGroupByNameAndType(t *testing.T) { DNSName: "foo.com", Targets: endpoint.Targets{"10.10.10.1", "10.10.10.2"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -1278,28 +1278,28 @@ func TestCloudflareGroupByNameAndType(t *testing.T) { Name: "foo.com", Type: endpoint.RecordTypeA, Content: "10.10.10.1", - TTL: defaultCloudFlareRecordTTL, + TTL: defaultTTL, Proxied: proxyDisabled, }, { Name: "foo.com", Type: endpoint.RecordTypeA, Content: "10.10.10.2", - TTL: defaultCloudFlareRecordTTL, + TTL: defaultTTL, Proxied: proxyDisabled, }, { Name: "bar.de", Type: endpoint.RecordTypeA, Content: "10.10.10.1", - TTL: defaultCloudFlareRecordTTL, + TTL: defaultTTL, Proxied: proxyDisabled, }, { Name: "bar.de", Type: endpoint.RecordTypeA, Content: "10.10.10.2", - TTL: defaultCloudFlareRecordTTL, + TTL: defaultTTL, Proxied: proxyDisabled, }, }, @@ -1308,7 +1308,7 @@ func TestCloudflareGroupByNameAndType(t *testing.T) { DNSName: "foo.com", Targets: endpoint.Targets{"10.10.10.1", "10.10.10.2"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -1321,7 +1321,7 @@ func TestCloudflareGroupByNameAndType(t *testing.T) { DNSName: "bar.de", Targets: endpoint.Targets{"10.10.10.1", "10.10.10.2"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -1339,21 +1339,21 @@ func TestCloudflareGroupByNameAndType(t *testing.T) { Name: "foo.com", Type: endpoint.RecordTypeA, Content: "10.10.10.1", - TTL: defaultCloudFlareRecordTTL, + TTL: defaultTTL, Proxied: proxyDisabled, }, { Name: "foo.com", Type: endpoint.RecordTypeA, Content: "10.10.10.2", - TTL: defaultCloudFlareRecordTTL, + TTL: defaultTTL, Proxied: proxyDisabled, }, { Name: "bar.de", Type: endpoint.RecordTypeA, Content: "10.10.10.1", - TTL: defaultCloudFlareRecordTTL, + TTL: defaultTTL, Proxied: proxyDisabled, }, }, @@ -1362,7 +1362,7 @@ func TestCloudflareGroupByNameAndType(t *testing.T) { DNSName: "foo.com", Targets: endpoint.Targets{"10.10.10.1", "10.10.10.2"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -1375,7 +1375,7 @@ func TestCloudflareGroupByNameAndType(t *testing.T) { DNSName: "bar.de", Targets: endpoint.Targets{"10.10.10.1"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -1393,21 +1393,21 @@ func TestCloudflareGroupByNameAndType(t *testing.T) { Name: "foo.com", Type: endpoint.RecordTypeA, Content: "10.10.10.1", - TTL: defaultCloudFlareRecordTTL, + TTL: defaultTTL, Proxied: proxyDisabled, }, { Name: "foo.com", Type: endpoint.RecordTypeA, Content: "10.10.10.2", - TTL: defaultCloudFlareRecordTTL, + TTL: defaultTTL, Proxied: proxyDisabled, }, { Name: "bar.de", Type: "NOT SUPPORTED", Content: "10.10.10.1", - TTL: defaultCloudFlareRecordTTL, + TTL: defaultTTL, Proxied: proxyDisabled, }, }, @@ -1416,7 +1416,7 @@ func TestCloudflareGroupByNameAndType(t *testing.T) { DNSName: "foo.com", Targets: endpoint.Targets{"10.10.10.1", "10.10.10.2"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -1568,7 +1568,7 @@ func TestCloudflareComplexUpdate(t *testing.T) { DNSName: "foobar.bar.com", Targets: endpoint.Targets{"1.2.3.4", "2.3.4.5"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -1935,7 +1935,7 @@ func TestCloudflareDNSRecordsOperationsFail(t *testing.T) { DNSName: "newerror.bar.com", Targets: endpoint.Targets{"1.2.3.4"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, }, }, @@ -1948,7 +1948,7 @@ func TestCloudflareDNSRecordsOperationsFail(t *testing.T) { DNSName: "newerror-list-1.foo.bar.com", Targets: endpoint.Targets{"1.2.3.4"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, }, }, @@ -1966,7 +1966,7 @@ func TestCloudflareDNSRecordsOperationsFail(t *testing.T) { DNSName: "newerror-update-1.foo.bar.com", Targets: endpoint.Targets{"1.2.3.4"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, }, }, @@ -2050,7 +2050,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) { DNSName: "create.foo.bar.com", Targets: endpoint.Targets{"1.2.3.4"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -2069,7 +2069,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) { DNSName: "origin.foo.bar.com", Targets: endpoint.Targets{"1.2.3.4", "2.3.4.5"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -2082,7 +2082,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) { DNSName: "another-origin.foo.bar.com", Targets: endpoint.Targets{"3.4.5.6"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -2101,7 +2101,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) { DNSName: "c.foo.bar.com", Targets: endpoint.Targets{"c.cname.foo.bar.com"}, RecordType: endpoint.RecordTypeCNAME, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -2122,7 +2122,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) { "heritage=external-dns,external-dns/owner=default,external-dns/resource=service/external-dns/my-domain-here-app", }, RecordType: endpoint.RecordTypeTXT, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -2141,7 +2141,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) { DNSName: "fail.foo.bar.com", Targets: endpoint.Targets{"1.2.3.4"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -2160,7 +2160,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) { DNSName: "fail.list.foo.bar.com", Targets: endpoint.Targets{"1.2.3.4"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -2184,7 +2184,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) { DNSName: "b.foo.bar.com", Targets: endpoint.Targets{"1.2.3.4"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -2203,7 +2203,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) { DNSName: "b.foo.bar.com", Targets: endpoint.Targets{"1.2.3.4"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -2222,7 +2222,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) { DNSName: "b.foo.bar.com", Targets: endpoint.Targets{"1.2.3.4"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -2241,7 +2241,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) { DNSName: "b.foo.bar.com", Targets: endpoint.Targets{"1.2.3.4"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, }, }, @@ -2254,7 +2254,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) { DNSName: "b.foo.bar.com", Targets: endpoint.Targets{"1.2.3.4"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -2285,7 +2285,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) { DNSName: "nocustomhostname.foo.bar.com", Targets: endpoint.Targets{"1.2.3.4"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, }, }, @@ -2298,7 +2298,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) { DNSName: "a.foo.bar.com", Targets: endpoint.Targets{"1.2.3.4"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -2311,7 +2311,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) { DNSName: "txt.foo.bar.com", Targets: endpoint.Targets{"value"}, RecordType: endpoint.RecordTypeTXT, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -2332,7 +2332,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) { DNSName: "a.foo.bar.com", Targets: endpoint.Targets{"1.2.3.4"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -2353,7 +2353,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) { DNSName: "a.foo.bar.com", Targets: endpoint.Targets{"1.2.3.4"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -2376,7 +2376,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) { DNSName: "a.foo.bar.com", Targets: endpoint.Targets{"1.2.3.4"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -2399,7 +2399,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) { DNSName: "a.foo.bar.com", Targets: endpoint.Targets{"1.2.3.4"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -2420,7 +2420,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) { DNSName: "a.foo.bar.com", Targets: endpoint.Targets{"1.2.3.4"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, }, }, @@ -2509,7 +2509,7 @@ func TestCloudflareDisabledCustomHostnameOperations(t *testing.T) { DNSName: "a.foo.bar.com", Targets: endpoint.Targets{"1.2.3.11"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -2522,14 +2522,14 @@ func TestCloudflareDisabledCustomHostnameOperations(t *testing.T) { DNSName: "b.foo.bar.com", Targets: endpoint.Targets{"1.2.3.12"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, }, { DNSName: "c.foo.bar.com", Targets: endpoint.Targets{"1.2.3.13"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -2548,14 +2548,14 @@ func TestCloudflareDisabledCustomHostnameOperations(t *testing.T) { DNSName: "a.foo.bar.com", Targets: endpoint.Targets{"1.2.3.11"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, }, { DNSName: "b.foo.bar.com", Targets: endpoint.Targets{"1.2.3.12"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -2568,7 +2568,7 @@ func TestCloudflareDisabledCustomHostnameOperations(t *testing.T) { DNSName: "c.foo.bar.com", Targets: endpoint.Targets{"1.2.3.13"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -2632,7 +2632,7 @@ func TestCloudflareCustomHostnameNotFoundOnRecordDeletion(t *testing.T) { DNSName: "create.foo.bar.com", Targets: endpoint.Targets{"1.2.3.4"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -2664,7 +2664,7 @@ func TestCloudflareCustomHostnameNotFoundOnRecordDeletion(t *testing.T) { DNSName: "a.foo.bar.com", Targets: endpoint.Targets{"1.2.3.4"}, RecordType: endpoint.RecordTypeA, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { @@ -2751,7 +2751,7 @@ func TestCloudflareListCustomHostnamesWithPagionation(t *testing.T) { DNSName: fmt.Sprintf("host-%d.foo.bar.com", i), Targets: endpoint.Targets{fmt.Sprintf("cname-%d.foo.bar.com", i)}, RecordType: endpoint.RecordTypeCNAME, - RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL), + RecordTTL: endpoint.TTL(defaultTTL), Labels: endpoint.Labels{}, ProviderSpecific: endpoint.ProviderSpecific{ { diff --git a/provider/digitalocean/digital_ocean.go b/provider/digitalocean/digital_ocean.go index 409681317..2bac6dce3 100644 --- a/provider/digitalocean/digital_ocean.go +++ b/provider/digitalocean/digital_ocean.go @@ -34,8 +34,8 @@ import ( ) const ( - // digitalOceanRecordTTL is the default TTL value - digitalOceanRecordTTL = 300 + // defaultTTL is the default TTL value + defaultTTL = 300 ) // DigitalOceanProvider is an implementation of Provider for Digital Ocean's DNS. @@ -397,7 +397,7 @@ func getTTLFromEndpoint(ep *endpoint.Endpoint) int { if ep.RecordTTL.IsConfigured() { return int(ep.RecordTTL) } - return digitalOceanRecordTTL + return defaultTTL } func endpointsByZone(zoneNameIDMapper provider.ZoneIDName, endpoints []*endpoint.Endpoint) map[string][]*endpoint.Endpoint { diff --git a/provider/digitalocean/digital_ocean_test.go b/provider/digitalocean/digital_ocean_test.go index cd5555b32..7088b0922 100644 --- a/provider/digitalocean/digital_ocean_test.go +++ b/provider/digitalocean/digital_ocean_test.go @@ -309,32 +309,32 @@ 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) + "1.2.3.4", defaultTTL) assert.Equal(t, &godo.DomainRecordEditRequest{ Type: endpoint.RecordTypeA, Name: "@", Data: "1.2.3.4", - TTL: digitalOceanRecordTTL, + TTL: defaultTTL, }, r1) // Ensure the CNAME records have a `.` appended. r2 := makeDomainEditRequest("example.com", "foo.example.com", endpoint.RecordTypeCNAME, - "bar.example.com", digitalOceanRecordTTL) + "bar.example.com", defaultTTL) assert.Equal(t, &godo.DomainRecordEditRequest{ Type: endpoint.RecordTypeCNAME, Name: "foo", Data: "bar.example.com.", - TTL: digitalOceanRecordTTL, + TTL: defaultTTL, }, 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) + "bar.example.com.", defaultTTL) assert.Equal(t, &godo.DomainRecordEditRequest{ Type: endpoint.RecordTypeCNAME, Name: "foo", Data: "bar.example.com.", - TTL: digitalOceanRecordTTL, + TTL: defaultTTL, }, r3) // Ensure that custom TTLs can be set @@ -350,24 +350,24 @@ func TestDigitalOceanMakeDomainEditRequest(t *testing.T) { // Ensure that MX records have `.` appended. r5 := makeDomainEditRequest("example.com", "foo.example.com", endpoint.RecordTypeMX, - "10 mx.example.com", digitalOceanRecordTTL) + "10 mx.example.com", defaultTTL) assert.Equal(t, &godo.DomainRecordEditRequest{ Type: endpoint.RecordTypeMX, Name: "foo", Data: "mx.example.com.", Priority: 10, - TTL: digitalOceanRecordTTL, + TTL: defaultTTL, }, r5) // Ensure that MX records do not have an extra `.` appended if they already have a `.` r6 := makeDomainEditRequest("example.com", "foo.example.com", endpoint.RecordTypeMX, - "10 mx.example.com.", digitalOceanRecordTTL) + "10 mx.example.com.", defaultTTL) assert.Equal(t, &godo.DomainRecordEditRequest{ Type: endpoint.RecordTypeMX, Name: "foo", Data: "mx.example.com.", Priority: 10, - TTL: digitalOceanRecordTTL, + TTL: defaultTTL, }, r6) } @@ -420,7 +420,7 @@ func TestDigitalOceanProcessCreateActions(t *testing.T) { Name: "foo", Type: endpoint.RecordTypeA, Data: "1.2.3.4", - TTL: digitalOceanRecordTTL, + TTL: defaultTTL, }, }, { @@ -429,7 +429,7 @@ func TestDigitalOceanProcessCreateActions(t *testing.T) { Name: "@", Type: endpoint.RecordTypeCNAME, Data: "foo.example.com.", - TTL: digitalOceanRecordTTL, + TTL: defaultTTL, }, }, { @@ -439,7 +439,7 @@ func TestDigitalOceanProcessCreateActions(t *testing.T) { Type: endpoint.RecordTypeMX, Priority: 10, Data: "mx.example.com.", - TTL: digitalOceanRecordTTL, + TTL: defaultTTL, }, }, { @@ -448,7 +448,7 @@ func TestDigitalOceanProcessCreateActions(t *testing.T) { Name: "@", Type: endpoint.RecordTypeTXT, Data: "SOME-TXT-TEXT", - TTL: digitalOceanRecordTTL, + TTL: defaultTTL, }, }, } @@ -466,21 +466,21 @@ func TestDigitalOceanProcessUpdateActions(t *testing.T) { Name: "foo", Type: endpoint.RecordTypeA, Data: "1.2.3.4", - TTL: digitalOceanRecordTTL, + TTL: defaultTTL, }, { ID: 2, Name: "foo", Type: endpoint.RecordTypeA, Data: "5.6.7.8", - TTL: digitalOceanRecordTTL, + TTL: defaultTTL, }, { ID: 3, Name: "@", Type: endpoint.RecordTypeCNAME, Data: "foo.example.com.", - TTL: digitalOceanRecordTTL, + TTL: defaultTTL, }, { ID: 4, @@ -488,7 +488,7 @@ func TestDigitalOceanProcessUpdateActions(t *testing.T) { Type: endpoint.RecordTypeMX, Data: "mx1.example.com.", Priority: 10, - TTL: digitalOceanRecordTTL, + TTL: defaultTTL, }, { ID: 5, @@ -496,14 +496,14 @@ func TestDigitalOceanProcessUpdateActions(t *testing.T) { Type: endpoint.RecordTypeMX, Data: "mx2.example.com.", Priority: 10, - TTL: digitalOceanRecordTTL, + TTL: defaultTTL, }, { ID: 6, Name: "@", Type: endpoint.RecordTypeTXT, Data: "SOME_TXTX_TEXT", - TTL: digitalOceanRecordTTL, + TTL: defaultTTL, }, }, } @@ -532,7 +532,7 @@ func TestDigitalOceanProcessUpdateActions(t *testing.T) { Name: "foo", Type: endpoint.RecordTypeA, Data: "10.11.12.13", - TTL: digitalOceanRecordTTL, + TTL: defaultTTL, }, }, { @@ -541,7 +541,7 @@ func TestDigitalOceanProcessUpdateActions(t *testing.T) { Name: "@", Type: endpoint.RecordTypeCNAME, Data: "bar.example.com.", - TTL: digitalOceanRecordTTL, + TTL: defaultTTL, }, }, { @@ -551,7 +551,7 @@ func TestDigitalOceanProcessUpdateActions(t *testing.T) { Type: endpoint.RecordTypeMX, Data: "mx3.example.com.", Priority: 10, - TTL: digitalOceanRecordTTL, + TTL: defaultTTL, }, }, { @@ -560,7 +560,7 @@ func TestDigitalOceanProcessUpdateActions(t *testing.T) { Name: "@", Type: endpoint.RecordTypeTXT, Data: "ANOTHER-TXT", - TTL: digitalOceanRecordTTL, + TTL: defaultTTL, }, }, } @@ -609,7 +609,7 @@ func TestDigitalOceanProcessDeleteActions(t *testing.T) { Name: "foo", Type: endpoint.RecordTypeA, Data: "1.2.3.4", - TTL: digitalOceanRecordTTL, + TTL: defaultTTL, }, // This record will not be deleted because it represents a target not specified to be deleted. { @@ -617,14 +617,14 @@ func TestDigitalOceanProcessDeleteActions(t *testing.T) { Name: "foo", Type: endpoint.RecordTypeA, Data: "5.6.7.8", - TTL: digitalOceanRecordTTL, + TTL: defaultTTL, }, { ID: 3, Name: "@", Type: endpoint.RecordTypeCNAME, Data: "foo.example.com.", - TTL: digitalOceanRecordTTL, + TTL: defaultTTL, }, }, } diff --git a/provider/dnsimple/dnsimple.go b/provider/dnsimple/dnsimple.go index 991fda08a..0230cbabb 100644 --- a/provider/dnsimple/dnsimple.go +++ b/provider/dnsimple/dnsimple.go @@ -38,7 +38,7 @@ const ( dnsimpleDelete = "DELETE" dnsimpleUpdate = "UPDATE" - dnsimpleRecordTTL = 3600 // Default TTL of 1 hour if not set (DNSimple's default) + defaultTTL = 3600 // Default TTL of 1 hour if not set (DNSimple's default) ) type dnsimpleIdentityService struct { @@ -231,7 +231,7 @@ func (p *dnsimpleProvider) Records(ctx context.Context) (endpoints []*endpoint.E // newDnsimpleChange initializes a new change to dns records func newDnsimpleChange(action string, e *endpoint.Endpoint) *dnsimpleChange { - ttl := dnsimpleRecordTTL + ttl := defaultTTL if e.RecordTTL.IsConfigured() { ttl = int(e.RecordTTL) } diff --git a/provider/gandi/gandi.go b/provider/gandi/gandi.go index 63b193f8f..37ed34605 100644 --- a/provider/gandi/gandi.go +++ b/provider/gandi/gandi.go @@ -33,7 +33,7 @@ const ( gandiCreate = "CREATE" gandiDelete = "DELETE" gandiUpdate = "UPDATE" - gandiTTL = 600 + defaultTTL = 600 gandiLiveDNSProvider = "livedns" ) @@ -255,7 +255,7 @@ func (p *GandiProvider) submitChanges(ctx context.Context, changes []*GandiChang func (p *GandiProvider) newGandiChanges(action string, endpoints []*endpoint.Endpoint) []*GandiChanges { changes := make([]*GandiChanges, 0, len(endpoints)) - ttl := gandiTTL + ttl := defaultTTL for _, e := range endpoints { if e.RecordTTL.IsConfigured() { ttl = int(e.RecordTTL) diff --git a/provider/godaddy/client.go b/provider/godaddy/client.go index c199143cc..4104087ec 100644 --- a/provider/godaddy/client.go +++ b/provider/godaddy/client.go @@ -34,17 +34,18 @@ import ( "sigs.k8s.io/external-dns/pkg/apis/externaldns" ) +const ( + ErrCodeQuotaExceeded = "QUOTA_EXCEEDED" + + // DefaultTimeout api requests after + DefaultTimeout = 180 * time.Second +) + // Errors var ( ErrAPIDown = errors.New("godaddy: the GoDaddy API is down") ) -const ( - ErrCodeQuotaExceeded = "QUOTA_EXCEEDED" - // DefaultTimeout api requests after 180s - DefaultTimeout = 180 * time.Second -) - // APIError error type APIError struct { Code string diff --git a/provider/godaddy/godaddy.go b/provider/godaddy/godaddy.go index 432fe8303..c74f4bbef 100644 --- a/provider/godaddy/godaddy.go +++ b/provider/godaddy/godaddy.go @@ -32,10 +32,10 @@ import ( ) const ( - gdMinimalTTL = 600 - gdCreate = 0 - gdReplace = 1 - gdDelete = 2 + defaultTTL = 600 + gdCreate = 0 + gdReplace = 1 + gdDelete = 2 domainsURI = "/v1/domains?statuses=ACTIVE,PENDING_DNS_ACTIVE" ) @@ -144,7 +144,7 @@ func NewGoDaddyProvider(ctx context.Context, domainFilter endpoint.DomainFilter, return &GDProvider{ client: client, domainFilter: domainFilter, - ttl: maxOf(gdMinimalTTL, ttl), + ttl: maxOf(defaultTTL, ttl), DryRun: dryRun, }, nil } @@ -353,7 +353,7 @@ func (p *GDProvider) changeAllRecords(endpoints []gdEndpoint, zoneRecords []*gdR dnsName = "@" } - e.endpoint.RecordTTL = endpoint.TTL(maxOf(gdMinimalTTL, int64(e.endpoint.RecordTTL))) + e.endpoint.RecordTTL = endpoint.TTL(maxOf(defaultTTL, int64(e.endpoint.RecordTTL))) if err := zoneRecord.applyEndpoint(e.action, p.client, *e.endpoint, dnsName, p.DryRun); err != nil { log.Errorf("Unable to apply change %s on record %s type %s, %v", actionNames[e.action], dnsName, e.endpoint.RecordType, err) diff --git a/provider/godaddy/godaddy_test.go b/provider/godaddy/godaddy_test.go index 22107df19..57e04e21f 100644 --- a/provider/godaddy/godaddy_test.go +++ b/provider/godaddy/godaddy_test.go @@ -138,13 +138,13 @@ func TestGoDaddyZoneRecords(t *testing.T) { { Name: "godaddy", Type: "NS", - TTL: gdMinimalTTL, + TTL: defaultTTL, Data: "203.0.113.42", }, { Name: "godaddy", Type: "A", - TTL: gdMinimalTTL, + TTL: defaultTTL, Data: "203.0.113.42", }, }, nil).Once() @@ -164,13 +164,13 @@ func TestGoDaddyZoneRecords(t *testing.T) { { Name: "godaddy", Type: "NS", - TTL: gdMinimalTTL, + TTL: defaultTTL, Data: "203.0.113.42", }, { Name: "godaddy", Type: "A", - TTL: gdMinimalTTL, + TTL: defaultTTL, Data: "203.0.113.42", }, }, @@ -240,13 +240,13 @@ func TestGoDaddyRecords(t *testing.T) { { Name: "@", Type: "A", - TTL: gdMinimalTTL, + TTL: defaultTTL, Data: "203.0.113.42", }, { Name: "www", Type: "CNAME", - TTL: gdMinimalTTL, + TTL: defaultTTL, Data: "example.org", }, }, nil).Once() @@ -255,13 +255,13 @@ func TestGoDaddyRecords(t *testing.T) { { Name: "godaddy", Type: "A", - TTL: gdMinimalTTL, + TTL: defaultTTL, Data: "203.0.113.42", }, { Name: "godaddy", Type: "A", - TTL: gdMinimalTTL, + TTL: defaultTTL, Data: "203.0.113.43", }, }, nil).Once() @@ -278,7 +278,7 @@ func TestGoDaddyRecords(t *testing.T) { { DNSName: "godaddy.example.net", RecordType: "A", - RecordTTL: gdMinimalTTL, + RecordTTL: defaultTTL, Labels: endpoint.NewLabels(), Targets: []string{ "203.0.113.42", @@ -288,7 +288,7 @@ func TestGoDaddyRecords(t *testing.T) { { DNSName: "example.org", RecordType: "A", - RecordTTL: gdMinimalTTL, + RecordTTL: defaultTTL, Labels: endpoint.NewLabels(), Targets: []string{ "203.0.113.42", @@ -297,7 +297,7 @@ func TestGoDaddyRecords(t *testing.T) { { DNSName: "www.example.org", RecordType: "CNAME", - RecordTTL: gdMinimalTTL, + RecordTTL: defaultTTL, Labels: endpoint.NewLabels(), Targets: []string{ "example.org", @@ -327,7 +327,7 @@ func TestGoDaddyChange(t *testing.T) { { DNSName: ".example.net", RecordType: "A", - RecordTTL: gdMinimalTTL, + RecordTTL: defaultTTL, Targets: []string{ "203.0.113.42", }, @@ -356,7 +356,7 @@ func TestGoDaddyChange(t *testing.T) { { Name: "godaddy", Type: "A", - TTL: gdMinimalTTL, + TTL: defaultTTL, Data: "203.0.113.43", }, }, nil).Once() @@ -366,7 +366,7 @@ func TestGoDaddyChange(t *testing.T) { { Name: "@", Type: "A", - TTL: gdMinimalTTL, + TTL: defaultTTL, Data: "203.0.113.42", }, }).Return(nil, nil).Once() @@ -398,7 +398,7 @@ func TestGoDaddyErrorResponse(t *testing.T) { { DNSName: ".example.net", RecordType: "A", - RecordTTL: gdMinimalTTL, + RecordTTL: defaultTTL, Targets: []string{ "203.0.113.42", }, @@ -427,7 +427,7 @@ func TestGoDaddyErrorResponse(t *testing.T) { { Name: "godaddy", Type: "A", - TTL: gdMinimalTTL, + TTL: defaultTTL, Data: "203.0.113.43", }, }, nil).Once() diff --git a/provider/google/google.go b/provider/google/google.go index 148573b88..df0a71595 100644 --- a/provider/google/google.go +++ b/provider/google/google.go @@ -37,7 +37,7 @@ import ( ) const ( - googleRecordTTL = 300 + defaultTTL = 300 ) type managedZonesCreateCallInterface interface { @@ -450,7 +450,7 @@ func newRecord(ep *endpoint.Endpoint) *dns.ResourceRecordSet { } // no annotation results in a Ttl of 0, default to 300 for backwards-compatibility - var ttl int64 = googleRecordTTL + var ttl int64 = defaultTTL if ep.RecordTTL.IsConfigured() { ttl = int64(ep.RecordTTL) } diff --git a/provider/google/google_test.go b/provider/google/google_test.go index 0cec40a38..457243218 100644 --- a/provider/google/google_test.go +++ b/provider/google/google_test.go @@ -279,12 +279,12 @@ func TestGoogleRecords(t *testing.T) { func TestGoogleRecordsFilter(t *testing.T) { originalEndpoints := []*endpoint.Endpoint{ - endpoint.NewEndpointWithTTL("update-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, googleRecordTTL, "8.8.8.8"), - endpoint.NewEndpointWithTTL("delete-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, googleRecordTTL, "8.8.8.8"), - endpoint.NewEndpointWithTTL("update-test.zone-2.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, googleRecordTTL, "8.8.4.4"), - endpoint.NewEndpointWithTTL("delete-test.zone-2.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, googleRecordTTL, "8.8.4.4"), - endpoint.NewEndpointWithTTL("update-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, googleRecordTTL, "bar.elb.amazonaws.com"), - endpoint.NewEndpointWithTTL("delete-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, googleRecordTTL, "qux.elb.amazonaws.com"), + endpoint.NewEndpointWithTTL("update-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, defaultTTL, "8.8.8.8"), + endpoint.NewEndpointWithTTL("delete-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, defaultTTL, "8.8.8.8"), + endpoint.NewEndpointWithTTL("update-test.zone-2.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, defaultTTL, "8.8.4.4"), + endpoint.NewEndpointWithTTL("delete-test.zone-2.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, defaultTTL, "8.8.4.4"), + endpoint.NewEndpointWithTTL("update-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, defaultTTL, "bar.elb.amazonaws.com"), + endpoint.NewEndpointWithTTL("delete-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, defaultTTL, "qux.elb.amazonaws.com"), } provider := newGoogleProvider( @@ -339,12 +339,12 @@ func TestGoogleApplyChanges(t *testing.T) { provider.NewZoneIDFilter([]string{""}), false, []*endpoint.Endpoint{ - endpoint.NewEndpointWithTTL("update-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, googleRecordTTL, "8.8.8.8"), - endpoint.NewEndpointWithTTL("delete-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, googleRecordTTL, "8.8.8.8"), + endpoint.NewEndpointWithTTL("update-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, defaultTTL, "8.8.8.8"), + endpoint.NewEndpointWithTTL("delete-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, defaultTTL, "8.8.8.8"), endpoint.NewEndpointWithTTL("update-test-ttl.zone-2.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, endpoint.TTL(10), "8.8.4.4"), - endpoint.NewEndpointWithTTL("delete-test.zone-2.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, googleRecordTTL, "8.8.4.4"), - endpoint.NewEndpointWithTTL("update-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, googleRecordTTL, "bar.elb.amazonaws.com"), - endpoint.NewEndpointWithTTL("delete-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, googleRecordTTL, "qux.elb.amazonaws.com"), + endpoint.NewEndpointWithTTL("delete-test.zone-2.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, defaultTTL, "8.8.4.4"), + endpoint.NewEndpointWithTTL("update-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, defaultTTL, "bar.elb.amazonaws.com"), + endpoint.NewEndpointWithTTL("delete-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, defaultTTL, "qux.elb.amazonaws.com"), }, nil, nil, @@ -393,23 +393,23 @@ func TestGoogleApplyChanges(t *testing.T) { require.NoError(t, err) validateEndpoints(t, records, []*endpoint.Endpoint{ - endpoint.NewEndpointWithTTL("create-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, googleRecordTTL, "8.8.8.8"), - endpoint.NewEndpointWithTTL("update-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, googleRecordTTL, "1.2.3.4"), + endpoint.NewEndpointWithTTL("create-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, defaultTTL, "8.8.8.8"), + endpoint.NewEndpointWithTTL("update-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, defaultTTL, "1.2.3.4"), endpoint.NewEndpointWithTTL("create-test-ttl.zone-2.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, endpoint.TTL(15), "8.8.4.4"), endpoint.NewEndpointWithTTL("update-test-ttl.zone-2.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, endpoint.TTL(25), "4.3.2.1"), - endpoint.NewEndpointWithTTL("create-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, googleRecordTTL, "foo.elb.amazonaws.com"), - endpoint.NewEndpointWithTTL("update-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, googleRecordTTL, "baz.elb.amazonaws.com"), + endpoint.NewEndpointWithTTL("create-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, defaultTTL, "foo.elb.amazonaws.com"), + endpoint.NewEndpointWithTTL("update-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, defaultTTL, "baz.elb.amazonaws.com"), }) } func TestGoogleApplyChangesDryRun(t *testing.T) { originalEndpoints := []*endpoint.Endpoint{ - endpoint.NewEndpointWithTTL("update-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, googleRecordTTL, "8.8.8.8"), - endpoint.NewEndpointWithTTL("delete-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, googleRecordTTL, "8.8.8.8"), - endpoint.NewEndpointWithTTL("update-test.zone-2.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, googleRecordTTL, "8.8.4.4"), - endpoint.NewEndpointWithTTL("delete-test.zone-2.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, googleRecordTTL, "8.8.4.4"), - endpoint.NewEndpointWithTTL("update-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, googleRecordTTL, "bar.elb.amazonaws.com"), - endpoint.NewEndpointWithTTL("delete-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, googleRecordTTL, "qux.elb.amazonaws.com"), + endpoint.NewEndpointWithTTL("update-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, defaultTTL, "8.8.8.8"), + endpoint.NewEndpointWithTTL("delete-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, defaultTTL, "8.8.8.8"), + endpoint.NewEndpointWithTTL("update-test.zone-2.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, defaultTTL, "8.8.4.4"), + endpoint.NewEndpointWithTTL("delete-test.zone-2.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, defaultTTL, "8.8.4.4"), + endpoint.NewEndpointWithTTL("update-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, defaultTTL, "bar.elb.amazonaws.com"), + endpoint.NewEndpointWithTTL("delete-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, defaultTTL, "qux.elb.amazonaws.com"), } provider := newGoogleProvider(t, endpoint.NewDomainFilter([]string{"ext-dns-test-2.gcp.zalan.do."}), provider.NewZoneIDFilter([]string{""}), true, originalEndpoints, nil, nil) diff --git a/provider/ibmcloud/ibmcloud.go b/provider/ibmcloud/ibmcloud.go index c8a16cbdf..85bc8ae72 100644 --- a/provider/ibmcloud/ibmcloud.go +++ b/provider/ibmcloud/ibmcloud.go @@ -61,8 +61,8 @@ const ( recordDelete = "DELETE" // recordUpdate is a ChangeAction enum value recordUpdate = "UPDATE" - // defaultPublicRecordTTL 1 = automatic - defaultPublicRecordTTL = 1 + // defaultTTL 1 = automatic + defaultTTL = 1 proxyFilter = "ibmcloud-proxied" vpcFilter = "ibmcloud-vpc" @@ -244,7 +244,7 @@ func (c *ibmcloudConfig) Validate(authenticator core.Authenticator, domainFilter return service, isPrivate, fmt.Errorf("failed to initialize ibmcloud public zones client: %v", err) } if c.Endpoint != "" { - service.publicZonesService.SetServiceURL(c.Endpoint) + _ = service.publicZonesService.SetServiceURL(c.Endpoint) } zonesResp, _, err := service.publicZonesService.ListZones(&zonesv1.ListZonesOptions{}) @@ -277,7 +277,7 @@ func (c *ibmcloudConfig) Validate(authenticator core.Authenticator, domainFilter return service, isPrivate, fmt.Errorf("failed to initialize ibmcloud public records client: %v", err) } if c.Endpoint != "" { - service.publicRecordsService.SetServiceURL(c.Endpoint) + _ = service.publicRecordsService.SetServiceURL(c.Endpoint) } case strings.Contains(crn.ServiceName, "dns-svcs"): isPrivate = true @@ -289,7 +289,7 @@ func (c *ibmcloudConfig) Validate(authenticator core.Authenticator, domainFilter return service, isPrivate, fmt.Errorf("failed to initialize ibmcloud private records client: %v", err) } if c.Endpoint != "" { - service.privateDNSService.SetServiceURL(c.Endpoint) + _ = service.privateDNSService.SetServiceURL(c.Endpoint) } default: return service, isPrivate, fmt.Errorf("IBM Cloud instance crn is not provided or invalid dns crn : %s", c.CRN) @@ -350,9 +350,9 @@ func (p *IBMCloudProvider) Records(ctx context.Context) (endpoints []*endpoint.E func (p *IBMCloudProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error { log.Debugln("applying change...") ibmcloudChanges := []*ibmcloudChange{} - for _, endpoint := range changes.Create { - for _, target := range endpoint.Targets { - ibmcloudChanges = append(ibmcloudChanges, p.newIBMCloudChange(recordCreate, endpoint, target)) + for _, et := range changes.Create { + for _, target := range et.Targets { + ibmcloudChanges = append(ibmcloudChanges, p.newIBMCloudChange(recordCreate, et, target)) } } @@ -375,9 +375,9 @@ func (p *IBMCloudProvider) ApplyChanges(ctx context.Context, changes *plan.Chang } } - for _, endpoint := range changes.Delete { - for _, target := range endpoint.Targets { - ibmcloudChanges = append(ibmcloudChanges, p.newIBMCloudChange(recordDelete, endpoint, target)) + for _, et := range changes.Delete { + for _, target := range et.Targets { + ibmcloudChanges = append(ibmcloudChanges, p.newIBMCloudChange(recordDelete, et, target)) } } @@ -687,7 +687,7 @@ func (p *IBMCloudProvider) privateRecords(ctx context.Context) ([]*endpoint.Endp } } - endpoints := []*endpoint.Endpoint{} + var endpoints []*endpoint.Endpoint for _, zone := range zones { if len(vpc) > 0 && *zone.State == zoneStatePendingNetwork { log.Debugf("active zone: %s", *zone.ID) @@ -729,7 +729,7 @@ GETRECORDS: } func (p *IBMCloudProvider) groupPrivateRecords(records []dnssvcsv1.ResourceRecord) []*endpoint.Endpoint { - endpoints := []*endpoint.Endpoint{} + var endpoints []*endpoint.Endpoint // group supported records by name and type groups := map[string][]dnssvcsv1.ResourceRecord{} for _, r := range records { @@ -805,7 +805,7 @@ func (p *IBMCloudProvider) getPrivateRecordID(records []dnssvcsv1.ResourceRecord } func (p *IBMCloudProvider) newIBMCloudChange(action string, endpoint *endpoint.Endpoint, target string) *ibmcloudChange { - ttl := defaultPublicRecordTTL + ttl := defaultTTL proxied := shouldBeProxied(endpoint, p.proxiedByDefault) if endpoint.RecordTTL.IsConfigured() { @@ -994,6 +994,7 @@ func checkVPCAnnotation(endpoint *endpoint.Endpoint) string { return vpc } +// TODO: could be shared function func isNil(i interface{}) bool { if i == nil { return true diff --git a/provider/ns1/ns1.go b/provider/ns1/ns1.go index 03b673d86..a6f207a86 100644 --- a/provider/ns1/ns1.go +++ b/provider/ns1/ns1.go @@ -40,8 +40,8 @@ const ( ns1Delete = "DELETE" // ns1Update is a ChangeAction enum value ns1Update = "UPDATE" - // ns1DefaultTTL is the default ttl for ttls that are not set - ns1DefaultTTL = 10 + // defaultTTL is the default ttl for ttls that are not set + defaultTTL = 10 ) // NS1DomainClient is a subset of the NS1 API the the provider uses, to ease testing @@ -183,7 +183,7 @@ func (p *NS1Provider) ns1BuildRecord(zoneName string, change *ns1Change) *dns.Re record.AddAnswer(dns.NewAnswer(strings.Split(v, " "))) } // set default ttl, but respect minTTLSeconds - ttl := ns1DefaultTTL + ttl := defaultTTL if p.minTTLSeconds > ttl { ttl = p.minTTLSeconds } diff --git a/provider/oci/oci.go b/provider/oci/oci.go index 66f291c5d..af6fbd518 100644 --- a/provider/oci/oci.go +++ b/provider/oci/oci.go @@ -35,7 +35,7 @@ import ( "sigs.k8s.io/external-dns/provider" ) -const ociRecordTTL = 300 +const defaultTTL = 300 // OCIAuthConfig holds connection parameters for the OCI API. type OCIAuthConfig struct { @@ -370,7 +370,7 @@ func newRecordOperation(ep *endpoint.Endpoint, opType dns.RecordOperationOperati } rdata := strings.Join(targets, " ") - ttl := ociRecordTTL + ttl := defaultTTL if ep.RecordTTL.IsConfigured() { ttl = int(ep.RecordTTL) } diff --git a/provider/oci/oci_test.go b/provider/oci/oci_test.go index 7906951aa..dce6b7386 100644 --- a/provider/oci/oci_test.go +++ b/provider/oci/oci_test.go @@ -93,12 +93,12 @@ func (c *mockOCIDNSClient) GetZoneRecords(ctx context.Context, request dns.GetZo Domain: common.String("foo.foo.com"), Rdata: common.String("127.0.0.1"), Rtype: common.String(endpoint.RecordTypeA), - Ttl: common.Int(ociRecordTTL), + Ttl: common.Int(defaultTTL), }, { Domain: common.String("foo.foo.com"), Rdata: common.String("heritage=external-dns,external-dns/owner=default,external-dns/resource=service/default/my-svc"), Rtype: common.String(endpoint.RecordTypeTXT), - Ttl: common.Int(ociRecordTTL), + Ttl: common.Int(defaultTTL), }} response.OpcNextPage = common.String("1") } else { @@ -106,7 +106,7 @@ func (c *mockOCIDNSClient) GetZoneRecords(ctx context.Context, request dns.GetZo Domain: common.String("bar.foo.com"), Rdata: common.String("bar.com."), Rtype: common.String(endpoint.RecordTypeCNAME), - Ttl: common.Int(ociRecordTTL), + Ttl: common.Int(defaultTTL), }} } case "ocid1.dns-zone.oc1..502aeddba262b92fd13ed7874f6f1404": @@ -115,7 +115,7 @@ func (c *mockOCIDNSClient) GetZoneRecords(ctx context.Context, request dns.GetZo Domain: common.String("foo.bar.com"), Rdata: common.String("127.0.0.1"), Rtype: common.String(endpoint.RecordTypeA), - Ttl: common.Int(ociRecordTTL), + Ttl: common.Int(defaultTTL), }} } } @@ -329,26 +329,26 @@ func TestOCIRecords(t *testing.T) { domainFilter: endpoint.NewDomainFilter([]string{""}), zoneIDFilter: provider.NewZoneIDFilter([]string{""}), expected: []*endpoint.Endpoint{ - endpoint.NewEndpointWithTTL("foo.foo.com", endpoint.RecordTypeA, endpoint.TTL(ociRecordTTL), "127.0.0.1"), - endpoint.NewEndpointWithTTL("foo.foo.com", endpoint.RecordTypeTXT, endpoint.TTL(ociRecordTTL), "heritage=external-dns,external-dns/owner=default,external-dns/resource=service/default/my-svc"), - endpoint.NewEndpointWithTTL("bar.foo.com", endpoint.RecordTypeCNAME, endpoint.TTL(ociRecordTTL), "bar.com."), - endpoint.NewEndpointWithTTL("foo.bar.com", endpoint.RecordTypeA, endpoint.TTL(ociRecordTTL), "127.0.0.1"), + endpoint.NewEndpointWithTTL("foo.foo.com", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "127.0.0.1"), + endpoint.NewEndpointWithTTL("foo.foo.com", endpoint.RecordTypeTXT, endpoint.TTL(defaultTTL), "heritage=external-dns,external-dns/owner=default,external-dns/resource=service/default/my-svc"), + endpoint.NewEndpointWithTTL("bar.foo.com", endpoint.RecordTypeCNAME, endpoint.TTL(defaultTTL), "bar.com."), + endpoint.NewEndpointWithTTL("foo.bar.com", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "127.0.0.1"), }, }, { name: "DomainFilter_foo.com", domainFilter: endpoint.NewDomainFilter([]string{"foo.com"}), zoneIDFilter: provider.NewZoneIDFilter([]string{""}), expected: []*endpoint.Endpoint{ - endpoint.NewEndpointWithTTL("foo.foo.com", endpoint.RecordTypeA, endpoint.TTL(ociRecordTTL), "127.0.0.1"), - endpoint.NewEndpointWithTTL("foo.foo.com", endpoint.RecordTypeTXT, endpoint.TTL(ociRecordTTL), "heritage=external-dns,external-dns/owner=default,external-dns/resource=service/default/my-svc"), - endpoint.NewEndpointWithTTL("bar.foo.com", endpoint.RecordTypeCNAME, endpoint.TTL(ociRecordTTL), "bar.com."), + endpoint.NewEndpointWithTTL("foo.foo.com", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "127.0.0.1"), + endpoint.NewEndpointWithTTL("foo.foo.com", endpoint.RecordTypeTXT, endpoint.TTL(defaultTTL), "heritage=external-dns,external-dns/owner=default,external-dns/resource=service/default/my-svc"), + endpoint.NewEndpointWithTTL("bar.foo.com", endpoint.RecordTypeCNAME, endpoint.TTL(defaultTTL), "bar.com."), }, }, { name: "ZoneIDFilter_ocid1.dns-zone.oc1..502aeddba262b92fd13ed7874f6f1404", domainFilter: endpoint.NewDomainFilter([]string{""}), zoneIDFilter: provider.NewZoneIDFilter([]string{"ocid1.dns-zone.oc1..502aeddba262b92fd13ed7874f6f1404"}), expected: []*endpoint.Endpoint{ - endpoint.NewEndpointWithTTL("foo.bar.com", endpoint.RecordTypeA, endpoint.TTL(ociRecordTTL), "127.0.0.1"), + endpoint.NewEndpointWithTTL("foo.bar.com", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "127.0.0.1"), }, }, } @@ -375,7 +375,7 @@ func TestNewRecordOperation(t *testing.T) { ep: endpoint.NewEndpointWithTTL( "foo.foo.com", endpoint.RecordTypeA, - endpoint.TTL(ociRecordTTL), + endpoint.TTL(defaultTTL), "127.0.0.1"), expected: dns.RecordOperation{ Domain: common.String("foo.foo.com"), @@ -390,7 +390,7 @@ func TestNewRecordOperation(t *testing.T) { ep: endpoint.NewEndpointWithTTL( "foo.foo.com", endpoint.RecordTypeTXT, - endpoint.TTL(ociRecordTTL), + endpoint.TTL(defaultTTL), "heritage=external-dns,external-dns/owner=default,external-dns/resource=service/default/my-svc"), expected: dns.RecordOperation{ Domain: common.String("foo.foo.com"), @@ -405,7 +405,7 @@ func TestNewRecordOperation(t *testing.T) { ep: endpoint.NewEndpointWithTTL( "foo.foo.com", endpoint.RecordTypeCNAME, - endpoint.TTL(ociRecordTTL), + endpoint.TTL(defaultTTL), "bar.com."), expected: dns.RecordOperation{ Domain: common.String("foo.foo.com"), @@ -640,12 +640,12 @@ func TestMutableMockOCIDNSClient(t *testing.T) { Domain: common.String("foo.foo.com"), Rdata: common.String("127.0.0.1"), Rtype: common.String(endpoint.RecordTypeA), - Ttl: common.Int(ociRecordTTL), + Ttl: common.Int(defaultTTL), }, { Domain: common.String("foo.foo.com"), Rdata: common.String("heritage=external-dns,external-dns/owner=default,external-dns/resource=service/default/my-svc"), Rtype: common.String(endpoint.RecordTypeTXT), - Ttl: common.Int(ociRecordTTL), + Ttl: common.Int(defaultTTL), }}, } client := newMutableMockOCIDNSClient(zones, records) @@ -732,14 +732,14 @@ func TestOCIApplyChanges(t *testing.T) { Create: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL( "foo.foo.com", endpoint.RecordTypeA, - endpoint.TTL(ociRecordTTL), + endpoint.TTL(defaultTTL), "127.0.0.1", )}, }, expectedEndpoints: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL( "foo.foo.com", endpoint.RecordTypeA, - endpoint.TTL(ociRecordTTL), + endpoint.TTL(defaultTTL), "127.0.0.1", )}, }, { @@ -753,26 +753,26 @@ func TestOCIApplyChanges(t *testing.T) { Domain: common.String("foo.foo.com"), Rdata: common.String("127.0.0.1"), Rtype: common.String(endpoint.RecordTypeA), - Ttl: common.Int(ociRecordTTL), + Ttl: common.Int(defaultTTL), }, { Domain: common.String("foo.foo.com"), Rdata: common.String("heritage=external-dns,external-dns/owner=default,external-dns/resource=service/default/my-svc"), Rtype: common.String(endpoint.RecordTypeTXT), - Ttl: common.Int(ociRecordTTL), + Ttl: common.Int(defaultTTL), }}, }, changes: &plan.Changes{ Delete: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL( "foo.foo.com", endpoint.RecordTypeTXT, - endpoint.TTL(ociRecordTTL), + endpoint.TTL(defaultTTL), "127.0.0.1", )}, }, expectedEndpoints: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL( "foo.foo.com", endpoint.RecordTypeA, - endpoint.TTL(ociRecordTTL), + endpoint.TTL(defaultTTL), "127.0.0.1", )}, }, { @@ -786,27 +786,27 @@ func TestOCIApplyChanges(t *testing.T) { Domain: common.String("foo.foo.com"), Rdata: common.String("127.0.0.1"), Rtype: common.String(endpoint.RecordTypeA), - Ttl: common.Int(ociRecordTTL), + Ttl: common.Int(defaultTTL), }}, }, changes: &plan.Changes{ UpdateOld: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL( "foo.foo.com", endpoint.RecordTypeA, - endpoint.TTL(ociRecordTTL), + endpoint.TTL(defaultTTL), "127.0.0.1", )}, UpdateNew: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL( "foo.foo.com", endpoint.RecordTypeA, - endpoint.TTL(ociRecordTTL), + endpoint.TTL(defaultTTL), "10.0.0.1", )}, }, expectedEndpoints: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL( "foo.foo.com", endpoint.RecordTypeA, - endpoint.TTL(ociRecordTTL), + endpoint.TTL(defaultTTL), "10.0.0.1", )}, }, { @@ -820,14 +820,14 @@ func TestOCIApplyChanges(t *testing.T) { Domain: common.String("foo.foo.com"), Rdata: common.String("127.0.0.1"), Rtype: common.String(endpoint.RecordTypeA), - Ttl: common.Int(ociRecordTTL), + Ttl: common.Int(defaultTTL), }}, }, changes: &plan.Changes{ Delete: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL( "foo.foo.com", endpoint.RecordTypeA, - endpoint.TTL(ociRecordTTL), + endpoint.TTL(defaultTTL), "127.0.0.1", )}, }, @@ -835,7 +835,7 @@ func TestOCIApplyChanges(t *testing.T) { expectedEndpoints: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL( "foo.foo.com", endpoint.RecordTypeA, - endpoint.TTL(ociRecordTTL), + endpoint.TTL(defaultTTL), "127.0.0.1", )}, }, { @@ -849,42 +849,42 @@ func TestOCIApplyChanges(t *testing.T) { Domain: common.String("foo.foo.com"), Rdata: common.String("127.0.0.1"), Rtype: common.String(endpoint.RecordTypeA), - Ttl: common.Int(ociRecordTTL), + Ttl: common.Int(defaultTTL), }, { Domain: common.String("car.foo.com"), Rdata: common.String("bar.com."), Rtype: common.String(endpoint.RecordTypeCNAME), - Ttl: common.Int(ociRecordTTL), + Ttl: common.Int(defaultTTL), }, { Domain: common.String("bar.foo.com"), Rdata: common.String("baz.com."), Rtype: common.String(endpoint.RecordTypeCNAME), - Ttl: common.Int(ociRecordTTL), + Ttl: common.Int(defaultTTL), }}, }, changes: &plan.Changes{ Delete: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL( "foo.foo.com", endpoint.RecordTypeA, - endpoint.TTL(ociRecordTTL), + endpoint.TTL(defaultTTL), "127.0.0.1", )}, UpdateOld: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL( "car.foo.com", endpoint.RecordTypeCNAME, - endpoint.TTL(ociRecordTTL), + endpoint.TTL(defaultTTL), "baz.com.", )}, UpdateNew: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL( "bar.foo.com", endpoint.RecordTypeCNAME, - endpoint.TTL(ociRecordTTL), + endpoint.TTL(defaultTTL), "foo.bar.com.", )}, Create: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL( "baz.foo.com", endpoint.RecordTypeA, - endpoint.TTL(ociRecordTTL), + endpoint.TTL(defaultTTL), "127.0.0.1", )}, }, @@ -892,13 +892,13 @@ func TestOCIApplyChanges(t *testing.T) { endpoint.NewEndpointWithTTL( "bar.foo.com", endpoint.RecordTypeCNAME, - endpoint.TTL(ociRecordTTL), + endpoint.TTL(defaultTTL), "foo.bar.com.", ), endpoint.NewEndpointWithTTL( "baz.foo.com", endpoint.RecordTypeA, - endpoint.TTL(ociRecordTTL), + endpoint.TTL(defaultTTL), "127.0.0.1"), }, }, @@ -913,19 +913,19 @@ func TestOCIApplyChanges(t *testing.T) { Create: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL( "foo.foo.com", endpoint.RecordTypeA, - endpoint.TTL(ociRecordTTL), + endpoint.TTL(defaultTTL), "192.168.1.2", ), endpoint.NewEndpointWithTTL( "foo.foo.com", endpoint.RecordTypeA, - endpoint.TTL(ociRecordTTL), + endpoint.TTL(defaultTTL), "192.168.2.5", )}, }, expectedEndpoints: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL( "foo.foo.com", endpoint.RecordTypeA, - endpoint.TTL(ociRecordTTL), "192.168.1.2", "192.168.2.5", + endpoint.TTL(defaultTTL), "192.168.1.2", "192.168.2.5", )}, }, { @@ -939,26 +939,26 @@ func TestOCIApplyChanges(t *testing.T) { Domain: common.String("foo.foo.com"), Rdata: common.String("192.168.1.2"), Rtype: common.String(endpoint.RecordTypeA), - Ttl: common.Int(ociRecordTTL), + Ttl: common.Int(defaultTTL), }, { Domain: common.String("foo.foo.com"), Rdata: common.String("192.168.2.5"), Rtype: common.String(endpoint.RecordTypeA), - Ttl: common.Int(ociRecordTTL), + Ttl: common.Int(defaultTTL), }}, }, changes: &plan.Changes{ Delete: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL( "foo.foo.com", endpoint.RecordTypeA, - endpoint.TTL(ociRecordTTL), + endpoint.TTL(defaultTTL), "192.168.1.2", )}, }, expectedEndpoints: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL( "foo.foo.com", endpoint.RecordTypeA, - endpoint.TTL(ociRecordTTL), "192.168.2.5", + endpoint.TTL(defaultTTL), "192.168.2.5", )}, }, { @@ -972,27 +972,27 @@ func TestOCIApplyChanges(t *testing.T) { Domain: common.String("first.foo.com"), Rdata: common.String("10.77.4.5"), Rtype: common.String(endpoint.RecordTypeA), - Ttl: common.Int(ociRecordTTL), + Ttl: common.Int(defaultTTL), }}, }, changes: &plan.Changes{ UpdateOld: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL( "first.foo.com", endpoint.RecordTypeA, - endpoint.TTL(ociRecordTTL), + endpoint.TTL(defaultTTL), "10.77.4.5", )}, UpdateNew: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL( "first.foo.com", endpoint.RecordTypeA, - endpoint.TTL(ociRecordTTL), + endpoint.TTL(defaultTTL), "10.77.6.10", )}, }, expectedEndpoints: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL( "first.foo.com", endpoint.RecordTypeA, - endpoint.TTL(ociRecordTTL), + endpoint.TTL(defaultTTL), "10.77.6.10", )}, }, @@ -1007,21 +1007,21 @@ func TestOCIApplyChanges(t *testing.T) { Domain: common.String("first.foo.com"), Rdata: common.String("10.77.4.5"), Rtype: common.String(endpoint.RecordTypeA), - Ttl: common.Int(ociRecordTTL), + Ttl: common.Int(defaultTTL), }}, }, changes: &plan.Changes{ Create: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL( "first.foo.com", endpoint.RecordTypeA, - endpoint.TTL(ociRecordTTL), + endpoint.TTL(defaultTTL), "10.77.6.10", )}, }, expectedEndpoints: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL( "first.foo.com", endpoint.RecordTypeA, - endpoint.TTL(ociRecordTTL), + endpoint.TTL(defaultTTL), "10.77.4.5", "10.77.6.10", )}, }, diff --git a/provider/ovh/ovh.go b/provider/ovh/ovh.go index 15c745b22..f7b67a65c 100644 --- a/provider/ovh/ovh.go +++ b/provider/ovh/ovh.go @@ -41,8 +41,8 @@ import ( ) const ( - ovhDefaultTTL = 0 - ovhCreate = iota + defaultTTL = 0 + ovhCreate = iota ovhDelete ovhUpdate ) @@ -506,7 +506,7 @@ func (p OVHProvider) newOvhChangeCreateDelete(action int, endpoints []*endpoint. FieldType: e.RecordType, ovhRecordFieldUpdate: ovhRecordFieldUpdate{ SubDomain: convertDNSNameIntoSubDomain(e.DNSName, zone), - TTL: ovhDefaultTTL, + TTL: defaultTTL, Target: target, }, }, @@ -617,7 +617,7 @@ func (p OVHProvider) newOvhChangeUpdate(endpointsOld []*endpoint.Endpoint, endpo if endpointsNew.RecordTTL.IsConfigured() { record.TTL = int64(endpointsNew.RecordTTL) } else { - record.TTL = ovhDefaultTTL + record.TTL = defaultTTL } change := ovhChange{ @@ -634,7 +634,7 @@ func (p OVHProvider) newOvhChangeUpdate(endpointsOld []*endpoint.Endpoint, endpo if len(toInsertTarget) > 0 { for _, target := range toInsertTarget { - recordTTL := int64(ovhDefaultTTL) + recordTTL := int64(defaultTTL) if endpointsNew.RecordTTL.IsConfigured() { recordTTL = int64(endpointsNew.RecordTTL) } @@ -680,6 +680,8 @@ func (c *ovhChange) String() string { action = "update" case ovhDelete: action = "delete" + default: + action = "unknown" } if c.ID != 0 { diff --git a/provider/ovh/ovh_test.go b/provider/ovh/ovh_test.go index fef1f3200..2e69d7a5d 100644 --- a/provider/ovh/ovh_test.go +++ b/provider/ovh/ovh_test.go @@ -371,8 +371,8 @@ func TestOvhNewChange(t *testing.T) { changes, _ := provider.newOvhChangeCreateDelete(ovhCreate, endpoints, "example.net", []ovhRecord{}) td.Cmp(t, changes, []ovhChange{ {Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "", TTL: 10, Target: "203.0.113.42"}}}}, - {Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh", TTL: ovhDefaultTTL, Target: "203.0.113.43"}}}}, - {Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "CNAME", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh2", TTL: ovhDefaultTTL, Target: "ovh.example.net."}}}}, + {Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh", TTL: defaultTTL, Target: "203.0.113.43"}}}}, + {Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "CNAME", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh2", TTL: defaultTTL, Target: "ovh.example.net."}}}}, }) // Delete change @@ -386,9 +386,9 @@ func TestOvhNewChange(t *testing.T) { } changes, _ = provider.newOvhChangeCreateDelete(ovhDelete, endpoints, "example.net", records) td.Cmp(t, changes, []ovhChange{ - {Action: ovhDelete, ovhRecord: ovhRecord{ID: 42, Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh", TTL: ovhDefaultTTL, Target: "203.0.113.42"}}}}, - {Action: ovhDelete, ovhRecord: ovhRecord{ID: 43, Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh", TTL: ovhDefaultTTL, Target: "203.0.113.42"}}}}, - {Action: ovhDelete, ovhRecord: ovhRecord{ID: 44, Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh", TTL: ovhDefaultTTL, Target: "203.0.113.42"}}}}, + {Action: ovhDelete, ovhRecord: ovhRecord{ID: 42, Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh", TTL: defaultTTL, Target: "203.0.113.42"}}}}, + {Action: ovhDelete, ovhRecord: ovhRecord{ID: 43, Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh", TTL: defaultTTL, Target: "203.0.113.42"}}}}, + {Action: ovhDelete, ovhRecord: ovhRecord{ID: 44, Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh", TTL: defaultTTL, Target: "203.0.113.42"}}}}, }) // Create change with CNAME relative @@ -403,8 +403,8 @@ func TestOvhNewChange(t *testing.T) { changes, _ = provider.newOvhChangeCreateDelete(ovhCreate, endpoints, "example.net", []ovhRecord{}) td.Cmp(t, changes, []ovhChange{ {Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "", TTL: 10, Target: "203.0.113.42"}}}}, - {Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh", TTL: ovhDefaultTTL, Target: "203.0.113.43"}}}}, - {Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "CNAME", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh2", TTL: ovhDefaultTTL, Target: "ovh"}}}}, + {Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh", TTL: defaultTTL, Target: "203.0.113.43"}}}}, + {Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "CNAME", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh2", TTL: defaultTTL, Target: "ovh"}}}}, }) // Test with CNAME when target has already final dot @@ -419,8 +419,8 @@ func TestOvhNewChange(t *testing.T) { changes, _ = provider.newOvhChangeCreateDelete(ovhCreate, endpoints, "example.net", []ovhRecord{}) td.Cmp(t, changes, []ovhChange{ {Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "", TTL: 10, Target: "203.0.113.42"}}}}, - {Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh", TTL: ovhDefaultTTL, Target: "203.0.113.43"}}}}, - {Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "CNAME", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh2", TTL: ovhDefaultTTL, Target: "ovh.example.com."}}}}, + {Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh", TTL: defaultTTL, Target: "203.0.113.43"}}}}, + {Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "CNAME", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh2", TTL: defaultTTL, Target: "ovh.example.com."}}}}, }) } diff --git a/provider/plural/plural.go b/provider/plural/plural.go index de6b2e1bb..691c7c683 100644 --- a/provider/plural/plural.go +++ b/provider/plural/plural.go @@ -45,7 +45,6 @@ type RecordChange struct { func NewPluralProvider(cluster, provider string) (*PluralProvider, error) { token := os.Getenv("PLURAL_ACCESS_TOKEN") - if token == "" { return nil, fmt.Errorf("no plural access token provided, you must set the PLURAL_ACCESS_TOKEN env var") } diff --git a/provider/rfc2136/rfc2136.go b/provider/rfc2136/rfc2136.go index 40ec52b34..8b1b58d53 100644 --- a/provider/rfc2136/rfc2136.go +++ b/provider/rfc2136/rfc2136.go @@ -19,6 +19,7 @@ package rfc2136 import ( "context" "crypto/tls" + "errors" "fmt" "math/rand" "net" @@ -32,7 +33,6 @@ import ( "github.com/bodgit/tsig/gss" "github.com/miekg/dns" - "github.com/pkg/errors" log "github.com/sirupsen/logrus" "sigs.k8s.io/external-dns/endpoint" @@ -116,7 +116,7 @@ type rfc2136Actions interface { func NewRfc2136Provider(hosts []string, port int, zoneNames []string, insecure bool, keyName string, secret string, secretAlg string, axfr bool, domainFilter endpoint.DomainFilter, dryRun bool, minTTL time.Duration, createPTR bool, gssTsig bool, krb5Username string, krb5Password string, krb5Realm string, batchChangeSize int, tlsConfig TLSConfig, loadBalancingStrategy string, actions rfc2136Actions) (provider.Provider, error) { secretAlgChecked, ok := tsigAlgs[secretAlg] if !ok && !insecure && !gssTsig { - return nil, errors.Errorf("%s is not supported TSIG algorithm", secretAlg) + return nil, fmt.Errorf("%s is not supported TSIG algorithm", secretAlg) } // Set zone to root if no set @@ -307,7 +307,7 @@ func (r *rfc2136Provider) List() ([]dns.RR, error) { for e := range env { if e.Error != nil { - if e.Error == dns.ErrSoa { + if errors.Is(e.Error, dns.ErrSoa) { log.Error("AXFR error: unexpected response received from the server") } else { log.Errorf("AXFR error: %v", e.Error) @@ -342,8 +342,6 @@ func (r *rfc2136Provider) RemoveReverseRecord(ip string, hostname string) error } func (r *rfc2136Provider) GenerateReverseRecord(ip string, hostname string) []*endpoint.Endpoint { - // Find the zone for the PTR record - // zone := findMsgZone(&endpoint.Endpoint{DNSName: ip}, p.ptrZoneNames) // Generate PTR notation record starting from the IP address var records []*endpoint.Endpoint @@ -364,7 +362,7 @@ func (r *rfc2136Provider) GenerateReverseRecord(ip string, hostname string) []*e func (r *rfc2136Provider) ApplyChanges(ctx context.Context, changes *plan.Changes) error { log.Debugf("ApplyChanges (Create: %d, UpdateOld: %d, UpdateNew: %d, Delete: %d)", len(changes.Create), len(changes.UpdateOld), len(changes.UpdateNew), len(changes.Delete)) - var errors []error + var errs []error for c, chunk := range chunkBy(changes.Create, r.batchChangeSize) { log.Debugf("Processing batch %d of create changes", c) @@ -397,7 +395,7 @@ func (r *rfc2136Provider) ApplyChanges(ctx context.Context, changes *plan.Change if len(z.Ns) > 0 { if err := r.actions.SendMessage(z); err != nil { log.Errorf("RFC2136 create record failed: %v", err) - errors = append(errors, err) + errs = append(errs, err) continue } } @@ -436,7 +434,7 @@ func (r *rfc2136Provider) ApplyChanges(ctx context.Context, changes *plan.Change if len(z.Ns) > 0 { if err := r.actions.SendMessage(z); err != nil { log.Errorf("RFC2136 update record failed: %v", err) - errors = append(errors, err) + errs = append(errs, err) continue } } @@ -473,15 +471,15 @@ func (r *rfc2136Provider) ApplyChanges(ctx context.Context, changes *plan.Change if len(z.Ns) > 0 { if err := r.actions.SendMessage(z); err != nil { log.Errorf("RFC2136 delete record failed: %v", err) - errors = append(errors, err) + errs = append(errs, err) continue } } } } - if len(errors) > 0 { - return fmt.Errorf("RFC2136 had errors in one or more of its batches: %v", errors) + if len(errs) > 0 { + return fmt.Errorf("RFC2136 had errors in one or more of its batches: %v", errs) } return nil diff --git a/provider/scaleway/scaleway.go b/provider/scaleway/scaleway.go index 87663e285..6ffe8acdc 100644 --- a/provider/scaleway/scaleway.go +++ b/provider/scaleway/scaleway.go @@ -34,7 +34,7 @@ import ( ) const ( - scalewyRecordTTL uint32 = 300 + defaultTTL uint32 = 300 scalewayDefaultPriority uint32 = 0 scalewayPriorityKey string = "scw/priority" ) @@ -110,7 +110,7 @@ func (p *ScalewayProvider) AdjustEndpoints(endpoints []*endpoint.Endpoint) ([]*e for i := range endpoints { eps[i] = endpoints[i] if !eps[i].RecordTTL.IsConfigured() { - eps[i].RecordTTL = endpoint.TTL(scalewyRecordTTL) + eps[i].RecordTTL = endpoint.TTL(defaultTTL) } if _, ok := eps[i].GetProviderSpecificProperty(scalewayPriorityKey); !ok { eps[i] = eps[i].WithProviderSpecific(scalewayPriorityKey, fmt.Sprintf("%d", scalewayDefaultPriority)) @@ -300,7 +300,7 @@ func getCompleteZoneName(zone *domain.DNSZone) string { func endpointToScalewayRecords(zoneName string, ep *endpoint.Endpoint) []*domain.Record { // no annotation results in a TTL of 0, default to 300 for consistency with other providers - ttl := scalewyRecordTTL + ttl := defaultTTL if ep.RecordTTL.IsConfigured() { ttl = uint32(ep.RecordTTL) } diff --git a/provider/transip/transip.go b/provider/transip/transip.go index af8992383..ea392d117 100644 --- a/provider/transip/transip.go +++ b/provider/transip/transip.go @@ -34,7 +34,7 @@ import ( const ( // 60 seconds is the current minimal TTL for TransIP and will replace unconfigured // TTL's for Endpoints - transipMinimalValidTTL = 60 + defaultTTL = 60 ) // TransIPProvider is an implementation of Provider for TransIP. @@ -336,11 +336,11 @@ func recordNameForEndpoint(ep *endpoint.Endpoint, zoneName string) string { } // getMinimalValidTTL returns max between given Endpoint's RecordTTL and -// transipMinimalValidTTL +// defaultTTL func getMinimalValidTTL(ep *endpoint.Endpoint) int { - // TTL cannot be lower than transipMinimalValidTTL - if ep.RecordTTL < transipMinimalValidTTL { - return transipMinimalValidTTL + // TTL cannot be lower than defaultTTL + if ep.RecordTTL < defaultTTL { + return defaultTTL } return int(ep.RecordTTL) diff --git a/provider/transip/transip_test.go b/provider/transip/transip_test.go index 31d13cb4a..76e4189d8 100644 --- a/provider/transip/transip_test.go +++ b/provider/transip/transip_test.go @@ -94,15 +94,15 @@ func TestTransIPDnsEntriesAreEqual(t *testing.T) { func TestTransIPGetMinimalValidTTL(t *testing.T) { // test with 'unconfigured' TTL ep := &endpoint.Endpoint{} - assert.EqualValues(t, transipMinimalValidTTL, getMinimalValidTTL(ep)) + assert.EqualValues(t, defaultTTL, getMinimalValidTTL(ep)) // test with lower than minimal ttl - ep.RecordTTL = (transipMinimalValidTTL - 1) - assert.EqualValues(t, transipMinimalValidTTL, getMinimalValidTTL(ep)) + ep.RecordTTL = (defaultTTL - 1) + assert.EqualValues(t, defaultTTL, getMinimalValidTTL(ep)) // test with higher than minimal ttl - ep.RecordTTL = (transipMinimalValidTTL + 1) - assert.EqualValues(t, transipMinimalValidTTL+1, getMinimalValidTTL(ep)) + ep.RecordTTL = (defaultTTL + 1) + assert.EqualValues(t, defaultTTL+1, getMinimalValidTTL(ep)) } func TestTransIPRecordNameForEndpoint(t *testing.T) { From 72a761c22be0a460aacd5c463cbdce4383b68605 Mon Sep 17 00:00:00 2001 From: ivan katliarchuk Date: Mon, 28 Apr 2025 10:31:56 +0100 Subject: [PATCH 17/42] chore(code-quality): webhook increase code coverage --- provider/webhook/api/httpapi.go | 7 +- provider/webhook/api/httpapi_test.go | 16 +- provider/webhook/webhook.go | 23 +-- provider/webhook/webhook_test.go | 234 ++++++++++++++++++++++++++- 4 files changed, 256 insertions(+), 24 deletions(-) diff --git a/provider/webhook/api/httpapi.go b/provider/webhook/api/httpapi.go index 717fee7f3..2dbb3a19b 100644 --- a/provider/webhook/api/httpapi.go +++ b/provider/webhook/api/httpapi.go @@ -33,6 +33,9 @@ import ( const ( MediaTypeFormatAndVersion = "application/external.dns.webhook+json;version=1" ContentTypeHeader = "Content-Type" + UrlAdjustEndpoints = "/adjustendpoints" + UrlApplyChanges = "/applychanges" + UrlRecords = "/records" ) type WebhookServer struct { @@ -121,8 +124,8 @@ func StartHTTPApi(provider provider.Provider, startedChan chan struct{}, readTim m := http.NewServeMux() m.HandleFunc("/", p.NegotiateHandler) - m.HandleFunc("/records", p.RecordsHandler) - m.HandleFunc("/adjustendpoints", p.AdjustEndpointsHandler) + m.HandleFunc(UrlRecords, p.RecordsHandler) + m.HandleFunc(UrlAdjustEndpoints, p.AdjustEndpointsHandler) s := &http.Server{ Addr: providerPort, diff --git a/provider/webhook/api/httpapi_test.go b/provider/webhook/api/httpapi_test.go index a15efec47..1fa51f46f 100644 --- a/provider/webhook/api/httpapi_test.go +++ b/provider/webhook/api/httpapi_test.go @@ -77,7 +77,7 @@ func TestMain(m *testing.M) { } func TestRecordsHandlerRecords(t *testing.T) { - req := httptest.NewRequest(http.MethodGet, "/records", nil) + req := httptest.NewRequest(http.MethodGet, UrlRecords, nil) w := httptest.NewRecorder() providerAPIServer := &WebhookServer{ @@ -99,7 +99,7 @@ func TestRecordsHandlerRecords(t *testing.T) { } func TestRecordsHandlerRecordsWithErrors(t *testing.T) { - req := httptest.NewRequest(http.MethodGet, "/records", nil) + req := httptest.NewRequest(http.MethodGet, UrlRecords, nil) w := httptest.NewRecorder() providerAPIServer := &WebhookServer{ @@ -139,7 +139,7 @@ func TestRecordsHandlerApplyChangesWithValidRequest(t *testing.T) { reader := bytes.NewReader(j) - req := httptest.NewRequest(http.MethodPost, "/applychanges", reader) + req := httptest.NewRequest(http.MethodPost, UrlApplyChanges, reader) w := httptest.NewRecorder() providerAPIServer := &WebhookServer{ @@ -165,7 +165,7 @@ func TestRecordsHandlerApplyChangesWithErrors(t *testing.T) { reader := bytes.NewReader(j) - req := httptest.NewRequest(http.MethodPost, "/applychanges", reader) + req := httptest.NewRequest(http.MethodPost, UrlApplyChanges, reader) w := httptest.NewRecorder() providerAPIServer := &WebhookServer{ @@ -191,7 +191,7 @@ func TestRecordsHandlerWithWrongHTTPMethod(t *testing.T) { } func TestAdjustEndpointsHandlerWithInvalidRequest(t *testing.T) { - req := httptest.NewRequest(http.MethodPost, "/adjustendpoints", nil) + req := httptest.NewRequest(http.MethodPost, UrlAdjustEndpoints, nil) w := httptest.NewRecorder() providerAPIServer := &WebhookServer{ @@ -201,7 +201,7 @@ func TestAdjustEndpointsHandlerWithInvalidRequest(t *testing.T) { res := w.Result() require.Equal(t, http.StatusBadRequest, res.StatusCode) - req = httptest.NewRequest(http.MethodGet, "/adjustendpoints", nil) + req = httptest.NewRequest(http.MethodGet, UrlAdjustEndpoints, nil) providerAPIServer.AdjustEndpointsHandler(w, req) res = w.Result() @@ -222,7 +222,7 @@ func TestAdjustEndpointsHandlerWithValidRequest(t *testing.T) { require.NoError(t, err) reader := bytes.NewReader(j) - req := httptest.NewRequest(http.MethodPost, "/adjustendpoints", reader) + req := httptest.NewRequest(http.MethodPost, UrlAdjustEndpoints, reader) w := httptest.NewRecorder() providerAPIServer := &WebhookServer{ @@ -248,7 +248,7 @@ func TestAdjustEndpointsHandlerWithError(t *testing.T) { require.NoError(t, err) reader := bytes.NewReader(j) - req := httptest.NewRequest(http.MethodPost, "/adjustendpoints", reader) + req := httptest.NewRequest(http.MethodPost, UrlAdjustEndpoints, reader) w := httptest.NewRecorder() providerAPIServer := &WebhookServer{ diff --git a/provider/webhook/webhook.go b/provider/webhook/webhook.go index 1a1558d4e..21d2695cb 100644 --- a/provider/webhook/webhook.go +++ b/provider/webhook/webhook.go @@ -113,7 +113,7 @@ func NewWebhookProvider(u string) (*WebhookProvider, error) { } // negotiate API information - req, err := http.NewRequest("GET", u, nil) + req, err := http.NewRequest(http.MethodGet, u, nil) if err != nil { return nil, err } @@ -128,8 +128,8 @@ func NewWebhookProvider(u string) (*WebhookProvider, error) { return err } // we currently only use 200 as success, but considering okay all 2XX for future usage - if resp.StatusCode >= 300 && resp.StatusCode < 500 { - return backoff.Permanent(fmt.Errorf("status code < 500")) + if resp.StatusCode >= http.StatusMultipleChoices && resp.StatusCode < http.StatusInternalServerError { + return backoff.Permanent(fmt.Errorf("status code < %d", http.StatusInternalServerError)) } return nil }, backoff.WithMaxRetries(backoff.NewExponentialBackOff(), maxRetries)) @@ -164,7 +164,7 @@ func (p WebhookProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, err recordsRequestsGauge.Gauge.Inc() u := p.remoteServerURL.JoinPath("records").String() - req, err := http.NewRequest("GET", u, nil) + req, err := http.NewRequest(http.MethodGet, u, nil) if err != nil { recordsErrorsGauge.Gauge.Inc() log.Debugf("Failed to create request: %s", err.Error()) @@ -189,7 +189,7 @@ func (p WebhookProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, err return nil, err } - endpoints := []*endpoint.Endpoint{} + var endpoints []*endpoint.Endpoint if err := json.NewDecoder(resp.Body).Decode(&endpoints); err != nil { recordsErrorsGauge.Gauge.Inc() log.Debugf("Failed to decode response body: %s", err.Error()) @@ -201,7 +201,7 @@ func (p WebhookProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, err // ApplyChanges will make a POST to remoteServerURL/records with the changes func (p WebhookProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error { applyChangesRequestsGauge.Gauge.Inc() - u := p.remoteServerURL.JoinPath("records").String() + u := p.remoteServerURL.JoinPath(webhookapi.UrlRecords).String() b := new(bytes.Buffer) if err := json.NewEncoder(b).Encode(changes); err != nil { @@ -210,7 +210,7 @@ func (p WebhookProvider) ApplyChanges(ctx context.Context, changes *plan.Changes return err } - req, err := http.NewRequest("POST", u, b) + req, err := http.NewRequest(http.MethodPost, u, b) if err != nil { applyChangesErrorsGauge.Gauge.Inc() log.Debugf("Failed to create request: %s", err.Error()) @@ -225,6 +225,7 @@ func (p WebhookProvider) ApplyChanges(ctx context.Context, changes *plan.Changes log.Debugf("Failed to perform request: %s", err.Error()) return err } + defer resp.Body.Close() if resp.StatusCode != http.StatusNoContent { @@ -240,12 +241,12 @@ func (p WebhookProvider) ApplyChanges(ctx context.Context, changes *plan.Changes } // AdjustEndpoints will call the provider doing a POST on `/adjustendpoints` which will return a list of modified endpoints -// based on a provider specific requirement. +// based on a provider-specific requirement. // This method returns an empty slice in case there is a technical error on the provider's side so that no endpoints will be considered. func (p WebhookProvider) AdjustEndpoints(e []*endpoint.Endpoint) ([]*endpoint.Endpoint, error) { adjustEndpointsRequestsGauge.Gauge.Inc() - endpoints := []*endpoint.Endpoint{} - u, err := url.JoinPath(p.remoteServerURL.String(), "adjustendpoints") + var endpoints []*endpoint.Endpoint + u, err := url.JoinPath(p.remoteServerURL.String(), webhookapi.UrlAdjustEndpoints) if err != nil { adjustEndpointsErrorsGauge.Gauge.Inc() log.Debugf("Failed to join path, %s", err) @@ -259,7 +260,7 @@ func (p WebhookProvider) AdjustEndpoints(e []*endpoint.Endpoint) ([]*endpoint.En return nil, err } - req, err := http.NewRequest("POST", u, b) + req, err := http.NewRequest(http.MethodPost, u, b) if err != nil { adjustEndpointsErrorsGauge.Gauge.Inc() log.Debugf("Failed to create new HTTP request, %s", err) diff --git a/provider/webhook/webhook_test.go b/provider/webhook/webhook_test.go index 999cdc3bf..d0f25f9c8 100644 --- a/provider/webhook/webhook_test.go +++ b/provider/webhook/webhook_test.go @@ -22,8 +22,10 @@ import ( "io" "net/http" "net/http/httptest" + "net/url" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "sigs.k8s.io/external-dns/endpoint" "sigs.k8s.io/external-dns/plan" @@ -31,6 +33,55 @@ import ( webhookapi "sigs.k8s.io/external-dns/provider/webhook/api" ) +func TestNewWebhookProvider_InvalidURL(t *testing.T) { + _, err := NewWebhookProvider("://invalid-url") + require.Error(t, err) +} + +func TestNewWebhookProvider_HTTPRequestFailure(t *testing.T) { + _, err := NewWebhookProvider("http://nonexistent.url") + require.Error(t, err) +} + +func TestNewWebhookProvider_InvalidResponseBody(t *testing.T) { + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set(webhookapi.ContentTypeHeader, webhookapi.MediaTypeFormatAndVersion) + w.WriteHeader(http.StatusOK) + w.Write([]byte("invalid-json")) // Invalid JSON + })) + defer svr.Close() + + _, err := NewWebhookProvider(svr.URL) + require.Error(t, err) + require.Contains(t, err.Error(), "failed to unmarshal response body of DomainFilter") +} + +func TestNewWebhookProvider_Non2XXStatusCode(t *testing.T) { + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusBadRequest) + })) + defer svr.Close() + + _, err := NewWebhookProvider(svr.URL) + require.Error(t, err) + require.Contains(t, err.Error(), "status code < 500") +} + +func TestNewWebhookProvider_WrongContentTypeHeader(t *testing.T) { + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/" { + w.Header().Set(webhookapi.ContentTypeHeader, webhookapi.MediaTypeFormatAndVersion+"wrong") + _, _ = w.Write([]byte(`{}`)) + return + } + })) + defer svr.Close() + + _, err := NewWebhookProvider(svr.URL) + require.Error(t, err) + require.Contains(t, err.Error(), "wrong content type returned from server") +} + func TestInvalidDomainFilter(t *testing.T) { svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/" { @@ -108,6 +159,68 @@ func TestRecordsWithErrors(t *testing.T) { require.ErrorIs(t, err, provider.SoftError) } +func TestRecords_HTTPRequestErrorMissingHost0(t *testing.T) { + wpr := WebhookProvider{ + remoteServerURL: &url.URL{Scheme: "http", Host: "example\\x00.com", Path: "\\x00"}, + client: &http.Client{}, + } + + _, err := wpr.Records(nil) + require.Error(t, err) + require.Contains(t, err.Error(), "invalid URL escape") +} + +func TestRecords_HTTPRequestErrorMissingHost(t *testing.T) { + wpr := WebhookProvider{ + remoteServerURL: &url.URL{Host: "example.com", Path: "\\x00"}, + client: &http.Client{}, + } + + _, err := wpr.Records(nil) + require.Error(t, err) + require.Contains(t, err.Error(), "unsupported protocol scheme") +} + +func TestRecords_DecodeError(t *testing.T) { + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == webhookapi.UrlRecords { + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte("invalid-json")) // Simulate invalid JSON response + return + } + })) + defer svr.Close() + + parsedURL, _ := url.Parse(svr.URL) + p := WebhookProvider{ + remoteServerURL: parsedURL, + client: &http.Client{}, + } + + _, err := p.Records(context.Background()) + require.Error(t, err) + require.Contains(t, err.Error(), "invalid character 'i' looking for beginning of value") +} + +func TestRecords_NonOKStatusCode(t *testing.T) { + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNetworkAuthenticationRequired) + return + })) + defer svr.Close() + + parsedURL, _ := url.Parse(svr.URL) + + p := WebhookProvider{ + remoteServerURL: &url.URL{Scheme: parsedURL.Scheme, Host: parsedURL.Host}, + client: &http.Client{}, + } + + _, err := p.Records(nil) + require.Error(t, err) + assert.Contains(t, err.Error(), "failed to get records with code 511") +} + func TestApplyChanges(t *testing.T) { successfulApplyChanges := true svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -137,6 +250,49 @@ func TestApplyChanges(t *testing.T) { require.ErrorIs(t, err, provider.SoftError) } +func TestApplyChanges_HTTPNewRequestErrorWrongHost(t *testing.T) { + wpr := WebhookProvider{ + remoteServerURL: &url.URL{Host: "exa\\x00mple.com"}, + client: &http.Client{}, + } + + err := wpr.ApplyChanges(context.Background(), nil) + require.Error(t, err) + require.Contains(t, err.Error(), "invalid URL escape") +} + +func TestApplyChanges_GetFailed(t *testing.T) { + p := WebhookProvider{ + remoteServerURL: &url.URL{Host: "localhost"}, + client: &http.Client{}, + } + + err := p.ApplyChanges(context.TODO(), &plan.Changes{}) + require.Error(t, err) + assert.Contains(t, err.Error(), "unsupported protocol scheme") +} + +func TestApplyChanges_StatusCodeError(t *testing.T) { + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/" { + w.Header().Set(webhookapi.ContentTypeHeader, webhookapi.MediaTypeFormatAndVersion) + w.Write([]byte(`{}`)) + return + } + require.Equal(t, webhookapi.UrlRecords, r.URL.Path) + w.WriteHeader(http.StatusNetworkAuthenticationRequired) + })) + defer svr.Close() + + p, err := NewWebhookProvider(svr.URL) + require.NoError(t, err) + + err = p.ApplyChanges(context.TODO(), nil) + require.NotNil(t, err) + require.NotErrorIs(t, err, provider.SoftError) + assert.Contains(t, err.Error(), "failed to apply changes with code 511") +} + func TestAdjustEndpoints(t *testing.T) { svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/" { @@ -144,7 +300,7 @@ func TestAdjustEndpoints(t *testing.T) { w.Write([]byte(`{}`)) return } - require.Equal(t, "/adjustendpoints", r.URL.Path) + require.Equal(t, webhookapi.UrlAdjustEndpoints, r.URL.Path) var endpoints []*endpoint.Endpoint defer r.Body.Close() @@ -162,7 +318,6 @@ func TestAdjustEndpoints(t *testing.T) { } j, _ := json.Marshal(endpoints) w.Write(j) - })) defer svr.Close() @@ -197,7 +352,7 @@ func TestAdjustendpointsWithError(t *testing.T) { w.Write([]byte(`{}`)) return } - require.Equal(t, "/adjustendpoints", r.URL.Path) + require.Equal(t, webhookapi.UrlAdjustEndpoints, r.URL.Path) w.WriteHeader(http.StatusInternalServerError) })) defer svr.Close() @@ -269,3 +424,76 @@ func TestApplyChangesWithProviderSpecificProperty(t *testing.T) { }) require.NoError(t, err) } + +func TestAdjustEndpoints_JoinPathError(t *testing.T) { + wpr := WebhookProvider{ + remoteServerURL: &url.URL{Scheme: "http", Host: "example\\x00.com"}, + } + + _, err := wpr.AdjustEndpoints(nil) + require.Error(t, err) + require.Contains(t, err.Error(), "invalid URL escape") +} + +func TestAdjustEndpoints_HTTPRequestErrorMissingHost(t *testing.T) { + wpr := WebhookProvider{ + remoteServerURL: &url.URL{Host: "example.com", Path: "\\x00"}, + client: &http.Client{}, + } + + _, err := wpr.AdjustEndpoints(nil) + require.Error(t, err) + require.Contains(t, err.Error(), "unsupported protocol scheme") // Ensure the "BINGO" log is triggered +} + +func TestAdjustEndpoints_NonOKStatusCode(t *testing.T) { + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNetworkAuthenticationRequired) + return + })) + defer svr.Close() + + parsedURL, _ := url.Parse(svr.URL) + + p := WebhookProvider{ + remoteServerURL: &url.URL{Scheme: parsedURL.Scheme, Host: parsedURL.Host}, + client: &http.Client{}, + } + + endpoints := []*endpoint.Endpoint{ + { + DNSName: "test.example.com", + RecordTTL: 10, + RecordType: "A", + Targets: endpoint.Targets{""}, + }, + } + + _, err := p.AdjustEndpoints(endpoints) + require.Error(t, err) + assert.Contains(t, err.Error(), "failed to AdjustEndpoints with code 511") +} + +func TestAdjustEndpoints_DecodeError(t *testing.T) { + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == webhookapi.UrlAdjustEndpoints { + w.Header().Set(webhookapi.ContentTypeHeader, webhookapi.MediaTypeFormatAndVersion) + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte("invalid-json")) // Simulate invalid JSON response + return + } + })) + defer svr.Close() + + parsedURL, _ := url.Parse(svr.URL) + p := WebhookProvider{ + remoteServerURL: parsedURL, + client: &http.Client{}, + } + + var endpoints []*endpoint.Endpoint + + _, err := p.AdjustEndpoints(endpoints) + require.Error(t, err) + require.Contains(t, err.Error(), "invalid character 'i' looking for beginning of value") +} From ba64e8bb01bd4dd9049ffb727bed8343f409e8cf Mon Sep 17 00:00:00 2001 From: Ivan Ka <5395690+ivankatliarchuk@users.noreply.github.com> Date: Tue, 29 Apr 2025 09:17:57 +0100 Subject: [PATCH 18/42] chore(deps): code cleanup, do not use pkg/errors (#5335) Signed-off-by: ivan katliarchuk --- Makefile | 4 ++++ go.mod | 2 +- provider/oci/oci.go | 2 +- provider/oci/oci_test.go | 5 +++-- source/ambassador_host.go | 10 +++++----- source/contour_httpproxy.go | 12 ++++++------ source/contour_httpproxy_test.go | 2 +- source/f5_transportserver.go | 6 +++--- source/f5_virtualserver.go | 6 +++--- source/istio_gateway_test.go | 2 +- source/istio_virtualservice_test.go | 2 +- source/kong_tcpingress.go | 6 +++--- source/skipper_routegroup_test.go | 2 +- source/store.go | 5 +++-- source/traefik_proxy.go | 16 ++++++++-------- source/traefik_proxy_test.go | 3 ++- 16 files changed, 46 insertions(+), 39 deletions(-) diff --git a/Makefile b/Makefile index 8cff3cba3..74ee98737 100644 --- a/Makefile +++ b/Makefile @@ -201,3 +201,7 @@ helm-template: helm-lint: scripts/helm-tools.sh --schema scripts/helm-tools.sh --docs + +.PHONY: go-dependency +go-dependency: ## Dependency maintanance + go mod tidy diff --git a/go.mod b/go.mod index 0dc59e851..23bba3eff 100644 --- a/go.mod +++ b/go.mod @@ -50,7 +50,6 @@ require ( github.com/oracle/oci-go-sdk/v65 v65.89.1 github.com/ovh/go-ovh v1.7.0 github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/pkg/errors v0.9.1 github.com/pluralsh/gqlclient v1.12.2 github.com/projectcontour/contour v1.30.3 github.com/prometheus/client_golang v1.22.0 @@ -170,6 +169,7 @@ require ( github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect github.com/peterhellberg/link v1.1.0 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.62.0 // indirect diff --git a/provider/oci/oci.go b/provider/oci/oci.go index af6fbd518..4fd4c1040 100644 --- a/provider/oci/oci.go +++ b/provider/oci/oci.go @@ -18,6 +18,7 @@ package oci import ( "context" + "errors" "fmt" "os" "strings" @@ -27,7 +28,6 @@ import ( "github.com/oracle/oci-go-sdk/v65/common" "github.com/oracle/oci-go-sdk/v65/common/auth" "github.com/oracle/oci-go-sdk/v65/dns" - "github.com/pkg/errors" log "github.com/sirupsen/logrus" "sigs.k8s.io/external-dns/endpoint" diff --git a/provider/oci/oci_test.go b/provider/oci/oci_test.go index dce6b7386..427f713d1 100644 --- a/provider/oci/oci_test.go +++ b/provider/oci/oci_test.go @@ -18,6 +18,8 @@ package oci import ( "context" + "errors" + "fmt" "sort" "strings" "testing" @@ -25,7 +27,6 @@ import ( "github.com/oracle/oci-go-sdk/v65/common" "github.com/oracle/oci-go-sdk/v65/dns" - "github.com/pkg/errors" "github.com/stretchr/testify/require" "sigs.k8s.io/external-dns/endpoint" @@ -621,7 +622,7 @@ func (c *mutableMockOCIDNSClient) PatchZoneRecords(ctx context.Context, request case dns.RecordOperationOperationRemove: delete(records, k) default: - err = errors.Errorf("unsupported operation %q", op.Operation) + err = fmt.Errorf("unsupported operation %q", op.Operation) return } } diff --git a/source/ambassador_host.go b/source/ambassador_host.go index cb0501210..0ddc89118 100644 --- a/source/ambassador_host.go +++ b/source/ambassador_host.go @@ -18,12 +18,12 @@ package source import ( "context" + "errors" "fmt" "sort" "strings" ambassador "github.com/datawire/ambassador/pkg/api/getambassador.io/v2" - "github.com/pkg/errors" log "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -96,7 +96,7 @@ func NewAmbassadorHostSource( uc, err := newUnstructuredConverter() if err != nil { - return nil, errors.Wrapf(err, "failed to setup Unstructured Converter") + return nil, fmt.Errorf("failed to setup Unstructured Converter: %w", err) } return &ambassadorHostSource{ @@ -137,10 +137,10 @@ func (sc *ambassadorHostSource) Endpoints(ctx context.Context) ([]*endpoint.Endp // Filter Ambassador Hosts ambassadorHosts, err = sc.filterByAnnotations(ambassadorHosts) if err != nil { - return nil, errors.Wrap(err, "failed to filter Ambassador Hosts by annotation") + return nil, fmt.Errorf("failed to filter Ambassador Hosts by annotation: %w", err) } - endpoints := []*endpoint.Endpoint{} + var endpoints []*endpoint.Endpoint for _, host := range ambassadorHosts { fullname := fmt.Sprintf("%s/%s", host.Namespace, host.Name) @@ -260,7 +260,7 @@ func parseAmbLoadBalancerService(service string) (namespace, name string, err er } // If we got here, this string is simply ill-formatted. Return an error. - return "", "", errors.New(fmt.Sprintf("invalid external-dns service: %s", service)) + return "", "", fmt.Errorf("invalid external-dns service: %s", service) } func (sc *ambassadorHostSource) AddEventHandler(ctx context.Context, handler func()) { diff --git a/source/contour_httpproxy.go b/source/contour_httpproxy.go index fb028dc64..823b91e33 100644 --- a/source/contour_httpproxy.go +++ b/source/contour_httpproxy.go @@ -18,11 +18,11 @@ package source import ( "context" + "errors" "fmt" "sort" "text/template" - "github.com/pkg/errors" projectcontour "github.com/projectcontour/contour/apis/projectcontour/v1" log "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -87,7 +87,7 @@ func NewContourHTTPProxySource( uc, err := NewUnstructuredConverter() if err != nil { - return nil, errors.Wrap(err, "failed to setup Unstructured Converter") + return nil, fmt.Errorf("failed to setup Unstructured Converter: %w", err) } return &httpProxySource{ @@ -121,14 +121,14 @@ func (sc *httpProxySource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, hpConverted := &projectcontour.HTTPProxy{} err := sc.unstructuredConverter.scheme.Convert(unstructuredHP, hpConverted, nil) if err != nil { - return nil, errors.Wrap(err, "failed to convert to HTTPProxy") + return nil, fmt.Errorf("failed to convert to HTTPProxy: %w", err) } httpProxies = append(httpProxies, hpConverted) } httpProxies, err = sc.filterByAnnotations(httpProxies) if err != nil { - return nil, errors.Wrap(err, "failed to filter HTTPProxies") + return nil, fmt.Errorf("failed to filter HTTPProxies: %w", err) } endpoints := []*endpoint.Endpoint{} @@ -144,14 +144,14 @@ func (sc *httpProxySource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, hpEndpoints, err := sc.endpointsFromHTTPProxy(hp) if err != nil { - return nil, errors.Wrap(err, "failed to get endpoints from HTTPProxy") + return nil, fmt.Errorf("failed to get endpoints from HTTPProxy: %w", err) } // apply template if fqdn is missing on HTTPProxy if (sc.combineFQDNAnnotation || len(hpEndpoints) == 0) && sc.fqdnTemplate != nil { tmplEndpoints, err := sc.endpointsFromTemplate(hp) if err != nil { - return nil, errors.Wrap(err, "failed to get endpoints from template") + return nil, fmt.Errorf("failed to get endpoints from template: %w", err) } if sc.combineFQDNAnnotation { diff --git a/source/contour_httpproxy_test.go b/source/contour_httpproxy_test.go index 895adeaa0..f26afdcda 100644 --- a/source/contour_httpproxy_test.go +++ b/source/contour_httpproxy_test.go @@ -18,11 +18,11 @@ package source import ( "context" + "errors" "testing" fakeDynamic "k8s.io/client-go/dynamic/fake" - "github.com/pkg/errors" projectcontour "github.com/projectcontour/contour/apis/projectcontour/v1" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/source/f5_transportserver.go b/source/f5_transportserver.go index 1c4a7cc85..d3042a58e 100644 --- a/source/f5_transportserver.go +++ b/source/f5_transportserver.go @@ -18,10 +18,10 @@ package source import ( "context" + "errors" "fmt" "strings" - "github.com/pkg/errors" log "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -82,7 +82,7 @@ func NewF5TransportServerSource( uc, err := newTSUnstructuredConverter() if err != nil { - return nil, errors.Wrapf(err, "failed to setup unstructured converter") + return nil, fmt.Errorf("failed to setup unstructured converter: %w", err) } return &f5TransportServerSource{ @@ -120,7 +120,7 @@ func (ts *f5TransportServerSource) Endpoints(ctx context.Context) ([]*endpoint.E transportServers, err = ts.filterByAnnotations(transportServers) if err != nil { - return nil, errors.Wrap(err, "failed to filter TransportServers") + return nil, fmt.Errorf("failed to filter TransportServers: %w", err) } endpoints, err := ts.endpointsFromTransportServers(transportServers) diff --git a/source/f5_virtualserver.go b/source/f5_virtualserver.go index f4ada2f85..85b1538fe 100644 --- a/source/f5_virtualserver.go +++ b/source/f5_virtualserver.go @@ -18,11 +18,11 @@ package source import ( "context" + "errors" "fmt" "sort" "strings" - "github.com/pkg/errors" log "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -83,7 +83,7 @@ func NewF5VirtualServerSource( uc, err := newVSUnstructuredConverter() if err != nil { - return nil, errors.Wrapf(err, "failed to setup unstructured converter") + return nil, fmt.Errorf("failed to setup unstructured converter: %w", err) } return &f5VirtualServerSource{ @@ -121,7 +121,7 @@ func (vs *f5VirtualServerSource) Endpoints(ctx context.Context) ([]*endpoint.End virtualServers, err = vs.filterByAnnotations(virtualServers) if err != nil { - return nil, errors.Wrap(err, "failed to filter VirtualServers") + return nil, fmt.Errorf("failed to filter VirtualServers: %w", err) } endpoints, err := vs.endpointsFromVirtualServers(virtualServers) diff --git a/source/istio_gateway_test.go b/source/istio_gateway_test.go index 9c74d7a7f..43120ff3d 100644 --- a/source/istio_gateway_test.go +++ b/source/istio_gateway_test.go @@ -18,9 +18,9 @@ package source import ( "context" + "errors" "testing" - "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" diff --git a/source/istio_virtualservice_test.go b/source/istio_virtualservice_test.go index c56dce704..324827814 100644 --- a/source/istio_virtualservice_test.go +++ b/source/istio_virtualservice_test.go @@ -18,10 +18,10 @@ package source import ( "context" + "errors" "fmt" "testing" - "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" diff --git a/source/kong_tcpingress.go b/source/kong_tcpingress.go index 7d81832be..bca023dbe 100644 --- a/source/kong_tcpingress.go +++ b/source/kong_tcpingress.go @@ -18,10 +18,10 @@ package source import ( "context" + "errors" "fmt" "sort" - "github.com/pkg/errors" log "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -82,7 +82,7 @@ func NewKongTCPIngressSource(ctx context.Context, dynamicKubeClient dynamic.Inte uc, err := newKongUnstructuredConverter() if err != nil { - return nil, errors.Wrapf(err, "failed to setup Unstructured Converter") + return nil, fmt.Errorf("failed to setup Unstructured Converter: %w", err) } return &kongTCPIngressSource{ @@ -121,7 +121,7 @@ func (sc *kongTCPIngressSource) Endpoints(ctx context.Context) ([]*endpoint.Endp tcpIngresses, err = sc.filterByAnnotations(tcpIngresses) if err != nil { - return nil, errors.Wrap(err, "failed to filter TCPIngresses") + return nil, fmt.Errorf("failed to filter TCPIngresses: %w", err) } var endpoints []*endpoint.Endpoint diff --git a/source/skipper_routegroup_test.go b/source/skipper_routegroup_test.go index 68f70bc48..03650b3a0 100644 --- a/source/skipper_routegroup_test.go +++ b/source/skipper_routegroup_test.go @@ -18,9 +18,9 @@ package source import ( "context" + "errors" "testing" - "github.com/pkg/errors" "github.com/stretchr/testify/assert" "sigs.k8s.io/external-dns/endpoint" ) diff --git a/source/store.go b/source/store.go index 7970634c9..8a9149ba5 100644 --- a/source/store.go +++ b/source/store.go @@ -18,6 +18,8 @@ package source import ( "context" + "errors" + "fmt" "net/http" "os" "strings" @@ -27,7 +29,6 @@ import ( "github.com/cloudfoundry-community/go-cfclient" "github.com/linki/instrumented_http" openshift "github.com/openshift/client-go/route/clientset/versioned" - "github.com/pkg/errors" log "github.com/sirupsen/logrus" istioclient "istio.io/client-go/pkg/clientset/versioned" "k8s.io/apimachinery/pkg/labels" @@ -509,7 +510,7 @@ func NewIstioClient(kubeConfig string, apiServerURL string) (*istioclient.Client ic, err := istioclient.NewForConfig(restCfg) if err != nil { - return nil, errors.Wrap(err, "Failed to create istio client") + return nil, fmt.Errorf("failed to create istio client: %w", err) } return ic, nil diff --git a/source/traefik_proxy.go b/source/traefik_proxy.go index a63142ef8..3a07ac91b 100644 --- a/source/traefik_proxy.go +++ b/source/traefik_proxy.go @@ -18,12 +18,12 @@ package source import ( "context" + "errors" "fmt" "regexp" "sort" "strings" - "github.com/pkg/errors" log "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -151,7 +151,7 @@ func NewTraefikSource(ctx context.Context, dynamicKubeClient dynamic.Interface, uc, err := newTraefikUnstructuredConverter() if err != nil { - return nil, errors.Wrapf(err, "failed to setup Unstructured Converter") + return nil, fmt.Errorf("failed to setup Unstructured Converter: %w", err) } return &traefikSource{ @@ -249,7 +249,7 @@ func (ts *traefikSource) ingressRouteEndpoints() ([]*endpoint.Endpoint, error) { ingressRoutes, err = ts.filterIngressRouteByAnnotation(ingressRoutes) if err != nil { - return nil, errors.Wrap(err, "failed to filter IngressRoute") + return nil, fmt.Errorf("failed to filter IngressRoute: %w", err) } for _, ingressRoute := range ingressRoutes { @@ -301,7 +301,7 @@ func (ts *traefikSource) ingressRouteTCPEndpoints() ([]*endpoint.Endpoint, error ingressRouteTCPs, err = ts.filterIngressRouteTcpByAnnotations(ingressRouteTCPs) if err != nil { - return nil, errors.Wrap(err, "failed to filter IngressRouteTCP") + return nil, fmt.Errorf("failed to filter IngressRouteTCP: %w", err) } for _, ingressRouteTCP := range ingressRouteTCPs { @@ -353,7 +353,7 @@ func (ts *traefikSource) ingressRouteUDPEndpoints() ([]*endpoint.Endpoint, error ingressRouteUDPs, err = ts.filterIngressRouteUdpByAnnotations(ingressRouteUDPs) if err != nil { - return nil, errors.Wrap(err, "failed to filter IngressRouteUDP") + return nil, fmt.Errorf("failed to filter IngressRouteUDP: %w", err) } for _, ingressRouteUDP := range ingressRouteUDPs { @@ -405,7 +405,7 @@ func (ts *traefikSource) oldIngressRouteEndpoints() ([]*endpoint.Endpoint, error ingressRoutes, err = ts.filterIngressRouteByAnnotation(ingressRoutes) if err != nil { - return nil, errors.Wrap(err, "failed to filter IngressRoute") + return nil, fmt.Errorf("failed to filter IngressRoute: %w", err) } for _, ingressRoute := range ingressRoutes { @@ -457,7 +457,7 @@ func (ts *traefikSource) oldIngressRouteTCPEndpoints() ([]*endpoint.Endpoint, er ingressRouteTCPs, err = ts.filterIngressRouteTcpByAnnotations(ingressRouteTCPs) if err != nil { - return nil, errors.Wrap(err, "failed to filter IngressRouteTCP") + return nil, fmt.Errorf("failed to filter IngressRouteTCP: %w", err) } for _, ingressRouteTCP := range ingressRouteTCPs { @@ -509,7 +509,7 @@ func (ts *traefikSource) oldIngressRouteUDPEndpoints() ([]*endpoint.Endpoint, er ingressRouteUDPs, err = ts.filterIngressRouteUdpByAnnotations(ingressRouteUDPs) if err != nil { - return nil, errors.Wrap(err, "failed to filter IngressRouteUDP") + return nil, fmt.Errorf("failed to filter IngressRouteUDP: %w", err) } for _, ingressRouteUDP := range ingressRouteUDPs { diff --git a/source/traefik_proxy_test.go b/source/traefik_proxy_test.go index 730d833a8..88cefb51f 100644 --- a/source/traefik_proxy_test.go +++ b/source/traefik_proxy_test.go @@ -19,9 +19,10 @@ package source import ( "context" "encoding/json" - "k8s.io/apimachinery/pkg/runtime/schema" "testing" + "k8s.io/apimachinery/pkg/runtime/schema" + "github.com/stretchr/testify/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" From d587756d062c74af544aaa44696ad08d2b9275b5 Mon Sep 17 00:00:00 2001 From: Ivan Ka <5395690+ivankatliarchuk@users.noreply.github.com> Date: Wed, 30 Apr 2025 08:11:56 +0100 Subject: [PATCH 19/42] chore(webhook): bump cenkalti/backoff version (#5342) Co-authored-by: Kubernetes Prow Robot <20407524+k8s-ci-robot@users.noreply.github.com> Co-authored-by: Michel Loiseleur <97035654+mloiseleur@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 +-- provider/webhook/webhook.go | 43 ++++++++++++++++---------------- provider/webhook/webhook_test.go | 33 ++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 24 deletions(-) diff --git a/go.mod b/go.mod index 23bba3eff..147a71d32 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.35.4 github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 github.com/bodgit/tsig v1.2.2 - github.com/cenkalti/backoff/v4 v4.3.0 + github.com/cenkalti/backoff/v5 v5.0.2 github.com/civo/civogo v0.3.98 github.com/cloudflare/cloudflare-go v0.115.0 github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381 diff --git a/go.sum b/go.sum index 762a4b0f0..ffc50c0e1 100644 --- a/go.sum +++ b/go.sum @@ -179,8 +179,8 @@ github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0Bsq github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= -github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8= +github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= diff --git a/provider/webhook/webhook.go b/provider/webhook/webhook.go index 21d2695cb..4b7d020ce 100644 --- a/provider/webhook/webhook.go +++ b/provider/webhook/webhook.go @@ -30,7 +30,7 @@ import ( "sigs.k8s.io/external-dns/provider" webhookapi "sigs.k8s.io/external-dns/provider/webhook/api" - "github.com/cenkalti/backoff/v4" + "github.com/cenkalti/backoff/v5" "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" ) @@ -120,38 +120,23 @@ func NewWebhookProvider(u string) (*WebhookProvider, error) { req.Header.Set(acceptHeader, webhookapi.MediaTypeFormatAndVersion) client := &http.Client{} - var resp *http.Response - err = backoff.Retry(func() error { - resp, err = client.Do(req) - if err != nil { - log.Debugf("Failed to connect to webhook: %v", err) - return err - } - // we currently only use 200 as success, but considering okay all 2XX for future usage - if resp.StatusCode >= http.StatusMultipleChoices && resp.StatusCode < http.StatusInternalServerError { - return backoff.Permanent(fmt.Errorf("status code < %d", http.StatusInternalServerError)) - } - return nil - }, backoff.WithMaxRetries(backoff.NewExponentialBackOff(), maxRetries)) + resp, err := requestWithRetry(client, req) if err != nil { return nil, fmt.Errorf("failed to connect to webhook: %v", err) } - - contentType := resp.Header.Get(webhookapi.ContentTypeHeader) - // read the serialized DomainFilter from the response body and set it in the webhook provider struct defer resp.Body.Close() + if ct := resp.Header.Get(webhookapi.ContentTypeHeader); ct != webhookapi.MediaTypeFormatAndVersion { + return nil, fmt.Errorf("wrong content type returned from server: %s", ct) + } + df := endpoint.DomainFilter{} if err := json.NewDecoder(resp.Body).Decode(&df); err != nil { return nil, fmt.Errorf("failed to unmarshal response body of DomainFilter: %v", err) } - if contentType != webhookapi.MediaTypeFormatAndVersion { - return nil, fmt.Errorf("wrong content type returned from server: %s", contentType) - } - return &WebhookProvider{ client: client, remoteServerURL: parsedURL, @@ -159,6 +144,22 @@ func NewWebhookProvider(u string) (*WebhookProvider, error) { }, nil } +func requestWithRetry(client *http.Client, req *http.Request) (*http.Response, error) { + resp, err := backoff.Retry(context.Background(), func() (*http.Response, error) { + resp, err := client.Do(req) + if err != nil { + log.Debugf("Failed to connect to webhook: %v", err) + return nil, err + } + // we currently only use 200 as success, but considering okay all 2XX for future usage + if resp.StatusCode >= http.StatusMultipleChoices && resp.StatusCode < http.StatusInternalServerError { + return nil, backoff.Permanent(fmt.Errorf("status code < %d", http.StatusInternalServerError)) + } + return resp, nil + }, backoff.WithMaxTries(maxRetries)) + return resp, err +} + // Records will make a GET call to remoteServerURL/records and return the results func (p WebhookProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error) { recordsRequestsGauge.Gauge.Inc() diff --git a/provider/webhook/webhook_test.go b/provider/webhook/webhook_test.go index d0f25f9c8..f4a0ea390 100644 --- a/provider/webhook/webhook_test.go +++ b/provider/webhook/webhook_test.go @@ -24,6 +24,7 @@ import ( "net/http/httptest" "net/url" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -497,3 +498,35 @@ func TestAdjustEndpoints_DecodeError(t *testing.T) { require.Error(t, err) require.Contains(t, err.Error(), "invalid character 'i' looking for beginning of value") } + +func TestRequestWithRetry_Success(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + io.WriteString(w, "ok") + })) + defer server.Close() + + client := &http.Client{Timeout: 2 * time.Second} + req, err := http.NewRequest(http.MethodGet, server.URL, nil) + require.NoError(t, err) + + resp, err := requestWithRetry(client, req) + require.NoError(t, err) + require.NotNil(t, resp) + require.Equal(t, http.StatusOK, resp.StatusCode) +} + +func TestRequestWithRetry_NonRetriableStatus(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusBadRequest) + })) + defer server.Close() + + client := &http.Client{Timeout: 2 * time.Second} + req, err := http.NewRequest(http.MethodGet, server.URL, nil) + require.NoError(t, err) + + resp, err := requestWithRetry(client, req) + require.Error(t, err) + require.Nil(t, resp) +} From 5742c3c783d322b53acf11f49e05de6cbdf41a7a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 May 2025 03:11:52 +0000 Subject: [PATCH 20/42] chore(deps): bump the dev-dependencies group across 1 directory with 14 updates Bumps the dev-dependencies group with 12 updates in the / directory: | Package | From | To | | --- | --- | --- | | [github.com/IBM-Cloud/ibm-cloud-cli-sdk](https://github.com/IBM-Cloud/ibm-cloud-cli-sdk) | `1.7.1` | `1.7.2` | | [github.com/Yamashou/gqlgenc](https://github.com/Yamashou/gqlgenc) | `0.32.0` | `0.32.1` | | [github.com/aliyun/alibaba-cloud-sdk-go](https://github.com/aliyun/alibaba-cloud-sdk-go) | `1.63.106` | `1.63.107` | | [github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue](https://github.com/aws/aws-sdk-go-v2) | `1.18.12` | `1.19.0` | | [github.com/civo/civogo](https://github.com/civo/civogo) | `0.3.98` | `0.4.1` | | [github.com/digitalocean/godo](https://github.com/digitalocean/godo) | `1.142.0` | `1.145.0` | | [github.com/oracle/oci-go-sdk/v65](https://github.com/oracle/oci-go-sdk) | `65.89.1` | `65.89.3` | | [github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common](https://github.com/tencentcloud/tencentcloud-sdk-go) | `1.0.1146` | `1.0.1158` | | [google.golang.org/api](https://github.com/googleapis/google-api-go-client) | `0.229.0` | `0.231.0` | | [k8s.io/api](https://github.com/kubernetes/api) | `0.32.3` | `0.33.0` | | [k8s.io/client-go](https://github.com/kubernetes/client-go) | `0.32.3` | `0.33.0` | | [sigs.k8s.io/gateway-api](https://github.com/kubernetes-sigs/gateway-api) | `1.2.1` | `1.3.0` | Updates `github.com/IBM-Cloud/ibm-cloud-cli-sdk` from 1.7.1 to 1.7.2 - [Release notes](https://github.com/IBM-Cloud/ibm-cloud-cli-sdk/releases) - [Commits](https://github.com/IBM-Cloud/ibm-cloud-cli-sdk/compare/v1.7.1...v1.7.2) Updates `github.com/Yamashou/gqlgenc` from 0.32.0 to 0.32.1 - [Release notes](https://github.com/Yamashou/gqlgenc/releases) - [Commits](https://github.com/Yamashou/gqlgenc/compare/v0.32.0...v0.32.1) Updates `github.com/aliyun/alibaba-cloud-sdk-go` from 1.63.106 to 1.63.107 - [Release notes](https://github.com/aliyun/alibaba-cloud-sdk-go/releases) - [Changelog](https://github.com/aliyun/alibaba-cloud-sdk-go/blob/master/ChangeLog.txt) - [Commits](https://github.com/aliyun/alibaba-cloud-sdk-go/compare/v1.63.106...v1.63.107) Updates `github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue` from 1.18.12 to 1.19.0 - [Release notes](https://github.com/aws/aws-sdk-go-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/v1.19.0/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.18.12...v1.19.0) Updates `github.com/aws/aws-sdk-go-v2/service/dynamodb` from 1.42.4 to 1.43.1 - [Release notes](https://github.com/aws/aws-sdk-go-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json) - [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/ivs/v1.42.4...service/s3/v1.43.1) Updates `github.com/civo/civogo` from 0.3.98 to 0.4.1 - [Release notes](https://github.com/civo/civogo/releases) - [Changelog](https://github.com/civo/civogo/blob/master/changelog.yml) - [Commits](https://github.com/civo/civogo/compare/v0.3.98...v0.4.1) Updates `github.com/digitalocean/godo` from 1.142.0 to 1.145.0 - [Release notes](https://github.com/digitalocean/godo/releases) - [Changelog](https://github.com/digitalocean/godo/blob/main/CHANGELOG.md) - [Commits](https://github.com/digitalocean/godo/compare/v1.142.0...v1.145.0) Updates `github.com/oracle/oci-go-sdk/v65` from 65.89.1 to 65.89.3 - [Release notes](https://github.com/oracle/oci-go-sdk/releases) - [Changelog](https://github.com/oracle/oci-go-sdk/blob/master/CHANGELOG.md) - [Commits](https://github.com/oracle/oci-go-sdk/compare/v65.89.1...v65.89.3) Updates `github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common` from 1.0.1146 to 1.0.1158 - [Changelog](https://github.com/TencentCloud/tencentcloud-sdk-go/blob/master/SERVICE_CHANGELOG.md) - [Commits](https://github.com/tencentcloud/tencentcloud-sdk-go/compare/v1.0.1146...v1.0.1158) Updates `google.golang.org/api` from 0.229.0 to 0.231.0 - [Release notes](https://github.com/googleapis/google-api-go-client/releases) - [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md) - [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.229.0...v0.231.0) Updates `k8s.io/api` from 0.32.3 to 0.33.0 - [Commits](https://github.com/kubernetes/api/compare/v0.32.3...v0.33.0) Updates `k8s.io/apimachinery` from 0.32.3 to 0.33.0 - [Commits](https://github.com/kubernetes/apimachinery/compare/v0.32.3...v0.33.0) Updates `k8s.io/client-go` from 0.32.3 to 0.33.0 - [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md) - [Commits](https://github.com/kubernetes/client-go/compare/v0.32.3...v0.33.0) Updates `sigs.k8s.io/gateway-api` from 1.2.1 to 1.3.0 - [Release notes](https://github.com/kubernetes-sigs/gateway-api/releases) - [Changelog](https://github.com/kubernetes-sigs/gateway-api/blob/main/RELEASE.md) - [Commits](https://github.com/kubernetes-sigs/gateway-api/compare/v1.2.1...v1.3.0) --- updated-dependencies: - dependency-name: github.com/IBM-Cloud/ibm-cloud-cli-sdk dependency-version: 1.7.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: github.com/Yamashou/gqlgenc dependency-version: 0.32.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: github.com/aliyun/alibaba-cloud-sdk-go dependency-version: 1.63.107 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue dependency-version: 1.19.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dev-dependencies - dependency-name: github.com/aws/aws-sdk-go-v2/service/dynamodb dependency-version: 1.43.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dev-dependencies - dependency-name: github.com/civo/civogo dependency-version: 0.4.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dev-dependencies - dependency-name: github.com/digitalocean/godo dependency-version: 1.145.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dev-dependencies - dependency-name: github.com/oracle/oci-go-sdk/v65 dependency-version: 65.89.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common dependency-version: 1.0.1158 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: google.golang.org/api dependency-version: 0.231.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dev-dependencies - dependency-name: k8s.io/api dependency-version: 0.33.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dev-dependencies - dependency-name: k8s.io/apimachinery dependency-version: 0.33.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dev-dependencies - dependency-name: k8s.io/client-go dependency-version: 0.33.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dev-dependencies - dependency-name: sigs.k8s.io/gateway-api dependency-version: 1.3.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dev-dependencies ... Signed-off-by: dependabot[bot] --- go.mod | 56 +++++++++++++-------------- go.sum | 117 +++++++++++++++++++++++++++++---------------------------- 2 files changed, 88 insertions(+), 85 deletions(-) diff --git a/go.mod b/go.mod index 147a71d32..8be2944fb 100644 --- a/go.mod +++ b/go.mod @@ -9,29 +9,29 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.3.0 github.com/F5Networks/k8s-bigip-ctlr/v2 v2.19.1 - github.com/IBM-Cloud/ibm-cloud-cli-sdk v1.7.1 + github.com/IBM-Cloud/ibm-cloud-cli-sdk v1.7.2 github.com/IBM/go-sdk-core/v5 v5.19.1 github.com/IBM/networking-go-sdk v0.51.4 - github.com/Yamashou/gqlgenc v0.32.0 + github.com/Yamashou/gqlgenc v0.32.1 github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 github.com/alecthomas/kingpin/v2 v2.4.0 - github.com/aliyun/alibaba-cloud-sdk-go v1.63.106 + github.com/aliyun/alibaba-cloud-sdk-go v1.63.107 github.com/aws/aws-sdk-go-v2 v1.36.3 github.com/aws/aws-sdk-go-v2/config v1.29.14 github.com/aws/aws-sdk-go-v2/credentials v1.17.67 - github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.18.12 - github.com/aws/aws-sdk-go-v2/service/dynamodb v1.42.4 + github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.19.0 + github.com/aws/aws-sdk-go-v2/service/dynamodb v1.43.1 github.com/aws/aws-sdk-go-v2/service/route53 v1.51.1 github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.35.4 github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 github.com/bodgit/tsig v1.2.2 github.com/cenkalti/backoff/v5 v5.0.2 - github.com/civo/civogo v0.3.98 + github.com/civo/civogo v0.4.1 github.com/cloudflare/cloudflare-go v0.115.0 github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381 github.com/datawire/ambassador v1.12.4 github.com/denverdino/aliyungo v0.0.0-20230411124812-ab98a9173ace - github.com/digitalocean/godo v1.142.0 + github.com/digitalocean/godo v1.145.0 github.com/dnsimple/dnsimple-go v1.7.0 github.com/exoscale/egoscale v0.102.3 github.com/ffledgling/pdns-go v0.0.0-20180219074714-524e7daccd99 @@ -47,7 +47,7 @@ require ( github.com/onsi/ginkgo v1.16.5 github.com/openshift/api v0.0.0-20230607130528-611114dca681 github.com/openshift/client-go v0.0.0-20230607134213-3cd0021bbee3 - github.com/oracle/oci-go-sdk/v65 v65.89.1 + github.com/oracle/oci-go-sdk/v65 v65.89.3 github.com/ovh/go-ovh v1.7.0 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pluralsh/gqlclient v1.12.2 @@ -56,7 +56,7 @@ require ( github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.10.0 - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1146 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1158 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1136 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns v1.0.1145 github.com/transip/gotransip/v6 v6.26.0 @@ -68,25 +68,25 @@ require ( golang.org/x/sync v0.13.0 golang.org/x/text v0.24.0 golang.org/x/time v0.11.0 - google.golang.org/api v0.229.0 + google.golang.org/api v0.231.0 gopkg.in/ns1/ns1-go.v2 v2.14.2 istio.io/api v1.25.2 istio.io/client-go v1.25.2 - k8s.io/api v0.32.3 - k8s.io/apimachinery v0.32.3 - k8s.io/client-go v0.32.3 + k8s.io/api v0.33.0 + k8s.io/apimachinery v0.33.0 + k8s.io/client-go v0.33.0 k8s.io/klog/v2 v2.130.1 - sigs.k8s.io/gateway-api v1.2.1 + sigs.k8s.io/gateway-api v1.3.0 ) require ( - cloud.google.com/go/auth v0.16.0 // indirect + cloud.google.com/go/auth v0.16.1 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f // indirect - github.com/99designs/gqlgen v0.17.70 // indirect + github.com/99designs/gqlgen v0.17.71 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect - github.com/Masterminds/semver v1.4.2 // indirect + github.com/Masterminds/semver v1.5.0 // indirect github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect @@ -130,9 +130,8 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v5 v5.2.2 // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/gnostic-models v0.6.9 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect github.com/google/s2a-go v0.1.9 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect @@ -179,10 +178,10 @@ require ( github.com/shopspring/decimal v1.3.1 // indirect github.com/sony/gobreaker v0.5.0 // indirect github.com/sosodev/duration v1.3.1 // indirect - github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/pflag v1.0.6 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/terra-farm/udnssdk v1.3.5 // indirect - github.com/vektah/gqlparser/v2 v2.5.24 // indirect + github.com/vektah/gqlparser/v2 v2.5.25 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect @@ -196,15 +195,15 @@ require ( go.opentelemetry.io/otel/trace v1.35.0 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.26.0 // indirect + go.uber.org/zap v1.27.0 // indirect golang.org/x/crypto v0.37.0 // indirect golang.org/x/mod v0.24.0 // indirect golang.org/x/sys v0.32.0 // indirect golang.org/x/term v0.31.0 // indirect golang.org/x/tools v0.32.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e // indirect - google.golang.org/grpc v1.71.1 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250425173222-7b384671a197 // indirect + google.golang.org/grpc v1.72.0 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect @@ -212,11 +211,12 @@ require ( gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect + k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect moul.io/http2curl v1.0.0 // indirect - sigs.k8s.io/controller-runtime v0.18.7 // indirect + sigs.k8s.io/controller-runtime v0.20.4 // indirect sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index ffc50c0e1..3b6dede9e 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxo cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go/auth v0.16.0 h1:Pd8P1s9WkcrBE2n/PhAwKsdrR35V3Sg2II9B+ndM3CU= -cloud.google.com/go/auth v0.16.0/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI= +cloud.google.com/go/auth v0.16.1 h1:XrXauHMd30LhQYVRHLGvJiYeczweKQXZxsTbV9TiguU= +cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= @@ -12,8 +12,8 @@ code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f h1:UrKzEwTg code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f/go.mod h1:sk5LnIjB/nIEU7yP5sDQExVm62wu0pBh3yrElngUisI= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= git.lukeshu.com/go/libsystemd v0.5.3/go.mod h1:FfDoP0i92r4p5Vn4NCLxvjkd7rCOe6otPa4L6hZg9WM= -github.com/99designs/gqlgen v0.17.70 h1:xgLIgQuG+Q2L/AE9cW595CT7xCWCe/bpPIFGSfsGSGs= -github.com/99designs/gqlgen v0.17.70/go.mod h1:fvCiqQAu2VLhKXez2xFvLmE47QgAPf/KTPN5XQ4rsHQ= +github.com/99designs/gqlgen v0.17.71 h1:6JdwweHlSMWGY+6VWY5ey0tO+sF8LckbUV0NmdOQi04= +github.com/99designs/gqlgen v0.17.71/go.mod h1:3yz6ekwCAjC90zaFvPoy+mEjaKiyYJjhtCnwn1seoxE= github.com/Azure/azure-sdk-for-go v16.2.1+incompatible h1:KnPIugL51v3N3WwvaSmZbxukD1WuWXOiE9fRdu32f2I= github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 h1:Gt0j3wceWMwPmiazCa8MzMA0MfhmPIz0Qp0FJ6qcM0U= @@ -51,8 +51,8 @@ github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q github.com/F5Networks/k8s-bigip-ctlr/v2 v2.19.1 h1:NHWjSBeXbL8mlx+0QyCl4OrUvytCZ3nkEIRqX7t97wQ= github.com/F5Networks/k8s-bigip-ctlr/v2 v2.19.1/go.mod h1:JwdtGjHFTmUM1zjzvvCotCCyP55S146IuVPOJZ7D/Jw= github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= -github.com/IBM-Cloud/ibm-cloud-cli-sdk v1.7.1 h1:O9CXYO4upLrGlxFTZBW91yFdpWkHblezhbuKS/JjaVg= -github.com/IBM-Cloud/ibm-cloud-cli-sdk v1.7.1/go.mod h1:L1O3/tOKGedJ8db8i0KAgGBUHp8Fb0/00Lc8ebnj0DM= +github.com/IBM-Cloud/ibm-cloud-cli-sdk v1.7.2 h1:eW5o8NpblAyqPjwOlZ+XISdhlYynjf7B7dsCmsvfC/s= +github.com/IBM-Cloud/ibm-cloud-cli-sdk v1.7.2/go.mod h1:HulyrJLLc9FSZlwKQ9vu5Jq83thNlUfg1afonOdhrRA= github.com/IBM/go-sdk-core/v5 v5.19.1 h1:sleVks1O4XjgF4YEGvyDh6PZbP6iZhlTPeDkQc8nWDs= github.com/IBM/go-sdk-core/v5 v5.19.1/go.mod h1:Q3BYO6iDA2zweQPDGbNTtqft5tDcEpm6RTuqMlPcvbw= github.com/IBM/networking-go-sdk v0.51.4 h1:rkbR+gUkksLKjNYL5YEWEAMv3qddR0mUkxObDMa4l/s= @@ -60,8 +60,9 @@ github.com/IBM/networking-go-sdk v0.51.4/go.mod h1:gjCFEp+UVP7FUlcq2C1RaoZAXFcD3 github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc= github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/sprig v2.17.1+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/Masterminds/sprig/v3 v3.1.0/go.mod h1:ONGMf7UfYGAbMXCZmQLy8x3lCDIPrEZE/rU8pmrbihA= @@ -81,8 +82,8 @@ github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:H github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/Yamashou/gqlgenc v0.32.0 h1:f5Ebm9RG5jCL1iXxUN5X6e7Fgo/p3eQIDEaf0JO0GgQ= -github.com/Yamashou/gqlgenc v0.32.0/go.mod h1:DExQmcD8yilMdtLdLWLofPrbWuxKjaf6HFZdG49i3EA= +github.com/Yamashou/gqlgenc v0.32.1 h1:EHs9//xQxXlyltkSFXM+fhO2rTXcWNw6FPKRJ6t+iQQ= +github.com/Yamashou/gqlgenc v0.32.1/go.mod h1:o5SxKt9d3+oUZ2i0V3CW8lHFyunfLR+KcKHubS4zf5E= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= @@ -98,8 +99,8 @@ github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAu github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5 h1:P5U+E4x5OkVEKQDklVPmzs71WM56RTTRqV4OrDC//Y4= github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5/go.mod h1:976q2ETgjT2snVCf2ZaBnyBbVoPERGjUz+0sofzEfro= -github.com/aliyun/alibaba-cloud-sdk-go v1.63.106 h1:+YPfQheppCKOPJxhWDmStF1UMJrxnA1iiwBH12t6Fa4= -github.com/aliyun/alibaba-cloud-sdk-go v1.63.106/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ= +github.com/aliyun/alibaba-cloud-sdk-go v1.63.107 h1:qagvUyrgOnBIlVRQWOyCZGVKUIYbMBdGdJ104vBpRFU= +github.com/aliyun/alibaba-cloud-sdk-go v1.63.107/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/andybalholm/brotli v0.0.0-20190621154722-5f990b63d2d6/go.mod h1:+lx6/Aqd1kLJ1GQfkvOnaZ1WGmLpMpbprPuIOOZX30U= @@ -127,8 +128,8 @@ github.com/aws/aws-sdk-go-v2/config v1.29.14 h1:f+eEi/2cKCg9pqKBoAIwRGzVb70MRKqW github.com/aws/aws-sdk-go-v2/config v1.29.14/go.mod h1:wVPHWcIFv3WO89w0rE10gzf17ZYy+UVS1Geq8Iei34g= github.com/aws/aws-sdk-go-v2/credentials v1.17.67 h1:9KxtdcIA/5xPNQyZRgUSpYOE6j9Bc4+D7nZua0KGYOM= github.com/aws/aws-sdk-go-v2/credentials v1.17.67/go.mod h1:p3C44m+cfnbv763s52gCqrjaqyPikj9Sg47kUVaNZQQ= -github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.18.12 h1:mwAIR3fhxhSzXFj530LNCBe0JocYVQx6GuJpQiA+QOs= -github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.18.12/go.mod h1:9cWrNL8q7ApFmZzKhnb63ub4zrdMzOGQVn/kxvagfeE= +github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.19.0 h1:F3W0YqWZrpCcelbvXMP9LWSTOI620aAq1+8fZ/71TBg= +github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.19.0/go.mod h1:34X+UzFJwsQfyk5U1hYiCO/gv9ZVL+Hh8w+bJQ6+HbU= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 h1:x793wxmUWVDhshP8WW2mlnXuFrO4cOd3HLBroh1paFw= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30/go.mod h1:Jpne2tDnYiFascUEs2AWHJL9Yp7A5ZVy3TNyxaAjD6M= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q= @@ -137,8 +138,8 @@ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0io github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= -github.com/aws/aws-sdk-go-v2/service/dynamodb v1.42.4 h1:5GjCSGIpndYU/tVABz+4XnAcluU6wrjlPzAAgFUDG98= -github.com/aws/aws-sdk-go-v2/service/dynamodb v1.42.4/go.mod h1:yYaWRnVSPyAmexW5t7G3TcuYoalYfT+xQwzWsvtUQ7M= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.43.1 h1:YYjNTAyPL0425ECmq6Xm48NSXdT6hDVQmLOJZxyhNTM= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.43.1/go.mod h1:yYaWRnVSPyAmexW5t7G3TcuYoalYfT+xQwzWsvtUQ7M= github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.25.3 h1:GHC1WTF3ZBZy+gvz2qtYB6ttALVx35hlwc4IzOIUY7g= github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.25.3/go.mod h1:lUqWdw5/esjPTkITXhN4C66o1ltwDq2qQ12j3SOzhVg= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE= @@ -187,8 +188,8 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= -github.com/civo/civogo v0.3.98 h1:FEbB5oxCcHeHUK3fJODxVoMQzhpLV9Jtb7bezANTY5c= -github.com/civo/civogo v0.3.98/go.mod h1:LaEbkszc+9nXSh4YNG0sYXFGYqdQFmXXzQg0gESs2hc= +github.com/civo/civogo v0.4.1 h1:C+lwZ7hBqKy6eKy6qgviuselF0V5Z/um0x7X/eLEQ64= +github.com/civo/civogo v0.4.1/go.mod h1:LaEbkszc+9nXSh4YNG0sYXFGYqdQFmXXzQg0gESs2hc= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.115.0 h1:84/dxeeXweCc0PN5Cto44iTA8AkG1fyT11yPO5ZB7sM= @@ -257,8 +258,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/digitalocean/godo v1.142.0 h1:OZwDccTSL7yrgkGIiPMcJ4DXD8tCpu3xfbEVHAIB8mw= -github.com/digitalocean/godo v1.142.0/go.mod h1:tYeiWY5ZXVpU48YaFv0M5irUFHXGorZpDNm7zzdWMzM= +github.com/digitalocean/godo v1.145.0 h1:xBhWr+vCBy7GsexCUsWC+dKhPAWBMRLazavvXwyPBp8= +github.com/digitalocean/godo v1.145.0/go.mod h1:tYeiWY5ZXVpU48YaFv0M5irUFHXGorZpDNm7zzdWMzM= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/dnsimple/dnsimple-go v1.7.0 h1:JKu9xJtZ3SqOC+BuYgAWeab7+EEx0sz422vu8j611ZY= github.com/dnsimple/dnsimple-go v1.7.0/go.mod h1:EKpuihlWizqYafSnQHGCd/gyvy3HkEQJ7ODB4KdV8T8= @@ -303,8 +304,8 @@ github.com/exoscale/egoscale v0.102.3/go.mod h1:RPf2Gah6up+6kAEayHTQwqapzXlm93f0 github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= -github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= @@ -425,8 +426,8 @@ github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= @@ -492,8 +493,8 @@ github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkY github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= +github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -509,8 +510,6 @@ github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= @@ -848,8 +847,8 @@ github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxS github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/oracle/oci-go-sdk/v65 v65.89.1 h1:8sVjxYPNQ83yqUgZKkdeUA0CnSodmL1Bme2oxq8gyKg= -github.com/oracle/oci-go-sdk/v65 v65.89.1/go.mod h1:u6XRPsw9tPziBh76K7GrrRXPa8P8W3BQeqJ6ZZt9VLA= +github.com/oracle/oci-go-sdk/v65 v65.89.3 h1:KSUykb5Ou54jF4SeJNjBwcDg+umbAwcvT+xhrvNDog0= +github.com/oracle/oci-go-sdk/v65 v65.89.3/go.mod h1:u6XRPsw9tPziBh76K7GrrRXPa8P8W3BQeqJ6ZZt9VLA= github.com/ovh/go-ovh v1.7.0 h1:V14nF7FwDjQrZt9g7jzcvAAQ3HN6DNShRFRMC3jLoPw= github.com/ovh/go-ovh v1.7.0/go.mod h1:cTVDnl94z4tl8pP1uZ/8jlVxntjSIf09bNcQ5TJSC7c= github.com/oxtoacart/bpool v0.0.0-20150712133111-4e1c5567d7c2 h1:CXwSGu/LYmbjEab5aMCs5usQRVBGThelUKBNnoSOuso= @@ -991,8 +990,9 @@ github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzu github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= @@ -1020,8 +1020,8 @@ github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1136/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1145/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1146 h1:PMhgU4BETyTiikegps6gDtLamNWUiLMEx4fv16UWspY= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1146/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1158 h1:N+C8Tz6JKGwnDFDfd3g5CkTsiKTa6/Uia0uAL0OhimE= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1158/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1136 h1:kMIdSU5IvpOROh27ToVQ3hlm6ym3lCRs9tnGCOBoZqk= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1136/go.mod h1:FpyIz3mymKaExVs6Fz27kxDBS42jqZn7vbACtxdeEH4= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns v1.0.1145 h1:K5N0Uxqm9kM7KU6DFBekCTKbldlXq6UD1ekOyXn4zEc= @@ -1052,8 +1052,8 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= -github.com/vektah/gqlparser/v2 v2.5.24 h1:Dnip1ilW+nnXmaXL6s6f1w4IaXpAFDLLE1f9SqMegpI= -github.com/vektah/gqlparser/v2 v2.5.24/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo= +github.com/vektah/gqlparser/v2 v2.5.25 h1:FmWtFEa+invTIzWlWK6Vk7BVEZU/97QBzeI8Z1JjGt8= +github.com/vektah/gqlparser/v2 v2.5.25/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -1129,8 +1129,8 @@ go.uber.org/ratelimit v0.3.1/go.mod h1:6euWsTB6U/Nb3X++xEUXA8ciPJvr19Q/0h1+oDcJh go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1382,8 +1382,8 @@ gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZ google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.229.0 h1:p98ymMtqeJ5i3lIBMj5MpR9kzIIgzpHHh8vQ+vgAzx8= -google.golang.org/api v0.229.0/go.mod h1:wyDfmq5g1wYJWn29O22FDWN48P7Xcz0xz+LBpptYvB0= +google.golang.org/api v0.231.0 h1:LbUD5FUl0C4qwia2bjXhCMH65yz1MLPzA/0OYEsYY7Q= +google.golang.org/api v0.231.0/go.mod h1:H52180fPI/QQlUc0F4xWfGZILdv09GCWKt2bcsn164A= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1397,10 +1397,10 @@ google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 h1:GVIKPyP/kLIyVOgOnTwFOrvQaQUzOzGMCxgFUOEmm24= -google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422/go.mod h1:b6h1vNKhxaSoEI+5jc3PJUCustfli/mRab7295pY7rw= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e h1:ztQaXfzEXTmCBvbtWYRhJxW+0iJcz2qXfd38/e9l7bA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a h1:nwKuGPlUAt+aR+pcrkfFRrTU1BVrSmYyYMxYbUIVHr0= +google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a/go.mod h1:3kWAYMk1I75K4vykHtKt2ycnOgpA6974V7bREqbsenU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250425173222-7b384671a197 h1:29cjnHVylHwTzH66WfFZqgSQgnxzvWE+jvBwpZCLRxY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250425173222-7b384671a197/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1414,8 +1414,8 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI= -google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= +google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM= +google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1489,16 +1489,16 @@ istio.io/client-go v1.25.2/go.mod h1:E2LTxTcCVe4cqpKy4/9Y4VmwSoLiH6ff9MEG7EhfSDo k8s.io/api v0.18.0/go.mod h1:q2HRQkfDzHMBZL9l/y9rH63PkQl4vae0xRT+8prbrK8= k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= k8s.io/api v0.18.4/go.mod h1:lOIQAKYgai1+vz9J7YcDZwC26Z0zQewYOGWdyIPUUQ4= -k8s.io/api v0.32.3 h1:Hw7KqxRusq+6QSplE3NYG4MBxZw1BZnq4aP4cJVINls= -k8s.io/api v0.32.3/go.mod h1:2wEDTXADtm/HA7CCMD8D8bK4yuBUptzaRhYcYEEYA3k= +k8s.io/api v0.33.0 h1:yTgZVn1XEe6opVpP1FylmNrIFWuDqe2H0V8CT5gxfIU= +k8s.io/api v0.33.0/go.mod h1:CTO61ECK/KU7haa3qq8sarQ0biLq2ju405IZAd9zsiM= k8s.io/apiextensions-apiserver v0.18.0/go.mod h1:18Cwn1Xws4xnWQNC00FLq1E350b9lUF+aOdIWDOZxgo= k8s.io/apiextensions-apiserver v0.18.2/go.mod h1:q3faSnRGmYimiocj6cHQ1I3WpLqmDgJFlKL37fC4ZvY= k8s.io/apiextensions-apiserver v0.18.4/go.mod h1:NYeyeYq4SIpFlPxSAB6jHPIdvu3hL0pc36wuRChybio= k8s.io/apimachinery v0.18.0/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= k8s.io/apimachinery v0.18.4/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= -k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U= -k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= +k8s.io/apimachinery v0.33.0 h1:1a6kHrJxb2hs4t8EE5wuR/WxKDwGN1FKH3JvDtA0CIQ= +k8s.io/apimachinery v0.33.0/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= k8s.io/apiserver v0.18.0/go.mod h1:3S2O6FeBBd6XTo0njUrLxiqk8GNy6wWOftjhJcXYnjw= k8s.io/apiserver v0.18.2/go.mod h1:Xbh066NqrZO8cbsoenCwyDJ1OSi8Ag8I2lezeHxzwzw= k8s.io/apiserver v0.18.4/go.mod h1:q+zoFct5ABNnYkGIaGQ3bcbUNdmPyOCoEBcg51LChY8= @@ -1507,8 +1507,8 @@ k8s.io/cli-runtime v0.18.4/go.mod h1:9/hS/Cuf7NVzWR5F/5tyS6xsnclxoPLVtwhnkJG1Y4g k8s.io/client-go v0.18.0/go.mod h1:uQSYDYs4WhVZ9i6AIoEZuwUggLVEF64HOD37boKAtF8= k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU= k8s.io/client-go v0.18.4/go.mod h1:f5sXwL4yAZRkAtzOxRWUhA/N8XzGCb+nPZI8PfobZ9g= -k8s.io/client-go v0.32.3 h1:RKPVltzopkSgHS7aS98QdscAgtgah/+zmpAogooIqVU= -k8s.io/client-go v0.32.3/go.mod h1:3v0+3k4IcT9bXTc4V2rt+d2ZPPG700Xy6Oi0Gdl2PaY= +k8s.io/client-go v0.33.0 h1:UASR0sAYVUzs2kYuKn/ZakZlcs2bEHaizrrHUZg0G98= +k8s.io/client-go v0.33.0/go.mod h1:kGkd+l/gNGg8GYWAPr0xF1rRKvVWvzh9vmZAMXtaKOg= k8s.io/code-generator v0.18.0/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= k8s.io/code-generator v0.18.4/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= @@ -1526,8 +1526,8 @@ k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= -k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y= -k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= k8s.io/kubectl v0.18.0/go.mod h1:LOkWx9Z5DXMEg5KtOjHhRiC1fqJPLyCr3KtQgEolCkU= k8s.io/kubectl v0.18.4/go.mod h1:EzB+nfeUWk6fm6giXQ8P4Fayw3dsN+M7Wjy23mTRtB0= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= @@ -1543,18 +1543,21 @@ rsc.io/letsencrypt v0.0.3/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0= sigs.k8s.io/controller-runtime v0.6.1/go.mod h1:XRYBPdbf5XJu9kpS84VJiZ7h/u1hF3gEORz0efEja7A= -sigs.k8s.io/controller-runtime v0.18.7 h1:WDnx8LTRY8Fn1j/7B+S/R9MeDjWNAzpDBoaSvMSrQME= -sigs.k8s.io/controller-runtime v0.18.7/go.mod h1:L9r3fUZhID7Q9eK9mseNskpaTg2n11f/tlb8odyzJ4Y= +sigs.k8s.io/controller-runtime v0.20.4 h1:X3c+Odnxz+iPTRobG4tp092+CvBU9UK0t/bRf+n0DGU= +sigs.k8s.io/controller-runtime v0.20.4/go.mod h1:xg2XB0K5ShQzAgsoujxuKN4LNXR2LfwwHsPj7Iaw+XY= sigs.k8s.io/controller-tools v0.3.1-0.20200517180335-820a4a27ea84/go.mod h1:enhtKGfxZD1GFEoMgP8Fdbu+uKQ/cq1/WGJhdVChfvI= -sigs.k8s.io/gateway-api v1.2.1 h1:fZZ/+RyRb+Y5tGkwxFKuYuSRQHu9dZtbjenblleOLHM= -sigs.k8s.io/gateway-api v1.2.1/go.mod h1:EpNfEXNjiYfUJypf0eZ0P5iXA9ekSGWaS1WgPaM42X0= +sigs.k8s.io/gateway-api v1.3.0 h1:q6okN+/UKDATola4JY7zXzx40WO4VISk7i9DIfOvr9M= +sigs.k8s.io/gateway-api v1.3.0/go.mod h1:d8NV8nJbaRbEKem+5IuxkL8gJGOZ+FJ+NvOIltV8gDk= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= +sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= -sigs.k8s.io/structured-merge-diff/v4 v4.5.0 h1:nbCitCK2hfnhyiKo6uf2HxUPTCodY6Qaf85SbDIaMBk= -sigs.k8s.io/structured-merge-diff/v4 v4.5.0/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= From d72c913f97d5003d9f29946bba2f2afa4e862da2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 May 2025 03:55:07 +0000 Subject: [PATCH 21/42] chore(deps): bump the dev-dependencies group across 1 directory with 2 updates Bumps the dev-dependencies group with 2 updates in the / directory: [renovatebot/github-action](https://github.com/renovatebot/github-action) and [actions/setup-python](https://github.com/actions/setup-python). Updates `renovatebot/github-action` from 41.0.20 to 41.0.21 - [Release notes](https://github.com/renovatebot/github-action/releases) - [Changelog](https://github.com/renovatebot/github-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/renovatebot/github-action/compare/v41.0.20...v41.0.21) Updates `actions/setup-python` from 5.5.0 to 5.6.0 - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/8d9ed9ac5c53483de85588cdf95a591a75ab9f55...a26af69be951a213d495a4c3e4e4022e16d87065) --- updated-dependencies: - dependency-name: renovatebot/github-action dependency-version: 41.0.21 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: actions/setup-python dependency-version: 5.6.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dev-dependencies ... Signed-off-by: dependabot[bot] --- .github/workflows/dependency-update.yaml | 2 +- .github/workflows/docs.yaml | 2 +- .github/workflows/lint-test-chart.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dependency-update.yaml b/.github/workflows/dependency-update.yaml index 095331b08..67ad0cb72 100644 --- a/.github/workflows/dependency-update.yaml +++ b/.github/workflows/dependency-update.yaml @@ -17,7 +17,7 @@ jobs: uses: actions/checkout@v4.2.2 # https://github.com/renovatebot/github-action - name: self-hosted renovate - uses: renovatebot/github-action@v41.0.20 + uses: renovatebot/github-action@v41.0.22 with: # https://docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 52e23f500..0faa3d066 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -19,7 +19,7 @@ jobs: with: fetch-depth: 0 - - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: "3.12" cache: "pip" diff --git a/.github/workflows/lint-test-chart.yaml b/.github/workflows/lint-test-chart.yaml index 1412a868d..fa8fcf62a 100644 --- a/.github/workflows/lint-test-chart.yaml +++ b/.github/workflows/lint-test-chart.yaml @@ -78,7 +78,7 @@ jobs: run: ah lint --kind helm || exit 1 - name: Install Python - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: token: ${{ github.token }} python-version: "3.x" From 219e19fee74be8aaf6a7bd5a8a2e5d367a26a6c2 Mon Sep 17 00:00:00 2001 From: Jordan Jones Date: Fri, 2 May 2025 20:10:11 -0700 Subject: [PATCH 22/42] fix: check that parent generation matches current generation. --- source/gateway.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/gateway.go b/source/gateway.go index 2a7135212..8a78bd2f8 100644 --- a/source/gateway.go +++ b/source/gateway.go @@ -307,7 +307,13 @@ func (c *gatewayRouteResolver) resolve(rt gatewayRoute) (map[string]endpoint.Tar for _, rps := range rt.RouteStatus().Parents { // Confirm the Parent is the standard Gateway kind. ref := rps.ParentRef + namespace := strVal((*string)(ref.Namespace), meta.Namespace) + if rps.Conditions[0].ObservedGeneration != meta.Generation { + log.Debugf("Ignoring parent %s/%s of %s/%s as generation %d does not match current generation %d", namespace, ref.Name, meta.Namespace, meta.Name, rps.Conditions[0].ObservedGeneration, meta.Generation) + continue + } + // Ensure that the parent reference is in the routeParentRefs list if !gwRouteHasParentRef(routeParentRefs, ref, meta) { log.Debugf("Parent reference %s/%s not found in routeParentRefs for %s %s/%s", namespace, string(ref.Name), c.src.rtKind, meta.Namespace, meta.Name) From 1ad804caea9ce5e6faedae657e7d128e8461c957 Mon Sep 17 00:00:00 2001 From: Tyler Holinka <1685504+tholinka@users.noreply.github.com> Date: Sat, 3 May 2025 04:26:54 -0500 Subject: [PATCH 23/42] fix: add unit tests for generation check --- source/gateway.go | 4 ++- source/gateway_httproute_test.go | 57 ++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/source/gateway.go b/source/gateway.go index 8a78bd2f8..6c07e5b8c 100644 --- a/source/gateway.go +++ b/source/gateway.go @@ -309,7 +309,9 @@ func (c *gatewayRouteResolver) resolve(rt gatewayRoute) (map[string]endpoint.Tar ref := rps.ParentRef namespace := strVal((*string)(ref.Namespace), meta.Namespace) - if rps.Conditions[0].ObservedGeneration != meta.Generation { + + // Ensure that the parent reference is for the current generation + if len(rps.Conditions) > 0 && rps.Conditions[0].ObservedGeneration != meta.Generation { log.Debugf("Ignoring parent %s/%s of %s/%s as generation %d does not match current generation %d", namespace, ref.Name, meta.Namespace, meta.Name, rps.Conditions[0].ObservedGeneration, meta.Generation) continue } diff --git a/source/gateway_httproute_test.go b/source/gateway_httproute_test.go index 19f009fb7..2d068ae6a 100644 --- a/source/gateway_httproute_test.go +++ b/source/gateway_httproute_test.go @@ -70,6 +70,23 @@ func gwRouteStatus(refs ...v1.ParentReference) v1.RouteStatus { return v } +func omWithGeneration(meta metav1.ObjectMeta, generation int64) metav1.ObjectMeta { + meta.Generation = generation + return meta +} + +func rsWithGeneration(routeStatus v1.HTTPRouteStatus, generation ...int64) v1.HTTPRouteStatus { + for i, parent := range routeStatus.Parents { + if len(generation) <= i { + break + } + + parent.Conditions[0].ObservedGeneration = generation[i] + } + + return routeStatus +} + func gwParentRef(namespace, name string, options ...gwParentRefOption) v1.ParentReference { group := v1.Group("gateway.networking.k8s.io") kind := v1.Kind("Gateway") @@ -192,6 +209,46 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) { "level=debug msg=\"Gateway gateway-namespace/not-gateway-name does not match gateway-name route-namespace/test\"", }, }, + { + title: "GatewayNameOldGeneration", + config: Config{ + GatewayName: "gateway-name", + }, + namespaces: namespaces("gateway-namespace", "route-namespace"), + gateways: []*v1beta1.Gateway{ + { + ObjectMeta: omWithGeneration(objectMeta("gateway-namespace", "gateway-name"), 2), + Spec: v1.GatewaySpec{ + Listeners: []v1.Listener{{ + Protocol: v1.HTTPProtocolType, + AllowedRoutes: allowAllNamespaces, + }}, + }, + Status: gatewayStatus("1.2.3.4"), + }, + }, + routes: []*v1beta1.HTTPRoute{{ + ObjectMeta: omWithGeneration(objectMeta("route-namespace", "old-test"), 5), + Spec: v1.HTTPRouteSpec{ + Hostnames: hostnames("test.example.internal"), + CommonRouteSpec: v1.CommonRouteSpec{ + ParentRefs: []v1.ParentReference{ + gwParentRef("gateway-namespace", "gateway-name"), + }, + }, + }, + Status: rsWithGeneration(httpRouteStatus( // The route was previously attached to a different gateway + gwParentRef("gateway-namespace", "gateway-name"), + gwParentRef("gateway-namespace", "gateway-name"), + ), 5, 4), + }}, + endpoints: []*endpoint.Endpoint{ + newTestEndpoint("test.example.internal", "A", "1.2.3.4"), + }, + logExpectations: []string{ + "level=debug msg=\"Ignoring parent gateway-namespace/gateway-name of route-namespace/old-test as generation 4 does not match current generation 5\"", + }, + }, { title: "GatewayNamespace", config: Config{ From 0dcd6c922cb7b87d06fe77bd83e3f183de2944bb Mon Sep 17 00:00:00 2001 From: Jordan Jones Date: Sat, 3 May 2025 11:42:21 -0700 Subject: [PATCH 24/42] chore: move into pre-existing conditions check --- source/gateway.go | 16 +++++----------- source/gateway_httproute_test.go | 2 +- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/source/gateway.go b/source/gateway.go index 6c07e5b8c..a2c273d9d 100644 --- a/source/gateway.go +++ b/source/gateway.go @@ -307,15 +307,8 @@ func (c *gatewayRouteResolver) resolve(rt gatewayRoute) (map[string]endpoint.Tar for _, rps := range rt.RouteStatus().Parents { // Confirm the Parent is the standard Gateway kind. ref := rps.ParentRef - namespace := strVal((*string)(ref.Namespace), meta.Namespace) - // Ensure that the parent reference is for the current generation - if len(rps.Conditions) > 0 && rps.Conditions[0].ObservedGeneration != meta.Generation { - log.Debugf("Ignoring parent %s/%s of %s/%s as generation %d does not match current generation %d", namespace, ref.Name, meta.Namespace, meta.Name, rps.Conditions[0].ObservedGeneration, meta.Generation) - continue - } - // Ensure that the parent reference is in the routeParentRefs list if !gwRouteHasParentRef(routeParentRefs, ref, meta) { log.Debugf("Parent reference %s/%s not found in routeParentRefs for %s %s/%s", namespace, string(ref.Name), c.src.rtKind, meta.Namespace, meta.Name) @@ -341,10 +334,11 @@ func (c *gatewayRouteResolver) resolve(rt gatewayRoute) (map[string]endpoint.Tar } // Confirm the Gateway has accepted the Route. - if !gwRouteIsAccepted(rps.Conditions) { - log.Debugf("Gateway %s/%s has not accepted %s %s/%s", namespace, ref.Name, c.src.rtKind, meta.Namespace, meta.Name) + if !gwRouteIsAccepted(rps.Conditions, meta) { + log.Debugf("Gateway %s/%s has not accepted the current generation %s %s/%s", namespace, ref.Name, c.src.rtKind, meta.Namespace, meta.Name) continue } + // Match the Route to all possible Listeners. match := false section := sectionVal(ref.SectionName, "") @@ -502,10 +496,10 @@ func gwRouteHasParentRef(routeParentRefs []v1.ParentReference, ref v1.ParentRefe return false } -func gwRouteIsAccepted(conds []metav1.Condition) bool { +func gwRouteIsAccepted(conds []metav1.Condition, meta *metav1.ObjectMeta) bool { for _, c := range conds { if v1.RouteConditionType(c.Type) == v1.RouteConditionAccepted { - return c.Status == metav1.ConditionTrue + return c.Status == metav1.ConditionTrue && c.ObservedGeneration == meta.Generation } } return false diff --git a/source/gateway_httproute_test.go b/source/gateway_httproute_test.go index 2d068ae6a..abeb06b1b 100644 --- a/source/gateway_httproute_test.go +++ b/source/gateway_httproute_test.go @@ -246,7 +246,7 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) { newTestEndpoint("test.example.internal", "A", "1.2.3.4"), }, logExpectations: []string{ - "level=debug msg=\"Ignoring parent gateway-namespace/gateway-name of route-namespace/old-test as generation 4 does not match current generation 5\"", + "level=debug msg=\"Gateway gateway-namespace/gateway-name has not accepted the current generation HTTPRoute route-namespace/old-test\"", }, }, { From 059daadcfec8d2a08be153091eb24af661adb639 Mon Sep 17 00:00:00 2001 From: Jordan Jones Date: Sat, 3 May 2025 11:43:15 -0700 Subject: [PATCH 25/42] chore: remove unneccessary new line --- source/gateway.go | 1 - 1 file changed, 1 deletion(-) diff --git a/source/gateway.go b/source/gateway.go index a2c273d9d..77203819b 100644 --- a/source/gateway.go +++ b/source/gateway.go @@ -308,7 +308,6 @@ func (c *gatewayRouteResolver) resolve(rt gatewayRoute) (map[string]endpoint.Tar // Confirm the Parent is the standard Gateway kind. ref := rps.ParentRef namespace := strVal((*string)(ref.Namespace), meta.Namespace) - // Ensure that the parent reference is in the routeParentRefs list if !gwRouteHasParentRef(routeParentRefs, ref, meta) { log.Debugf("Parent reference %s/%s not found in routeParentRefs for %s %s/%s", namespace, string(ref.Name), c.src.rtKind, meta.Namespace, meta.Name) From 4be9faf77b30c22307c68e0a21f4652f71771dcb Mon Sep 17 00:00:00 2001 From: riupie Date: Sun, 4 May 2025 12:27:28 +0700 Subject: [PATCH 26/42] RFC2136: fix typo on environment variable --- docs/tutorials/rfc2136.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/tutorials/rfc2136.md b/docs/tutorials/rfc2136.md index 5211a6d7c..dd95ea633 100644 --- a/docs/tutorials/rfc2136.md +++ b/docs/tutorials/rfc2136.md @@ -508,12 +508,12 @@ extraArgs: - --rfc2136-tsig-axfr env: - - name: "EXTERNAL_DNS_RDC2136_TSIG_SECRET" + - name: "EXTERNAL_DNS_RFC2136_TSIG_SECRET" valueFrom: secretKeyRef: name: rfc2136-keys key: rfc2136-tsig-secret - - name: "EXTERNAL_DNS_RDC2136_TSIG_KEYNAME" + - name: "EXTERNAL_DNS_RFC2136_TSIG_KEYNAME" valueFrom: secretKeyRef: name: rfc2136-keys From b4dc53590344cbe124d32a0f99c048d326ba0b1a Mon Sep 17 00:00:00 2001 From: Michel Loiseleur <97035654+mloiseleur@users.noreply.github.com> Date: Sun, 4 May 2025 16:11:56 +0200 Subject: [PATCH 27/42] docs(contributing): add conventional commits (#5333) * docs(contributing): add conventional commits * fix md linter * Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 723484a71..785a60270 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,6 +12,8 @@ We have full documentation on how to get started contributing here: - [Kubernetes Contributor Guide](https://git.k8s.io/community/contributors/guide) - Main contributor documentation, or you can just jump directly to the [contributing section](https://git.k8s.io/community/contributors/guide#contributing) - [Contributor Cheat Sheet](https://git.k8s.io/community/contributors/guide/contributor-cheatsheet) - Common resources for existing developers +This project follows the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification on PR title. The explicit commit history is used, among other things, to provide a readable changelog in release notes. + ## Mentorship - [Mentoring Initiatives](https://git.k8s.io/community/mentoring) - We have a diverse set of mentorship programs available that are always looking for volunteers! From 597a72f1937a9b7600bb4080985c194f61124a5b Mon Sep 17 00:00:00 2001 From: natitomattis Date: Sun, 4 May 2025 11:41:57 -0300 Subject: [PATCH 28/42] test: add tests for cloudflare provider (#5248) * Improve cloudflare code coverage * refactor TestCloudflareProvider * go lint * fix data race --- provider/cloudflare/cloudflare_test.go | 169 ++++++++++++++++++------- 1 file changed, 120 insertions(+), 49 deletions(-) diff --git a/provider/cloudflare/cloudflare_test.go b/provider/cloudflare/cloudflare_test.go index 4d841776c..f50940142 100644 --- a/provider/cloudflare/cloudflare_test.go +++ b/provider/cloudflare/cloudflare_test.go @@ -51,6 +51,7 @@ type mockCloudFlareClient struct { Records map[string]map[string]cloudflare.DNSRecord Actions []MockAction listZonesError error + zoneDetailsError error listZonesContextError error dnsRecordsError error customHostnames map[string][]cloudflare.CustomHostname @@ -410,6 +411,10 @@ func (m *mockCloudFlareClient) ListZonesContext(ctx context.Context, opts ...clo } func (m *mockCloudFlareClient) ZoneDetails(ctx context.Context, zoneID string) (cloudflare.Zone, error) { + if m.zoneDetailsError != nil { + return cloudflare.Zone{}, m.zoneDetailsError + } + for id, zoneName := range m.Zones { if zoneID == id { return cloudflare.Zone{ @@ -891,6 +896,24 @@ func TestCloudflareZones(t *testing.T) { assert.Equal(t, "bar.com", zones[0].Name) } +// test failures on zone lookup +func TestCloudflareZonesFailed(t *testing.T) { + + client := NewMockCloudFlareClient() + client.zoneDetailsError = errors.New("zone lookup failed") + + provider := &CloudFlareProvider{ + Client: client, + domainFilter: endpoint.NewDomainFilter([]string{"bar.com"}), + zoneIDFilter: provider.NewZoneIDFilter([]string{"001"}), + } + + _, err := provider.Zones(context.Background()) + if err == nil { + t.Errorf("should fail, %s", err) + } +} + func TestCloudFlareZonesWithIDFilter(t *testing.T) { client := NewMockCloudFlareClient() client.listZonesError = errors.New("shouldn't need to list zones when ZoneIDFilter in use") @@ -1002,64 +1025,88 @@ func TestCloudflareRecords(t *testing.T) { } func TestCloudflareProvider(t *testing.T) { - _ = os.Setenv("CF_API_TOKEN", "abc123def") - _, err := NewCloudFlareProvider( - endpoint.NewDomainFilter([]string{"bar.com"}), - provider.NewZoneIDFilter([]string{""}), - false, - true, - 5000, - "", - CustomHostnamesConfig{Enabled: false}) - if err != nil { - t.Errorf("should not fail, %s", err) + var err error + + type EnvVar struct { + Key string + Value string } - _ = os.Unsetenv("CF_API_TOKEN") tokenFile := "/tmp/cf_api_token" if err := os.WriteFile(tokenFile, []byte("abc123def"), 0o644); err != nil { t.Errorf("failed to write token file, %s", err) } - _ = os.Setenv("CF_API_TOKEN", tokenFile) - _, err = NewCloudFlareProvider( - endpoint.NewDomainFilter([]string{"bar.com"}), - provider.NewZoneIDFilter([]string{""}), - false, - true, - 5000, - "", - CustomHostnamesConfig{Enabled: false}) - if err != nil { - t.Errorf("should not fail, %s", err) + + testCases := []struct { + Name string + Environment []EnvVar + ShouldFail bool + }{ + { + Name: "use_api_token", + Environment: []EnvVar{ + {Key: "CF_API_TOKEN", Value: "abc123def"}, + }, + ShouldFail: false, + }, + { + Name: "use_api_token_file_contents", + Environment: []EnvVar{ + {Key: "CF_API_TOKEN", Value: tokenFile}, + }, + ShouldFail: false, + }, + { + Name: "use_email_and_key", + Environment: []EnvVar{ + {Key: "CF_API_KEY", Value: "xxxxxxxxxxxxxxxxx"}, + {Key: "CF_API_EMAIL", Value: "test@test.com"}, + }, + ShouldFail: false, + }, + { + Name: "no_use_email_and_key", + Environment: []EnvVar{}, + ShouldFail: true, + }, + { + Name: "use_credentials_in_missing_file", + Environment: []EnvVar{ + {Key: "CF_API_TOKEN", Value: "file://abc"}, + }, + ShouldFail: true, + }, + { + Name: "use_credentials_in_missing_file", + Environment: []EnvVar{ + {Key: "CF_API_TOKEN", Value: "file:/tmp/cf_api_token"}, + }, + ShouldFail: false, + }, } - _ = os.Unsetenv("CF_API_TOKEN") - _ = os.Setenv("CF_API_KEY", "xxxxxxxxxxxxxxxxx") - _ = os.Setenv("CF_API_EMAIL", "test@test.com") - _, err = NewCloudFlareProvider( - endpoint.NewDomainFilter([]string{"bar.com"}), - provider.NewZoneIDFilter([]string{""}), - false, - true, - 5000, - "", - CustomHostnamesConfig{Enabled: false}) - if err != nil { - t.Errorf("should not fail, %s", err) - } + for _, tc := range testCases { + t.Run(tc.Name, func(t *testing.T) { + for _, env := range tc.Environment { + t.Setenv(env.Key, env.Value) + } + + _, err = NewCloudFlareProvider( + endpoint.NewDomainFilter([]string{"bar.com"}), + provider.NewZoneIDFilter([]string{""}), + false, + true, + 5000, + "", + CustomHostnamesConfig{Enabled: false}) + if err != nil && !tc.ShouldFail { + t.Errorf("should not fail, %s", err) + } + if err == nil && tc.ShouldFail { + t.Errorf("should fail, %s", err) + } + }) - _ = os.Unsetenv("CF_API_KEY") - _ = os.Unsetenv("CF_API_EMAIL") - _, err = NewCloudFlareProvider( - endpoint.NewDomainFilter([]string{"bar.com"}), - provider.NewZoneIDFilter([]string{""}), - false, - true, - 5000, - "", - CustomHostnamesConfig{Enabled: false}) - if err == nil { - t.Errorf("expected to fail") } } @@ -1132,6 +1179,30 @@ func TestCloudflareApplyChanges(t *testing.T) { } } +func TestCloudflareDryRunApplyChanges(t *testing.T) { + changes := &plan.Changes{} + client := NewMockCloudFlareClient() + + provider := &CloudFlareProvider{ + Client: client, + DryRun: true, + } + changes.Create = []*endpoint.Endpoint{{ + DNSName: "new.bar.com", + Targets: endpoint.Targets{"target"}, + }} + err := provider.ApplyChanges(context.Background(), changes) + if err != nil { + t.Errorf("should not fail, %s", err) + } + ctx := context.Background() + records, err := provider.Records(ctx) + if err != nil { + t.Errorf("should not fail, %s", err) + } + assert.Equal(t, 0, len(records), "should not have any records") +} + func TestCloudflareApplyChangesError(t *testing.T) { changes := &plan.Changes{} client := NewMockCloudFlareClient() From 902fab75036e5e31e6f6cf769b5f8e85fdefa984 Mon Sep 17 00:00:00 2001 From: Luthfi Anandra Date: Mon, 5 May 2025 01:29:56 +0700 Subject: [PATCH 29/42] chore: fix typo on txtOwnerId comment/description (#5351) * chore: fix typo on txtOwnerId comment/description * docs: update txtOwnerId description in chart README --- charts/external-dns/README.md | 2 +- charts/external-dns/values.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/external-dns/README.md b/charts/external-dns/README.md index 6126679bb..d1a255e2b 100644 --- a/charts/external-dns/README.md +++ b/charts/external-dns/README.md @@ -180,7 +180,7 @@ If `namespaced` is set to `true`, please ensure that `sources` my only contains | tolerations | list | `[]` | Node taints which will be tolerated for `Pod` [scheduling](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). | | topologySpreadConstraints | list | `[]` | Topology spread constraints for `Pod` [scheduling](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). If an explicit label selector is not provided one will be created from the pod selector labels. | | triggerLoopOnEvent | bool | `false` | If `true`, triggers run loop on create/update/delete events in addition of regular interval. | -| txtOwnerId | string | `nil` | Specify an identifier for this instance of _ExternalDNS_ wWhen using a registry other than `noop`. | +| txtOwnerId | string | `nil` | Specify an identifier for this instance of _ExternalDNS_ when using a registry other than `noop`. | | txtPrefix | string | `nil` | Specify a prefix for the domain names of TXT records created for the `txt` registry. Mutually exclusive with `txtSuffix`. | | txtSuffix | string | `nil` | Specify a suffix for the domain names of TXT records created for the `txt` registry. Mutually exclusive with `txtPrefix`. | diff --git a/charts/external-dns/values.yaml b/charts/external-dns/values.yaml index 0e85050a3..5ea00c9da 100644 --- a/charts/external-dns/values.yaml +++ b/charts/external-dns/values.yaml @@ -216,7 +216,7 @@ policy: upsert-only # @schema enum:[sync, upsert-only]; type:string; default: " # -- Specify the registry for storing ownership and labels. # Valid values are `txt`, `aws-sd`, `dynamodb` & `noop`. registry: txt # @schema enum:[txt, aws-sd, dynamodb, noop]; default: "txt" -# -- (string) Specify an identifier for this instance of _ExternalDNS_ wWhen using a registry other than `noop`. +# -- (string) Specify an identifier for this instance of _ExternalDNS_ when using a registry other than `noop`. txtOwnerId: # @schema type:[string, null]; default: null # -- (string) Specify a prefix for the domain names of TXT records created for the `txt` registry. # Mutually exclusive with `txtSuffix`. From 57ba99094d85b7c5de0cc5e6223b73c4c4ae9672 Mon Sep 17 00:00:00 2001 From: Tyler Holinka <1685504+tholinka@users.noreply.github.com> Date: Sun, 4 May 2025 14:28:15 -0500 Subject: [PATCH 30/42] fix: add unit test for route never being accepted --- source/gateway_httproute_test.go | 50 +++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/source/gateway_httproute_test.go b/source/gateway_httproute_test.go index abeb06b1b..a7f9bbe90 100644 --- a/source/gateway_httproute_test.go +++ b/source/gateway_httproute_test.go @@ -87,6 +87,19 @@ func rsWithGeneration(routeStatus v1.HTTPRouteStatus, generation ...int64) v1.HT return routeStatus } +func rsWithoutAccepted(routeStatus v1.HTTPRouteStatus) v1.HTTPRouteStatus { + for _, parent := range routeStatus.Parents { + for j := range parent.Conditions { + cond := &parent.Conditions[j] + if cond.Type == string(v1.RouteConditionAccepted) { + cond.Type = "NotAccepted" // fake type to test for having no accepted condition + } + } + } + + return routeStatus +} + func gwParentRef(namespace, name string, options ...gwParentRefOption) v1.ParentReference { group := v1.Group("gateway.networking.k8s.io") kind := v1.Kind("Gateway") @@ -237,7 +250,7 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) { }, }, }, - Status: rsWithGeneration(httpRouteStatus( // The route was previously attached to a different gateway + Status: rsWithGeneration(httpRouteStatus( // The route was previously attached in a different generation gwParentRef("gateway-namespace", "gateway-name"), gwParentRef("gateway-namespace", "gateway-name"), ), 5, 4), @@ -249,6 +262,41 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) { "level=debug msg=\"Gateway gateway-namespace/gateway-name has not accepted the current generation HTTPRoute route-namespace/old-test\"", }, }, + { + title: "GatewayNameNoneAccepted", + config: Config{ + GatewayName: "gateway-name", + }, + namespaces: namespaces("gateway-namespace", "route-namespace"), + gateways: []*v1beta1.Gateway{ + { + ObjectMeta: omWithGeneration(objectMeta("gateway-namespace", "gateway-name"), 2), + Spec: v1.GatewaySpec{ + Listeners: []v1.Listener{{ + Protocol: v1.HTTPProtocolType, + AllowedRoutes: allowAllNamespaces, + }}, + }, + Status: gatewayStatus("1.2.3.4"), + }, + }, + routes: []*v1beta1.HTTPRoute{{ + ObjectMeta: omWithGeneration(objectMeta("route-namespace", "old-test"), 5), + Spec: v1.HTTPRouteSpec{ + Hostnames: hostnames("test.example.internal"), + CommonRouteSpec: v1.CommonRouteSpec{ + ParentRefs: []v1.ParentReference{ + gwParentRef("gateway-namespace", "gateway-name"), + }, + }, + }, + Status: rsWithoutAccepted(httpRouteStatus(gwParentRef("gateway-namespace", "gateway-name"))), + }}, + endpoints: []*endpoint.Endpoint{}, + logExpectations: []string{ + "level=debug msg=\"Gateway gateway-namespace/gateway-name has not accepted the current generation HTTPRoute route-namespace/old-test\"", + }, + }, { title: "GatewayNamespace", config: Config{ From 2481c07e95a2e6baff8d74d59c577dc3daf33186 Mon Sep 17 00:00:00 2001 From: Michel Loiseleur <97035654+mloiseleur@users.noreply.github.com> Date: Sun, 4 May 2025 21:53:56 +0200 Subject: [PATCH 31/42] chore(crd): use conventional paths and update controller-gen to v0.17.2 (#5287) * chore(crd): update controller-gen to v0.17.2 * review: only one crd manifest * set crd in expected paths --- Makefile | 9 +- charts/external-dns/crds/dnsendpoint.yaml | 168 +++++++++--------- .../crd/standard/dnsendpoint.yaml | 2 +- docs/sources/crd.md | 4 +- endpoint/endpoint.go | 2 + endpoint/zz_generated.deepcopy.go | 120 +------------ scripts/install-tools.sh | 2 +- 7 files changed, 100 insertions(+), 207 deletions(-) rename docs/sources/crd/crd-manifest.yaml => config/crd/standard/dnsendpoint.yaml (98%) diff --git a/Makefile b/Makefile index 74ee98737..d8b7a74e5 100644 --- a/Makefile +++ b/Makefile @@ -32,10 +32,6 @@ else CONTROLLER_GEN=$(shell which controller-gen) endif -#? controller-gen-install: download controller-gen if necessary -controller-gen-install: - @scripts/install-tools.sh --generator - #? golangci-lint-install: Install golangci-lint tool golangci-lint-install: @scripts/install-tools.sh --golangci @@ -67,10 +63,11 @@ oas-lint: .PHONY: lint lint: licensecheck go-lint oas-lint -#? crd: Generates CRD using controller-gen +#? crd: Generates CRD using controller-gen and copy it into chart .PHONY: crd crd: controller-gen-install - ${CONTROLLER_GEN} crd:crdVersions=v1 paths="./endpoint/..." output:crd:stdout > docs/contributing/crd-source/crd-manifest.yaml + ${CONTROLLER_GEN} crd:crdVersions=v1 paths="./endpoint/..." output:crd:stdout > config/crd/standard/dnsendpoint.yaml + cp -f config/crd/standard/dnsendpoint.yaml charts/external-dns/crds/dnsendpoint.yaml #? test: The verify target runs tasks similar to the CI tasks, but without code coverage .PHONY: test diff --git a/charts/external-dns/crds/dnsendpoint.yaml b/charts/external-dns/crds/dnsendpoint.yaml index 822cd8503..88845aaae 100644 --- a/charts/external-dns/crds/dnsendpoint.yaml +++ b/charts/external-dns/crds/dnsendpoint.yaml @@ -1,9 +1,11 @@ +--- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: - name: dnsendpoints.externaldns.k8s.io annotations: api-approved.kubernetes.io: https://github.com/kubernetes-sigs/external-dns/pull/2007 + controller-gen.kubebuilder.io/version: v0.17.2 + name: dnsendpoints.externaldns.k8s.io spec: group: externaldns.k8s.io names: @@ -13,90 +15,86 @@ spec: singular: dnsendpoint scope: Namespaced versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - apiVersion: - description: |- - APIVersion defines the versioned schema of this representation of an object. - Servers should convert recognized schemas to the latest internal value, and - may reject unrecognized values. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - type: string - kind: - description: |- - Kind is a string value representing the REST resource this object represents. - Servers may infer this from the endpoint the client submits requests to. - Cannot be updated. - In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - metadata: - type: object - spec: - description: DNSEndpointSpec defines the desired state of DNSEndpoint - properties: - endpoints: - items: - description: - Endpoint is a high-level way of a connection between - a service and an IP - properties: - dnsName: - description: The hostname of the DNS record + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: DNSEndpointSpec defines the desired state of DNSEndpoint + properties: + endpoints: + items: + description: Endpoint is a high-level way of a connection between + a service and an IP + properties: + dnsName: + description: The hostname of the DNS record + type: string + labels: + additionalProperties: type: string - labels: - additionalProperties: - type: string - description: Labels stores labels defined for the Endpoint + description: Labels stores labels defined for the Endpoint + type: object + providerSpecific: + description: ProviderSpecific stores provider specific config + items: + description: ProviderSpecificProperty holds the name and value + of a configuration which is specific to individual DNS providers + properties: + name: + type: string + value: + type: string type: object - providerSpecific: - description: ProviderSpecific stores provider specific config - items: - description: - ProviderSpecificProperty holds the name and value - of a configuration which is specific to individual DNS providers - properties: - name: - type: string - value: - type: string - type: object - type: array - recordTTL: - description: TTL for the record - format: int64 - type: integer - recordType: - description: - RecordType type of record, e.g. CNAME, A, AAAA, - SRV, TXT etc + type: array + recordTTL: + description: TTL for the record + format: int64 + type: integer + recordType: + description: RecordType type of record, e.g. CNAME, A, AAAA, + SRV, TXT etc + type: string + setIdentifier: + description: Identifier to distinguish multiple records with + the same name and type (e.g. Route53 records with routing + policies other than 'simple') + type: string + targets: + description: The targets the DNS record points to + items: type: string - setIdentifier: - description: - Identifier to distinguish multiple records with - the same name and type (e.g. Route53 records with routing - policies other than 'simple') - type: string - targets: - description: The targets the DNS record points to - items: - type: string - type: array - type: object - type: array - type: object - status: - description: DNSEndpointStatus defines the observed state of DNSEndpoint - properties: - observedGeneration: - description: The generation observed by the external-dns controller. - format: int64 - type: integer - type: object - type: object - served: true - storage: true - subresources: - status: {} + type: array + type: object + type: array + type: object + status: + description: DNSEndpointStatus defines the observed state of DNSEndpoint + properties: + observedGeneration: + description: The generation observed by the external-dns controller. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/docs/sources/crd/crd-manifest.yaml b/config/crd/standard/dnsendpoint.yaml similarity index 98% rename from docs/sources/crd/crd-manifest.yaml rename to config/crd/standard/dnsendpoint.yaml index 5d4a44159..88845aaae 100644 --- a/docs/sources/crd/crd-manifest.yaml +++ b/config/crd/standard/dnsendpoint.yaml @@ -4,7 +4,7 @@ kind: CustomResourceDefinition metadata: annotations: api-approved.kubernetes.io: https://github.com/kubernetes-sigs/external-dns/pull/2007 - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.17.2 name: dnsendpoints.externaldns.k8s.io spec: group: externaldns.k8s.io diff --git a/docs/sources/crd.md b/docs/sources/crd.md index a7332f6b5..bd21ef005 100644 --- a/docs/sources/crd.md +++ b/docs/sources/crd.md @@ -81,11 +81,11 @@ Create the objects of CRD type by filling in the fields of CRD and DNS record wo ### Example -Here is an example [CRD manifest](crd/crd-manifest.yaml) generated by kubebuilder. +Here is an example [CRD manifest](https://github.com/kubernetes-sigs/external-dns/blob/HEAD/charts/external-dns/crds/dnsendpoint.yaml) generated by kubebuilder. Apply this to register the CRD ```sh -$ kubectl apply --validate=false -f docs/sources/crd/crd-manifest.yaml +$ kubectl apply --server-side=true -f "https://raw.githubusercontent.com/kubernetes-sigs/external-dns/master/config/crd/standard/dnsendpoint.yaml" customresourcedefinition.apiextensions.k8s.io "dnsendpoints.externaldns.k8s.io" created ``` diff --git a/endpoint/endpoint.go b/endpoint/endpoint.go index a8a385c57..bbf67f641 100644 --- a/endpoint/endpoint.go +++ b/endpoint/endpoint.go @@ -204,6 +204,7 @@ type EndpointKey struct { } // Endpoint is a high-level way of a connection between a service and an IP +// +kubebuilder:object:generate=true type Endpoint struct { // The hostname of the DNS record DNSName string `json:"dnsName,omitempty"` @@ -337,6 +338,7 @@ func FilterEndpointsByOwnerID(ownerID string, eps []*Endpoint) []*Endpoint { } // DNSEndpointSpec defines the desired state of DNSEndpoint +// +kubebuilder:object:generate=true type DNSEndpointSpec struct { Endpoints []*Endpoint `json:"endpoints,omitempty"` } diff --git a/endpoint/zz_generated.deepcopy.go b/endpoint/zz_generated.deepcopy.go index aaa69927d..ec07dace1 100644 --- a/endpoint/zz_generated.deepcopy.go +++ b/endpoint/zz_generated.deepcopy.go @@ -1,28 +1,11 @@ //go:build !ignore_autogenerated -// +build !ignore_autogenerated -/* -Copyright 2018 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. -*/ - -// Code generated by deepcopy-gen. DO NOT EDIT. +// Code generated by controller-gen. DO NOT EDIT. package endpoint import ( - "k8s.io/apimachinery/pkg/runtime" + runtime "k8s.io/apimachinery/pkg/runtime" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. @@ -32,7 +15,6 @@ func (in *DNSEndpoint) DeepCopyInto(out *DNSEndpoint) { in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) out.Status = in.Status - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNSEndpoint. @@ -57,7 +39,7 @@ func (in *DNSEndpoint) DeepCopyObject() runtime.Object { func (in *DNSEndpointList) DeepCopyInto(out *DNSEndpointList) { *out = *in out.TypeMeta = in.TypeMeta - out.ListMeta = in.ListMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items *out = make([]DNSEndpoint, len(*in)) @@ -65,7 +47,6 @@ func (in *DNSEndpointList) DeepCopyInto(out *DNSEndpointList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNSEndpointList. @@ -93,15 +74,13 @@ func (in *DNSEndpointSpec) DeepCopyInto(out *DNSEndpointSpec) { in, out := &in.Endpoints, &out.Endpoints *out = make([]*Endpoint, len(*in)) for i := range *in { - if (*in)[i] == nil { - (*out)[i] = nil - } else { - (*out)[i] = new(Endpoint) - (*in)[i].DeepCopyInto((*out)[i]) + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Endpoint) + (*in).DeepCopyInto(*out) } } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNSEndpointSpec. @@ -114,22 +93,6 @@ func (in *DNSEndpointSpec) DeepCopy() *DNSEndpointSpec { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *DNSEndpointStatus) DeepCopyInto(out *DNSEndpointStatus) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNSEndpointStatus. -func (in *DNSEndpointStatus) DeepCopy() *DNSEndpointStatus { - if in == nil { - return nil - } - out := new(DNSEndpointStatus) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Endpoint) DeepCopyInto(out *Endpoint) { *out = *in @@ -148,11 +111,8 @@ func (in *Endpoint) DeepCopyInto(out *Endpoint) { if in.ProviderSpecific != nil { in, out := &in.ProviderSpecific, &out.ProviderSpecific *out = make(ProviderSpecific, len(*in)) - for key, val := range *in { - (*out)[key] = val - } + copy(*out, *in) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Endpoint. @@ -164,67 +124,3 @@ func (in *Endpoint) DeepCopy() *Endpoint { in.DeepCopyInto(out) return out } - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in Labels) DeepCopyInto(out *Labels) { - { - in := &in - *out = make(Labels, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - return - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Labels. -func (in Labels) DeepCopy() Labels { - if in == nil { - return nil - } - out := new(Labels) - in.DeepCopyInto(out) - return *out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in ProviderSpecific) DeepCopyInto(out *ProviderSpecific) { - { - in := &in - *out = make(ProviderSpecific, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - return - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderSpecific. -func (in ProviderSpecific) DeepCopy() ProviderSpecific { - if in == nil { - return nil - } - out := new(ProviderSpecific) - in.DeepCopyInto(out) - return *out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in Targets) DeepCopyInto(out *Targets) { - { - in := &in - *out = make(Targets, len(*in)) - copy(*out, *in) - return - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Targets. -func (in Targets) DeepCopy() Targets { - if in == nil { - return nil - } - out := new(Targets) - in.DeepCopyInto(out) - return *out -} diff --git a/scripts/install-tools.sh b/scripts/install-tools.sh index 56b440778..54c8f2c40 100755 --- a/scripts/install-tools.sh +++ b/scripts/install-tools.sh @@ -15,7 +15,7 @@ # limitations under the License. # renovate: datasource=github-releases depName=kubernetes-sigs/controller-tools -CONTROLLER_TOOLS_GENERATOR_VERSION=v0.15.0 +CONTROLLER_TOOLS_GENERATOR_VERSION=v0.17.2 # renovate: datasource=github-releases depName=golangci/golangci-lint GOLANG_CI_LINTER_VERSION=v2.0.2 From 923a6d95c0221d6b82d3e613b6b68da4d267b748 Mon Sep 17 00:00:00 2001 From: Ivan Ka <5395690+ivankatliarchuk@users.noreply.github.com> Date: Wed, 7 May 2025 21:21:16 +0100 Subject: [PATCH 32/42] fix(webhook): api json object plan.Changes case (#5355) * fix(webhook): api case * fix(webhook): api case Signed-off-by: ivan katliarchuk --------- Signed-off-by: ivan katliarchuk --- plan/plan.go | 8 ++--- plan/plan_test.go | 45 ++++++++++++++++++++++++++ provider/webhook/api/httpapi.go | 4 +-- provider/webhook/api/httpapi_test.go | 47 ++++++++++++++++++++++++++-- provider/webhook/webhook.go | 2 +- 5 files changed, 96 insertions(+), 10 deletions(-) diff --git a/plan/plan.go b/plan/plan.go index c77f2f2a1..e5e7acd5f 100644 --- a/plan/plan.go +++ b/plan/plan.go @@ -54,13 +54,13 @@ type Plan struct { // Changes holds lists of actions to be executed by dns providers type Changes struct { // Records that need to be created - Create []*endpoint.Endpoint + Create []*endpoint.Endpoint `json:"create,omitempty"` // Records that need to be updated (current data) - UpdateOld []*endpoint.Endpoint + UpdateOld []*endpoint.Endpoint `json:"updateOld,omitempty"` // Records that need to be updated (desired data) - UpdateNew []*endpoint.Endpoint + UpdateNew []*endpoint.Endpoint `json:"updateNew,omitempty"` // Records that need to be deleted - Delete []*endpoint.Endpoint + Delete []*endpoint.Endpoint `json:"delete,omitempty"` } // planKey is a key for a row in `planTable`. diff --git a/plan/plan_test.go b/plan/plan_test.go index af1f5c2c0..c25a17d8e 100644 --- a/plan/plan_test.go +++ b/plan/plan_test.go @@ -17,6 +17,9 @@ limitations under the License. package plan import ( + "bytes" + "encoding/json" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -245,6 +248,48 @@ func (suite *PlanTestSuite) SetupTest() { } } +func TestPlan_ChangesJson_DecodeEncode(t *testing.T) { + ch := &Changes{ + Create: []*endpoint.Endpoint{ + { + DNSName: "foo", + }, + }, + UpdateOld: []*endpoint.Endpoint{ + { + DNSName: "bar", + }, + }, + UpdateNew: []*endpoint.Endpoint{ + { + DNSName: "baz", + }, + }, + Delete: []*endpoint.Endpoint{ + { + DNSName: "qux", + }, + }, + } + jsonBytes, err := json.Marshal(ch) + assert.NoError(t, err) + assert.Equal(t, + `{"create":[{"dnsName":"foo"}],"updateOld":[{"dnsName":"bar"}],"updateNew":[{"dnsName":"baz"}],"delete":[{"dnsName":"qux"}]}`, + string(jsonBytes)) + var changes Changes + err = json.NewDecoder(bytes.NewBuffer(jsonBytes)).Decode(&changes) + assert.NoError(t, err) + assert.Equal(t, ch, &changes) +} + +func TestPlan_ChangesJson_DecodeMixedCase(t *testing.T) { + input := `{"Create":[{"dnsName":"foo"}],"UpdateOld":[{"dnsName":"bar"}],"updateNew":[{"dnsName":"baz"}],"Delete":[{"dnsName":"qux"}]}` + var changes Changes + err := json.NewDecoder(strings.NewReader(input)).Decode(&changes) + assert.NoError(t, err) + assert.Len(t, changes.Create, 1) +} + func (suite *PlanTestSuite) TestSyncFirstRound() { current := []*endpoint.Endpoint{} desired := []*endpoint.Endpoint{suite.fooV1Cname, suite.fooV2Cname, suite.bar127A} diff --git a/provider/webhook/api/httpapi.go b/provider/webhook/api/httpapi.go index 2dbb3a19b..13c09bca7 100644 --- a/provider/webhook/api/httpapi.go +++ b/provider/webhook/api/httpapi.go @@ -85,7 +85,7 @@ func (p *WebhookServer) AdjustEndpointsHandler(w http.ResponseWriter, req *http. return } - pve := []*endpoint.Endpoint{} + var pve []*endpoint.Endpoint if err := json.NewDecoder(req.Body).Decode(&pve); err != nil { log.Errorf("Failed to decode in adjustEndpointsHandler: %v", err) w.WriteHeader(http.StatusBadRequest) @@ -104,7 +104,7 @@ func (p *WebhookServer) AdjustEndpointsHandler(w http.ResponseWriter, req *http. } } -func (p *WebhookServer) NegotiateHandler(w http.ResponseWriter, req *http.Request) { +func (p *WebhookServer) NegotiateHandler(w http.ResponseWriter, _ *http.Request) { w.Header().Set(ContentTypeHeader, MediaTypeFormatAndVersion) json.NewEncoder(w).Encode(p.Provider.GetDomainFilter()) } diff --git a/provider/webhook/api/httpapi_test.go b/provider/webhook/api/httpapi_test.go index 1fa51f46f..82af2ac84 100644 --- a/provider/webhook/api/httpapi_test.go +++ b/provider/webhook/api/httpapi_test.go @@ -24,9 +24,11 @@ import ( "io" "net/http" "net/http/httptest" + "strings" "testing" "time" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "sigs.k8s.io/external-dns/endpoint" "sigs.k8s.io/external-dns/plan" @@ -35,8 +37,9 @@ import ( var records []*endpoint.Endpoint type FakeWebhookProvider struct { - err error - domainFilter endpoint.DomainFilter + err error + domainFilter endpoint.DomainFilter + assertChanges func(*plan.Changes) } func (p FakeWebhookProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error) { @@ -51,6 +54,9 @@ func (p FakeWebhookProvider) ApplyChanges(ctx context.Context, changes *plan.Cha return p.err } records = append(records, changes.Create...) + if p.assertChanges != nil { + p.assertChanges(changes) + } return nil } @@ -179,7 +185,7 @@ func TestRecordsHandlerApplyChangesWithErrors(t *testing.T) { } func TestRecordsHandlerWithWrongHTTPMethod(t *testing.T) { - req := httptest.NewRequest(http.MethodPut, "/records", nil) + req := httptest.NewRequest(http.MethodPut, UrlRecords, nil) w := httptest.NewRecorder() providerAPIServer := &WebhookServer{ @@ -190,6 +196,41 @@ func TestRecordsHandlerWithWrongHTTPMethod(t *testing.T) { require.Equal(t, http.StatusBadRequest, res.StatusCode) } +func TestRecordsHandlerWithMixedCase(t *testing.T) { + input := `{"Create":[{"dnsName":"foo"}],"updateOld":[{"dnsName":"bar"}],"updateNew":[{"dnsName":"baz"}],"Delete":[{"dnsName":"qux"}]}` + req := httptest.NewRequest(http.MethodPost, UrlRecords, strings.NewReader(input)) + w := httptest.NewRecorder() + + records = []*endpoint.Endpoint{} + + providerAPIServer := &WebhookServer{ + Provider: &FakeWebhookProvider{ + assertChanges: func(changes *plan.Changes) { + t.Helper() + require.Equal(t, []*endpoint.Endpoint{ + { + DNSName: "foo", + }, + }, changes.Create) + require.Equal(t, []*endpoint.Endpoint{ + { + DNSName: "bar", + }, + }, changes.UpdateOld) + require.Equal(t, []*endpoint.Endpoint{ + { + DNSName: "qux", + }, + }, changes.Delete) + }, + }, + } + providerAPIServer.RecordsHandler(w, req) + res := w.Result() + require.Equal(t, http.StatusNoContent, res.StatusCode) + assert.Equal(t, 1, len(records)) +} + func TestAdjustEndpointsHandlerWithInvalidRequest(t *testing.T) { req := httptest.NewRequest(http.MethodPost, UrlAdjustEndpoints, nil) w := httptest.NewRecorder() diff --git a/provider/webhook/webhook.go b/provider/webhook/webhook.go index 4b7d020ce..bd142b3c7 100644 --- a/provider/webhook/webhook.go +++ b/provider/webhook/webhook.go @@ -200,7 +200,7 @@ func (p WebhookProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, err } // ApplyChanges will make a POST to remoteServerURL/records with the changes -func (p WebhookProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error { +func (p WebhookProvider) ApplyChanges(_ context.Context, changes *plan.Changes) error { applyChangesRequestsGauge.Gauge.Inc() u := p.remoteServerURL.JoinPath(webhookapi.UrlRecords).String() From b12e3e815554a6b9aee826dd88cae5a2fe5af721 Mon Sep 17 00:00:00 2001 From: Michel Loiseleur Date: Wed, 7 May 2025 22:50:51 +0200 Subject: [PATCH 33/42] chore(deps): update linter to v2.1.x --- .github/workflows/lint.yaml | 6 +++--- scripts/install-tools.sh | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 6bdcae2ff..acf7d21c7 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -26,7 +26,7 @@ jobs: files: '.' config_file: ".markdownlint.json" - - name: Set up Go 1.x + - name: Set up Go uses: actions/setup-go@v5 with: go-version-file: go.mod @@ -44,11 +44,11 @@ jobs: # https://github.com/golangci/golangci-lint-action?tab=readme-ov-file#verify - name: Verify linter configuration and Lint go code - uses: golangci/golangci-lint-action@v7 + uses: golangci/golangci-lint-action@v2 with: verify: true args: --timeout=30m - version: v2.0 + version: v2.1 # Run Spectral - name: Lint OpenAPI spec diff --git a/scripts/install-tools.sh b/scripts/install-tools.sh index 54c8f2c40..ce2eb86b9 100755 --- a/scripts/install-tools.sh +++ b/scripts/install-tools.sh @@ -17,7 +17,7 @@ # renovate: datasource=github-releases depName=kubernetes-sigs/controller-tools CONTROLLER_TOOLS_GENERATOR_VERSION=v0.17.2 # renovate: datasource=github-releases depName=golangci/golangci-lint -GOLANG_CI_LINTER_VERSION=v2.0.2 +GOLANG_CI_LINTER_VERSION=v2.1.6 # Execute # scripts/install-tools.sh From 1863af84e17457b05e0c6048e3a5d7ff2479cd2f Mon Sep 17 00:00:00 2001 From: Michel Loiseleur Date: Wed, 7 May 2025 23:12:04 +0200 Subject: [PATCH 34/42] fix typo --- .github/workflows/lint.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index acf7d21c7..8e784de6b 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -44,7 +44,7 @@ jobs: # https://github.com/golangci/golangci-lint-action?tab=readme-ov-file#verify - name: Verify linter configuration and Lint go code - uses: golangci/golangci-lint-action@v2 + uses: golangci/golangci-lint-action@v8 with: verify: true args: --timeout=30m From d60d96176f045c9ea1f7a843559bec4585a206be Mon Sep 17 00:00:00 2001 From: Srdjan Milutinovic <118281153+smilutinovic-ionos@users.noreply.github.com> Date: Thu, 8 May 2025 10:17:25 +0200 Subject: [PATCH 35/42] docs(tutorials): add IONOS Cloud setup tutorial for ExternalDNS (#5364) * docs(tutorials): add IONOS Cloud setup tutorial for ExternalDNS * docs(tutorials): improve formatting and clarity in IONOS Cloud tutorial * docs(tutorials): address comments, file names to use dash, and more information on ionos webhook repo and image * Update docs/tutorials/ionoscloud.md Co-authored-by: Michel Loiseleur <97035654+mloiseleur@users.noreply.github.com> --------- Co-authored-by: Michel Loiseleur <97035654+mloiseleur@users.noreply.github.com> --- docs/tutorials/ionoscloud.md | 256 +++++++++++++++++++++++++++++++++++ 1 file changed, 256 insertions(+) create mode 100644 docs/tutorials/ionoscloud.md diff --git a/docs/tutorials/ionoscloud.md b/docs/tutorials/ionoscloud.md new file mode 100644 index 000000000..e03d18161 --- /dev/null +++ b/docs/tutorials/ionoscloud.md @@ -0,0 +1,256 @@ +# IONOS Cloud + +This tutorial describes how to set up ExternalDNS for use within a Kubernetes cluster using IONOS Cloud DNS. +For more details, visit the [IONOS external-dns webhook repository](https://github.com/ionos-cloud/external-dns-ionos-webhook). +You can also find the [external-dns-ionos-webhook container image](https://github.com/ionos-cloud/external-dns-ionos-webhook/pkgs/container/external-dns-ionos-webhook) required for this setup. + +## Creating a DNS Zone with IONOS Cloud DNS + +If you are new to IONOS Cloud DNS, we recommend you first read the following instructions for creating a DNS zone: + +- [Manage DNS Zones in Data Centre Designer](https://docs.ionos.com/cloud/network-services/cloud-dns/dcd-how-tos/manage-dns-zone) +- [Creating a DNS Zone using the IONOS Cloud DNS API](https://docs.ionos.com/cloud/network-services/cloud-dns/api-how-tos/create-dns-zone) + +### Steps to Create a DNS Zone + +1. Log in to the [IONOS Cloud Data Center Designer](https://dcd.ionos.com/). +2. Navigate to the **Network Services** section and select **Cloud DNS**. +3. Click on **Create Zone** and provide the following details: + - **Zone Name**: Enter the domain name (e.g., `example.com`). + - **Description**: It is optional to provide a description of your zone. +4. Save the zone configuration. + +For more advanced configurations, such as adding records or managing subdomains, refer to the [IONOS Cloud DNS Documentation](https://docs.ionos.com/cloud/network-services/cloud-dns/). + +## Creating an IONOS API Token + +To use ExternalDNS with IONOS Cloud DNS, you need an API token with sufficient privileges to manage DNS zones and records. Follow these steps to create an API token: + +1. Log in to the [IONOS Cloud Data Center Designer](https://dcd.ionos.com/). +2. Navigate to the **Management** section in the top right corner and select **Token Manager**. +3. Select the Time To Live(TTL) of the token and click on **Create Token**. +4. Copy the generated token and store it securely. You will use this token to authenticate ExternalDNS. + +## Deploy ExternalDNS + +### Step 1: Create a Kubernetes Secret for the IONOS API Token + +Store your IONOS API token securely in a Kubernetes secret: + +```bash +kubectl create secret generic ionos-credentials --from-literal=api-key='' +``` + +Replace `` with your actual IONOS API token. + +### Step 2: Configure ExternalDNS + +Create a Helm values file for the ExternalDNS Helm chart that includes the webhook configuration. In this example, the values file is called `external-dns-ionos-values.yaml` . + +```yaml +logLevel: debug # ExternalDNS Log level, reduce in production + +namespaced: false # if true, ExternalDNS will run in a namespaced scope (Role and Rolebinding will be namespaced too). +triggerLoopOnEvent: true # if true, ExternalDNS will trigger a loop on every event (create/update/delete) on the resources it watches. + +logLevel: debug +sources: + - ingress + - service +provider: + name: webhook + webhook: + image: + repository: ghcr.io/ionos-cloud/external-dns-ionos-webhook + tag: latest + pullPolicy: IfNotPresent + env: + - name: IONOS_API_KEY + valueFrom: + secretKeyRef: + name: ionos-credentials + key: api-key + - name: SERVER_PORT + value: "8888" + - name: METRICS_PORT + value: "8080" + - name: DRY_RUN + value: "false" +``` + +### Step 3: Install ExternalDNS Using Helm + +Install ExternalDNS with the IONOS webhook provider: + +```bash +helm repo add external-dns https://kubernetes-sigs.github.io/external-dns/ +helm upgrade --install external-dns external-dns/external-dns -f external-dns-ionos-values.yaml +``` + +## Deploying an Example Application + +### Step 1: Create a Deployment + +In this step we will create `echoserver` application manifest with the following content: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: echoserver + namespace: default +spec: + replicas: 1 + selector: + matchLabels: + app: echoserver + template: + metadata: + labels: + app: echoserver + spec: + containers: + - name: echoserver + image: ealen/echo-server:latest + ports: + - containerPort: 80 +``` + +Deployment manifest can be saved in `echoserver-deployment.yaml` file. + +Next, we will apply the deployment: + +```bash +kubectl apply -f echoserver-deployment.yaml +``` + +### Step 2: Create a Service + +In this step, we will create a `Service` manifest to expose the `echoserver` application within the cluster. The service will also include an annotation for ExternalDNS to create a DNS record for the specified hostname. + +Save the following content in a file named `echoserver-service.yaml`: + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: echoserver + annotations: + external-dns.alpha.kubernetes.io/hostname: app.example.com +spec: + ports: + - port: 80 + targetPort: 80 + selector: + app: echoserver +``` + + **Note:** Replace `app.example.com` with a subdomain of your DNS zone configured in IONOS Cloud DNS. For example, if your DNS zone is `example.com`, you can use a subdomain like `app.example.com`. + +Next, apply the service: + +```bash +kubectl apply -f echoserver-service.yaml +``` + +This service will expose the echoserver application on port 80 and instruct ExternalDNS to create a DNS record for `app.example.com`. + +### Step 3: Create an Ingress + +In this step, we will create an `Ingress` resource to expose the `echoserver` application externally. The ingress will route HTTP traffic to the `echoserver` service and include a hostname that ExternalDNS will use to create the corresponding DNS record. + +Save the following content in a file named `echoserver-ingress.yaml` : + +```yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: echoserver +spec: + rules: + - host: app.example.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: echoserver + port: + number: 80 +``` + + **Note:** Replace `app.example.com` with a subdomain of your DNS zone configured in IONOS Cloud DNS. For example, if your DNS zone is `example.com`, you can use a subdomain like `app.example.com`. + +Next, apply the ingress manifest: + +```bash +kubectl apply -f echoserver-ingress.yaml +``` + +This ingress will expose the `echoserver` application at `http://app.example.com` and instruct ExternalDNS to create a DNS record for the specified hostname. + +## Accessing the Application + +Once the `Ingress` resource has been applied and the DNS records have been created, you can access the application using the hostname specified in the ingress (`app.example.com`). + +### Verify Application Access + +Use the following `curl` command to verify that the application is accessible: + +```bash +curl -I http://app.example.com +``` + +Replace app.example.com with the subdomain you configured in your DNS zone. + + **Note:** Ensure that your DNS changes have propagated and that the hostname resolves to the correct IP address before running the command. + +### Expected result + +You should see an HTTP response header indicating that the application is running, such as: + +```bash +HTTP/1.1 200 OK +``` + +> **Troubleshooting:** +> +>If you encounter any issues, verify the following: +> +> - The DNS record for `app.example.com` (replace with your own subdomain configured in IONOS Cloud DNS) has been created in IONOS Cloud DNS. +> - The ingress controller is running and properly configured in your Kubernetes cluster. +> - The `echoserver` application is running and accessible within the cluster. + +## Verifying IONOS Cloud DNS Records + +Use the IONOS Cloud Console or API to verify that the A and TXT records for your domain have been created. For example, you can use the following API call: + +```bash +curl --location --request GET 'https://dns.de-fra.ionos.com/records?filter.name=app' \ +--header 'Authorization: Bearer ' +``` + +Replace `` with your actual API token. + +The API response should include the `A` and `TXT` records for the subdomain you configured. + +> **Note:** DNS changes may take a few minutes to propagate. If the records are not visible immediately, wait and try again. + +## Cleanup + +> **Optional:** Perform the cleanup step only if you no longer need the deployed resources. + +Once you have verified the setup, you can clean up the resources created during this tutorial: + +```bash +kubectl delete -f echoserver-deployment.yaml +kubectl delete -f echoserver-service.yaml +kubectl delete -f echoserver-ingress.yaml +``` + +## Summary + +In this tutorial, you successfully deployed ExternalDNS webhook with IONOS Cloud DNS as the provider. +You created a Kubernetes deployment, service, and ingress, and verified that DNS records were created and the application was accessible. +You also learned how to clean up the resources when they are no longer needed. From 7aaa274f170e36742c9c50bdab7940d887657a5c Mon Sep 17 00:00:00 2001 From: Lino Layani <39967417+linoleparquet@users.noreply.github.com> Date: Thu, 8 May 2025 13:55:15 -0400 Subject: [PATCH 36/42] test(source): cover unhappy paths (#5369) * Improve test coverage store * Improve test coverage --- source/store_test.go | 43 +++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/source/store_test.go b/source/store_test.go index d65889328..94b42b4f1 100644 --- a/source/store_test.go +++ b/source/store_test.go @@ -195,17 +195,16 @@ func (suite *ByNamesTestSuite) TestKubeClientFails() { mockClientGenerator := new(MockClientGenerator) mockClientGenerator.On("KubeClient").Return(nil, errors.New("foo")) - _, err := ByNames(context.TODO(), mockClientGenerator, []string{"service"}, &Config{}) - suite.Error(err, "should return an error if kubernetes client cannot be created") + sourcesDependentOnKubeClient := []string{ + "node", "service", "ingress", "pod", "istio-gateway", "istio-virtualservice", + "ambassador-host", "gloo-proxy", "traefik-proxy", "crd", "kong-tcpingress", + "f5-virtualserver", "f5-transportserver", + } - _, err = ByNames(context.TODO(), mockClientGenerator, []string{"ingress"}, &Config{}) - suite.Error(err, "should return an error if kubernetes client cannot be created") - - _, err = ByNames(context.TODO(), mockClientGenerator, []string{"istio-gateway"}, &Config{}) - suite.Error(err, "should return an error if kubernetes client cannot be created") - - _, err = ByNames(context.TODO(), mockClientGenerator, []string{"kong-tcpingress"}, &Config{}) - suite.Error(err, "should return an error if kubernetes client cannot be created") + for _, source := range sourcesDependentOnKubeClient { + _, err := ByNames(context.TODO(), mockClientGenerator, []string{source}, &Config{}) + suite.Error(err, source+" should return an error if kubernetes client cannot be created") + } } func (suite *ByNamesTestSuite) TestIstioClientFails() { @@ -214,11 +213,27 @@ func (suite *ByNamesTestSuite) TestIstioClientFails() { mockClientGenerator.On("IstioClient").Return(nil, errors.New("foo")) mockClientGenerator.On("DynamicKubernetesClient").Return(nil, errors.New("foo")) - _, err := ByNames(context.TODO(), mockClientGenerator, []string{"istio-gateway"}, &Config{}) - suite.Error(err, "should return an error if istio client cannot be created") + sourcesDependentOnIstioClient := []string{"istio-gateway", "istio-virtualservice"} - _, err = ByNames(context.TODO(), mockClientGenerator, []string{"contour-httpproxy"}, &Config{}) - suite.Error(err, "should return an error if contour client cannot be created") + for _, source := range sourcesDependentOnIstioClient { + _, err := ByNames(context.TODO(), mockClientGenerator, []string{source}, &Config{}) + suite.Error(err, source+" should return an error if istio client cannot be created") + } +} + +func (suite *ByNamesTestSuite) TestDynamicKubernetesClientFails() { + mockClientGenerator := new(MockClientGenerator) + mockClientGenerator.On("KubeClient").Return(fakeKube.NewSimpleClientset(), nil) + mockClientGenerator.On("IstioClient").Return(istiofake.NewSimpleClientset(), nil) + mockClientGenerator.On("DynamicKubernetesClient").Return(nil, errors.New("foo")) + + sourcesDependentOnDynamicKubernetesClient := []string{"ambassador-host", "contour-httpproxy", "gloo-proxy", "traefik-proxy", + "kong-tcpingress", "f5-virtualserver", "f5-transportserver"} + + for _, source := range sourcesDependentOnDynamicKubernetesClient { + _, err := ByNames(context.TODO(), mockClientGenerator, []string{source}, &Config{}) + suite.Error(err, source+" should return an error if dynamic kubernetes client cannot be created") + } } func TestByNames(t *testing.T) { From 9f8f30882b724474449c93baecd82bb69e47722c Mon Sep 17 00:00:00 2001 From: ivan katliarchuk Date: Fri, 9 May 2025 08:21:31 +0100 Subject: [PATCH 37/42] chore(source): code cleanup Signed-off-by: ivan katliarchuk --- provider/aws/aws.go | 2 +- provider/inmemory/inmemory.go | 8 ++++---- registry/dynamodb_test.go | 2 +- source/ambassador_host.go | 10 ++++------ source/compatibility.go | 4 ++-- source/contour_httpproxy.go | 7 ++----- source/crd.go | 5 +---- source/f5_transportserver.go | 5 +---- source/f5_virtualserver.go | 5 +---- source/gloo_proxy.go | 14 +++++++------- source/istio_gateway.go | 12 ++++-------- source/istio_virtualservice.go | 9 +++------ source/kong_tcpingress.go | 5 +---- source/node.go | 7 ++----- source/openshift_route.go | 9 +++------ source/service.go | 13 +++++-------- source/source.go | 31 +++++++++++++++---------------- source/traefik_proxy.go | 19 +++++-------------- 18 files changed, 62 insertions(+), 105 deletions(-) diff --git a/provider/aws/aws.go b/provider/aws/aws.go index 89d90a47b..2ec309256 100644 --- a/provider/aws/aws.go +++ b/provider/aws/aws.go @@ -254,7 +254,7 @@ func (z zoneTags) filterZonesByTags(p *AWSProvider, zones map[string]*profiledZo // append adds tags to the ZoneTags for a given zoneID. func (z zoneTags) append(id string, tags []route53types.Tag) { zoneId := fmt.Sprintf("/hostedzone/%s", id) - if _, exists := z[zoneId]; !exists { + if _, ok := z[zoneId]; !ok { z[zoneId] = make(map[string]string) } for _, tag := range tags { diff --git a/provider/inmemory/inmemory.go b/provider/inmemory/inmemory.go index 1f636dfda..a2c054f0d 100644 --- a/provider/inmemory/inmemory.go +++ b/provider/inmemory/inmemory.go @@ -312,7 +312,7 @@ func (c *inMemoryClient) validateChangeBatch(zone string, changes *plan.Changes) } mesh := sets.New[endpoint.EndpointKey]() for _, newEndpoint := range changes.Create { - if _, exists := curZone[newEndpoint.Key()]; exists { + if _, ok := curZone[newEndpoint.Key()]; ok { return ErrRecordAlreadyExists } if err := c.updateMesh(mesh, newEndpoint); err != nil { @@ -320,7 +320,7 @@ func (c *inMemoryClient) validateChangeBatch(zone string, changes *plan.Changes) } } for _, updateEndpoint := range changes.UpdateNew { - if _, exists := curZone[updateEndpoint.Key()]; !exists { + if _, ok := curZone[updateEndpoint.Key()]; !ok { return ErrRecordNotFound } if err := c.updateMesh(mesh, updateEndpoint); err != nil { @@ -328,12 +328,12 @@ func (c *inMemoryClient) validateChangeBatch(zone string, changes *plan.Changes) } } for _, updateOldEndpoint := range changes.UpdateOld { - if rec, exists := curZone[updateOldEndpoint.Key()]; !exists || rec.Targets[0] != updateOldEndpoint.Targets[0] { + if rec, ok := curZone[updateOldEndpoint.Key()]; !ok || rec.Targets[0] != updateOldEndpoint.Targets[0] { return ErrRecordNotFound } } for _, deleteEndpoint := range changes.Delete { - if rec, exists := curZone[deleteEndpoint.Key()]; !exists || rec.Targets[0] != deleteEndpoint.Targets[0] { + if rec, ok := curZone[deleteEndpoint.Key()]; !ok || rec.Targets[0] != deleteEndpoint.Targets[0] { return ErrRecordNotFound } if err := c.updateMesh(mesh, deleteEndpoint); err != nil { diff --git a/registry/dynamodb_test.go b/registry/dynamodb_test.go index 281e274d9..e6e71b47d 100644 --- a/registry/dynamodb_test.go +++ b/registry/dynamodb_test.go @@ -1248,7 +1248,7 @@ func (r *DynamoDBStub) BatchExecuteStatement(context context.Context, input *dyn var key string assert.Nil(r.t, attributevalue.Unmarshal(statement.Parameters[0], &key)) - if code, exists := r.stubConfig.ExpectInsertError[key]; exists { + if code, ok := r.stubConfig.ExpectInsertError[key]; ok { delete(r.stubConfig.ExpectInsertError, key) responses = append(responses, dynamodbtypes.BatchStatementResponse{ Error: &dynamodbtypes.BatchStatementError{ diff --git a/source/ambassador_host.go b/source/ambassador_host.go index 0ddc89118..4dde2eaf8 100644 --- a/source/ambassador_host.go +++ b/source/ambassador_host.go @@ -119,7 +119,7 @@ func (sc *ambassadorHostSource) Endpoints(ctx context.Context) ([]*endpoint.Endp } // Get a list of Ambassador Host resources - ambassadorHosts := []*ambassador.Host{} + var ambassadorHosts []*ambassador.Host for _, hostObj := range hosts { unstructuredHost, ok := hostObj.(*unstructured.Unstructured) if !ok { @@ -185,11 +185,10 @@ func (sc *ambassadorHostSource) Endpoints(ctx context.Context) ([]*endpoint.Endp // endpointsFromHost extracts the endpoints from a Host object func (sc *ambassadorHostSource) endpointsFromHost(host *ambassador.Host, targets endpoint.Targets) ([]*endpoint.Endpoint, error) { var endpoints []*endpoint.Endpoint - annotations := host.Annotations resource := fmt.Sprintf("host/%s/%s", host.Namespace, host.Name) - providerSpecific, setIdentifier := getProviderSpecificAnnotations(annotations) - ttl := getTTLFromAnnotations(annotations, resource) + providerSpecific, setIdentifier := getProviderSpecificAnnotations(host.Annotations) + ttl := getTTLFromAnnotations(host.Annotations, resource) if host.Spec != nil { hostname := host.Spec.Hostname @@ -311,9 +310,8 @@ func (sc *ambassadorHostSource) filterByAnnotations(ambassadorHosts []*ambassado // Return a filtered list of Ambassador Hosts filteredList := []*ambassador.Host{} for _, host := range ambassadorHosts { - annotations := labels.Set(host.Annotations) // include Ambassador Host if its annotations match the annotation filter - if selector.Matches(annotations) { + if selector.Matches(labels.Set(host.Annotations)) { filteredList = append(filteredList, host) } } diff --git a/source/compatibility.go b/source/compatibility.go index d7f4351c8..afb1de3e4 100644 --- a/source/compatibility.go +++ b/source/compatibility.go @@ -84,8 +84,8 @@ func legacyEndpointsFromMoleculeService(svc *v1.Service) []*endpoint.Endpoint { } // Get the desired hostname of the service from the annotation. - hostnameAnnotation, exists := svc.Annotations[moleculeAnnotationKey] - if !exists { + hostnameAnnotation, ok := svc.Annotations[moleculeAnnotationKey] + if !ok { return nil } diff --git a/source/contour_httpproxy.go b/source/contour_httpproxy.go index 823b91e33..b8d58e11e 100644 --- a/source/contour_httpproxy.go +++ b/source/contour_httpproxy.go @@ -224,14 +224,11 @@ func (sc *httpProxySource) filterByAnnotations(httpProxies []*projectcontour.HTT return httpProxies, nil } - filteredList := []*projectcontour.HTTPProxy{} + var filteredList []*projectcontour.HTTPProxy for _, httpProxy := range httpProxies { - // convert the HTTPProxy's annotations to an equivalent label selector - annotations := labels.Set(httpProxy.Annotations) - // include HTTPProxy if its annotations match the selector - if selector.Matches(annotations) { + if selector.Matches(labels.Set(httpProxy.Annotations)) { filteredList = append(filteredList, httpProxy) } } diff --git a/source/crd.go b/source/crd.go index 31a775b06..d62805162 100644 --- a/source/crd.go +++ b/source/crd.go @@ -287,11 +287,8 @@ func (cs *crdSource) filterByAnnotations(dnsendpoints *endpoint.DNSEndpointList) filteredList := endpoint.DNSEndpointList{} for _, dnsendpoint := range dnsendpoints.Items { - // convert the dnsendpoint' annotations to an equivalent label selector - annotations := labels.Set(dnsendpoint.Annotations) - // include dnsendpoint if its annotations match the selector - if selector.Matches(annotations) { + if selector.Matches(labels.Set(dnsendpoint.Annotations)) { filteredList.Items = append(filteredList.Items, dnsendpoint) } } diff --git a/source/f5_transportserver.go b/source/f5_transportserver.go index d3042a58e..7a055982e 100644 --- a/source/f5_transportserver.go +++ b/source/f5_transportserver.go @@ -201,11 +201,8 @@ func (ts *f5TransportServerSource) filterByAnnotations(transportServers []*f5.Tr filteredList := []*f5.TransportServer{} for _, ts := range transportServers { - // convert the TransportServer's annotations to an equivalent label selector - annotations := labels.Set(ts.Annotations) - // include TransportServer if its annotations match the selector - if selector.Matches(annotations) { + if selector.Matches(labels.Set(ts.Annotations)) { filteredList = append(filteredList, ts) } } diff --git a/source/f5_virtualserver.go b/source/f5_virtualserver.go index 85b1538fe..1e98dc33a 100644 --- a/source/f5_virtualserver.go +++ b/source/f5_virtualserver.go @@ -208,11 +208,8 @@ func (vs *f5VirtualServerSource) filterByAnnotations(virtualServers []*f5.Virtua filteredList := []*f5.VirtualServer{} for _, vs := range virtualServers { - // convert the VirtualServer's annotations to an equivalent label selector - annotations := labels.Set(vs.Annotations) - // include VirtualServer if its annotations match the selector - if selector.Matches(annotations) { + if selector.Matches(labels.Set(vs.Annotations)) { filteredList = append(filteredList, vs) } } diff --git a/source/gloo_proxy.go b/source/gloo_proxy.go index 74754c19a..e851b2875 100644 --- a/source/gloo_proxy.go +++ b/source/gloo_proxy.go @@ -161,12 +161,12 @@ func (gs *glooSource) generateEndpointsFromProxy(ctx context.Context, proxy *pro for _, listener := range proxy.Spec.Listeners { for _, virtualHost := range listener.HTTPListener.VirtualHosts { - annotations, err := gs.annotationsFromProxySource(ctx, virtualHost) + ants, err := gs.annotationsFromProxySource(ctx, virtualHost) if err != nil { return nil, err } - ttl := getTTLFromAnnotations(annotations, resource) - providerSpecific, setIdentifier := getProviderSpecificAnnotations(annotations) + ttl := getTTLFromAnnotations(ants, resource) + providerSpecific, setIdentifier := getProviderSpecificAnnotations(ants) for _, domain := range virtualHost.Domains { endpoints = append(endpoints, endpointsForHostname(strings.TrimSuffix(domain, "."), targets, ttl, providerSpecific, setIdentifier, "")...) } @@ -176,7 +176,7 @@ func (gs *glooSource) generateEndpointsFromProxy(ctx context.Context, proxy *pro } func (gs *glooSource) annotationsFromProxySource(ctx context.Context, virtualHost proxyVirtualHost) (map[string]string, error) { - annotations := map[string]string{} + ants := map[string]string{} for _, src := range virtualHost.Metadata.Source { kind := sourceKind(src.Kind) if kind != nil { @@ -185,7 +185,7 @@ func (gs *glooSource) annotationsFromProxySource(ctx context.Context, virtualHos return nil, err } for key, value := range source.GetAnnotations() { - annotations[key] = value + ants[key] = value } } } @@ -197,11 +197,11 @@ func (gs *glooSource) annotationsFromProxySource(ctx context.Context, virtualHos return nil, err } for key, value := range source.GetAnnotations() { - annotations[key] = value + ants[key] = value } } } - return annotations, nil + return ants, nil } func (gs *glooSource) proxyTargets(ctx context.Context, name string, namespace string) (endpoint.Targets, error) { diff --git a/source/istio_gateway.go b/source/istio_gateway.go index d158b30a7..0ca2a9835 100644 --- a/source/istio_gateway.go +++ b/source/istio_gateway.go @@ -217,11 +217,8 @@ func (sc *gatewaySource) filterByAnnotations(gateways []*networkingv1alpha3.Gate var filteredList []*networkingv1alpha3.Gateway for _, gw := range gateways { - // convert the annotations to an equivalent label selector - annotations := labels.Set(gw.Annotations) - // include if the annotations match the selector - if selector.Matches(annotations) { + if selector.Matches(labels.Set(gw.Annotations)) { filteredList = append(filteredList, gw) } } @@ -313,10 +310,9 @@ func (sc *gatewaySource) endpointsFromGateway(ctx context.Context, hostnames []s resource := fmt.Sprintf("gateway/%s/%s", gateway.Namespace, gateway.Name) - annotations := gateway.Annotations - ttl := getTTLFromAnnotations(annotations, resource) + ttl := getTTLFromAnnotations(gateway.Annotations, resource) - targets := getTargetsFromTargetAnnotation(annotations) + targets := getTargetsFromTargetAnnotation(gateway.Annotations) if len(targets) == 0 { targets, err = sc.targetsFromGateway(ctx, gateway) if err != nil { @@ -324,7 +320,7 @@ func (sc *gatewaySource) endpointsFromGateway(ctx context.Context, hostnames []s } } - providerSpecific, setIdentifier := getProviderSpecificAnnotations(annotations) + providerSpecific, setIdentifier := getProviderSpecificAnnotations(gateway.Annotations) for _, host := range hostnames { endpoints = append(endpoints, endpointsForHostname(host, targets, ttl, providerSpecific, setIdentifier, resource)...) diff --git a/source/istio_virtualservice.go b/source/istio_virtualservice.go index 039aa6f3c..ca6edfbb7 100644 --- a/source/istio_virtualservice.go +++ b/source/istio_virtualservice.go @@ -268,13 +268,10 @@ func (sc *virtualServiceSource) filterByAnnotations(virtualservices []*networkin var filteredList []*networkingv1alpha3.VirtualService - for _, virtualservice := range virtualservices { - // convert the annotations to an equivalent label selector - annotations := labels.Set(virtualservice.Annotations) - + for _, vs := range virtualservices { // include if the annotations match the selector - if selector.Matches(annotations) { - filteredList = append(filteredList, virtualservice) + if selector.Matches(labels.Set(vs.Annotations)) { + filteredList = append(filteredList, vs) } } diff --git a/source/kong_tcpingress.go b/source/kong_tcpingress.go index bca023dbe..f710a80d8 100644 --- a/source/kong_tcpingress.go +++ b/source/kong_tcpingress.go @@ -179,11 +179,8 @@ func (sc *kongTCPIngressSource) filterByAnnotations(tcpIngresses []*TCPIngress) filteredList := []*TCPIngress{} for _, tcpIngress := range tcpIngresses { - // convert the TCPIngress's annotations to an equivalent label selector - annotations := labels.Set(tcpIngress.Annotations) - // include TCPIngress if its annotations match the selector - if selector.Matches(annotations) { + if selector.Matches(labels.Set(tcpIngress.Annotations)) { filteredList = append(filteredList, tcpIngress) } } diff --git a/source/node.go b/source/node.go index a0e426f17..d2991d4b4 100644 --- a/source/node.go +++ b/source/node.go @@ -222,14 +222,11 @@ func (ns *nodeSource) filterByAnnotations(nodes []*v1.Node) ([]*v1.Node, error) return nodes, nil } - filteredList := []*v1.Node{} + var filteredList []*v1.Node for _, node := range nodes { - // convert the node's annotations to an equivalent label selector - annotations := labels.Set(node.Annotations) - // include node if its annotations match the selector - if selector.Matches(annotations) { + if selector.Matches(labels.Set(node.Annotations)) { filteredList = append(filteredList, node) } } diff --git a/source/openshift_route.go b/source/openshift_route.go index dd50913f6..b47a14dab 100644 --- a/source/openshift_route.go +++ b/source/openshift_route.go @@ -24,7 +24,7 @@ import ( "time" routev1 "github.com/openshift/api/route/v1" - versioned "github.com/openshift/client-go/route/clientset/versioned" + "github.com/openshift/client-go/route/clientset/versioned" extInformers "github.com/openshift/client-go/route/informers/externalversions" routeInformer "github.com/openshift/client-go/route/informers/externalversions/route/v1" log "github.com/sirupsen/logrus" @@ -208,14 +208,11 @@ func (ors *ocpRouteSource) filterByAnnotations(ocpRoutes []*routev1.Route) ([]*r return ocpRoutes, nil } - filteredList := []*routev1.Route{} + var filteredList []*routev1.Route for _, ocpRoute := range ocpRoutes { - // convert the Route's annotations to an equivalent label selector - annotations := labels.Set(ocpRoute.Annotations) - // include ocpRoute if its annotations match the selector - if selector.Matches(annotations) { + if selector.Matches(labels.Set(ocpRoute.Annotations)) { filteredList = append(filteredList, ocpRoute) } } diff --git a/source/service.go b/source/service.go index e0f38c69a..6cbdcf0db 100644 --- a/source/service.go +++ b/source/service.go @@ -434,14 +434,11 @@ func (sc *serviceSource) filterByAnnotations(services []*v1.Service) ([]*v1.Serv return services, nil } - filteredList := []*v1.Service{} + var filteredList []*v1.Service for _, service := range services { - // convert the service's annotations to an equivalent label selector - annotations := labels.Set(service.Annotations) - // include service if its annotations match the selector - if selector.Matches(annotations) { + if selector.Matches(labels.Set(service.Annotations)) { filteredList = append(filteredList, service) } } @@ -504,9 +501,9 @@ func (sc *serviceSource) generateEndpoints(svc *v1.Service, hostname string, pro targets = extractServiceExternalName(svc) } - for _, endpoint := range endpoints { - endpoint.ProviderSpecific = providerSpecific - endpoint.SetIdentifier = setIdentifier + for _, en := range endpoints { + en.ProviderSpecific = providerSpecific + en.SetIdentifier = setIdentifier } } diff --git a/source/source.go b/source/source.go index 4f0b69d42..5e9174320 100644 --- a/source/source.go +++ b/source/source.go @@ -89,10 +89,10 @@ type Source interface { AddEventHandler(context.Context, func()) } -func getTTLFromAnnotations(annotations map[string]string, resource string) endpoint.TTL { +func getTTLFromAnnotations(ants map[string]string, resource string) endpoint.TTL { ttlNotConfigured := endpoint.TTL(0) - ttlAnnotation, exists := annotations[ttlAnnotationKey] - if !exists { + ttlAnnotation, ok := ants[ttlAnnotationKey] + if !ok { return ttlNotConfigured } ttlValue, err := parseTTL(ttlAnnotation) @@ -171,9 +171,9 @@ func getEndpointsTypeFromAnnotations(annotations map[string]string) string { return annotations[endpointsTypeAnnotationKey] } -func getInternalHostnamesFromAnnotations(annotations map[string]string) []string { - internalHostnameAnnotation, exists := annotations[internalHostnameAnnotationKey] - if !exists { +func getInternalHostnamesFromAnnotations(ants map[string]string) []string { + internalHostnameAnnotation, ok := ants[internalHostnameAnnotationKey] + if !ok { return nil } return splitHostnameAnnotation(internalHostnameAnnotation) @@ -183,40 +183,40 @@ func splitHostnameAnnotation(annotation string) []string { return strings.Split(strings.ReplaceAll(annotation, " ", ""), ",") } -func getAliasFromAnnotations(annotations map[string]string) bool { - aliasAnnotation, exists := annotations[aliasAnnotationKey] +func getAliasFromAnnotations(ants map[string]string) bool { + aliasAnnotation, exists := ants[aliasAnnotationKey] return exists && aliasAnnotation == "true" } -func getProviderSpecificAnnotations(annotations map[string]string) (endpoint.ProviderSpecific, string) { +func getProviderSpecificAnnotations(ants map[string]string) (endpoint.ProviderSpecific, string) { providerSpecificAnnotations := endpoint.ProviderSpecific{} - if v, exists := annotations[CloudflareProxiedKey]; exists { + if v, exists := ants[CloudflareProxiedKey]; exists { providerSpecificAnnotations = append(providerSpecificAnnotations, endpoint.ProviderSpecificProperty{ Name: CloudflareProxiedKey, Value: v, }) } - if v, exists := annotations[CloudflareCustomHostnameKey]; exists { + if v, exists := ants[CloudflareCustomHostnameKey]; exists { providerSpecificAnnotations = append(providerSpecificAnnotations, endpoint.ProviderSpecificProperty{ Name: CloudflareCustomHostnameKey, Value: v, }) } - if v, exists := annotations[CloudflareRegionKey]; exists { + if v, exists := ants[CloudflareRegionKey]; exists { providerSpecificAnnotations = append(providerSpecificAnnotations, endpoint.ProviderSpecificProperty{ Name: CloudflareRegionKey, Value: v, }) } - if getAliasFromAnnotations(annotations) { + if getAliasFromAnnotations(ants) { providerSpecificAnnotations = append(providerSpecificAnnotations, endpoint.ProviderSpecificProperty{ Name: "alias", Value: "true", }) } setIdentifier := "" - for k, v := range annotations { + for k, v := range ants { if k == SetIdentifierKey { setIdentifier = v } else if strings.HasPrefix(k, "external-dns.alpha.kubernetes.io/aws-") { @@ -346,8 +346,7 @@ func getLabelSelector(annotationFilter string) (labels.Selector, error) { } func matchLabelSelector(selector labels.Selector, srcAnnotations map[string]string) bool { - annotations := labels.Set(srcAnnotations) - return selector.Matches(annotations) + return selector.Matches(labels.Set(srcAnnotations)) } type eventHandlerFunc func() diff --git a/source/traefik_proxy.go b/source/traefik_proxy.go index 3a07ac91b..1fd919a45 100644 --- a/source/traefik_proxy.go +++ b/source/traefik_proxy.go @@ -554,11 +554,8 @@ func (ts *traefikSource) filterIngressRouteByAnnotation(ingressRoutes []*Ingress filteredList := []*IngressRoute{} for _, ingressRoute := range ingressRoutes { - // convert the IngressRoute's annotations to an equivalent label selector - annotations := labels.Set(ingressRoute.Annotations) - // include IngressRoute if its annotations match the selector - if selector.Matches(annotations) { + if selector.Matches(labels.Set(ingressRoute.Annotations)) { filteredList = append(filteredList, ingressRoute) } } @@ -582,14 +579,11 @@ func (ts *traefikSource) filterIngressRouteTcpByAnnotations(ingressRoutes []*Ing return ingressRoutes, nil } - filteredList := []*IngressRouteTCP{} + var filteredList []*IngressRouteTCP for _, ingressRoute := range ingressRoutes { - // convert the IngressRoute's annotations to an equivalent label selector - annotations := labels.Set(ingressRoute.Annotations) - // include IngressRoute if its annotations match the selector - if selector.Matches(annotations) { + if selector.Matches(labels.Set(ingressRoute.Annotations)) { filteredList = append(filteredList, ingressRoute) } } @@ -613,14 +607,11 @@ func (ts *traefikSource) filterIngressRouteUdpByAnnotations(ingressRoutes []*Ing return ingressRoutes, nil } - filteredList := []*IngressRouteUDP{} + var filteredList []*IngressRouteUDP for _, ingressRoute := range ingressRoutes { - // convert the IngressRoute's annotations to an equivalent label selector - annotations := labels.Set(ingressRoute.Annotations) - // include IngressRoute if its annotations match the selector - if selector.Matches(annotations) { + if selector.Matches(labels.Set(ingressRoute.Annotations)) { filteredList = append(filteredList, ingressRoute) } } From e22c451744c5ec4f35c99929022f7366eea53c29 Mon Sep 17 00:00:00 2001 From: ivan katliarchuk Date: Sat, 10 May 2025 13:23:16 +0100 Subject: [PATCH 38/42] feat(code-quality): source/pod improve code coverage Signed-off-by: ivan katliarchuk --- source/pod.go | 2 +- source/pod_test.go | 309 +++++++++++++++++---------------------------- 2 files changed, 117 insertions(+), 194 deletions(-) diff --git a/source/pod.go b/source/pod.go index 3a34a985b..8c77e6ed2 100644 --- a/source/pod.go +++ b/source/pod.go @@ -161,7 +161,7 @@ func (ps *podSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error } } } - endpoints := []*endpoint.Endpoint{} + var endpoints []*endpoint.Endpoint for key, targets := range endpointMap { endpoints = append(endpoints, endpoint.NewEndpoint(key.DNSName, key.RecordType, targets...)) } diff --git a/source/pod_test.go b/source/pod_test.go index 8429ad7b1..7d41a1f4d 100644 --- a/source/pod_test.go +++ b/source/pod_test.go @@ -23,8 +23,9 @@ import ( "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes/fake" "sigs.k8s.io/external-dns/endpoint" + + "k8s.io/client-go/kubernetes/fake" ) // testPodSource tests that various services generate the correct endpoints. @@ -53,30 +54,7 @@ func TestPodSource(t *testing.T) { {DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"10.0.1.1", "10.0.1.2"}, RecordType: endpoint.RecordTypeA}, }, false, - []*corev1.Node{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "my-node1", - }, - Status: corev1.NodeStatus{ - Addresses: []corev1.NodeAddress{ - {Type: corev1.NodeExternalIP, Address: "54.10.11.1"}, - {Type: corev1.NodeInternalIP, Address: "10.0.1.1"}, - }, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "my-node2", - }, - Status: corev1.NodeStatus{ - Addresses: []corev1.NodeAddress{ - {Type: corev1.NodeExternalIP, Address: "54.10.11.2"}, - {Type: corev1.NodeInternalIP, Address: "10.0.1.2"}, - }, - }, - }, - }, + nodesFixturesIPv4(), []*corev1.Pod{ { ObjectMeta: metav1.ObjectMeta{ @@ -125,30 +103,7 @@ func TestPodSource(t *testing.T) { {DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"10.0.1.1", "10.0.1.2"}, RecordType: endpoint.RecordTypeA}, }, false, - []*corev1.Node{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "my-node1", - }, - Status: corev1.NodeStatus{ - Addresses: []corev1.NodeAddress{ - {Type: corev1.NodeExternalIP, Address: "54.10.11.1"}, - {Type: corev1.NodeInternalIP, Address: "10.0.1.1"}, - }, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "my-node2", - }, - Status: corev1.NodeStatus{ - Addresses: []corev1.NodeAddress{ - {Type: corev1.NodeExternalIP, Address: "54.10.11.2"}, - {Type: corev1.NodeInternalIP, Address: "10.0.1.2"}, - }, - }, - }, - }, + nodesFixturesIPv4(), []*corev1.Pod{ { ObjectMeta: metav1.ObjectMeta{ @@ -197,28 +152,7 @@ func TestPodSource(t *testing.T) { {DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"2001:DB8::1", "2001:DB8::2"}, RecordType: endpoint.RecordTypeAAAA}, }, false, - []*corev1.Node{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "my-node1", - }, - Status: corev1.NodeStatus{ - Addresses: []corev1.NodeAddress{ - {Type: corev1.NodeInternalIP, Address: "2001:DB8::1"}, - }, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "my-node2", - }, - Status: corev1.NodeStatus{ - Addresses: []corev1.NodeAddress{ - {Type: corev1.NodeInternalIP, Address: "2001:DB8::2"}, - }, - }, - }, - }, + nodesFixturesIPv6(), []*corev1.Pod{ { ObjectMeta: metav1.ObjectMeta{ @@ -267,28 +201,7 @@ func TestPodSource(t *testing.T) { {DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"2001:DB8::1", "2001:DB8::2"}, RecordType: endpoint.RecordTypeAAAA}, }, false, - []*corev1.Node{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "my-node1", - }, - Status: corev1.NodeStatus{ - Addresses: []corev1.NodeAddress{ - {Type: corev1.NodeInternalIP, Address: "2001:DB8::1"}, - }, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "my-node2", - }, - Status: corev1.NodeStatus{ - Addresses: []corev1.NodeAddress{ - {Type: corev1.NodeInternalIP, Address: "2001:DB8::2"}, - }, - }, - }, - }, + nodesFixturesIPv6(), []*corev1.Pod{ { ObjectMeta: metav1.ObjectMeta{ @@ -337,30 +250,7 @@ func TestPodSource(t *testing.T) { {DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"208.1.2.1", "208.1.2.2"}, RecordType: endpoint.RecordTypeA}, }, false, - []*corev1.Node{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "my-node1", - }, - Status: corev1.NodeStatus{ - Addresses: []corev1.NodeAddress{ - {Type: corev1.NodeExternalIP, Address: "54.10.11.1"}, - {Type: corev1.NodeInternalIP, Address: "10.0.1.1"}, - }, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "my-node2", - }, - Status: corev1.NodeStatus{ - Addresses: []corev1.NodeAddress{ - {Type: corev1.NodeExternalIP, Address: "54.10.11.2"}, - {Type: corev1.NodeInternalIP, Address: "10.0.1.2"}, - }, - }, - }, - }, + nodesFixturesIPv4(), []*corev1.Pod{ { ObjectMeta: metav1.ObjectMeta{ @@ -483,30 +373,7 @@ func TestPodSource(t *testing.T) { {DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"10.0.1.1"}, RecordType: endpoint.RecordTypeA}, }, false, - []*corev1.Node{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "my-node1", - }, - Status: corev1.NodeStatus{ - Addresses: []corev1.NodeAddress{ - {Type: corev1.NodeExternalIP, Address: "54.10.11.1"}, - {Type: corev1.NodeInternalIP, Address: "10.0.1.1"}, - }, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "my-node2", - }, - Status: corev1.NodeStatus{ - Addresses: []corev1.NodeAddress{ - {Type: corev1.NodeExternalIP, Address: "54.10.11.2"}, - {Type: corev1.NodeInternalIP, Address: "10.0.1.2"}, - }, - }, - }, - }, + nodesFixturesIPv4(), []*corev1.Pod{ { ObjectMeta: metav1.ObjectMeta{ @@ -555,30 +422,7 @@ func TestPodSource(t *testing.T) { {DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"10.0.1.1"}, RecordType: endpoint.RecordTypeA}, }, false, - []*corev1.Node{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "my-node1", - }, - Status: corev1.NodeStatus{ - Addresses: []corev1.NodeAddress{ - {Type: corev1.NodeExternalIP, Address: "54.10.11.1"}, - {Type: corev1.NodeInternalIP, Address: "10.0.1.1"}, - }, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "my-node2", - }, - Status: corev1.NodeStatus{ - Addresses: []corev1.NodeAddress{ - {Type: corev1.NodeExternalIP, Address: "54.10.11.2"}, - {Type: corev1.NodeInternalIP, Address: "10.0.1.2"}, - }, - }, - }, - }, + nodesFixturesIPv4(), []*corev1.Pod{ { ObjectMeta: metav1.ObjectMeta{ @@ -669,30 +513,7 @@ func TestPodSource(t *testing.T) { {DNSName: "my-pod2.example.org", Targets: endpoint.Targets{"192.168.1.2"}, RecordType: endpoint.RecordTypeA}, }, false, - []*corev1.Node{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "my-node1", - }, - Status: corev1.NodeStatus{ - Addresses: []corev1.NodeAddress{ - {Type: corev1.NodeExternalIP, Address: "54.10.11.1"}, - {Type: corev1.NodeInternalIP, Address: "10.0.1.1"}, - }, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "my-node2", - }, - Status: corev1.NodeStatus{ - Addresses: []corev1.NodeAddress{ - {Type: corev1.NodeExternalIP, Address: "54.10.11.2"}, - {Type: corev1.NodeInternalIP, Address: "10.0.1.2"}, - }, - }, - }, - }, + nodesFixturesIPv4(), []*corev1.Pod{ { ObjectMeta: metav1.ObjectMeta{ @@ -724,13 +545,65 @@ func TestPodSource(t *testing.T) { }, }, }, + { + "create records based on pod's target annotation with pod source domain", + "", + "", + true, + "example.org", + []*endpoint.Endpoint{ + {DNSName: "my-pod1.example.org", Targets: endpoint.Targets{"208.1.2.1"}, RecordType: endpoint.RecordTypeA}, + {DNSName: "my-pod2.example.org", Targets: endpoint.Targets{"208.1.2.2"}, RecordType: endpoint.RecordTypeA}, + {DNSName: "a.foo.example.org", Targets: endpoint.Targets{"208.1.2.1", "208.1.2.2"}, RecordType: endpoint.RecordTypeA}, + {DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"208.1.2.1", "208.1.2.2"}, RecordType: endpoint.RecordTypeA}, + }, + false, + nodesFixturesIPv4(), + []*corev1.Pod{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-pod1", + Namespace: "kube-system", + Annotations: map[string]string{ + internalHostnameAnnotationKey: "internal.a.foo.example.org", + hostnameAnnotationKey: "a.foo.example.org", + targetAnnotationKey: "208.1.2.1", + }, + }, + Spec: corev1.PodSpec{ + HostNetwork: true, + NodeName: "my-node1", + }, + Status: corev1.PodStatus{ + PodIP: "10.0.1.1", + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-pod2", + Namespace: "kube-system", + Annotations: map[string]string{ + internalHostnameAnnotationKey: "internal.a.foo.example.org", + hostnameAnnotationKey: "a.foo.example.org", + targetAnnotationKey: "208.1.2.2", + }, + }, + Spec: corev1.PodSpec{ + HostNetwork: true, + NodeName: "my-node2", + }, + Status: corev1.PodStatus{ + PodIP: "10.0.1.2", + }, + }, + }, + }, } { tc := tc t.Run(tc.title, func(t *testing.T) { t.Parallel() - // Create a Kubernetes testing client - kubernetes := fake.NewSimpleClientset() + kubernetes := fake.NewClientset() ctx := context.Background() // Create the nodes @@ -757,10 +630,60 @@ func TestPodSource(t *testing.T) { } else { require.NoError(t, err) } - // Validate returned endpoints against desired endpoints. validateEndpoints(t, endpoints, tc.expected) }) - + } +} + +func nodesFixturesIPv6() []*corev1.Node { + return []*corev1.Node{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-node1", + }, + Status: corev1.NodeStatus{ + Addresses: []corev1.NodeAddress{ + {Type: corev1.NodeInternalIP, Address: "2001:DB8::1"}, + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-node2", + }, + Status: corev1.NodeStatus{ + Addresses: []corev1.NodeAddress{ + {Type: corev1.NodeInternalIP, Address: "2001:DB8::2"}, + }, + }, + }, + } +} + +func nodesFixturesIPv4() []*corev1.Node { + return []*corev1.Node{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-node1", + }, + Status: corev1.NodeStatus{ + Addresses: []corev1.NodeAddress{ + {Type: corev1.NodeExternalIP, Address: "54.10.11.1"}, + {Type: corev1.NodeInternalIP, Address: "10.0.1.1"}, + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-node2", + }, + Status: corev1.NodeStatus{ + Addresses: []corev1.NodeAddress{ + {Type: corev1.NodeExternalIP, Address: "54.10.11.2"}, + {Type: corev1.NodeInternalIP, Address: "10.0.1.2"}, + }, + }, + }, } } From 51d063ad289e99da2aa6aa16b7c057598e5ecd1f Mon Sep 17 00:00:00 2001 From: Ivan Ka <5395690+ivankatliarchuk@users.noreply.github.com> Date: Sat, 10 May 2025 13:53:22 +0100 Subject: [PATCH 39/42] chore(fqdn-template): fqdn templating move to specific folder and update documentation (#5354) * chore(fqdn): fqdn move to specific folder and update documentation * chore(fqdn): fqdn move to specific folder and update documentation Co-authored-by: Michel Loiseleur <97035654+mloiseleur@users.noreply.github.com> * chore(fqdn): fqdn move to specific folder and update documentation Signed-off-by: ivan katliarchuk * chore(fqdn): fqdn move to specific folder and update documentation Signed-off-by: ivan katliarchuk * chore(fqdn): fqdn move to specific folder and update documentation Signed-off-by: ivan katliarchuk --------- Signed-off-by: ivan katliarchuk Co-authored-by: Michel Loiseleur <97035654+mloiseleur@users.noreply.github.com> --- .../tests/deployment-flags_test.yaml | 1 - docs/advanced/fqdn-templating.md | 306 ++++++++++++++++++ docs/{ => advanced}/nat64.md | 0 docs/{ => advanced}/rate-limits.md | 0 docs/{ => advanced}/ttl.md | 0 docs/faq.md | 4 - mkdocs.yml | 7 +- scripts/helm-tools.sh | 2 +- source/contour_httpproxy.go | 4 +- source/fqdn/fqdn.go | 32 ++ source/fqdn/fqdn_test.go | 73 +++++ source/gateway.go | 3 +- source/ingress.go | 3 +- source/istio_gateway.go | 4 +- source/istio_virtualservice.go | 3 +- source/node.go | 3 +- source/openshift_route.go | 3 +- source/service.go | 3 +- source/skipper_routegroup.go | 3 +- source/skipper_routegroup_test.go | 54 +--- source/source.go | 10 - 21 files changed, 438 insertions(+), 80 deletions(-) create mode 100644 docs/advanced/fqdn-templating.md rename docs/{ => advanced}/nat64.md (100%) rename docs/{ => advanced}/rate-limits.md (100%) rename docs/{ => advanced}/ttl.md (100%) create mode 100644 source/fqdn/fqdn.go create mode 100644 source/fqdn/fqdn_test.go diff --git a/charts/external-dns/tests/deployment-flags_test.yaml b/charts/external-dns/tests/deployment-flags_test.yaml index 97e89a451..5b86502f8 100644 --- a/charts/external-dns/tests/deployment-flags_test.yaml +++ b/charts/external-dns/tests/deployment-flags_test.yaml @@ -164,4 +164,3 @@ tests: asserts: - failedTemplate: errorMessage: "'txtPrefix' and 'txtSuffix' are mutually exclusive" - diff --git a/docs/advanced/fqdn-templating.md b/docs/advanced/fqdn-templating.md new file mode 100644 index 000000000..531eb8bcc --- /dev/null +++ b/docs/advanced/fqdn-templating.md @@ -0,0 +1,306 @@ +# FQDN Templating Guide + +## What is FQDN Templating? + +**FQDN templating** is a feature that allows to dynamically construct Fully Qualified Domain Names (FQDNs) using a Go templating engine. +Instead of relying solely on annotations or static names, you can use metadata from Kubernetes objects—such as service names, namespaces, and labels—to generate DNS records programmatically and dynamically. + +This is useful for: + +- Creating consistent naming conventions across environments. +- Reducing boilerplate annotations. +- Supporting multi-tenant or dynamic environments. +- Migrating from one DNS scheme to another +- Supporting multiple variants, such as a regional one and then one that doesn't or similar. + +## How It Works + +ExternalDNS has a flag: `--fqdn-template`, which defines a Go template for rendering the desired DNS names. + +The template uses the following data from the source object (e.g., a `Service` or `Ingress`): + +| Field | Description | +|:--------------|:------------------------------------------------------------------| +| `Name` | Name of the object (e.g., service) | +| `Namespace` | Namespace of the object | +| `Labels` | Map of labels applied to the object | +| `Annotations` | Map of annotations | +| `TargetName` | For `Service`, it's the service name; for `Ingress`, the hostname | +| `Endpoint` | Contains more contextual endpoint info, such as IP/target | +| `Controller` | Controller type (optional) | + +## Supported Sources + + + +| Source | Description | FQDN Supported | +|:-----------------------|:----------------------------------------------------------------|:--------------:| +| `ambassador-host` | Queries Ambassador Host resources for endpoints. | ❌ | +| `cloudfoundry` | Queries Cloud Foundry resources for endpoints. | ❌ | +| `connector` | Queries a custom connector source for endpoints. | ❌ | +| `contour-httpproxy` | Queries Contour HTTPProxy resources for endpoints. | ✅ | +| `crd` | Queries Custom Resource Definitions (CRDs) for endpoints. | ❌ | +| `empty` | Uses an empty source, typically for testing or no-op scenarios. | ❌ | +| `f5-transportserver` | Queries F5 TransportServer resources for endpoints. | ❌ | +| `f5-virtualserver` | Queries F5 VirtualServer resources for endpoints. | ❌ | +| `fake` | Uses a fake source for testing purposes. | ❌ | +| `gateway-grpcroute` | Queries GRPCRoute resources from the Gateway API. | ✅ | +| `gateway-httproute` | Queries HTTPRoute resources from the Gateway API. | ✅ | +| `gateway-tcproute` | Queries TCPRoute resources from the Gateway API. | ✅ | +| `gateway-tlsroute` | Queries TLSRoute resources from the Gateway API. | ❌ | +| `gateway-udproute` | Queries UDPRoute resources from the Gateway API. | ❌ | +| `gloo-proxy` | Queries Gloo Proxy resources for endpoints. | ❌ | +| `ingress` | Queries Kubernetes Ingress resources for endpoints. | ✅ | +| `istio-gateway` | Queries Istio Gateway resources for endpoints. | ✅ | +| `istio-virtualservice` | Queries Istio VirtualService resources for endpoints. | ✅ | +| `kong-tcpingress` | Queries Kong TCPIngress resources for endpoints. | ❌ | +| `node` | Queries Kubernetes Node resources for endpoints. | ✅ | +| `openshift-route` | Queries OpenShift Route resources for endpoints. | ✅ | +| `pod` | Queries Kubernetes Pod resources for endpoints. | ❌ | +| `service` | Queries Kubernetes Service resources for endpoints. | ✅ | +| `skipper-routegroup` | Queries Skipper RouteGroup resources for endpoints. | ✅ | +| `traefik-proxy` | Queries Traefik Proxy resources for endpoints. | ❌ | + +## Custom Functions + + + +| Function | Description | +|:-------------|:-----------------------------------------------------------------------------------------| +| `trimPrefix` | Function from the `strings` package. Returns `string` without the provided leading prefix. | + +--- + +## Example Usage + +> These examples should provide a solid foundation for implementing FQDN templating in your ExternalDNS setup. +> If you have specific requirements or encounter issues, feel free to explore the issues or update this guide. + +### Basic Usage + +```yml +apiVersion: v1 +kind: Service +metadata: + name: my-service + namespace: my-namespace +``` + +```sh +external-dns \ + --provider=aws \ + --source=service \ + --fqdn-template="{{ .Name }}.example.com,{{ .Name }}.{{ .Namespace }}.example.tld" + +# This will result in DNS entries like +>route53> my-service.example.com +>route53> my-service.my-namespace.example.tld +``` + +### With Namespace + +```yml +--- +apiVersion: v1 +kind: Service +metadata: + name: my-service + namespace: default +--- +apiVersion: v1 +kind: Service +metadata: + name: other-service + namespace: kube-system +``` + +```yml +args: + --fqdn-template="{{.Name}}.{{.Namespace}}.example.com" + +# This will result in DNS entries like +# route53> my-service.default.example.com +# route53> other-service.kube-system.example.com +``` + +### Using Labels in Templates + +You can also utilize labels in your FQDN templates to create more dynamic DNS entries. Assuming your service has: + +```yml +apiVersion: v1 +kind: Service +metadata: + name: my-service + labels: + environment: staging +``` + +```yml +args: + --fqdn-template="{{ .Labels.environment }}.{{ .Name }}.example.com" + +# This will result in DNS entries like +# route53> staging.my-service.example.com +``` + +### Multiple FQDN Templates + +ExternalDNS allows specifying multiple FQDN templates, which can be useful when you want to create multiple DNS entries for a single service or ingress. + +> Be cautious, as this will create multiple DNS records per resource, potentially increasing the number of API calls to your DNS provider. + +```yml +args: + --fqdn-template={{.Name}}.example.com,{{.Name}}.svc.example.com +``` + +### Conditional Templating combined with Annotations processing + +In scenarios where you want to conditionally generate FQDNs based on annotations, you can use Go template functions like or to provide defaults. + +```yml +args: + - --combine-fqdn-annotation # this is required to combine FQDN templating and annotation processing + - --fqdn-template={{ or .Annotations.dns "invalid" }}.example.com + - --exclude-domains=invalid.example.com +``` + +### Using Annotations for FQDN Templating + +This example demonstrates how to use annotations in Kubernetes objects to dynamically generate Fully Qualified Domain Names (FQDNs) using the --fqdn-template flag in ExternalDNS. + +The Service object includes an annotation dns.company.com/label with the value my-org-tld-v2. This annotation is used as part of the FQDN template to construct the DNS name. + +```yml +apiVersion: v1 +kind: Service +metadata: + name: nginx-v2 + namespace: my-namespace + annotations: + dns.company.com/label: my-org-tld-v2 +spec: + type: ClusterIP + clusterIP: None +``` + +The --fqdn-template flag is configured to use the annotation value (dns.company.com/label) and append the namespace and a custom domain (company.local) to generate the FQDN. + +```yml +args: + --source=service + --fqdn-template='{{ index .ObjectMeta.Annotations "dns.company.com/label" }}.{{ .Namespace }}.company.local' + +# For the given Service object, the resulting FQDN will be: +# route53> my-org-tld-v2.my-namespace.company.local +``` + +### DNS Scheme Migration + +If you're transitioning from one naming convention to another (e.g., from svc.cluster.local to svc.example.com), --fqdn-template allows you to generate the new records alongside or in place of the old ones — without requiring changes to your Kubernetes manifests. + +```yml +args: +- --fqdn-template='{{.Name}}.new-dns.example.com' +``` + +This helps automate DNS record migration while maintaining service continuity. + +### Multi-Variant Domain Support + +You can also support regional variants or multi-tenant architectures, where the same service is deployed to different regions or environments: + +```yaml +--fqdn-template='{{ .Name }}.{{ .Labels.env }}.{{ .Labels.region }}.example.com, {{ if eq .Labels.env "prod" }}{{ .Name }}.my-company.tld{{ end }}' +``` + +With additional context (e.g., annotations), this can produce FQDNs like: + +```yml +api.prod.us-east-1.example.com +api.my-company.tld +``` + +This is helpful in scenarios such as: + +- Blue/green deployments across domains +- Staging vs. production resolution +- Multi-cloud or multi-region failover strategies + +## Tips + +- If `--fqdn-template` is specified, ExternalDNS ignores any `external-dns.alpha.kubernetes.io/hostname` annotations. +- You must still ensure the resulting FQDN is valid and unique. +- Since Go templates can be error-prone, test your template with simple examples before deploying. Mismatched field names or nil values (e.g., missing labels) will result in errors or skipped entries. + +## FaQ + +### Can I specify multiple global FQDN templates? + +Yes, you can. Pass in a comma separated list to --fqdn-template. Beware this will double (triple, etc) the amount of DNS entries based on how many services, ingresses and so on you have and will get you faster towards the API request limit of your DNS provider. + +### Where to find template syntax + +- [Go template syntax](https://pkg.go.dev/text/template) +- [Go func builtins](https://github.com/golang/go/blob/master/src/text/template/funcs.go#L39-L63) + +### FQDN Templating, Helm and improper templating syntax + +The user encountered errors due to improper templating syntax: + +```yml +extraArgs: + - --fqdn-template={{name}}.uat.example.com +``` + +The correct syntax should include a dot prefix: `{{ .Name }}`. +Additionally, when using Helm's `tpl` function, it's necessary to escape the braces to prevent premature evaluation: + +```yml +extraArgs: + - --fqdn-template={{ `{{ .Name }}.uat.example.com` }} +``` + +### Handling Subdomain-Only Hostnames + +In [Issue #1872](https://github.com/kubernetes-sigs/external-dns/issues/1872), it was observed that ExternalDNS ignores the `--fqdn-template` when the ingress host field is set to a subdomain (e.g., foo) without a full domain. +The expectation was that the template would still apply, generating entries like `foo.bar.example.com.` +This highlights a limitation to be aware of when designing FQDN templates. + +> :warning: This is currently not supported ! User would expect external-dns to generate a dns record according to the fqdnTemplate +> e.g. if the ingress name: foo and host: foo is created while fqdnTemplate={{.Name}}.bar.example.com then a dns record foo.bar.example.com should be created + +```yml +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: foo +spec: + rules: + - host: foo + http: + paths: + - backend: + serviceName: foo + servicePort: 80 + path: / +``` + +### Combining FQDN Template with Annotations + +In [Issue #3318](https://github.com/kubernetes-sigs/external-dns/issues/3318), a question was raised about the interaction between --fqdn-template and --combine-fqdn-annotation. +The discussion clarified that when both flags are used, ExternalDNS combines the FQDN generated from the template with the annotation value, providing flexibility in DNS name construction. + +### Using Annotations for Dynamic FQDNs + +In [Issue #2627](https://github.com/kubernetes-sigs/external-dns/issues/2627), a user aimed to generate DNS entries based on ingress annotations: + +```yml +args: + - --fqdn-template={{.Annotations.hostname}}.example.com + - --combine-fqdn-annotation + - --domain-filter=example.com +``` + +By setting the hostname annotation in the ingress resource, ExternalDNS constructs the FQDN accordingly. This approach allows for dynamic DNS entries without hardcoding hostnames. diff --git a/docs/nat64.md b/docs/advanced/nat64.md similarity index 100% rename from docs/nat64.md rename to docs/advanced/nat64.md diff --git a/docs/rate-limits.md b/docs/advanced/rate-limits.md similarity index 100% rename from docs/rate-limits.md rename to docs/advanced/rate-limits.md diff --git a/docs/ttl.md b/docs/advanced/ttl.md similarity index 100% rename from docs/ttl.md rename to docs/advanced/ttl.md diff --git a/docs/faq.md b/docs/faq.md index 5ac1e86ec..76256bd7d 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -50,10 +50,6 @@ There are three sources of information for ExternalDNS to decide on DNS name. Ex 3. If `--fqdn-template` flag is specified, e.g. `--fqdn-template={{.Name}}.my-org.com`, ExternalDNS will use service/ingress specifications for the provided template to generate DNS name. -## Can I specify multiple global FQDN templates? - -Yes, you can. Pass in a comma separated list to `--fqdn-template`. Beaware this will double (triple, etc) the amount of DNS entries based on how many services, ingresses and so on you have and will get you faster towards the API request limit of your DNS provider. - ## Which Service and Ingress controllers are supported? Regarding Services, we'll support the OSI Layer 4 load balancers that Kubernetes creates on AWS and Google Kubernetes Engine, and possibly other clusters running on Google Compute Engine. diff --git a/mkdocs.yml b/mkdocs.yml index b491f7836..ed0bbd5e6 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -29,9 +29,10 @@ nav: - Leader Election: docs/proposal/001-leader-election.md - Monitoring: docs/monitoring/* - MultiTarget: docs/proposal/multi-target.md - - NAT64: docs/nat64.md - - Rate Limits: docs/rate-limits.md - - TTL: docs/ttl.md + - NAT64: docs/advanced/nat64.md + - Rate Limits: docs/advanced/rate-limits.md + - TTL: docs/advanced/ttl.md + - FQDN Templating: docs/advanced/fqdn-templating.md - Contributing: - Kubernetes Contributions: CONTRIBUTING.md - Release: docs/release. diff --git a/scripts/helm-tools.sh b/scripts/helm-tools.sh index 0d635a6ca..825a22c84 100755 --- a/scripts/helm-tools.sh +++ b/scripts/helm-tools.sh @@ -116,7 +116,7 @@ function main() { helm_unittest ;; --helm-template) - helm_unittest + helm_template ;; -d|--diff) diff_schema diff --git a/source/contour_httpproxy.go b/source/contour_httpproxy.go index 823b91e33..8a86aa44d 100644 --- a/source/contour_httpproxy.go +++ b/source/contour_httpproxy.go @@ -33,6 +33,8 @@ import ( "k8s.io/client-go/informers" "k8s.io/client-go/tools/cache" + "sigs.k8s.io/external-dns/source/fqdn" + "sigs.k8s.io/external-dns/endpoint" ) @@ -60,7 +62,7 @@ func NewContourHTTPProxySource( combineFqdnAnnotation bool, ignoreHostnameAnnotation bool, ) (Source, error) { - tmpl, err := parseTemplate(fqdnTemplate) + tmpl, err := fqdn.ParseTemplate(fqdnTemplate) if err != nil { return nil, err } diff --git a/source/fqdn/fqdn.go b/source/fqdn/fqdn.go new file mode 100644 index 000000000..50fc16f6f --- /dev/null +++ b/source/fqdn/fqdn.go @@ -0,0 +1,32 @@ +/* +Copyright 2025 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 fqdn + +import ( + "strings" + "text/template" +) + +func ParseTemplate(fqdnTemplate string) (tmpl *template.Template, err error) { + if fqdnTemplate == "" { + return nil, nil + } + funcs := template.FuncMap{ + "trimPrefix": strings.TrimPrefix, + } + return template.New("endpoint").Funcs(funcs).Parse(fqdnTemplate) +} diff --git a/source/fqdn/fqdn_test.go b/source/fqdn/fqdn_test.go new file mode 100644 index 000000000..d135bad82 --- /dev/null +++ b/source/fqdn/fqdn_test.go @@ -0,0 +1,73 @@ +/* +Copyright 2025 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 fqdn + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestParseTemplate(t *testing.T) { + for _, tt := range []struct { + name string + annotationFilter string + fqdnTemplate string + combineFQDNAndAnnotation bool + expectError bool + }{ + { + name: "invalid template", + expectError: true, + fqdnTemplate: "{{.Name", + }, + { + name: "valid empty template", + expectError: false, + }, + { + name: "valid template", + expectError: false, + fqdnTemplate: "{{.Name}}-{{.Namespace}}.ext-dns.test.com", + }, + { + name: "valid template", + expectError: false, + fqdnTemplate: "{{.Name}}-{{.Namespace}}.ext-dns.test.com, {{.Name}}-{{.Namespace}}.ext-dna.test.com", + }, + { + name: "valid template", + expectError: false, + fqdnTemplate: "{{.Name}}-{{.Namespace}}.ext-dns.test.com, {{.Name}}-{{.Namespace}}.ext-dna.test.com", + combineFQDNAndAnnotation: true, + }, + { + name: "non-empty annotation filter label", + expectError: false, + annotationFilter: "kubernetes.io/ingress.class=nginx", + }, + } { + t.Run(tt.name, func(t *testing.T) { + _, err := ParseTemplate(tt.fqdnTemplate) + if tt.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} diff --git a/source/gateway.go b/source/gateway.go index 77203819b..c903ccaef 100644 --- a/source/gateway.go +++ b/source/gateway.go @@ -40,6 +40,7 @@ import ( informers_v1beta1 "sigs.k8s.io/gateway-api/pkg/client/informers/externalversions/apis/v1beta1" "sigs.k8s.io/external-dns/endpoint" + "sigs.k8s.io/external-dns/source/fqdn" ) const ( @@ -117,7 +118,7 @@ func newGatewayRouteSource(clients ClientGenerator, config *Config, kind string, if err != nil { return nil, err } - tmpl, err := parseTemplate(config.FQDNTemplate) + tmpl, err := fqdn.ParseTemplate(config.FQDNTemplate) if err != nil { return nil, err } diff --git a/source/ingress.go b/source/ingress.go index df0a39c9c..1a63b99a8 100644 --- a/source/ingress.go +++ b/source/ingress.go @@ -34,6 +34,7 @@ import ( "k8s.io/client-go/tools/cache" "sigs.k8s.io/external-dns/endpoint" + "sigs.k8s.io/external-dns/source/fqdn" ) const ( @@ -64,7 +65,7 @@ type ingressSource struct { // NewIngressSource creates a new ingressSource with the given config. func NewIngressSource(ctx context.Context, kubeClient kubernetes.Interface, namespace, annotationFilter string, fqdnTemplate string, combineFqdnAnnotation bool, ignoreHostnameAnnotation bool, ignoreIngressTLSSpec bool, ignoreIngressRulesSpec bool, labelSelector labels.Selector, ingressClassNames []string) (Source, error) { - tmpl, err := parseTemplate(fqdnTemplate) + tmpl, err := fqdn.ParseTemplate(fqdnTemplate) if err != nil { return nil, err } diff --git a/source/istio_gateway.go b/source/istio_gateway.go index d158b30a7..08664c091 100644 --- a/source/istio_gateway.go +++ b/source/istio_gateway.go @@ -35,6 +35,8 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/cache" + "sigs.k8s.io/external-dns/source/fqdn" + "sigs.k8s.io/external-dns/endpoint" ) @@ -68,7 +70,7 @@ func NewIstioGatewaySource( combineFQDNAnnotation bool, ignoreHostnameAnnotation bool, ) (Source, error) { - tmpl, err := parseTemplate(fqdnTemplate) + tmpl, err := fqdn.ParseTemplate(fqdnTemplate) if err != nil { return nil, err } diff --git a/source/istio_virtualservice.go b/source/istio_virtualservice.go index 039aa6f3c..83161324a 100644 --- a/source/istio_virtualservice.go +++ b/source/istio_virtualservice.go @@ -37,6 +37,7 @@ import ( "k8s.io/client-go/tools/cache" "sigs.k8s.io/external-dns/endpoint" + "sigs.k8s.io/external-dns/source/fqdn" ) // IstioMeshGateway is the built in gateway for all sidecars @@ -69,7 +70,7 @@ func NewIstioVirtualServiceSource( combineFQDNAnnotation bool, ignoreHostnameAnnotation bool, ) (Source, error) { - tmpl, err := parseTemplate(fqdnTemplate) + tmpl, err := fqdn.ParseTemplate(fqdnTemplate) if err != nil { return nil, err } diff --git a/source/node.go b/source/node.go index a0e426f17..c5dfd37e1 100644 --- a/source/node.go +++ b/source/node.go @@ -31,6 +31,7 @@ import ( "k8s.io/client-go/tools/cache" "sigs.k8s.io/external-dns/endpoint" + "sigs.k8s.io/external-dns/source/fqdn" ) const warningMsg = "The default behavior of exposing internal IPv6 addresses will change in the next minor version. Use --no-expose-internal-ipv6 flag to opt-in to the new behavior." @@ -47,7 +48,7 @@ type nodeSource struct { // NewNodeSource creates a new nodeSource with the given config. func NewNodeSource(ctx context.Context, kubeClient kubernetes.Interface, annotationFilter, fqdnTemplate string, labelSelector labels.Selector, exposeInternalIPv6 bool, excludeUnschedulable bool) (Source, error) { - tmpl, err := parseTemplate(fqdnTemplate) + tmpl, err := fqdn.ParseTemplate(fqdnTemplate) if err != nil { return nil, err } diff --git a/source/openshift_route.go b/source/openshift_route.go index dd50913f6..c6a662bab 100644 --- a/source/openshift_route.go +++ b/source/openshift_route.go @@ -34,6 +34,7 @@ import ( "k8s.io/client-go/tools/cache" "sigs.k8s.io/external-dns/endpoint" + "sigs.k8s.io/external-dns/source/fqdn" ) // ocpRouteSource is an implementation of Source for OpenShift Route objects. @@ -65,7 +66,7 @@ func NewOcpRouteSource( labelSelector labels.Selector, ocpRouterName string, ) (Source, error) { - tmpl, err := parseTemplate(fqdnTemplate) + tmpl, err := fqdn.ParseTemplate(fqdnTemplate) if err != nil { return nil, err } diff --git a/source/service.go b/source/service.go index e0f38c69a..6e8c77408 100644 --- a/source/service.go +++ b/source/service.go @@ -34,6 +34,7 @@ import ( "k8s.io/client-go/tools/cache" "sigs.k8s.io/external-dns/endpoint" + "sigs.k8s.io/external-dns/source/fqdn" ) // serviceSource is an implementation of Source for Kubernetes service objects. @@ -66,7 +67,7 @@ type serviceSource struct { // NewServiceSource creates a new serviceSource with the given config. func NewServiceSource(ctx context.Context, kubeClient kubernetes.Interface, namespace, annotationFilter, fqdnTemplate string, combineFqdnAnnotation bool, compatibility string, publishInternal, publishHostIP, alwaysPublishNotReadyAddresses bool, serviceTypeFilter []string, ignoreHostnameAnnotation bool, labelSelector labels.Selector, resolveLoadBalancerHostname, listenEndpointEvents bool) (Source, error) { - tmpl, err := parseTemplate(fqdnTemplate) + tmpl, err := fqdn.ParseTemplate(fqdnTemplate) if err != nil { return nil, err } diff --git a/source/skipper_routegroup.go b/source/skipper_routegroup.go index 943b98862..98b05ccb2 100644 --- a/source/skipper_routegroup.go +++ b/source/skipper_routegroup.go @@ -36,6 +36,7 @@ import ( log "github.com/sirupsen/logrus" "sigs.k8s.io/external-dns/endpoint" + "sigs.k8s.io/external-dns/source/fqdn" ) const ( @@ -192,7 +193,7 @@ func (cli *routeGroupClient) do(req *http.Request) (*http.Response, error) { // NewRouteGroupSource creates a new routeGroupSource with the given config. func NewRouteGroupSource(timeout time.Duration, token, tokenPath, apiServerURL, namespace, annotationFilter, fqdnTemplate, routegroupVersion string, combineFqdnAnnotation, ignoreHostnameAnnotation bool) (Source, error) { - tmpl, err := parseTemplate(fqdnTemplate) + tmpl, err := fqdn.ParseTemplate(fqdnTemplate) if err != nil { return nil, err } diff --git a/source/skipper_routegroup_test.go b/source/skipper_routegroup_test.go index 03650b3a0..4c68a8724 100644 --- a/source/skipper_routegroup_test.go +++ b/source/skipper_routegroup_test.go @@ -21,8 +21,8 @@ import ( "errors" "testing" - "github.com/stretchr/testify/assert" "sigs.k8s.io/external-dns/endpoint" + "sigs.k8s.io/external-dns/source/fqdn" ) func createTestRouteGroup(ns, name string, annotations map[string]string, hosts []string, destinations []routeGroupLoadBalancer) *routeGroup { @@ -788,7 +788,7 @@ func TestRouteGroupsEndpoints(t *testing.T) { } { t.Run(tt.name, func(t *testing.T) { if tt.fqdnTemplate != "" { - tmpl, err := parseTemplate(tt.fqdnTemplate) + tmpl, err := fqdn.ParseTemplate(tt.fqdnTemplate) if err != nil { t.Fatalf("Failed to parse template: %v", err) } @@ -836,53 +836,3 @@ func TestResourceLabelIsSet(t *testing.T) { } } } - -func TestParseTemplate(t *testing.T) { - for _, tt := range []struct { - name string - annotationFilter string - fqdnTemplate string - combineFQDNAndAnnotation bool - expectError bool - }{ - { - name: "invalid template", - expectError: true, - fqdnTemplate: "{{.Name", - }, - { - name: "valid empty template", - expectError: false, - }, - { - name: "valid template", - expectError: false, - fqdnTemplate: "{{.Name}}-{{.Namespace}}.ext-dns.test.com", - }, - { - name: "valid template", - expectError: false, - fqdnTemplate: "{{.Name}}-{{.Namespace}}.ext-dns.test.com, {{.Name}}-{{.Namespace}}.ext-dna.test.com", - }, - { - name: "valid template", - expectError: false, - fqdnTemplate: "{{.Name}}-{{.Namespace}}.ext-dns.test.com, {{.Name}}-{{.Namespace}}.ext-dna.test.com", - combineFQDNAndAnnotation: true, - }, - { - name: "non-empty annotation filter label", - expectError: false, - annotationFilter: "kubernetes.io/ingress.class=nginx", - }, - } { - t.Run(tt.name, func(t *testing.T) { - _, err := parseTemplate(tt.fqdnTemplate) - if tt.expectError { - assert.Error(t, err) - } else { - assert.NoError(t, err) - } - }) - } -} diff --git a/source/source.go b/source/source.go index 4f0b69d42..8975c1e91 100644 --- a/source/source.go +++ b/source/source.go @@ -145,16 +145,6 @@ func execTemplate(tmpl *template.Template, obj kubeObject) (hostnames []string, return hostnames, nil } -func parseTemplate(fqdnTemplate string) (tmpl *template.Template, err error) { - if fqdnTemplate == "" { - return nil, nil - } - funcs := template.FuncMap{ - "trimPrefix": strings.TrimPrefix, - } - return template.New("endpoint").Funcs(funcs).Parse(fqdnTemplate) -} - func getHostnamesFromAnnotations(annotations map[string]string) []string { hostnameAnnotation, exists := annotations[hostnameAnnotationKey] if !exists { From de6fb9d385b9a82e986eeeb4d9642009a66a378a Mon Sep 17 00:00:00 2001 From: Ivan Ka <5395690+ivankatliarchuk@users.noreply.github.com> Date: Mon, 12 May 2025 09:49:15 +0100 Subject: [PATCH 40/42] fix(log testing): re-use logger library testing functionality (#5368) * fix(log testing): re-use logger library testing functionality * fix(log testing): re-use logger library testing functionality Signed-off-by: ivan katliarchuk * fix(log testing): re-use logger library testing functionality Signed-off-by: ivan katliarchuk --------- Signed-off-by: ivan katliarchuk --- docs/contributing/dev-guide.md | 30 ++++++++ internal/testutils/log.go | 94 +++++++++++++++++++++++--- pkg/metrics/metrics_test.go | 4 +- provider/aws/aws_fixtures_test.go | 5 +- provider/aws/aws_utils_test.go | 2 +- provider/cloudflare/cloudflare_test.go | 13 ++-- provider/zonefinder_test.go | 5 +- registry/txt_test.go | 5 +- source/gateway_httproute_test.go | 18 ++--- source/node_test.go | 17 +++-- 10 files changed, 151 insertions(+), 42 deletions(-) diff --git a/docs/contributing/dev-guide.md b/docs/contributing/dev-guide.md index 6c474f144..2747c7c7f 100644 --- a/docs/contributing/dev-guide.md +++ b/docs/contributing/dev-guide.md @@ -48,6 +48,36 @@ make generate-metrics-documentation We require all changes to be covered by acceptance tests and/or unit tests, depending on the situation. In the context of the `external-dns`, acceptance tests are tests of interactions with providers, such as creating, reading information about, and destroying DNS resources. In contrast, unit tests test functionality wholly within the codebase itself, such as function tests. +### Log Unit Testing + +Testing log messages within codebase provides significant advantages, especially when it comes to debugging, monitoring, and gaining a deeper understanding of system behavior. Log library [build-in testing functionality](https://github.com/sirupsen/logrus?tab=readme-ov-file#testing) + +This practice enables: + +- Early detection of logging issues +- Verification of Important Information +- Ensuring Correct Severity Levels +- Improving Observability and Monitoring +- Driving Better Logging Practices + +To illustrate how to unit test log output within functions, consider the following example: + +```go +import ( + "testing" + + "sigs.k8s.io/external-dns/internal/testutils" +) + +func TestMe(t *testing.T) { + hook := testutils.LogsUnderTestWithLogLeve(log.WarnLevel, t) + ... function under tests ... + testutils.TestHelperLogContains("example warning message", hook, t) + // provide negative assertion + testuitls.TestHelperLogNotContains("this message should not be shown", hook, t) +} +``` + ### Continuous Integration When submitting a pull request, you'll notice that we run several automated processes on your proposed change. Some of these processes are tests to ensure your contribution aligns with our standards. While we strive for accuracy, some users may find these tests confusing. diff --git a/internal/testutils/log.go b/internal/testutils/log.go index 25b7a4270..05686564a 100644 --- a/internal/testutils/log.go +++ b/internal/testutils/log.go @@ -17,24 +17,100 @@ limitations under the License. package testutils import ( - "bytes" + "strings" "testing" log "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + + "github.com/sirupsen/logrus/hooks/test" ) -// LogsToBuffer redirects log(s) output to a buffer for testing purposes +// LogsUnderTestWithLogLevel redirects log(s) output to a buffer for testing purposes // -// Usage: LogsToBuffer(t) +// Usage: LogsUnderTestWithLogLevel(t) // Example: // -// buf := LogsToBuffer(log.DebugLevel, t) +// hook := testutils.LogsUnderTestWithLogLevel(log.DebugLevel, t) // ... do something that logs ... -// assert.Contains(t, buf.String(), "expected debug log message") -func LogsToBuffer(level log.Level, t *testing.T) *bytes.Buffer { +// +// testutils.TestHelperLogContains("expected debug log message", hook, t) +func LogsUnderTestWithLogLevel(level log.Level, t *testing.T) *test.Hook { t.Helper() - buf := new(bytes.Buffer) - log.SetOutput(buf) + logger, hook := test.NewNullLogger() + + log.AddHook(hook) + log.SetOutput(logger.Out) log.SetLevel(level) - return buf + return hook +} + +// TestHelperLogContains verifies that a specific log message is present +// in the captured log entries. It asserts that the provided message `msg` +// appears in at least one of the log entries recorded by the `hook`. +// +// Parameters: +// - msg: The log message that should be found. +// - hook: The test hook capturing log entries. +// - t: The testing object used for assertions. +// +// Usage: +// This helper is used in tests to ensure that certain log messages are +// logged during the execution of the code under test. +func TestHelperLogContains(msg string, hook *test.Hook, t *testing.T) { + t.Helper() + isContains := false + for _, entry := range hook.AllEntries() { + if strings.Contains(entry.Message, msg) { + isContains = true + } + } + assert.True(t, isContains, "Expected log message not found: %s", msg) +} + +// TestHelperLogNotContains verifies that a specific log message is not present +// in the captured log entries. It asserts that the provided message `msg` +// does not appear in any of the log entries recorded by the `hook`. +// +// Parameters: +// - msg: The log message that should not be found. +// - hook: The test hook capturing log entries. +// - t: The testing object used for assertions. +// +// Usage: +// This helper is used in tests to ensure that certain log messages are not +// logged during the execution of the code under test. +func TestHelperLogNotContains(msg string, hook *test.Hook, t *testing.T) { + t.Helper() + isContains := false + for _, entry := range hook.AllEntries() { + if strings.Contains(entry.Message, msg) { + isContains = true + } + } + assert.False(t, isContains, "Expected log message found when should not: %s", msg) +} + +// TestHelperLogContainsWithLogLevel verifies that a specific log message with a given log level +// is present in the captured log entries. It asserts that the provided message `msg` +// appears in at least one of the log entries recorded by the `hook` with the specified log level. +// +// Parameters: +// - msg: The log message that should be found. +// - level: The log level that the message should have. +// - hook: The test hook capturing log entries. +// - t: The testing object used for assertions. +// +// Usage: +// This helper is used in tests to ensure that certain log messages with a specific log level +// are logged during the execution of the code under test. +func TestHelperLogContainsWithLogLevel(msg string, level log.Level, hook *test.Hook, t *testing.T) { + t.Helper() + isContains := false + for _, entry := range hook.AllEntries() { + if strings.Contains(entry.Message, msg) && entry.Level == level { + isContains = true + } + } + assert.True(t, isContains, "Expected log message not found: %s with level %s", msg, level) } diff --git a/pkg/metrics/metrics_test.go b/pkg/metrics/metrics_test.go index 878ed784a..9c8164203 100644 --- a/pkg/metrics/metrics_test.go +++ b/pkg/metrics/metrics_test.go @@ -84,13 +84,13 @@ func TestMustRegister(t *testing.T) { } func TestUnsupportedMetricWarning(t *testing.T) { - buf := testutils.LogsToBuffer(log.WarnLevel, t) + hook := testutils.LogsUnderTestWithLogLevel(log.WarnLevel, t) registry := NewMetricsRegister() mockUnsupported := &MockMetric{FQDN: "unsupported_metric"} registry.MustRegister(mockUnsupported) assert.NotContains(t, registry.mName, "unsupported_metric") - assert.Contains(t, buf.String(), "Unsupported metric type: *metrics.MockMetric") + testutils.TestHelperLogContains("Unsupported metric type: *metrics.MockMetric", hook, t) } func TestNewMetricsRegister(t *testing.T) { diff --git a/provider/aws/aws_fixtures_test.go b/provider/aws/aws_fixtures_test.go index 0edeb0d7c..eed93954c 100644 --- a/provider/aws/aws_fixtures_test.go +++ b/provider/aws/aws_fixtures_test.go @@ -101,7 +101,8 @@ func TestAWSZonesSecondRequestHitsTheCache(t *testing.T) { ctx := context.Background() _, err := provider.Zones(ctx) assert.NoError(t, err) - b := testutils.LogsToBuffer(log.DebugLevel, t) + hook := testutils.LogsUnderTestWithLogLevel(log.DebugLevel, t) _, _ = provider.Zones(ctx) - assert.Contains(t, b.String(), "level=debug msg=\"Using cached zones list\"") + + testutils.TestHelperLogContainsWithLogLevel("Using cached zones list", log.DebugLevel, hook, t) } diff --git a/provider/aws/aws_utils_test.go b/provider/aws/aws_utils_test.go index eddb8dc8d..57dbaba93 100644 --- a/provider/aws/aws_utils_test.go +++ b/provider/aws/aws_utils_test.go @@ -24,7 +24,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/route53" route53types "github.com/aws/aws-sdk-go-v2/service/route53/types" - yaml "github.com/goccy/go-yaml" + "github.com/goccy/go-yaml" "github.com/stretchr/testify/assert" "sigs.k8s.io/external-dns/endpoint" "sigs.k8s.io/external-dns/provider" diff --git a/provider/cloudflare/cloudflare_test.go b/provider/cloudflare/cloudflare_test.go index f50940142..b5c05cea5 100644 --- a/provider/cloudflare/cloudflare_test.go +++ b/provider/cloudflare/cloudflare_test.go @@ -1960,7 +1960,7 @@ func TestCloudflareLongRecordsErrorLog(t *testing.T) { }, }, }) - b := testutils.LogsToBuffer(log.InfoLevel, t) + hook := testutils.LogsUnderTestWithLogLevel(log.InfoLevel, t) p := &CloudFlareProvider{ Client: client, CustomHostnamesConfig: CustomHostnamesConfig{Enabled: true}, @@ -1970,7 +1970,7 @@ func TestCloudflareLongRecordsErrorLog(t *testing.T) { if err != nil { t.Errorf("should not fail - too long record, %s", err) } - assert.Contains(t, b.String(), "is longer than 63 characters. Cannot create endpoint") + testutils.TestHelperLogContains("s longer than 63 characters. Cannot create endpoint", hook, t) } // check if the error is expected @@ -2720,7 +2720,7 @@ func TestCloudflareCustomHostnameNotFoundOnRecordDeletion(t *testing.T) { Name: "remove DNS record with unexpectedly missing custom hostname", Endpoints: []*endpoint.Endpoint{}, preApplyHook: "corrupt", - logOutput: "level=warning msg=\"failed to delete custom hostname \\\"newerror-getCustomHostnameOrigin.foo.fancybar.com\\\": failed to get custom hostname: \\\"newerror-getCustomHostnameOrigin.foo.fancybar.com\\\" not found\" action=DELETE record=create.foo.bar.com", + logOutput: "failed to delete custom hostname \"newerror-getCustomHostnameOrigin.foo.fancybar.com\": failed to get custom hostname: \"newerror-getCustomHostnameOrigin.foo.fancybar.com\" not found", }, { Name: "duplicate custom hostname", @@ -2746,12 +2746,12 @@ func TestCloudflareCustomHostnameNotFoundOnRecordDeletion(t *testing.T) { }, }, preApplyHook: "", - logOutput: "custom hostname \\\"a.foo.fancybar.com\\\" already exists with the same origin \\\"a.foo.bar.com\\\", continue", + logOutput: "custom hostname \"a.foo.fancybar.com\" already exists with the same origin \"a.foo.bar.com\", continue", }, } for _, tc := range testCases { - b := testutils.LogsToBuffer(log.InfoLevel, t) + hook := testutils.LogsUnderTestWithLogLevel(log.InfoLevel, t) records, err := provider.Records(ctx) if err != nil { @@ -2801,7 +2801,8 @@ func TestCloudflareCustomHostnameNotFoundOnRecordDeletion(t *testing.T) { if e := checkFailed(tc.Name, err, false); !errors.Is(e, nil) { t.Error(e) } - assert.Contains(t, b.String(), tc.logOutput) + + testutils.TestHelperLogContains(tc.logOutput, hook, t) } } diff --git a/provider/zonefinder_test.go b/provider/zonefinder_test.go index 8b33f566f..751b326b7 100644 --- a/provider/zonefinder_test.go +++ b/provider/zonefinder_test.go @@ -76,7 +76,8 @@ func TestZoneIDName(t *testing.T) { assert.Equal(t, "エイミー.みんな", zoneName) assert.Equal(t, "987654", zoneID) - b := testutils.LogsToBuffer(log.WarnLevel, t) + hook := testutils.LogsUnderTestWithLogLevel(log.WarnLevel, t) _, _ = z.FindZone("???") - assert.Contains(t, b.String(), "level=warning msg=\"Failed to convert label '???' of hostname '???' to its Unicode form: idna: disallowed rune U+003F\"") + + testutils.TestHelperLogContains("Failed to convert label '???' of hostname '???' to its Unicode form: idna: disallowed rune U+003F", hook, t) } diff --git a/registry/txt_test.go b/registry/txt_test.go index 6cb598b25..5b0dea682 100644 --- a/registry/txt_test.go +++ b/registry/txt_test.go @@ -1821,7 +1821,7 @@ func TestTXTRegistryRecordsWithEmptyTargets(t *testing.T) { }) r, _ := NewTXTRegistry(p, "", "", "owner", time.Hour, "", []string{}, []string{}, false, nil, false) - b := testutils.LogsToBuffer(log.ErrorLevel, t) + hook := testutils.LogsUnderTestWithLogLevel(log.ErrorLevel, t) records, err := r.Records(ctx) require.NoError(t, err) @@ -1835,5 +1835,6 @@ func TestTXTRegistryRecordsWithEmptyTargets(t *testing.T) { } assert.True(t, testutils.SameEndpoints(records, expectedRecords)) - assert.Contains(t, b.String(), "TXT record has no targets empty-targets.test-zone.example.org") + + testutils.TestHelperLogContains("TXT record has no targets empty-targets.test-zone.example.org", hook, t) } diff --git a/source/gateway_httproute_test.go b/source/gateway_httproute_test.go index a7f9bbe90..0308080b3 100644 --- a/source/gateway_httproute_test.go +++ b/source/gateway_httproute_test.go @@ -219,7 +219,7 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) { newTestEndpoint("test.example.internal", "A", "1.2.3.4"), }, logExpectations: []string{ - "level=debug msg=\"Gateway gateway-namespace/not-gateway-name does not match gateway-name route-namespace/test\"", + "Gateway gateway-namespace/not-gateway-name does not match gateway-name route-namespace/test", }, }, { @@ -259,7 +259,7 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) { newTestEndpoint("test.example.internal", "A", "1.2.3.4"), }, logExpectations: []string{ - "level=debug msg=\"Gateway gateway-namespace/gateway-name has not accepted the current generation HTTPRoute route-namespace/old-test\"", + "Gateway gateway-namespace/gateway-name has not accepted the current generation HTTPRoute route-namespace/old-test", }, }, { @@ -294,7 +294,7 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) { }}, endpoints: []*endpoint.Endpoint{}, logExpectations: []string{ - "level=debug msg=\"Gateway gateway-namespace/gateway-name has not accepted the current generation HTTPRoute route-namespace/old-test\"", + "Gateway gateway-namespace/gateway-name has not accepted the current generation HTTPRoute route-namespace/old-test", }, }, { @@ -1509,8 +1509,8 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) { newTestEndpoint("test.two.internal", "A", "2.3.4.5"), }, logExpectations: []string{ - "level=debug msg=\"Endpoints generated from HTTPRoute default/one: [test.one.internal 0 IN A 1.2.3.4 []]\"", - "level=debug msg=\"Endpoints generated from HTTPRoute default/two: [test.two.internal 0 IN A 2.3.4.5 []]\"", + "Endpoints generated from HTTPRoute default/one: [test.one.internal 0 IN A 1.2.3.4 []]", + "Endpoints generated from HTTPRoute default/two: [test.two.internal 0 IN A 2.3.4.5 []]", }, }, { @@ -1540,7 +1540,7 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) { }}, endpoints: []*endpoint.Endpoint{}, logExpectations: []string{ - "level=debug msg=\"No parent references found for HTTPRoute route-namespace/test\"", + "No parent references found for HTTPRoute route-namespace/test", }, }, { @@ -1575,7 +1575,7 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) { }}, endpoints: []*endpoint.Endpoint{}, logExpectations: []string{ - "level=debug msg=\"Parent reference gateway-namespace/other-gateway not found in routeParentRefs for HTTPRoute route-namespace/test\"", + "Parent reference gateway-namespace/other-gateway not found in routeParentRefs for HTTPRoute route-namespace/test", }, }, } @@ -1610,14 +1610,14 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) { src, err := NewGatewayHTTPRouteSource(clients, &tt.config) require.NoError(t, err, "failed to create Gateway HTTPRoute Source") - b := testutils.LogsToBuffer(log.DebugLevel, t) + hook := testutils.LogsUnderTestWithLogLevel(log.DebugLevel, t) endpoints, err := src.Endpoints(ctx) require.NoError(t, err, "failed to get Endpoints") validateEndpoints(t, endpoints, tt.endpoints) for _, msg := range tt.logExpectations { - require.Contains(t, b.String(), msg) + testutils.TestHelperLogContains(msg, hook, t) } }) } diff --git a/source/node_test.go b/source/node_test.go index 9746bbaba..ee400d4d9 100644 --- a/source/node_test.go +++ b/source/node_test.go @@ -17,11 +17,11 @@ limitations under the License. package source import ( - "bytes" "context" "testing" log "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus/hooks/test" "sigs.k8s.io/external-dns/internal/testutils" "github.com/stretchr/testify/assert" @@ -391,7 +391,7 @@ func testNodeSourceEndpoints(t *testing.T) { }, } { t.Run(tc.title, func(t *testing.T) { - buf := testutils.LogsToBuffer(log.DebugLevel, t) + hook := testutils.LogsUnderTestWithLogLevel(log.DebugLevel, t) labelSelector := labels.Everything() if tc.labelSelector != "" { @@ -443,11 +443,10 @@ func testNodeSourceEndpoints(t *testing.T) { validateEndpoints(t, endpoints, tc.expected) for _, entry := range tc.expectedLogs { - assert.Contains(t, buf.String(), entry) + testutils.TestHelperLogContains(entry, hook, t) } - for _, entry := range tc.expectedAbsentLogs { - assert.NotContains(t, buf.String(), entry) + testutils.TestHelperLogNotContains(entry, hook, t) } }) } @@ -533,9 +532,9 @@ func testNodeEndpointsWithIPv6(t *testing.T) { _, err := kubernetes.CoreV1().Nodes().Create(context.Background(), node, metav1.CreateOptions{}) require.NoError(t, err) - var buf *bytes.Buffer + var hook *test.Hook if tc.exposeInternalIPv6 { - buf = testutils.LogsToBuffer(log.WarnLevel, t) + hook = testutils.LogsUnderTestWithLogLevel(log.WarnLevel, t) } // Create our object under test and get the endpoints. @@ -556,8 +555,8 @@ func testNodeEndpointsWithIPv6(t *testing.T) { } else { require.NoError(t, err) - if tc.exposeInternalIPv6 && buf != nil { - assert.Contains(t, buf.String(), warningMsg) + if tc.exposeInternalIPv6 && hook != nil { + testutils.TestHelperLogContainsWithLogLevel(warningMsg, log.WarnLevel, hook, t) } } From 1ac744f3042858b8fcca9187c435f27d0493dba8 Mon Sep 17 00:00:00 2001 From: Lino Layani <39967417+linoleparquet@users.noreply.github.com> Date: Mon, 12 May 2025 06:03:15 -0400 Subject: [PATCH 41/42] test(tlsconfig): add unit tests (#5381) * test(tlsconfig): add unit tests for CreateTLSConfig function * Add licence banner --- pkg/tlsutils/tlsconfig_test.go | 147 +++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 pkg/tlsutils/tlsconfig_test.go diff --git a/pkg/tlsutils/tlsconfig_test.go b/pkg/tlsutils/tlsconfig_test.go new file mode 100644 index 000000000..ed5c97806 --- /dev/null +++ b/pkg/tlsutils/tlsconfig_test.go @@ -0,0 +1,147 @@ +/* +Copyright 2023 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 tlsutils + +import ( + "crypto/tls" + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "sigs.k8s.io/external-dns/internal/gen/docs/utils" +) + +var rsaCertPEM = `-----BEGIN CERTIFICATE----- +MIIB0zCCAX2gAwIBAgIJAI/M7BYjwB+uMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTIwOTEyMjE1MjAyWhcNMTUwOTEyMjE1MjAyWjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANLJ +hPHhITqQbPklG3ibCVxwGMRfp/v4XqhfdQHdcVfHap6NQ5Wok/4xIA+ui35/MmNa +rtNuC+BdZ1tMuVCPFZcCAwEAAaNQME4wHQYDVR0OBBYEFJvKs8RfJaXTH08W+SGv +zQyKn0H8MB8GA1UdIwQYMBaAFJvKs8RfJaXTH08W+SGvzQyKn0H8MAwGA1UdEwQF +MAMBAf8wDQYJKoZIhvcNAQEFBQADQQBJlffJHybjDGxRMqaRmDhX0+6v02TUKZsW +r5QuVbpQhH6u+0UgcW0jp9QwpxoPTLTWGXEWBBBurxFwiCBhkQ+V +-----END CERTIFICATE----- +` + +var rsaKeyPEM = testingKey(`-----BEGIN RSA TESTING KEY----- +MIIBOwIBAAJBANLJhPHhITqQbPklG3ibCVxwGMRfp/v4XqhfdQHdcVfHap6NQ5Wo +k/4xIA+ui35/MmNartNuC+BdZ1tMuVCPFZcCAwEAAQJAEJ2N+zsR0Xn8/Q6twa4G +6OB1M1WO+k+ztnX/1SvNeWu8D6GImtupLTYgjZcHufykj09jiHmjHx8u8ZZB/o1N +MQIhAPW+eyZo7ay3lMz1V01WVjNKK9QSn1MJlb06h/LuYv9FAiEA25WPedKgVyCW +SmUwbPw8fnTcpqDWE3yTO3vKcebqMSsCIBF3UmVue8YU3jybC3NxuXq3wNm34R8T +xVLHwDXh/6NJAiEAl2oHGGLz64BuAfjKrqwz7qMYr9HCLIe/YsoWq/olzScCIQDi +D2lWusoe2/nEqfDVVWGWlyJ7yOmqaVm/iNUN9B2N2g== +-----END RSA TESTING KEY----- +`) + +func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") } + +func TestCreateTLSConfig(t *testing.T) { + + tests := []struct { + title string + prefix string + caFile string + certFile string + keyFile string + isInsecureStr string + serverName string + assertions func(actual *tls.Config, err error) + }{ + { + "Provide only CA returns error", + "prefix", + "", + rsaCertPEM, + "", + "", + "", + func(actual *tls.Config, err error) { + assert.Contains(t, err.Error(), "either both cert and key or none must be provided") + }, + }, + { + "Invalid cert and key returns error", + "prefix", + "", + "invalid-cert", + "invalid-key", + "", + "", + func(actual *tls.Config, err error) { + assert.Contains(t, err.Error(), "could not load TLS cert") + }, + }, + { + "Valid cert and key return a valid tls.Config with a certificate", + "prefix", + "", + rsaCertPEM, + rsaKeyPEM, + "", + "server-name", + func(actual *tls.Config, err error) { + assert.Nil(t, err) + assert.Equal(t, actual.ServerName, "server-name") + assert.NotNil(t, actual.Certificates[0]) + assert.Equal(t, actual.InsecureSkipVerify, false) + assert.Equal(t, actual.MinVersion, uint16(defaultMinVersion)) + }, + }, + } + + for _, tc := range tests { + t.Run(tc.title, func(t *testing.T) { + // setup + dir := t.TempDir() + + if tc.caFile != "" { + path := fmt.Sprintf("%s/caFile", dir) + utils.WriteToFile(path, tc.caFile) + t.Setenv(fmt.Sprintf("%s_CA_FILE", tc.prefix), path) + } + + if tc.certFile != "" { + path := fmt.Sprintf("%s/certFile", dir) + utils.WriteToFile(path, tc.certFile) + t.Setenv(fmt.Sprintf("%s_CERT_FILE", tc.prefix), path) + } + + if tc.keyFile != "" { + path := fmt.Sprintf("%s/keyFile", dir) + utils.WriteToFile(path, tc.keyFile) + t.Setenv(fmt.Sprintf("%s_KEY_FILE", tc.prefix), path) + } + + if tc.serverName != "" { + t.Setenv(fmt.Sprintf("%s_TLS_SERVER_NAME", tc.prefix), tc.serverName) + } + + if tc.isInsecureStr != "" { + t.Setenv(fmt.Sprintf("%s_INSECURE", tc.prefix), tc.isInsecureStr) + } + + // test + actual, err := CreateTLSConfig(tc.prefix) + tc.assertions(actual, err) + }) + } + +} From 0cc2c50c6c8dec46df3a1d17152bad9a79b752e0 Mon Sep 17 00:00:00 2001 From: Ivan Ka <5395690+ivankatliarchuk@users.noreply.github.com> Date: Mon, 12 May 2025 12:53:15 +0100 Subject: [PATCH 42/42] fix(log testing): re-use logger library testing functionality (#5370) Signed-off-by: ivan katliarchuk --- .github/workflows/ci.yaml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 73f0c926a..9edbb7cc6 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -17,7 +17,11 @@ jobs: checks: write # to create a new check based on the results (shogo82148/actions-goveralls) name: Build - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} + strategy: + matrix: + # tests for target OS + os: [ubuntu-latest, macos-latest] steps: - name: Check out code into the Go module directory @@ -38,7 +42,7 @@ jobs: run: | apt update apt install -y make gcc libc-dev git - if: github.actor == 'nektos/act' + if: github.actor == 'nektos/act' && matrix.os == 'ubuntu-latest' - name: Test run: make test @@ -47,5 +51,5 @@ jobs: uses: shogo82148/actions-goveralls@v1 with: path-to-profile: profile.cov - if: github.actor != 'nektos/act' + if: github.actor != 'nektos/act' && matrix.os == 'ubuntu-latest' continue-on-error: true