From 4a0bde92e0ab1ce86aacb7467d014e092d68093c Mon Sep 17 00:00:00 2001 From: Alexander Soelberg Heidarsson Date: Thu, 2 Mar 2023 13:04:40 +0100 Subject: [PATCH] Add custom tidydns provider --- .github/workflows/gh-workflow-approve.yaml | 41 --- .github/workflows/lint-test-chart.yaml | 4 +- .github/workflows/release-chart.yaml | 14 +- Dockerfile | 2 - charts/external-dns/CHANGELOG.md | 8 - charts/external-dns/Chart.yaml | 10 +- charts/external-dns/README.md | 117 +++---- .../templates/servicemonitor.yaml | 32 +- charts/external-dns/values.yaml | 44 +-- docs/faq.md | 2 +- docs/release.md | 1 - docs/tutorials/ANS_Group_SafeDNS.md | 4 +- docs/tutorials/akamai-edgedns.md | 4 +- docs/tutorials/alibabacloud.md | 4 +- docs/tutorials/aws-sd.md | 4 +- docs/tutorials/aws.md | 8 +- docs/tutorials/azure-private-dns.md | 180 ++++------ docs/tutorials/azure.md | 51 +-- docs/tutorials/bluecat.md | 4 +- docs/tutorials/civo.md | 4 +- docs/tutorials/cloudflare.md | 4 +- docs/tutorials/contour.md | 4 +- docs/tutorials/coredns.md | 4 +- docs/tutorials/designate.md | 4 +- docs/tutorials/digitalocean.md | 4 +- docs/tutorials/dnsimple.md | 4 +- docs/tutorials/dyn.md | 2 +- docs/tutorials/exoscale.md | 2 +- docs/tutorials/externalname.md | 2 +- docs/tutorials/gandi.md | 4 +- docs/tutorials/gateway-api.md | 2 +- docs/tutorials/gke.md | 2 +- docs/tutorials/gloo-proxy.md | 4 +- docs/tutorials/godaddy.md | 4 +- docs/tutorials/hostport.md | 4 +- docs/tutorials/ibmcloud.md | 4 +- docs/tutorials/infoblox.md | 12 +- docs/tutorials/istio.md | 4 +- docs/tutorials/kong.md | 4 +- docs/tutorials/linode.md | 4 +- docs/tutorials/nginx-ingress.md | 4 +- docs/tutorials/nodes.md | 4 +- docs/tutorials/ns1.md | 4 +- docs/tutorials/openshift.md | 4 +- docs/tutorials/oracle.md | 2 +- docs/tutorials/ovh.md | 4 +- docs/tutorials/pdns.md | 2 +- docs/tutorials/pihole.md | 2 +- docs/tutorials/plural.md | 4 +- docs/tutorials/public-private-route53.md | 4 +- docs/tutorials/rcodezero.md | 4 +- docs/tutorials/rdns.md | 4 +- docs/tutorials/rfc2136.md | 4 +- docs/tutorials/scaleway.md | 4 +- docs/tutorials/security-context.md | 2 +- docs/tutorials/tencentcloud.md | 2 +- docs/tutorials/transip.md | 4 +- docs/tutorials/ultradns.md | 4 +- docs/tutorials/vinyldns.md | 4 +- docs/tutorials/vultr.md | 4 +- endpoint/labels.go | 2 - go.mod | 19 +- go.sum | 38 ++- internal/testutils/endpoint.go | 1 - kustomize/kustomization.yaml | 2 +- main.go | 6 +- pkg/apis/externaldns/types.go | 9 +- pkg/apis/externaldns/types_test.go | 4 + provider/alibabacloud/alibaba_cloud.go | 57 ++-- provider/alibabacloud/alibaba_cloud_test.go | 19 +- provider/aws/aws.go | 200 +++-------- provider/aws/aws_test.go | 254 +++++--------- provider/awssd/aws_sd.go | 2 +- provider/awssd/aws_sd_test.go | 13 +- provider/cloudflare/cloudflare.go | 54 +-- provider/cloudflare/cloudflare_test.go | 67 ++-- provider/infoblox/infoblox.go | 23 +- provider/infoblox/infoblox_test.go | 33 +- provider/pihole/pihole.go | 29 +- provider/pihole/pihole_test.go | 88 +---- provider/tidydns/tidydns.go | 312 ++++++++++++++++++ provider/tidydns/tidydns_test.go | 207 ++++++++++++ registry/txt.go | 2 - registry/txt_test.go | 132 ++++---- 84 files changed, 1088 insertions(+), 1171 deletions(-) delete mode 100644 .github/workflows/gh-workflow-approve.yaml create mode 100644 provider/tidydns/tidydns.go create mode 100644 provider/tidydns/tidydns_test.go diff --git a/.github/workflows/gh-workflow-approve.yaml b/.github/workflows/gh-workflow-approve.yaml deleted file mode 100644 index c0dc99008d..0000000000 --- a/.github/workflows/gh-workflow-approve.yaml +++ /dev/null @@ -1,41 +0,0 @@ -name: Approve GH Workflows - -on: - pull_request_target: - types: - - labeled - - synchronize - branches: - - master - -jobs: - approve: - name: Approve ok-to-test - if: contains(github.event.pull_request.labels.*.name, 'ok-to-test') - runs-on: ubuntu-latest - permissions: - actions: write - steps: - - name: Update PR - uses: actions/github-script@d556feaca394842dc55e4734bf3bb9f685482fa0 # v6.3.3 - continue-on-error: true - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - debug: ${{ secrets.ACTIONS_RUNNER_DEBUG }} - script: | - const result = await github.rest.actions.listWorkflowRunsForRepo({ - owner: context.repo.owner, - repo: context.repo.repo, - event: "pull_request", - status: "action_required", - head_sha: context.payload.pull_request.head.sha, - per_page: 100 - }); - - for (var run of result.data.workflow_runs) { - await github.rest.actions.approveWorkflowRun({ - owner: context.repo.owner, - repo: context.repo.repo, - run_id: run.id - }); - } diff --git a/.github/workflows/lint-test-chart.yaml b/.github/workflows/lint-test-chart.yaml index f8207ef507..20f222ba94 100644 --- a/.github/workflows/lint-test-chart.yaml +++ b/.github/workflows/lint-test-chart.yaml @@ -27,7 +27,7 @@ jobs: rm -f ./ah ./ah_linux_amd64.tar.gz - name: Set-up Helm - uses: azure/setup-helm@5119fcb9089d432beecbf79bb2c7915207344b78 + uses: azure/setup-helm@f382f75448129b3be48f8121b9857be18d815a82 with: token: ${{ secrets.GITHUB_TOKEN }} version: latest @@ -52,7 +52,7 @@ jobs: run: ct lint --check-version-increment=false - name: Set-up Kind cluster - uses: helm/kind-action@d8ccf8fb623ce1bb360ae2f45f323d9d5c5e9f00 + uses: helm/kind-action@9e8295d178de23cbfbd8fa16cf844eec1d773a07 with: wait: 120s if: steps.list-changed.outputs.changed == 'true' diff --git a/.github/workflows/release-chart.yaml b/.github/workflows/release-chart.yaml index 95ce0baa85..0bc1780993 100644 --- a/.github/workflows/release-chart.yaml +++ b/.github/workflows/release-chart.yaml @@ -10,8 +10,9 @@ on: permissions: {} jobs: release: + permissions: - contents: write # to push chart release and create a release (helm/chart-releaser-action) + contents: write # to push chart release and create a release (helm/chart-releaser-action) if: github.repository == 'kubernetes-sigs/external-dns' runs-on: ubuntu-latest @@ -33,7 +34,7 @@ jobs: - name: Get changelog entry id: changelog_reader - uses: mindsers/changelog-reader-action@b97ce03a10d9bdbb07beb491c76a5a01d78cd3ef + uses: mindsers/changelog-reader-action@5bfb30f7871d5c4cde50cd897314f37578043394 with: path: charts/external-dns/CHANGELOG.md version: "v${{ steps.chart_version.outputs.version }}" @@ -41,7 +42,7 @@ jobs: - name: Create release notes run: | set -euo pipefail - cat <<"EOF" > charts/external-dns/RELEASE.md + cat <<"EOF" > charts/external-dns/_release-notes.md ${{ steps.changelog_reader.outputs.changes }} EOF @@ -51,15 +52,14 @@ jobs: git config user.email "$GITHUB_ACTOR@users.noreply.github.com" - name: Set-up Helm - uses: azure/setup-helm@5119fcb9089d432beecbf79bb2c7915207344b78 + uses: azure/setup-helm@f382f75448129b3be48f8121b9857be18d815a82 with: token: ${{ secrets.GITHUB_TOKEN }} version: latest - name: Run chart-releaser - uses: helm/chart-releaser-action@be16258da8010256c6e82849661221415f031968 + uses: helm/chart-releaser-action@98bccfd32b0f76149d188912ac8e45ddd3f8695f env: CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" CR_RELEASE_NAME_TEMPLATE: "external-dns-helm-chart-{{ .Version }}" - CR_RELEASE_NOTES_FILE: RELEASE.md - CR_MAKE_RELEASE_LATEST: false + CR_RELEASE_NOTES_FILE: _release-notes.md diff --git a/Dockerfile b/Dockerfile index 12af3f2ab8..aad662d91a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -29,8 +29,6 @@ RUN make test build.$ARCH # final image FROM $ARCH/alpine:3.17 -RUN apk update && apk add "libcrypto3>=3.0.8-r0" "libssl3>=3.0.8-r0" && rm -rf /var/cache/apt/* - COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt COPY --from=builder /sigs.k8s.io/external-dns/build/external-dns /bin/external-dns diff --git a/charts/external-dns/CHANGELOG.md b/charts/external-dns/CHANGELOG.md index 8e30bd0e22..7b7197da6e 100644 --- a/charts/external-dns/CHANGELOG.md +++ b/charts/external-dns/CHANGELOG.md @@ -17,14 +17,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Deprecated - Removed --> -## [v1.12.1] - 2023-02-06 - -### All Changes - -- Updated _ExternalDNS_ version to [v0.13.2](https://github.com/kubernetes-sigs/external-dns/releases/tag/v0.13.2). ([#3371](https://github.com/kubernetes-sigs/external-dns/pull/3371)) [@stevehipwell](https://github.com/stevehipwell) -- Added `secretConfiguration.subPath` to mount specific files from secret as a sub-path. ([#3227](https://github.com/kubernetes-sigs/external-dns/pull/3227)) [@jkroepke](https://github.com/jkroepke) -- Changed to use `registry.k8s.io` instead of `k8s.gcr.io`. ([#3261](https://github.com/kubernetes-sigs/external-dns/pull/3261)) [@johngmyers](https://github.com/johngmyers) - ## [v1.12.0] - 2022-11-29 ### All Changes diff --git a/charts/external-dns/Chart.yaml b/charts/external-dns/Chart.yaml index 9dbbda3800..72d1c1f3ba 100644 --- a/charts/external-dns/Chart.yaml +++ b/charts/external-dns/Chart.yaml @@ -2,8 +2,8 @@ apiVersion: v2 name: external-dns description: ExternalDNS synchronizes exposed Kubernetes Services and Ingresses with DNS providers. type: application -version: 1.12.1 -appVersion: 0.13.2 +version: 1.12.0 +appVersion: 0.13.1 keywords: - kubernetes - externaldns @@ -21,8 +21,4 @@ maintainers: annotations: artifacthub.io/changes: | - kind: changed - description: "Updated ExternalDNS version to v0.13.2." - - kind: added - description: "Added secretConfiguration.subPath to mount specific files from secret as a sub-path." - - kind: changed - description: "Changed to use registry.k8s.io instead of k8s.gcr.io." + description: "Updated ExternalDNS version to v0.13.1." diff --git a/charts/external-dns/README.md b/charts/external-dns/README.md index 67ab1f5df1..cfbed3371a 100644 --- a/charts/external-dns/README.md +++ b/charts/external-dns/README.md @@ -20,65 +20,58 @@ helm upgrade --install external-dns external-dns/external-dns The following table lists the configurable parameters of the _ExternalDNS_ chart and their default values. -| Parameter | Description | Default | -|------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------| -| `image.repository` | Image repository. | `registry.k8s.io/external-dns/external-dns` | -| `image.tag` | Image tag, will override the default tag derived from the chart app version. | `""` | -| `image.pullPolicy` | Image pull policy. | `IfNotPresent` | -| `imagePullSecrets` | Image pull secrets. | `[]` | -| `nameOverride` | Override the `name` of the chart. | `""` | -| `fullnameOverride` | Override the `fullname` of the chart. | `""` | -| `serviceAccount.create` | If `true`, create a new `serviceaccount`. | `true` | -| `serviceAccount.annotations` | Annotations to add to the service account. | `{}` | -| `serviceAccount.labels` | Labels to add to the service account. | `{}` | -| `serviceAccount.name` | Service account to be used. If not set and `serviceAccount.create` is `true`, a name is generated using the full name template. | `""` | -| `rbac.create` | If `true`, create the RBAC resources. | `true` | -| `rbac.additionalPermissions` | Additional permissions to be added to the cluster role. | `{}` | -| `deploymentAnnotations` | Annotations to add to the Deployment. | `{}` | -| `podLabels` | Labels to add to the pod. | `{}` | -| `podAnnotations` | Annotations to add to the pod. | `{}` | -| `podSecurityContext` | Security context for the pod, this supports the full [PodSecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#podsecuritycontext-v1-core) API. | _see values.yaml_ | -| `shareProcessNamespace` | If `true` enable [Process Namespace Sharing](https://kubernetes.io/docs/tasks/configure-pod-container/share-process-namespace/) | `false` | -| `securityContext` | Security context for the _external-dns_ container, this supports the full [SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#securitycontext-v1-core) API. | _see values.yaml_ | -| `priorityClassName` | Priority class name to use for the pod. | `""` | -| `terminationGracePeriodSeconds` | Termination grace period for the pod. | `null` | -| `serviceMonitor.enabled` | If `true`, create a _Prometheus_ service monitor. | `false` | -| `serviceMonitor.namespace` | Forced namespace for ServiceMonitor. | `null` | -| `serviceMonitor.annotations` | Annotations to be set on the ServiceMonitor. | `{}` | -| `serviceMonitor.additionalLabels` | Additional labels to be set on the ServiceMonitor. | `{}` | -| `serviceMonitor.interval` | _Prometheus_ scrape frequency. | `null` | -| `serviceMonitor.scrapeTimeout` | _Prometheus_ scrape timeout. | `null` | -| `serviceMonitor.scheme` | _Prometheus_ scrape scheme. | `null` | -| `serviceMonitor.tlsConfig` | _Prometheus_ scrape tlsConfig. | `{}` | -| `serviceMonitor.metricRelabelings` | _Prometheus_ scrape metricRelabelings. | `[]` | -| `serviceMonitor.relabelings` | _Prometheus_ scrape relabelings. | `[]` | -| `serviceMonitor.targetLabels` | _Prometheus_ scrape targetLabels. | `[]` | -| `env` | [Environment variables](https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/) for the _external-dns_ container, this supports the full [EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#envvar-v1-core) API including secrets and configmaps. | `[]` | -| `livenessProbe` | [Liveness probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) for the _external-dns_ container, this supports the full [Probe](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#probe-v1-core) API. | See _values.yaml_ | -| `readinessProbe` | [Readiness probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) for the _external-dns_ container, this supports the full [Probe](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#probe-v1-core) API. | See _values.yaml_ | -| `service.annotations` | Annotations to add to the service. | `{}` | -| `service.port` | Port to expose via the service. | `7979` | -| `extraVolumes` | Additional volumes for the pod, this supports the full [VolumeDevice](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#volumedevice-v1-core) API. | `[]` | -| `extraVolumeMounts` | Additional volume mounts for the _external-dns_ container, this supports the full [VolumeMount](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#volumemount-v1-core) API. | `[]` | -| `resources` | Resource requests and limits for the _external-dns_ container, this supports the full [ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#resourcerequirements-v1-core) API. | `{}` | -| `nodeSelector` | Node labels for pod assignment. | `{}` | -| `tolerations` | Tolerations for pod assignment, this supports the full [Toleration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#toleration-v1-core) API. | `[]` | -| `affinity` | Affinity settings for pod assignment, this supports the full [Affinity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#affinity-v1-core) API. | `{}` | -| `topologySpreadConstraints` | TopologySpreadConstraint settings for pod assignment, this supports the full [TopologySpreadConstraints](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#topologyspreadconstraint-v1-core) API. | `[]` | -| `logLevel` | Verbosity of the logs, available values are: `panic`, `debug`, `info`, `warning`, `error`, `fatal`. | `info` | -| `logFormat` | Formats of the logs, available values are: `text`, `json`. | `text` | -| `interval` | The interval for DNS updates. | `1m` | -| `triggerLoopOnEvent` | When enabled, triggers run loop on create/update/delete events in addition of regular interval. | `false` | -| `sources` | K8s resources type to be observed for new DNS entries. | See _values.yaml_ | -| `policy` | How DNS records are synchronized between sources and providers, available values are: `sync`, `upsert-only`. | `upsert-only` | -| `registry` | Registry Type, available types are: `txt`, `noop`. | `txt` | -| `txtOwnerId` | TXT registry identifier. | `""` | -| `txtPrefix` | Prefix to create a TXT record with a name following the pattern `prefix.`. | `""` | -| `domainFilters` | Limit possible target zones by domain suffixes. | `[]` | -| `provider` | DNS provider where the DNS records will be created, for the available providers and how to configure them see the [README](https://github.com/kubernetes-sigs/external-dns#deploying-to-a-cluster) (this can be templated). | `aws` | -| `extraArgs` | Extra arguments to pass to the _external-dns_ container, these are needed for provider specific arguments (these can be templated). | `[]` | -| `deploymentStrategy` | .spec.strategy of the external-dns Deployment. Defaults to 'Recreate' since multiple external-dns pods may conflict with each other. | `{type: Recreate}` | -| `secretConfiguration.enabled` | Enable additional secret configuration. | `false` | -| `secretConfiguration.mountPath` | Mount path of secret configuration secret (this can be templated). | `""` | -| `secretConfiguration.data` | Secret configuration secret data. Could be used to store DNS provider credentials. | `{}` | -| `secretConfiguration.subPath` | Sub-path of secret configuration secret (this can be templated). | `""` | +| Parameter | Description | Default | +|-----------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------| +| `image.repository` | Image repository. | `registry.k8s.io/external-dns/external-dns` | +| `image.tag` | Image tag, will override the default tag derived from the chart app version. | `""` | +| `image.pullPolicy` | Image pull policy. | `IfNotPresent` | +| `imagePullSecrets` | Image pull secrets. | `[]` | +| `nameOverride` | Override the `name` of the chart. | `""` | +| `fullnameOverride` | Override the `fullname` of the chart. | `""` | +| `serviceAccount.create` | If `true`, create a new `serviceaccount`. | `true` | +| `serviceAccount.annotations` | Annotations to add to the service account. | `{}` | +| `serviceAccount.labels` | Labels to add to the service account. | `{}` | +| `serviceAccount.name` | Service account to be used. If not set and `serviceAccount.create` is `true`, a name is generated using the full name template. | `""` | +| `rbac.create` | If `true`, create the RBAC resources. | `true` | +| `rbac.additionalPermissions` | Additional permissions to be added to the cluster role. | `{}` | +| `deploymentAnnotations` | Annotations to add to the Deployment. | `{}` | +| `podLabels` | Labels to add to the pod. | `{}` | +| `podAnnotations` | Annotations to add to the pod. | `{}` | +| `podSecurityContext` | Security context for the pod, this supports the full [PodSecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#podsecuritycontext-v1-core) API. | _see values.yaml_ | +| `shareProcessNamespace` | If `true` enable [Process Namespace Sharing](https://kubernetes.io/docs/tasks/configure-pod-container/share-process-namespace/) | `false` | +| `securityContext` | Security context for the _external-dns_ container, this supports the full [SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#securitycontext-v1-core) API. | _see values.yaml_ | +| `priorityClassName` | Priority class name to use for the pod. | `""` | +| `terminationGracePeriodSeconds` | Termination grace period for the pod. | `null` | +| `serviceMonitor.enabled` | If `true`, create a _Prometheus_ service monitor. | `false` | +| `serviceMonitor.additionalLabels` | Additional labels to be set on the ServiceMonitor. | `{}` | +| `serviceMonitor.interval` | _Prometheus_ scrape frequency. | `1m` | +| `serviceMonitor.scrapeTimeout` | _Prometheus_ scrape timeout. | `10s` | +| `env` | [Environment variables](https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/) for the _external-dns_ container, this supports the full [EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#envvar-v1-core) API including secrets and configmaps. | `[]` | +| `livenessProbe` | [Liveness probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) for the _external-dns_ container, this supports the full [Probe](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#probe-v1-core) API. | See _values.yaml_ | +| `readinessProbe` | [Readiness probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) for the _external-dns_ container, this supports the full [Probe](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#probe-v1-core) API. | See _values.yaml_ | +| `service.annotations` | Annotations to add to the service. | `{}` | +| `service.port` | Port to expose via the service. | `7979` | +| `extraVolumes` | Additional volumes for the pod, this supports the full [VolumeDevice](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#volumedevice-v1-core) API. | `[]` | +| `extraVolumeMounts` | Additional volume mounts for the _external-dns_ container, this supports the full [VolumeMount](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#volumemount-v1-core) API. | `[]` | +| `resources` | Resource requests and limits for the _external-dns_ container, this supports the full [ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#resourcerequirements-v1-core) API. | `{}` | +| `nodeSelector` | Node labels for pod assignment. | `{}` | +| `tolerations` | Tolerations for pod assignment, this supports the full [Toleration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#toleration-v1-core) API. | `[]` | +| `affinity` | Affinity settings for pod assignment, this supports the full [Affinity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#affinity-v1-core) API. | `{}` | +| `topologySpreadConstraints` | TopologySpreadConstraint settings for pod assignment, this supports the full [TopologySpreadConstraints](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#topologyspreadconstraint-v1-core) API. | `[]` | +| `logLevel` | Verbosity of the logs, available values are: `panic`, `debug`, `info`, `warning`, `error`, `fatal`. | `info` | +| `logFormat` | Formats of the logs, available values are: `text`, `json`. | `text` | +| `interval` | The interval for DNS updates. | `1m` | +| `triggerLoopOnEvent` | When enabled, triggers run loop on create/update/delete events in addition of regular interval. | `false` | +| `sources` | K8s resources type to be observed for new DNS entries. | See _values.yaml_ | +| `policy` | How DNS records are synchronized between sources and providers, available values are: `sync`, `upsert-only`. | `upsert-only` | +| `registry` | Registry Type, available types are: `txt`, `noop`. | `txt` | +| `txtOwnerId` | TXT registry identifier. | `""` | +| `txtPrefix` | Prefix to create a TXT record with a name following the pattern `prefix.`. | `""` | +| `domainFilters` | Limit possible target zones by domain suffixes. | `[]` | +| `provider` | DNS provider where the DNS records will be created, for the available providers and how to configure them see the [README](https://github.com/kubernetes-sigs/external-dns#deploying-to-a-cluster) (this can be templated). | `aws` | +| `extraArgs` | Extra arguments to pass to the _external-dns_ container, these are needed for provider specific arguments (these can be templated). | `[]` | +| `deploymentStrategy` | .spec.strategy of the external-dns Deployment. Defaults to 'Recreate' since multiple external-dns pods may conflict with each other. | `{type: Recreate}` | +| `secretConfiguration.enabled` | Enable additional secret configuration. | `false` | +| `secretConfiguration.mountPath` | Mount path of secret configuration secret (this can be templated). | `""` | +| `secretConfiguration.data` | Secret configuration secret data. Could be used to store DNS provider credentials. | `{}` | +| `secretConfiguration.subPath` | Sub-path of secret configuration secret (this can be templated). | `""` | diff --git a/charts/external-dns/templates/servicemonitor.yaml b/charts/external-dns/templates/servicemonitor.yaml index ad11a99084..44d6454ad0 100644 --- a/charts/external-dns/templates/servicemonitor.yaml +++ b/charts/external-dns/templates/servicemonitor.yaml @@ -1,13 +1,9 @@ -{{- if .Values.serviceMonitor.enabled -}} +{{- if.Values.serviceMonitor.enabled -}} apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: {{ include "external-dns.fullname" . }} - namespace: {{ default .Release.Namespace .Values.serviceMonitor.namespace }} - {{- with .Values.serviceMonitor.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} + namespace: {{ .Release.Namespace }} labels: {{- include "external-dns.labels" . | nindent 4 }} {{- with .Values.serviceMonitor.additionalLabels }} @@ -27,29 +23,7 @@ spec: {{- with .Values.serviceMonitor.interval }} interval: {{ . }} {{- end }} - {{- with .Values.serviceMonitor.scheme }} - scheme: {{ . }} - {{- end }} - {{- with .Values.serviceMonitor.bearerTokenFile }} - bearerTokenFile: {{ . }} - {{- end }} - {{- with .Values.serviceMonitor.tlsConfig }} - tlsConfig: - {{- toYaml .| nindent 8 }} - {{- end }} - {{- with .Values.serviceMonitor.scrapeTimeout }} + {{- with .Values.serviceMonitor.scrapeTimeout }} scrapeTimeout: {{ . }} {{- end }} - {{- with .Values.serviceMonitor.metricRelabelings }} - metricRelabelings: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.serviceMonitor.relabelings }} - relabelings: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.serviceMonitor.targetLabels }} - targetLabels: - {{- toYaml . | nindent 4 }} - {{- end }} {{- end }} diff --git a/charts/external-dns/values.yaml b/charts/external-dns/values.yaml index 5b30a9c0ec..fd0070722e 100644 --- a/charts/external-dns/values.yaml +++ b/charts/external-dns/values.yaml @@ -61,49 +61,9 @@ terminationGracePeriodSeconds: serviceMonitor: enabled: false - # force namespace - # namespace: monitoring - - # Fallback to the prometheus default unless specified - # interval: 10s - - ## scheme: HTTP scheme to use for scraping. Can be used with `tlsConfig` for example if using istio mTLS. - # scheme: "" - - ## tlsConfig: TLS configuration to use when scraping the endpoint. For example if using istio mTLS. - ## Of type: https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#tlsconfig - # tlsConfig: {} - - # bearerTokenFile: - # Fallback to the prometheus default unless specified - # scrapeTimeout: 30s - - ## Used to pass Labels that are used by the Prometheus installed in your cluster to select Service Monitors to work with - ## ref: https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#prometheusspec additionalLabels: {} - - ## Used to pass annotations that are used by the Prometheus installed in your cluster to select Service Monitors to work with - ## ref: https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#prometheusspec - annotations: {} - - ## Metric relabel configs to apply to samples before ingestion. - ## [Metric Relabeling](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs) - metricRelabelings: [] - # - action: keep - # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' - # sourceLabels: [__name__] - - ## Relabel configs to apply to samples before ingestion. - ## [Relabeling](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config) - relabelings: [] - # - sourceLabels: [__meta_kubernetes_pod_node_name] - # separator: ; - # regex: ^(.*)$ - # targetLabel: nodename - # replacement: $1 - # action: replace - - targetLabels: [] + interval: 1m + scrapeTimeout: 10s env: [] diff --git a/docs/faq.md b/docs/faq.md index 217951aaab..703669680f 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -205,7 +205,7 @@ $ docker run \ -e EXTERNAL_DNS_SOURCE=$'service\ningress' \ -e EXTERNAL_DNS_PROVIDER=google \ -e EXTERNAL_DNS_DOMAIN_FILTER=$'foo.com\nbar.com' \ - registry.k8s.io/external-dns/external-dns:v0.13.2 + registry.k8s.io/external-dns/external-dns:v0.13.1 time="2017-08-08T14:10:26Z" level=info msg="config: &{APIServerURL: KubeConfig: Sources:[service ingress] Namespace: ... ``` diff --git a/docs/release.md b/docs/release.md index de37dce595..ff1521011b 100644 --- a/docs/release.md +++ b/docs/release.md @@ -31,7 +31,6 @@ You must be an official maintainer of the project to be able to do a release. - Branch out from the default branch and run `scripts/kustomize-version-updater.sh` to update the image tag used in the kustomization.yaml. - Create an issue to release the corresponding Helm chart via the chart release process (below) assigned to a chart maintainer - Create a PR with the kustomize change. -- Create a PR to replace all versions for docker images in the tutorials. A possible script to use is `sd registry.k8s.io/external-dns/external-dns:.* registry.k8s.io/external-dns/external-dns:v0.13.2 $(fd --type file)` which uses the `fd` and `sd` utilities. - Once the PR is merged, all is done :-) ## How to release a new chart version diff --git a/docs/tutorials/ANS_Group_SafeDNS.md b/docs/tutorials/ANS_Group_SafeDNS.md index 9f636b310e..29157a9060 100644 --- a/docs/tutorials/ANS_Group_SafeDNS.md +++ b/docs/tutorials/ANS_Group_SafeDNS.md @@ -48,7 +48,7 @@ spec: - name: external-dns # You will need to check what the latest version is yourself: # https://github.com/kubernetes-sigs/external-dns/releases - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:vX.Y.Z args: - --source=service # ingress is also possible # (optional) limit to only example.com domains; change to match the @@ -114,7 +114,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible # (optional) limit to only example.com domains; change to match the diff --git a/docs/tutorials/akamai-edgedns.md b/docs/tutorials/akamai-edgedns.md index beda1096ad..323835757a 100644 --- a/docs/tutorials/akamai-edgedns.md +++ b/docs/tutorials/akamai-edgedns.md @@ -57,7 +57,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # or ingress or both - --provider=akamai @@ -143,7 +143,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # or ingress or both - --provider=akamai diff --git a/docs/tutorials/alibabacloud.md b/docs/tutorials/alibabacloud.md index 3f24f71fcb..4133c7636f 100644 --- a/docs/tutorials/alibabacloud.md +++ b/docs/tutorials/alibabacloud.md @@ -113,7 +113,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service - --source=ingress @@ -187,7 +187,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service - --source=ingress diff --git a/docs/tutorials/aws-sd.md b/docs/tutorials/aws-sd.md index 321928a737..9bc6b60bb0 100644 --- a/docs/tutorials/aws-sd.md +++ b/docs/tutorials/aws-sd.md @@ -81,7 +81,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 env: - name: AWS_REGION value: us-east-1 # put your CloudMap NameSpace region @@ -148,7 +148,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 env: - name: AWS_REGION value: us-east-1 # put your CloudMap NameSpace region diff --git a/docs/tutorials/aws.md b/docs/tutorials/aws.md index b14136ad3e..3e442ec177 100644 --- a/docs/tutorials/aws.md +++ b/docs/tutorials/aws.md @@ -413,7 +413,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service - --source=ingress @@ -508,7 +508,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service - --source=ingress @@ -853,7 +853,7 @@ args: - --txt-prefix={{ YOUR_PREFIX }} ``` -* The first two changes are needed if you use Route53 in Govcloud, which only supports private zones. There are also no cross account IAM whatsoever between Govcloud and commercial AWS accounts. If services and ingresses need to make Route 53 entries to an public zone in a commercial account, you will have set env variables of `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` with a key and secret to the commercial account that has the sufficient rights. +* The first two changes are needed if you use Route53 in Govcloud, which only supports private zones. There are also no cross account IAM whatsoever between Govcloud and commerical AWS accounts. If services and ingresses need to make Route 53 entries to an public zone in a commerical account, you will have set env variables of `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` with a key and secret to the commerical account that has the sufficient rights. ```yaml env: @@ -950,7 +950,7 @@ A simple way to implement randomised startup is with an init container: spec: initContainers: - name: init-jitter - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 command: - /bin/sh - -c diff --git a/docs/tutorials/azure-private-dns.md b/docs/tutorials/azure-private-dns.md index 2e8dab0e4c..87f9ebb5bd 100644 --- a/docs/tutorials/azure-private-dns.md +++ b/docs/tutorials/azure-private-dns.md @@ -3,20 +3,61 @@ This tutorial describes how to set up ExternalDNS for managing records in Azure Private DNS. It comprises of the following steps: -1) Provision Azure Private DNS -2) Configure service principal for managing the zone -3) Deploy ExternalDNS -4) Expose an NGINX service with a LoadBalancer and annotate it with the desired DNS name -5) Install NGINX Ingress Controller (Optional) -6) Expose an nginx service with an ingress (Optional) -7) Verify the DNS records - -Everything will be deployed on Kubernetes. +1) Install NGINX Ingress Controller +2) Provision Azure Private DNS +3) Configure service principal for managing the zone +4) Deploy ExternalDNS + +Everything will be deployed on Kubernetes. Therefore, please see the subsequent prerequisites. ## Prerequisites - Azure Kubernetes Service is deployed and ready -- [Azure CLI 2.0](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) and `kubectl` installed on the box to execute the subsequent steps +- [Azure CLI 2.0](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) and `kubectl` installed on the box to execute the subsequent steps + +## Install NGINX Ingress Controller + +Helm is used to deploy the ingress controller. + +We employ the popular chart [ingress-nginx](https://github.com/kubernetes/ingress-nginx/tree/main/charts/ingress-nginx). + +``` +$ helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx +$ helm repo update +$ helm install [RELEASE_NAME] ingress-nginx/ingress-nginx + --set controller.publishService.enabled=true +``` + +The parameter `controller.publishService.enabled` needs to be set to `true.` + +It will make the ingress controller update the endpoint records of ingress-resources to contain the external-ip of the loadbalancer serving the ingress-controller. +This is crucial as ExternalDNS reads those endpoints records when creating DNS-Records from ingress-resources. +In the subsequent parameter we will make use of this. If you don't want to work with ingress-resources in your later use, you can leave the parameter out. + +Verify the correct propagation of the loadbalancer's ip by listing the ingresses. + +``` +$ kubectl get ingress +``` + +The address column should contain the ip for each ingress. ExternalDNS will pick up exactly this piece of information. + +``` +NAME HOSTS ADDRESS PORTS AGE +nginx1 sample1.aks.com 52.167.195.110 80 6d22h +nginx2 sample2.aks.com 52.167.195.110 80 6d21h +``` + +If you do not want to deploy the ingress controller with Helm, ensure to pass the following cmdline-flags to it through the mechanism of your choice: + +``` +flags: +--publish-service=/ +--update-status=true (default-value) + +example: +./nginx-ingress-controller --publish-service=default/nginx-ingress-controller +``` ## Provision Azure Private DNS @@ -31,7 +72,7 @@ $ az group create -n externaldns -l westeurope Substitute a more suitable location for the resource group if desired. -As a prerequisite for Azure Private DNS to resolve records is to define links with VNETs. +As a prerequisite for Azure Private DNS to resolve records is to define links with VNETs. Thus, first create a VNET. ``` @@ -60,11 +101,11 @@ $ az network private-dns link vnet create -g externaldns -n mylink \ ``` ## Configure service principal for managing the zone -ExternalDNS needs permissions to make changes in Azure Private DNS. +ExternalDNS needs permissions to make changes in Azure Private DNS. These permissions are roles assigned to the service principal used by ExternalDNS. A service principal with a minimum access level of `Private DNS Zone Contributor` to the Private DNS zone(s) and `Reader` to the resource group containing the Azure Private DNS zone(s) is necessary. -More powerful role-assignments like `Owner` or assignments on subscription-level work too. +More powerful role-assignments like `Owner` or assignments on subscription-level work too. Start off by **creating the service principal** without role-assignments. ``` @@ -78,7 +119,8 @@ $ az ad sp create-for-rbac --skip-assignment -n http://externaldns-sp ``` > Note: Alternatively, you can issue `az account show --query "tenantId"` to retrieve the id of your AAD Tenant too. -Next, assign the roles to the service principal. + +Next, assign the roles to the service principal. But first **retrieve the ID's** of the objects to assign roles on. ``` @@ -92,17 +134,17 @@ $ az network private-dns zone show --name example.com -g externaldns --query id Now, **create role assignments**. ``` # 1. as a reader to the resource group -$ az role assignment create --role "Reader" --assignee --scope +$ az role assignment create --role "Reader" --assignee --scope # 2. as a contributor to DNS Zone itself -$ az role assignment create --role "Private DNS Zone Contributor" --assignee --scope +$ az role assignment create --role "Private DNS Zone Contributor" --assignee --scope ``` ## Deploy ExternalDNS -Configure `kubectl` to be able to communicate and authenticate with your cluster. +Configure `kubectl` to be able to communicate and authenticate with your cluster. This is per default done through the file `~/.kube/config`. -For general background information on this see [kubernetes-docs](https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/). +For general background information on this see [kubernetes-docs](https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/). Azure-CLI features functionality for automatically maintaining this file for AKS-Clusters. See [Azure-Docs](https://docs.microsoft.com/de-de/cli/azure/aks?view=azure-cli-latest#az-aks-get-credentials). Follow the steps for [azure-dns provider](./azure.md#creating-configuration-file) to create a configuration file. @@ -130,7 +172,7 @@ spec: spec: containers: - name: externaldns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service - --source=ingress @@ -201,7 +243,7 @@ spec: serviceAccountName: externaldns containers: - name: externaldns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service - --source=ingress @@ -272,7 +314,7 @@ spec: serviceAccountName: externaldns containers: - name: externaldns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service - --source=ingress @@ -296,12 +338,11 @@ Create the deployment for ExternalDNS: $ kubectl create -f externaldns.yaml ``` -## Create an nginx deployment +## Deploying sample service -This step creates a demo workload in your cluster. Apply the following manifest to create a deployment that we are going to expose later in this tutorial in multiple ways: +Create a service file called 'nginx.yaml' with the following contents: ```yaml ---- apiVersion: apps/v1 kind: Deployment metadata: @@ -316,92 +357,15 @@ spec: app: nginx spec: containers: - - image: nginx - name: nginx - ports: - - containerPort: 80 -``` - -## Expose the nginx deployment with a load balancer - -Apply the following manifest to create a service of type `LoadBalancer`. This will create a public load balancer in Azure that will forward traffic to the nginx pods. - -```yaml + - image: nginx + name: nginx + ports: + - containerPort: 80 --- apiVersion: v1 kind: Service -annotations: - service.beta.kubernetes.io/azure-load-balancer-internal: "true" - external-dns.alpha.kubernetes.io/hostname: server.example.com - external-dns.alpha.kubernetes.io/internal-hostname: server-clusterip.example.com metadata: name: nginx-svc -spec: - ports: - - port: 80 - protocol: TCP - targetPort: 80 - selector: - app: nginx - type: LoadBalancer -``` - -In the service we used multiple annptations. The annotation `service.beta.kubernetes.io/azure-load-balancer-internal` is used to create an internal load balancer. The annotation `external-dns.alpha.kubernetes.io/hostname` is used to create a DNS record for the load balancer that will point to the internal IP address in the VNET allocated by the internal load balancer. The annotation `external-dns.alpha.kubernetes.io/internal-hostname` is used to create a private DNS record for the load balancer that will point to the cluster IP. - -## Install NGINX Ingress Controller (Optional) - -Helm is used to deploy the ingress controller. - -We employ the popular chart [ingress-nginx](https://github.com/kubernetes/ingress-nginx/tree/main/charts/ingress-nginx). - -``` -$ helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx -$ helm repo update -$ helm install [RELEASE_NAME] ingress-nginx/ingress-nginx - --set controller.publishService.enabled=true -``` - -The parameter `controller.publishService.enabled` needs to be set to `true.` - -It will make the ingress controller update the endpoint records of ingress-resources to contain the external-ip of the loadbalancer serving the ingress-controller. -This is crucial as ExternalDNS reads those endpoints records when creating DNS-Records from ingress-resources. -In the subsequent parameter we will make use of this. If you don't want to work with ingress-resources in your later use, you can leave the parameter out. - -Verify the correct propagation of the loadbalancer's ip by listing the ingresses. - -``` -$ kubectl get ingress -``` - -The address column should contain the ip for each ingress. ExternalDNS will pick up exactly this piece of information. - -``` -NAME HOSTS ADDRESS PORTS AGE -nginx1 sample1.aks.com 52.167.195.110 80 6d22h -nginx2 sample2.aks.com 52.167.195.110 80 6d21h -``` - -If you do not want to deploy the ingress controller with Helm, ensure to pass the following cmdline-flags to it through the mechanism of your choice: - -``` -flags: ---publish-service=/ ---update-status=true (default-value) - -example: -./nginx-ingress-controller --publish-service=default/nginx-ingress-controller -``` - -## Expose the nginx deployment with the ingress (Optional) - -Apply the following manifest to create an ingress resource that will expose the nginx deployment. The ingress resource backend points to a `ClusterIP` service that is needed to select the pods that will receive the traffic. - -```yaml ---- -apiVersion: v1 -kind: Service -metadata: - name: nginx-svc-clusterip spec: ports: - port: 80 @@ -410,7 +374,7 @@ spec: selector: app: nginx type: ClusterIP - + --- apiVersion: networking.k8s.io/v1 kind: Ingress @@ -425,7 +389,7 @@ spec: paths: - backend: service: - name: nginx-svc-clusterip + name: nginx-svc port: number: 80 pathType: Prefix @@ -439,7 +403,7 @@ Create the deployment, service and ingress object: $ kubectl create -f nginx.yaml ``` -Since your external IP would have already been assigned to the nginx-ingress service, the DNS records pointing to the IP of the nginx-ingress service should be created within a minute. +Since your external IP would have already been assigned to the nginx-ingress service, the DNS records pointing to the IP of the nginx-ingress service should be created within a minute. ## Verify created records diff --git a/docs/tutorials/azure.md b/docs/tutorials/azure.md index 47974a1c10..96128f1bab 100644 --- a/docs/tutorials/azure.md +++ b/docs/tutorials/azure.md @@ -356,7 +356,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service - --source=ingress @@ -424,7 +424,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service - --source=ingress @@ -495,7 +495,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service - --source=ingress @@ -518,7 +518,7 @@ Create the deployment for ExternalDNS: $ kubectl create --namespace "default" --filename externaldns.yaml ``` -## Ingress Option: Expose an nginx service with an ingress +## Deploying an Nginx Service Create a file called `nginx.yaml` with the following contents: @@ -586,49 +586,6 @@ $ kubectl create --namespace "default" --filename nginx.yaml Since your external IP would have already been assigned to the nginx-ingress service, the DNS records pointing to the IP of the nginx-ingress service should be created within a minute. -## Azure Load Balancer option: Expose an nginx service with a load balancer - -Create a file called `nginx.yaml` with the following contents: - -```yaml ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: nginx -spec: - selector: - matchLabels: - app: nginx - template: - metadata: - labels: - app: nginx - spec: - containers: - - image: nginx - name: nginx - ports: - - containerPort: 80 ---- -apiVersion: v1 -kind: Service -annotations: - external-dns.alpha.kubernetes.io/hostname: server.example.com -metadata: - name: nginx-svc -spec: - ports: - - port: 80 - protocol: TCP - targetPort: 80 - selector: - app: nginx - type: LoadBalancer -``` - -The annotation `external-dns.alpha.kubernetes.io/hostname` is used to specify the DNS name that should be created for the service. The annotation value is a comma separated list of host names. - ## Verifying Azure DNS records Run the following command to view the A records for your Azure DNS zone: diff --git a/docs/tutorials/bluecat.md b/docs/tutorials/bluecat.md index f0cd4295e1..075e9f6300 100644 --- a/docs/tutorials/bluecat.md +++ b/docs/tutorials/bluecat.md @@ -46,7 +46,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --log-level=debug - --source=service @@ -136,7 +136,7 @@ spec: secretName: bluecatconfig containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 volumeMounts: - name: bluecatconfig mountPath: "/etc/external-dns/" diff --git a/docs/tutorials/civo.md b/docs/tutorials/civo.md index 52cd8dfe70..ebba6a7272 100644 --- a/docs/tutorials/civo.md +++ b/docs/tutorials/civo.md @@ -41,7 +41,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. @@ -105,7 +105,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. diff --git a/docs/tutorials/cloudflare.md b/docs/tutorials/cloudflare.md index 6f03ba5dd7..b992e2034d 100644 --- a/docs/tutorials/cloudflare.md +++ b/docs/tutorials/cloudflare.md @@ -50,7 +50,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. @@ -118,7 +118,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. diff --git a/docs/tutorials/contour.md b/docs/tutorials/contour.md index 649fddd09f..1df2fb8e57 100644 --- a/docs/tutorials/contour.md +++ b/docs/tutorials/contour.md @@ -26,7 +26,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service - --source=ingress @@ -102,7 +102,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service - --source=ingress diff --git a/docs/tutorials/coredns.md b/docs/tutorials/coredns.md index 0f6e2d3eaf..a4c30e58b6 100644 --- a/docs/tutorials/coredns.md +++ b/docs/tutorials/coredns.md @@ -108,7 +108,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=ingress - --provider=coredns @@ -175,7 +175,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=ingress - --provider=coredns diff --git a/docs/tutorials/designate.md b/docs/tutorials/designate.md index c2317e7203..d8e342fb79 100644 --- a/docs/tutorials/designate.md +++ b/docs/tutorials/designate.md @@ -59,7 +59,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. @@ -136,7 +136,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. diff --git a/docs/tutorials/digitalocean.md b/docs/tutorials/digitalocean.md index 83431b7aae..f0a8b07da5 100644 --- a/docs/tutorials/digitalocean.md +++ b/docs/tutorials/digitalocean.md @@ -43,7 +43,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. @@ -107,7 +107,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. diff --git a/docs/tutorials/dnsimple.md b/docs/tutorials/dnsimple.md index 1363f05fa9..ecaf6b86b9 100644 --- a/docs/tutorials/dnsimple.md +++ b/docs/tutorials/dnsimple.md @@ -35,7 +35,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone you create in DNSimple. @@ -100,7 +100,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone you create in DNSimple. diff --git a/docs/tutorials/dyn.md b/docs/tutorials/dyn.md index 5285dbe932..574ec39201 100644 --- a/docs/tutorials/dyn.md +++ b/docs/tutorials/dyn.md @@ -43,7 +43,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=ingress - --txt-prefix=_d diff --git a/docs/tutorials/exoscale.md b/docs/tutorials/exoscale.md index 0347cbf787..20f1d24797 100644 --- a/docs/tutorials/exoscale.md +++ b/docs/tutorials/exoscale.md @@ -41,7 +41,7 @@ spec: # serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=ingress # or service or both - --provider=exoscale diff --git a/docs/tutorials/externalname.md b/docs/tutorials/externalname.md index 0bf6aaff2c..15255c5313 100644 --- a/docs/tutorials/externalname.md +++ b/docs/tutorials/externalname.md @@ -27,7 +27,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --log-level=debug - --source=service diff --git a/docs/tutorials/gandi.md b/docs/tutorials/gandi.md index 52132f0474..d4bcea69d6 100644 --- a/docs/tutorials/gandi.md +++ b/docs/tutorials/gandi.md @@ -39,7 +39,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. @@ -103,7 +103,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. diff --git a/docs/tutorials/gateway-api.md b/docs/tutorials/gateway-api.md index 6172585609..38da979e2b 100644 --- a/docs/tutorials/gateway-api.md +++ b/docs/tutorials/gateway-api.md @@ -72,7 +72,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: # Add desired Gateway API Route sources. - --source=gateway-httproute diff --git a/docs/tutorials/gke.md b/docs/tutorials/gke.md index 4f3246cf79..5ff9bba027 100644 --- a/docs/tutorials/gke.md +++ b/docs/tutorials/gke.md @@ -319,7 +319,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service - --source=ingress diff --git a/docs/tutorials/gloo-proxy.md b/docs/tutorials/gloo-proxy.md index 0ec63da803..876b7b77bb 100644 --- a/docs/tutorials/gloo-proxy.md +++ b/docs/tutorials/gloo-proxy.md @@ -22,7 +22,7 @@ spec: containers: - name: external-dns # update this to the desired external-dns version - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=gloo-proxy - --gloo-namespace=custom-gloo-system # gloo system namespace. Omit to use the default (gloo-system) @@ -90,7 +90,7 @@ spec: containers: - name: external-dns # update this to the desired external-dns version - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=gloo-proxy - --gloo-namespace=custom-gloo-system # gloo system namespace. Omit to use the default (gloo-system) diff --git a/docs/tutorials/godaddy.md b/docs/tutorials/godaddy.md index 02e22a14f2..d4311272d6 100644 --- a/docs/tutorials/godaddy.md +++ b/docs/tutorials/godaddy.md @@ -44,7 +44,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. @@ -115,7 +115,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. diff --git a/docs/tutorials/hostport.md b/docs/tutorials/hostport.md index 34f94a3103..ad89671580 100644 --- a/docs/tutorials/hostport.md +++ b/docs/tutorials/hostport.md @@ -31,7 +31,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --log-level=debug - --source=service @@ -96,7 +96,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --log-level=debug - --source=service diff --git a/docs/tutorials/ibmcloud.md b/docs/tutorials/ibmcloud.md index 93784c29cd..313b3970bb 100644 --- a/docs/tutorials/ibmcloud.md +++ b/docs/tutorials/ibmcloud.md @@ -69,7 +69,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. @@ -142,7 +142,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. diff --git a/docs/tutorials/infoblox.md b/docs/tutorials/infoblox.md index 7e713e036e..ee2450f139 100644 --- a/docs/tutorials/infoblox.md +++ b/docs/tutorials/infoblox.md @@ -69,7 +69,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service - --domain-filter=example.com # (optional) limit to only example.com domains. @@ -150,7 +150,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service - --domain-filter=example.com # (optional) limit to only example.com domains. @@ -271,14 +271,6 @@ There is also the ability to filter results from the Infoblox zone_auth service --infoblox-fqdn-regex=^staging.*test.com$ ``` -## Ability to filter A, Host, CNAME and TXT records from the by name using a regular expression - -Infoblox supports filtering records by name using a regular expression. See the [Infoblox API document](https://www.infoblox.com/wp-content/uploads/infoblox-deployment-infoblox-rest-api.pdf) for examples. To use this feature, set the parameter infoblox-name-regex for external-dns to a regular expression that makes sense for you. For instance, if all your dns records end with `cluster1.example.com`, you can fetch records matching this style by setting the following: - -``` ---infoblox-name-regex=cluster1.example.com -``` - ## Infoblox PTR record support There is an option to enable PTR records support for infoblox provider. PTR records allow to do reverse dns search. To enable PTR records support, add following into arguments for external-dns: diff --git a/docs/tutorials/istio.md b/docs/tutorials/istio.md index a4e5976571..1bc529bed7 100644 --- a/docs/tutorials/istio.md +++ b/docs/tutorials/istio.md @@ -28,7 +28,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service - --source=ingress @@ -98,7 +98,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service - --source=ingress diff --git a/docs/tutorials/kong.md b/docs/tutorials/kong.md index 49a456f694..dc0e96fedb 100644 --- a/docs/tutorials/kong.md +++ b/docs/tutorials/kong.md @@ -22,7 +22,7 @@ spec: containers: - name: external-dns # update this to the desired external-dns version - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=kong-tcpingress - --provider=aws @@ -86,7 +86,7 @@ spec: containers: - name: external-dns # update this to the desired external-dns version - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=kong-tcpingress - --provider=aws diff --git a/docs/tutorials/linode.md b/docs/tutorials/linode.md index 9505a6eeaa..27ce6d5c19 100644 --- a/docs/tutorials/linode.md +++ b/docs/tutorials/linode.md @@ -41,7 +41,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. @@ -105,7 +105,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. diff --git a/docs/tutorials/nginx-ingress.md b/docs/tutorials/nginx-ingress.md index bf491ea516..a540b35d41 100644 --- a/docs/tutorials/nginx-ingress.md +++ b/docs/tutorials/nginx-ingress.md @@ -273,7 +273,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=ingress - --domain-filter=external-dns-test.gcp.zalan.do @@ -570,7 +570,7 @@ spec: - --google-project=zalando-external-dns-test - --registry=txt - --txt-owner-id=my-identifier - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 name: external-dns securityContext: fsGroup: 65534 diff --git a/docs/tutorials/nodes.md b/docs/tutorials/nodes.md index a4a1e1f156..6fd3290e35 100644 --- a/docs/tutorials/nodes.md +++ b/docs/tutorials/nodes.md @@ -28,7 +28,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=node # will use nodes as source - --provider=aws @@ -99,7 +99,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=node # will use nodes as source - --provider=aws diff --git a/docs/tutorials/ns1.md b/docs/tutorials/ns1.md index d286497f8e..2cfddca9ef 100644 --- a/docs/tutorials/ns1.md +++ b/docs/tutorials/ns1.md @@ -61,7 +61,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. @@ -125,7 +125,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. diff --git a/docs/tutorials/openshift.md b/docs/tutorials/openshift.md index 6cdda8d3ba..2776a1bb40 100644 --- a/docs/tutorials/openshift.md +++ b/docs/tutorials/openshift.md @@ -66,7 +66,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=openshift-route - --domain-filter=external-dns-test.my-org.com # will make ExternalDNS see only the hosted zones matching provided domain, omit to process all available hosted zones @@ -133,7 +133,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=openshift-route - --domain-filter=external-dns-test.my-org.com # will make ExternalDNS see only the hosted zones matching provided domain, omit to process all available hosted zones diff --git a/docs/tutorials/oracle.md b/docs/tutorials/oracle.md index 7459479727..96dfb32d7a 100644 --- a/docs/tutorials/oracle.md +++ b/docs/tutorials/oracle.md @@ -93,7 +93,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service - --source=ingress diff --git a/docs/tutorials/ovh.md b/docs/tutorials/ovh.md index bdf5315206..181ed011fa 100644 --- a/docs/tutorials/ovh.md +++ b/docs/tutorials/ovh.md @@ -86,7 +86,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. @@ -160,7 +160,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. diff --git a/docs/tutorials/pdns.md b/docs/tutorials/pdns.md index 5cd492e3bf..f81d058a40 100644 --- a/docs/tutorials/pdns.md +++ b/docs/tutorials/pdns.md @@ -42,7 +42,7 @@ spec: # serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # or ingress or both - --provider=pdns diff --git a/docs/tutorials/pihole.md b/docs/tutorials/pihole.md index a55c8589b8..01824ea498 100644 --- a/docs/tutorials/pihole.md +++ b/docs/tutorials/pihole.md @@ -78,7 +78,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:latest # If authentication is disabled and/or you didn't create # a secret, you can remove this block. envFrom: diff --git a/docs/tutorials/plural.md b/docs/tutorials/plural.md index c6c1404248..43408c7c4d 100644 --- a/docs/tutorials/plural.md +++ b/docs/tutorials/plural.md @@ -35,7 +35,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. @@ -105,7 +105,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. diff --git a/docs/tutorials/public-private-route53.md b/docs/tutorials/public-private-route53.md index 284da28a4d..6f6434cb7c 100644 --- a/docs/tutorials/public-private-route53.md +++ b/docs/tutorials/public-private-route53.md @@ -243,7 +243,7 @@ spec: - --txt-owner-id=external-dns - --annotation-filter=kubernetes.io/ingress.class in (external-ingress) - --aws-zone-type=public - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 name: external-dns-public ``` @@ -281,7 +281,7 @@ spec: - --txt-owner-id=dev.k8s.nexus - --annotation-filter=kubernetes.io/ingress.class in (internal-ingress) - --aws-zone-type=private - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 name: external-dns-private ``` diff --git a/docs/tutorials/rcodezero.md b/docs/tutorials/rcodezero.md index 95a6115e2d..df0a946148 100644 --- a/docs/tutorials/rcodezero.md +++ b/docs/tutorials/rcodezero.md @@ -53,7 +53,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. @@ -120,7 +120,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. diff --git a/docs/tutorials/rdns.md b/docs/tutorials/rdns.md index b6f9a3b890..6efa6f5e48 100644 --- a/docs/tutorials/rdns.md +++ b/docs/tutorials/rdns.md @@ -54,7 +54,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=ingress - --provider=rdns @@ -123,7 +123,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=ingress - --provider=rdns diff --git a/docs/tutorials/rfc2136.md b/docs/tutorials/rfc2136.md index 980df16af0..47f916a317 100644 --- a/docs/tutorials/rfc2136.md +++ b/docs/tutorials/rfc2136.md @@ -218,7 +218,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --registry=txt - --txt-prefix=external-dns- @@ -260,7 +260,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --registry=txt - --txt-prefix=external-dns- diff --git a/docs/tutorials/scaleway.md b/docs/tutorials/scaleway.md index ae903c6cb3..b3b7ca88ac 100644 --- a/docs/tutorials/scaleway.md +++ b/docs/tutorials/scaleway.md @@ -53,7 +53,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. @@ -121,7 +121,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. diff --git a/docs/tutorials/security-context.md b/docs/tutorials/security-context.md index 785f38b0e6..320e5b8378 100644 --- a/docs/tutorials/security-context.md +++ b/docs/tutorials/security-context.md @@ -20,7 +20,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - ... # your arguments here securityContext: diff --git a/docs/tutorials/tencentcloud.md b/docs/tutorials/tencentcloud.md index 902ae87bed..067a3b7c4e 100644 --- a/docs/tutorials/tencentcloud.md +++ b/docs/tutorials/tencentcloud.md @@ -129,7 +129,7 @@ spec: - --policy=sync # set `upsert-only` would prevent ExternalDNS from deleting any records - --tencent-cloud-zone-type=private # only look at private hosted zones. set `public` to use the public dns service. - --tencent-cloud-config-file=/etc/kubernetes/tencent-cloud.json - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 imagePullPolicy: Always name: external-dns resources: {} diff --git a/docs/tutorials/transip.md b/docs/tutorials/transip.md index e9b445e7fc..7b884b4c1b 100644 --- a/docs/tutorials/transip.md +++ b/docs/tutorials/transip.md @@ -36,7 +36,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains @@ -107,7 +107,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains diff --git a/docs/tutorials/ultradns.md b/docs/tutorials/ultradns.md index c112185ab8..bc025e8a03 100644 --- a/docs/tutorials/ultradns.md +++ b/docs/tutorials/ultradns.md @@ -44,7 +44,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service - --source=ingress # ingress is also possible @@ -116,7 +116,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service - --source=ingress diff --git a/docs/tutorials/vinyldns.md b/docs/tutorials/vinyldns.md index bf15795cc3..15e5e138b0 100644 --- a/docs/tutorials/vinyldns.md +++ b/docs/tutorials/vinyldns.md @@ -66,7 +66,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --provider=vinyldns - --source=service @@ -137,7 +137,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --provider=vinyldns - --source=service diff --git a/docs/tutorials/vultr.md b/docs/tutorials/vultr.md index 81fa6060a3..1384734c40 100644 --- a/docs/tutorials/vultr.md +++ b/docs/tutorials/vultr.md @@ -42,7 +42,7 @@ spec: spec: containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. @@ -106,7 +106,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: registry.k8s.io/external-dns/external-dns:v0.13.2 + image: registry.k8s.io/external-dns/external-dns:v0.13.1 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. diff --git a/endpoint/labels.go b/endpoint/labels.go index 797190db41..544eb3e7a5 100644 --- a/endpoint/labels.go +++ b/endpoint/labels.go @@ -32,8 +32,6 @@ const ( OwnerLabelKey = "owner" // ResourceLabelKey is the name of the label that identifies k8s resource which wants to acquire the DNS name ResourceLabelKey = "resource" - // OwnedRecordLabelKey is the name of the label that identifies the record that is owned by the labeled TXT registry record - OwnedRecordLabelKey = "ownedRecord" // AWSSDDescriptionLabel label responsible for storing raw owner/resource combination information in the Labels // supposed to be inserted by AWS SD Provider, and parsed into OwnerLabelKey and ResourceLabelKey key by AWS SD Registry diff --git a/go.mod b/go.mod index 6ea67c4892..d8299df8b7 100644 --- a/go.mod +++ b/go.mod @@ -19,12 +19,12 @@ require ( github.com/aws/aws-sdk-go v1.44.136 github.com/bodgit/tsig v1.2.0 github.com/civo/civogo v0.3.14 - github.com/cloudflare/cloudflare-go v0.58.1 + github.com/cloudflare/cloudflare-go v0.50.0 github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381 github.com/datawire/ambassador v1.6.0 github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba github.com/digitalocean/godo v1.81.0 - github.com/dnsimple/dnsimple-go v1.0.1 + github.com/dnsimple/dnsimple-go v0.71.1 github.com/exoscale/egoscale v1.19.0 github.com/ffledgling/pdns-go v0.0.0-20180219074714-524e7daccd99 github.com/go-gandi/go-gandi v0.5.0 @@ -50,9 +50,9 @@ require ( github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f github.com/sirupsen/logrus v1.9.0 github.com/stretchr/testify v1.8.1 - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.599 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.550 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.344 - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns v1.0.599 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns v1.0.550 github.com/transip/gotransip/v6 v6.17.0 github.com/ultradns/ultradns-sdk-go v0.0.0-20200616202852-e62052662f60 github.com/vinyldns/go-vinyldns v0.0.0-20200211145900-fe8a3d82e556 @@ -60,7 +60,7 @@ require ( go.etcd.io/etcd/api/v3 v3.5.5 go.etcd.io/etcd/client/v3 v3.5.5 go.uber.org/ratelimit v0.2.0 - golang.org/x/net v0.7.0 + golang.org/x/net v0.4.0 golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 google.golang.org/api v0.93.0 @@ -124,7 +124,7 @@ require ( github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/go-retryablehttp v0.7.2 // indirect + github.com/hashicorp/go-retryablehttp v0.7.1 // indirect github.com/hashicorp/go-uuid v1.0.2 // indirect github.com/imdario/mergo v0.3.13 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect @@ -147,6 +147,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/neticdk/tidydns-go v0.0.3 // indirect github.com/nxadm/tail v1.4.8 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/openshift/gssapi v0.0.0-20161010215902-5fb4217df13b // indirect @@ -173,9 +174,9 @@ require ( go.uber.org/zap v1.19.1 // indirect golang.org/x/crypto v0.1.0 // indirect golang.org/x/mod v0.6.0 // indirect - golang.org/x/sys v0.5.0 // indirect - golang.org/x/term v0.5.0 // indirect - golang.org/x/text v0.7.0 // indirect + golang.org/x/sys v0.3.0 // indirect + golang.org/x/term v0.3.0 // indirect + golang.org/x/text v0.5.0 // indirect golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect golang.org/x/tools v0.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index 847140a182..dad0e515fc 100644 --- a/go.sum +++ b/go.sum @@ -216,8 +216,8 @@ github.com/civo/civogo v0.3.14 h1:W+o+hFXtEhWyJOmZOm2C5s8OEorSXGP6eyPYOa69NA8= github.com/civo/civogo v0.3.14/go.mod h1:SbS06e0JPgIF27r1sLC97gjU1xWmONQeHgzF1hfLpak= 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.58.1 h1:+Tqt4N9nuNEMgSC3tCQOixyifU5jihaq+JfDQidTSgY= -github.com/cloudflare/cloudflare-go v0.58.1/go.mod h1:QaA8x4JI0/gA/tni1nTdyimFuyEGJi8cB7YSGoFhXFo= +github.com/cloudflare/cloudflare-go v0.50.0 h1:RS4tttMecD1rYCiMMfJeW8s9OEhCm85Y+70RJuOoxNA= +github.com/cloudflare/cloudflare-go v0.50.0/go.mod h1:4+j2gGo6xyrFiYmpa2y4mNzu7pPPN42kyv1b2EqiZGQ= github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381 h1:rdRS5BT13Iae9ssvcslol66gfOOXjaLYwqerEn/cl9s= github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381/go.mod h1:e5+USP2j8Le2M0Jo3qKPFnNhuo1wueU4nWHCXBOfQ14= github.com/cncf/udpa v0.0.0-20200324003616-bae28a880fdb/go.mod h1:HNVadOiXCy7Jk3R2knJ+qm++zkncJxxBMpjdGgJ+UJc= @@ -284,8 +284,8 @@ github.com/digitalocean/godo v1.81.0 h1:sjb3fOfPfSlUQUK22E87BcI8Zx2qtnF7VUCCO4UK github.com/digitalocean/godo v1.81.0/go.mod h1:BPCqvwbjbGqxuUnIKB4EvS/AX7IDnNmt5fwvIkWo+ew= github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= -github.com/dnsimple/dnsimple-go v1.0.1 h1:ueDji5xvz6+hLA4JPNvOXGYGHelex0TT7uXdN5ZEWnQ= -github.com/dnsimple/dnsimple-go v1.0.1/go.mod h1:iw/53UDs5RV4ptHVyNrBBr7GHKnndETsP0J/n/JVnA4= +github.com/dnsimple/dnsimple-go v0.71.1 h1:1hGoBA3CIjpjZj5DM3081xfxr4e2jYmYnkO2VuBF8Qc= +github.com/dnsimple/dnsimple-go v0.71.1/go.mod h1:F9WHww9cC76hrnwGFfAfrqdW99j3MOYasQcIwTS/aUk= github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v0.0.0-20191216044856-a8371794149d/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= @@ -649,8 +649,8 @@ github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHh github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0= -github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ= +github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= @@ -859,6 +859,8 @@ github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uY github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/nesv/go-dynect v0.6.0 h1:Ow/DiSm4LAISwnFku/FITSQHnU6pBvhQMsUE5Gu6Oq4= github.com/nesv/go-dynect v0.6.0/go.mod h1:GHRBRKzTwjAMhosHJQq/KrZaFkXIFyJ5zRE7thGXXrs= +github.com/neticdk/tidydns-go v0.0.3 h1:S/fBb3qzSF1vjhSDdXRo+fFE/7XPZKBUJr1bPVarB5c= +github.com/neticdk/tidydns-go v0.0.3/go.mod h1:EGd1iL3+g67y4zxEybaEV0ZK/LwcVubBhePAx+WLK1E= github.com/nic-at/rc0go v1.1.1 h1:bf2gTwYecJEh7qmnOEuarXKueZn4A8N08U1Uop3K8+s= github.com/nic-at/rc0go v1.1.1/go.mod h1:KEa3H5fmDNXCaXSqOeAZxkKnG/8ggr1OHIG25Ve7fjU= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= @@ -1097,12 +1099,12 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.599 h1:9rMFA8++HynZHYz32gAluJ2ONtz7NjhlBaiomVHWwdw= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.599/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.550 h1:Yni5V2K50ke+YAdq2Y2C0F8wrz2f4BM6WXQU2g+/m2Y= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.550/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.344 h1:pdwJ6T3iEjP5nB9Mgi4y/OBO8XNtkGN2/+mjGZ8yCbw= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.344/go.mod h1:CuOaLxOQr477GhMWAQPYQFUJrsZbW+ZqkAgP2uHDZXg= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns v1.0.599 h1:VQqI9ln8dsCDCOleLvm8bR1/g8q8x2QIiMyzRLRrwWg= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns v1.0.599/go.mod h1:GexzvtWfywrNN4h0+enS8iZBu2OeL6ArsSdcG1ScrwI= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns v1.0.550 h1:dJ5Rhnrx8lGd1dzfeuZvFK5nvMWe/qAp8U164fh86PM= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns v1.0.550/go.mod h1:wzxhy082eCcH3tVMl7J+YtXDY+EnNO+xCJP8CdsLrDg= 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 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= @@ -1330,8 +1332,8 @@ golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190130055435-99b60b757ec1/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1474,14 +1476,14 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1493,8 +1495,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/internal/testutils/endpoint.go b/internal/testutils/endpoint.go index f8b4657958..033b2e03de 100644 --- a/internal/testutils/endpoint.go +++ b/internal/testutils/endpoint.go @@ -62,7 +62,6 @@ func SameEndpoint(a, b *endpoint.Endpoint) bool { return a.DNSName == b.DNSName && a.Targets.Same(b.Targets) && a.RecordType == b.RecordType && a.SetIdentifier == b.SetIdentifier && a.Labels[endpoint.OwnerLabelKey] == b.Labels[endpoint.OwnerLabelKey] && a.RecordTTL == b.RecordTTL && a.Labels[endpoint.ResourceLabelKey] == b.Labels[endpoint.ResourceLabelKey] && - a.Labels[endpoint.OwnedRecordLabelKey] == b.Labels[endpoint.OwnedRecordLabelKey] && SameProviderSpecific(a.ProviderSpecific, b.ProviderSpecific) } diff --git a/kustomize/kustomization.yaml b/kustomize/kustomization.yaml index 03d30833da..294b5a2d8f 100644 --- a/kustomize/kustomization.yaml +++ b/kustomize/kustomization.yaml @@ -3,7 +3,7 @@ kind: Kustomization images: - name: registry.k8s.io/external-dns/external-dns - newTag: v0.13.2 + newTag: v0.13.1 resources: - ./external-dns-deployment.yaml diff --git a/main.go b/main.go index 2f9e146b3f..ef7fa27800 100644 --- a/main.go +++ b/main.go @@ -68,6 +68,7 @@ import ( "sigs.k8s.io/external-dns/provider/safedns" "sigs.k8s.io/external-dns/provider/scaleway" "sigs.k8s.io/external-dns/provider/tencentcloud" + "sigs.k8s.io/external-dns/provider/tidydns" "sigs.k8s.io/external-dns/provider/transip" "sigs.k8s.io/external-dns/provider/ultradns" "sigs.k8s.io/external-dns/provider/vinyldns" @@ -260,8 +261,7 @@ func main() { View: cfg.InfobloxView, MaxResults: cfg.InfobloxMaxResults, DryRun: cfg.DryRun, - FQDNRegEx: cfg.InfobloxFQDNRegEx, - NameRegEx: cfg.InfobloxNameRegEx, + FQDNRexEx: cfg.InfobloxFQDNRegEx, CreatePTR: cfg.InfobloxCreatePTR, CacheDuration: cfg.InfobloxCacheDuration, }, @@ -355,6 +355,8 @@ func main() { p, err = plural.NewPluralProvider(cfg.PluralCluster, cfg.PluralProvider) case "tencentcloud": p, err = tencentcloud.NewTencentCloudProvider(domainFilter, zoneIDFilter, cfg.TencentCloudConfigFile, cfg.TencentCloudZoneType, cfg.DryRun) + case "tidydns": + p, err = tidydns.NewTidyDNSProvider(domainFilter, zoneIDFilter, cfg.TidyDNSEndpoint, cfg.DryRun) default: log.Fatalf("unknown dns provider: %s", cfg.Provider) } diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index c77e3a3a0b..83fbf98638 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -123,7 +123,6 @@ type Config struct { InfobloxView string InfobloxMaxResults int InfobloxFQDNRegEx string - InfobloxNameRegEx string InfobloxCreatePTR bool InfobloxCacheDuration int DynCustomerName string @@ -199,6 +198,7 @@ type Config struct { PiholeTLSInsecureSkipVerify bool PluralCluster string PluralProvider string + TidyDNSEndpoint string } var defaultConfig = &Config{ @@ -341,6 +341,7 @@ var defaultConfig = &Config{ PiholeTLSInsecureSkipVerify: false, PluralCluster: "", PluralProvider: "", + TidyDNSEndpoint: "", } // NewConfig returns new Config object @@ -430,7 +431,7 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("exclude-target-net", "Exclude target nets (optional)").StringsVar(&cfg.ExcludeTargetNets) // Flags related to providers - providers := []string{"akamai", "alibabacloud", "aws", "aws-sd", "azure", "azure-dns", "azure-private-dns", "bluecat", "civo", "cloudflare", "coredns", "designate", "digitalocean", "dnsimple", "dyn", "exoscale", "gandi", "godaddy", "google", "ibmcloud", "infoblox", "inmemory", "linode", "ns1", "oci", "ovh", "pdns", "pihole", "plural", "rcodezero", "rdns", "rfc2136", "safedns", "scaleway", "skydns", "tencentcloud", "transip", "ultradns", "vinyldns", "vultr"} + providers := []string{"akamai", "alibabacloud", "aws", "aws-sd", "azure", "azure-dns", "azure-private-dns", "bluecat", "civo", "cloudflare", "coredns", "designate", "digitalocean", "dnsimple", "dyn", "exoscale", "gandi", "godaddy", "google", "ibmcloud", "infoblox", "inmemory", "linode", "ns1", "oci", "ovh", "pdns", "pihole", "plural", "rcodezero", "rdns", "rfc2136", "safedns", "scaleway", "skydns", "tencentcloud", "transip", "ultradns", "vinyldns", "vultr", "tidydns"} app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: "+strings.Join(providers, ", ")+")").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, providers...) app.Flag("domain-filter", "Limit possible target zones by a domain suffix; specify multiple times for multiple domains (optional)").Default("").StringsVar(&cfg.DomainFilter) app.Flag("exclude-domains", "Exclude subdomains (optional)").Default("").StringsVar(&cfg.ExcludeDomains) @@ -490,7 +491,6 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("infoblox-view", "DNS view (default: \"\")").Default(defaultConfig.InfobloxView).StringVar(&cfg.InfobloxView) app.Flag("infoblox-max-results", "Add _max_results as query parameter to the URL on all API requests. The default is 0 which means _max_results is not set and the default of the server is used.").Default(strconv.Itoa(defaultConfig.InfobloxMaxResults)).IntVar(&cfg.InfobloxMaxResults) app.Flag("infoblox-fqdn-regex", "Apply this regular expression as a filter for obtaining zone_auth objects. This is disabled by default.").Default(defaultConfig.InfobloxFQDNRegEx).StringVar(&cfg.InfobloxFQDNRegEx) - app.Flag("infoblox-name-regex", "Apply this regular expression as a filter on the name field for obtaining infoblox records. This is disabled by default.").Default(defaultConfig.InfobloxNameRegEx).StringVar(&cfg.InfobloxNameRegEx) app.Flag("infoblox-create-ptr", "When using the Infoblox provider, create a ptr entry in addition to an entry").Default(strconv.FormatBool(defaultConfig.InfobloxCreatePTR)).BoolVar(&cfg.InfobloxCreatePTR) app.Flag("infoblox-cache-duration", "When using the Infoblox provider, set the record TTL (0s to disable).").Default(strconv.Itoa(defaultConfig.InfobloxCacheDuration)).IntVar(&cfg.InfobloxCacheDuration) app.Flag("dyn-customer-name", "When using the Dyn provider, specify the Customer Name").Default("").StringVar(&cfg.DynCustomerName) @@ -555,6 +555,9 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("plural-cluster", "When using the plural provider, specify the cluster name you're running with").Default(defaultConfig.PluralCluster).StringVar(&cfg.PluralCluster) app.Flag("plural-provider", "When using the plural provider, specify the provider name you're running with").Default(defaultConfig.PluralProvider).StringVar(&cfg.PluralProvider) + // Flags related to TidyDNS + app.Flag("tidydns-endpoint", "Provide the endpoint for the TidyDNS service").Default(defaultConfig.TidyDNSEndpoint).StringVar(&cfg.TidyDNSEndpoint) + // Flags related to policies app.Flag("policy", "Modify how DNS records are synchronized between sources and providers (default: sync, options: sync, upsert-only, create-only)").Default(defaultConfig.Policy).EnumVar(&cfg.Policy, "sync", "upsert-only", "create-only") diff --git a/pkg/apis/externaldns/types_test.go b/pkg/apis/externaldns/types_test.go index 6cd42b5b4f..ce9172bce7 100644 --- a/pkg/apis/externaldns/types_test.go +++ b/pkg/apis/externaldns/types_test.go @@ -129,6 +129,7 @@ var ( IBMCloudConfigFile: "/etc/kubernetes/ibmcloud.json", TencentCloudConfigFile: "/etc/kubernetes/tencent-cloud.json", TencentCloudZoneType: "", + TidyDNSEndpoint: "", } overriddenConfig = &Config{ @@ -239,6 +240,7 @@ var ( IBMCloudConfigFile: "ibmcloud.json", TencentCloudConfigFile: "tencent-cloud.json", TencentCloudZoneType: "private", + TidyDNSEndpoint: "https://tidy.example.com/index.cgi", } ) @@ -379,6 +381,7 @@ func TestParseFlags(t *testing.T) { "--ibmcloud-config-file=ibmcloud.json", "--tencent-cloud-config-file=tencent-cloud.json", "--tencent-cloud-zone-type=private", + "--tidydns-endpoint=https://tidy.example.com/index.cgi", }, envVars: map[string]string{}, expected: overriddenConfig, @@ -494,6 +497,7 @@ func TestParseFlags(t *testing.T) { "EXTERNAL_DNS_IBMCLOUD_CONFIG_FILE": "ibmcloud.json", "EXTERNAL_DNS_TENCENT_CLOUD_CONFIG_FILE": "tencent-cloud.json", "EXTERNAL_DNS_TENCENT_CLOUD_ZONE_TYPE": "private", + "EXTERNAL_DNS_TIDYDNS_ENDPOINT": "https://tidy.example.com/index.cgi", }, expected: overriddenConfig, }, diff --git a/provider/alibabacloud/alibaba_cloud.go b/provider/alibabacloud/alibaba_cloud.go index a43e62c4a2..ccd9c7caa0 100644 --- a/provider/alibabacloud/alibaba_cloud.go +++ b/provider/alibabacloud/alibaba_cloud.go @@ -390,7 +390,6 @@ func (p *AlibabaCloudProvider) records() ([]alidns.Record, error) { } } else { for _, domainName := range p.domainFilter.Filters { - _, domainName = p.splitDNSName(domainName) tmpResults, err := p.getDomainRecords(domainName) if err != nil { log.Errorf("getDomainRecords %s error %v", domainName, err) @@ -443,7 +442,7 @@ func (p *AlibabaCloudProvider) getDomainRecords(domainName string) ([]alidns.Rec } for _, record := range response.DomainRecords.Record { - domainName := record.RR + "." + record.DomainName + domainName := record.DomainName recordType := record.Type if !p.domainFilter.Match(domainName) { @@ -495,7 +494,7 @@ func (p *AlibabaCloudProvider) unescapeTXTRecordValue(value string) string { } func (p *AlibabaCloudProvider) createRecord(endpoint *endpoint.Endpoint, target string) error { - rr, domain := p.splitDNSName(endpoint.DNSName) + rr, domain := p.splitDNSName(endpoint) request := alidns.CreateAddDomainRecordRequest() request.DomainName = domain request.Type = endpoint.RecordType @@ -659,24 +658,44 @@ func (p *AlibabaCloudProvider) updateRecords(recordMap map[string][]alidns.Recor return nil } -func (p *AlibabaCloudProvider) splitDNSName(fullName string) (rr string, domain string) { - name := strings.TrimSuffix(fullName, ".") - parts := strings.Split(name, ".") - if len(parts) < 2 { - rr = name - domain = "" - } else { - domain = parts[len(parts)-2] + "." + parts[len(parts)-1] - rrIndex := strings.Index(name, domain) - if rrIndex < 1 { - rrIndex = 1 +func (p *AlibabaCloudProvider) splitDNSName(endpoint *endpoint.Endpoint) (rr string, domain string) { + name := strings.TrimSuffix(endpoint.DNSName, ".") + + found := false + + for _, filter := range p.domainFilter.Filters { + if strings.HasSuffix(name, "."+filter) { + rr = name[0 : len(name)-len(filter)-1] + domain = filter + found = true + break + } else if name == filter { + domain = filter + rr = "" + found = true } - rr = name[0 : rrIndex-1] } + + if !found { + parts := strings.Split(name, ".") + if len(parts) < 2 { + rr = name + domain = "" + } else { + domain = parts[len(parts)-2] + "." + parts[len(parts)-1] + rrIndex := strings.Index(name, domain) + if rrIndex < 1 { + rrIndex = 1 + } + rr = name[0 : rrIndex-1] + } + } + if rr == "" { rr = nullHostAlibabaCloud } - return + + return rr, domain } func (p *AlibabaCloudProvider) matchVPC(zoneID string) bool { @@ -844,7 +863,7 @@ func (p *AlibabaCloudProvider) privateZoneRecords() (endpoints []*endpoint.Endpo } func (p *AlibabaCloudProvider) createPrivateZoneRecord(zones map[string]*alibabaPrivateZone, endpoint *endpoint.Endpoint, target string) error { - rr, domain := p.splitDNSName(endpoint.DNSName) + rr, domain := p.splitDNSName(endpoint) zone := zones[domain] if zone == nil { err := fmt.Errorf("failed to find private zone '%s'", domain) @@ -914,7 +933,7 @@ func (p *AlibabaCloudProvider) deletePrivateZoneRecord(recordID int64) error { func (p *AlibabaCloudProvider) deletePrivateZoneRecords(zones map[string]*alibabaPrivateZone, endpoints []*endpoint.Endpoint) error { for _, endpoint := range endpoints { - rr, domain := p.splitDNSName(endpoint.DNSName) + rr, domain := p.splitDNSName(endpoint) zone := zones[domain] if zone == nil { @@ -1004,7 +1023,7 @@ func (p *AlibabaCloudProvider) equalsPrivateZone(record pvtz.Record, endpoint *e func (p *AlibabaCloudProvider) updatePrivateZoneRecords(zones map[string]*alibabaPrivateZone, endpoints []*endpoint.Endpoint) error { for _, endpoint := range endpoints { - rr, domain := p.splitDNSName(endpoint.DNSName) + rr, domain := p.splitDNSName(endpoint) zone := zones[domain] if zone == nil { err := fmt.Errorf("failed to find private zone '%s'", domain) diff --git a/provider/alibabacloud/alibaba_cloud_test.go b/provider/alibabacloud/alibaba_cloud_test.go index e2ebd0ec99..2e0fc86527 100644 --- a/provider/alibabacloud/alibaba_cloud_test.go +++ b/provider/alibabacloud/alibaba_cloud_test.go @@ -18,9 +18,10 @@ package alibabacloud import ( "context" + "testing" + "github.com/aliyun/alibaba-cloud-sdk-go/services/alidns" "github.com/aliyun/alibaba-cloud-sdk-go/services/pvtz" - "testing" "sigs.k8s.io/external-dns/endpoint" "sigs.k8s.io/external-dns/plan" @@ -392,42 +393,42 @@ func TestAlibabaCloudProvider_splitDNSName(t *testing.T) { p := newTestAlibabaCloudProvider(false) endpoint := &endpoint.Endpoint{} endpoint.DNSName = "www.example.org" - rr, domain := p.splitDNSName(endpoint.DNSName) + rr, domain := p.splitDNSName(endpoint) if rr != "www" || domain != "example.org" { t.Errorf("Failed to splitDNSName for %s: rr=%s, domain=%s", endpoint.DNSName, rr, domain) } endpoint.DNSName = ".example.org" - rr, domain = p.splitDNSName(endpoint.DNSName) + rr, domain = p.splitDNSName(endpoint) if rr != "@" || domain != "example.org" { t.Errorf("Failed to splitDNSName for %s: rr=%s, domain=%s", endpoint.DNSName, rr, domain) } endpoint.DNSName = "www" - rr, domain = p.splitDNSName(endpoint.DNSName) + rr, domain = p.splitDNSName(endpoint) if rr != "www" || domain != "" { t.Errorf("Failed to splitDNSName for %s: rr=%s, domain=%s", endpoint.DNSName, rr, domain) } endpoint.DNSName = "" - rr, domain = p.splitDNSName(endpoint.DNSName) + rr, domain = p.splitDNSName(endpoint) if rr != "@" || domain != "" { t.Errorf("Failed to splitDNSName for %s: rr=%s, domain=%s", endpoint.DNSName, rr, domain) } endpoint.DNSName = "_30000._tcp.container-service.top" - rr, domain = p.splitDNSName(endpoint.DNSName) + rr, domain = p.splitDNSName(endpoint) if rr != "_30000._tcp" || domain != "container-service.top" { t.Errorf("Failed to splitDNSName for %s: rr=%s, domain=%s", endpoint.DNSName, rr, domain) } endpoint.DNSName = "container-service.top" - rr, domain = p.splitDNSName(endpoint.DNSName) + rr, domain = p.splitDNSName(endpoint) if rr != "@" || domain != "container-service.top" { t.Errorf("Failed to splitDNSName for %s: rr=%s, domain=%s", endpoint.DNSName, rr, domain) } endpoint.DNSName = "a.b.container-service.top" - rr, domain = p.splitDNSName(endpoint.DNSName) + rr, domain = p.splitDNSName(endpoint) if rr != "a.b" || domain != "container-service.top" { t.Errorf("Failed to splitDNSName for %s: rr=%s, domain=%s", endpoint.DNSName, rr, domain) } endpoint.DNSName = "a.b.c.container-service.top" - rr, domain = p.splitDNSName(endpoint.DNSName) + rr, domain = p.splitDNSName(endpoint) if rr != "a.b.c" || domain != "container-service.top" { t.Errorf("Failed to splitDNSName for %s: rr=%s, domain=%s", endpoint.DNSName, rr, domain) } diff --git a/provider/aws/aws.go b/provider/aws/aws.go index 6818cc3755..b1b5e6aa59 100644 --- a/provider/aws/aws.go +++ b/provider/aws/aws.go @@ -80,7 +80,6 @@ var canonicalHostedZones = map[string]string{ "ap-southeast-3.elb.amazonaws.com": "Z08888821HLRG5A9ZRTER", "ap-northeast-1.elb.amazonaws.com": "Z14GRHDCWA56QT", "eu-central-1.elb.amazonaws.com": "Z215JYRZR1TBD5", - "eu-central-2.elb.amazonaws.com": "Z06391101F2ZOEP8P5EB3", "eu-west-1.elb.amazonaws.com": "Z32O12XQLNTSW2", "eu-west-2.elb.amazonaws.com": "ZHURV8PSTC4K8", "eu-west-3.elb.amazonaws.com": "Z3Q77PNBQS71R4", @@ -102,14 +101,12 @@ var canonicalHostedZones = map[string]string{ "elb.ca-central-1.amazonaws.com": "Z2EPGBW3API2WT", "elb.ap-east-1.amazonaws.com": "Z12Y7K3UBGUAD1", "elb.ap-south-1.amazonaws.com": "ZVDDRBQ08TROA", - "elb.ap-northeast-3.amazonaws.com": "Z1GWIQ4HH19I5X", "elb.ap-northeast-2.amazonaws.com": "ZIBE1TIR4HY56", "elb.ap-southeast-1.amazonaws.com": "ZKVM4W9LS7TM", "elb.ap-southeast-2.amazonaws.com": "ZCT6FZBF4DROD", "elb.ap-southeast-3.amazonaws.com": "Z01971771FYVNCOVWJU1G", "elb.ap-northeast-1.amazonaws.com": "Z31USIVHYNEOWT", "elb.eu-central-1.amazonaws.com": "Z3F0SRJ5LGBH90", - "elb.eu-central-2.amazonaws.com": "Z02239872DOALSIDCX66S", "elb.eu-west-1.amazonaws.com": "Z2IFOLAFXWLO4F", "elb.eu-west-2.amazonaws.com": "ZD4D7Y8KGAS4G", "elb.eu-west-3.amazonaws.com": "Z1CMS0P5QUZ6D5", @@ -139,22 +136,6 @@ type Route53API interface { ListTagsForResourceWithContext(ctx context.Context, input *route53.ListTagsForResourceInput, opts ...request.Option) (*route53.ListTagsForResourceOutput, error) } -// wrapper to handle ownership relation throughout the provider implementation -type Route53Change struct { - route53.Change - OwnedRecord string -} - -type Route53Changes []*Route53Change - -func (cs Route53Changes) Route53Changes() []*route53.Change { - ret := []*route53.Change{} - for _, c := range cs { - ret = append(ret, &c.Change) - } - return ret -} - type zonesListCache struct { age time.Time duration time.Duration @@ -179,8 +160,6 @@ type AWSProvider struct { zoneTagFilter provider.ZoneTagFilter preferCNAME bool zonesCache *zonesListCache - // queue for collecting changes to submit them in the next iteration, but after all other changes - failedChangesQueue map[string]Route53Changes } // AWSConfig contains configuration to create a new AWS provider. @@ -245,7 +224,6 @@ func NewAWSProvider(awsConfig AWSConfig) (*AWSProvider, error) { preferCNAME: awsConfig.PreferCNAME, dryRun: awsConfig.DryRun, zonesCache: &zonesListCache{duration: awsConfig.ZoneCacheDuration}, - failedChangesQueue: make(map[string]Route53Changes), } return provider, nil @@ -489,7 +467,7 @@ func (p *AWSProvider) requiresDeleteCreate(old *endpoint.Endpoint, new *endpoint return false } -func (p *AWSProvider) createUpdateChanges(newEndpoints, oldEndpoints []*endpoint.Endpoint) Route53Changes { +func (p *AWSProvider) createUpdateChanges(newEndpoints, oldEndpoints []*endpoint.Endpoint) []*route53.Change { var deletes []*endpoint.Endpoint var creates []*endpoint.Endpoint var updates []*endpoint.Endpoint @@ -505,7 +483,7 @@ func (p *AWSProvider) createUpdateChanges(newEndpoints, oldEndpoints []*endpoint } } - combined := make(Route53Changes, 0, len(deletes)+len(creates)+len(updates)) + combined := make([]*route53.Change, 0, len(deletes)+len(creates)+len(updates)) combined = append(combined, p.newChanges(route53.ChangeActionCreate, creates)...) combined = append(combined, p.newChanges(route53.ChangeActionUpsert, updates)...) combined = append(combined, p.newChanges(route53.ChangeActionDelete, deletes)...) @@ -536,7 +514,7 @@ func (p *AWSProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) e updateChanges := p.createUpdateChanges(changes.UpdateNew, changes.UpdateOld) - combinedChanges := make(Route53Changes, 0, len(changes.Delete)+len(changes.Create)+len(updateChanges)) + combinedChanges := make([]*route53.Change, 0, len(changes.Delete)+len(changes.Create)+len(updateChanges)) combinedChanges = append(combinedChanges, p.newChanges(route53.ChangeActionCreate, changes.Create)...) combinedChanges = append(combinedChanges, p.newChanges(route53.ChangeActionDelete, changes.Delete)...) combinedChanges = append(combinedChanges, updateChanges...) @@ -545,7 +523,7 @@ func (p *AWSProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) e } // submitChanges takes a zone and a collection of Changes and sends them as a single transaction. -func (p *AWSProvider) submitChanges(ctx context.Context, changes Route53Changes, zones map[string]*route53.HostedZone) error { +func (p *AWSProvider) submitChanges(ctx context.Context, changes []*route53.Change, zones map[string]*route53.HostedZone) error { // return early if there is nothing to change if len(changes) == 0 { log.Info("All records are already up to date") @@ -562,16 +540,9 @@ func (p *AWSProvider) submitChanges(ctx context.Context, changes Route53Changes, for z, cs := range changesByZone { var failedUpdate bool - // group changes into new changes and into changes that failed in a previous iteration and are retried - retriedChanges, newChanges := findChangesInQueue(cs, p.failedChangesQueue[z]) - p.failedChangesQueue[z] = nil + batchCs := batchChangeSet(cs, p.batchChangeSize) - batchCs := append(batchChangeSet(newChanges, p.batchChangeSize), batchChangeSet(retriedChanges, p.batchChangeSize)...) for i, b := range batchCs { - if len(b) == 0 { - continue - } - for _, c := range b { log.Infof("Desired change: %s %s %s [Id: %s]", *c.Action, *c.ResourceRecordSet.Name, *c.ResourceRecordSet.Type, z) } @@ -580,45 +551,17 @@ func (p *AWSProvider) submitChanges(ctx context.Context, changes Route53Changes, params := &route53.ChangeResourceRecordSetsInput{ HostedZoneId: aws.String(z), ChangeBatch: &route53.ChangeBatch{ - Changes: b.Route53Changes(), + Changes: b, }, } - successfulChanges := 0 - if _, err := p.client.ChangeResourceRecordSetsWithContext(ctx, params); err != nil { - log.Errorf("Failure in zone %s [Id: %s] when submitting change batch: %v", aws.StringValue(zones[z].Name), z, err) - - changesByOwnership := groupChangesByNameAndOwnershipRelation(b) - - if len(changesByOwnership) > 1 { - log.Debug("Trying to submit change sets one-by-one instead") - - for _, changes := range changesByOwnership { - for _, c := range changes { - log.Debugf("Desired change: %s %s %s [Id: %s]", *c.Action, *c.ResourceRecordSet.Name, *c.ResourceRecordSet.Type, z) - } - params.ChangeBatch = &route53.ChangeBatch{ - Changes: changes.Route53Changes(), - } - if _, err := p.client.ChangeResourceRecordSetsWithContext(ctx, params); err != nil { - failedUpdate = true - log.Errorf("Failed submitting change (error: %v), it will be retried in a separate change batch in the next iteration", err) - p.failedChangesQueue[z] = append(p.failedChangesQueue[z], changes...) - } else { - successfulChanges = successfulChanges + len(changes) - } - } - } else { - failedUpdate = true - } + log.Errorf("Failure in zone %s [Id: %s]", aws.StringValue(zones[z].Name), z) + log.Error(err) // TODO(ideahitme): consider changing the interface in cases when this error might be a concern for other components + failedUpdate = true } else { - successfulChanges = len(b) - } - - if successfulChanges > 0 { // z is the R53 Hosted Zone ID already as aws.StringValue - log.Infof("%d record(s) in zone %s [Id: %s] were successfully updated", successfulChanges, aws.StringValue(zones[z].Name), z) + log.Infof("%d record(s) in zone %s [Id: %s] were successfully updated", len(b), aws.StringValue(zones[z].Name), z) } if i != len(batchCs)-1 { @@ -640,8 +583,8 @@ func (p *AWSProvider) submitChanges(ctx context.Context, changes Route53Changes, } // newChanges returns a collection of Changes based on the given records and action. -func (p *AWSProvider) newChanges(action string, endpoints []*endpoint.Endpoint) Route53Changes { - changes := make(Route53Changes, 0, len(endpoints)) +func (p *AWSProvider) newChanges(action string, endpoints []*endpoint.Endpoint) []*route53.Change { + changes := make([]*route53.Change, 0, len(endpoints)) for _, endpoint := range endpoints { change, dualstack := p.newChange(action, endpoint) @@ -649,7 +592,7 @@ func (p *AWSProvider) newChanges(action string, endpoints []*endpoint.Endpoint) if dualstack { // make a copy of change, modify RRS type to AAAA, then add new change rrs := *change.ResourceRecordSet - change2 := &Route53Change{Change: route53.Change{Action: change.Action, ResourceRecordSet: &rrs}} + change2 := &route53.Change{Action: change.Action, ResourceRecordSet: &rrs} change2.ResourceRecordSet.Type = aws.String(route53.RRTypeAaaa) changes = append(changes, change2) } @@ -692,13 +635,11 @@ func (p *AWSProvider) AdjustEndpoints(endpoints []*endpoint.Endpoint) []*endpoin // returned Change is based on the given record by the given action, e.g. // action=ChangeActionCreate returns a change for creation of the record and // action=ChangeActionDelete returns a change for deletion of the record. -func (p *AWSProvider) newChange(action string, ep *endpoint.Endpoint) (*Route53Change, bool) { - change := &Route53Change{ - Change: route53.Change{ - Action: aws.String(action), - ResourceRecordSet: &route53.ResourceRecordSet{ - Name: aws.String(ep.DNSName), - }, +func (p *AWSProvider) newChange(action string, ep *endpoint.Endpoint) (*route53.Change, bool) { + change := &route53.Change{ + Action: aws.String(action), + ResourceRecordSet: &route53.ResourceRecordSet{ + Name: aws.String(ep.DNSName), }, } dualstack := false @@ -777,51 +718,9 @@ func (p *AWSProvider) newChange(action string, ep *endpoint.Endpoint) (*Route53C change.ResourceRecordSet.HealthCheckId = aws.String(prop.Value) } - if ownedRecord, ok := ep.Labels[endpoint.OwnedRecordLabelKey]; ok { - change.OwnedRecord = ownedRecord - } - return change, dualstack } -// searches for `changes` that are contained in `queue` and returns the `changes` separated by whether they were found in the queue (`foundChanges`) or not (`notFoundChanges`) -func findChangesInQueue(changes Route53Changes, queue Route53Changes) (foundChanges, notFoundChanges Route53Changes) { - if queue == nil { - return Route53Changes{}, changes - } - - for _, c := range changes { - found := false - for _, qc := range queue { - if c == qc { - foundChanges = append(foundChanges, c) - found = true - break - } - } - if !found { - notFoundChanges = append(notFoundChanges, c) - } - } - - return -} - -// group the given changes by name and ownership relation to ensure these are always submitted in the same transaction to Route53; -// grouping by name is done to always submit changes with the same name but different set identifier together, -// grouping by ownership relation is done to always submit changes of records and e.g. their corresponding TXT registry records together -func groupChangesByNameAndOwnershipRelation(cs Route53Changes) map[string]Route53Changes { - changesByOwnership := make(map[string]Route53Changes) - for _, v := range cs { - key := v.OwnedRecord - if key == "" { - key = aws.StringValue(v.ResourceRecordSet.Name) - } - changesByOwnership[key] = append(changesByOwnership[key], v) - } - return changesByOwnership -} - func (p *AWSProvider) tagsForZone(ctx context.Context, zoneID string) (map[string]string, error) { response, err := p.client.ListTagsForResourceWithContext(ctx, &route53.ListTagsForResourceInput{ ResourceType: aws.String("hostedzone"), @@ -837,48 +736,55 @@ func (p *AWSProvider) tagsForZone(ctx context.Context, zoneID string) (map[strin return tagMap, nil } -func batchChangeSet(cs Route53Changes, batchSize int) []Route53Changes { +func batchChangeSet(cs []*route53.Change, batchSize int) [][]*route53.Change { if len(cs) <= batchSize { res := sortChangesByActionNameType(cs) - return []Route53Changes{res} + return [][]*route53.Change{res} } - batchChanges := make([]Route53Changes, 0) + batchChanges := make([][]*route53.Change, 0) - changesByOwnership := groupChangesByNameAndOwnershipRelation(cs) + changesByName := make(map[string][]*route53.Change) + for _, v := range cs { + changesByName[*v.ResourceRecordSet.Name] = append(changesByName[*v.ResourceRecordSet.Name], v) + } names := make([]string, 0) - for v := range changesByOwnership { + for v := range changesByName { names = append(names, v) } sort.Strings(names) - currentBatch := Route53Changes{} - for k, name := range names { - v := changesByOwnership[name] - if len(v) > batchSize { - log.Warnf("Total changes for %v exceeds max batch size of %d, total changes: %d; changes will not be performed", k, batchSize, len(v)) + for _, name := range names { + totalChangesByName := len(changesByName[name]) + + if totalChangesByName > batchSize { + log.Warnf("Total changes for %s exceeds max batch size of %d, total changes: %d", name, + batchSize, totalChangesByName) continue } - if len(currentBatch)+len(v) > batchSize { - // currentBatch would be too large if we add this changeset; - // add currentBatch to batchChanges and start a new currentBatch - batchChanges = append(batchChanges, sortChangesByActionNameType(currentBatch)) - currentBatch = append(Route53Changes{}, v...) - } else { - currentBatch = append(currentBatch, v...) + var existingBatch bool + for i, b := range batchChanges { + if len(b)+totalChangesByName <= batchSize { + batchChanges[i] = append(batchChanges[i], changesByName[name]...) + existingBatch = true + break + } + } + if !existingBatch { + batchChanges = append(batchChanges, changesByName[name]) } } - if len(currentBatch) > 0 { - // add final currentBatch - batchChanges = append(batchChanges, sortChangesByActionNameType(currentBatch)) + + for i, batch := range batchChanges { + batchChanges[i] = sortChangesByActionNameType(batch) } return batchChanges } -func sortChangesByActionNameType(cs Route53Changes) Route53Changes { +func sortChangesByActionNameType(cs []*route53.Change) []*route53.Change { sort.SliceStable(cs, func(i, j int) bool { if *cs[i].Action > *cs[j].Action { return true @@ -899,11 +805,11 @@ func sortChangesByActionNameType(cs Route53Changes) Route53Changes { } // changesByZone separates a multi-zone change into a single change per zone. -func changesByZone(zones map[string]*route53.HostedZone, changeSet Route53Changes) map[string]Route53Changes { - changes := make(map[string]Route53Changes) +func changesByZone(zones map[string]*route53.HostedZone, changeSet []*route53.Change) map[string][]*route53.Change { + changes := make(map[string][]*route53.Change) for _, z := range zones { - changes[aws.StringValue(z.Id)] = Route53Changes{} + changes[aws.StringValue(z.Id)] = []*route53.Change{} } for _, c := range changeSet { @@ -922,11 +828,9 @@ func changesByZone(zones map[string]*route53.HostedZone, changeSet Route53Change aliasTarget := *rrset.AliasTarget aliasTarget.HostedZoneId = aws.String(cleanZoneID(aws.StringValue(z.Id))) rrset.AliasTarget = &aliasTarget - c = &Route53Change{ - Change: route53.Change{ - Action: c.Action, - ResourceRecordSet: &rrset, - }, + c = &route53.Change{ + Action: c.Action, + ResourceRecordSet: &rrset, } } changes[aws.StringValue(z.Id)] = append(changes[aws.StringValue(z.Id)], c) diff --git a/provider/aws/aws_test.go b/provider/aws/aws_test.go index fee401373f..58e18f353e 100644 --- a/provider/aws/aws_test.go +++ b/provider/aws/aws_test.go @@ -688,37 +688,29 @@ func TestAWSApplyChangesDryRun(t *testing.T) { } func TestAWSChangesByZones(t *testing.T) { - changes := Route53Changes{ + changes := []*route53.Change{ { - Change: route53.Change{ - Action: aws.String(route53.ChangeActionCreate), - ResourceRecordSet: &route53.ResourceRecordSet{ - Name: aws.String("qux.foo.example.org"), TTL: aws.Int64(1), - }, + Action: aws.String(route53.ChangeActionCreate), + ResourceRecordSet: &route53.ResourceRecordSet{ + Name: aws.String("qux.foo.example.org"), TTL: aws.Int64(1), }, }, { - Change: route53.Change{ - Action: aws.String(route53.ChangeActionCreate), - ResourceRecordSet: &route53.ResourceRecordSet{ - Name: aws.String("qux.bar.example.org"), TTL: aws.Int64(2), - }, + Action: aws.String(route53.ChangeActionCreate), + ResourceRecordSet: &route53.ResourceRecordSet{ + Name: aws.String("qux.bar.example.org"), TTL: aws.Int64(2), }, }, { - Change: route53.Change{ - Action: aws.String(route53.ChangeActionDelete), - ResourceRecordSet: &route53.ResourceRecordSet{ - Name: aws.String("wambo.foo.example.org"), TTL: aws.Int64(10), - }, + Action: aws.String(route53.ChangeActionDelete), + ResourceRecordSet: &route53.ResourceRecordSet{ + Name: aws.String("wambo.foo.example.org"), TTL: aws.Int64(10), }, }, { - Change: route53.Change{ - Action: aws.String(route53.ChangeActionDelete), - ResourceRecordSet: &route53.ResourceRecordSet{ - Name: aws.String("wambo.bar.example.org"), TTL: aws.Int64(20), - }, + Action: aws.String(route53.ChangeActionDelete), + ResourceRecordSet: &route53.ResourceRecordSet{ + Name: aws.String("wambo.bar.example.org"), TTL: aws.Int64(20), }, }, } @@ -746,59 +738,47 @@ func TestAWSChangesByZones(t *testing.T) { changesByZone := changesByZone(zones, changes) require.Len(t, changesByZone, 3) - validateAWSChangeRecords(t, changesByZone["foo-example-org"], Route53Changes{ + validateAWSChangeRecords(t, changesByZone["foo-example-org"], []*route53.Change{ { - Change: route53.Change{ - Action: aws.String(route53.ChangeActionCreate), - ResourceRecordSet: &route53.ResourceRecordSet{ - Name: aws.String("qux.foo.example.org"), TTL: aws.Int64(1), - }, + Action: aws.String(route53.ChangeActionCreate), + ResourceRecordSet: &route53.ResourceRecordSet{ + Name: aws.String("qux.foo.example.org"), TTL: aws.Int64(1), }, }, { - Change: route53.Change{ - Action: aws.String(route53.ChangeActionDelete), - ResourceRecordSet: &route53.ResourceRecordSet{ - Name: aws.String("wambo.foo.example.org"), TTL: aws.Int64(10), - }, + Action: aws.String(route53.ChangeActionDelete), + ResourceRecordSet: &route53.ResourceRecordSet{ + Name: aws.String("wambo.foo.example.org"), TTL: aws.Int64(10), }, }, }) - validateAWSChangeRecords(t, changesByZone["bar-example-org"], Route53Changes{ + validateAWSChangeRecords(t, changesByZone["bar-example-org"], []*route53.Change{ { - Change: route53.Change{ - Action: aws.String(route53.ChangeActionCreate), - ResourceRecordSet: &route53.ResourceRecordSet{ - Name: aws.String("qux.bar.example.org"), TTL: aws.Int64(2), - }, + Action: aws.String(route53.ChangeActionCreate), + ResourceRecordSet: &route53.ResourceRecordSet{ + Name: aws.String("qux.bar.example.org"), TTL: aws.Int64(2), }, }, { - Change: route53.Change{ - Action: aws.String(route53.ChangeActionDelete), - ResourceRecordSet: &route53.ResourceRecordSet{ - Name: aws.String("wambo.bar.example.org"), TTL: aws.Int64(20), - }, + Action: aws.String(route53.ChangeActionDelete), + ResourceRecordSet: &route53.ResourceRecordSet{ + Name: aws.String("wambo.bar.example.org"), TTL: aws.Int64(20), }, }, }) - validateAWSChangeRecords(t, changesByZone["bar-example-org-private"], Route53Changes{ + validateAWSChangeRecords(t, changesByZone["bar-example-org-private"], []*route53.Change{ { - Change: route53.Change{ - Action: aws.String(route53.ChangeActionCreate), - ResourceRecordSet: &route53.ResourceRecordSet{ - Name: aws.String("qux.bar.example.org"), TTL: aws.Int64(2), - }, + Action: aws.String(route53.ChangeActionCreate), + ResourceRecordSet: &route53.ResourceRecordSet{ + Name: aws.String("qux.bar.example.org"), TTL: aws.Int64(2), }, }, { - Change: route53.Change{ - Action: aws.String(route53.ChangeActionDelete), - ResourceRecordSet: &route53.ResourceRecordSet{ - Name: aws.String("wambo.bar.example.org"), TTL: aws.Int64(20), - }, + Action: aws.String(route53.ChangeActionDelete), + ResourceRecordSet: &route53.ResourceRecordSet{ + Name: aws.String("wambo.bar.example.org"), TTL: aws.Int64(20), }, }, }) @@ -822,7 +802,7 @@ func TestAWSsubmitChanges(t *testing.T) { ctx := context.Background() zones, _ := provider.Zones(ctx) records, _ := provider.Records(ctx) - cs := make(Route53Changes, 0, len(endpoints)) + cs := make([]*route53.Change, 0, len(endpoints)) cs = append(cs, provider.newChanges(route53.ChangeActionCreate, endpoints)...) require.NoError(t, provider.submitChanges(ctx, cs, zones)) @@ -847,85 +827,22 @@ func TestAWSsubmitChangesError(t *testing.T) { require.Error(t, provider.submitChanges(ctx, cs, zones)) } -func TestAWSsubmitChangesRetryOnError(t *testing.T) { - provider, clientStub := newAWSProvider(t, endpoint.NewDomainFilter([]string{"ext-dns-test-2.teapot.zalan.do."}), provider.NewZoneIDFilter([]string{}), provider.NewZoneTypeFilter(""), defaultEvaluateTargetHealth, false, []*endpoint.Endpoint{}) - - ctx := context.Background() - 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") - - 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.Labels = map[string]string{ - endpoint.OwnedRecordLabelKey: "fail.zone-1.ext-dns-test-2.teapot.zalan.do", - } - - // "success" and "fail" are created in the first step, both are submitted in the same batch; this should fail - cs1 := provider.newChanges(route53.ChangeActionCreate, []*endpoint.Endpoint{ep2, ep2txt, ep1}) - input1 := &route53.ChangeResourceRecordSetsInput{ - HostedZoneId: aws.String("/hostedzone/zone-1.ext-dns-test-2.teapot.zalan.do."), - ChangeBatch: &route53.ChangeBatch{ - Changes: cs1.Route53Changes(), - }, - } - clientStub.MockMethod("ChangeResourceRecordSets", input1).Return(nil, fmt.Errorf("Mock route53 failure")) - - // because of the failure, changes will be retried one by one; make "fail" submitted in its own batch fail as well - cs2 := provider.newChanges(route53.ChangeActionCreate, []*endpoint.Endpoint{ep2, ep2txt}) - input2 := &route53.ChangeResourceRecordSetsInput{ - HostedZoneId: aws.String("/hostedzone/zone-1.ext-dns-test-2.teapot.zalan.do."), - ChangeBatch: &route53.ChangeBatch{ - Changes: cs2.Route53Changes(), - }, - } - clientStub.MockMethod("ChangeResourceRecordSets", input2).Return(nil, fmt.Errorf("Mock route53 failure")) - - // "success" should have been created, verify that we still get an error because "fail" failed - require.Error(t, provider.submitChanges(ctx, cs1, zones)) - - // assert that "success" was successfully created and "fail" and its TXT record were not - records, err := provider.Records(ctx) - require.NoError(t, err) - require.True(t, containsRecordWithDNSName(records, "success.zone-1.ext-dns-test-2.teapot.zalan.do")) - require.False(t, containsRecordWithDNSName(records, "fail.zone-1.ext-dns-test-2.teapot.zalan.do")) - require.False(t, containsRecordWithDNSName(records, "fail__edns_housekeeping.zone-1.ext-dns-test-2.teapot.zalan.do")) - - // next batch should contain "fail" and "success2", should succeed this time - cs3 := provider.newChanges(route53.ChangeActionCreate, []*endpoint.Endpoint{ep2, ep2txt, ep3}) - require.NoError(t, provider.submitChanges(ctx, cs3, zones)) - - // verify all records are there - records, err = provider.Records(ctx) - require.NoError(t, err) - require.True(t, containsRecordWithDNSName(records, "success.zone-1.ext-dns-test-2.teapot.zalan.do")) - require.True(t, containsRecordWithDNSName(records, "fail.zone-1.ext-dns-test-2.teapot.zalan.do")) - require.True(t, containsRecordWithDNSName(records, "success2.zone-1.ext-dns-test-2.teapot.zalan.do")) - require.True(t, containsRecordWithDNSName(records, "fail__edns_housekeeping.zone-1.ext-dns-test-2.teapot.zalan.do")) -} - func TestAWSBatchChangeSet(t *testing.T) { - var cs Route53Changes + var cs []*route53.Change for i := 1; i <= defaultBatchChangeSize; i += 2 { - cs = append(cs, &Route53Change{ - Change: route53.Change{ - Action: aws.String(route53.ChangeActionCreate), - ResourceRecordSet: &route53.ResourceRecordSet{ - Name: aws.String(fmt.Sprintf("host-%d", i)), - Type: aws.String("A"), - }, + cs = append(cs, &route53.Change{ + Action: aws.String(route53.ChangeActionCreate), + ResourceRecordSet: &route53.ResourceRecordSet{ + Name: aws.String(fmt.Sprintf("host-%d", i)), + Type: aws.String("A"), }, }) - cs = append(cs, &Route53Change{ - Change: route53.Change{ - Action: aws.String(route53.ChangeActionCreate), - ResourceRecordSet: &route53.ResourceRecordSet{ - Name: aws.String(fmt.Sprintf("host-%d", i)), - Type: aws.String("TXT"), - }, + cs = append(cs, &route53.Change{ + Action: aws.String(route53.ChangeActionCreate), + ResourceRecordSet: &route53.ResourceRecordSet{ + Name: aws.String(fmt.Sprintf("host-%d", i)), + Type: aws.String("TXT"), }, }) } @@ -939,33 +856,27 @@ func TestAWSBatchChangeSet(t *testing.T) { } func TestAWSBatchChangeSetExceeding(t *testing.T) { - var cs Route53Changes + var cs []*route53.Change const testCount = 50 const testLimit = 11 const expectedBatchCount = 5 const expectedChangesCount = 10 for i := 1; i <= testCount; i += 2 { - cs = append(cs, - &Route53Change{ - Change: route53.Change{ - Action: aws.String(route53.ChangeActionCreate), - ResourceRecordSet: &route53.ResourceRecordSet{ - Name: aws.String(fmt.Sprintf("host-%d", i)), - Type: aws.String("A"), - }, - }, + cs = append(cs, &route53.Change{ + Action: aws.String(route53.ChangeActionCreate), + ResourceRecordSet: &route53.ResourceRecordSet{ + Name: aws.String(fmt.Sprintf("host-%d", i)), + Type: aws.String("A"), }, - &Route53Change{ - Change: route53.Change{ - Action: aws.String(route53.ChangeActionCreate), - ResourceRecordSet: &route53.ResourceRecordSet{ - Name: aws.String(fmt.Sprintf("host-%d", i)), - Type: aws.String("TXT"), - }, - }, + }) + cs = append(cs, &route53.Change{ + Action: aws.String(route53.ChangeActionCreate), + ResourceRecordSet: &route53.ResourceRecordSet{ + Name: aws.String(fmt.Sprintf("host-%d", i)), + Type: aws.String("TXT"), }, - ) + }) } batchCs := batchChangeSet(cs, testLimit) @@ -979,31 +890,25 @@ func TestAWSBatchChangeSetExceeding(t *testing.T) { } func TestAWSBatchChangeSetExceedingNameChange(t *testing.T) { - var cs Route53Changes + var cs []*route53.Change const testCount = 10 const testLimit = 1 for i := 1; i <= testCount; i += 2 { - cs = append(cs, - &Route53Change{ - Change: route53.Change{ - Action: aws.String(route53.ChangeActionCreate), - ResourceRecordSet: &route53.ResourceRecordSet{ - Name: aws.String(fmt.Sprintf("host-%d", i)), - Type: aws.String("A"), - }, - }, + cs = append(cs, &route53.Change{ + Action: aws.String(route53.ChangeActionCreate), + ResourceRecordSet: &route53.ResourceRecordSet{ + Name: aws.String(fmt.Sprintf("host-%d", i)), + Type: aws.String("A"), }, - &Route53Change{ - Change: route53.Change{ - Action: aws.String(route53.ChangeActionCreate), - ResourceRecordSet: &route53.ResourceRecordSet{ - Name: aws.String(fmt.Sprintf("host-%d", i)), - Type: aws.String("TXT"), - }, - }, + }) + cs = append(cs, &route53.Change{ + Action: aws.String(route53.ChangeActionCreate), + ResourceRecordSet: &route53.ResourceRecordSet{ + Name: aws.String(fmt.Sprintf("host-%d", i)), + Type: aws.String("TXT"), }, - ) + }) } batchCs := batchChangeSet(cs, testLimit) @@ -1028,7 +933,7 @@ func validateAWSZone(t *testing.T, zone *route53.HostedZone, expected *route53.H assert.Equal(t, aws.StringValue(expected.Name), aws.StringValue(zone.Name)) } -func validateAWSChangeRecords(t *testing.T, records Route53Changes, expected Route53Changes) { +func validateAWSChangeRecords(t *testing.T, records []*route53.Change, expected []*route53.Change) { require.Len(t, records, len(expected)) for i := range records { @@ -1036,7 +941,7 @@ func validateAWSChangeRecords(t *testing.T, records Route53Changes, expected Rou } } -func validateAWSChangeRecord(t *testing.T, record *Route53Change, expected *Route53Change) { +func validateAWSChangeRecord(t *testing.T, record *route53.Change, expected *route53.Change) { assert.Equal(t, aws.StringValue(expected.Action), aws.StringValue(record.Action)) assert.Equal(t, aws.StringValue(expected.ResourceRecordSet.Name), aws.StringValue(record.ResourceRecordSet.Name)) assert.Equal(t, aws.StringValue(expected.ResourceRecordSet.Type), aws.StringValue(record.ResourceRecordSet.Type)) @@ -1218,7 +1123,6 @@ func TestAWSCanonicalHostedZone(t *testing.T) { {"foo.elb.ca-central-1.amazonaws.com", "Z2EPGBW3API2WT"}, {"foo.elb.ap-east-1.amazonaws.com", "Z12Y7K3UBGUAD1"}, {"foo.elb.ap-south-1.amazonaws.com", "ZVDDRBQ08TROA"}, - {"foo.elb.ap-northeast-3.amazonaws.com", "Z1GWIQ4HH19I5X"}, {"foo.elb.ap-northeast-2.amazonaws.com", "ZIBE1TIR4HY56"}, {"foo.elb.ap-southeast-1.amazonaws.com", "ZKVM4W9LS7TM"}, {"foo.elb.ap-southeast-2.amazonaws.com", "ZCT6FZBF4DROD"}, @@ -1435,7 +1339,6 @@ func newAWSProviderWithTagFilter(t *testing.T, domainFilter endpoint.DomainFilte zoneTagFilter: zoneTagFilter, dryRun: false, zonesCache: &zonesListCache{duration: 1 * time.Minute}, - failedChangesQueue: make(map[string]Route53Changes), } createAWSZone(t, provider, &route53.HostedZone{ @@ -1510,15 +1413,6 @@ func validateRecords(t *testing.T, records []*route53.ResourceRecordSet, expecte assert.ElementsMatch(t, expected, records) } -func containsRecordWithDNSName(records []*endpoint.Endpoint, dnsName string) bool { - for _, record := range records { - if record.DNSName == dnsName { - return true - } - } - return false -} - func TestRequiresDeleteCreate(t *testing.T) { provider, _ := newAWSProvider(t, endpoint.NewDomainFilter([]string{"foo.bar."}), provider.NewZoneIDFilter([]string{}), provider.NewZoneTypeFilter(""), defaultEvaluateTargetHealth, false, []*endpoint.Endpoint{}) diff --git a/provider/awssd/aws_sd.go b/provider/awssd/aws_sd.go index ecdb7efc58..144a0e2978 100644 --- a/provider/awssd/aws_sd.go +++ b/provider/awssd/aws_sd.go @@ -511,7 +511,7 @@ func (p *AWSSDProvider) DeleteService(service *sd.Service) error { label[endpoint.OwnerLabelKey] = p.ownerID label[endpoint.AWSSDDescriptionLabel] = label.Serialize(false) - if strings.HasPrefix(aws.StringValue(service.Description), label[endpoint.AWSSDDescriptionLabel]) { + if aws.StringValue(service.Description) == label[endpoint.AWSSDDescriptionLabel] { log.Infof("Deleting service \"%s\"", *service.Name) _, err := p.client.DeleteService(&sd.DeleteServiceInput{ Id: aws.String(*service.Id), diff --git a/provider/awssd/aws_sd_test.go b/provider/awssd/aws_sd_test.go index d8a2ef3dba..ad73b07f91 100644 --- a/provider/awssd/aws_sd_test.go +++ b/provider/awssd/aws_sd_test.go @@ -683,12 +683,6 @@ func TestAWSSDProvider_DeleteService(t *testing.T) { Name: aws.String("service2"), NamespaceId: aws.String("private"), }, - "srv3": { - Id: aws.String("srv3"), - Description: aws.String("heritage=external-dns,external-dns/owner=owner-id,external-dns/resource=virtualservice/grpc-server/validate-grpc-server"), - Name: aws.String("service3"), - NamespaceId: aws.String("private"), - }, }, } @@ -699,14 +693,9 @@ func TestAWSSDProvider_DeleteService(t *testing.T) { provider := newTestAWSSDProvider(api, endpoint.NewDomainFilter([]string{}), "", "owner-id") - // delete first service + // delete fist service err := provider.DeleteService(services["private"]["srv1"]) assert.NoError(t, err) - assert.Len(t, api.services["private"], 2) - - // delete third service - err1 := provider.DeleteService(services["private"]["srv3"]) - assert.NoError(t, err1) assert.Len(t, api.services["private"], 1) expectedServices := map[string]*sd.Service{ diff --git a/provider/cloudflare/cloudflare.go b/provider/cloudflare/cloudflare.go index 6948be49b6..0799364029 100644 --- a/provider/cloudflare/cloudflare.go +++ b/provider/cloudflare/cloudflare.go @@ -67,10 +67,10 @@ type cloudFlareDNS interface { ListZones(ctx context.Context, zoneID ...string) ([]cloudflare.Zone, error) ListZonesContext(ctx context.Context, opts ...cloudflare.ReqOption) (cloudflare.ZonesResponse, error) ZoneDetails(ctx context.Context, zoneID string) (cloudflare.Zone, error) - ListDNSRecords(ctx context.Context, rc *cloudflare.ResourceContainer, rp cloudflare.ListDNSRecordsParams) ([]cloudflare.DNSRecord, *cloudflare.ResultInfo, error) - CreateDNSRecord(ctx context.Context, rc *cloudflare.ResourceContainer, rp cloudflare.CreateDNSRecordParams) (*cloudflare.DNSRecordResponse, error) - DeleteDNSRecord(ctx context.Context, rc *cloudflare.ResourceContainer, recordID string) error - UpdateDNSRecord(ctx context.Context, rc *cloudflare.ResourceContainer, rp cloudflare.UpdateDNSRecordParams) error + DNSRecords(ctx context.Context, zoneID string, rr cloudflare.DNSRecord) ([]cloudflare.DNSRecord, error) + CreateDNSRecord(ctx context.Context, zoneID string, rr cloudflare.DNSRecord) (*cloudflare.DNSRecordResponse, error) + DeleteDNSRecord(ctx context.Context, zoneID, recordID string) error + UpdateDNSRecord(ctx context.Context, zoneID, recordID string, rr cloudflare.DNSRecord) error } type zoneService struct { @@ -89,20 +89,20 @@ func (z zoneService) ZoneIDByName(zoneName string) (string, error) { return z.service.ZoneIDByName(zoneName) } -func (z zoneService) CreateDNSRecord(ctx context.Context, rc *cloudflare.ResourceContainer, rp cloudflare.CreateDNSRecordParams) (*cloudflare.DNSRecordResponse, error) { - return z.service.CreateDNSRecord(ctx, rc, rp) +func (z zoneService) CreateDNSRecord(ctx context.Context, zoneID string, rr cloudflare.DNSRecord) (*cloudflare.DNSRecordResponse, error) { + return z.service.CreateDNSRecord(ctx, zoneID, rr) } -func (z zoneService) ListDNSRecords(ctx context.Context, rc *cloudflare.ResourceContainer, rp cloudflare.ListDNSRecordsParams) ([]cloudflare.DNSRecord, *cloudflare.ResultInfo, error) { - return z.service.ListDNSRecords(ctx, rc, rp) +func (z zoneService) DNSRecords(ctx context.Context, zoneID string, rr cloudflare.DNSRecord) ([]cloudflare.DNSRecord, error) { + return z.service.DNSRecords(ctx, zoneID, rr) } -func (z zoneService) UpdateDNSRecord(ctx context.Context, rc *cloudflare.ResourceContainer, rp cloudflare.UpdateDNSRecordParams) error { - return z.service.UpdateDNSRecord(ctx, rc, rp) +func (z zoneService) UpdateDNSRecord(ctx context.Context, zoneID, recordID string, rr cloudflare.DNSRecord) error { + return z.service.UpdateDNSRecord(ctx, zoneID, recordID, rr) } -func (z zoneService) DeleteDNSRecord(ctx context.Context, rc *cloudflare.ResourceContainer, recordID string) error { - return z.service.DeleteDNSRecord(ctx, rc, recordID) +func (z zoneService) DeleteDNSRecord(ctx context.Context, zoneID, recordID string) error { + return z.service.DeleteDNSRecord(ctx, zoneID, recordID) } func (z zoneService) ListZonesContext(ctx context.Context, opts ...cloudflare.ReqOption) (cloudflare.ZonesResponse, error) { @@ -131,22 +131,6 @@ type cloudFlareChange struct { ResourceRecord cloudflare.DNSRecord } -// RecordParamsTypes is a typeset of the possible Record Params that can be passed to cloudflare-go library -type RecordParamsTypes interface { - cloudflare.UpdateDNSRecordParams | cloudflare.CreateDNSRecordParams -} - -// getRecordParam is a generic function that returns the appropriate Record Param based on the cloudFlareChange passed in -func getRecordParam[T RecordParamsTypes](cfc cloudFlareChange) T { - return T{ - Name: cfc.ResourceRecord.Name, - TTL: cfc.ResourceRecord.TTL, - Proxied: cfc.ResourceRecord.Proxied, - Type: cfc.ResourceRecord.Type, - Content: cfc.ResourceRecord.Content, - } -} - // NewCloudFlareProvider initializes a new CloudFlare DNS based Provider. func NewCloudFlareProvider(domainFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, zonesPerPage int, proxiedByDefault bool, dryRun bool) (*CloudFlareProvider, error) { // initialize via chosen auth method and returns new API object @@ -229,7 +213,7 @@ func (p *CloudFlareProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, endpoints := []*endpoint.Endpoint{} for _, zone := range zones { - records, _, err := p.Client.ListDNSRecords(ctx, cloudflare.ZoneIdentifier(zone.ID), cloudflare.ListDNSRecordsParams{}) + records, err := p.Client.DNSRecords(ctx, zone.ID, cloudflare.DNSRecord{}) if err != nil { return nil, err } @@ -303,7 +287,7 @@ func (p *CloudFlareProvider) submitChanges(ctx context.Context, changes []*cloud changesByZone := p.changesByZone(zones, changes) for zoneID, changes := range changesByZone { - records, _, err := p.Client.ListDNSRecords(ctx, cloudflare.ZoneIdentifier(zoneID), cloudflare.ListDNSRecordsParams{}) + records, err := p.Client.DNSRecords(ctx, zoneID, cloudflare.DNSRecord{}) if err != nil { return fmt.Errorf("could not fetch records from zone, %v", err) } @@ -322,16 +306,13 @@ func (p *CloudFlareProvider) submitChanges(ctx context.Context, changes []*cloud continue } - resourceContainer := cloudflare.ZoneIdentifier(zoneID) if change.Action == cloudFlareUpdate { recordID := p.getRecordID(records, change.ResourceRecord) if recordID == "" { log.WithFields(logFields).Errorf("failed to find previous record: %v", change.ResourceRecord) continue } - recordParam := getRecordParam[cloudflare.UpdateDNSRecordParams](*change) - recordParam.ID = recordID - err := p.Client.UpdateDNSRecord(ctx, resourceContainer, recordParam) + err := p.Client.UpdateDNSRecord(ctx, zoneID, recordID, change.ResourceRecord) if err != nil { log.WithFields(logFields).Errorf("failed to update record: %v", err) } @@ -341,13 +322,12 @@ func (p *CloudFlareProvider) submitChanges(ctx context.Context, changes []*cloud log.WithFields(logFields).Errorf("failed to find previous record: %v", change.ResourceRecord) continue } - err := p.Client.DeleteDNSRecord(ctx, resourceContainer, recordID) + err := p.Client.DeleteDNSRecord(ctx, zoneID, recordID) if err != nil { log.WithFields(logFields).Errorf("failed to delete record: %v", err) } } else if change.Action == cloudFlareCreate { - recordParam := getRecordParam[cloudflare.CreateDNSRecordParams](*change) - _, err := p.Client.CreateDNSRecord(ctx, resourceContainer, recordParam) + _, err := p.Client.CreateDNSRecord(ctx, zoneID, change.ResourceRecord) if err != nil { log.WithFields(logFields).Errorf("failed to create record: %v", err) } diff --git a/provider/cloudflare/cloudflare_test.go b/provider/cloudflare/cloudflare_test.go index b2136bff0a..af48f08480 100644 --- a/provider/cloudflare/cloudflare_test.go +++ b/provider/cloudflare/cloudflare_test.go @@ -105,80 +105,55 @@ func NewMockCloudFlareClientWithRecords(records map[string][]cloudflare.DNSRecor return m } -func getDNSRecordFromRecordParams(rp any) cloudflare.DNSRecord { - switch params := rp.(type) { - case cloudflare.CreateDNSRecordParams: - return cloudflare.DNSRecord{ - Name: params.Name, - TTL: params.TTL, - Proxied: params.Proxied, - Type: params.Type, - Content: params.Content, - } - case cloudflare.UpdateDNSRecordParams: - return cloudflare.DNSRecord{ - Name: params.Name, - TTL: params.TTL, - Proxied: params.Proxied, - Type: params.Type, - Content: params.Content, - } - default: - return cloudflare.DNSRecord{} - } -} - -func (m *mockCloudFlareClient) CreateDNSRecord(ctx context.Context, rc *cloudflare.ResourceContainer, rp cloudflare.CreateDNSRecordParams) (*cloudflare.DNSRecordResponse, error) { - recordData := getDNSRecordFromRecordParams(rp) +func (m *mockCloudFlareClient) CreateDNSRecord(ctx context.Context, zoneID string, rr cloudflare.DNSRecord) (*cloudflare.DNSRecordResponse, error) { m.Actions = append(m.Actions, MockAction{ Name: "Create", - ZoneId: rc.Identifier, - RecordId: rp.ID, - RecordData: recordData, + ZoneId: zoneID, + RecordId: rr.ID, + RecordData: rr, }) - if zone, ok := m.Records[rc.Identifier]; ok { - zone[rp.ID] = recordData + if zone, ok := m.Records[zoneID]; ok { + zone[rr.ID] = rr } return nil, nil } -func (m *mockCloudFlareClient) ListDNSRecords(ctx context.Context, rc *cloudflare.ResourceContainer, rp cloudflare.ListDNSRecordsParams) ([]cloudflare.DNSRecord, *cloudflare.ResultInfo, error) { +func (m *mockCloudFlareClient) DNSRecords(ctx context.Context, zoneID string, rr cloudflare.DNSRecord) ([]cloudflare.DNSRecord, error) { if m.dnsRecordsError != nil { - return nil, &cloudflare.ResultInfo{}, m.dnsRecordsError + return nil, m.dnsRecordsError } result := []cloudflare.DNSRecord{} - if zone, ok := m.Records[rc.Identifier]; ok { + if zone, ok := m.Records[zoneID]; ok { for _, record := range zone { result = append(result, record) } - return result, &cloudflare.ResultInfo{}, nil + return result, nil } - return result, &cloudflare.ResultInfo{}, nil + return result, nil } -func (m *mockCloudFlareClient) UpdateDNSRecord(ctx context.Context, rc *cloudflare.ResourceContainer, rp cloudflare.UpdateDNSRecordParams) error { - recordData := getDNSRecordFromRecordParams(rp) +func (m *mockCloudFlareClient) UpdateDNSRecord(ctx context.Context, zoneID, recordID string, rr cloudflare.DNSRecord) error { m.Actions = append(m.Actions, MockAction{ Name: "Update", - ZoneId: rc.Identifier, - RecordId: rp.ID, - RecordData: recordData, + ZoneId: zoneID, + RecordId: recordID, + RecordData: rr, }) - if zone, ok := m.Records[rc.Identifier]; ok { - if _, ok := zone[rp.ID]; ok { - zone[rp.ID] = recordData + if zone, ok := m.Records[zoneID]; ok { + if _, ok := zone[recordID]; ok { + zone[recordID] = rr } } return nil } -func (m *mockCloudFlareClient) DeleteDNSRecord(ctx context.Context, rc *cloudflare.ResourceContainer, recordID string) error { +func (m *mockCloudFlareClient) DeleteDNSRecord(ctx context.Context, zoneID, recordID string) error { m.Actions = append(m.Actions, MockAction{ Name: "Delete", - ZoneId: rc.Identifier, + ZoneId: zoneID, RecordId: recordID, }) - if zone, ok := m.Records[rc.Identifier]; ok { + if zone, ok := m.Records[zoneID]; ok { if _, ok := zone[recordID]; ok { delete(zone, recordID) return nil diff --git a/provider/infoblox/infoblox.go b/provider/infoblox/infoblox.go index b6afb4e242..916dc9ef11 100644 --- a/provider/infoblox/infoblox.go +++ b/provider/infoblox/infoblox.go @@ -58,8 +58,7 @@ type StartupConfig struct { DryRun bool View string MaxResults int - FQDNRegEx string - NameRegEx string + FQDNRexEx string CreatePTR bool CacheDuration int } @@ -86,17 +85,15 @@ type infobloxRecordSet struct { // additional query parameter on all get requests type ExtendedRequestBuilder struct { fqdnRegEx string - nameRegEx string maxResults int ibclient.WapiRequestBuilder } // NewExtendedRequestBuilder returns a ExtendedRequestBuilder which adds // _max_results query parameter to all GET requests -func NewExtendedRequestBuilder(maxResults int, fqdnRegEx string, nameRegEx string) *ExtendedRequestBuilder { +func NewExtendedRequestBuilder(maxResults int, fqdnRegEx string) *ExtendedRequestBuilder { return &ExtendedRequestBuilder{ fqdnRegEx: fqdnRegEx, - nameRegEx: nameRegEx, maxResults: maxResults, } } @@ -110,16 +107,10 @@ func (mrb *ExtendedRequestBuilder) BuildRequest(t ibclient.RequestType, obj ibcl if mrb.maxResults > 0 { query.Set("_max_results", strconv.Itoa(mrb.maxResults)) } - _, zoneAuthQuery := obj.(*ibclient.ZoneAuth) - if zoneAuthQuery && t == ibclient.GET && mrb.fqdnRegEx != "" { + _, ok := obj.(*ibclient.ZoneAuth) + if ok && t == ibclient.GET && mrb.fqdnRegEx != "" { query.Set("fqdn~", mrb.fqdnRegEx) } - - // if we are not doing a ZoneAuth query, support the name filter - if !zoneAuthQuery && mrb.nameRegEx != "" { - query.Set("name~", mrb.nameRegEx) - } - req.URL.RawQuery = query.Encode() } return @@ -151,9 +142,9 @@ func NewInfobloxProvider(ibStartupCfg StartupConfig) (*ProviderConfig, error) { requestBuilder ibclient.HttpRequestBuilder err error ) - if ibStartupCfg.MaxResults != 0 || ibStartupCfg.FQDNRegEx != "" || ibStartupCfg.NameRegEx != "" { + if ibStartupCfg.MaxResults != 0 || ibStartupCfg.FQDNRexEx != "" { // use our own HttpRequestBuilder which sets _max_results parameter on GET requests - requestBuilder = NewExtendedRequestBuilder(ibStartupCfg.MaxResults, ibStartupCfg.FQDNRegEx, ibStartupCfg.NameRegEx) + requestBuilder = NewExtendedRequestBuilder(ibStartupCfg.MaxResults, ibStartupCfg.FQDNRexEx) } else { // use the default HttpRequestBuilder of the infoblox client requestBuilder, err = ibclient.NewWapiRequestBuilder(hostCfg, authCfg) @@ -175,7 +166,7 @@ func NewInfobloxProvider(ibStartupCfg StartupConfig) (*ProviderConfig, error) { zoneIDFilter: ibStartupCfg.ZoneIDFilter, dryRun: ibStartupCfg.DryRun, view: ibStartupCfg.View, - fqdnRegEx: ibStartupCfg.FQDNRegEx, + fqdnRegEx: ibStartupCfg.FQDNRexEx, createPTR: ibStartupCfg.CreatePTR, cacheDuration: ibStartupCfg.CacheDuration, } diff --git a/provider/infoblox/infoblox_test.go b/provider/infoblox/infoblox_test.go index 13b5e0b52e..521b3f8f83 100644 --- a/provider/infoblox/infoblox_test.go +++ b/provider/infoblox/infoblox_test.go @@ -698,7 +698,7 @@ func TestExtendedRequestFDQDRegExBuilder(t *testing.T) { Password: "abcd", } - requestBuilder := NewExtendedRequestBuilder(0, "^staging.*test.com$", "") + requestBuilder := NewExtendedRequestBuilder(0, "^staging.*test.com$") requestBuilder.Init(hostCfg, authCfg) obj := ibclient.NewZoneAuth(ibclient.ZoneAuth{}) @@ -712,33 +712,6 @@ func TestExtendedRequestFDQDRegExBuilder(t *testing.T) { assert.True(t, req.URL.Query().Get("fqdn~") == "") } -func TestExtendedRequestNameRegExBuilder(t *testing.T) { - hostCfg := ibclient.HostConfig{ - Host: "localhost", - Port: "8080", - Version: "2.3.1", - } - - authCfg := ibclient.AuthConfig{ - Username: "user", - Password: "abcd", - } - - requestBuilder := NewExtendedRequestBuilder(0, "", "^staging.*test.com$") - requestBuilder.Init(hostCfg, authCfg) - - obj := ibclient.NewEmptyRecordCNAME() - - req, _ := requestBuilder.BuildRequest(ibclient.GET, obj, "", &ibclient.QueryParams{}) - - assert.True(t, req.URL.Query().Get("name~") == "^staging.*test.com$") - - req, _ = requestBuilder.BuildRequest(ibclient.CREATE, obj, "", &ibclient.QueryParams{}) - - assert.True(t, req.URL.Query().Get("name~") == "") -} - - func TestExtendedRequestMaxResultsBuilder(t *testing.T) { hostCfg := ibclient.HostConfig{ Host: "localhost", @@ -751,7 +724,7 @@ func TestExtendedRequestMaxResultsBuilder(t *testing.T) { Password: "abcd", } - requestBuilder := NewExtendedRequestBuilder(54321, "", "") + requestBuilder := NewExtendedRequestBuilder(54321, "") requestBuilder.Init(hostCfg, authCfg) obj := ibclient.NewEmptyRecordCNAME() @@ -770,7 +743,7 @@ func TestGetObject(t *testing.T) { hostCfg := ibclient.HostConfig{} authCfg := ibclient.AuthConfig{} transportConfig := ibclient.TransportConfig{} - requestBuilder := NewExtendedRequestBuilder(1000, "mysite.com", "") + requestBuilder := NewExtendedRequestBuilder(1000, "mysite.com") requestor := mockRequestor{} client, _ := ibclient.NewConnector(hostCfg, authCfg, transportConfig, requestBuilder, &requestor) diff --git a/provider/pihole/pihole.go b/provider/pihole/pihole.go index 6b1f352d9c..a777affccc 100644 --- a/provider/pihole/pihole.go +++ b/provider/pihole/pihole.go @@ -49,12 +49,6 @@ type PiholeConfig struct { DryRun bool } -// Helper struct for de-duping DNS entry updates. -type piholeEntryKey struct { - Target string - RecordType string -} - // NewPiholeProvider initializes a new Pi-hole Local DNS based Provider. func NewPiholeProvider(cfg PiholeConfig) (*PiholeProvider, error) { api, err := newPiholeClient(cfg) @@ -80,42 +74,25 @@ func (p *PiholeProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, err // ApplyChanges implements Provider, syncing desired state with the Pi-hole server Local DNS. func (p *PiholeProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error { - // Handle pure deletes first. + // Handle deletions first - there are no endpoints for updating in place. for _, ep := range changes.Delete { if err := p.api.deleteRecord(ctx, ep); err != nil { return err } } - - // Handle updated state - there are no endpoints for updating in place. - updateNew := make(map[piholeEntryKey]*endpoint.Endpoint) - for _, ep := range changes.UpdateNew { - key := piholeEntryKey{ep.DNSName, ep.RecordType} - updateNew[key] = ep - } - for _, ep := range changes.UpdateOld { - // Check if this existing entry has an exact match for an updated entry and skip it if so. - key := piholeEntryKey{ep.DNSName, ep.RecordType} - if newRecord := updateNew[key]; newRecord != nil { - // PiHole only has a single target; no need to compare other fields. - if newRecord.Targets[0] == ep.Targets[0] { - delete(updateNew, key) - continue - } - } if err := p.api.deleteRecord(ctx, ep); err != nil { return err } } - // Handle pure creates before applying new updated state. + // Handle desired state for _, ep := range changes.Create { if err := p.api.createRecord(ctx, ep); err != nil { return err } } - for _, ep := range updateNew { + for _, ep := range changes.UpdateNew { if err := p.api.createRecord(ctx, ep); err != nil { return err } diff --git a/provider/pihole/pihole_test.go b/provider/pihole/pihole_test.go index bd19196afd..b936b68fb3 100644 --- a/provider/pihole/pihole_test.go +++ b/provider/pihole/pihole_test.go @@ -18,7 +18,6 @@ package pihole import ( "context" - "reflect" "testing" "sigs.k8s.io/external-dns/endpoint" @@ -27,7 +26,6 @@ import ( type testPiholeClient struct { endpoints []*endpoint.Endpoint - requests *requestTracker } func (t *testPiholeClient) listRecords(ctx context.Context, rtype string) ([]*endpoint.Endpoint, error) { @@ -42,7 +40,6 @@ func (t *testPiholeClient) listRecords(ctx context.Context, rtype string) ([]*en func (t *testPiholeClient) createRecord(ctx context.Context, ep *endpoint.Endpoint) error { t.endpoints = append(t.endpoints, ep) - t.requests.createRequests = append(t.requests.createRequests, ep) return nil } @@ -54,20 +51,9 @@ func (t *testPiholeClient) deleteRecord(ctx context.Context, ep *endpoint.Endpoi } } t.endpoints = newEPs - t.requests.deleteRequests = append(t.requests.deleteRequests, ep) return nil } -type requestTracker struct { - createRequests []*endpoint.Endpoint - deleteRequests []*endpoint.Endpoint -} - -func (r *requestTracker) clear() { - r.createRequests = nil - r.deleteRequests = nil -} - func TestNewPiholeProvider(t *testing.T) { // Test invalid configuration _, err := NewPiholeProvider(PiholeConfig{}) @@ -82,9 +68,8 @@ func TestNewPiholeProvider(t *testing.T) { } func TestProvider(t *testing.T) { - requests := requestTracker{} p := &PiholeProvider{ - api: &testPiholeClient{endpoints: make([]*endpoint.Endpoint, 0), requests: &requests}, + api: &testPiholeClient{}, } records, err := p.Records(context.Background()) @@ -128,12 +113,6 @@ func TestProvider(t *testing.T) { if len(newRecords) != 3 { t.Fatal("Expected list of 3 records, got:", records) } - if len(requests.createRequests) != 3 { - t.Fatal("Expected 3 create requests, got:", requests.createRequests) - } - if len(requests.deleteRequests) != 0 { - t.Fatal("Expected no delete requests, got:", requests.deleteRequests) - } for idx, record := range records { if newRecords[idx].DNSName != record.DNSName { @@ -142,14 +121,8 @@ func TestProvider(t *testing.T) { if newRecords[idx].Targets[0] != record.Targets[0] { t.Error("Targets malformed on retrieval, got:", newRecords[idx].Targets, "expected:", record.Targets) } - - if !reflect.DeepEqual(requests.createRequests[idx], record) { - t.Error("Unexpected create request, got:", newRecords[idx].DNSName, "expected:", record.DNSName) - } } - requests.clear() - // Test delete a record records = []*endpoint.Endpoint{ @@ -164,14 +137,13 @@ func TestProvider(t *testing.T) { RecordType: endpoint.RecordTypeA, }, } - recordToDelete := endpoint.Endpoint{ - DNSName: "test3.example.com", - Targets: []string{"192.168.1.3"}, - RecordType: endpoint.RecordTypeA, - } if err := p.ApplyChanges(context.Background(), &plan.Changes{ Delete: []*endpoint.Endpoint{ - &recordToDelete, + { + DNSName: "test3.example.com", + Targets: []string{"192.168.1.3"}, + RecordType: endpoint.RecordTypeA, + }, }, }); err != nil { t.Fatal(err) @@ -185,12 +157,6 @@ func TestProvider(t *testing.T) { if len(newRecords) != 2 { t.Fatal("Expected list of 2 records, got:", records) } - if len(requests.createRequests) != 0 { - t.Fatal("Expected no create requests, got:", requests.createRequests) - } - if len(requests.deleteRequests) != 1 { - t.Fatal("Expected 1 delete request, got:", requests.deleteRequests) - } for idx, record := range records { if newRecords[idx].DNSName != record.DNSName { @@ -201,12 +167,6 @@ func TestProvider(t *testing.T) { } } - if !reflect.DeepEqual(requests.deleteRequests[0], &recordToDelete) { - t.Error("Unexpected delete request, got:", requests.deleteRequests[0], "expected:", recordToDelete) - } - - requests.clear() - // Test update a record records = []*endpoint.Endpoint{ @@ -223,11 +183,6 @@ func TestProvider(t *testing.T) { } if err := p.ApplyChanges(context.Background(), &plan.Changes{ UpdateOld: []*endpoint.Endpoint{ - { - DNSName: "test1.example.com", - Targets: []string{"192.168.1.1"}, - RecordType: endpoint.RecordTypeA, - }, { DNSName: "test2.example.com", Targets: []string{"192.168.1.2"}, @@ -235,11 +190,6 @@ func TestProvider(t *testing.T) { }, }, UpdateNew: []*endpoint.Endpoint{ - { - DNSName: "test1.example.com", - Targets: []string{"192.168.1.1"}, - RecordType: endpoint.RecordTypeA, - }, { DNSName: "test2.example.com", Targets: []string{"10.0.0.1"}, @@ -258,12 +208,6 @@ func TestProvider(t *testing.T) { if len(newRecords) != 2 { t.Fatal("Expected list of 2 records, got:", records) } - if len(requests.createRequests) != 1 { - t.Fatal("Expected 1 create request, got:", requests.createRequests) - } - if len(requests.deleteRequests) != 1 { - t.Fatal("Expected 1 delete request, got:", requests.deleteRequests) - } for idx, record := range records { if newRecords[idx].DNSName != record.DNSName { @@ -273,24 +217,4 @@ func TestProvider(t *testing.T) { t.Error("Targets malformed on retrieval, got:", newRecords[idx].Targets, "expected:", record.Targets) } } - - expectedCreate := endpoint.Endpoint{ - DNSName: "test2.example.com", - Targets: []string{"10.0.0.1"}, - RecordType: endpoint.RecordTypeA, - } - expectedDelete := endpoint.Endpoint{ - DNSName: "test2.example.com", - Targets: []string{"192.168.1.2"}, - RecordType: endpoint.RecordTypeA, - } - - if !reflect.DeepEqual(requests.createRequests[0], &expectedCreate) { - t.Error("Unexpected create request, got:", requests.createRequests[0], "expected:", &expectedCreate) - } - if !reflect.DeepEqual(requests.deleteRequests[0], &expectedDelete) { - t.Error("Unexpected delete request, got:", requests.deleteRequests[0], "expected:", &expectedDelete) - } - - requests.clear() } diff --git a/provider/tidydns/tidydns.go b/provider/tidydns/tidydns.go new file mode 100644 index 0000000000..6a15306be9 --- /dev/null +++ b/provider/tidydns/tidydns.go @@ -0,0 +1,312 @@ +package tidydns + +import ( + "context" + "fmt" + "os" + "strconv" + "strings" + + "github.com/neticdk/tidydns-go/pkg/tidydns" + log "github.com/sirupsen/logrus" + "sigs.k8s.io/external-dns/endpoint" + "sigs.k8s.io/external-dns/plan" + "sigs.k8s.io/external-dns/provider" +) + +var ( + errorSkip = fmt.Errorf("skipping record") +) + +type tidyDNSProvider struct { + provider.BaseProvider + domainFilter endpoint.DomainFilter + zoneIDFilter provider.ZoneIDFilter + dryRun bool + client tidydns.TidyDNSClient +} + +type groupKey struct { + name string + rType string +} + +// NewTidyDNSProvider initializes a new Dnsimple based provider +func NewTidyDNSProvider(domainFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, endpoint string, dryRun bool) (provider.Provider, error) { + username := os.Getenv("TIDYDNS_USER") + if len(username) == 0 { + return nil, fmt.Errorf("no tidydns username provided") + } + + password := os.Getenv("TIDYDNS_PASS") + if len(password) == 0 { + return nil, fmt.Errorf("no tidydns password provided") + } + + if len(endpoint) == 0 { + return nil, fmt.Errorf("no tidydns endpoint provided") + } + + provider := &tidyDNSProvider{ + domainFilter: domainFilter, + zoneIDFilter: zoneIDFilter, + dryRun: dryRun, + client: tidydns.New(endpoint, username, password), + } + return provider, nil +} + +func (t *tidyDNSProvider) Records(ctx context.Context) (endpoints []*endpoint.Endpoint, err error) { + zones, err := t.client.ListZones(ctx) + if err != nil { + return nil, err + } + + grouped := make(map[groupKey][]*tidydns.RecordInfo) + for _, z := range zones { + if !(t.domainFilter.Match(z.Name) || t.domainFilter.MatchParent(z.Name)) || !t.zoneIDFilter.Match(strconv.Itoa(z.ID)) { + log.Debugf("Skipping zone %d due to zone filter", z.ID) + continue + } + + records, err := t.client.ListRecords(ctx, z.ID) + log.Debugf("Got %d records for zone %d", len(records), z.ID) + if err != nil { + return nil, err + } + + for _, r := range records { + rType := "" + switch r.Type { + case tidydns.RecordTypeA: + rType = "A" + case tidydns.RecordTypeCNAME: + rType = "CNAME" + case tidydns.RecordTypeTXT: + rType = "TXT" + r.Destination = fmt.Sprintf("\"%s\"", r.Destination) // external-dns expects quotation marks around the TXT records + default: + continue + } + + dnsName := r.Name + "." + z.Name + if len(strings.Trim(r.Name, ".")) == 0 { + dnsName = z.Name + } + gId := groupKey{name: dnsName, rType: rType} + _, ok := grouped[gId] + if !ok { + grouped[gId] = make([]*tidydns.RecordInfo, 0) + } + grouped[gId] = append(grouped[gId], r) + + } + } + + for k, v := range grouped { + targets := make([]string, 0) + ttl := endpoint.TTL(0) + description := "" + for _, r := range v { + targets = append(targets, r.Destination) + ttl = endpoint.TTL(r.TTL) + description = r.Description + } + endpoints = append(endpoints, endpoint.NewEndpointWithTTL(k.name, k.rType, ttl, targets...).WithSetIdentifier(description)) + } + + log.Debugf("Returning endpoints: %+v", endpoints) + + return endpoints, nil +} + +func (t *tidyDNSProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error { + if !changes.HasChanges() { + return nil + } + + zones, err := t.client.ListZones(ctx) + if err != nil { + return err + } + + for _, c := range changes.Create { + log.Tracef("Handling creation record %+v", c) + + z := findSuitableZones(zones, c.DNSName) + if z == nil { + log.Debugf("Skipping create of record %s because no hosted zone matching record DNS Name was detected", c.DNSName) + continue + } + + rType := convertRecordType(c.RecordType) + if rType == tidydns.RecordType(-1) { + log.Warnf("Skipping create of record %s because it has unsupported record type %s", c.DNSName, c.RecordType) + continue + } + + infos := createRecordInfo(c, z.Name) + for _, in := range infos { + log.Infof("Create record %s (%s) of type %s in zone %s with target %s", c.DNSName, in.Name, c.RecordType, z.Name, in.Destination) + if !t.dryRun { + _, err = t.client.CreateRecord(ctx, z.ID, in) + if err != nil { + return err + } + } + } + } + + for i, u := range changes.UpdateNew { + log.Tracef("Handling update record %+v", u) + + z := findSuitableZones(zones, u.DNSName) + if z == nil { + log.Debugf("Skipping update of record %s because no hosted zone matching record DNS Name was detected", u.DNSName) + continue + } + + records, err := t.findRecords(ctx, u, z) + if err != nil { + if err == errorSkip { + continue + } else { + return err + } + } + + for _, r := range records { + if r.Description == u.SetIdentifier { + infos := createRecordInfo(u, z.Name) + log.Tracef("infos: %+v", infos) + for j, in := range infos { + if changes.UpdateOld[i].Targets[j] == r.Destination { + log.Infof("Update record %s (%s/%d) of type %s in zone %s with target %s", u.DNSName, in.Name, r.ID, u.RecordType, z.Name, in.Destination) + if !t.dryRun { + err := t.client.UpdateRecord(ctx, z.ID, r.ID, in) + if err != nil { + return err + } + } + } + } + } + } + } + + for _, d := range changes.Delete { + log.Tracef("Handling deletion record %+v", d) + + z := findSuitableZones(zones, d.DNSName) + if z == nil { + log.Debugf("Skipping delete of record %s because no hosted zone matching record DNS Name was detected", d.DNSName) + continue + } + + records, err := t.findRecords(ctx, d, z) + if err != nil { + if err == errorSkip { + continue + } else { + return err + } + } + + for _, r := range records { + if r.Description == d.SetIdentifier { + for _, ta := range d.Targets { + if ta == r.Destination { + log.Infof("Deleting record %s (%s/%d) of type %s in zone %s with target %s", d.DNSName, r.Name, r.ID, d.RecordType, z.Name, ta) + if !t.dryRun { + err := t.client.DeleteRecord(ctx, z.ID, r.ID) + if err != nil { + return err + } + } + } + } + } + } + } + + return nil +} + +// findRecords retrives DNS records matching the given endpoint within the given zone +func (t *tidyDNSProvider) findRecords(ctx context.Context, e *endpoint.Endpoint, z *tidydns.ZoneInfo) ([]*tidydns.RecordInfo, error) { + rType := convertRecordType(e.RecordType) + if rType == tidydns.RecordType(-1) { + log.Warnf("Skipping record %s because it has unsupported record type %s", e.DNSName, e.RecordType) + return nil, errorSkip + } + + hostname := strings.TrimSuffix(strings.TrimSuffix(e.DNSName, z.Name), ".") + records, err := t.client.FindRecord(ctx, z.ID, hostname, rType) + log.Tracef("Found records %d based on hostname %s and type %+v", len(records), hostname, rType) + if err != nil { + return nil, err + } + + for _, r := range records { + if r.Type == tidydns.RecordTypeTXT { + r.Destination = fmt.Sprintf("\"%s\"", r.Destination) // external-dns expects quotation marks around the TXT records + } + } + + return records, nil +} + +// findSuitableZones returns DNS zone matching the longest part of the domain of the hostname +func findSuitableZones(zones []*tidydns.ZoneInfo, hostname string) *tidydns.ZoneInfo { + var zone *tidydns.ZoneInfo + for _, z := range zones { + if strings.HasSuffix(hostname, z.Name) { + if zone == nil || len(z.Name) > len(zone.Name) { + zone = z + } + } + + } + return zone +} + +// convertRecordType translates the text record type into Tidy constants +func convertRecordType(rType string) tidydns.RecordType { + switch rType { + case "A": + return tidydns.RecordTypeA + case "CNAME": + return tidydns.RecordTypeCNAME + case "TXT": + return tidydns.RecordTypeTXT + default: + return tidydns.RecordType(-1) + } +} + +// createRecordInfo creates record info structures from endpoint +func createRecordInfo(e *endpoint.Endpoint, zone string) []tidydns.RecordInfo { + rType := convertRecordType(e.RecordType) + + dnsName := strings.TrimSuffix(strings.TrimSuffix(e.DNSName, zone), ".") + if len(dnsName) == 0 { + dnsName = "." + } + + records := make([]tidydns.RecordInfo, 0) + for _, ta := range e.Targets { + if rType == tidydns.RecordTypeTXT { + ta = strings.TrimSuffix(strings.TrimPrefix(ta, "\""), "\"") + } + r := tidydns.RecordInfo{ + Name: dnsName, + Destination: ta, + Type: rType, + TTL: int(e.RecordTTL), + Description: e.SetIdentifier, + } + records = append(records, r) + } + + return records +} diff --git a/provider/tidydns/tidydns_test.go b/provider/tidydns/tidydns_test.go new file mode 100644 index 0000000000..e01f4b8dca --- /dev/null +++ b/provider/tidydns/tidydns_test.go @@ -0,0 +1,207 @@ +package tidydns + +import ( + "context" + "os" + "testing" + + "github.com/neticdk/tidydns-go/pkg/tidydns" + log "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "sigs.k8s.io/external-dns/endpoint" + "sigs.k8s.io/external-dns/plan" + "sigs.k8s.io/external-dns/provider" +) + +func TestNewTidyDNSProvider(t *testing.T) { + _ = os.Setenv("TIDYDNS_USER", "user") + _ = os.Setenv("TIDYDNS_PASS", "pass") + _, err := NewTidyDNSProvider(endpoint.NewDomainFilter([]string{"tidydns.com"}), provider.NewZoneIDFilter([]string{"1234"}), "endpoint", true) + assert.NoError(t, err) + + _ = os.Unsetenv("TIDYDNS_USER") + _ = os.Unsetenv("TIDYDNS_PASS") + _, err = NewTidyDNSProvider(endpoint.NewDomainFilter([]string{"tidydns.com"}), provider.NewZoneIDFilter([]string{"1234"}), "endpoint", true) + assert.Error(t, err) +} + +func TestTidyDNSRecords(t *testing.T) { + client := &mockClient{} + client.On("ListZones", mock.AnythingOfType("*context.emptyCtx")).Return(zones, nil) + client.On("ListRecords", mock.AnythingOfType("*context.emptyCtx"), 1).Return(zone1, nil) + client.On("ListRecords", mock.AnythingOfType("*context.emptyCtx"), 2).Return(zone2, nil) + + provider := &tidyDNSProvider{ + client: client, + } + recs, err := provider.Records(context.Background()) + assert.NoError(t, err) + assert.Len(t, recs, 3) + client.AssertExpectations(t) +} + +func TestTidyDNSApplyChanges(t *testing.T) { + log.SetLevel(log.TraceLevel) + + client := &mockClient{} + client.On("ListZones", mock.AnythingOfType("*context.emptyCtx")).Return(zones, nil) + client.On("FindRecord", mock.AnythingOfType("*context.emptyCtx"), 1, "ttl", tidydns.RecordTypeA).Return(ttl, nil) + client.On("FindRecord", mock.AnythingOfType("*context.emptyCtx"), 1, "regular3", tidydns.RecordTypeA).Return(regular3, nil) + client.On("FindRecord", mock.AnythingOfType("*context.emptyCtx"), 1, "regular4", tidydns.RecordTypeA).Return(regular4, nil) + client.On("FindRecord", mock.AnythingOfType("*context.emptyCtx"), 1, "regular5", tidydns.RecordTypeA).Return(regular5, nil) + client.On("CreateRecord", mock.AnythingOfType("*context.emptyCtx"), 1, tidydns.RecordInfo{ID: 0, Type: 0, Name: "regular1", Description: "", Destination: "1.1.1.1", TTL: 0, Status: 0, Location: 0}).Return(1, nil) + client.On("CreateRecord", mock.AnythingOfType("*context.emptyCtx"), 1, tidydns.RecordInfo{ID: 0, Type: 0, Name: "ttl", Description: "", Destination: "1.1.1.1", TTL: 100, Status: 0, Location: 0}).Return(2, nil) + client.On("CreateRecord", mock.AnythingOfType("*context.emptyCtx"), 1, tidydns.RecordInfo{ID: 0, Type: 0, Name: "regular2", Description: "", Destination: "1.1.1.2", TTL: 0, Status: 0, Location: 0}).Return(3, nil) + client.On("UpdateRecord", mock.AnythingOfType("*context.emptyCtx"), 1, 3, tidydns.RecordInfo{ID: 0, Type: 0, Name: "regular3", Description: "", Destination: "1.1.2.2", TTL: 100, Status: 0, Location: 0}).Return(nil) + client.On("UpdateRecord", mock.AnythingOfType("*context.emptyCtx"), 1, 4, tidydns.RecordInfo{ID: 0, Type: 0, Name: "regular4", Description: "", Destination: "1.1.2.2", TTL: 100, Status: 0, Location: 0}).Return(nil) + client.On("DeleteRecord", mock.AnythingOfType("*context.emptyCtx"), 1, 5).Return(nil) + client.On("DeleteRecord", mock.AnythingOfType("*context.emptyCtx"), 1, 42).Return(nil) + + provider := &tidyDNSProvider{ + client: client, + dryRun: false, + } + + changes := &plan.Changes{} + changes.Create = []*endpoint.Endpoint{ + {DNSName: "regular1.tidydns1.com", Targets: endpoint.Targets{"1.1.1.1"}, RecordType: "A"}, + {DNSName: "ttl.tidydns1.com", Targets: endpoint.Targets{"1.1.1.1"}, RecordType: "A", RecordTTL: 100}, + {DNSName: "regular2.tidydns1.com", Targets: endpoint.Targets{"1.1.1.2"}, RecordType: "A"}, + } + changes.UpdateOld = []*endpoint.Endpoint{ + {DNSName: "regular3.tidydns1.com", Targets: endpoint.Targets{"127.0.3.1"}, RecordType: "A"}, + {DNSName: "regular4.tidydns1.com", Targets: endpoint.Targets{"127.0.4.1"}, RecordType: "A"}, + } + changes.UpdateNew = []*endpoint.Endpoint{ + {DNSName: "regular3.tidydns1.com", Targets: endpoint.Targets{"1.1.2.2"}, RecordType: "A", RecordTTL: 100}, + {DNSName: "regular4.tidydns1.com", Targets: endpoint.Targets{"1.1.2.2"}, RecordType: "A", RecordTTL: 100}, + } + changes.Delete = []*endpoint.Endpoint{ + {DNSName: "regular5.tidydns1.com", Targets: endpoint.Targets{"1.1.2.2"}, RecordType: "A", RecordTTL: 100}, + {DNSName: "ttl.tidydns1.com", Targets: endpoint.Targets{"1.1.1.1"}, RecordType: "A", RecordTTL: 100}, + } + + err := provider.ApplyChanges(context.Background(), changes) + assert.NoError(t, err) + client.AssertExpectations(t) +} + +type mockClient struct { + mock.Mock +} + +var ( + zones = []*tidydns.ZoneInfo{ + { + ID: 1, + Name: "tidydns1.com", + }, + { + ID: 2, + Name: "tidydns2.com", + }, + } + + zone1 = []*tidydns.RecordInfo{ + { + ID: 11, + Type: tidydns.RecordTypeA, + Name: "tidy11", + Destination: "127.0.1.1", + }, + { + ID: 11, + Type: tidydns.RecordTypeTXT, + Name: "tidy11", + Destination: "\"heritage=external-dns,external-dns/owner=prod1,external-dns/resource=ingress/namesapce/ingress1\"", + }, + } + + zone2 = []*tidydns.RecordInfo{ + { + ID: 21, + Type: tidydns.RecordTypeA, + Name: "tidy21", + Destination: "127.0.2.1", + }, + } + + ttl = []*tidydns.RecordInfo{ + { + ID: 42, + Type: tidydns.RecordTypeA, + Name: "ttl", + Destination: "1.1.1.1", + }, + } + regular3 = []*tidydns.RecordInfo{ + { + ID: 3, + Type: tidydns.RecordTypeA, + Name: "regular3", + Destination: "127.0.3.1", + }, + } + regular4 = []*tidydns.RecordInfo{ + { + ID: 4, + Type: tidydns.RecordTypeA, + Name: "regular4", + Destination: "127.0.4.1", + }, + } + regular5 = []*tidydns.RecordInfo{ + { + ID: 5, + Type: tidydns.RecordTypeA, + Name: "regular5", + Destination: "1.1.2.2", + }, + } +) + +func (m *mockClient) ListZones(ctx context.Context) ([]*tidydns.ZoneInfo, error) { + args := m.Called(ctx) + return args.Get(0).([]*tidydns.ZoneInfo), args.Error(1) +} + +func (*mockClient) FindZoneID(ctx context.Context, name string) (int, error) { + return 0, nil +} + +func (m *mockClient) CreateRecord(ctx context.Context, zoneID int, info tidydns.RecordInfo) (int, error) { + args := m.Called(ctx, zoneID, info) + return args.Int(0), args.Error(1) +} + +func (m *mockClient) UpdateRecord(ctx context.Context, zoneID int, recordID int, info tidydns.RecordInfo) error { + args := m.Called(ctx, zoneID, recordID, info) + return args.Error(0) +} + +func (m *mockClient) ReadRecord(ctx context.Context, zoneID int, recordID int) (*tidydns.RecordInfo, error) { + args := m.Called(ctx, zoneID, recordID) + if args.Get(0) != nil { + return args.Get(0).(*tidydns.RecordInfo), args.Error(1) + } + return nil, args.Error(1) +} + +func (m *mockClient) FindRecord(ctx context.Context, zoneID int, name string, rType tidydns.RecordType) ([]*tidydns.RecordInfo, error) { + args := m.Called(ctx, zoneID, name, rType) + if args.Get(0) != nil { + return args.Get(0).([]*tidydns.RecordInfo), args.Error(1) + } + return nil, args.Error(1) +} + +func (m *mockClient) ListRecords(ctx context.Context, zoneID int) ([]*tidydns.RecordInfo, error) { + args := m.Called(ctx, zoneID) + return args.Get(0).([]*tidydns.RecordInfo), args.Error(1) +} + +func (m *mockClient) DeleteRecord(ctx context.Context, zoneID int, recordID int) error { + args := m.Called(ctx, zoneID, recordID) + return args.Error(0) +} diff --git a/registry/txt.go b/registry/txt.go index faa3b7453a..5a652fec0e 100644 --- a/registry/txt.go +++ b/registry/txt.go @@ -198,7 +198,6 @@ func (im *TXTRegistry) generateTXTRecord(r *endpoint.Endpoint) []*endpoint.Endpo txt := endpoint.NewEndpoint(im.mapper.toTXTName(r.DNSName), endpoint.RecordTypeTXT, r.Labels.Serialize(true)) if txt != nil { txt.WithSetIdentifier(r.SetIdentifier) - txt.Labels[endpoint.OwnedRecordLabelKey] = r.DNSName txt.ProviderSpecific = r.ProviderSpecific endpoints = append(endpoints, txt) } @@ -207,7 +206,6 @@ func (im *TXTRegistry) generateTXTRecord(r *endpoint.Endpoint) []*endpoint.Endpo txtNew := endpoint.NewEndpoint(im.mapper.toNewTXTName(r.DNSName, r.RecordType), endpoint.RecordTypeTXT, r.Labels.Serialize(true)) if txtNew != nil { txtNew.WithSetIdentifier(r.SetIdentifier) - txtNew.Labels[endpoint.OwnedRecordLabelKey] = r.DNSName txtNew.ProviderSpecific = r.ProviderSpecific endpoints = append(endpoints, txtNew) } diff --git a/registry/txt_test.go b/registry/txt_test.go index 5e8168045e..9d5f263b95 100644 --- a/registry/txt_test.go +++ b/registry/txt_test.go @@ -436,38 +436,38 @@ func testTXTRegistryApplyChangesWithPrefix(t *testing.T) { expected := &plan.Changes{ Create: []*endpoint.Endpoint{ newEndpointWithOwnerResource("new-record-1.test-zone.example.org", "new-loadbalancer-1.lb.com", endpoint.RecordTypeCNAME, "owner", "ingress/default/my-ingress"), - newEndpointWithOwnerAndOwnedRecord("txt.new-record-1.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, "", "new-record-1.test-zone.example.org"), - newEndpointWithOwnerAndOwnedRecord("txt.cname-new-record-1.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, "", "new-record-1.test-zone.example.org"), + newEndpointWithOwner("txt.new-record-1.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, ""), + newEndpointWithOwner("txt.cname-new-record-1.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, ""), newEndpointWithOwnerResource("multiple.test-zone.example.org", "lb3.loadbalancer.com", endpoint.RecordTypeCNAME, "owner", "ingress/default/my-ingress").WithSetIdentifier("test-set-3"), - newEndpointWithOwnerAndOwnedRecord("txt.multiple.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, "", "multiple.test-zone.example.org").WithSetIdentifier("test-set-3"), - newEndpointWithOwnerAndOwnedRecord("txt.cname-multiple.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, "", "multiple.test-zone.example.org").WithSetIdentifier("test-set-3"), + newEndpointWithOwner("txt.multiple.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, "").WithSetIdentifier("test-set-3"), + newEndpointWithOwner("txt.cname-multiple.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, "").WithSetIdentifier("test-set-3"), newEndpointWithOwnerResource("example", "new-loadbalancer-1.lb.com", endpoint.RecordTypeCNAME, "owner", "ingress/default/my-ingress"), - newEndpointWithOwnerAndOwnedRecord("txt.example", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, "", "example"), - newEndpointWithOwnerAndOwnedRecord("txt.cname-example", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, "", "example"), + newEndpointWithOwner("txt.example", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, ""), + newEndpointWithOwner("txt.cname-example", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, ""), }, Delete: []*endpoint.Endpoint{ newEndpointWithOwner("foobar.test-zone.example.org", "foobar.loadbalancer.com", endpoint.RecordTypeCNAME, "owner"), - newEndpointWithOwnerAndOwnedRecord("txt.foobar.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "foobar.test-zone.example.org"), - newEndpointWithOwnerAndOwnedRecord("txt.cname-foobar.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "foobar.test-zone.example.org"), + newEndpointWithOwner("txt.foobar.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""), + newEndpointWithOwner("txt.cname-foobar.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""), newEndpointWithOwner("multiple.test-zone.example.org", "lb1.loadbalancer.com", endpoint.RecordTypeCNAME, "owner").WithSetIdentifier("test-set-1"), - newEndpointWithOwnerAndOwnedRecord("txt.multiple.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "multiple.test-zone.example.org").WithSetIdentifier("test-set-1"), - newEndpointWithOwnerAndOwnedRecord("txt.cname-multiple.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "multiple.test-zone.example.org").WithSetIdentifier("test-set-1"), + newEndpointWithOwner("txt.multiple.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "").WithSetIdentifier("test-set-1"), + newEndpointWithOwner("txt.cname-multiple.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "").WithSetIdentifier("test-set-1"), }, UpdateNew: []*endpoint.Endpoint{ newEndpointWithOwnerResource("tar.test-zone.example.org", "new-tar.loadbalancer.com", endpoint.RecordTypeCNAME, "owner", "ingress/default/my-ingress-2"), - newEndpointWithOwnerAndOwnedRecord("txt.tar.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress-2\"", endpoint.RecordTypeTXT, "", "tar.test-zone.example.org"), - newEndpointWithOwnerAndOwnedRecord("txt.cname-tar.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress-2\"", endpoint.RecordTypeTXT, "", "tar.test-zone.example.org"), + newEndpointWithOwner("txt.tar.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress-2\"", endpoint.RecordTypeTXT, ""), + newEndpointWithOwner("txt.cname-tar.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress-2\"", endpoint.RecordTypeTXT, ""), newEndpointWithOwnerResource("multiple.test-zone.example.org", "new.loadbalancer.com", endpoint.RecordTypeCNAME, "owner", "ingress/default/my-ingress-2").WithSetIdentifier("test-set-2"), - newEndpointWithOwnerAndOwnedRecord("txt.multiple.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress-2\"", endpoint.RecordTypeTXT, "", "multiple.test-zone.example.org").WithSetIdentifier("test-set-2"), - newEndpointWithOwnerAndOwnedRecord("txt.cname-multiple.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress-2\"", endpoint.RecordTypeTXT, "", "multiple.test-zone.example.org").WithSetIdentifier("test-set-2"), + newEndpointWithOwner("txt.multiple.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress-2\"", endpoint.RecordTypeTXT, "").WithSetIdentifier("test-set-2"), + newEndpointWithOwner("txt.cname-multiple.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress-2\"", endpoint.RecordTypeTXT, "").WithSetIdentifier("test-set-2"), }, UpdateOld: []*endpoint.Endpoint{ newEndpointWithOwner("tar.test-zone.example.org", "tar.loadbalancer.com", endpoint.RecordTypeCNAME, "owner"), - newEndpointWithOwnerAndOwnedRecord("txt.tar.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "tar.test-zone.example.org"), - newEndpointWithOwnerAndOwnedRecord("txt.cname-tar.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "tar.test-zone.example.org"), + newEndpointWithOwner("txt.tar.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""), + newEndpointWithOwner("txt.cname-tar.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""), newEndpointWithOwner("multiple.test-zone.example.org", "lb2.loadbalancer.com", endpoint.RecordTypeCNAME, "owner").WithSetIdentifier("test-set-2"), - newEndpointWithOwnerAndOwnedRecord("txt.multiple.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "multiple.test-zone.example.org").WithSetIdentifier("test-set-2"), - newEndpointWithOwnerAndOwnedRecord("txt.cname-multiple.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "multiple.test-zone.example.org").WithSetIdentifier("test-set-2"), + newEndpointWithOwner("txt.multiple.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "").WithSetIdentifier("test-set-2"), + newEndpointWithOwner("txt.cname-multiple.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "").WithSetIdentifier("test-set-2"), }, } p.OnApplyChanges = func(ctx context.Context, got *plan.Changes) { @@ -513,8 +513,8 @@ func testTXTRegistryApplyChangesWithTemplatedPrefix(t *testing.T) { expected := &plan.Changes{ Create: []*endpoint.Endpoint{ newEndpointWithOwnerResource("new-record-1.test-zone.example.org", "new-loadbalancer-1.lb.com", endpoint.RecordTypeCNAME, "owner", "ingress/default/my-ingress"), - newEndpointWithOwnerAndOwnedRecord("prefix.new-record-1.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, "", "new-record-1.test-zone.example.org"), - newEndpointWithOwnerAndOwnedRecord("prefixcname.new-record-1.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, "", "new-record-1.test-zone.example.org"), + newEndpointWithOwner("prefix.new-record-1.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, ""), + newEndpointWithOwner("prefixcname.new-record-1.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, ""), }, } p.OnApplyChanges = func(ctx context.Context, got *plan.Changes) { @@ -557,8 +557,8 @@ func testTXTRegistryApplyChangesWithTemplatedSuffix(t *testing.T) { expected := &plan.Changes{ Create: []*endpoint.Endpoint{ newEndpointWithOwnerResource("new-record-1.test-zone.example.org", "new-loadbalancer-1.lb.com", endpoint.RecordTypeCNAME, "owner", "ingress/default/my-ingress"), - newEndpointWithOwnerAndOwnedRecord("new-record-1-cnamesuffix.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, "", "new-record-1.test-zone.example.org"), - newEndpointWithOwnerAndOwnedRecord("new-record-1-suffix.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, "", "new-record-1.test-zone.example.org"), + newEndpointWithOwner("new-record-1-cnamesuffix.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, ""), + newEndpointWithOwner("new-record-1-suffix.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, ""), }, } p.OnApplyChanges = func(ctx context.Context, got *plan.Changes) { @@ -636,41 +636,41 @@ func testTXTRegistryApplyChangesWithSuffix(t *testing.T) { expected := &plan.Changes{ Create: []*endpoint.Endpoint{ newEndpointWithOwnerResource("new-record-1.test-zone.example.org", "new-loadbalancer-1.lb.com", endpoint.RecordTypeCNAME, "owner", "ingress/default/my-ingress"), - newEndpointWithOwnerAndOwnedRecord("new-record-1-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, "", "new-record-1.test-zone.example.org"), - newEndpointWithOwnerAndOwnedRecord("cname-new-record-1-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, "", "new-record-1.test-zone.example.org"), + newEndpointWithOwner("new-record-1-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, ""), + newEndpointWithOwner("cname-new-record-1-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, ""), newEndpointWithOwnerResource("multiple.test-zone.example.org", "lb3.loadbalancer.com", endpoint.RecordTypeCNAME, "owner", "ingress/default/my-ingress").WithSetIdentifier("test-set-3"), - newEndpointWithOwnerAndOwnedRecord("multiple-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, "", "multiple.test-zone.example.org").WithSetIdentifier("test-set-3"), - newEndpointWithOwnerAndOwnedRecord("cname-multiple-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, "", "multiple.test-zone.example.org").WithSetIdentifier("test-set-3"), + newEndpointWithOwner("multiple-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, "").WithSetIdentifier("test-set-3"), + newEndpointWithOwner("cname-multiple-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, "").WithSetIdentifier("test-set-3"), newEndpointWithOwnerResource("example", "new-loadbalancer-1.lb.com", endpoint.RecordTypeCNAME, "owner", "ingress/default/my-ingress"), - newEndpointWithOwnerAndOwnedRecord("example-txt", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, "", "example"), - newEndpointWithOwnerAndOwnedRecord("cname-example-txt", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, "", "example"), + newEndpointWithOwner("example-txt", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, ""), + newEndpointWithOwner("cname-example-txt", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, ""), newEndpointWithOwnerResource("*.wildcard.test-zone.example.org", "new-loadbalancer-1.lb.com", endpoint.RecordTypeCNAME, "owner", "ingress/default/my-ingress"), - newEndpointWithOwnerAndOwnedRecord("wildcard-txt.wildcard.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, "", "*.wildcard.test-zone.example.org"), - newEndpointWithOwnerAndOwnedRecord("cname-wildcard-txt.wildcard.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, "", "*.wildcard.test-zone.example.org"), + newEndpointWithOwner("wildcard-txt.wildcard.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, ""), + newEndpointWithOwner("cname-wildcard-txt.wildcard.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress\"", endpoint.RecordTypeTXT, ""), }, Delete: []*endpoint.Endpoint{ newEndpointWithOwner("foobar.test-zone.example.org", "foobar.loadbalancer.com", endpoint.RecordTypeCNAME, "owner"), - newEndpointWithOwnerAndOwnedRecord("foobar-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "foobar.test-zone.example.org"), - newEndpointWithOwnerAndOwnedRecord("cname-foobar-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "foobar.test-zone.example.org"), + newEndpointWithOwner("foobar-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""), + newEndpointWithOwner("cname-foobar-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""), newEndpointWithOwner("multiple.test-zone.example.org", "lb1.loadbalancer.com", endpoint.RecordTypeCNAME, "owner").WithSetIdentifier("test-set-1"), - newEndpointWithOwnerAndOwnedRecord("multiple-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "multiple.test-zone.example.org").WithSetIdentifier("test-set-1"), - newEndpointWithOwnerAndOwnedRecord("cname-multiple-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "multiple.test-zone.example.org").WithSetIdentifier("test-set-1"), + newEndpointWithOwner("multiple-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "").WithSetIdentifier("test-set-1"), + newEndpointWithOwner("cname-multiple-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "").WithSetIdentifier("test-set-1"), }, UpdateNew: []*endpoint.Endpoint{ newEndpointWithOwnerResource("tar.test-zone.example.org", "new-tar.loadbalancer.com", endpoint.RecordTypeCNAME, "owner", "ingress/default/my-ingress-2"), - newEndpointWithOwnerAndOwnedRecord("tar-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress-2\"", endpoint.RecordTypeTXT, "", "tar.test-zone.example.org"), - newEndpointWithOwnerAndOwnedRecord("cname-tar-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress-2\"", endpoint.RecordTypeTXT, "", "tar.test-zone.example.org"), + newEndpointWithOwner("tar-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress-2\"", endpoint.RecordTypeTXT, ""), + newEndpointWithOwner("cname-tar-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress-2\"", endpoint.RecordTypeTXT, ""), newEndpointWithOwnerResource("multiple.test-zone.example.org", "new.loadbalancer.com", endpoint.RecordTypeCNAME, "owner", "ingress/default/my-ingress-2").WithSetIdentifier("test-set-2"), - newEndpointWithOwnerAndOwnedRecord("multiple-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress-2\"", endpoint.RecordTypeTXT, "", "multiple.test-zone.example.org").WithSetIdentifier("test-set-2"), - newEndpointWithOwnerAndOwnedRecord("cname-multiple-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress-2\"", endpoint.RecordTypeTXT, "", "multiple.test-zone.example.org").WithSetIdentifier("test-set-2"), + newEndpointWithOwner("multiple-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress-2\"", endpoint.RecordTypeTXT, "").WithSetIdentifier("test-set-2"), + newEndpointWithOwner("cname-multiple-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner,external-dns/resource=ingress/default/my-ingress-2\"", endpoint.RecordTypeTXT, "").WithSetIdentifier("test-set-2"), }, UpdateOld: []*endpoint.Endpoint{ newEndpointWithOwner("tar.test-zone.example.org", "tar.loadbalancer.com", endpoint.RecordTypeCNAME, "owner"), - newEndpointWithOwnerAndOwnedRecord("tar-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "tar.test-zone.example.org"), - newEndpointWithOwnerAndOwnedRecord("cname-tar-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "tar.test-zone.example.org"), + newEndpointWithOwner("tar-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""), + newEndpointWithOwner("cname-tar-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""), newEndpointWithOwner("multiple.test-zone.example.org", "lb2.loadbalancer.com", endpoint.RecordTypeCNAME, "owner").WithSetIdentifier("test-set-2"), - newEndpointWithOwnerAndOwnedRecord("multiple-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "multiple.test-zone.example.org").WithSetIdentifier("test-set-2"), - newEndpointWithOwnerAndOwnedRecord("cname-multiple-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "multiple.test-zone.example.org").WithSetIdentifier("test-set-2"), + newEndpointWithOwner("multiple-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "").WithSetIdentifier("test-set-2"), + newEndpointWithOwner("cname-multiple-txt.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "").WithSetIdentifier("test-set-2"), }, } p.OnApplyChanges = func(ctx context.Context, got *plan.Changes) { @@ -735,16 +735,16 @@ func testTXTRegistryApplyChangesNoPrefix(t *testing.T) { expected := &plan.Changes{ Create: []*endpoint.Endpoint{ newEndpointWithOwner("new-record-1.test-zone.example.org", "new-loadbalancer-1.lb.com", endpoint.RecordTypeCNAME, "owner"), - newEndpointWithOwnerAndOwnedRecord("new-record-1.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "new-record-1.test-zone.example.org"), - newEndpointWithOwnerAndOwnedRecord("cname-new-record-1.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "new-record-1.test-zone.example.org"), + newEndpointWithOwner("new-record-1.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""), + newEndpointWithOwner("cname-new-record-1.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""), newEndpointWithOwner("example", "new-loadbalancer-1.lb.com", endpoint.RecordTypeCNAME, "owner"), - newEndpointWithOwnerAndOwnedRecord("example", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "example"), - newEndpointWithOwnerAndOwnedRecord("cname-example", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "example"), + newEndpointWithOwner("example", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""), + newEndpointWithOwner("cname-example", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""), }, Delete: []*endpoint.Endpoint{ newEndpointWithOwner("foobar.test-zone.example.org", "foobar.loadbalancer.com", endpoint.RecordTypeCNAME, "owner"), - newEndpointWithOwnerAndOwnedRecord("foobar.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "foobar.test-zone.example.org"), - newEndpointWithOwnerAndOwnedRecord("cname-foobar.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "foobar.test-zone.example.org"), + newEndpointWithOwner("foobar.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""), + newEndpointWithOwner("cname-foobar.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""), }, UpdateNew: []*endpoint.Endpoint{}, UpdateOld: []*endpoint.Endpoint{}, @@ -867,17 +867,11 @@ func testTXTRegistryMissingRecordsNoPrefix(t *testing.T) { // owner is taken from the source record (A, CNAME, etc.) Targets: endpoint.Targets{"\"heritage=external-dns,external-dns/owner=owner\""}, RecordType: endpoint.RecordTypeTXT, - Labels: endpoint.Labels{ - endpoint.OwnedRecordLabelKey: "oldformat.test-zone.example.org", - }, }, { DNSName: "a-oldformat2.test-zone.example.org", Targets: endpoint.Targets{"\"heritage=external-dns,external-dns/owner=owner\""}, RecordType: endpoint.RecordTypeTXT, - Labels: endpoint.Labels{ - endpoint.OwnedRecordLabelKey: "oldformat2.test-zone.example.org", - }, }, } @@ -971,17 +965,11 @@ func testTXTRegistryMissingRecordsWithPrefix(t *testing.T) { // owner is taken from the source record (A, CNAME, etc.) Targets: endpoint.Targets{"\"heritage=external-dns,external-dns/owner=owner\""}, RecordType: endpoint.RecordTypeTXT, - Labels: endpoint.Labels{ - endpoint.OwnedRecordLabelKey: "oldformat.test-zone.example.org", - }, }, { DNSName: "txt.a-oldformat2.test-zone.example.org", Targets: endpoint.Targets{"\"heritage=external-dns,external-dns/owner=owner\""}, RecordType: endpoint.RecordTypeTXT, - Labels: endpoint.Labels{ - endpoint.OwnedRecordLabelKey: "oldformat2.test-zone.example.org", - }, }, } @@ -1124,16 +1112,16 @@ func TestNewTXTScheme(t *testing.T) { expected := &plan.Changes{ Create: []*endpoint.Endpoint{ newEndpointWithOwner("new-record-1.test-zone.example.org", "new-loadbalancer-1.lb.com", endpoint.RecordTypeCNAME, "owner"), - newEndpointWithOwnerAndOwnedRecord("new-record-1.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "new-record-1.test-zone.example.org"), - newEndpointWithOwnerAndOwnedRecord("cname-new-record-1.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "new-record-1.test-zone.example.org"), + newEndpointWithOwner("new-record-1.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""), + newEndpointWithOwner("cname-new-record-1.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""), newEndpointWithOwner("example", "new-loadbalancer-1.lb.com", endpoint.RecordTypeCNAME, "owner"), - newEndpointWithOwnerAndOwnedRecord("example", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "example"), - newEndpointWithOwnerAndOwnedRecord("cname-example", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "example"), + newEndpointWithOwner("example", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""), + newEndpointWithOwner("cname-example", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""), }, Delete: []*endpoint.Endpoint{ newEndpointWithOwner("foobar.test-zone.example.org", "foobar.loadbalancer.com", endpoint.RecordTypeCNAME, "owner"), - newEndpointWithOwnerAndOwnedRecord("foobar.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "foobar.test-zone.example.org"), - newEndpointWithOwnerAndOwnedRecord("cname-foobar.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, "", "foobar.test-zone.example.org"), + newEndpointWithOwner("foobar.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""), + newEndpointWithOwner("cname-foobar.test-zone.example.org", "\"heritage=external-dns,external-dns/owner=owner\"", endpoint.RecordTypeTXT, ""), }, UpdateNew: []*endpoint.Endpoint{}, UpdateOld: []*endpoint.Endpoint{}, @@ -1165,17 +1153,13 @@ func TestGenerateTXT(t *testing.T) { DNSName: "foo.test-zone.example.org", Targets: endpoint.Targets{"\"heritage=external-dns,external-dns/owner=owner\""}, RecordType: endpoint.RecordTypeTXT, - Labels: map[string]string{ - endpoint.OwnedRecordLabelKey: "foo.test-zone.example.org", - }, + Labels: map[string]string{}, }, { DNSName: "cname-foo.test-zone.example.org", Targets: endpoint.Targets{"\"heritage=external-dns,external-dns/owner=owner\""}, RecordType: endpoint.RecordTypeTXT, - Labels: map[string]string{ - endpoint.OwnedRecordLabelKey: "foo.test-zone.example.org", - }, + Labels: map[string]string{}, }, } p := inmemory.NewInMemoryProvider() @@ -1212,10 +1196,6 @@ func newEndpointWithOwner(dnsName, target, recordType, ownerID string) *endpoint return newEndpointWithOwnerAndLabels(dnsName, target, recordType, ownerID, nil) } -func newEndpointWithOwnerAndOwnedRecord(dnsName, target, recordType, ownerID, ownedRecord string) *endpoint.Endpoint { - return newEndpointWithOwnerAndLabels(dnsName, target, recordType, ownerID, endpoint.Labels{endpoint.OwnedRecordLabelKey: ownedRecord}) -} - func newEndpointWithOwnerAndLabels(dnsName, target, recordType, ownerID string, labels endpoint.Labels) *endpoint.Endpoint { e := endpoint.NewEndpoint(dnsName, recordType, target) e.Labels[endpoint.OwnerLabelKey] = ownerID