Repository: kubernetes-sigs/external-dns

Issue:
Increase Cloudflare Test Coverage
              The current pull request covers a few more edge cases to the unit tests framework.

The in master version of `cloudflare.go` is 75%, while code coverage is not an indication of things, would you mind try to increase a code coverage for this file, it would be very helpful? There are quite few logic flows not covered by any tests cases.

You could try run `make cover-html`

![Screenshot 2025-02-21 at 17 14 30](https://github.com/user-attachments/assets/579551fb-c48a-4b82-9fab-c0167b81a55f)
![Screenshot 2025-02-21 at 17 14 44](https://github.com/user-attachments/assets/14a7212d-b7d8-4040-a0bb-383c7f715314)
![Screenshot 2025-02-21 at 17 14 51](https://github.com/user-attachments/assets/de67ce72-4721-4304-872a-63d500a36959)
![Screenshot 2025-02-21 at 17 14 58](https://github.com/user-attachments/assets/fadc13e1-4d32-4b82-b7f4-100ca099b7f2)

_Originally posted by @ivankatliarchuk in https://github.com/kubernetes-sigs/external-dns/issues/5054#issuecomment-2675122026_
            

Hints from issue comments:
@mloiseleur: /kind cleanup@ivankatliarchuk: /help
/good-first-issue@k8s-ci-robot: @ivankatliarchuk: 
	This request has been marked as suitable for new contributors.

### Guidelines
Please ensure that the issue body includes answers to the following questions:
- Why are we solving this issue?
- To address this issue, are there any code changes? If there are code changes, what needs to be done in the code and what places can the assignee treat as reference points?
- Does this issue have zero to low barrier of entry?
- How can the assignee reach out to you for help?


For more details on the requirements of such an issue, please see [here](https://git.k8s.io/community/contributors/guide/help-wanted.md#good-first-issue) and ensure that they are met.

If this request no longer meets these requirements, the label can be removed
by commenting with the `/remove-good-first-issue` command.


<details>

In response to [this](https://github.com/kubernetes-sigs/external-dns/issues/5118):

>/help
>/good-first-issue


Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository.
</details>

Solution patch:
diff --git a/.github/renovate-config.js b/.github/renovate-config.js
index d21caf1c..9d3803f4 100644
--- a/.github/renovate-config.js
+++ b/.github/renovate-config.js
@@ -52,6 +52,14 @@ module.exports = {
       "depNameTemplate": "kubernetes-sigs/external-dns",
       "datasourceTemplate": "github-releases",
       "versioningTemplate": "semver"
-    }
+    },
+    {
+      "customType": "regex",
+      "fileMatch": [".*"],
+      "matchStrings": [
+        "datasource=(?<datasource>.*?) depName=(?<depName>.*?)( versioning=(?<versioning>.*?))?\\s.*?_VERSION=(?<currentValue>.*)\\s"
+      ],
+      "versioningTemplate": "{{#if versioning}}{{{versioning}}}{{else}}semver{{/if}}",
+    },
   ]
 };
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 030ad588..73f0c926 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -27,6 +27,7 @@ jobs:
       uses: actions/setup-go@v5
       with:
         go-version-file: go.mod
+        check-latest: true
       id: go
 
     - name: Install CI
@@ -47,3 +48,4 @@ jobs:
       with:
         path-to-profile: profile.cov
       if: github.actor != 'nektos/act'
+      continue-on-error: true
diff --git a/.github/workflows/dependency-update.yaml b/.github/workflows/dependency-update.yaml
index 18c394c0..095331b0 100644
--- a/.github/workflows/dependency-update.yaml
+++ b/.github/workflows/dependency-update.yaml
@@ -17,7 +17,7 @@ jobs:
         uses: actions/checkout@v4.2.2
       # https://github.com/renovatebot/github-action
       - name: self-hosted renovate
-        uses: renovatebot/github-action@v41.0.17
+        uses: renovatebot/github-action@v41.0.20
         with:
           # https://docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication
           token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml
index 1a21b3db..52e23f50 100644
--- a/.github/workflows/docs.yaml
+++ b/.github/workflows/docs.yaml
@@ -19,7 +19,7 @@ jobs:
         with:
           fetch-depth: 0
 
-      - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
+      - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
         with:
           python-version: "3.12"
           cache: "pip"
diff --git a/.github/workflows/json-yaml-validate.yml b/.github/workflows/json-yaml-validate.yml
index 8aeb600c..7cf8d250 100644
--- a/.github/workflows/json-yaml-validate.yml
+++ b/.github/workflows/json-yaml-validate.yml
@@ -17,7 +17,7 @@ jobs:
       - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
 
       - name: json-yaml-validate
-        uses: GrantBirki/json-yaml-validate@v3.2.1
+        uses: GrantBirki/json-yaml-validate@v3.3.0
         with:
           comment: "true" # enable comment mode
           yaml_exclude_regex: "(charts/external-dns/templates.*|mkdocs.yml)"
diff --git a/.github/workflows/lint-test-chart.yaml b/.github/workflows/lint-test-chart.yaml
index 14514f69..1412a868 100644
--- a/.github/workflows/lint-test-chart.yaml
+++ b/.github/workflows/lint-test-chart.yaml
@@ -78,7 +78,7 @@ jobs:
         run: ah lint --kind helm || exit 1
 
       - name: Install Python
-        uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
+        uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
         with:
           token: ${{ github.token }}
           python-version: "3.x"
diff --git a/.gitignore b/.gitignore
index 3907ba75..29561b90 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,6 +15,7 @@
 
 # Vscode files
 .vscode
+__debug_*
 
 # This is where the result of the go build goes
 /output*/
diff --git a/.golangci.yml b/.golangci.yml
index 99b3dde0..17669081 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -1,7 +1,8 @@
+# https://golangci-lint.run/usage/configuration/
 version: "2"
 linters:
   default: none
-  enable:
+  enable: # golangci-lint help linters
     - dogsled
     - goprintffuncname
     - govet
@@ -13,6 +14,9 @@ linters:
     - unconvert
     - unused
     - whitespace
+    - predeclared # Find code that shadows one of Go's predeclared identifiers
+    - sloglint # Ensure consistent code style when using log/slog
+    - asciicheck  # Checks that all code identifiers does not have non-ASCII symbols in the name
   settings:
     exhaustive:
       default-signifies-exhaustive: false
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 723484a7..785a6027 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -12,6 +12,8 @@ We have full documentation on how to get started contributing here:
 - [Kubernetes Contributor Guide](https://git.k8s.io/community/contributors/guide) - Main contributor documentation, or you can just jump directly to the [contributing section](https://git.k8s.io/community/contributors/guide#contributing)
 - [Contributor Cheat Sheet](https://git.k8s.io/community/contributors/guide/contributor-cheatsheet) - Common resources for existing developers
 
+This project follows the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification on PR title. The explicit commit history is used, among other things, to provide a readable changelog in release notes.
+
 ## Mentorship
 
 - [Mentoring Initiatives](https://git.k8s.io/community/mentoring) - We have a diverse set of mentorship programs available that are always looking for volunteers!
diff --git a/Makefile b/Makefile
index 8b0bd52f..74ee9873 100644
--- a/Makefile
+++ b/Makefile
@@ -24,28 +24,26 @@ cover-html: cover
 	@go tool cover -html=cover.out
 
 #? controller-gen: download controller-gen if necessary
-controller-gen:
+controller-gen-install:
+	@scripts/install-tools.sh --generator
 ifeq (, $(shell which controller-gen))
-	@{ \
-	set -e ;\
-	go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.15.0 ;\
-	}
 CONTROLLER_GEN=$(GOBIN)/controller-gen
 else
 CONTROLLER_GEN=$(shell which controller-gen)
 endif
 
-#? golangci-lint: Install golangci-lint tool
-golangci-lint:
-	@command -v golangci-lint > /dev/null || curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.0.2
+#? controller-gen-install: download controller-gen if necessary
+controller-gen-install:
+	@scripts/install-tools.sh --generator
 
-#? golangci-lint-verify: Verify golangci-lint configuration
-golangci-lint-verify: golangci-lint
-	@golangci-lint config verify
+#? golangci-lint-install: Install golangci-lint tool
+golangci-lint-install:
+	@scripts/install-tools.sh --golangci
 
 #? go-lint: Run the golangci-lint tool
 .PHONY: go-lint
-go-lint: golangci-lint
+go-lint: golangci-lint-install
+	golangci-lint config verify
 	gofmt -l -s -w .
 	golangci-lint run --timeout=30m --fix ./...
 
@@ -71,7 +69,7 @@ lint: licensecheck go-lint oas-lint
 
 #? crd: Generates CRD using controller-gen
 .PHONY: crd
-crd: controller-gen
+crd: controller-gen-install
 	${CONTROLLER_GEN} crd:crdVersions=v1 paths="./endpoint/..." output:crd:stdout > docs/contributing/crd-source/crd-manifest.yaml
 
 #? test: The verify target runs tasks similar to the CI tasks, but without code coverage
@@ -203,3 +201,7 @@ helm-template:
 helm-lint:
 	scripts/helm-tools.sh --schema
 	scripts/helm-tools.sh --docs
+
+.PHONY: go-dependency
+go-dependency: ## Dependency maintanance
+	go mod tidy
diff --git a/README.md b/README.md
index 4322a364..45841e9a 100644
--- a/README.md
+++ b/README.md
@@ -88,7 +88,7 @@ Known providers using webhooks:
 | --------------------- | -------------------------------------------------------------------- |
 | Abion                 | https://github.com/abiondevelopment/external-dns-webhook-abion       |
 | Adguard Home Provider | https://github.com/muhlba91/external-dns-provider-adguard            |
-| Anexia                | https://github.com/ProbstenHias/external-dns-anexia-webhook          |
+| Anexia                | https://github.com/anexia/k8s-external-dns-webhook                   |
 | Bizfly Cloud          | https://github.com/bizflycloud/external-dns-bizflycloud-webhook      |
 | ClouDNS               | https://github.com/rwunderer/external-dns-cloudns-webhook            |
 | Dreamhost             | https://github.com/asymingt/external-dns-dreamhost-webhook           |
diff --git a/charts/external-dns/CHANGELOG.md b/charts/external-dns/CHANGELOG.md
index 3a455220..2f909eb8 100644
--- a/charts/external-dns/CHANGELOG.md
+++ b/charts/external-dns/CHANGELOG.md
@@ -20,12 +20,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Changed
 
-- Set defaults for `automountServiceAccountToken` and `serviceAccount.automountServiceAccountToken` to `true` in helm chart values ([#5207](https://github.com/kubernetes-sigs/external-dns/pull/5207)) _@t3mi_
+- Allow extraArgs to also be a map enabling overrides of individual values ([#5293](https://github.com/kubernetes-sigs/external-dns/pull/5293)) _@frittentheke
 
 ### Fixed
 
-- Add missing types in the schema for empty values ([#5228](https://github.com/kubernetes-sigs/external-dns/pull/5228)) _@ivankatliarchuk_
-- Add missing types in the schema for empty values ([#5207](https://github.com/kubernetes-sigs/external-dns/pull/5207)) _@t3mi_
+- Fixed wrong type definitions for webhook probes. ([#5297](https://github.com/kubernetes-sigs/external-dns/pull/5297)) _@semnell_
+
+## [v1.16.1] - 2025-04-10
+
+### Changed
+
+- Set defaults for `automountServiceAccountToken` and `serviceAccount.automountServiceAccountToken` to `true` in Helm chart values. ([#5207](https://github.com/kubernetes-sigs/external-dns/pull/5207)) _@t3mi_
+
+### Fixed
+
+- Correctly handles 'txtPrefix' and 'txtSuffix' arguments when both are provided. ([#5250](https://github.com/kubernetes-sigs/external-dns/pull/5250)) _@ivankatliarchuk_
+- Add missing types in the schema for empty values. ([#5228](https://github.com/kubernetes-sigs/external-dns/pull/5228)) _@ivankatliarchuk_
+- Add missing types in the schema for empty values. ([#5207](https://github.com/kubernetes-sigs/external-dns/pull/5207)) _@t3mi_
 
 ## [v1.16.0] - 2025-03-20
 
@@ -38,7 +49,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 ### Changed
 
 - Regenerate JSON schema with `helm-values-schema-json' plugin. ([#5075](https://github.com/kubernetes-sigs/external-dns/pull/5075)) _@ivankatliarchuk_
-- Update _ExternalDNS_ OCI image version to [v0.16.1](https://github.com/kubernetes-sigs/external-dns/releases/tag/v0.16.1). ([#xxxx](https://github.com/kubernetes-sigs/external-dns/pull/xxxx)) _@stevehipwell_
+- Update _ExternalDNS_ OCI image version to [v0.16.1](https://github.com/kubernetes-sigs/external-dns/releases/tag/v0.16.1). ([#5201](https://github.com/kubernetes-sigs/external-dns/pull/5201)) _@stevehipwell_
 
 ## [v1.15.2] - 2025-02-14
 
@@ -250,6 +261,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 RELEASE LINKS
 -->
 [UNRELEASED]: https://github.com/kubernetes-sigs/external-dns/tree/master/charts/external-dns
+[v1.16.1]: https://github.com/kubernetes-sigs/external-dns/releases/tag/external-dns-helm-chart-1.16.1
 [v1.16.0]: https://github.com/kubernetes-sigs/external-dns/releases/tag/external-dns-helm-chart-1.16.0
 [v1.15.2]: https://github.com/kubernetes-sigs/external-dns/releases/tag/external-dns-helm-chart-1.15.2
 [v1.15.1]: https://github.com/kubernetes-sigs/external-dns/releases/tag/external-dns-helm-chart-1.15.1
diff --git a/charts/external-dns/Chart.yaml b/charts/external-dns/Chart.yaml
index 4644c549..1944e2ab 100644
--- a/charts/external-dns/Chart.yaml
+++ b/charts/external-dns/Chart.yaml
@@ -2,7 +2,7 @@ apiVersion: v2
 name: external-dns
 description: ExternalDNS synchronizes exposed Kubernetes Services and Ingresses with DNS providers.
 type: application
-version: 1.16.0
+version: 1.16.1
 appVersion: 0.16.1
 keywords:
   - kubernetes
@@ -20,13 +20,9 @@ maintainers:
     email: steve.hipwell@gmail.com
 annotations:
   artifacthub.io/changes: |
-    - kind: added
-      description: "Add helm testing framework `helm plugin unittest`."
-    - kind: added
-      description: "Add ability to generate schema with `helm plugin schema`."
-    - kind: added
-      description: "Add `docs/contributing/dev-guide.md#helm-values` guide."
     - kind: changed
-      description: "Regenerate JSON schema with `helm-values-schema-json' plugin."
-    - kind: changed
-      description: "Update _ExternalDNS_ OCI image version to [v0.16.1](https://github.com/kubernetes-sigs/external-dns/releases/tag/v0.16.1)."
+      description: "Set defaults for `automountServiceAccountToken` and `serviceAccount.automountServiceAccountToken` to `true` in Helm chart values."
+    - kind: fixed
+      description: "Correctly handles 'txtPrefix' and 'txtSuffix' arguments when both are provided."
+    - kind: fixed
+      description: "Add missing types in the schema for empty values."
diff --git a/charts/external-dns/README.md b/charts/external-dns/README.md
index 0552b6cc..6126679b 100644
--- a/charts/external-dns/README.md
+++ b/charts/external-dns/README.md
@@ -1,6 +1,6 @@
 # external-dns
 
-![Version: 1.16.0](https://img.shields.io/badge/Version-1.16.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.16.1](https://img.shields.io/badge/AppVersion-0.16.1-informational?style=flat-square)
+![Version: 1.16.1](https://img.shields.io/badge/Version-1.16.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.16.1](https://img.shields.io/badge/AppVersion-0.16.1-informational?style=flat-square)
 
 ExternalDNS synchronizes exposed Kubernetes Services and Ingresses with DNS providers.
 
@@ -27,7 +27,7 @@ helm repo add external-dns https://kubernetes-sigs.github.io/external-dns/
 After you've installed the repo you can install the chart.
 
 ```shell
-helm upgrade --install external-dns external-dns/external-dns --version 1.16.0
+helm upgrade --install external-dns external-dns/external-dns --version 1.16.1
 ```
 
 ## Providers
@@ -104,7 +104,7 @@ If `namespaced` is set to `true`, please ensure that `sources` my only contains
 | enabled | bool | `nil` | No effect - reserved for use in sub-charting. |
 | env | list | `[]` | [Environment variables](https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/) for the `external-dns` container. |
 | excludeDomains | list | `[]` | Intentionally exclude domains from being managed. |
-| extraArgs | list | `[]` | Extra arguments to provide to _ExternalDNS_. |
+| extraArgs | object | `{}` | Extra arguments to provide to _ExternalDNS_. An array or map can be used, with maps allowing for value overrides; maps also support slice values to use the same arg multiple times. |
 | extraContainers | object | `{}` | Extra containers to add to the `Deployment`. |
 | extraVolumeMounts | list | `[]` | Extra [volume mounts](https://kubernetes.io/docs/concepts/storage/volumes/) for the `external-dns` container. |
 | extraVolumes | list | `[]` | Extra [volumes](https://kubernetes.io/docs/concepts/storage/volumes/) for the `Pod`. |
diff --git a/charts/external-dns/templates/deployment.yaml b/charts/external-dns/templates/deployment.yaml
index ae60cffc..f0c967a3 100644
--- a/charts/external-dns/templates/deployment.yaml
+++ b/charts/external-dns/templates/deployment.yaml
@@ -100,10 +100,12 @@ spec:
             {{- if .Values.txtOwnerId }}
             - --txt-owner-id={{ .Values.txtOwnerId }}
             {{- end }}
+            {{- if and .Values.txtPrefix .Values.txtSuffix }}
+            {{- fail (printf "'txtPrefix' and 'txtSuffix' are mutually exclusive") }}
+            {{- end }}
             {{- if .Values.txtPrefix }}
             - --txt-prefix={{ .Values.txtPrefix }}
-            {{- end }}
-            {{- if and (eq .Values.txtPrefix "") (ne .Values.txtSuffix "") }}
+            {{- else if .Values.txtSuffix }}
             - --txt-suffix={{ .Values.txtSuffix }}
             {{- end }}
             {{- if .Values.namespaced }}
@@ -122,9 +124,26 @@ spec:
             - --managed-record-types={{ . }}
             {{- end }}
             - --provider={{ $providerName }}
-          {{- range .Values.extraArgs }}
+            {{- if kindIs "map" .Values.extraArgs }}
+            {{- range $key, $value := .Values.extraArgs }}
+            {{- if not (kindIs "invalid" $value) }}
+            {{- if kindIs "slice" $value }}
+            {{- range $value }}
+            - --{{ $key }}={{ tpl (. | toString) $ }}
+            {{- end }}
+            {{- else }}
+            - --{{ $key }}={{ tpl ($value | toString) $ }}
+            {{- end }}
+            {{- else }}
+            - --{{ $key }}
+            {{- end }}
+            {{- end }}
+            {{- end }}
+            {{- if kindIs "slice" .Values.extraArgs }}
+            {{- range .Values.extraArgs }}
             - {{ tpl . $ }}
-          {{- end }}
+            {{- end }}
+            {{- end }}
           ports:
             - name: http
               protocol: TCP
diff --git a/charts/external-dns/values.schema.json b/charts/external-dns/values.schema.json
index d5e64143..72143d64 100644
--- a/charts/external-dns/values.schema.json
+++ b/charts/external-dns/values.schema.json
@@ -64,9 +64,11 @@
       "items": {
         "type": "string"
       },
+      "properties": {},
       "type": [
         "array",
-        "null"
+        "null",
+        "object"
       ],
       "uniqueItems": true
     },
@@ -308,30 +310,51 @@
             "livenessProbe": {
               "properties": {
                 "failureThreshold": {
-                  "type": "integer"
+                  "type": [
+                    "integer",
+                    "null"
+                  ]
                 },
                 "httpGet": {
                   "properties": {
                     "path": {
-                      "type": "string"
+                      "type": [
+                        "string",
+                        "null"
+                      ]
                     },
                     "port": {
-                      "type": "string"
+                      "type": [
+                        "integer",
+                        "string"
+                      ]
                     }
                   },
                   "type": "object"
                 },
                 "initialDelaySeconds": {
-                  "type": "integer"
+                  "type": [
+                    "integer",
+                    "null"
+                  ]
                 },
                 "periodSeconds": {
-                  "type": "integer"
+                  "type": [
+                    "integer",
+                    "null"
+                  ]
                 },
                 "successThreshold": {
-                  "type": "integer"
+                  "type": [
+                    "integer",
+                    "null"
+                  ]
                 },
                 "timeoutSeconds": {
-                  "type": "integer"
+                  "type": [
+                    "integer",
+                    "null"
+                  ]
                 }
               },
               "type": "object"
@@ -339,30 +362,51 @@
             "readinessProbe": {
               "properties": {
                 "failureThreshold": {
-                  "type": "integer"
+                  "type": [
+                    "integer",
+                    "null"
+                  ]
                 },
                 "httpGet": {
                   "properties": {
                     "path": {
-                      "type": "string"
+                      "type": [
+                        "string",
+                        "null"
+                      ]
                     },
                     "port": {
-                      "type": "string"
+                      "type": [
+                        "integer",
+                        "string"
+                      ]
                     }
                   },
                   "type": "object"
                 },
                 "initialDelaySeconds": {
-                  "type": "integer"
+                  "type": [
+                    "integer",
+                    "null"
+                  ]
                 },
                 "periodSeconds": {
-                  "type": "integer"
+                  "type": [
+                    "integer",
+                    "null"
+                  ]
                 },
                 "successThreshold": {
-                  "type": "integer"
+                  "type": [
+                    "integer",
+                    "null"
+                  ]
                 },
                 "timeoutSeconds": {
-                  "type": "integer"
+                  "type": [
+                    "integer",
+                    "null"
+                  ]
                 }
               },
               "type": "object"
diff --git a/charts/external-dns/values.yaml b/charts/external-dns/values.yaml
index c1acf0c4..0e85050a 100644
--- a/charts/external-dns/values.yaml
+++ b/charts/external-dns/values.yaml
@@ -263,24 +263,24 @@ provider:  # @schema type: [object, string];
     # @default -- See _values.yaml_
     livenessProbe:
       httpGet:
-        path: /healthz
-        port: http-webhook
-      initialDelaySeconds: 10
-      periodSeconds: 10
-      timeoutSeconds: 5
-      failureThreshold: 2
-      successThreshold: 1
+        path: /healthz  # @schema type:[string, null]; default: null
+        port: http-webhook  # @schema type:[integer,string]; default: string
+      initialDelaySeconds: 10  # @schema type:[integer, null]; default: null
+      periodSeconds: 10  # @schema type:[integer, null]; default: null
+      timeoutSeconds: 5  # @schema type:[integer, null]; default: null
+      failureThreshold: 2  # @schema type:[integer, null]; default: null
+      successThreshold: 1  # @schema type:[integer, null]; default: null
     # -- [Readiness probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) configuration for the `webhook` container.
     # @default -- See _values.yaml_
     readinessProbe:
       httpGet:
-        path: /healthz
-        port: http-webhook
-      initialDelaySeconds: 5
-      periodSeconds: 10
-      timeoutSeconds: 5
-      failureThreshold: 6
-      successThreshold: 1
+        path: /healthz  # @schema type:[string, null]; default: null
+        port: http-webhook  # @schema type:[integer,string]; default: string
+      initialDelaySeconds: 5  # @schema type:[integer, null]; default: null
+      periodSeconds: 10  # @schema type:[integer, null]; default: null
+      timeoutSeconds: 5  # @schema type:[integer, null]; default: null
+      failureThreshold: 6  # @schema type:[integer, null]; default: null
+      successThreshold: 1  # @schema type:[integer, null]; default: null
     service:
       # -- Webhook exposed HTTP port for the service.
       port: 8080
@@ -296,7 +296,8 @@ provider:  # @schema type: [object, string];
       relabelings: []
 
 # -- Extra arguments to provide to _ExternalDNS_.
-extraArgs: []  # @schema type: [array, null]; item: string; uniqueItems: true;
+# An array or map can be used, with maps allowing for value overrides; maps also support slice values to use the same arg multiple times.
+extraArgs: {}  # @schema type: [array, null, object]; item: string; uniqueItems: true;
 
 secretConfiguration:
   # -- If `true`, create a `Secret` to store sensitive provider configuration (**DEPRECATED**).
diff --git a/docs/flags.md b/docs/flags.md
index 055b9a0a..06af5277 100644
--- a/docs/flags.md
+++ b/docs/flags.md
@@ -17,39 +17,40 @@
 | `--cf-password=""` | The password to log into the cloud foundry API |
 | `--gloo-namespace=gloo-system` | The Gloo Proxy namespace; specify multiple times for multiple namespaces. (default: gloo-system) |
 | `--skipper-routegroup-groupversion="zalando.org/v1"` | The resource version for skipper routegroup |
-| `--source=source` | The resource types that are queried for endpoints; specify multiple times for multiple sources (required, options: service, ingress, node, pod, fake, connector, gateway-httproute, gateway-grpcroute, gateway-tlsroute, gateway-tcproute, gateway-udproute, istio-gateway, istio-virtualservice, cloudfoundry, contour-httpproxy, gloo-proxy, crd, empty, skipper-routegroup, openshift-route, ambassador-host, kong-tcpingress, f5-virtualserver, f5-transportserver, traefik-proxy) |
-| `--openshift-router-name=OPENSHIFT-ROUTER-NAME` | if source is openshift-route then you can pass the ingress controller name. Based on this name external-dns will select the respective router from the route status and map that routerCanonicalHostname to the route host while creating a CNAME record. |
-| `--namespace=""` | Limit resources queried for endpoints to a specific namespace (default: all namespaces) |
+| `--[no-]always-publish-not-ready-addresses` | Always publish also not ready addresses for headless services (optional) |
 | `--annotation-filter=""` | Filter resources queried for endpoints by annotation, using label selector semantics |
-| `--label-filter=""` | Filter resources queried for endpoints by label selector; currently supported by source types crd, gateway-httproute, gateway-grpcroute, gateway-tlsroute, gateway-tcproute, gateway-udproute, ingress, node, openshift-route, service and ambassador-host |
-| `--ingress-class=INGRESS-CLASS` | Require an Ingress to have this class name (defaults to any class; specify multiple times to allow more than one class) |
-| `--fqdn-template=""` | A templated string that's used to generate DNS names from sources that don't define a hostname themselves, or to add a hostname suffix when paired with the fake source (optional). Accepts comma separated list for multiple global FQDN. |
 | `--[no-]combine-fqdn-annotation` | Combine FQDN template and Annotations instead of overwriting |
-| `--[no-]ignore-hostname-annotation` | Ignore hostname annotation when generating DNS names, valid only when --fqdn-template is set (default: false) |
-| `--[no-]ignore-non-host-network-pods` | Ignore pods not running on host network when using pod source (default: true) |
-| `--[no-]ignore-ingress-tls-spec` | Ignore the spec.tls section in Ingress resources (default: false) |
+| `--compatibility=` | Process annotation semantics from legacy implementations (optional, options: mate, molecule, kops-dns-controller) |
+| `--connector-source-server="localhost:8080"` | The server to connect for connector source, valid only when using connector source |
+| `--crd-source-apiversion="externaldns.k8s.io/v1alpha1"` | API version of the CRD for crd source, e.g. `externaldns.k8s.io/v1alpha1`, valid only when using crd source |
+| `--crd-source-kind="DNSEndpoint"` | Kind of the CRD for the crd source in API group and version specified by crd-source-apiversion |
+| `--default-targets=DEFAULT-TARGETS` | Set globally default host/IP that will apply as a target instead of source addresses. Specify multiple times for multiple targets (optional) |
+| `--exclude-record-types=EXCLUDE-RECORD-TYPES` | Record types to exclude from management; specify multiple times to exclude many; (optional) |
+| `--exclude-target-net=EXCLUDE-TARGET-NET` | Exclude target nets (optional) |
+| `--[no-]exclude-unschedulable` | Exclude nodes that are considered unschedulable (default: true) |
+| `--[no-]expose-internal-ipv6` | When using the node source, expose internal IPv6 addresses (optional). Default is true. |
+| `--fqdn-template=""` | A templated string that's used to generate DNS names from sources that don't define a hostname themselves, or to add a hostname suffix when paired with the fake source (optional). Accepts comma separated list for multiple global FQDN. |
+| `--gateway-label-filter=GATEWAY-LABEL-FILTER` | Filter Gateways of Route endpoints via label selector (default: all gateways) |
 | `--gateway-name=GATEWAY-NAME` | Limit Gateways of Route endpoints to a specific name (default: all names) |
 | `--gateway-namespace=GATEWAY-NAMESPACE` | Limit Gateways of Route endpoints to a specific namespace (default: all namespaces) |
-| `--gateway-label-filter=GATEWAY-LABEL-FILTER` | Filter Gateways of Route endpoints via label selector (default: all gateways) |
-| `--compatibility=` | Process annotation semantics from legacy implementations (optional, options: mate, molecule, kops-dns-controller) |
+| `--[no-]ignore-hostname-annotation` | Ignore hostname annotation when generating DNS names, valid only when --fqdn-template is set (default: false) |
 | `--[no-]ignore-ingress-rules-spec` | Ignore the spec.rules section in Ingress resources (default: false) |
+| `--[no-]ignore-ingress-tls-spec` | Ignore the spec.tls section in Ingress resources (default: false) |
+| `--[no-]ignore-non-host-network-pods` | Ignore pods not running on host network when using pod source (default: true) |
+| `--ingress-class=INGRESS-CLASS` | Require an Ingress to have this class name (defaults to any class; specify multiple times to allow more than one class) |
+| `--label-filter=""` | Filter resources queried for endpoints by label selector; currently supported by source types crd, gateway-httproute, gateway-grpcroute, gateway-tlsroute, gateway-tcproute, gateway-udproute, ingress, node, openshift-route, service and ambassador-host |
+| `--managed-record-types=A...` | Record types to manage; specify multiple times to include many; (default: A,AAAA,CNAME) (supported records: A, AAAA, CNAME, NS, SRV, TXT) |
+| `--namespace=""` | Limit resources queried for endpoints to a specific namespace (default: all namespaces) |
+| `--nat64-networks=NAT64-NETWORKS` | Adding an A record for each AAAA record in NAT64-enabled networks; specify multiple times for multiple possible nets (optional) |
+| `--openshift-router-name=OPENSHIFT-ROUTER-NAME` | if source is openshift-route then you can pass the ingress controller name. Based on this name external-dns will select the respective router from the route status and map that routerCanonicalHostname to the route host while creating a CNAME record. |
 | `--pod-source-domain=""` | Domain to use for pods records (optional) |
-| `--[no-]publish-internal-services` | Allow external-dns to publish DNS records for ClusterIP services (optional) |
 | `--[no-]publish-host-ip` | Allow external-dns to publish host-ip for headless services (optional) |
-| `--[no-]always-publish-not-ready-addresses` | Always publish also not ready addresses for headless services (optional) |
-| `--connector-source-server="localhost:8080"` | The server to connect for connector source, valid only when using connector source |
-| `--crd-source-apiversion="externaldns.k8s.io/v1alpha1"` | API version of the CRD for crd source, e.g. `externaldns.k8s.io/v1alpha1`, valid only when using crd source |
-| `--crd-source-kind="DNSEndpoint"` | Kind of the CRD for the crd source in API group and version specified by crd-source-apiversion |
+| `--[no-]publish-internal-services` | Allow external-dns to publish DNS records for ClusterIP services (optional) |
 | `--service-type-filter=SERVICE-TYPE-FILTER` | The service types to take care about (default: all, expected: ClusterIP, NodePort, LoadBalancer or ExternalName) |
-| `--managed-record-types=A...` | Record types to manage; specify multiple times to include many; (default: A, AAAA, CNAME) (supported records: A, AAAA, CNAME, NS, SRV, TXT) |
-| `--exclude-record-types=EXCLUDE-RECORD-TYPES` | Record types to exclude from management; specify multiple times to exclude many; (optional) |
-| `--default-targets=DEFAULT-TARGETS` | Set globally default host/IP that will apply as a target instead of source addresses. Specify multiple times for multiple targets (optional) |
+| `--source=source` | The resource types that are queried for endpoints; specify multiple times for multiple sources (required, options: service, ingress, node, pod, fake, connector, gateway-httproute, gateway-grpcroute, gateway-tlsroute, gateway-tcproute, gateway-udproute, istio-gateway, istio-virtualservice, cloudfoundry, contour-httpproxy, gloo-proxy, crd, empty, skipper-routegroup, openshift-route, ambassador-host, kong-tcpingress, f5-virtualserver, f5-transportserver, traefik-proxy) |
 | `--target-net-filter=TARGET-NET-FILTER` | Limit possible targets by a net filter; specify multiple times for multiple possible nets (optional) |
-| `--exclude-target-net=EXCLUDE-TARGET-NET` | Exclude target nets (optional) |
 | `--[no-]traefik-disable-legacy` | Disable listeners on Resources under the traefik.containo.us API Group |
 | `--[no-]traefik-disable-new` | Disable listeners on Resources under the traefik.io API Group |
-| `--nat64-networks=NAT64-NETWORKS` | Adding an A record for each AAAA record in NAT64-enabled networks; specify multiple times for multiple possible nets (optional) |
-| `--[no-]expose-internal-ipv6` | When using the node source, expose internal IPv6 addresses (optional). Default is true. |
 | `--provider=provider` | The DNS provider where the DNS records will be created (required, options: akamai, alibabacloud, aws, aws-sd, azure, azure-dns, azure-private-dns, civo, cloudflare, coredns, digitalocean, dnsimple, exoscale, gandi, godaddy, google, ibmcloud, inmemory, linode, ns1, oci, ovh, pdns, pihole, plural, rfc2136, scaleway, skydns, tencentcloud, transip, ultradns, webhook) |
 | `--provider-cache-time=0s` | The time to cache the DNS provider record list requests. |
 | `--domain-filter=` | Limit possible target zones by a domain suffix; specify multiple times for multiple domains (optional) |
@@ -132,7 +133,7 @@
 | `--exoscale-apisecret=""` | Provide your API Secret for the Exoscale provider |
 | `--rfc2136-host=` | When using the RFC2136 provider, specify the host of the DNS server (optionally specify multiple times when when using --rfc2136-load-balancing-strategy) |
 | `--rfc2136-port=0` | When using the RFC2136 provider, specify the port of the DNS server |
-| `--rfc2136-zone=RFC2136-ZONE` | When using the RFC2136 provider, specify zone entries of the DNS server to use |
+| `--rfc2136-zone=RFC2136-ZONE` | When using the RFC2136 provider, specify zone entry of the DNS server to use (can be specified multiple times) |
 | `--[no-]rfc2136-create-ptr` | When using the RFC2136 provider, enable PTR management |
 | `--[no-]rfc2136-insecure` | When using the RFC2136 provider, specify whether to attach TSIG or not (default: false, requires --rfc2136-tsig-keyname and rfc2136-tsig-secret) |
 | `--rfc2136-tsig-keyname=""` | When using the RFC2136 provider, specify the TSIG key to attached to DNS messages (required when --rfc2136-insecure=false) |
diff --git a/docs/providers.md b/docs/providers.md
new file mode 100644
index 00000000..4a9511aa
--- /dev/null
+++ b/docs/providers.md
@@ -0,0 +1,35 @@
+# Providers
+
+Provider supported configurations
+
+| Provider Name | Zone Cache | Dry Run | Default TTL (seconds) |
+|:--------------|:-----------|:--------|:----------------------|
+| Akamai        | n/a        | yes     | 600                   |
+| AlibabaCloud  | n/a        | yes     | 600                   |
+| AWS           | yes        | yes     | 300                   |
+| AWSSD         | n/a        | yes     | 300                   |
+| Azure         | yes        | yes     | 300                   |
+| Civo          | n/a        | yes     | n/a                   |
+| Cloudflare    | n/a        | yes     | 1                     |
+| CoreDNS       | n/a        | yes     | n/a                   |
+| DigitalOcean  | n/a        | yes     | 300                   |
+| DNSSimple     | n/a        | yes     | 3600                  |
+| Exoscale      | n/a        | yes     | n/a                   |
+| Gandi         | n/a        | no      | 600                   |
+| GoDaddy       | n/a        | yes     | 600                   |
+| Google GCP    | n/a        | yes     | 300                   |
+| IBMCloud      | n/a        | yes     | 1                     |
+| InMemory      | n/a        | n/a     | n/a                   |
+| Linode        | n/a        | n/a     | n/a                   |
+| NS1           | n/a        | yes     | 10                    |
+| OCI           | yes        | yes     | 300                   |
+| OVH           | n/a        | yes     | 0                     |
+| PDNS          | n/a        | yes     | 300                   |
+| PiHole        | n/a        | yes     | n/a                   |
+| Plural        | n/a        | n/a     | n/a                   |
+| RFC2136       | n/a        | yes     | n/a                   |
+| Scaleway      | n/a        | n/a     | 300                   |
+| TencentCloud  | n/a        | n/a     | n/a                   |
+| Transip       | n/a        | yes     | 60                    |
+| Ultradns      | n/a        | yes     | n/a                   |
+| Webhook       | n/a        | n/a     | n/a                   |
diff --git a/docs/sources/nodes.md b/docs/sources/nodes.md
index ca683097..b3ede960 100644
--- a/docs/sources/nodes.md
+++ b/docs/sources/nodes.md
@@ -7,8 +7,9 @@ The node source adds an `A` record per each node `externalIP` (if not found, any
 It also adds an `AAAA` record per each node IPv6 `internalIP`. Refer to the [IPv6 Behavior](#ipv6-behavior) section for more details.
 The TTL of the records can be set with the `external-dns.alpha.kubernetes.io/ttl` node annotation.
 
-Nodes marked as **Unschedulable** as per [core/v1/NodeSpec](https://pkg.go.dev/k8s.io/api@v0.31.1/core/v1#NodeSpec) are excluded.
-This avoid exposing Unhealthy, NotReady or SchedulingDisabled (cordon) nodes.
+Nodes marked as **Unschedulable** as per [core/v1/NodeSpec](https://pkg.go.dev/k8s.io/api@v0.31.1/core/v1#NodeSpec) are excluded by default.
+As such, no DNS records are created for Unhealthy, NotReady or SchedulingDisabled (cordon) nodes (and existing ones are removed).
+In case you want to override the default, for example if you manage per-host DNS records via ExternalDNS, you can specify `--no-exclude-unschedulable` to always expose nodes no matter their status.
 
 ## IPv6 Behavior
 
diff --git a/docs/tutorials/cloudflare.md b/docs/tutorials/cloudflare.md
index fb1eceb7..55509609 100644
--- a/docs/tutorials/cloudflare.md
+++ b/docs/tutorials/cloudflare.md
@@ -310,7 +310,9 @@ If not set the value will default to `global`.
 
 ## Setting cloudflare-custom-hostname
 
-You can automatically configure custom hostnames for A/CNAME DNS records (as custom origins) using the `--cloudflare-custom-hostnames` flag and the `external-dns.alpha.kubernetes.io/cloudflare-custom-hostname: "<custom hostname>"` annotation.
+Automatic configuration of Cloudflare custom hostnames (using A/CNAME DNS records as custom origin servers) is enabled by the --cloudflare-custom-hostnames flag and the `external-dns.alpha.kubernetes.io/cloudflare-custom-hostname: <custom hostname>` annotation.
+
+Multiple hostnames are supported via a comma-separated list: `external-dns.alpha.kubernetes.io/cloudflare-custom-hostname: <custom hostname 1>,<custom hostname 2>`.
 
 See [Cloudflare for Platforms](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/) for more information on custom hostnames.
 
diff --git a/docs/tutorials/rfc2136.md b/docs/tutorials/rfc2136.md
index c14c184b..5211a6d7 100644
--- a/docs/tutorials/rfc2136.md
+++ b/docs/tutorials/rfc2136.md
@@ -497,6 +497,35 @@ external-dns \
   --rfc2136-insecure
 ```
 
+### Helm
+
+```yaml
+extraArgs:
+  - --rfc2136-host="dns-host-1.yourdomain.com"
+  - --rfc2136-port=53
+  - --rfc2136-zone=example.com
+  - --rfc2136-tsig-secret-alg=hmac-sha256
+  - --rfc2136-tsig-axfr
+
+env:
+  - name: "EXTERNAL_DNS_RDC2136_TSIG_SECRET"
+    valueFrom:
+      secretKeyRef:
+        name: rfc2136-keys
+        key: rfc2136-tsig-secret
+  - name: "EXTERNAL_DNS_RDC2136_TSIG_KEYNAME"
+    valueFrom:
+      secretKeyRef:
+        name: rfc2136-keys
+        key: rfc2136-tsig-keyname
+```
+
+#### Secret creation
+
+```shell
+kubectl create secret generic rfc2136-keys --from-literal=rfc2136-tsig-secret='xxx' --from-literal=rfc2136-tsig-keyname='k8s-external-dns-key' -n external-dns
+```
+
 ### Benefits
 
 - Distributes the load of DNS updates across multiple data centers, preventing any single DC from becoming a bottleneck.
diff --git a/go.mod b/go.mod
index e7a122fb..147a71d3 100644
--- a/go.mod
+++ b/go.mod
@@ -1,31 +1,32 @@
 module sigs.k8s.io/external-dns
 
-go 1.24.0
+go 1.24.2
+
 require (
 	cloud.google.com/go/compute/metadata v0.6.0
-	github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1
-	github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2
+	github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0
+	github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0
 	github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0
 	github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.3.0
 	github.com/F5Networks/k8s-bigip-ctlr/v2 v2.19.1
-	github.com/IBM-Cloud/ibm-cloud-cli-sdk v1.7.0
-	github.com/IBM/go-sdk-core/v5 v5.19.0
-	github.com/IBM/networking-go-sdk v0.51.3
-	github.com/Yamashou/gqlgenc v0.31.0
+	github.com/IBM-Cloud/ibm-cloud-cli-sdk v1.7.1
+	github.com/IBM/go-sdk-core/v5 v5.19.1
+	github.com/IBM/networking-go-sdk v0.51.4
+	github.com/Yamashou/gqlgenc v0.32.0
 	github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2
 	github.com/alecthomas/kingpin/v2 v2.4.0
-	github.com/aliyun/alibaba-cloud-sdk-go v1.63.103
+	github.com/aliyun/alibaba-cloud-sdk-go v1.63.106
 	github.com/aws/aws-sdk-go-v2 v1.36.3
-	github.com/aws/aws-sdk-go-v2/config v1.29.12
-	github.com/aws/aws-sdk-go-v2/credentials v1.17.65
-	github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.18.8
-	github.com/aws/aws-sdk-go-v2/service/dynamodb v1.42.0
-	github.com/aws/aws-sdk-go-v2/service/route53 v1.50.0
-	github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.35.1
-	github.com/aws/aws-sdk-go-v2/service/sts v1.33.17
+	github.com/aws/aws-sdk-go-v2/config v1.29.14
+	github.com/aws/aws-sdk-go-v2/credentials v1.17.67
+	github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.18.12
+	github.com/aws/aws-sdk-go-v2/service/dynamodb v1.42.4
+	github.com/aws/aws-sdk-go-v2/service/route53 v1.51.1
+	github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.35.4
+	github.com/aws/aws-sdk-go-v2/service/sts v1.33.19
 	github.com/bodgit/tsig v1.2.2
-	github.com/cenkalti/backoff/v4 v4.3.0
-	github.com/civo/civogo v0.3.96
+	github.com/cenkalti/backoff/v5 v5.0.2
+	github.com/civo/civogo v0.3.98
 	github.com/cloudflare/cloudflare-go v0.115.0
 	github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381
 	github.com/datawire/ambassador v1.12.4
@@ -36,43 +37,41 @@ require (
 	github.com/ffledgling/pdns-go v0.0.0-20180219074714-524e7daccd99
 	github.com/go-gandi/go-gandi v0.7.0
 	github.com/go-logr/logr v1.4.2
+	github.com/goccy/go-yaml v1.17.1
 	github.com/google/go-cmp v0.7.0
 	github.com/google/uuid v1.6.0
 	github.com/linki/instrumented_http v0.3.0
-	github.com/linode/linodego v1.48.1
+	github.com/linode/linodego v1.49.0
 	github.com/maxatome/go-testdeep v1.14.0
-	github.com/miekg/dns v1.1.64
+	github.com/miekg/dns v1.1.65
 	github.com/onsi/ginkgo v1.16.5
 	github.com/openshift/api v0.0.0-20230607130528-611114dca681
 	github.com/openshift/client-go v0.0.0-20230607134213-3cd0021bbee3
-	github.com/oracle/oci-go-sdk/v65 v65.88.0
+	github.com/oracle/oci-go-sdk/v65 v65.89.1
 	github.com/ovh/go-ovh v1.7.0
 	github.com/patrickmn/go-cache v2.1.0+incompatible
-	github.com/pkg/errors v0.9.1
 	github.com/pluralsh/gqlclient v1.12.2
 	github.com/projectcontour/contour v1.30.3
-	github.com/prometheus/client_golang v1.21.1
+	github.com/prometheus/client_golang v1.22.0
 	github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33
 	github.com/sirupsen/logrus v1.9.3
 	github.com/stretchr/testify v1.10.0
-	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1134
-	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1134
-	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns v1.0.1132
+	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1146
+	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1136
+	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns v1.0.1145
 	github.com/transip/gotransip/v6 v6.26.0
 	github.com/ultradns/ultradns-sdk-go v1.3.7
 	go.etcd.io/etcd/client/v3 v3.5.21
 	go.uber.org/ratelimit v0.3.1
-	golang.org/x/net v0.38.0
-	golang.org/x/oauth2 v0.28.0
-	golang.org/x/sync v0.12.0
-	golang.org/x/text v0.23.0
+	golang.org/x/net v0.39.0
+	golang.org/x/oauth2 v0.29.0
+	golang.org/x/sync v0.13.0
+	golang.org/x/text v0.24.0
 	golang.org/x/time v0.11.0
-	google.golang.org/api v0.228.0
-	gopkg.in/ns1/ns1-go.v2 v2.13.0
-	gopkg.in/yaml.v2 v2.4.0
-	gopkg.in/yaml.v3 v3.0.1
-	istio.io/api v1.25.1
-	istio.io/client-go v1.25.1
+	google.golang.org/api v0.229.0
+	gopkg.in/ns1/ns1-go.v2 v2.14.2
+	istio.io/api v1.25.2
+	istio.io/client-go v1.25.2
 	k8s.io/api v0.32.3
 	k8s.io/apimachinery v0.32.3
 	k8s.io/client-go v0.32.3
@@ -81,12 +80,12 @@ require (
 )
 
 require (
-	cloud.google.com/go/auth v0.15.0 // indirect
+	cloud.google.com/go/auth v0.16.0 // indirect
 	cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
 	code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f // indirect
-	github.com/99designs/gqlgen v0.17.61 // indirect
-	github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
-	github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 // indirect
+	github.com/99designs/gqlgen v0.17.70 // indirect
+	github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect
+	github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect
 	github.com/Masterminds/semver v1.4.2 // indirect
 	github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
 	github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5 // indirect
@@ -95,12 +94,12 @@ require (
 	github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
 	github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
 	github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
-	github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.25.1 // indirect
+	github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.25.3 // indirect
 	github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect
 	github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.15 // indirect
 	github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect
-	github.com/aws/aws-sdk-go-v2/service/sso v1.25.2 // indirect
-	github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.0 // indirect
+	github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 // indirect
+	github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 // indirect
 	github.com/aws/smithy-go v1.22.2 // indirect
 	github.com/benbjohnson/clock v1.3.0 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
@@ -123,13 +122,13 @@ require (
 	github.com/go-openapi/swag v0.23.0 // indirect
 	github.com/go-playground/locales v0.14.1 // indirect
 	github.com/go-playground/universal-translator v0.18.1 // indirect
-	github.com/go-playground/validator/v10 v10.24.0 // indirect
+	github.com/go-playground/validator/v10 v10.26.0 // indirect
 	github.com/go-resty/resty/v2 v2.16.5 // indirect
 	github.com/goccy/go-json v0.10.5 // indirect
 	github.com/gofrs/flock v0.8.1 // indirect
 	github.com/gofrs/uuid v4.4.0+incompatible // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
-	github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
+	github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
 	github.com/golang/protobuf v1.5.4 // indirect
 	github.com/google/gnostic-models v0.6.8 // indirect
 	github.com/google/go-querystring v1.1.0 // indirect
@@ -154,7 +153,6 @@ require (
 	github.com/jmespath/go-jmespath v0.4.0 // indirect
 	github.com/josharian/intern v1.0.0 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
-	github.com/klauspost/compress v1.17.11 // indirect
 	github.com/kylelemons/godebug v1.1.0 // indirect
 	github.com/leodido/go-urn v1.4.0 // indirect
 	github.com/mailru/easyjson v0.7.7 // indirect
@@ -171,6 +169,7 @@ require (
 	github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
 	github.com/peterhellberg/link v1.1.0 // indirect
 	github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
+	github.com/pkg/errors v0.9.1 // indirect
 	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
 	github.com/prometheus/client_model v0.6.1 // indirect
 	github.com/prometheus/common v0.62.0 // indirect
@@ -183,33 +182,36 @@ require (
 	github.com/spf13/pflag v1.0.5 // indirect
 	github.com/stretchr/objx v0.5.2 // indirect
 	github.com/terra-farm/udnssdk v1.3.5 // indirect
-	github.com/vektah/gqlparser/v2 v2.5.20 // indirect
+	github.com/vektah/gqlparser/v2 v2.5.24 // indirect
 	github.com/x448/float16 v0.8.4 // indirect
 	github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
+	github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
 	go.etcd.io/etcd/api/v3 v3.5.21 // indirect
 	go.etcd.io/etcd/client/pkg/v3 v3.5.21 // indirect
 	go.mongodb.org/mongo-driver v1.17.2 // indirect
 	go.opentelemetry.io/auto/sdk v1.1.0 // indirect
-	go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect
-	go.opentelemetry.io/otel v1.34.0 // indirect
-	go.opentelemetry.io/otel/metric v1.34.0 // indirect
-	go.opentelemetry.io/otel/trace v1.34.0 // indirect
+	go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
+	go.opentelemetry.io/otel v1.35.0 // indirect
+	go.opentelemetry.io/otel/metric v1.35.0 // indirect
+	go.opentelemetry.io/otel/trace v1.35.0 // indirect
 	go.uber.org/atomic v1.10.0 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
 	go.uber.org/zap v1.26.0 // indirect
-	golang.org/x/crypto v0.36.0 // indirect
-	golang.org/x/mod v0.23.0 // indirect
-	golang.org/x/sys v0.31.0 // indirect
-	golang.org/x/term v0.30.0 // indirect
-	golang.org/x/tools v0.30.0 // indirect
+	golang.org/x/crypto v0.37.0 // indirect
+	golang.org/x/mod v0.24.0 // indirect
+	golang.org/x/sys v0.32.0 // indirect
+	golang.org/x/term v0.31.0 // indirect
+	golang.org/x/tools v0.32.0 // indirect
 	google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 // indirect
-	google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 // indirect
-	google.golang.org/grpc v1.71.0 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e // indirect
+	google.golang.org/grpc v1.71.1 // indirect
 	google.golang.org/protobuf v1.36.6 // indirect
 	gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/ini.v1 v1.67.0 // indirect
 	gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
+	gopkg.in/yaml.v2 v2.4.0 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
 	k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect
 	k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
 	moul.io/http2curl v1.0.0 // indirect
diff --git a/go.sum b/go.sum
index f44fd6bd..ffc50c0e 100644
--- a/go.sum
+++ b/go.sum
@@ -2,8 +2,8 @@ bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxo
 cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
-cloud.google.com/go/auth v0.15.0 h1:Ly0u4aA5vG/fsSsxu98qCQBemXtAtJf+95z9HK+cxps=
-cloud.google.com/go/auth v0.15.0/go.mod h1:WJDGqZ1o9E9wKIL+IwStfyn/+s59zl4Bi+1KQNVXLZ8=
+cloud.google.com/go/auth v0.16.0 h1:Pd8P1s9WkcrBE2n/PhAwKsdrR35V3Sg2II9B+ndM3CU=
+cloud.google.com/go/auth v0.16.0/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI=
 cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
 cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
 cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
@@ -12,18 +12,18 @@ code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f h1:UrKzEwTg
 code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f/go.mod h1:sk5LnIjB/nIEU7yP5sDQExVm62wu0pBh3yrElngUisI=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 git.lukeshu.com/go/libsystemd v0.5.3/go.mod h1:FfDoP0i92r4p5Vn4NCLxvjkd7rCOe6otPa4L6hZg9WM=
-github.com/99designs/gqlgen v0.17.61 h1:vE7xLRC066n9wehgjeplILOWtwz75zbzcV2/Iv9i3pw=
-github.com/99designs/gqlgen v0.17.61/go.mod h1:rFU1T3lhv/tPeAlww/DJ4ol2YxT/pPpue+xxPbkd3r4=
+github.com/99designs/gqlgen v0.17.70 h1:xgLIgQuG+Q2L/AE9cW595CT7xCWCe/bpPIFGSfsGSGs=
+github.com/99designs/gqlgen v0.17.70/go.mod h1:fvCiqQAu2VLhKXez2xFvLmE47QgAPf/KTPN5XQ4rsHQ=
 github.com/Azure/azure-sdk-for-go v16.2.1+incompatible h1:KnPIugL51v3N3WwvaSmZbxukD1WuWXOiE9fRdu32f2I=
 github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1 h1:DSDNVxqkoXJiko6x8a90zidoYqnYYa6c1MTzDKzKkTo=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1/go.mod h1:zGqV2R4Cr/k8Uye5w+dgQ06WJtEcbQG/8J7BB6hnCr4=
-github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 h1:F0gBpfdPLGsw+nsgk6aqqkZS1jiixa5WwFe3fk/T3Ys=
-github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2/go.mod h1:SqINnQ9lVVdRlyC8cd1lCI0SdX4n2paeABd2K8ggfnE=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 h1:Gt0j3wceWMwPmiazCa8MzMA0MfhmPIz0Qp0FJ6qcM0U=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0 h1:OVoM452qUFBrX+URdH3VpR299ma4kfom0yB0URYky9g=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0/go.mod h1:kUjrAo8bgEwLeZ/CmHqNl3Z/kPm7y6FKfxxK0izYUg4=
 github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY=
 github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8=
-github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY=
-github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 h1:FPKJS1T+clwv+OLGt13a8UjqeRuh0O4SJ3lUriThc+4=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA=
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 h1:lpOxwrQ919lCZoNCd69rVt8u1eLZuMORrGXqy8sNf3c=
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0/go.mod h1:fSvRkb8d26z9dbL40Uf/OO6Vo9iExtZK3D0ulRV+8M0=
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v3 v3.1.0 h1:2qsIIvxVT+uE6yrNldntJKlLRgxGbZ85kgtz5SNBhMw=
@@ -43,20 +43,20 @@ github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6L
 github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
 github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
 github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
-github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 h1:H5xDQaE3XowWfhZRUpnfC+rGZMEVoSiji+b+/HFAPU4=
-github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
+github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs=
+github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
 github.com/F5Networks/k8s-bigip-ctlr/v2 v2.19.1 h1:NHWjSBeXbL8mlx+0QyCl4OrUvytCZ3nkEIRqX7t97wQ=
 github.com/F5Networks/k8s-bigip-ctlr/v2 v2.19.1/go.mod h1:JwdtGjHFTmUM1zjzvvCotCCyP55S146IuVPOJZ7D/Jw=
 github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
-github.com/IBM-Cloud/ibm-cloud-cli-sdk v1.7.0 h1:VMMr9Yu2QkIdXtQfi3v/+qoqlnzUuFx7vfU+GDfuhh0=
-github.com/IBM-Cloud/ibm-cloud-cli-sdk v1.7.0/go.mod h1:+fXHt9ZUw/AlSAHvQXkTcEMKXLVwSBvA7uReQXqDwmU=
-github.com/IBM/go-sdk-core/v5 v5.19.0 h1:YN2S5JUvq/EwYulmcNFwgyYBxZhVWl9nkY22H7Hpghw=
-github.com/IBM/go-sdk-core/v5 v5.19.0/go.mod h1:deZO1J5TSlU69bCnl/YV7nPxFZA2UEaup7cq/7ZTOgw=
-github.com/IBM/networking-go-sdk v0.51.3 h1:GW2VLP7XVcAHin6eWnCNA9l3gsv5tnyjf5UgGwMA7hk=
-github.com/IBM/networking-go-sdk v0.51.3/go.mod h1:T27XI2gtPjT7tW9nkHgrpBUNbmAc9OR41Z78Y493PoA=
+github.com/IBM-Cloud/ibm-cloud-cli-sdk v1.7.1 h1:O9CXYO4upLrGlxFTZBW91yFdpWkHblezhbuKS/JjaVg=
+github.com/IBM-Cloud/ibm-cloud-cli-sdk v1.7.1/go.mod h1:L1O3/tOKGedJ8db8i0KAgGBUHp8Fb0/00Lc8ebnj0DM=
+github.com/IBM/go-sdk-core/v5 v5.19.1 h1:sleVks1O4XjgF4YEGvyDh6PZbP6iZhlTPeDkQc8nWDs=
+github.com/IBM/go-sdk-core/v5 v5.19.1/go.mod h1:Q3BYO6iDA2zweQPDGbNTtqft5tDcEpm6RTuqMlPcvbw=
+github.com/IBM/networking-go-sdk v0.51.4 h1:rkbR+gUkksLKjNYL5YEWEAMv3qddR0mUkxObDMa4l/s=
+github.com/IBM/networking-go-sdk v0.51.4/go.mod h1:gjCFEp+UVP7FUlcq2C1RaoZAXFcD39CQdlUk7uVKko4=
 github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
 github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E=
 github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
@@ -81,8 +81,8 @@ github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:H
 github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
 github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
 github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
-github.com/Yamashou/gqlgenc v0.31.0 h1:t54Gi6Zx9Ub1oa/RvJ+DkOC1c2wdK1R4n7wyRBuQkyc=
-github.com/Yamashou/gqlgenc v0.31.0/go.mod h1:0VNZtzXhyDofkNNZXXPw8LSLvi3vyG6LXo7XvcWv2X4=
+github.com/Yamashou/gqlgenc v0.32.0 h1:f5Ebm9RG5jCL1iXxUN5X6e7Fgo/p3eQIDEaf0JO0GgQ=
+github.com/Yamashou/gqlgenc v0.32.0/go.mod h1:DExQmcD8yilMdtLdLWLofPrbWuxKjaf6HFZdG49i3EA=
 github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
 github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
 github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
@@ -98,8 +98,8 @@ github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAu
 github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
 github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5 h1:P5U+E4x5OkVEKQDklVPmzs71WM56RTTRqV4OrDC//Y4=
 github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5/go.mod h1:976q2ETgjT2snVCf2ZaBnyBbVoPERGjUz+0sofzEfro=
-github.com/aliyun/alibaba-cloud-sdk-go v1.63.103 h1:kZsvZo6waUg5313S6VkoPx8QyyeoUfMgF/KgxpiEfCw=
-github.com/aliyun/alibaba-cloud-sdk-go v1.63.103/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
+github.com/aliyun/alibaba-cloud-sdk-go v1.63.106 h1:+YPfQheppCKOPJxhWDmStF1UMJrxnA1iiwBH12t6Fa4=
+github.com/aliyun/alibaba-cloud-sdk-go v1.63.106/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
 github.com/andybalholm/brotli v0.0.0-20190621154722-5f990b63d2d6/go.mod h1:+lx6/Aqd1kLJ1GQfkvOnaZ1WGmLpMpbprPuIOOZX30U=
@@ -123,12 +123,12 @@ github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN
 github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
 github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM=
 github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg=
-github.com/aws/aws-sdk-go-v2/config v1.29.12 h1:Y/2a+jLPrPbHpFkpAAYkVEtJmxORlXoo5k2g1fa2sUo=
-github.com/aws/aws-sdk-go-v2/config v1.29.12/go.mod h1:xse1YTjmORlb/6fhkWi8qJh3cvZi4JoVNhc+NbJt4kI=
-github.com/aws/aws-sdk-go-v2/credentials v1.17.65 h1:q+nV2yYegofO/SUXruT+pn4KxkxmaQ++1B/QedcKBFM=
-github.com/aws/aws-sdk-go-v2/credentials v1.17.65/go.mod h1:4zyjAuGOdikpNYiSGpsGz8hLGmUzlY8pc8r9QQ/RXYQ=
-github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.18.8 h1:hGcg4DGGO+kolelCoOfuS7DGdySfx1vDe6QQsuuYKRU=
-github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.18.8/go.mod h1:fpFbG/4VQvI/DXpY5tG+CEtRZ2DDfi6krAI4sUj8aFE=
+github.com/aws/aws-sdk-go-v2/config v1.29.14 h1:f+eEi/2cKCg9pqKBoAIwRGzVb70MRKqWX4dg1BDcSJM=
+github.com/aws/aws-sdk-go-v2/config v1.29.14/go.mod h1:wVPHWcIFv3WO89w0rE10gzf17ZYy+UVS1Geq8Iei34g=
+github.com/aws/aws-sdk-go-v2/credentials v1.17.67 h1:9KxtdcIA/5xPNQyZRgUSpYOE6j9Bc4+D7nZua0KGYOM=
+github.com/aws/aws-sdk-go-v2/credentials v1.17.67/go.mod h1:p3C44m+cfnbv763s52gCqrjaqyPikj9Sg47kUVaNZQQ=
+github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.18.12 h1:mwAIR3fhxhSzXFj530LNCBe0JocYVQx6GuJpQiA+QOs=
+github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.18.12/go.mod h1:9cWrNL8q7ApFmZzKhnb63ub4zrdMzOGQVn/kxvagfeE=
 github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 h1:x793wxmUWVDhshP8WW2mlnXuFrO4cOd3HLBroh1paFw=
 github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30/go.mod h1:Jpne2tDnYiFascUEs2AWHJL9Yp7A5ZVy3TNyxaAjD6M=
 github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q=
@@ -137,26 +137,26 @@ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0io
 github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q=
 github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=
 github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=
-github.com/aws/aws-sdk-go-v2/service/dynamodb v1.42.0 h1:EJXx6zb+lOe/Do2bO0d0dwVnIRGoP5J5xZ0BTn3LbqM=
-github.com/aws/aws-sdk-go-v2/service/dynamodb v1.42.0/go.mod h1:yYaWRnVSPyAmexW5t7G3TcuYoalYfT+xQwzWsvtUQ7M=
-github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.25.1 h1:ZJfy2cSyoAOl7maGfRI4/J+cy00AczaYwVCow+bsc4k=
-github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.25.1/go.mod h1:lUqWdw5/esjPTkITXhN4C66o1ltwDq2qQ12j3SOzhVg=
+github.com/aws/aws-sdk-go-v2/service/dynamodb v1.42.4 h1:5GjCSGIpndYU/tVABz+4XnAcluU6wrjlPzAAgFUDG98=
+github.com/aws/aws-sdk-go-v2/service/dynamodb v1.42.4/go.mod h1:yYaWRnVSPyAmexW5t7G3TcuYoalYfT+xQwzWsvtUQ7M=
+github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.25.3 h1:GHC1WTF3ZBZy+gvz2qtYB6ttALVx35hlwc4IzOIUY7g=
+github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.25.3/go.mod h1:lUqWdw5/esjPTkITXhN4C66o1ltwDq2qQ12j3SOzhVg=
 github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE=
 github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA=
 github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.15 h1:M1R1rud7HzDrfCdlBQ7NjnRsDNEhXO/vGhuD189Ggmk=
 github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.15/go.mod h1:uvFKBSq9yMPV4LGAi7N4awn4tLY+hKE35f8THes2mzQ=
 github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2F1JbDaGooxTq18wmmFzbJRfXfVfy96/1CXM=
 github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15/go.mod h1:SwFBy2vjtA0vZbjjaFtfN045boopadnoVPhu4Fv66vY=
-github.com/aws/aws-sdk-go-v2/service/route53 v1.50.0 h1:/nkJHXtJXJeelXHqG0898+fWKgvfaXBhGzbCsSmn9j8=
-github.com/aws/aws-sdk-go-v2/service/route53 v1.50.0/go.mod h1:kGYOjvTa0Vw0qxrqrOLut1vMnui6qLxqv/SX3vYeM8Y=
-github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.35.1 h1:IG+YKQBAriN+tnBUiEE3wAZ1bA49Vg8B1GyYzeCuFLM=
-github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.35.1/go.mod h1:IbC8X3WZvsN+w48OrHBDUKcVnhhzO1YpXkCkFlr0qs8=
-github.com/aws/aws-sdk-go-v2/service/sso v1.25.2 h1:pdgODsAhGo4dvzC3JAG5Ce0PX8kWXrTZGx+jxADD+5E=
-github.com/aws/aws-sdk-go-v2/service/sso v1.25.2/go.mod h1:qs4a9T5EMLl/Cajiw2TcbNt2UNo/Hqlyp+GiuG4CFDI=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.0 h1:90uX0veLKcdHVfvxhkWUQSCi5VabtwMLFutYiRke4oo=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.0/go.mod h1:MlYRNmYu/fGPoxBQVvBYr9nyr948aY/WLUvwBMBJubs=
-github.com/aws/aws-sdk-go-v2/service/sts v1.33.17 h1:PZV5W8yk4OtH1JAuhV2PXwwO9v5G5Aoj+eMCn4T+1Kc=
-github.com/aws/aws-sdk-go-v2/service/sts v1.33.17/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4=
+github.com/aws/aws-sdk-go-v2/service/route53 v1.51.1 h1:41HrH51fydStW2Tah74zkqZlJfyx4gXeuGOdsIFuckY=
+github.com/aws/aws-sdk-go-v2/service/route53 v1.51.1/go.mod h1:kGYOjvTa0Vw0qxrqrOLut1vMnui6qLxqv/SX3vYeM8Y=
+github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.35.4 h1:zZvziql5vgfDs2hTfF8fRF4pySG7A28/qNJQihJvpwc=
+github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.35.4/go.mod h1:IbC8X3WZvsN+w48OrHBDUKcVnhhzO1YpXkCkFlr0qs8=
+github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 h1:1Gw+9ajCV1jogloEv1RRnvfRFia2cL6c9cuKV2Ps+G8=
+github.com/aws/aws-sdk-go-v2/service/sso v1.25.3/go.mod h1:qs4a9T5EMLl/Cajiw2TcbNt2UNo/Hqlyp+GiuG4CFDI=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 h1:hXmVKytPfTy5axZ+fYbR5d0cFmC3JvwLm5kM83luako=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1/go.mod h1:MlYRNmYu/fGPoxBQVvBYr9nyr948aY/WLUvwBMBJubs=
+github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 h1:1XuUZ8mYJw9B6lzAkXhqHlJd/XvaX32evhproijJEZY=
+github.com/aws/aws-sdk-go-v2/service/sts v1.33.19/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4=
 github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ=
 github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
 github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
@@ -179,16 +179,16 @@ github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0Bsq
 github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
 github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
 github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
-github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
-github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
+github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8=
+github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
 github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw=
-github.com/civo/civogo v0.3.96 h1:9R3yZS3B8B0oAqIlNDnMvsONk0mqZUkHREd0EH6HRIc=
-github.com/civo/civogo v0.3.96/go.mod h1:LaEbkszc+9nXSh4YNG0sYXFGYqdQFmXXzQg0gESs2hc=
+github.com/civo/civogo v0.3.98 h1:FEbB5oxCcHeHUK3fJODxVoMQzhpLV9Jtb7bezANTY5c=
+github.com/civo/civogo v0.3.98/go.mod h1:LaEbkszc+9nXSh4YNG0sYXFGYqdQFmXXzQg0gESs2hc=
 github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cloudflare/cloudflare-go v0.115.0 h1:84/dxeeXweCc0PN5Cto44iTA8AkG1fyT11yPO5ZB7sM=
@@ -418,8 +418,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
 github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
 github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
 github.com/go-playground/validator/v10 v10.9.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
-github.com/go-playground/validator/v10 v10.24.0 h1:KHQckvo8G6hlWnrPX4NJJ+aBfWNAE/HH+qdL2cBpCmg=
-github.com/go-playground/validator/v10 v10.24.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
+github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k=
+github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
 github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM=
 github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA=
 github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
@@ -439,6 +439,8 @@ github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJA
 github.com/goccy/go-json v0.7.8/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
 github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
 github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
+github.com/goccy/go-yaml v1.17.1 h1:LI34wktB2xEE3ONG/2Ar54+/HJVBriAGJ55PHls4YuY=
+github.com/goccy/go-yaml v1.17.1/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
 github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/godror/godror v0.13.3/go.mod h1:2ouUT4kdhUBk7TAkHWD4SN0CdI0pgEQbo8FVHhbSKWg=
@@ -456,8 +458,8 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
 github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
 github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
 github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
-github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
-github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
+github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
+github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
 github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
 github.com/golang/gddo v0.0.0-20190419222130-af0f2af80721/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4=
@@ -648,16 +650,16 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
 github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
 github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
-github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs=
-github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw=
+github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU=
+github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k=
 github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
 github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
 github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
 github.com/klauspost/compress v1.9.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
-github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
-github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
+github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
+github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
 github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
 github.com/klauspost/pgzip v1.2.1/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -700,8 +702,8 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b
 github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
 github.com/linki/instrumented_http v0.3.0 h1:dsN92+mXpfZtjJraartcQ99jnuw7fqsnPDjr85ma2dA=
 github.com/linki/instrumented_http v0.3.0/go.mod h1:pjYbItoegfuVi2GUOMhEqzvm/SJKuEL3H0tc8QRLRFk=
-github.com/linode/linodego v1.48.1 h1:Ojw1S+K5jJr1dggO8/H6r4FINxXnJbOU5GkbpaTfmhU=
-github.com/linode/linodego v1.48.1/go.mod h1:fc3t60If8X+yZTFAebhCnNDFrhwQhq9HDU92WnBousQ=
+github.com/linode/linodego v1.49.0 h1:MNd3qwvQzbXB5mCpvdCqlUIu1RPA9oC+50LyB9kK+GQ=
+github.com/linode/linodego v1.49.0/go.mod h1:B+HAM3//4w1wOS0BwdaQBKwBxlfe6kYJ7bSC6jJ/xtc=
 github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
 github.com/lyft/protoc-gen-star v0.4.10/go.mod h1:mE8fbna26u7aEA2QCVvvfBU/ZrPgocG1206xAFPcs94=
 github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
@@ -722,8 +724,8 @@ github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIG
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
 github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
 github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
-github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
-github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
+github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
 github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
@@ -747,8 +749,8 @@ github.com/mholt/archiver/v3 v3.3.0/go.mod h1:YnQtqsp+94Rwd0D/rk5cnLrxusUBUXg+08
 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
 github.com/miekg/dns v1.1.6/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
 github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
-github.com/miekg/dns v1.1.64 h1:wuZgD9wwCE6XMT05UU/mlSko71eRSXEAm2EbjQXLKnQ=
-github.com/miekg/dns v1.1.64/go.mod h1:Dzw9769uoKVaLuODMDZz9M6ynFU6Em65csPuoi8G0ck=
+github.com/miekg/dns v1.1.65 h1:0+tIPHzUW0GCge7IiK3guGP57VAw7hoPDfApjkMD1Fc=
+github.com/miekg/dns v1.1.65/go.mod h1:Dzw9769uoKVaLuODMDZz9M6ynFU6Em65csPuoi8G0ck=
 github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
 github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
 github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
@@ -808,16 +810,16 @@ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+
 github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
 github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
 github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
-github.com/onsi/ginkgo/v2 v2.23.0 h1:FA1xjp8ieYDzlgS5ABTpdUDB7wtngggONc8a7ku2NqQ=
-github.com/onsi/ginkgo/v2 v2.23.0/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM=
+github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
+github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
 github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
 github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
 github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
 github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
 github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
 github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
-github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
-github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
+github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
+github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
 github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
 github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
@@ -846,8 +848,8 @@ github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxS
 github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
 github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
 github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
-github.com/oracle/oci-go-sdk/v65 v65.88.0 h1:SbsGKsoRRxJxVTbwUyIPCPwPsHWb8aPgEEpo6qfRJnI=
-github.com/oracle/oci-go-sdk/v65 v65.88.0/go.mod h1:IBEV9l1qBzUpo7zgGaRUhbB05BVfcDGYRFBCPlTcPp0=
+github.com/oracle/oci-go-sdk/v65 v65.89.1 h1:8sVjxYPNQ83yqUgZKkdeUA0CnSodmL1Bme2oxq8gyKg=
+github.com/oracle/oci-go-sdk/v65 v65.89.1/go.mod h1:u6XRPsw9tPziBh76K7GrrRXPa8P8W3BQeqJ6ZZt9VLA=
 github.com/ovh/go-ovh v1.7.0 h1:V14nF7FwDjQrZt9g7jzcvAAQ3HN6DNShRFRMC3jLoPw=
 github.com/ovh/go-ovh v1.7.0/go.mod h1:cTVDnl94z4tl8pP1uZ/8jlVxntjSIf09bNcQ5TJSC7c=
 github.com/oxtoacart/bpool v0.0.0-20150712133111-4e1c5567d7c2 h1:CXwSGu/LYmbjEab5aMCs5usQRVBGThelUKBNnoSOuso=
@@ -891,8 +893,8 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf
 github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
 github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
 github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4=
-github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk=
-github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg=
+github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
+github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
 github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
@@ -923,8 +925,8 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg
 github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
 github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
-github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E=
-github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
+github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=
+github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA=
 github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
@@ -1016,13 +1018,14 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl
 github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
 github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1132/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1134 h1:NDCzSm7r8OZeWQje1FJNHM73Ku4QRrCP1GymfgZYLSM=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1134/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1134 h1:Iel1hDW0eQt6p8YDRH2EbjiK5mqC4KEzabSKV0ZQ6FY=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1134/go.mod h1:8R/Xhu0hKGRFT30uwoN44bisb3cOoNjV8iwH65DjqUc=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns v1.0.1132 h1:YjVToKgm2V8aUxiDahVEFOvXYgswXiROUhrfSc3jamE=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns v1.0.1132/go.mod h1:2xDMNe2ohV2hRBldVgv++eByAhj3vSMnh0xl9jRFiEU=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1136/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1145/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1146 h1:PMhgU4BETyTiikegps6gDtLamNWUiLMEx4fv16UWspY=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1146/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1136 h1:kMIdSU5IvpOROh27ToVQ3hlm6ym3lCRs9tnGCOBoZqk=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1136/go.mod h1:FpyIz3mymKaExVs6Fz27kxDBS42jqZn7vbACtxdeEH4=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns v1.0.1145 h1:K5N0Uxqm9kM7KU6DFBekCTKbldlXq6UD1ekOyXn4zEc=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns v1.0.1145/go.mod h1:mgwxarWzLxIylWtHmkoMg0dX8aqhO5lwfrHkK4IGLKE=
 github.com/terra-farm/udnssdk v1.3.5 h1:MNR3adfuuEK/l04+jzo8WW/0fnorY+nW515qb3vEr6I=
 github.com/terra-farm/udnssdk v1.3.5/go.mod h1:8RnM56yZTR7mYyUIvrDgXzdRaEyFIzqdEi7+um26Sv8=
 github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
@@ -1049,8 +1052,8 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX
 github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
 github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
 github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
-github.com/vektah/gqlparser/v2 v2.5.20 h1:kPaWbhBntxoZPaNdBaIPT1Kh0i1b/onb5kXgEdP5JCo=
-github.com/vektah/gqlparser/v2 v2.5.20/go.mod h1:xMl+ta8a5M1Yo1A1Iwt/k7gSpscwSnHZdw7tfhEGfTM=
+github.com/vektah/gqlparser/v2 v2.5.24 h1:Dnip1ilW+nnXmaXL6s6f1w4IaXpAFDLLE1f9SqMegpI=
+github.com/vektah/gqlparser/v2 v2.5.24/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo=
 github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
 github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
 github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
@@ -1064,9 +1067,12 @@ github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMx
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
 github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8=
 github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
+github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
 github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
 github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
@@ -1092,24 +1098,26 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
 go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I=
-go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
-go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
-go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
-go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
-go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
-go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
-go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
-go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
-go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
-go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
+go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
+go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
+go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
+go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
+go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
+go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
+go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
+go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
+go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
+go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
 go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
 go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
 go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
+go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8=
+go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
 go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
 go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
@@ -1147,8 +1155,10 @@ golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5y
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
-golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
+golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
+golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
+golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
+golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
 golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1172,8 +1182,10 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
-golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
+golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
 golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1209,15 +1221,19 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
 golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20210913180222-943fd674d43e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.0.0-20220725212005-46097bf591d3/go.mod h1:AaygXjzTFtRAg2ttMY5RMuhpJ3cNnI0XpyFJD1iQRSM=
-golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
-golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
+golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
+golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190130055435-99b60b757ec1/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc=
-golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
+golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98=
+golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1227,8 +1243,10 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
-golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
+golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
 golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180425194835-bb9c189858d9/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -1277,17 +1295,25 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
-golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
+golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
 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.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
-golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
+golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
+golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
+golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
+golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
 golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1295,8 +1321,11 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/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.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
-golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
+golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
 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=
@@ -1337,8 +1366,10 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f
 golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
-golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=
+golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1351,8 +1382,8 @@ gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZ
 google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
 google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
 google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
-google.golang.org/api v0.228.0 h1:X2DJ/uoWGnY5obVjewbp8icSL5U4FzuCfy9OjbLSnLs=
-google.golang.org/api v0.228.0/go.mod h1:wNvRS1Pbe8r4+IfBIniV8fwCpGwTrYa+kMUDiC5z5a4=
+google.golang.org/api v0.229.0 h1:p98ymMtqeJ5i3lIBMj5MpR9kzIIgzpHHh8vQ+vgAzx8=
+google.golang.org/api v0.229.0/go.mod h1:wyDfmq5g1wYJWn29O22FDWN48P7Xcz0xz+LBpptYvB0=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -1368,8 +1399,8 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98
 google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
 google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 h1:GVIKPyP/kLIyVOgOnTwFOrvQaQUzOzGMCxgFUOEmm24=
 google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422/go.mod h1:b6h1vNKhxaSoEI+5jc3PJUCustfli/mRab7295pY7rw=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 h1:iK2jbkWL86DXjEx0qiHcRE9dE4/Ahua5k6V8OWFb//c=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e h1:ztQaXfzEXTmCBvbtWYRhJxW+0iJcz2qXfd38/e9l7bA=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
 google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
 google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@@ -1383,8 +1414,8 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ
 google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
 google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
 google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
-google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
-google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
+google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI=
+google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
 google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -1422,8 +1453,8 @@ gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
 gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
-gopkg.in/ns1/ns1-go.v2 v2.13.0 h1:I5NNqI9Bi1SGK92TVkOvLTwux5LNrix/99H2datVh48=
-gopkg.in/ns1/ns1-go.v2 v2.13.0/go.mod h1:pfaU0vECVP7DIOr453z03HXS6dFJpXdNRwOyRzwmPSc=
+gopkg.in/ns1/ns1-go.v2 v2.14.2 h1:wz/toj9U20wBrmYxW4vTz7sZWED+JJVRjUBBJ7CKrzI=
+gopkg.in/ns1/ns1-go.v2 v2.14.2/go.mod h1:pfaU0vECVP7DIOr453z03HXS6dFJpXdNRwOyRzwmPSc=
 gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
 gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
@@ -1451,10 +1482,10 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh
 honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
-istio.io/api v1.25.1 h1:l3JS6Rh4bH+6ox84hRvtsJsr7gMJLsoJG2BQZGbXRyc=
-istio.io/api v1.25.1/go.mod h1:QFzEXv/IT582T0FHZVp1QoolvE4ws0zz/vVO55blmlE=
-istio.io/client-go v1.25.1 h1:1Asibz5v2NBA6w4Sqa85NS7TkpEolZcPKAT5oUAXWi8=
-istio.io/client-go v1.25.1/go.mod h1:Vap9OyHJMvvDegYoZczcNybS4wbPaTk+4bZcWMb8+vE=
+istio.io/api v1.25.2 h1:FCRQy7iaTreKJdLemlQ1vRJEsf1soCHoTAuSf68w5I8=
+istio.io/api v1.25.2/go.mod h1:QFzEXv/IT582T0FHZVp1QoolvE4ws0zz/vVO55blmlE=
+istio.io/client-go v1.25.2 h1:faupTqeMD0PkuNTZdFlpxxT35jBSQapK5k+MNAkXvqA=
+istio.io/client-go v1.25.2/go.mod h1:E2LTxTcCVe4cqpKy4/9Y4VmwSoLiH6ff9MEG7EhfSDo=
 k8s.io/api v0.18.0/go.mod h1:q2HRQkfDzHMBZL9l/y9rH63PkQl4vae0xRT+8prbrK8=
 k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78=
 k8s.io/api v0.18.4/go.mod h1:lOIQAKYgai1+vz9J7YcDZwC26Z0zQewYOGWdyIPUUQ4=
diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go
index d4f0601f..b8e8d5c9 100644
--- a/pkg/apis/externaldns/types.go
+++ b/pkg/apis/externaldns/types.go
@@ -213,169 +213,172 @@ type Config struct {
 	TraefikDisableLegacy                          bool
 	TraefikDisableNew                             bool
 	NAT64Networks                                 []string
+	ExcludeUnschedulable                          bool
 }
 
 var defaultConfig = &Config{
-	APIServerURL:                           "",
-	KubeConfig:                             "",
-	RequestTimeout:                         time.Second * 30,
-	DefaultTargets:                         []string{},
-	GlooNamespaces:                         []string{"gloo-system"},
-	SkipperRouteGroupVersion:               "zalando.org/v1",
-	Sources:                                nil,
-	Namespace:                              "",
-	AnnotationFilter:                       "",
-	LabelFilter:                            labels.Everything().String(),
-	IngressClassNames:                      nil,
-	FQDNTemplate:                           "",
-	CombineFQDNAndAnnotation:               false,
-	IgnoreHostnameAnnotation:               false,
-	IgnoreIngressTLSSpec:                   false,
-	IgnoreIngressRulesSpec:                 false,
-	GatewayName:                            "",
-	GatewayNamespace:                       "",
-	GatewayLabelFilter:                     "",
-	Compatibility:                          "",
-	PublishInternal:                        false,
-	PublishHostIP:                          false,
-	ExposeInternalIPV6:                     true,
-	ConnectorSourceServer:                  "localhost:8080",
-	Provider:                               "",
-	ProviderCacheTime:                      0,
-	GoogleProject:                          "",
-	GoogleBatchChangeSize:                  1000,
-	GoogleBatchChangeInterval:              time.Second,
-	GoogleZoneVisibility:                   "",
-	DomainFilter:                           []string{},
-	ZoneIDFilter:                           []string{},
-	ExcludeDomains:                         []string{},
-	RegexDomainFilter:                      regexp.MustCompile(""),
-	RegexDomainExclusion:                   regexp.MustCompile(""),
-	TargetNetFilter:                        []string{},
-	ExcludeTargetNets:                      []string{},
-	AlibabaCloudConfigFile:                 "/etc/kubernetes/alibaba-cloud.json",
-	AWSZoneType:                            "",
-	AWSZoneTagFilter:                       []string{},
-	AWSZoneMatchParent:                     false,
-	AWSAssumeRole:                          "",
-	AWSAssumeRoleExternalID:                "",
-	AWSBatchChangeSize:                     1000,
-	AWSBatchChangeSizeBytes:                32000,
-	AWSBatchChangeSizeValues:               1000,
-	AWSBatchChangeInterval:                 time.Second,
-	AWSEvaluateTargetHealth:                true,
-	AWSAPIRetries:                          3,
-	AWSPreferCNAME:                         false,
-	AWSZoneCacheDuration:                   0 * time.Second,
-	AWSSDServiceCleanup:                    false,
-	AWSSDCreateTag:                         map[string]string{},
-	AWSDynamoDBRegion:                      "",
-	AWSDynamoDBTable:                       "external-dns",
-	AzureConfigFile:                        "/etc/kubernetes/azure.json",
-	AzureResourceGroup:                     "",
-	AzureSubscriptionID:                    "",
-	AzureZonesCacheDuration:                0 * time.Second,
-	CloudflareProxied:                      false,
-	CloudflareCustomHostnames:              false,
-	CloudflareCustomHostnamesMinTLSVersion: "1.0",
+	AkamaiAccessToken:           "",
+	AkamaiClientSecret:          "",
+	AkamaiClientToken:           "",
+	AkamaiEdgercPath:            "",
+	AkamaiEdgercSection:         "",
+	AkamaiServiceConsumerDomain: "",
+	AlibabaCloudConfigFile:      "/etc/kubernetes/alibaba-cloud.json",
+	AnnotationFilter:            "",
+	APIServerURL:                "",
+	AWSAPIRetries:               3,
+	AWSAssumeRole:               "",
+	AWSAssumeRoleExternalID:     "",
+	AWSBatchChangeInterval:      time.Second,
+	AWSBatchChangeSize:          1000,
+	AWSBatchChangeSizeBytes:     32000,
+	AWSBatchChangeSizeValues:    1000,
+	AWSDynamoDBRegion:           "",
+	AWSDynamoDBTable:            "external-dns",
+	AWSEvaluateTargetHealth:     true,
+	AWSPreferCNAME:              false,
+	AWSSDCreateTag:              map[string]string{},
+	AWSSDServiceCleanup:         false,
+	AWSZoneCacheDuration:        0 * time.Second,
+	AWSZoneMatchParent:          false,
+	AWSZoneTagFilter:            []string{},
+	AWSZoneType:                 "",
+	AzureConfigFile:             "/etc/kubernetes/azure.json",
+	AzureResourceGroup:          "",
+	AzureSubscriptionID:         "",
+	AzureZonesCacheDuration:     0 * time.Second,
+	CFAPIEndpoint:               "",
+	CFPassword:                  "",
+	CFUsername:                  "",
 	CloudflareCustomHostnamesCertificateAuthority: "google",
+	CloudflareCustomHostnames:                     false,
+	CloudflareCustomHostnamesMinTLSVersion:        "1.0",
 	CloudflareDNSRecordsPerPage:                   100,
+	CloudflareProxied:                             false,
 	CloudflareRegionKey:                           "earth",
-	CoreDNSPrefix:                                 "/skydns/",
-	AkamaiServiceConsumerDomain:                   "",
-	AkamaiClientToken:                             "",
-	AkamaiClientSecret:                            "",
-	AkamaiAccessToken:                             "",
-	AkamaiEdgercSection:                           "",
-	AkamaiEdgercPath:                              "",
-	OCIConfigFile:                                 "/etc/kubernetes/oci.yaml",
-	OCIZoneScope:                                  "GLOBAL",
-	OCIZoneCacheDuration:                          0 * time.Second,
-	InMemoryZones:                                 []string{},
-	OVHEndpoint:                                   "ovh-eu",
-	OVHApiRateLimit:                               20,
-	OVHEnableCNAMERelative:                        false,
-	PDNSServer:                                    "http://localhost:8081",
-	PDNSServerID:                                  "localhost",
-	PDNSAPIKey:                                    "",
-	PDNSSkipTLSVerify:                             false,
-	PodSourceDomain:                               "",
-	TLSCA:                                         "",
-	TLSClientCert:                                 "",
-	TLSClientCertKey:                              "",
-	Policy:                                        "sync",
-	Registry:                                      "txt",
-	TXTOwnerID:                                    "default",
-	TXTPrefix:                                     "",
-	TXTSuffix:                                     "",
-	TXTCacheInterval:                              0,
-	TXTWildcardReplacement:                        "",
-	MinEventSyncInterval:                          5 * time.Second,
-	TXTEncryptEnabled:                             false,
-	TXTEncryptAESKey:                              "",
-	TXTNewFormatOnly:                              false,
-	Interval:                                      time.Minute,
-	Once:                                          false,
-	DryRun:                                        false,
-	UpdateEvents:                                  false,
-	LogFormat:                                     "text",
-	MetricsAddress:                                ":7979",
-	LogLevel:                                      logrus.InfoLevel.String(),
-	ExoscaleAPIEnvironment:                        "api",
-	ExoscaleAPIZone:                               "ch-gva-2",
-	ExoscaleAPIKey:                                "",
-	ExoscaleAPISecret:                             "",
-	CRDSourceAPIVersion:                           "externaldns.k8s.io/v1alpha1",
-	CRDSourceKind:                                 "DNSEndpoint",
-	ServiceTypeFilter:                             []string{},
-	CFAPIEndpoint:                                 "",
-	CFUsername:                                    "",
-	CFPassword:                                    "",
-	RFC2136Host:                                   []string{""},
-	RFC2136Port:                                   0,
-	RFC2136Zone:                                   []string{},
-	RFC2136Insecure:                               false,
-	RFC2136GSSTSIG:                                false,
-	RFC2136KerberosRealm:                          "",
-	RFC2136KerberosUsername:                       "",
-	RFC2136KerberosPassword:                       "",
-	RFC2136TSIGKeyName:                            "",
-	RFC2136TSIGSecret:                             "",
-	RFC2136TSIGSecretAlg:                          "",
-	RFC2136TAXFR:                                  true,
-	RFC2136MinTTL:                                 0,
-	RFC2136BatchChangeSize:                        50,
-	RFC2136UseTLS:                                 false,
-	RFC2136LoadBalancingStrategy:                  "disabled",
-	RFC2136SkipTLSVerify:                          false,
-	NS1Endpoint:                                   "",
-	NS1IgnoreSSL:                                  false,
-	TransIPAccountName:                            "",
-	TransIPPrivateKeyFile:                         "",
-	DigitalOceanAPIPageSize:                       50,
-	ManagedDNSRecordTypes:                         []string{endpoint.RecordTypeA, endpoint.RecordTypeAAAA, endpoint.RecordTypeCNAME},
-	ExcludeDNSRecordTypes:                         []string{},
-	GoDaddyAPIKey:                                 "",
-	GoDaddySecretKey:                              "",
-	GoDaddyTTL:                                    600,
-	GoDaddyOTE:                                    false,
-	IBMCloudProxied:                               false,
-	IBMCloudConfigFile:                            "/etc/kubernetes/ibmcloud.json",
-	TencentCloudConfigFile:                        "/etc/kubernetes/tencent-cloud.json",
-	TencentCloudZoneType:                          "",
-	PiholeServer:                                  "",
-	PiholePassword:                                "",
-	PiholeTLSInsecureSkipVerify:                   false,
-	PiholeApiVersion:                              "5",
-	PluralCluster:                                 "",
-	PluralProvider:                                "",
-	WebhookProviderURL:                            "http://localhost:8888",
-	WebhookProviderReadTimeout:                    5 * time.Second,
-	WebhookProviderWriteTimeout:                   10 * time.Second,
-	WebhookServer:                                 false,
-	TraefikDisableLegacy:                          false,
-	TraefikDisableNew:                             false,
-	NAT64Networks:                                 []string{},
+
+	CombineFQDNAndAnnotation:     false,
+	Compatibility:                "",
+	ConnectorSourceServer:        "localhost:8080",
+	CoreDNSPrefix:                "/skydns/",
+	CRDSourceAPIVersion:          "externaldns.k8s.io/v1alpha1",
+	CRDSourceKind:                "DNSEndpoint",
+	DefaultTargets:               []string{},
+	DigitalOceanAPIPageSize:      50,
+	DomainFilter:                 []string{},
+	DryRun:                       false,
+	ExcludeDNSRecordTypes:        []string{},
+	ExcludeDomains:               []string{},
+	ExcludeTargetNets:            []string{},
+	ExcludeUnschedulable:         true,
+	ExoscaleAPIEnvironment:       "api",
+	ExoscaleAPIKey:               "",
+	ExoscaleAPISecret:            "",
+	ExoscaleAPIZone:              "ch-gva-2",
+	ExposeInternalIPV6:           true,
+	FQDNTemplate:                 "",
+	GatewayLabelFilter:           "",
+	GatewayName:                  "",
+	GatewayNamespace:             "",
+	GlooNamespaces:               []string{"gloo-system"},
+	GoDaddyAPIKey:                "",
+	GoDaddyOTE:                   false,
+	GoDaddySecretKey:             "",
+	GoDaddyTTL:                   600,
+	GoogleBatchChangeInterval:    time.Second,
+	GoogleBatchChangeSize:        1000,
+	GoogleProject:                "",
+	GoogleZoneVisibility:         "",
+	IBMCloudConfigFile:           "/etc/kubernetes/ibmcloud.json",
+	IBMCloudProxied:              false,
+	IgnoreHostnameAnnotation:     false,
+	IgnoreIngressRulesSpec:       false,
+	IgnoreIngressTLSSpec:         false,
+	IngressClassNames:            nil,
+	InMemoryZones:                []string{},
+	Interval:                     time.Minute,
+	KubeConfig:                   "",
+	LabelFilter:                  labels.Everything().String(),
+	LogFormat:                    "text",
+	LogLevel:                     logrus.InfoLevel.String(),
+	ManagedDNSRecordTypes:        []string{endpoint.RecordTypeA, endpoint.RecordTypeAAAA, endpoint.RecordTypeCNAME},
+	MetricsAddress:               ":7979",
+	MinEventSyncInterval:         5 * time.Second,
+	Namespace:                    "",
+	NAT64Networks:                []string{},
+	NS1Endpoint:                  "",
+	NS1IgnoreSSL:                 false,
+	OCIConfigFile:                "/etc/kubernetes/oci.yaml",
+	OCIZoneCacheDuration:         0 * time.Second,
+	OCIZoneScope:                 "GLOBAL",
+	Once:                         false,
+	OVHApiRateLimit:              20,
+	OVHEnableCNAMERelative:       false,
+	OVHEndpoint:                  "ovh-eu",
+	PDNSAPIKey:                   "",
+	PDNSServer:                   "http://localhost:8081",
+	PDNSServerID:                 "localhost",
+	PDNSSkipTLSVerify:            false,
+	PiholeApiVersion:             "5",
+	PiholePassword:               "",
+	PiholeServer:                 "",
+	PiholeTLSInsecureSkipVerify:  false,
+	PluralCluster:                "",
+	PluralProvider:               "",
+	PodSourceDomain:              "",
+	Policy:                       "sync",
+	Provider:                     "",
+	ProviderCacheTime:            0,
+	PublishHostIP:                false,
+	PublishInternal:              false,
+	RegexDomainExclusion:         regexp.MustCompile(""),
+	RegexDomainFilter:            regexp.MustCompile(""),
+	Registry:                     "txt",
+	RequestTimeout:               time.Second * 30,
+	RFC2136BatchChangeSize:       50,
+	RFC2136GSSTSIG:               false,
+	RFC2136Host:                  []string{""},
+	RFC2136Insecure:              false,
+	RFC2136KerberosPassword:      "",
+	RFC2136KerberosRealm:         "",
+	RFC2136KerberosUsername:      "",
+	RFC2136LoadBalancingStrategy: "disabled",
+	RFC2136MinTTL:                0,
+	RFC2136Port:                  0,
+	RFC2136SkipTLSVerify:         false,
+	RFC2136TAXFR:                 true,
+	RFC2136TSIGKeyName:           "",
+	RFC2136TSIGSecret:            "",
+	RFC2136TSIGSecretAlg:         "",
+	RFC2136UseTLS:                false,
+	RFC2136Zone:                  []string{},
+	ServiceTypeFilter:            []string{},
+	SkipperRouteGroupVersion:     "zalando.org/v1",
+	Sources:                      nil,
+	TargetNetFilter:              []string{},
+	TencentCloudConfigFile:       "/etc/kubernetes/tencent-cloud.json",
+	TencentCloudZoneType:         "",
+	TLSCA:                        "",
+	TLSClientCert:                "",
+	TLSClientCertKey:             "",
+	TraefikDisableLegacy:         false,
+	TraefikDisableNew:            false,
+	TransIPAccountName:           "",
+	TransIPPrivateKeyFile:        "",
+	TXTCacheInterval:             0,
+	TXTEncryptAESKey:             "",
+	TXTEncryptEnabled:            false,
+	TXTNewFormatOnly:             false,
+	TXTOwnerID:                   "default",
+	TXTPrefix:                    "",
+	TXTSuffix:                    "",
+	TXTWildcardReplacement:       "",
+	UpdateEvents:                 false,
+	WebhookProviderReadTimeout:   5 * time.Second,
+	WebhookProviderURL:           "http://localhost:8888",
+	WebhookProviderWriteTimeout:  10 * time.Second,
+	WebhookServer:                false,
+	ZoneIDFilter:                 []string{},
 }
 
 // NewConfig returns new Config object
@@ -451,39 +454,41 @@ func App(cfg *Config) *kingpin.Application {
 	app.Flag("skipper-routegroup-groupversion", "The resource version for skipper routegroup").Default(defaultConfig.SkipperRouteGroupVersion).StringVar(&cfg.SkipperRouteGroupVersion)
 
 	// Flags related to processing source
-	app.Flag("source", "The resource types that are queried for endpoints; specify multiple times for multiple sources (required, options: service, ingress, node, pod, fake, connector, gateway-httproute, gateway-grpcroute, gateway-tlsroute, gateway-tcproute, gateway-udproute, istio-gateway, istio-virtualservice, cloudfoundry, contour-httpproxy, gloo-proxy, crd, empty, skipper-routegroup, openshift-route, ambassador-host, kong-tcpingress, f5-virtualserver, f5-transportserver, traefik-proxy)").Required().PlaceHolder("source").EnumsVar(&cfg.Sources, "service", "ingress", "node", "pod", "gateway-httproute", "gateway-grpcroute", "gateway-tlsroute", "gateway-tcproute", "gateway-udproute", "istio-gateway", "istio-virtualservice", "cloudfoundry", "contour-httpproxy", "gloo-proxy", "fake", "connector", "crd", "empty", "skipper-routegroup", "openshift-route", "ambassador-host", "kong-tcpingress", "f5-virtualserver", "f5-transportserver", "traefik-proxy")
-	app.Flag("openshift-router-name", "if source is openshift-route then you can pass the ingress controller name. Based on this name external-dns will select the respective router from the route status and map that routerCanonicalHostname to the route host while creating a CNAME record.").StringVar(&cfg.OCPRouterName)
-	app.Flag("namespace", "Limit resources queried for endpoints to a specific namespace (default: all namespaces)").Default(defaultConfig.Namespace).StringVar(&cfg.Namespace)
+	app.Flag("always-publish-not-ready-addresses", "Always publish also not ready addresses for headless services (optional)").BoolVar(&cfg.AlwaysPublishNotReadyAddresses)
 	app.Flag("annotation-filter", "Filter resources queried for endpoints by annotation, using label selector semantics").Default(defaultConfig.AnnotationFilter).StringVar(&cfg.AnnotationFilter)
-	app.Flag("label-filter", "Filter resources queried for endpoints by label selector; currently supported by source types crd, gateway-httproute, gateway-grpcroute, gateway-tlsroute, gateway-tcproute, gateway-udproute, ingress, node, openshift-route, service and ambassador-host").Default(defaultConfig.LabelFilter).StringVar(&cfg.LabelFilter)
-	app.Flag("ingress-class", "Require an Ingress to have this class name (defaults to any class; specify multiple times to allow more than one class)").StringsVar(&cfg.IngressClassNames)
-	app.Flag("fqdn-template", "A templated string that's used to generate DNS names from sources that don't define a hostname themselves, or to add a hostname suffix when paired with the fake source (optional). Accepts comma separated list for multiple global FQDN.").Default(defaultConfig.FQDNTemplate).StringVar(&cfg.FQDNTemplate)
 	app.Flag("combine-fqdn-annotation", "Combine FQDN template and Annotations instead of overwriting").BoolVar(&cfg.CombineFQDNAndAnnotation)
-	app.Flag("ignore-hostname-annotation", "Ignore hostname annotation when generating DNS names, valid only when --fqdn-template is set (default: false)").BoolVar(&cfg.IgnoreHostnameAnnotation)
-	app.Flag("ignore-non-host-network-pods", "Ignore pods not running on host network when using pod source (default: true)").BoolVar(&cfg.IgnoreNonHostNetworkPods)
-	app.Flag("ignore-ingress-tls-spec", "Ignore the spec.tls section in Ingress resources (default: false)").BoolVar(&cfg.IgnoreIngressTLSSpec)
+	app.Flag("compatibility", "Process annotation semantics from legacy implementations (optional, options: mate, molecule, kops-dns-controller)").Default(defaultConfig.Compatibility).EnumVar(&cfg.Compatibility, "", "mate", "molecule", "kops-dns-controller")
+	app.Flag("connector-source-server", "The server to connect for connector source, valid only when using connector source").Default(defaultConfig.ConnectorSourceServer).StringVar(&cfg.ConnectorSourceServer)
+	app.Flag("crd-source-apiversion", "API version of the CRD for crd source, e.g. `externaldns.k8s.io/v1alpha1`, valid only when using crd source").Default(defaultConfig.CRDSourceAPIVersion).StringVar(&cfg.CRDSourceAPIVersion)
+	app.Flag("crd-source-kind", "Kind of the CRD for the crd source in API group and version specified by crd-source-apiversion").Default(defaultConfig.CRDSourceKind).StringVar(&cfg.CRDSourceKind)
+	app.Flag("default-targets", "Set globally default host/IP that will apply as a target instead of source addresses. Specify multiple times for multiple targets (optional)").StringsVar(&cfg.DefaultTargets)
+	app.Flag("exclude-record-types", "Record types to exclude from management; specify multiple times to exclude many; (optional)").Default().StringsVar(&cfg.ExcludeDNSRecordTypes)
+	app.Flag("exclude-target-net", "Exclude target nets (optional)").StringsVar(&cfg.ExcludeTargetNets)
+	app.Flag("exclude-unschedulable", "Exclude nodes that are considered unschedulable (default: true)").Default(strconv.FormatBool(defaultConfig.ExcludeUnschedulable)).BoolVar(&cfg.ExcludeUnschedulable)
+	app.Flag("expose-internal-ipv6", "When using the node source, expose internal IPv6 addresses (optional). Default is true.").BoolVar(&cfg.ExposeInternalIPV6)
+	app.Flag("fqdn-template", "A templated string that's used to generate DNS names from sources that don't define a hostname themselves, or to add a hostname suffix when paired with the fake source (optional). Accepts comma separated list for multiple global FQDN.").Default(defaultConfig.FQDNTemplate).StringVar(&cfg.FQDNTemplate)
+	app.Flag("gateway-label-filter", "Filter Gateways of Route endpoints via label selector (default: all gateways)").StringVar(&cfg.GatewayLabelFilter)
 	app.Flag("gateway-name", "Limit Gateways of Route endpoints to a specific name (default: all names)").StringVar(&cfg.GatewayName)
 	app.Flag("gateway-namespace", "Limit Gateways of Route endpoints to a specific namespace (default: all namespaces)").StringVar(&cfg.GatewayNamespace)
-	app.Flag("gateway-label-filter", "Filter Gateways of Route endpoints via label selector (default: all gateways)").StringVar(&cfg.GatewayLabelFilter)
-	app.Flag("compatibility", "Process annotation semantics from legacy implementations (optional, options: mate, molecule, kops-dns-controller)").Default(defaultConfig.Compatibility).EnumVar(&cfg.Compatibility, "", "mate", "molecule", "kops-dns-controller")
+	app.Flag("ignore-hostname-annotation", "Ignore hostname annotation when generating DNS names, valid only when --fqdn-template is set (default: false)").BoolVar(&cfg.IgnoreHostnameAnnotation)
 	app.Flag("ignore-ingress-rules-spec", "Ignore the spec.rules section in Ingress resources (default: false)").BoolVar(&cfg.IgnoreIngressRulesSpec)
+	app.Flag("ignore-ingress-tls-spec", "Ignore the spec.tls section in Ingress resources (default: false)").BoolVar(&cfg.IgnoreIngressTLSSpec)
+	app.Flag("ignore-non-host-network-pods", "Ignore pods not running on host network when using pod source (default: true)").BoolVar(&cfg.IgnoreNonHostNetworkPods)
+	app.Flag("ingress-class", "Require an Ingress to have this class name (defaults to any class; specify multiple times to allow more than one class)").StringsVar(&cfg.IngressClassNames)
+	app.Flag("label-filter", "Filter resources queried for endpoints by label selector; currently supported by source types crd, gateway-httproute, gateway-grpcroute, gateway-tlsroute, gateway-tcproute, gateway-udproute, ingress, node, openshift-route, service and ambassador-host").Default(defaultConfig.LabelFilter).StringVar(&cfg.LabelFilter)
+	managedRecordTypesHelp := fmt.Sprintf("Record types to manage; specify multiple times to include many; (default: %s) (supported records: A, AAAA, CNAME, NS, SRV, TXT)", strings.Join(defaultConfig.ManagedDNSRecordTypes, ","))
+	app.Flag("managed-record-types", managedRecordTypesHelp).Default(defaultConfig.ManagedDNSRecordTypes...).StringsVar(&cfg.ManagedDNSRecordTypes)
+	app.Flag("namespace", "Limit resources queried for endpoints to a specific namespace (default: all namespaces)").Default(defaultConfig.Namespace).StringVar(&cfg.Namespace)
+	app.Flag("nat64-networks", "Adding an A record for each AAAA record in NAT64-enabled networks; specify multiple times for multiple possible nets (optional)").StringsVar(&cfg.NAT64Networks)
+	app.Flag("openshift-router-name", "if source is openshift-route then you can pass the ingress controller name. Based on this name external-dns will select the respective router from the route status and map that routerCanonicalHostname to the route host while creating a CNAME record.").StringVar(&cfg.OCPRouterName)
 	app.Flag("pod-source-domain", "Domain to use for pods records (optional)").Default(defaultConfig.PodSourceDomain).StringVar(&cfg.PodSourceDomain)
-	app.Flag("publish-internal-services", "Allow external-dns to publish DNS records for ClusterIP services (optional)").BoolVar(&cfg.PublishInternal)
 	app.Flag("publish-host-ip", "Allow external-dns to publish host-ip for headless services (optional)").BoolVar(&cfg.PublishHostIP)
-	app.Flag("always-publish-not-ready-addresses", "Always publish also not ready addresses for headless services (optional)").BoolVar(&cfg.AlwaysPublishNotReadyAddresses)
-	app.Flag("connector-source-server", "The server to connect for connector source, valid only when using connector source").Default(defaultConfig.ConnectorSourceServer).StringVar(&cfg.ConnectorSourceServer)
-	app.Flag("crd-source-apiversion", "API version of the CRD for crd source, e.g. `externaldns.k8s.io/v1alpha1`, valid only when using crd source").Default(defaultConfig.CRDSourceAPIVersion).StringVar(&cfg.CRDSourceAPIVersion)
-	app.Flag("crd-source-kind", "Kind of the CRD for the crd source in API group and version specified by crd-source-apiversion").Default(defaultConfig.CRDSourceKind).StringVar(&cfg.CRDSourceKind)
+	app.Flag("publish-internal-services", "Allow external-dns to publish DNS records for ClusterIP services (optional)").BoolVar(&cfg.PublishInternal)
 	app.Flag("service-type-filter", "The service types to take care about (default: all, expected: ClusterIP, NodePort, LoadBalancer or ExternalName)").StringsVar(&cfg.ServiceTypeFilter)
-	app.Flag("managed-record-types", "Record types to manage; specify multiple times to include many; (default: A, AAAA, CNAME) (supported records: A, AAAA, CNAME, NS, SRV, TXT)").Default("A", "AAAA", "CNAME").StringsVar(&cfg.ManagedDNSRecordTypes)
-	app.Flag("exclude-record-types", "Record types to exclude from management; specify multiple times to exclude many; (optional)").Default().StringsVar(&cfg.ExcludeDNSRecordTypes)
-	app.Flag("default-targets", "Set globally default host/IP that will apply as a target instead of source addresses. Specify multiple times for multiple targets (optional)").StringsVar(&cfg.DefaultTargets)
+	app.Flag("source", "The resource types that are queried for endpoints; specify multiple times for multiple sources (required, options: service, ingress, node, pod, fake, connector, gateway-httproute, gateway-grpcroute, gateway-tlsroute, gateway-tcproute, gateway-udproute, istio-gateway, istio-virtualservice, cloudfoundry, contour-httpproxy, gloo-proxy, crd, empty, skipper-routegroup, openshift-route, ambassador-host, kong-tcpingress, f5-virtualserver, f5-transportserver, traefik-proxy)").Required().PlaceHolder("source").EnumsVar(&cfg.Sources, "service", "ingress", "node", "pod", "gateway-httproute", "gateway-grpcroute", "gateway-tlsroute", "gateway-tcproute", "gateway-udproute", "istio-gateway", "istio-virtualservice", "cloudfoundry", "contour-httpproxy", "gloo-proxy", "fake", "connector", "crd", "empty", "skipper-routegroup", "openshift-route", "ambassador-host", "kong-tcpingress", "f5-virtualserver", "f5-transportserver", "traefik-proxy")
 	app.Flag("target-net-filter", "Limit possible targets by a net filter; specify multiple times for multiple possible nets (optional)").StringsVar(&cfg.TargetNetFilter)
-	app.Flag("exclude-target-net", "Exclude target nets (optional)").StringsVar(&cfg.ExcludeTargetNets)
 	app.Flag("traefik-disable-legacy", "Disable listeners on Resources under the traefik.containo.us API Group").Default(strconv.FormatBool(defaultConfig.TraefikDisableLegacy)).BoolVar(&cfg.TraefikDisableLegacy)
 	app.Flag("traefik-disable-new", "Disable listeners on Resources under the traefik.io API Group").Default(strconv.FormatBool(defaultConfig.TraefikDisableNew)).BoolVar(&cfg.TraefikDisableNew)
-	app.Flag("nat64-networks", "Adding an A record for each AAAA record in NAT64-enabled networks; specify multiple times for multiple possible nets (optional)").StringsVar(&cfg.NAT64Networks)
-	app.Flag("expose-internal-ipv6", "When using the node source, expose internal IPv6 addresses (optional). Default is true.").BoolVar(&cfg.ExposeInternalIPV6)
 
 	// Flags related to providers
 	providers := []string{"akamai", "alibabacloud", "aws", "aws-sd", "azure", "azure-dns", "azure-private-dns", "civo", "cloudflare", "coredns", "digitalocean", "dnsimple", "exoscale", "gandi", "godaddy", "google", "ibmcloud", "inmemory", "linode", "ns1", "oci", "ovh", "pdns", "pihole", "plural", "rfc2136", "scaleway", "skydns", "tencentcloud", "transip", "ultradns", "webhook"}
@@ -577,7 +582,7 @@ func App(cfg *Config) *kingpin.Application {
 	// Flags related to RFC2136 provider
 	app.Flag("rfc2136-host", "When using the RFC2136 provider, specify the host of the DNS server (optionally specify multiple times when when using --rfc2136-load-balancing-strategy)").Default(defaultConfig.RFC2136Host[0]).StringsVar(&cfg.RFC2136Host)
 	app.Flag("rfc2136-port", "When using the RFC2136 provider, specify the port of the DNS server").Default(strconv.Itoa(defaultConfig.RFC2136Port)).IntVar(&cfg.RFC2136Port)
-	app.Flag("rfc2136-zone", "When using the RFC2136 provider, specify zone entries of the DNS server to use").StringsVar(&cfg.RFC2136Zone)
+	app.Flag("rfc2136-zone", "When using the RFC2136 provider, specify zone entry of the DNS server to use (can be specified multiple times)").StringsVar(&cfg.RFC2136Zone)
 	app.Flag("rfc2136-create-ptr", "When using the RFC2136 provider, enable PTR management").Default(strconv.FormatBool(defaultConfig.RFC2136CreatePTR)).BoolVar(&cfg.RFC2136CreatePTR)
 	app.Flag("rfc2136-insecure", "When using the RFC2136 provider, specify whether to attach TSIG or not (default: false, requires --rfc2136-tsig-keyname and rfc2136-tsig-secret)").Default(strconv.FormatBool(defaultConfig.RFC2136Insecure)).BoolVar(&cfg.RFC2136Insecure)
 	app.Flag("rfc2136-tsig-keyname", "When using the RFC2136 provider, specify the TSIG key to attached to DNS messages (required when --rfc2136-insecure=false)").Default(defaultConfig.RFC2136TSIGKeyName).StringVar(&cfg.RFC2136TSIGKeyName)
diff --git a/plan/conflict.go b/plan/conflict.go
index 3044059b..bf153dcf 100644
--- a/plan/conflict.go
+++ b/plan/conflict.go
@@ -25,7 +25,7 @@ import (
 )
 
 // ConflictResolver is used to make a decision in case of two or more different kubernetes resources
-// are trying to acquire same DNS name
+// are trying to acquire the same DNS name
 type ConflictResolver interface {
 	ResolveCreate(candidates []*endpoint.Endpoint) *endpoint.Endpoint
 	ResolveUpdate(current *endpoint.Endpoint, candidates []*endpoint.Endpoint) *endpoint.Endpoint
@@ -38,13 +38,13 @@ type PerResource struct{}
 // ResolveCreate is invoked when dns name is not owned by any resource
 // ResolveCreate takes "minimal" (string comparison of Target) endpoint to acquire the DNS record
 func (s PerResource) ResolveCreate(candidates []*endpoint.Endpoint) *endpoint.Endpoint {
-	var min *endpoint.Endpoint
+	var minE *endpoint.Endpoint
 	for _, ep := range candidates {
-		if min == nil || s.less(ep, min) {
-			min = ep
+		if minE == nil || s.less(ep, minE) {
+			minE = ep
 		}
 	}
-	return min
+	return minE
 }
 
 // ResolveUpdate is invoked when dns name is already owned by "current" endpoint
diff --git a/plan/plan.go b/plan/plan.go
index 6124b764..c77f2f2a 100644
--- a/plan/plan.go
+++ b/plan/plan.go
@@ -262,9 +262,11 @@ func (p *Plan) Calculate() *Plan {
 	}
 
 	plan := &Plan{
-		Current:        p.Current,
-		Desired:        p.Desired,
-		Changes:        changes,
+		Current: p.Current,
+		Desired: p.Desired,
+		Changes: changes,
+		// The default for ExternalDNS is to always only consider A/AAAA and CNAMEs.
+		// Everything else is an add on or something to be considered.
 		ManagedRecords: []string{endpoint.RecordTypeA, endpoint.RecordTypeAAAA, endpoint.RecordTypeCNAME},
 	}
 
diff --git a/provider/akamai/akamai.go b/provider/akamai/akamai.go
index bd36fd66..e553d3ff 100644
--- a/provider/akamai/akamai.go
+++ b/provider/akamai/akamai.go
@@ -34,9 +34,9 @@ import (
 
 const (
 	// Default Record TTL
-	edgeDNSRecordTTL = 600
-	maxUint          = ^uint(0)
-	maxInt           = int(maxUint >> 1)
+	defaultTTL = 600
+	maxUint    = ^uint(0)
+	maxInt     = int(maxUint >> 1)
 )
 
 // edgeDNSClient is a proxy interface of the Akamai edgegrid configdns-v2 package that can be stubbed for testing.
@@ -90,14 +90,6 @@ type akamaiZone struct {
 func NewAkamaiProvider(akamaiConfig AkamaiConfig, akaService AkamaiDNSService) (provider.Provider, error) {
 	var edgeGridConfig edgegrid.Config
 
-	/*
-		log.Debugf("Host: %s", akamaiConfig.ServiceConsumerDomain)
-		log.Debugf("ClientToken: %s", akamaiConfig.ClientToken)
-		log.Debugf("ClientSecret: %s", akamaiConfig.ClientSecret)
-		log.Debugf("AccessToken: %s", akamaiConfig.AccessToken)
-		log.Debugf("EdgePath: %s", akamaiConfig.EdgercPath)
-		log.Debugf("EdgeSection: %s", akamaiConfig.EdgercSection)
-	*/
 	// environment overrides edgerc file but config needs to be complete
 	if akamaiConfig.ServiceConsumerDomain == "" || akamaiConfig.ClientToken == "" || akamaiConfig.ClientSecret == "" || akamaiConfig.AccessToken == "" {
 		// Kubernetes config incomplete or non existent. Can't mix and match.
@@ -106,7 +98,7 @@ func NewAkamaiProvider(akamaiConfig AkamaiConfig, akaService AkamaiDNSService) (
 		edgeGridConfig, err = edgegrid.Init(akamaiConfig.EdgercPath, akamaiConfig.EdgercSection) // use default .edgerc location and section
 		if err != nil {
 			log.Errorf("Edgegrid Init Failed")
-			return &AkamaiProvider{}, err // return empty provider for backward compatibility
+			return &AkamaiProvider{}, err // return an empty provider for backward compatibility
 		}
 		edgeGridConfig.HeaderToSign = append(edgeGridConfig.HeaderToSign, "X-External-DNS")
 	} else {
@@ -360,7 +352,7 @@ func trimTxtRdata(rdata []string, rtype string) []string {
 func ttlAsInt(src endpoint.TTL) int {
 	var temp interface{} = int64(src)
 	temp64 := temp.(int64)
-	var ttl = edgeDNSRecordTTL
+	var ttl = defaultTTL
 	if temp64 > 0 && temp64 <= int64(maxInt) {
 		ttl = int(temp64)
 	}
diff --git a/provider/alibabacloud/alibaba_cloud.go b/provider/alibabacloud/alibaba_cloud.go
index 5183d443..16318385 100644
--- a/provider/alibabacloud/alibaba_cloud.go
+++ b/provider/alibabacloud/alibaba_cloud.go
@@ -29,8 +29,8 @@ import (
 	"github.com/aliyun/alibaba-cloud-sdk-go/services/alidns"
 	"github.com/aliyun/alibaba-cloud-sdk-go/services/pvtz"
 	"github.com/denverdino/aliyungo/metadata"
+	yaml "github.com/goccy/go-yaml"
 	log "github.com/sirupsen/logrus"
-	"gopkg.in/yaml.v2"
 
 	"sigs.k8s.io/external-dns/endpoint"
 	"sigs.k8s.io/external-dns/plan"
@@ -38,7 +38,7 @@ import (
 )
 
 const (
-	defaultAlibabaCloudRecordTTL            = 600
+	defaultTTL                              = 600
 	defaultAlibabaCloudPrivateZoneRecordTTL = 60
 	defaultAlibabaCloudPageSize             = 50
 	nullHostAlibabaCloud                    = "@"
@@ -606,12 +606,12 @@ func (p *AlibabaCloudProvider) deleteRecords(recordMap map[string][]alidns.Recor
 
 func (p *AlibabaCloudProvider) equals(record alidns.Record, endpoint *endpoint.Endpoint) bool {
 	ttl1 := record.TTL
-	if ttl1 == defaultAlibabaCloudRecordTTL {
+	if ttl1 == defaultTTL {
 		ttl1 = 0
 	}
 
 	ttl2 := int64(endpoint.RecordTTL)
-	if ttl2 == defaultAlibabaCloudRecordTTL {
+	if ttl2 == defaultTTL {
 		ttl2 = 0
 	}
 
diff --git a/provider/aws/aws.go b/provider/aws/aws.go
index c1197743..89d90a47 100644
--- a/provider/aws/aws.go
+++ b/provider/aws/aws.go
@@ -39,7 +39,7 @@ import (
 
 const (
 	defaultAWSProfile = "default"
-	recordTTL         = 300
+	defaultTTL        = 300
 	// From the experiments, it seems that the default MaxItems applied is 100,
 	// and that, on the server side, there is a hard limit of 300 elements per page.
 	// After a discussion with AWS representatives, clients should accept
@@ -232,7 +232,7 @@ type profiledZone struct {
 }
 
 func (cs Route53Changes) Route53Changes() []route53types.Change {
-	ret := []route53types.Change{}
+	var ret []route53types.Change
 	for _, c := range cs {
 		ret = append(ret, c.Change)
 	}
@@ -313,7 +313,7 @@ type AWSConfig struct {
 
 // NewAWSProvider initializes a new AWS Route53 based Provider.
 func NewAWSProvider(awsConfig AWSConfig, clients map[string]Route53API) (*AWSProvider, error) {
-	provider := &AWSProvider{
+	pr := &AWSProvider{
 		clients:               clients,
 		domainFilter:          awsConfig.DomainFilter,
 		zoneIDFilter:          awsConfig.ZoneIDFilter,
@@ -331,7 +331,7 @@ func NewAWSProvider(awsConfig AWSConfig, clients map[string]Route53API) (*AWSPro
 		failedChangesQueue:    make(map[string]Route53Changes),
 	}
 
-	return provider, nil
+	return pr, nil
 }
 
 // Zones returns the list of hosted zones.
@@ -510,7 +510,7 @@ func (p *AWSProvider) records(ctx context.Context, zones map[string]*profiledZon
 				if r.AliasTarget != nil {
 					// Alias records don't have TTLs so provide the default to match the TXT generation
 					if ttl == 0 {
-						ttl = recordTTL
+						ttl = defaultTTL
 					}
 					ep := endpoint.
 						NewEndpointWithTTL(name, string(r.Type), ttl, *r.AliasTarget.DNSName).
@@ -561,33 +561,33 @@ func (p *AWSProvider) records(ctx context.Context, zones map[string]*profiledZon
 }
 
 // Identify if old and new endpoints require DELETE/CREATE instead of UPDATE.
-func (p *AWSProvider) requiresDeleteCreate(old *endpoint.Endpoint, new *endpoint.Endpoint) bool {
-	// a change of record type
-	if old.RecordType != new.RecordType {
+func (p *AWSProvider) requiresDeleteCreate(old *endpoint.Endpoint, newE *endpoint.Endpoint) bool {
+	// a change of a record type
+	if old.RecordType != newE.RecordType {
 		return true
 	}
 
 	// an ALIAS record change to/from an A
 	if old.RecordType == endpoint.RecordTypeA {
 		oldAlias, _ := old.GetProviderSpecificProperty(providerSpecificAlias)
-		newAlias, _ := new.GetProviderSpecificProperty(providerSpecificAlias)
+		newAlias, _ := newE.GetProviderSpecificProperty(providerSpecificAlias)
 		if oldAlias != newAlias {
 			return true
 		}
 	}
 
 	// a set identifier change
-	if old.SetIdentifier != new.SetIdentifier {
+	if old.SetIdentifier != newE.SetIdentifier {
 		return true
 	}
 
 	// a change of routing policy
-	// default to true for geolocation properties if any geolocation property exists in old/new but not the other
+	// defaults to true for geolocation properties if any geolocation property exists in old/new but not the other
 	for _, propType := range [7]string{providerSpecificWeight, providerSpecificRegion, providerSpecificFailover,
 		providerSpecificFailover, providerSpecificGeolocationContinentCode, providerSpecificGeolocationCountryCode,
 		providerSpecificGeolocationSubdivisionCode} {
 		_, oldPolicy := old.GetProviderSpecificProperty(propType)
-		_, newPolicy := new.GetProviderSpecificProperty(propType)
+		_, newPolicy := newE.GetProviderSpecificProperty(propType)
 		if oldPolicy != newPolicy {
 			return true
 		}
@@ -601,14 +601,14 @@ func (p *AWSProvider) createUpdateChanges(newEndpoints, oldEndpoints []*endpoint
 	var creates []*endpoint.Endpoint
 	var updates []*endpoint.Endpoint
 
-	for i, new := range newEndpoints {
-		old := oldEndpoints[i]
-		if p.requiresDeleteCreate(old, new) {
-			deletes = append(deletes, old)
-			creates = append(creates, new)
+	for i, newE := range newEndpoints {
+		oldE := oldEndpoints[i]
+		if p.requiresDeleteCreate(oldE, newE) {
+			deletes = append(deletes, oldE)
+			creates = append(creates, newE)
 		} else {
 			// Safe to perform an UPSERT.
-			updates = append(updates, new)
+			updates = append(updates, newE)
 		}
 	}
 
@@ -760,8 +760,8 @@ func (p *AWSProvider) submitChanges(ctx context.Context, changes Route53Changes,
 func (p *AWSProvider) newChanges(action route53types.ChangeAction, endpoints []*endpoint.Endpoint) Route53Changes {
 	changes := make(Route53Changes, 0, len(endpoints))
 
-	for _, endpoint := range endpoints {
-		change := p.newChange(action, endpoint)
+	for _, ep := range endpoints {
+		change := p.newChange(action, ep)
 		changes = append(changes, change)
 	}
 
@@ -804,8 +804,8 @@ func (p *AWSProvider) AdjustEndpoints(endpoints []*endpoint.Endpoint) ([]*endpoi
 
 		if alias {
 			if ep.RecordTTL.IsConfigured() {
-				log.Debugf("Modifying endpoint: %v, setting ttl=%v", ep, recordTTL)
-				ep.RecordTTL = recordTTL
+				log.Debugf("Modifying endpoint: %v, setting ttl=%v", ep, defaultTTL)
+				ep.RecordTTL = defaultTTL
 			}
 			if prop, ok := ep.GetProviderSpecificProperty(providerSpecificEvaluateTargetHealth); ok {
 				if prop != "true" && prop != "false" {
@@ -866,7 +866,7 @@ func (p *AWSProvider) newChange(action route53types.ChangeAction, ep *endpoint.E
 		change.sizeValues += 1
 	} else {
 		if !ep.RecordTTL.IsConfigured() {
-			change.ResourceRecordSet.TTL = aws.Int64(recordTTL)
+			change.ResourceRecordSet.TTL = aws.Int64(defaultTTL)
 		} else {
 			change.ResourceRecordSet.TTL = aws.Int64(int64(ep.RecordTTL))
 		}
diff --git a/provider/awssd/aws_sd.go b/provider/awssd/aws_sd.go
index 95ecda40..44511f0b 100644
--- a/provider/awssd/aws_sd.go
+++ b/provider/awssd/aws_sd.go
@@ -35,7 +35,7 @@ import (
 )
 
 const (
-	sdDefaultRecordTTL = 300
+	defaultTTL = 300
 
 	sdNamespaceTypePublic  = "public"
 	sdNamespaceTypePrivate = "private"
@@ -407,7 +407,7 @@ func (p *AWSSDProvider) CreateService(ctx context.Context, namespaceID *string,
 	srvType := p.serviceTypeFromEndpoint(ep)
 	routingPolicy := p.routingPolicyFromEndpoint(ep)
 
-	ttl := int64(sdDefaultRecordTTL)
+	ttl := int64(defaultTTL)
 	if ep.RecordTTL.IsConfigured() {
 		ttl = int64(ep.RecordTTL)
 	}
@@ -443,7 +443,7 @@ func (p *AWSSDProvider) UpdateService(ctx context.Context, service *sdtypes.Serv
 
 	srvType := p.serviceTypeFromEndpoint(ep)
 
-	ttl := int64(sdDefaultRecordTTL)
+	ttl := int64(defaultTTL)
 	if ep.RecordTTL.IsConfigured() {
 		ttl = int64(ep.RecordTTL)
 	}
diff --git a/provider/azure/azure.go b/provider/azure/azure.go
index e80345e6..c71e638e 100644
--- a/provider/azure/azure.go
+++ b/provider/azure/azure.go
@@ -35,7 +35,7 @@ import (
 )
 
 const (
-	azureRecordTTL = 300
+	defaultTTL = 300
 )
 
 // ZonesClient is an interface of dns.ZoneClient that can be stubbed for testing.
@@ -337,7 +337,7 @@ func (p *AzureProvider) recordSetNameForZone(zone string, endpoint *endpoint.End
 }
 
 func (p *AzureProvider) newRecordSet(endpoint *endpoint.Endpoint) (dns.RecordSet, error) {
-	var ttl int64 = azureRecordTTL
+	var ttl int64 = defaultTTL
 	if endpoint.RecordTTL.IsConfigured() {
 		ttl = int64(endpoint.RecordTTL)
 	}
diff --git a/provider/azure/azure_private_dns.go b/provider/azure/azure_private_dns.go
index 5ca3f592..d31fa20a 100644
--- a/provider/azure/azure_private_dns.go
+++ b/provider/azure/azure_private_dns.go
@@ -344,7 +344,7 @@ func (p *AzurePrivateDNSProvider) recordSetNameForZone(zone string, endpoint *en
 }
 
 func (p *AzurePrivateDNSProvider) newRecordSet(endpoint *endpoint.Endpoint) (privatedns.RecordSet, error) {
-	var ttl int64 = azureRecordTTL
+	var ttl int64 = defaultTTL
 	if endpoint.RecordTTL.IsConfigured() {
 		ttl = int64(endpoint.RecordTTL)
 	}
diff --git a/provider/azure/config.go b/provider/azure/config.go
index eca4ae0d..ac24f0b4 100644
--- a/provider/azure/config.go
+++ b/provider/azure/config.go
@@ -17,6 +17,7 @@ limitations under the License.
 package azure
 
 import (
+	"encoding/json"
 	"fmt"
 	"os"
 	"strings"
@@ -26,7 +27,6 @@ import (
 	"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
 	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
 	log "github.com/sirupsen/logrus"
-	"gopkg.in/yaml.v2"
 )
 
 // config represents common config items for Azure DNS and Azure Private DNS
@@ -50,9 +50,8 @@ func getConfig(configFile, subscriptionID, resourceGroup, userAssignedIdentityCl
 		return nil, fmt.Errorf("failed to read Azure config file '%s': %v", configFile, err)
 	}
 	cfg := &config{}
-	err = yaml.Unmarshal(contents, &cfg)
-	if err != nil {
-		return nil, fmt.Errorf("failed to read Azure config file '%s': %v", configFile, err)
+	if err := json.Unmarshal(contents, &cfg); err != nil {
+		return nil, fmt.Errorf("failed to parse Azure config file '%s': %v", configFile, err)
 	}
 	// If a subscription ID was given, override what was present in the config file
 	if subscriptionID != "" {
diff --git a/provider/azure/config_test.json b/provider/azure/fixtures/config_test.json
similarity index 95%
rename from provider/azure/config_test.json
rename to provider/azure/fixtures/config_test.json
index ddcaa769..36863ed7 100644
--- a/provider/azure/config_test.json
+++ b/provider/azure/fixtures/config_test.json
@@ -1,7 +1,7 @@
-{
-  "tenantId": "tenant",
-  "subscriptionId": "subscription",
-  "resourceGroup": "rg",
-  "aadClientId": "clientId",
-  "aadClientSecret": "clientSecret"
-}
+{
+  "tenantId": "tenant",
+  "subscriptionId": "subscription",
+  "resourceGroup": "rg",
+  "aadClientId": "clientId",
+  "aadClientSecret": "clientSecret"
+}
diff --git a/provider/cloudflare/cloudflare.go b/provider/cloudflare/cloudflare.go
index a163c4c7..e89d82cf 100644
--- a/provider/cloudflare/cloudflare.go
+++ b/provider/cloudflare/cloudflare.go
@@ -20,11 +20,13 @@ import (
 	"context"
 	"errors"
 	"fmt"
+	"maps"
 	"net/http"
 	"os"
+	"slices"
+	"sort"
 	"strconv"
 	"strings"
-	"time"
 
 	cloudflare "github.com/cloudflare/cloudflare-go"
 	log "github.com/sirupsen/logrus"
@@ -42,20 +44,20 @@ const (
 	cloudFlareDelete = "DELETE"
 	// cloudFlareUpdate is a ChangeAction enum value
 	cloudFlareUpdate = "UPDATE"
-	// defaultCloudFlareRecordTTL 1 = automatic
-	defaultCloudFlareRecordTTL = 1
+	// defaultTTL 1 = automatic
+	defaultTTL = 1
 )
 
 // We have to use pointers to bools now, as the upstream cloudflare-go library requires them
 // see: https://github.com/cloudflare/cloudflare-go/pull/595
 
-// proxyEnabled is a pointer to a bool true showing the record should be proxied through cloudflare
-var proxyEnabled *bool = boolPtr(true)
-
-// proxyDisabled is a pointer to a bool false showing the record should not be proxied through cloudflare
-var proxyDisabled *bool = boolPtr(false)
+var (
+	// proxyEnabled is a pointer to a bool true showing the record should be proxied through cloudflare
+	proxyEnabled *bool = boolPtr(true)
+	// proxyDisabled is a pointer to a bool false showing the record should not be proxied through cloudflare
+	proxyDisabled *bool = boolPtr(false)
+)
 
-// for faster getRecordID() lookup
 type DNSRecordIndex struct {
 	Name    string
 	Type    string
@@ -71,6 +73,11 @@ type CustomHostnameIndex struct {
 
 type CustomHostnamesMap map[CustomHostnameIndex]cloudflare.CustomHostname
 
+type DataLocalizationRegionalHostnameChange struct {
+	Action string
+	cloudflare.RegionalHostname
+}
+
 var recordTypeProxyNotSupported = map[string]bool{
 	"LOC": true,
 	"MX":  true,
@@ -91,6 +98,12 @@ var recordTypeCustomHostnameSupported = map[string]bool{
 	"CNAME": true,
 }
 
+var recordTypeRegionalHostnameSupported = map[string]bool{
+	"A":     true,
+	"AAAA":  true,
+	"CNAME": true,
+}
+
 // cloudFlareDNS is the subset of the CloudFlare API that we actually use.  Add methods as required. Signatures must match exactly.
 type cloudFlareDNS interface {
 	UserDetails(ctx context.Context) (cloudflare.User, error)
@@ -102,7 +115,9 @@ type cloudFlareDNS interface {
 	CreateDNSRecord(ctx context.Context, rc *cloudflare.ResourceContainer, rp cloudflare.CreateDNSRecordParams) (cloudflare.DNSRecord, error)
 	DeleteDNSRecord(ctx context.Context, rc *cloudflare.ResourceContainer, recordID string) error
 	UpdateDNSRecord(ctx context.Context, rc *cloudflare.ResourceContainer, rp cloudflare.UpdateDNSRecordParams) error
+	CreateDataLocalizationRegionalHostname(ctx context.Context, rc *cloudflare.ResourceContainer, rp cloudflare.CreateDataLocalizationRegionalHostnameParams) error
 	UpdateDataLocalizationRegionalHostname(ctx context.Context, rc *cloudflare.ResourceContainer, rp cloudflare.UpdateDataLocalizationRegionalHostnameParams) error
+	DeleteDataLocalizationRegionalHostname(ctx context.Context, rc *cloudflare.ResourceContainer, hostname string) error
 	CustomHostnames(ctx context.Context, zoneID string, page int, filter cloudflare.CustomHostname) ([]cloudflare.CustomHostname, cloudflare.ResultInfo, error)
 	DeleteCustomHostname(ctx context.Context, zoneID string, customHostnameID string) error
 	CreateCustomHostname(ctx context.Context, zoneID string, ch cloudflare.CustomHostname) (*cloudflare.CustomHostnameResponse, error)
@@ -137,11 +152,20 @@ func (z zoneService) UpdateDNSRecord(ctx context.Context, rc *cloudflare.Resourc
 	return err
 }
 
+func (z zoneService) CreateDataLocalizationRegionalHostname(ctx context.Context, rc *cloudflare.ResourceContainer, rp cloudflare.CreateDataLocalizationRegionalHostnameParams) error {
+	_, err := z.service.CreateDataLocalizationRegionalHostname(ctx, rc, rp)
+	return err
+}
+
 func (z zoneService) UpdateDataLocalizationRegionalHostname(ctx context.Context, rc *cloudflare.ResourceContainer, rp cloudflare.UpdateDataLocalizationRegionalHostnameParams) error {
 	_, err := z.service.UpdateDataLocalizationRegionalHostname(ctx, rc, rp)
 	return err
 }
 
+func (z zoneService) DeleteDataLocalizationRegionalHostname(ctx context.Context, rc *cloudflare.ResourceContainer, hostname string) error {
+	return z.service.DeleteDataLocalizationRegionalHostname(ctx, rc, hostname)
+}
+
 func (z zoneService) DeleteDNSRecord(ctx context.Context, rc *cloudflare.ResourceContainer, recordID string) error {
 	return z.service.DeleteDNSRecord(ctx, rc, recordID)
 }
@@ -182,11 +206,11 @@ type CloudFlareProvider struct {
 
 // cloudFlareChange differentiates between ChangActions
 type cloudFlareChange struct {
-	Action             string
-	ResourceRecord     cloudflare.DNSRecord
-	RegionalHostname   cloudflare.RegionalHostname
-	CustomHostname     cloudflare.CustomHostname
-	CustomHostnamePrev string
+	Action              string
+	ResourceRecord      cloudflare.DNSRecord
+	RegionalHostname    cloudflare.RegionalHostname
+	CustomHostnames     map[string]cloudflare.CustomHostname
+	CustomHostnamesPrev []string
 }
 
 // RecordParamsTypes is a typeset of the possible Record Params that can be passed to cloudflare-go library
@@ -205,11 +229,19 @@ func updateDNSRecordParam(cfc cloudFlareChange) cloudflare.UpdateDNSRecordParams
 	}
 }
 
+// createDataLocalizationRegionalHostnameParams is a function that returns the appropriate RegionalHostname Param based on the cloudFlareChange passed in
+func createDataLocalizationRegionalHostnameParams(rhc DataLocalizationRegionalHostnameChange) cloudflare.CreateDataLocalizationRegionalHostnameParams {
+	return cloudflare.CreateDataLocalizationRegionalHostnameParams{
+		Hostname:  rhc.Hostname,
+		RegionKey: rhc.RegionKey,
+	}
+}
+
 // updateDataLocalizationRegionalHostnameParams is a function that returns the appropriate RegionalHostname Param based on the cloudFlareChange passed in
-func updateDataLocalizationRegionalHostnameParams(cfc cloudFlareChange) cloudflare.UpdateDataLocalizationRegionalHostnameParams {
+func updateDataLocalizationRegionalHostnameParams(rhc DataLocalizationRegionalHostnameChange) cloudflare.UpdateDataLocalizationRegionalHostnameParams {
 	return cloudflare.UpdateDataLocalizationRegionalHostnameParams{
-		Hostname:  cfc.RegionalHostname.Hostname,
-		RegionKey: cfc.RegionalHostname.RegionKey,
+		Hostname:  rhc.Hostname,
+		RegionKey: rhc.RegionKey,
 	}
 }
 
@@ -247,8 +279,8 @@ func NewCloudFlareProvider(domainFilter endpoint.DomainFilter, zoneIDFilter prov
 	if err != nil {
 		return nil, fmt.Errorf("failed to initialize cloudflare provider: %w", err)
 	}
-	provider := &CloudFlareProvider{
-		// Client: config,
+
+	return &CloudFlareProvider{
 		Client:                zoneService{config},
 		domainFilter:          domainFilter,
 		zoneIDFilter:          zoneIDFilter,
@@ -257,13 +289,12 @@ func NewCloudFlareProvider(domainFilter endpoint.DomainFilter, zoneIDFilter prov
 		DryRun:                dryRun,
 		DNSRecordsPerPage:     dnsRecordsPerPage,
 		RegionKey:             regionKey,
-	}
-	return provider, nil
+	}, nil
 }
 
 // Zones returns the list of hosted zones.
 func (p *CloudFlareProvider) Zones(ctx context.Context) ([]cloudflare.Zone, error) {
-	result := []cloudflare.Zone{}
+	var result []cloudflare.Zone
 
 	// if there is a zoneIDfilter configured
 	// && if the filter isn't just a blank string (used in tests)
@@ -317,13 +348,14 @@ func (p *CloudFlareProvider) Records(ctx context.Context) ([]*endpoint.Endpoint,
 		return nil, err
 	}
 
-	endpoints := []*endpoint.Endpoint{}
+	var endpoints []*endpoint.Endpoint
 	for _, zone := range zones {
 		records, err := p.listDNSRecordsWithAutoPagination(ctx, zone.ID)
 		if err != nil {
 			return nil, err
 		}
 
+		// nil if custom hostnames are not enabled
 		chs, chErr := p.listCustomHostnamesWithPagination(ctx, zone.ID)
 		if chErr != nil {
 			return nil, chErr
@@ -340,11 +372,20 @@ func (p *CloudFlareProvider) Records(ctx context.Context) ([]*endpoint.Endpoint,
 
 // ApplyChanges applies a given set of changes in a given zone.
 func (p *CloudFlareProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error {
-	cloudflareChanges := []*cloudFlareChange{}
+	var cloudflareChanges []*cloudFlareChange
+
+	// if custom hostnames are enabled, deleting first allows to avoid conflicts with the new ones
+	if p.CustomHostnamesConfig.Enabled {
+		for _, e := range changes.Delete {
+			for _, target := range e.Targets {
+				cloudflareChanges = append(cloudflareChanges, p.newCloudFlareChange(cloudFlareDelete, e, target, nil))
+			}
+		}
+	}
 
-	for _, endpoint := range changes.Create {
-		for _, target := range endpoint.Targets {
-			cloudflareChanges = append(cloudflareChanges, p.newCloudFlareChange(cloudFlareCreate, endpoint, target, nil))
+	for _, e := range changes.Create {
+		for _, target := range e.Targets {
+			cloudflareChanges = append(cloudflareChanges, p.newCloudFlareChange(cloudFlareCreate, e, target, nil))
 		}
 	}
 
@@ -366,9 +407,12 @@ func (p *CloudFlareProvider) ApplyChanges(ctx context.Context, changes *plan.Cha
 		}
 	}
 
-	for _, endpoint := range changes.Delete {
-		for _, target := range endpoint.Targets {
-			cloudflareChanges = append(cloudflareChanges, p.newCloudFlareChange(cloudFlareDelete, endpoint, target, nil))
+	// TODO: consider deleting before creating even if custom hostnames are not in use
+	if !p.CustomHostnamesConfig.Enabled {
+		for _, e := range changes.Delete {
+			for _, target := range e.Targets {
+				cloudflareChanges = append(cloudflareChanges, p.newCloudFlareChange(cloudFlareDelete, e, target, nil))
+			}
 		}
 	}
 
@@ -380,70 +424,199 @@ func (p *CloudFlareProvider) submitCustomHostnameChanges(ctx context.Context, zo
 	failedChange := false
 	// return early if disabled
 	if !p.CustomHostnamesConfig.Enabled {
-		return !failedChange
+		return true
 	}
 
 	switch change.Action {
 	case cloudFlareUpdate:
 		if recordTypeCustomHostnameSupported[change.ResourceRecord.Type] {
-			prevChName := change.CustomHostnamePrev
-			newChName := change.CustomHostname.Hostname
-			if prevCh, err := getCustomHostname(chs, prevChName); err == nil {
-				prevChID := prevCh.ID
-				if prevChID != "" && prevChName != newChName {
-					log.WithFields(logFields).Infof("Removing previous custom hostname %q/%q", prevChID, prevChName)
-					chErr := p.Client.DeleteCustomHostname(ctx, zoneID, prevChID)
-					if chErr != nil {
-						failedChange = true
-						log.WithFields(logFields).Errorf("failed to remove previous custom hostname %q/%q: %v", prevChID, prevChName, chErr)
+			add, remove, _ := provider.Difference(change.CustomHostnamesPrev, slices.Collect(maps.Keys(change.CustomHostnames)))
+
+			for _, changeCH := range remove {
+				if prevCh, err := getCustomHostname(chs, changeCH); err == nil {
+					prevChID := prevCh.ID
+					if prevChID != "" {
+						log.WithFields(logFields).Infof("Removing previous custom hostname %q/%q", prevChID, changeCH)
+						chErr := p.Client.DeleteCustomHostname(ctx, zoneID, prevChID)
+						if chErr != nil {
+							failedChange = true
+							log.WithFields(logFields).Errorf("failed to remove previous custom hostname %q/%q: %v", prevChID, changeCH, chErr)
+						}
 					}
 				}
 			}
-			if newChName != "" && prevChName != newChName {
-				log.WithFields(logFields).Infof("Adding custom hostname %q", newChName)
-				_, chErr := p.Client.CreateCustomHostname(ctx, zoneID, change.CustomHostname)
+			for _, changeCH := range add {
+				log.WithFields(logFields).Infof("Adding custom hostname %q", changeCH)
+				_, chErr := p.Client.CreateCustomHostname(ctx, zoneID, change.CustomHostnames[changeCH])
 				if chErr != nil {
 					failedChange = true
-					log.WithFields(logFields).Errorf("failed to add custom hostname %q: %v", newChName, chErr)
+					log.WithFields(logFields).Errorf("failed to add custom hostname %q: %v", changeCH, chErr)
 				}
 			}
 		}
 	case cloudFlareDelete:
-		if recordTypeCustomHostnameSupported[change.ResourceRecord.Type] && change.CustomHostname.Hostname != "" {
-			log.WithFields(logFields).Infof("Deleting custom hostname %q", change.CustomHostname.Hostname)
-			if ch, err := getCustomHostname(chs, change.CustomHostname.Hostname); err == nil {
-				chID := ch.ID
-				chErr := p.Client.DeleteCustomHostname(ctx, zoneID, chID)
-				if chErr != nil {
-					failedChange = true
-					log.WithFields(logFields).Errorf("failed to delete custom hostname %q/%q: %v", chID, change.CustomHostname.Hostname, chErr)
+		for _, changeCH := range change.CustomHostnames {
+			if recordTypeCustomHostnameSupported[change.ResourceRecord.Type] && changeCH.Hostname != "" {
+				log.WithFields(logFields).Infof("Deleting custom hostname %q", changeCH.Hostname)
+				if ch, err := getCustomHostname(chs, changeCH.Hostname); err == nil {
+					chID := ch.ID
+					chErr := p.Client.DeleteCustomHostname(ctx, zoneID, chID)
+					if chErr != nil {
+						failedChange = true
+						log.WithFields(logFields).Errorf("failed to delete custom hostname %q/%q: %v", chID, changeCH.Hostname, chErr)
+					}
+				} else {
+					log.WithFields(logFields).Warnf("failed to delete custom hostname %q: %v", changeCH.Hostname, err)
 				}
-			} else {
-				log.WithFields(logFields).Warnf("failed to delete custom hostname %q: %v", change.CustomHostname.Hostname, err)
 			}
 		}
 	case cloudFlareCreate:
-		if recordTypeCustomHostnameSupported[change.ResourceRecord.Type] && change.CustomHostname.Hostname != "" {
-			log.WithFields(logFields).Infof("Creating custom hostname %q", change.CustomHostname.Hostname)
-			if ch, err := getCustomHostname(chs, change.CustomHostname.Hostname); err == nil {
-				if change.CustomHostname.CustomOriginServer == ch.CustomOriginServer {
-					log.WithFields(logFields).Warnf("custom hostname %q already exists with the same origin %q, continue", change.CustomHostname.Hostname, ch.CustomOriginServer)
+		for _, changeCH := range change.CustomHostnames {
+			if recordTypeCustomHostnameSupported[change.ResourceRecord.Type] && changeCH.Hostname != "" {
+				log.WithFields(logFields).Infof("Creating custom hostname %q", changeCH.Hostname)
+				if ch, err := getCustomHostname(chs, changeCH.Hostname); err == nil {
+					if changeCH.CustomOriginServer == ch.CustomOriginServer {
+						log.WithFields(logFields).Warnf("custom hostname %q already exists with the same origin %q, continue", changeCH.Hostname, ch.CustomOriginServer)
+					} else {
+						failedChange = true
+						log.WithFields(logFields).Errorf("failed to create custom hostname, %q already exists with origin %q", changeCH.Hostname, ch.CustomOriginServer)
+					}
 				} else {
-					failedChange = true
-					log.WithFields(logFields).Errorf("failed to create custom hostname, %q already exists with origin %q", change.CustomHostname.Hostname, ch.CustomOriginServer)
+					_, chErr := p.Client.CreateCustomHostname(ctx, zoneID, changeCH)
+					if chErr != nil {
+						failedChange = true
+						log.WithFields(logFields).Errorf("failed to create custom hostname %q: %v", changeCH.Hostname, chErr)
+					}
 				}
-			} else {
-				_, chErr := p.Client.CreateCustomHostname(ctx, zoneID, change.CustomHostname)
-				if chErr != nil {
-					failedChange = true
-					log.WithFields(logFields).Errorf("failed to create custom hostname %q: %v", change.CustomHostname.Hostname, chErr)
+			}
+		}
+	}
+	return !failedChange
+}
+
+// submitDataLocalizationRegionalHostnameChanges applies a set of data localization regional hostname changes, returns false if it fails
+func (p *CloudFlareProvider) submitDataLocalizationRegionalHostnameChanges(ctx context.Context, changes []DataLocalizationRegionalHostnameChange, resourceContainer *cloudflare.ResourceContainer) bool {
+	failedChange := false
+
+	for _, change := range changes {
+		logFields := log.Fields{
+			"hostname":   change.Hostname,
+			"region_key": change.RegionKey,
+			"action":     change.Action,
+			"zone":       resourceContainer.Identifier,
+		}
+		log.WithFields(logFields).Info("Changing regional hostname")
+		switch change.Action {
+		case cloudFlareCreate:
+			log.WithFields(logFields).Debug("Creating regional hostname")
+			if p.DryRun {
+				continue
+			}
+			regionalHostnameParam := createDataLocalizationRegionalHostnameParams(change)
+			err := p.Client.CreateDataLocalizationRegionalHostname(ctx, resourceContainer, regionalHostnameParam)
+			if err != nil {
+				var apiErr *cloudflare.Error
+				if errors.As(err, &apiErr) && apiErr.StatusCode == http.StatusConflict {
+					log.WithFields(logFields).Debug("Regional hostname already exists, updating instead")
+					params := updateDataLocalizationRegionalHostnameParams(change)
+					err := p.Client.UpdateDataLocalizationRegionalHostname(ctx, resourceContainer, params)
+					if err != nil {
+						failedChange = true
+						log.WithFields(logFields).Errorf("failed to update regional hostname: %v", err)
+					}
+					continue
 				}
+				failedChange = true
+				log.WithFields(logFields).Errorf("failed to create regional hostname: %v", err)
+			}
+		case cloudFlareUpdate:
+			log.WithFields(logFields).Debug("Updating regional hostname")
+			if p.DryRun {
+				continue
+			}
+			regionalHostnameParam := updateDataLocalizationRegionalHostnameParams(change)
+			err := p.Client.UpdateDataLocalizationRegionalHostname(ctx, resourceContainer, regionalHostnameParam)
+			if err != nil {
+				var apiErr *cloudflare.Error
+				if errors.As(err, &apiErr) && apiErr.StatusCode == http.StatusNotFound {
+					log.WithFields(logFields).Debug("Regional hostname not does not exists, creating instead")
+					params := createDataLocalizationRegionalHostnameParams(change)
+					err := p.Client.CreateDataLocalizationRegionalHostname(ctx, resourceContainer, params)
+					if err != nil {
+						failedChange = true
+						log.WithFields(logFields).Errorf("failed to create regional hostname: %v", err)
+					}
+					continue
+				}
+				failedChange = true
+				log.WithFields(logFields).Errorf("failed to update regional hostname: %v", err)
+			}
+		case cloudFlareDelete:
+			log.WithFields(logFields).Debug("Deleting regional hostname")
+			if p.DryRun {
+				continue
+			}
+			err := p.Client.DeleteDataLocalizationRegionalHostname(ctx, resourceContainer, change.Hostname)
+			if err != nil {
+				var apiErr *cloudflare.Error
+				if errors.As(err, &apiErr) && apiErr.StatusCode == http.StatusNotFound {
+					log.WithFields(logFields).Debug("Regional hostname does not exists, nothing to do")
+					continue
+				}
+				failedChange = true
+				log.WithFields(logFields).Errorf("failed to delete regional hostname: %v", err)
 			}
 		}
 	}
+
 	return !failedChange
 }
 
+// dataLocalizationRegionalHostnamesChanges processes a slice of cloudFlare changes and consolidates them
+// into a list of data localization regional hostname changes.
+// returns nil if no changes are needed
+func dataLocalizationRegionalHostnamesChanges(changes []*cloudFlareChange) ([]DataLocalizationRegionalHostnameChange, error) {
+	regionalHostnameChanges := make(map[string]DataLocalizationRegionalHostnameChange)
+	for _, change := range changes {
+		if change.RegionalHostname.Hostname == "" {
+			continue
+		}
+		if change.RegionalHostname.RegionKey == "" {
+			return nil, fmt.Errorf("region key is empty for regional hostname %q", change.RegionalHostname.Hostname)
+		}
+		regionalHostname, ok := regionalHostnameChanges[change.RegionalHostname.Hostname]
+		switch change.Action {
+		case cloudFlareCreate, cloudFlareUpdate:
+			if !ok {
+				regionalHostnameChanges[change.RegionalHostname.Hostname] = DataLocalizationRegionalHostnameChange{
+					Action:           change.Action,
+					RegionalHostname: change.RegionalHostname,
+				}
+				continue
+			}
+			if regionalHostname.RegionKey != change.RegionalHostname.RegionKey {
+				return nil, fmt.Errorf("conflicting region keys for regional hostname %q: %q and %q", change.RegionalHostname.Hostname, regionalHostname.RegionKey, change.RegionalHostname.RegionKey)
+			}
+			if (change.Action == cloudFlareUpdate && regionalHostname.Action != cloudFlareUpdate) ||
+				regionalHostname.Action == cloudFlareDelete {
+				regionalHostnameChanges[change.RegionalHostname.Hostname] = DataLocalizationRegionalHostnameChange{
+					Action:           cloudFlareUpdate,
+					RegionalHostname: change.RegionalHostname,
+				}
+			}
+		case cloudFlareDelete:
+			if !ok {
+				regionalHostnameChanges[change.RegionalHostname.Hostname] = DataLocalizationRegionalHostnameChange{
+					Action:           cloudFlareDelete,
+					RegionalHostname: change.RegionalHostname,
+				}
+				continue
+			}
+		}
+	}
+	return slices.Collect(maps.Values(regionalHostnameChanges)), nil
+}
+
 // submitChanges takes a zone and a collection of Changes and sends them as a single transaction.
 func (p *CloudFlareProvider) submitChanges(ctx context.Context, changes []*cloudFlareChange) error {
 	// return early if there is nothing to change
@@ -460,9 +633,11 @@ func (p *CloudFlareProvider) submitChanges(ctx context.Context, changes []*cloud
 	changesByZone := p.changesByZone(zones, changes)
 
 	var failedZones []string
-	for zoneID, changes := range changesByZone {
+	for zoneID, zoneChanges := range changesByZone {
 		var failedChange bool
-		for _, change := range changes {
+		resourceContainer := cloudflare.ZoneIdentifier(zoneID)
+
+		for _, change := range zoneChanges {
 			logFields := log.Fields{
 				"record": change.ResourceRecord.Name,
 				"type":   change.ResourceRecord.Type,
@@ -477,7 +652,6 @@ func (p *CloudFlareProvider) submitChanges(ctx context.Context, changes []*cloud
 				continue
 			}
 
-			resourceContainer := cloudflare.ZoneIdentifier(zoneID)
 			records, err := p.listDNSRecordsWithAutoPagination(ctx, zoneID)
 			if err != nil {
 				return fmt.Errorf("could not fetch records from zone, %w", err)
@@ -502,13 +676,6 @@ func (p *CloudFlareProvider) submitChanges(ctx context.Context, changes []*cloud
 					failedChange = true
 					log.WithFields(logFields).Errorf("failed to update record: %v", err)
 				}
-				if regionalHostnameParam := updateDataLocalizationRegionalHostnameParams(*change); regionalHostnameParam.RegionKey != "" {
-					regionalHostnameErr := p.Client.UpdateDataLocalizationRegionalHostname(ctx, resourceContainer, regionalHostnameParam)
-					if regionalHostnameErr != nil {
-						failedChange = true
-						log.WithFields(logFields).Errorf("failed to update record when editing region: %v", regionalHostnameErr)
-					}
-				}
 			} else if change.Action == cloudFlareDelete {
 				recordID := p.getRecordID(records, change.ResourceRecord)
 				if recordID == "" {
@@ -535,6 +702,19 @@ func (p *CloudFlareProvider) submitChanges(ctx context.Context, changes []*cloud
 				}
 			}
 		}
+
+		if regionalHostnamesChanges, err := dataLocalizationRegionalHostnamesChanges(zoneChanges); err == nil {
+			if !p.submitDataLocalizationRegionalHostnameChanges(ctx, regionalHostnamesChanges, resourceContainer) {
+				failedChange = true
+			}
+		} else {
+			logFields := log.Fields{
+				"zone": zoneID,
+			}
+			log.WithFields(logFields).Errorf("failed to build data localization regional hostname changes: %v", err)
+			failedChange = true
+		}
+
 		if failedChange {
 			failedZones = append(failedZones, zoneID)
 		}
@@ -549,7 +729,7 @@ func (p *CloudFlareProvider) submitChanges(ctx context.Context, changes []*cloud
 
 // AdjustEndpoints modifies the endpoints as needed by the specific provider
 func (p *CloudFlareProvider) AdjustEndpoints(endpoints []*endpoint.Endpoint) ([]*endpoint.Endpoint, error) {
-	adjustedEndpoints := []*endpoint.Endpoint{}
+	var adjustedEndpoints []*endpoint.Endpoint
 	for _, e := range endpoints {
 		proxied := shouldBeProxied(e, p.proxiedByDefault)
 		if proxied {
@@ -557,6 +737,17 @@ func (p *CloudFlareProvider) AdjustEndpoints(endpoints []*endpoint.Endpoint) ([]
 		}
 		e.SetProviderSpecificProperty(source.CloudflareProxiedKey, strconv.FormatBool(proxied))
 
+		if p.CustomHostnamesConfig.Enabled {
+			// sort custom hostnames in annotation to properly detect changes
+			if customHostnames := getEndpointCustomHostnames(e); len(customHostnames) > 1 {
+				sort.Strings(customHostnames)
+				e.SetProviderSpecificProperty(source.CloudflareCustomHostnameKey, strings.Join(customHostnames, ","))
+			}
+		} else {
+			// ignore custom hostnames annotations if not enabled
+			e.DeleteProviderSpecificProperty(source.CloudflareCustomHostnameKey)
+		}
+
 		adjustedEndpoints = append(adjustedEndpoints, e)
 	}
 	return adjustedEndpoints, nil
@@ -601,48 +792,53 @@ func getCustomHostname(chs CustomHostnamesMap, chName string) (cloudflare.Custom
 	return cloudflare.CustomHostname{}, fmt.Errorf("failed to get custom hostname: %q not found", chName)
 }
 
-func (p *CloudFlareProvider) newCloudFlareChange(action string, endpoint *endpoint.Endpoint, target string, current *endpoint.Endpoint) *cloudFlareChange {
-	ttl := defaultCloudFlareRecordTTL
-	proxied := shouldBeProxied(endpoint, p.proxiedByDefault)
+func (p *CloudFlareProvider) newCustomHostname(customHostname string, origin string) cloudflare.CustomHostname {
+	return cloudflare.CustomHostname{
+		Hostname:           customHostname,
+		CustomOriginServer: origin,
+		SSL:                getCustomHostnamesSSLOptions(p.CustomHostnamesConfig),
+	}
+}
+
+func (p *CloudFlareProvider) newCloudFlareChange(action string, ep *endpoint.Endpoint, target string, current *endpoint.Endpoint) *cloudFlareChange {
+	ttl := defaultTTL
+	proxied := shouldBeProxied(ep, p.proxiedByDefault)
 
-	if endpoint.RecordTTL.IsConfigured() {
-		ttl = int(endpoint.RecordTTL)
+	if ep.RecordTTL.IsConfigured() {
+		ttl = int(ep.RecordTTL)
 	}
-	dt := time.Now()
 
-	customHostnamePrev := ""
-	newCustomHostname := cloudflare.CustomHostname{}
+	prevCustomHostnames := []string{}
+	newCustomHostnames := map[string]cloudflare.CustomHostname{}
 	if p.CustomHostnamesConfig.Enabled {
 		if current != nil {
-			customHostnamePrev = getEndpointCustomHostname(current)
+			prevCustomHostnames = getEndpointCustomHostnames(current)
 		}
-		newCustomHostname = cloudflare.CustomHostname{
-			Hostname:           getEndpointCustomHostname(endpoint),
-			CustomOriginServer: endpoint.DNSName,
-			SSL:                getCustomHostnamesSSLOptions(p.CustomHostnamesConfig),
+		for _, v := range getEndpointCustomHostnames(ep) {
+			newCustomHostnames[v] = p.newCustomHostname(v, ep.DNSName)
+		}
+	}
+	regionalHostname := cloudflare.RegionalHostname{}
+	if regionKey := getRegionKey(ep, p.RegionKey); regionKey != "" {
+		regionalHostname = cloudflare.RegionalHostname{
+			Hostname:  ep.DNSName,
+			RegionKey: regionKey,
 		}
 	}
 	return &cloudFlareChange{
 		Action: action,
 		ResourceRecord: cloudflare.DNSRecord{
-			Name: endpoint.DNSName,
+			Name: ep.DNSName,
 			TTL:  ttl,
 			// We have to use pointers to bools now, as the upstream cloudflare-go library requires them
 			// see: https://github.com/cloudflare/cloudflare-go/pull/595
 			Proxied: &proxied,
-			Type:    endpoint.RecordType,
+			Type:    ep.RecordType,
 			Content: target,
-			Meta: map[string]interface{}{
-				"region": p.RegionKey,
-			},
 		},
-		RegionalHostname: cloudflare.RegionalHostname{
-			Hostname:  endpoint.DNSName,
-			RegionKey: p.RegionKey,
-			CreatedOn: &dt,
-		},
-		CustomHostnamePrev: customHostnamePrev,
-		CustomHostname:     newCustomHostname,
+		RegionalHostname:    regionalHostname,
+		CustomHostnamesPrev: prevCustomHostnames,
+		CustomHostnames:     newCustomHostnames,
 	}
 }
 
@@ -727,10 +923,10 @@ func getCustomHostnamesSSLOptions(customHostnamesConfig CustomHostnamesConfig) *
 	}
 }
 
-func shouldBeProxied(endpoint *endpoint.Endpoint, proxiedByDefault bool) bool {
+func shouldBeProxied(ep *endpoint.Endpoint, proxiedByDefault bool) bool {
 	proxied := proxiedByDefault
 
-	for _, v := range endpoint.ProviderSpecific {
+	for _, v := range ep.ProviderSpecific {
 		if v.Name == source.CloudflareProxiedKey {
 			b, err := strconv.ParseBool(v.Value)
 			if err != nil {
@@ -742,23 +938,37 @@ func shouldBeProxied(endpoint *endpoint.Endpoint, proxiedByDefault bool) bool {
 		}
 	}
 
-	if recordTypeProxyNotSupported[endpoint.RecordType] {
+	if recordTypeProxyNotSupported[ep.RecordType] {
 		proxied = false
 	}
 	return proxied
 }
 
-func getEndpointCustomHostname(endpoint *endpoint.Endpoint) string {
+func getRegionKey(endpoint *endpoint.Endpoint, defaultRegionKey string) string {
+	if !recordTypeRegionalHostnameSupported[endpoint.RecordType] {
+		return ""
+	}
+
 	for _, v := range endpoint.ProviderSpecific {
-		if v.Name == source.CloudflareCustomHostnameKey {
+		if v.Name == source.CloudflareRegionKey {
 			return v.Value
 		}
 	}
-	return ""
+	return defaultRegionKey
+}
+
+func getEndpointCustomHostnames(ep *endpoint.Endpoint) []string {
+	for _, v := range ep.ProviderSpecific {
+		if v.Name == source.CloudflareCustomHostnameKey {
+			customHostnames := strings.Split(v.Value, ",")
+			return customHostnames
+		}
+	}
+	return []string{}
 }
 
 func groupByNameAndTypeWithCustomHostnames(records DNSRecordsMap, chs CustomHostnamesMap) []*endpoint.Endpoint {
-	endpoints := []*endpoint.Endpoint{}
+	var endpoints []*endpoint.Endpoint
 
 	// group supported records by name and type
 	groups := map[string][]cloudflare.DNSRecord{}
@@ -777,14 +987,13 @@ func groupByNameAndTypeWithCustomHostnames(records DNSRecordsMap, chs CustomHost
 	}
 
 	// map custom origin to custom hostname, custom origin should match to a dns record
-	customOriginServers := map[string]string{}
+	customHostnames := map[string][]string{}
 
-	// only one latest custom hostname for a dns record would work; noop (chs is empty) if custom hostnames feature is not in use
 	for _, c := range chs {
-		customOriginServers[c.CustomOriginServer] = c.Hostname
+		customHostnames[c.CustomOriginServer] = append(customHostnames[c.CustomOriginServer], c.Hostname)
 	}
 
-	// create single endpoint with all the targets for each name/type
+	// create a single endpoint with all the targets for each name/type
 	for _, records := range groups {
 		if len(records) == 0 {
 			return endpoints
@@ -793,7 +1002,7 @@ func groupByNameAndTypeWithCustomHostnames(records DNSRecordsMap, chs CustomHost
 		for i, record := range records {
 			targets[i] = record.Content
 		}
-		ep := endpoint.NewEndpointWithTTL(
+		e := endpoint.NewEndpointWithTTL(
 			records[0].Name,
 			records[0].Type,
 			endpoint.TTL(records[0].TTL),
@@ -802,16 +1011,17 @@ func groupByNameAndTypeWithCustomHostnames(records DNSRecordsMap, chs CustomHost
 		if records[0].Proxied != nil {
 			proxied = *records[0].Proxied
 		}
-		if ep == nil {
+		if e == nil {
 			continue
 		}
-		ep = ep.WithProviderSpecific(source.CloudflareProxiedKey, strconv.FormatBool(proxied))
-		// noop (customOriginServers is empty) if custom hostnames feature is not in use
-		if customHostname, ok := customOriginServers[records[0].Name]; ok {
-			ep = ep.WithProviderSpecific(source.CloudflareCustomHostnameKey, customHostname)
+		e = e.WithProviderSpecific(source.CloudflareProxiedKey, strconv.FormatBool(proxied))
+		// noop (customHostnames is empty) if the custom hostnames feature is not in use
+		if customHostnames, ok := customHostnames[records[0].Name]; ok {
+			sort.Strings(customHostnames)
+			e = e.WithProviderSpecific(source.CloudflareCustomHostnameKey, strings.Join(customHostnames, ","))
 		}
 
-		endpoints = append(endpoints, ep)
+		endpoints = append(endpoints, e)
 	}
 
 	return endpoints
diff --git a/provider/coredns/coredns.go b/provider/coredns/coredns.go
index eeb545ae..18dc9cea 100644
--- a/provider/coredns/coredns.go
+++ b/provider/coredns/coredns.go
@@ -92,7 +92,7 @@ type etcdClient struct {
 
 var _ coreDNSClient = etcdClient{}
 
-// GetService return all Service records stored in etcd stored anywhere under the given key (recursively)
+// GetServices GetService return all Service records stored in etcd stored anywhere under the given key (recursively)
 func (c etcdClient) GetServices(prefix string) ([]*Service, error) {
 	ctx, cancel := context.WithTimeout(c.ctx, etcdTimeout)
 	defer cancel()
diff --git a/provider/digitalocean/digital_ocean.go b/provider/digitalocean/digital_ocean.go
index 40968131..2bac6dce 100644
--- a/provider/digitalocean/digital_ocean.go
+++ b/provider/digitalocean/digital_ocean.go
@@ -34,8 +34,8 @@ import (
 )
 
 const (
-	// digitalOceanRecordTTL is the default TTL value
-	digitalOceanRecordTTL = 300
+	// defaultTTL is the default TTL value
+	defaultTTL = 300
 )
 
 // DigitalOceanProvider is an implementation of Provider for Digital Ocean's DNS.
@@ -397,7 +397,7 @@ func getTTLFromEndpoint(ep *endpoint.Endpoint) int {
 	if ep.RecordTTL.IsConfigured() {
 		return int(ep.RecordTTL)
 	}
-	return digitalOceanRecordTTL
+	return defaultTTL
 }
 
 func endpointsByZone(zoneNameIDMapper provider.ZoneIDName, endpoints []*endpoint.Endpoint) map[string][]*endpoint.Endpoint {
diff --git a/provider/dnsimple/dnsimple.go b/provider/dnsimple/dnsimple.go
index 3a1554e7..0230cbab 100644
--- a/provider/dnsimple/dnsimple.go
+++ b/provider/dnsimple/dnsimple.go
@@ -33,7 +33,13 @@ import (
 	"sigs.k8s.io/external-dns/provider"
 )
 
-const dnsimpleRecordTTL = 3600 // Default TTL of 1 hour if not set (DNSimple's default)
+const (
+	dnsimpleCreate = "CREATE"
+	dnsimpleDelete = "DELETE"
+	dnsimpleUpdate = "UPDATE"
+
+	defaultTTL = 3600 // Default TTL of 1 hour if not set (DNSimple's default)
+)
 
 type dnsimpleIdentityService struct {
 	service *dnsimple.IdentityService
@@ -91,12 +97,6 @@ type dnsimpleChange struct {
 	ResourceRecordSet dnsimple.ZoneRecord
 }
 
-const (
-	dnsimpleCreate = "CREATE"
-	dnsimpleDelete = "DELETE"
-	dnsimpleUpdate = "UPDATE"
-)
-
 // NewDnsimpleProvider initializes a new Dnsimple based provider
 func NewDnsimpleProvider(domainFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, dryRun bool) (provider.Provider, error) {
 	oauthToken := os.Getenv("DNSIMPLE_OAUTH")
@@ -149,7 +149,7 @@ func ZonesFromZoneString(zonestring string) map[string]dnsimple.Zone {
 	return zones
 }
 
-// Returns a list of filtered Zones
+// Zones Return a list of filtered Zones
 func (p *dnsimpleProvider) Zones(ctx context.Context) (map[string]dnsimple.Zone, error) {
 	zones := make(map[string]dnsimple.Zone)
 
@@ -231,7 +231,7 @@ func (p *dnsimpleProvider) Records(ctx context.Context) (endpoints []*endpoint.E
 
 // newDnsimpleChange initializes a new change to dns records
 func newDnsimpleChange(action string, e *endpoint.Endpoint) *dnsimpleChange {
-	ttl := dnsimpleRecordTTL
+	ttl := defaultTTL
 	if e.RecordTTL.IsConfigured() {
 		ttl = int(e.RecordTTL)
 	}
diff --git a/provider/exoscale/exoscale.go b/provider/exoscale/exoscale.go
index 6e13f14f..c1404b29 100644
--- a/provider/exoscale/exoscale.go
+++ b/provider/exoscale/exoscale.go
@@ -181,7 +181,7 @@ func (ep *ExoscaleProvider) ApplyChanges(ctx context.Context, changes *plan.Chan
 	}
 
 	for _, epoint := range changes.UpdateOld {
-		// Since Exoscale "Patches", we ignore UpdateOld
+		// Since Exoscale "Patches", we've ignored UpdateOld
 		// We leave this logging here for information
 		log.Debugf("UPDATE-OLD (ignored) for epoint: %+v", epoint)
 	}
@@ -310,10 +310,10 @@ func (f *zoneFilter) EndpointZoneID(endpoint *endpoint.Endpoint, zones map[strin
 
 func merge(updateOld, updateNew []*endpoint.Endpoint) []*endpoint.Endpoint {
 	findMatch := func(template *endpoint.Endpoint) *endpoint.Endpoint {
-		for _, new := range updateNew {
-			if template.DNSName == new.DNSName &&
-				template.RecordType == new.RecordType {
-				return new
+		for _, record := range updateNew {
+			if template.DNSName == record.DNSName &&
+				template.RecordType == record.RecordType {
+				return record
 			}
 		}
 		return nil
@@ -323,7 +323,7 @@ func merge(updateOld, updateNew []*endpoint.Endpoint) []*endpoint.Endpoint {
 	for _, old := range updateOld {
 		matchingNew := findMatch(old)
 		if matchingNew == nil {
-			// no match, shouldn't happen
+			// no match shouldn't happen
 			continue
 		}
 
diff --git a/provider/gandi/gandi.go b/provider/gandi/gandi.go
index 63b193f8..37ed3460 100644
--- a/provider/gandi/gandi.go
+++ b/provider/gandi/gandi.go
@@ -33,7 +33,7 @@ const (
 	gandiCreate          = "CREATE"
 	gandiDelete          = "DELETE"
 	gandiUpdate          = "UPDATE"
-	gandiTTL             = 600
+	defaultTTL           = 600
 	gandiLiveDNSProvider = "livedns"
 )
 
@@ -255,7 +255,7 @@ func (p *GandiProvider) submitChanges(ctx context.Context, changes []*GandiChang
 
 func (p *GandiProvider) newGandiChanges(action string, endpoints []*endpoint.Endpoint) []*GandiChanges {
 	changes := make([]*GandiChanges, 0, len(endpoints))
-	ttl := gandiTTL
+	ttl := defaultTTL
 	for _, e := range endpoints {
 		if e.RecordTTL.IsConfigured() {
 			ttl = int(e.RecordTTL)
diff --git a/provider/godaddy/client.go b/provider/godaddy/client.go
index e84b1fea..4104087e 100644
--- a/provider/godaddy/client.go
+++ b/provider/godaddy/client.go
@@ -34,19 +34,18 @@ import (
 	"sigs.k8s.io/external-dns/pkg/apis/externaldns"
 )
 
-// DefaultTimeout api requests after 180s
-const DefaultTimeout = 180 * time.Second
+const (
+	ErrCodeQuotaExceeded = "QUOTA_EXCEEDED"
+
+	// DefaultTimeout api requests after
+	DefaultTimeout = 180 * time.Second
+)
 
 // Errors
 var (
 	ErrAPIDown = errors.New("godaddy: the GoDaddy API is down")
 )
 
-// error codes
-const (
-	ErrCodeQuotaExceeded = "QUOTA_EXCEEDED"
-)
-
 // APIError error
 type APIError struct {
 	Code    string
diff --git a/provider/godaddy/godaddy.go b/provider/godaddy/godaddy.go
index ede7bf15..c74f4bbe 100644
--- a/provider/godaddy/godaddy.go
+++ b/provider/godaddy/godaddy.go
@@ -19,8 +19,8 @@ package godaddy
 import (
 	"context"
 	"encoding/json"
-	"errors"
 	"fmt"
+	"slices"
 	"strings"
 
 	log "github.com/sirupsen/logrus"
@@ -32,10 +32,12 @@ import (
 )
 
 const (
-	gdMinimalTTL = 600
-	gdCreate     = 0
-	gdReplace    = 1
-	gdDelete     = 2
+	defaultTTL = 600
+	gdCreate   = 0
+	gdReplace  = 1
+	gdDelete   = 2
+
+	domainsURI = "/v1/domains?statuses=ACTIVE,PENDING_DNS_ACTIVE"
 )
 
 var actionNames = []string{
@@ -44,11 +46,6 @@ var actionNames = []string{
 	"delete",
 }
 
-const domainsURI = "/v1/domains?statuses=ACTIVE,PENDING_DNS_ACTIVE"
-
-// ErrRecordToMutateNotFound when ApplyChange has to update/delete and didn't found the record in the existing zone (Change with no record ID)
-var ErrRecordToMutateNotFound = errors.New("record to mutate not found in current zone")
-
 type gdClient interface {
 	Patch(string, interface{}, interface{}) error
 	Post(string, interface{}, interface{}) error
@@ -147,7 +144,7 @@ func NewGoDaddyProvider(ctx context.Context, domainFilter endpoint.DomainFilter,
 	return &GDProvider{
 		client:       client,
 		domainFilter: domainFilter,
-		ttl:          maxOf(gdMinimalTTL, ttl),
+		ttl:          maxOf(defaultTTL, ttl),
 		DryRun:       dryRun,
 	}, nil
 }
@@ -294,14 +291,14 @@ func (p *GDProvider) groupByNameAndType(zoneRecords []gdRecords) []*endpoint.End
 				recordName = strings.TrimPrefix(fmt.Sprintf("%s.%s", records[0].Name, zoneName), ".")
 			}
 
-			endpoint := endpoint.NewEndpointWithTTL(
+			ep := endpoint.NewEndpointWithTTL(
 				recordName,
 				records[0].Type,
 				endpoint.TTL(records[0].TTL),
 				targets...,
 			)
 
-			endpoints = append(endpoints, endpoint)
+			endpoints = append(endpoints, ep)
 		}
 	}
 
@@ -356,7 +353,7 @@ func (p *GDProvider) changeAllRecords(endpoints []gdEndpoint, zoneRecords []*gdR
 				dnsName = "@"
 			}
 
-			e.endpoint.RecordTTL = endpoint.TTL(maxOf(gdMinimalTTL, int64(e.endpoint.RecordTTL)))
+			e.endpoint.RecordTTL = endpoint.TTL(maxOf(defaultTTL, int64(e.endpoint.RecordTTL)))
 
 			if err := zoneRecord.applyEndpoint(e.action, p.client, *e.endpoint, dnsName, p.DryRun); err != nil {
 				log.Errorf("Unable to apply change %s on record %s type %s, %v", actionNames[e.action], dnsName, e.endpoint.RecordType, err)
@@ -584,8 +581,8 @@ func countTargets(p *plan.Changes) int {
 	count := 0
 
 	for _, endpoints := range changes {
-		for _, endpoint := range endpoints {
-			count += len(endpoint.Targets)
+		for _, ep := range endpoints {
+			count += len(ep.Targets)
 		}
 	}
 
@@ -593,15 +590,7 @@ func countTargets(p *plan.Changes) int {
 }
 
 func maxOf(vars ...int64) int64 {
-	max := vars[0]
-
-	for _, i := range vars {
-		if max < i {
-			max = i
-		}
-	}
-
-	return max
+	return slices.Max(vars)
 }
 
 func toString(obj interface{}) string {
diff --git a/provider/google/google.go b/provider/google/google.go
index a3222ad5..df0a7159 100644
--- a/provider/google/google.go
+++ b/provider/google/google.go
@@ -37,7 +37,7 @@ import (
 )
 
 const (
-	googleRecordTTL = 300
+	defaultTTL = 300
 )
 
 type managedZonesCreateCallInterface interface {
@@ -154,7 +154,7 @@ func NewGoogleProvider(ctx context.Context, project string, domainFilter endpoin
 
 	zoneTypeFilter := provider.NewZoneTypeFilter(zoneVisibility)
 
-	provider := &GoogleProvider{
+	return &GoogleProvider{
 		project:                  project,
 		dryRun:                   dryRun,
 		batchChangeSize:          batchChangeSize,
@@ -166,9 +166,7 @@ func NewGoogleProvider(ctx context.Context, project string, domainFilter endpoin
 		managedZonesClient:       managedZonesService{dnsClient.ManagedZones},
 		changesClient:            changesService{dnsClient.Changes},
 		ctx:                      ctx,
-	}
-
-	return provider, nil
+	}, nil
 }
 
 // Zones returns the list of hosted zones.
@@ -261,11 +259,11 @@ func (p *GoogleProvider) SupportedRecordType(recordType string) bool {
 
 // newFilteredRecords returns a collection of RecordSets based on the given endpoints and domainFilter.
 func (p *GoogleProvider) newFilteredRecords(endpoints []*endpoint.Endpoint) []*dns.ResourceRecordSet {
-	records := []*dns.ResourceRecordSet{}
+	var records []*dns.ResourceRecordSet
 
-	for _, endpoint := range endpoints {
-		if p.domainFilter.Match(endpoint.DNSName) {
-			records = append(records, newRecord(endpoint))
+	for _, ep := range endpoints {
+		if p.domainFilter.Match(ep.DNSName) {
+			records = append(records, newRecord(ep))
 		}
 	}
 
@@ -314,7 +312,7 @@ func (p *GoogleProvider) submitChange(ctx context.Context, change *dns.Change) e
 
 // batchChange separates a zone in multiple transaction.
 func batchChange(change *dns.Change, batchSize int) []*dns.Change {
-	changes := []*dns.Change{}
+	var changes []*dns.Change
 
 	if batchSize == 0 {
 		return append(changes, change)
@@ -452,7 +450,7 @@ func newRecord(ep *endpoint.Endpoint) *dns.ResourceRecordSet {
 	}
 
 	// no annotation results in a Ttl of 0, default to 300 for backwards-compatibility
-	var ttl int64 = googleRecordTTL
+	var ttl int64 = defaultTTL
 	if ep.RecordTTL.IsConfigured() {
 		ttl = int64(ep.RecordTTL)
 	}
diff --git a/provider/ibmcloud/ibmcloud.go b/provider/ibmcloud/ibmcloud.go
index f442c76a..85bc8ae7 100644
--- a/provider/ibmcloud/ibmcloud.go
+++ b/provider/ibmcloud/ibmcloud.go
@@ -29,7 +29,7 @@ import (
 	"github.com/IBM/networking-go-sdk/dnsrecordsv1"
 	"github.com/IBM/networking-go-sdk/dnssvcsv1"
 	"github.com/IBM/networking-go-sdk/zonesv1"
-	"gopkg.in/yaml.v2"
+	yaml "github.com/goccy/go-yaml"
 
 	log "github.com/sirupsen/logrus"
 
@@ -61,8 +61,8 @@ const (
 	recordDelete = "DELETE"
 	// recordUpdate is a ChangeAction enum value
 	recordUpdate = "UPDATE"
-	// defaultPublicRecordTTL 1 = automatic
-	defaultPublicRecordTTL = 1
+	// defaultTTL 1 = automatic
+	defaultTTL = 1
 
 	proxyFilter             = "ibmcloud-proxied"
 	vpcFilter               = "ibmcloud-vpc"
@@ -244,7 +244,7 @@ func (c *ibmcloudConfig) Validate(authenticator core.Authenticator, domainFilter
 			return service, isPrivate, fmt.Errorf("failed to initialize ibmcloud public zones client: %v", err)
 		}
 		if c.Endpoint != "" {
-			service.publicZonesService.SetServiceURL(c.Endpoint)
+			_ = service.publicZonesService.SetServiceURL(c.Endpoint)
 		}
 
 		zonesResp, _, err := service.publicZonesService.ListZones(&zonesv1.ListZonesOptions{})
@@ -277,7 +277,7 @@ func (c *ibmcloudConfig) Validate(authenticator core.Authenticator, domainFilter
 			return service, isPrivate, fmt.Errorf("failed to initialize ibmcloud public records client: %v", err)
 		}
 		if c.Endpoint != "" {
-			service.publicRecordsService.SetServiceURL(c.Endpoint)
+			_ = service.publicRecordsService.SetServiceURL(c.Endpoint)
 		}
 	case strings.Contains(crn.ServiceName, "dns-svcs"):
 		isPrivate = true
@@ -289,7 +289,7 @@ func (c *ibmcloudConfig) Validate(authenticator core.Authenticator, domainFilter
 			return service, isPrivate, fmt.Errorf("failed to initialize ibmcloud private records client: %v", err)
 		}
 		if c.Endpoint != "" {
-			service.privateDNSService.SetServiceURL(c.Endpoint)
+			_ = service.privateDNSService.SetServiceURL(c.Endpoint)
 		}
 	default:
 		return service, isPrivate, fmt.Errorf("IBM Cloud instance crn is not provided or invalid dns crn : %s", c.CRN)
@@ -322,7 +322,7 @@ func NewIBMCloudProvider(configFile string, domainFilter endpoint.DomainFilter,
 		return nil, err
 	}
 
-	provider := &IBMCloudProvider{
+	return &IBMCloudProvider{
 		Client:           client,
 		source:           source,
 		domainFilter:     domainFilter,
@@ -331,8 +331,7 @@ func NewIBMCloudProvider(configFile string, domainFilter endpoint.DomainFilter,
 		privateZone:      isPrivate,
 		proxiedByDefault: proxiedByDefault,
 		DryRun:           dryRun,
-	}
-	return provider, nil
+	}, nil
 }
 
 // Records gets the current records.
@@ -351,9 +350,9 @@ func (p *IBMCloudProvider) Records(ctx context.Context) (endpoints []*endpoint.E
 func (p *IBMCloudProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error {
 	log.Debugln("applying change...")
 	ibmcloudChanges := []*ibmcloudChange{}
-	for _, endpoint := range changes.Create {
-		for _, target := range endpoint.Targets {
-			ibmcloudChanges = append(ibmcloudChanges, p.newIBMCloudChange(recordCreate, endpoint, target))
+	for _, et := range changes.Create {
+		for _, target := range et.Targets {
+			ibmcloudChanges = append(ibmcloudChanges, p.newIBMCloudChange(recordCreate, et, target))
 		}
 	}
 
@@ -376,9 +375,9 @@ func (p *IBMCloudProvider) ApplyChanges(ctx context.Context, changes *plan.Chang
 		}
 	}
 
-	for _, endpoint := range changes.Delete {
-		for _, target := range endpoint.Targets {
-			ibmcloudChanges = append(ibmcloudChanges, p.newIBMCloudChange(recordDelete, endpoint, target))
+	for _, et := range changes.Delete {
+		for _, target := range et.Targets {
+			ibmcloudChanges = append(ibmcloudChanges, p.newIBMCloudChange(recordDelete, et, target))
 		}
 	}
 
@@ -680,15 +679,15 @@ func (p *IBMCloudProvider) privateRecords(ctx context.Context) ([]*endpoint.Endp
 		return nil, err
 	}
 	// Filter VPC annoation for private zone active
-	for _, source := range sources {
-		vpc = checkVPCAnnotation(source)
+	for _, src := range sources {
+		vpc = checkVPCAnnotation(src)
 		if len(vpc) > 0 {
 			log.Debugf("VPC found: %s", vpc)
 			break
 		}
 	}
 
-	endpoints := []*endpoint.Endpoint{}
+	var endpoints []*endpoint.Endpoint
 	for _, zone := range zones {
 		if len(vpc) > 0 && *zone.State == zoneStatePendingNetwork {
 			log.Debugf("active zone: %s", *zone.ID)
@@ -730,7 +729,7 @@ GETRECORDS:
 }
 
 func (p *IBMCloudProvider) groupPrivateRecords(records []dnssvcsv1.ResourceRecord) []*endpoint.Endpoint {
-	endpoints := []*endpoint.Endpoint{}
+	var endpoints []*endpoint.Endpoint
 	// group supported records by name and type
 	groups := map[string][]dnssvcsv1.ResourceRecord{}
 	for _, r := range records {
@@ -806,7 +805,7 @@ func (p *IBMCloudProvider) getPrivateRecordID(records []dnssvcsv1.ResourceRecord
 }
 
 func (p *IBMCloudProvider) newIBMCloudChange(action string, endpoint *endpoint.Endpoint, target string) *ibmcloudChange {
-	ttl := defaultPublicRecordTTL
+	ttl := defaultTTL
 	proxied := shouldBeProxied(endpoint, p.proxiedByDefault)
 
 	if endpoint.RecordTTL.IsConfigured() {
@@ -984,7 +983,7 @@ func checkVPCAnnotation(endpoint *endpoint.Endpoint) string {
 	for _, v := range endpoint.ProviderSpecific {
 		if v.Name == vpcFilter {
 			vpcCrn, err := crn.Parse(v.Value)
-			if vpcCrn.ResourceType != "vpc" || err != nil {
+			if err != nil || vpcCrn.ResourceType != "vpc" {
 				log.Errorf("Failed to parse vpc [%s]: %v", v.Value, err)
 			} else {
 				vpc = v.Value
@@ -995,6 +994,7 @@ func checkVPCAnnotation(endpoint *endpoint.Endpoint) string {
 	return vpc
 }
 
+// TODO: could be shared function
 func isNil(i interface{}) bool {
 	if i == nil {
 		return true
@@ -1002,6 +1002,7 @@ func isNil(i interface{}) bool {
 	switch reflect.TypeOf(i).Kind() {
 	case reflect.Ptr, reflect.Map, reflect.Array, reflect.Chan, reflect.Slice:
 		return reflect.ValueOf(i).IsNil()
+	default:
+		return false
 	}
-	return false
 }
diff --git a/provider/linode/linode.go b/provider/linode/linode.go
index 71b839f1..0688b08d 100644
--- a/provider/linode/linode.go
+++ b/provider/linode/linode.go
@@ -96,15 +96,14 @@ func NewLinodeProvider(domainFilter endpoint.DomainFilter, dryRun bool) (*Linode
 	linodeClient := linodego.NewClient(oauth2Client)
 	linodeClient.SetUserAgent(fmt.Sprintf("%s linodego/%s", externaldns.UserAgent(), linodego.Version))
 
-	provider := &LinodeProvider{
+	return &LinodeProvider{
 		Client:       &linodeClient,
 		domainFilter: domainFilter,
 		DryRun:       dryRun,
-	}
-	return provider, nil
+	}, nil
 }
 
-// Zones returns the list of hosted zones.
+// Zones return the list of hosted zones.
 func (p *LinodeProvider) Zones(ctx context.Context) ([]linodego.Domain, error) {
 	zones, err := p.fetchZones(ctx)
 	if err != nil {
diff --git a/provider/ns1/ns1.go b/provider/ns1/ns1.go
index 14f2b3c8..a6f207a8 100644
--- a/provider/ns1/ns1.go
+++ b/provider/ns1/ns1.go
@@ -40,8 +40,8 @@ const (
 	ns1Delete = "DELETE"
 	// ns1Update is a ChangeAction enum value
 	ns1Update = "UPDATE"
-	// ns1DefaultTTL is the default ttl for ttls that are not set
-	ns1DefaultTTL = 10
+	// defaultTTL is the default ttl for ttls that are not set
+	defaultTTL = 10
 )
 
 // NS1DomainClient is a subset of the NS1 API the the provider uses, to ease testing
@@ -136,13 +136,12 @@ func newNS1ProviderWithHTTPClient(config NS1Config, client *http.Client) (*NS1Pr
 
 	apiClient := api.NewClient(client, clientArgs...)
 
-	provider := &NS1Provider{
+	return &NS1Provider{
 		client:        NS1DomainService{apiClient},
 		domainFilter:  config.DomainFilter,
 		zoneIDFilter:  config.ZoneIDFilter,
 		minTTLSeconds: config.MinTTLSeconds,
-	}
-	return provider, nil
+	}, nil
 }
 
 // Records returns the endpoints this provider knows about
@@ -184,7 +183,7 @@ func (p *NS1Provider) ns1BuildRecord(zoneName string, change *ns1Change) *dns.Re
 		record.AddAnswer(dns.NewAnswer(strings.Split(v, " ")))
 	}
 	// set default ttl, but respect minTTLSeconds
-	ttl := ns1DefaultTTL
+	ttl := defaultTTL
 	if p.minTTLSeconds > ttl {
 		ttl = p.minTTLSeconds
 	}
@@ -257,7 +256,7 @@ func (p *NS1Provider) zonesFiltered() ([]*dns.Zone, error) {
 		return nil, err
 	}
 
-	toReturn := []*dns.Zone{}
+	var toReturn []*dns.Zone
 
 	for _, z := range zones {
 		if p.domainFilter.Match(z.Zone) && p.zoneIDFilter.Match(z.ID) {
@@ -292,10 +291,10 @@ func (p *NS1Provider) ApplyChanges(ctx context.Context, changes *plan.Changes) e
 func newNS1Changes(action string, endpoints []*endpoint.Endpoint) []*ns1Change {
 	changes := make([]*ns1Change, 0, len(endpoints))
 
-	for _, endpoint := range endpoints {
+	for _, ep := range endpoints {
 		changes = append(changes, &ns1Change{
 			Action:   action,
-			Endpoint: endpoint,
+			Endpoint: ep,
 		},
 		)
 	}
diff --git a/provider/oci/oci.go b/provider/oci/oci.go
index c526be63..4fd4c104 100644
--- a/provider/oci/oci.go
+++ b/provider/oci/oci.go
@@ -18,24 +18,24 @@ package oci
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"os"
 	"strings"
 	"time"
 
+	"github.com/goccy/go-yaml"
 	"github.com/oracle/oci-go-sdk/v65/common"
 	"github.com/oracle/oci-go-sdk/v65/common/auth"
 	"github.com/oracle/oci-go-sdk/v65/dns"
-	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
-	yaml "gopkg.in/yaml.v2"
 
 	"sigs.k8s.io/external-dns/endpoint"
 	"sigs.k8s.io/external-dns/plan"
 	"sigs.k8s.io/external-dns/provider"
 )
 
-const ociRecordTTL = 300
+const defaultTTL = 300
 
 // OCIAuthConfig holds connection parameters for the OCI API.
 type OCIAuthConfig struct {
@@ -153,7 +153,7 @@ func (p *OCIProvider) zones(ctx context.Context) (map[string]dns.ZoneSummary, er
 	}
 	zones := make(map[string]dns.ZoneSummary)
 	scopes := []dns.GetZoneScopeEnum{dns.GetZoneScopeEnum(p.zoneScope)}
-	// If zone scope is empty, list all zones types.
+	// If the zone scope is empty, list all zones types.
 	if p.zoneScope == "" {
 		scopes = dns.GetGetZoneScopeEnumValues()
 	}
@@ -186,13 +186,13 @@ func mergeEndpointsMultiTargets(endpoints []*endpoint.Endpoint) []*endpoint.Endp
 
 	// Otherwise, create a new list of endpoints with the consolidated targets.
 	var mergedEndpoints []*endpoint.Endpoint
-	for _, endpoints := range endpointsByNameType {
-		dnsName := endpoints[0].DNSName
-		recordType := endpoints[0].RecordType
-		recordTTL := endpoints[0].RecordTTL
+	for _, ep := range endpointsByNameType {
+		dnsName := ep[0].DNSName
+		recordType := ep[0].RecordType
+		recordTTL := ep[0].RecordTTL
 
-		targets := make([]string, len(endpoints))
-		for i, e := range endpoints {
+		targets := make([]string, len(ep))
+		for i, e := range ep {
 			targets[i] = e.Targets[0]
 		}
 
@@ -232,7 +232,7 @@ func (p *OCIProvider) addPaginatedZones(ctx context.Context, zones map[string]dn
 }
 
 func (p *OCIProvider) newFilteredRecordOperations(endpoints []*endpoint.Endpoint, opType dns.RecordOperationOperationEnum) []dns.RecordOperation {
-	ops := []dns.RecordOperation{}
+	var ops []dns.RecordOperation
 	for _, ep := range endpoints {
 		if ep == nil {
 			continue
@@ -261,7 +261,7 @@ func (p *OCIProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error)
 		return nil, provider.NewSoftError(fmt.Errorf("getting zones: %w", err))
 	}
 
-	endpoints := []*endpoint.Endpoint{}
+	var endpoints []*endpoint.Endpoint
 	for _, zone := range zones {
 		var page *string
 		for {
@@ -303,7 +303,7 @@ func (p *OCIProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error)
 func (p *OCIProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error {
 	log.Debugf("Processing changes: %+v", changes)
 
-	ops := []dns.RecordOperation{}
+	var ops []dns.RecordOperation
 	ops = append(ops, p.newFilteredRecordOperations(changes.Create, dns.RecordOperationOperationAdd)...)
 
 	ops = append(ops, p.newFilteredRecordOperations(changes.UpdateNew, dns.RecordOperationOperationAdd)...)
@@ -349,7 +349,7 @@ func (p *OCIProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) e
 
 // AdjustEndpoints modifies the endpoints as needed by the specific provider
 func (p *OCIProvider) AdjustEndpoints(endpoints []*endpoint.Endpoint) ([]*endpoint.Endpoint, error) {
-	adjustedEndpoints := []*endpoint.Endpoint{}
+	var adjustedEndpoints []*endpoint.Endpoint
 	for _, e := range endpoints {
 		// OCI DNS does not support the set-identifier attribute, so we remove it to avoid plan failure
 		if e.SetIdentifier != "" {
@@ -370,7 +370,7 @@ func newRecordOperation(ep *endpoint.Endpoint, opType dns.RecordOperationOperati
 	}
 	rdata := strings.Join(targets, " ")
 
-	ttl := ociRecordTTL
+	ttl := defaultTTL
 	if ep.RecordTTL.IsConfigured() {
 		ttl = int(ep.RecordTTL)
 	}
diff --git a/provider/ovh/ovh.go b/provider/ovh/ovh.go
index 5b7eb8ee..f7b67a65 100644
--- a/provider/ovh/ovh.go
+++ b/provider/ovh/ovh.go
@@ -41,8 +41,8 @@ import (
 )
 
 const (
-	ovhDefaultTTL = 0
-	ovhCreate     = iota
+	defaultTTL = 0
+	ovhCreate  = iota
 	ovhDelete
 	ovhUpdate
 )
@@ -324,9 +324,9 @@ func (p *OVHProvider) change(ctx context.Context, change ovhChange) error {
 			return nil
 		}
 		return p.client.PutWithContext(ctx, fmt.Sprintf("/domain/zone/%s/record/%d", url.PathEscape(change.Zone), change.ID), change.ovhRecordFieldUpdate, nil)
+	default:
+		return nil
 	}
-
-	return nil
 }
 
 func (p *OVHProvider) invalidateCache(zone string) {
@@ -357,8 +357,8 @@ func (p *OVHProvider) zonesRecords(ctx context.Context) ([]string, []ovhRecord,
 }
 
 func (p *OVHProvider) zones(ctx context.Context) ([]string, error) {
-	zones := []string{}
-	filteredZones := []string{}
+	var zones []string
+	var filteredZones []string
 
 	p.apiRateLimiter.Take()
 	if err := p.client.GetWithContext(ctx, "/domain/zone", &zones); err != nil {
@@ -476,25 +476,25 @@ func ovhGroupByNameAndType(records []ovhRecord) []*endpoint.Endpoint {
 
 	// create single endpoint with all the targets for each name/type
 	for _, records := range groups {
-		targets := []string{}
+		var targets []string
 		for _, record := range records {
 			targets = append(targets, record.Target)
 		}
-		endpoint := endpoint.NewEndpointWithTTL(
+		ep := endpoint.NewEndpointWithTTL(
 			strings.TrimPrefix(records[0].SubDomain+"."+records[0].Zone, "."),
 			records[0].FieldType,
 			endpoint.TTL(records[0].TTL),
 			targets...,
 		)
-		endpoints = append(endpoints, endpoint)
+		endpoints = append(endpoints, ep)
 	}
 
 	return endpoints
 }
 
 func (p OVHProvider) newOvhChangeCreateDelete(action int, endpoints []*endpoint.Endpoint, zone string, existingRecords []ovhRecord) ([]ovhChange, []ovhRecord) {
-	ovhChanges := []ovhChange{}
-	toDeleteIds := []int{}
+	var ovhChanges []ovhChange
+	var toDeleteIds []int
 
 	for _, e := range endpoints {
 		for _, target := range e.Targets {
@@ -506,7 +506,7 @@ func (p OVHProvider) newOvhChangeCreateDelete(action int, endpoints []*endpoint.
 						FieldType: e.RecordType,
 						ovhRecordFieldUpdate: ovhRecordFieldUpdate{
 							SubDomain: convertDNSNameIntoSubDomain(e.DNSName, zone),
-							TTL:       ovhDefaultTTL,
+							TTL:       defaultTTL,
 							Target:    target,
 						},
 					},
@@ -579,13 +579,13 @@ func (p OVHProvider) newOvhChangeUpdate(endpointsOld []*endpoint.Endpoint, endpo
 		}
 	}
 
-	changes := []ovhChange{}
+	var changes []ovhChange
 
 	for id := range oldEndpointByTypeAndName {
 		oldRecords := slices.Clone(oldRecordsInZone[id])
 		endpointsNew := newEndpointByTypeAndName[id]
 
-		toInsertTarget := []string{}
+		var toInsertTarget []string
 
 		for _, target := range endpointsNew.Targets {
 			var toDelete = -1
@@ -617,7 +617,7 @@ func (p OVHProvider) newOvhChangeUpdate(endpointsOld []*endpoint.Endpoint, endpo
 			if endpointsNew.RecordTTL.IsConfigured() {
 				record.TTL = int64(endpointsNew.RecordTTL)
 			} else {
-				record.TTL = ovhDefaultTTL
+				record.TTL = defaultTTL
 			}
 
 			change := ovhChange{
@@ -634,7 +634,7 @@ func (p OVHProvider) newOvhChangeUpdate(endpointsOld []*endpoint.Endpoint, endpo
 
 		if len(toInsertTarget) > 0 {
 			for _, target := range toInsertTarget {
-				recordTTL := int64(ovhDefaultTTL)
+				recordTTL := int64(defaultTTL)
 				if endpointsNew.RecordTTL.IsConfigured() {
 					recordTTL = int64(endpointsNew.RecordTTL)
 				}
@@ -680,6 +680,8 @@ func (c *ovhChange) String() string {
 		action = "update"
 	case ovhDelete:
 		action = "delete"
+	default:
+		action = "unknown"
 	}
 
 	if c.ID != 0 {
diff --git a/provider/pihole/clientV6.go b/provider/pihole/clientV6.go
index ae6ae399..ebaaabd6 100644
--- a/provider/pihole/clientV6.go
+++ b/provider/pihole/clientV6.go
@@ -25,6 +25,7 @@ import (
 	"fmt"
 	"io"
 	"net/http"
+	"net/netip"
 	"net/url"
 	"strconv"
 	"strings"
@@ -63,6 +64,7 @@ func newPiholeClientV6(cfg PiholeConfig) (piholeAPI, error) {
 			},
 		},
 	}
+
 	cl := instrumented_http.NewClient(httpClient, &instrumented_http.Callbacks{})
 
 	p := &piholeClientV6{
@@ -114,6 +116,32 @@ func (p *piholeClientV6) getConfigValue(ctx context.Context, rtype string) ([]st
 	return results, nil
 }
 
+/**
+ * isValidIPv4 checks if the given IP address is a valid IPv4 address.
+ * It returns true if the IP address is valid, false otherwise.
+ * If the IP address is in IPv6 format, it will return false.
+ */
+func isValidIPv4(ip string) bool {
+	addr, err := netip.ParseAddr(ip)
+	if err != nil {
+		return false
+	}
+	return addr.Is4()
+}
+
+/**
+ * isValidIPv6 checks if the given IP address is a valid IPv6 address.
+ * It returns true if the IP address is valid, false otherwise.
+ * If the IP address is in IPv6 with dual format y:y:y:y:y:y:x.x.x.x. , it will return true.
+ */
+func isValidIPv6(ip string) bool {
+	addr, err := netip.ParseAddr(ip)
+	if err != nil {
+		return false
+	}
+	return addr.Is6()
+}
+
 func (p *piholeClientV6) listRecords(ctx context.Context, rtype string) ([]*endpoint.Endpoint, error) {
 	out := make([]*endpoint.Endpoint, 0)
 	results, err := p.getConfigValue(ctx, rtype)
@@ -126,42 +154,39 @@ func (p *piholeClientV6) listRecords(ctx context.Context, rtype string) ([]*endp
 			return r == ' ' || r == ','
 		})
 		if len(recs) < 2 {
-			log.Warnf("skipping record %s: invalid format", rec)
+			log.Warnf("skipping record %s: invalid format received from PiHole", rec)
 			continue
 		}
 		var DNSName, Target string
-		var Ttl endpoint.TTL = 0
+		var Ttl = endpoint.TTL(0)
 		// A/AAAA record format is target(IP) DNSName
 		DNSName, Target = recs[1], recs[0]
-
 		switch rtype {
 		case endpoint.RecordTypeA:
-			if strings.Contains(Target, ":") {
+			//PiHole return A and AAAA records. Filter to only keep the A records
+			if !isValidIPv4(Target) {
 				continue
 			}
 		case endpoint.RecordTypeAAAA:
-			if strings.Contains(Target, ".") {
+			//PiHole return A and AAAA records. Filter to only keep the AAAA records
+			if !isValidIPv6(Target) {
 				continue
 			}
 		case endpoint.RecordTypeCNAME:
-			// CNAME format is DNSName,target
+			//PiHole return only CNAME records.
+			// CNAME format is DNSName,target, ttl?
 			DNSName, Target = recs[0], recs[1]
 			if len(recs) == 3 { // TTL is present
 				// Parse string to int64 first
 				if ttlInt, err := strconv.ParseInt(recs[2], 10, 64); err == nil {
 					Ttl = endpoint.TTL(ttlInt)
 				} else {
-					log.Warnf("failed to parse TTL value '%s': %v; using a TTL of %d", recs[2], err, Ttl)
+					log.Warnf("failed to parse TTL value received from PiHole '%s': %v; using a TTL of %d", recs[2], err, Ttl)
 				}
 			}
 		}
 
-		out = append(out, &endpoint.Endpoint{
-			DNSName:    DNSName,
-			Targets:    []string{Target},
-			RecordTTL:  Ttl,
-			RecordType: rtype,
-		})
+		out = append(out, endpoint.NewEndpointWithTTL(DNSName, rtype, Ttl, Target))
 	}
 	return out, nil
 }
@@ -375,7 +400,13 @@ func (p *piholeClientV6) do(req *http.Request) ([]byte, error) {
 		if err := json.Unmarshal(jRes, &apiError); err != nil {
 			return nil, fmt.Errorf("failed to unmarshal error response: %w", err)
 		}
-		log.Debugf("Error on request %s", req.Body)
+		if log.IsLevelEnabled(log.DebugLevel) {
+			log.Debugf("Error on request %s", req.URL)
+			if req.Body != nil {
+				log.Debugf("Body of the request %s", req.Body)
+			}
+		}
+
 		if res.StatusCode == http.StatusUnauthorized && p.token != "" {
 			tryCount := 1
 			maxRetries := 3
diff --git a/provider/plural/plural.go b/provider/plural/plural.go
index 9f5a7715..691c7c68 100644
--- a/provider/plural/plural.go
+++ b/provider/plural/plural.go
@@ -45,29 +45,25 @@ type RecordChange struct {
 
 func NewPluralProvider(cluster, provider string) (*PluralProvider, error) {
 	token := os.Getenv("PLURAL_ACCESS_TOKEN")
-	endpoint := os.Getenv("PLURAL_ENDPOINT")
-
 	if token == "" {
 		return nil, fmt.Errorf("no plural access token provided, you must set the PLURAL_ACCESS_TOKEN env var")
 	}
 
 	config := &Config{
 		Token:    token,
-		Endpoint: endpoint,
+		Endpoint: os.Getenv("PLURAL_ENDPOINT"),
 		Cluster:  cluster,
 		Provider: provider,
 	}
 
-	client, err := NewClient(config)
+	cl, err := NewClient(config)
 	if err != nil {
 		return nil, err
 	}
 
-	prov := &PluralProvider{
-		Client: client,
-	}
-
-	return prov, nil
+	return &PluralProvider{
+		Client: cl,
+	}, nil
 }
 
 func (p *PluralProvider) Records(_ context.Context) (endpoints []*endpoint.Endpoint, err error) {
@@ -89,8 +85,8 @@ func (p *PluralProvider) AdjustEndpoints(endpoints []*endpoint.Endpoint) ([]*end
 
 func (p *PluralProvider) ApplyChanges(_ context.Context, diffs *plan.Changes) error {
 	var changes []*RecordChange
-	for _, endpoint := range diffs.Create {
-		changes = append(changes, makeChange(CreateAction, endpoint.Targets, endpoint))
+	for _, ep := range diffs.Create {
+		changes = append(changes, makeChange(CreateAction, ep.Targets, ep))
 	}
 
 	for _, desired := range diffs.UpdateNew {
diff --git a/provider/rfc2136/rfc2136.go b/provider/rfc2136/rfc2136.go
index 40ec52b3..8b1b58d5 100644
--- a/provider/rfc2136/rfc2136.go
+++ b/provider/rfc2136/rfc2136.go
@@ -19,6 +19,7 @@ package rfc2136
 import (
 	"context"
 	"crypto/tls"
+	"errors"
 	"fmt"
 	"math/rand"
 	"net"
@@ -32,7 +33,6 @@ import (
 	"github.com/bodgit/tsig/gss"
 	"github.com/miekg/dns"
 
-	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 
 	"sigs.k8s.io/external-dns/endpoint"
@@ -116,7 +116,7 @@ type rfc2136Actions interface {
 func NewRfc2136Provider(hosts []string, port int, zoneNames []string, insecure bool, keyName string, secret string, secretAlg string, axfr bool, domainFilter endpoint.DomainFilter, dryRun bool, minTTL time.Duration, createPTR bool, gssTsig bool, krb5Username string, krb5Password string, krb5Realm string, batchChangeSize int, tlsConfig TLSConfig, loadBalancingStrategy string, actions rfc2136Actions) (provider.Provider, error) {
 	secretAlgChecked, ok := tsigAlgs[secretAlg]
 	if !ok && !insecure && !gssTsig {
-		return nil, errors.Errorf("%s is not supported TSIG algorithm", secretAlg)
+		return nil, fmt.Errorf("%s is not supported TSIG algorithm", secretAlg)
 	}
 
 	// Set zone to root if no set
@@ -307,7 +307,7 @@ func (r *rfc2136Provider) List() ([]dns.RR, error) {
 
 			for e := range env {
 				if e.Error != nil {
-					if e.Error == dns.ErrSoa {
+					if errors.Is(e.Error, dns.ErrSoa) {
 						log.Error("AXFR error: unexpected response received from the server")
 					} else {
 						log.Errorf("AXFR error: %v", e.Error)
@@ -342,8 +342,6 @@ func (r *rfc2136Provider) RemoveReverseRecord(ip string, hostname string) error
 }
 
 func (r *rfc2136Provider) GenerateReverseRecord(ip string, hostname string) []*endpoint.Endpoint {
-	// Find the zone for the PTR record
-	// zone := findMsgZone(&endpoint.Endpoint{DNSName: ip}, p.ptrZoneNames)
 	// Generate PTR notation record starting from the IP address
 	var records []*endpoint.Endpoint
 
@@ -364,7 +362,7 @@ func (r *rfc2136Provider) GenerateReverseRecord(ip string, hostname string) []*e
 func (r *rfc2136Provider) ApplyChanges(ctx context.Context, changes *plan.Changes) error {
 	log.Debugf("ApplyChanges (Create: %d, UpdateOld: %d, UpdateNew: %d, Delete: %d)", len(changes.Create), len(changes.UpdateOld), len(changes.UpdateNew), len(changes.Delete))
 
-	var errors []error
+	var errs []error
 
 	for c, chunk := range chunkBy(changes.Create, r.batchChangeSize) {
 		log.Debugf("Processing batch %d of create changes", c)
@@ -397,7 +395,7 @@ func (r *rfc2136Provider) ApplyChanges(ctx context.Context, changes *plan.Change
 			if len(z.Ns) > 0 {
 				if err := r.actions.SendMessage(z); err != nil {
 					log.Errorf("RFC2136 create record failed: %v", err)
-					errors = append(errors, err)
+					errs = append(errs, err)
 					continue
 				}
 			}
@@ -436,7 +434,7 @@ func (r *rfc2136Provider) ApplyChanges(ctx context.Context, changes *plan.Change
 			if len(z.Ns) > 0 {
 				if err := r.actions.SendMessage(z); err != nil {
 					log.Errorf("RFC2136 update record failed: %v", err)
-					errors = append(errors, err)
+					errs = append(errs, err)
 					continue
 				}
 			}
@@ -473,15 +471,15 @@ func (r *rfc2136Provider) ApplyChanges(ctx context.Context, changes *plan.Change
 			if len(z.Ns) > 0 {
 				if err := r.actions.SendMessage(z); err != nil {
 					log.Errorf("RFC2136 delete record failed: %v", err)
-					errors = append(errors, err)
+					errs = append(errs, err)
 					continue
 				}
 			}
 		}
 	}
 
-	if len(errors) > 0 {
-		return fmt.Errorf("RFC2136 had errors in one or more of its batches: %v", errors)
+	if len(errs) > 0 {
+		return fmt.Errorf("RFC2136 had errors in one or more of its batches: %v", errs)
 	}
 
 	return nil
diff --git a/provider/scaleway/scaleway.go b/provider/scaleway/scaleway.go
index 87663e28..6ffe8acd 100644
--- a/provider/scaleway/scaleway.go
+++ b/provider/scaleway/scaleway.go
@@ -34,7 +34,7 @@ import (
 )
 
 const (
-	scalewyRecordTTL        uint32 = 300
+	defaultTTL              uint32 = 300
 	scalewayDefaultPriority uint32 = 0
 	scalewayPriorityKey     string = "scw/priority"
 )
@@ -110,7 +110,7 @@ func (p *ScalewayProvider) AdjustEndpoints(endpoints []*endpoint.Endpoint) ([]*e
 	for i := range endpoints {
 		eps[i] = endpoints[i]
 		if !eps[i].RecordTTL.IsConfigured() {
-			eps[i].RecordTTL = endpoint.TTL(scalewyRecordTTL)
+			eps[i].RecordTTL = endpoint.TTL(defaultTTL)
 		}
 		if _, ok := eps[i].GetProviderSpecificProperty(scalewayPriorityKey); !ok {
 			eps[i] = eps[i].WithProviderSpecific(scalewayPriorityKey, fmt.Sprintf("%d", scalewayDefaultPriority))
@@ -300,7 +300,7 @@ func getCompleteZoneName(zone *domain.DNSZone) string {
 
 func endpointToScalewayRecords(zoneName string, ep *endpoint.Endpoint) []*domain.Record {
 	// no annotation results in a TTL of 0, default to 300 for consistency with other providers
-	ttl := scalewyRecordTTL
+	ttl := defaultTTL
 	if ep.RecordTTL.IsConfigured() {
 		ttl = uint32(ep.RecordTTL)
 	}
diff --git a/provider/transip/transip.go b/provider/transip/transip.go
index af899238..ea392d11 100644
--- a/provider/transip/transip.go
+++ b/provider/transip/transip.go
@@ -34,7 +34,7 @@ import (
 const (
 	// 60 seconds is the current minimal TTL for TransIP and will replace unconfigured
 	// TTL's for Endpoints
-	transipMinimalValidTTL = 60
+	defaultTTL = 60
 )
 
 // TransIPProvider is an implementation of Provider for TransIP.
@@ -336,11 +336,11 @@ func recordNameForEndpoint(ep *endpoint.Endpoint, zoneName string) string {
 }
 
 // getMinimalValidTTL returns max between given Endpoint's RecordTTL and
-// transipMinimalValidTTL
+// defaultTTL
 func getMinimalValidTTL(ep *endpoint.Endpoint) int {
-	// TTL cannot be lower than transipMinimalValidTTL
-	if ep.RecordTTL < transipMinimalValidTTL {
-		return transipMinimalValidTTL
+	// TTL cannot be lower than defaultTTL
+	if ep.RecordTTL < defaultTTL {
+		return defaultTTL
 	}
 
 	return int(ep.RecordTTL)
diff --git a/provider/ultradns/ultradns.go b/provider/ultradns/ultradns.go
index 9303813c..1b2f2297 100644
--- a/provider/ultradns/ultradns.go
+++ b/provider/ultradns/ultradns.go
@@ -39,23 +39,20 @@ const (
 	rdPoolOrder    = "ROUND_ROBIN"
 )
 
-// global variables
-var sbPoolRunProbes = true
-
 var (
 	sbPoolActOnProbes = true
 	ultradnsPoolType  = "rdpool"
 	accountName       string
+	sbPoolRunProbes   = true
+	// Setting custom headers for ultradns api calls
+	customHeader = []udnssdk.CustomHeader{
+		{
+			Key:   "UltraClient",
+			Value: "kube-client",
+		},
+	}
 )
 
-// Setting custom headers for ultradns api calls
-var customHeader = []udnssdk.CustomHeader{
-	{
-		Key:   "UltraClient",
-		Value: "kube-client",
-	},
-}
-
 // UltraDNSProvider struct
 type UltraDNSProvider struct {
 	provider.BaseProvider
@@ -128,13 +125,11 @@ func NewUltraDNSProvider(domainFilter endpoint.DomainFilter, dryRun bool) (*Ultr
 		return nil, fmt.Errorf("connection cannot be established")
 	}
 
-	provider := &UltraDNSProvider{
+	return &UltraDNSProvider{
 		client:       *client,
 		domainFilter: domainFilter,
 		dryRun:       dryRun,
-	}
-
-	return provider, nil
+	}, nil
 }
 
 // Zones returns list of hosted zones
@@ -216,7 +211,7 @@ func (p *UltraDNSProvider) fetchRecords(ctx context.Context, k udnssdk.RRSetKey)
 	maxerrs := 5
 	waittime := 5 * time.Second
 
-	rrsets := []udnssdk.RRSet{}
+	var rrsets []udnssdk.RRSet
 	errcnt := 0
 	offset := 0
 	limit := 1000
diff --git a/provider/webhook/api/httpapi.go b/provider/webhook/api/httpapi.go
index 717fee7f..2dbb3a19 100644
--- a/provider/webhook/api/httpapi.go
+++ b/provider/webhook/api/httpapi.go
@@ -33,6 +33,9 @@ import (
 const (
 	MediaTypeFormatAndVersion = "application/external.dns.webhook+json;version=1"
 	ContentTypeHeader         = "Content-Type"
+	UrlAdjustEndpoints        = "/adjustendpoints"
+	UrlApplyChanges           = "/applychanges"
+	UrlRecords                = "/records"
 )
 
 type WebhookServer struct {
@@ -121,8 +124,8 @@ func StartHTTPApi(provider provider.Provider, startedChan chan struct{}, readTim
 
 	m := http.NewServeMux()
 	m.HandleFunc("/", p.NegotiateHandler)
-	m.HandleFunc("/records", p.RecordsHandler)
-	m.HandleFunc("/adjustendpoints", p.AdjustEndpointsHandler)
+	m.HandleFunc(UrlRecords, p.RecordsHandler)
+	m.HandleFunc(UrlAdjustEndpoints, p.AdjustEndpointsHandler)
 
 	s := &http.Server{
 		Addr:         providerPort,
diff --git a/provider/webhook/webhook.go b/provider/webhook/webhook.go
index 1a1558d4..4b7d020c 100644
--- a/provider/webhook/webhook.go
+++ b/provider/webhook/webhook.go
@@ -30,7 +30,7 @@ import (
 	"sigs.k8s.io/external-dns/provider"
 	webhookapi "sigs.k8s.io/external-dns/provider/webhook/api"
 
-	"github.com/cenkalti/backoff/v4"
+	"github.com/cenkalti/backoff/v5"
 	"github.com/prometheus/client_golang/prometheus"
 	log "github.com/sirupsen/logrus"
 )
@@ -113,45 +113,30 @@ func NewWebhookProvider(u string) (*WebhookProvider, error) {
 	}
 
 	// negotiate API information
-	req, err := http.NewRequest("GET", u, nil)
+	req, err := http.NewRequest(http.MethodGet, u, nil)
 	if err != nil {
 		return nil, err
 	}
 	req.Header.Set(acceptHeader, webhookapi.MediaTypeFormatAndVersion)
 
 	client := &http.Client{}
-	var resp *http.Response
-	err = backoff.Retry(func() error {
-		resp, err = client.Do(req)
-		if err != nil {
-			log.Debugf("Failed to connect to webhook: %v", err)
-			return err
-		}
-		// we currently only use 200 as success, but considering okay all 2XX for future usage
-		if resp.StatusCode >= 300 && resp.StatusCode < 500 {
-			return backoff.Permanent(fmt.Errorf("status code < 500"))
-		}
-		return nil
-	}, backoff.WithMaxRetries(backoff.NewExponentialBackOff(), maxRetries))
 
+	resp, err := requestWithRetry(client, req)
 	if err != nil {
 		return nil, fmt.Errorf("failed to connect to webhook: %v", err)
 	}
-
-	contentType := resp.Header.Get(webhookapi.ContentTypeHeader)
-
 	// read the serialized DomainFilter from the response body and set it in the webhook provider struct
 	defer resp.Body.Close()
 
+	if ct := resp.Header.Get(webhookapi.ContentTypeHeader); ct != webhookapi.MediaTypeFormatAndVersion {
+		return nil, fmt.Errorf("wrong content type returned from server: %s", ct)
+	}
+
 	df := endpoint.DomainFilter{}
 	if err := json.NewDecoder(resp.Body).Decode(&df); err != nil {
 		return nil, fmt.Errorf("failed to unmarshal response body of DomainFilter: %v", err)
 	}
 
-	if contentType != webhookapi.MediaTypeFormatAndVersion {
-		return nil, fmt.Errorf("wrong content type returned from server: %s", contentType)
-	}
-
 	return &WebhookProvider{
 		client:          client,
 		remoteServerURL: parsedURL,
@@ -159,12 +144,28 @@ func NewWebhookProvider(u string) (*WebhookProvider, error) {
 	}, nil
 }
 
+func requestWithRetry(client *http.Client, req *http.Request) (*http.Response, error) {
+	resp, err := backoff.Retry(context.Background(), func() (*http.Response, error) {
+		resp, err := client.Do(req)
+		if err != nil {
+			log.Debugf("Failed to connect to webhook: %v", err)
+			return nil, err
+		}
+		// we currently only use 200 as success, but considering okay all 2XX for future usage
+		if resp.StatusCode >= http.StatusMultipleChoices && resp.StatusCode < http.StatusInternalServerError {
+			return nil, backoff.Permanent(fmt.Errorf("status code < %d", http.StatusInternalServerError))
+		}
+		return resp, nil
+	}, backoff.WithMaxTries(maxRetries))
+	return resp, err
+}
+
 // Records will make a GET call to remoteServerURL/records and return the results
 func (p WebhookProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error) {
 	recordsRequestsGauge.Gauge.Inc()
 	u := p.remoteServerURL.JoinPath("records").String()
 
-	req, err := http.NewRequest("GET", u, nil)
+	req, err := http.NewRequest(http.MethodGet, u, nil)
 	if err != nil {
 		recordsErrorsGauge.Gauge.Inc()
 		log.Debugf("Failed to create request: %s", err.Error())
@@ -189,7 +190,7 @@ func (p WebhookProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, err
 		return nil, err
 	}
 
-	endpoints := []*endpoint.Endpoint{}
+	var endpoints []*endpoint.Endpoint
 	if err := json.NewDecoder(resp.Body).Decode(&endpoints); err != nil {
 		recordsErrorsGauge.Gauge.Inc()
 		log.Debugf("Failed to decode response body: %s", err.Error())
@@ -201,7 +202,7 @@ func (p WebhookProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, err
 // ApplyChanges will make a POST to remoteServerURL/records with the changes
 func (p WebhookProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error {
 	applyChangesRequestsGauge.Gauge.Inc()
-	u := p.remoteServerURL.JoinPath("records").String()
+	u := p.remoteServerURL.JoinPath(webhookapi.UrlRecords).String()
 
 	b := new(bytes.Buffer)
 	if err := json.NewEncoder(b).Encode(changes); err != nil {
@@ -210,7 +211,7 @@ func (p WebhookProvider) ApplyChanges(ctx context.Context, changes *plan.Changes
 		return err
 	}
 
-	req, err := http.NewRequest("POST", u, b)
+	req, err := http.NewRequest(http.MethodPost, u, b)
 	if err != nil {
 		applyChangesErrorsGauge.Gauge.Inc()
 		log.Debugf("Failed to create request: %s", err.Error())
@@ -225,6 +226,7 @@ func (p WebhookProvider) ApplyChanges(ctx context.Context, changes *plan.Changes
 		log.Debugf("Failed to perform request: %s", err.Error())
 		return err
 	}
+
 	defer resp.Body.Close()
 
 	if resp.StatusCode != http.StatusNoContent {
@@ -240,12 +242,12 @@ func (p WebhookProvider) ApplyChanges(ctx context.Context, changes *plan.Changes
 }
 
 // AdjustEndpoints will call the provider doing a POST on `/adjustendpoints` which will return a list of modified endpoints
-// based on a provider specific requirement.
+// based on a provider-specific requirement.
 // This method returns an empty slice in case there is a technical error on the provider's side so that no endpoints will be considered.
 func (p WebhookProvider) AdjustEndpoints(e []*endpoint.Endpoint) ([]*endpoint.Endpoint, error) {
 	adjustEndpointsRequestsGauge.Gauge.Inc()
-	endpoints := []*endpoint.Endpoint{}
-	u, err := url.JoinPath(p.remoteServerURL.String(), "adjustendpoints")
+	var endpoints []*endpoint.Endpoint
+	u, err := url.JoinPath(p.remoteServerURL.String(), webhookapi.UrlAdjustEndpoints)
 	if err != nil {
 		adjustEndpointsErrorsGauge.Gauge.Inc()
 		log.Debugf("Failed to join path, %s", err)
@@ -259,7 +261,7 @@ func (p WebhookProvider) AdjustEndpoints(e []*endpoint.Endpoint) ([]*endpoint.En
 		return nil, err
 	}
 
-	req, err := http.NewRequest("POST", u, b)
+	req, err := http.NewRequest(http.MethodPost, u, b)
 	if err != nil {
 		adjustEndpointsErrorsGauge.Gauge.Inc()
 		log.Debugf("Failed to create new HTTP request, %s", err)
diff --git a/provider/zonefinder.go b/provider/zonefinder.go
index 6a07646c..a81f997b 100644
--- a/provider/zonefinder.go
+++ b/provider/zonefinder.go
@@ -29,12 +29,34 @@ func (z ZoneIDName) Add(zoneID, zoneName string) {
 	z[zoneID] = zoneName
 }
 
+// FindZone identifies the most suitable DNS zone for a given hostname.
+// It returns the zone ID and name that best match the hostname.
+//
+// The function processes the hostname by splitting it into labels and
+// converting each label to its Unicode form using IDNA (Internationalized
+// Domain Names for Applications) standards.
+//
+// Labels containing underscores ('_') are skipped during Unicode conversion.
+// This is because underscores are often used in special DNS records (e.g.,
+// SRV records as per RFC 2782, or TXT record for services) that are not
+// IDNA-aware and cannot represent non-ASCII labels. Skipping these labels
+// ensures compatibility with such use cases.
 func (z ZoneIDName) FindZone(hostname string) (suitableZoneID, suitableZoneName string) {
-	name, err := idna.Lookup.ToUnicode(hostname)
-	if err != nil {
-		log.Warnf("Failed to convert hostname '%s' to its Unicode form: %v", hostname, err)
-		name = hostname
+	var name string
+	domain_labels := strings.Split(hostname, ".")
+	for i, label := range domain_labels {
+		if strings.Contains(label, "_") {
+			continue
+		}
+		convertedLabel, err := idna.Lookup.ToUnicode(label)
+		if err != nil {
+			log.Warnf("Failed to convert label '%s' of hostname '%s' to its Unicode form: %v", label, hostname, err)
+			convertedLabel = label
+		}
+		domain_labels[i] = convertedLabel
 	}
+	name = strings.Join(domain_labels, ".")
+
 	for zoneID, zoneName := range z {
 		if name == zoneName || strings.HasSuffix(name, "."+zoneName) {
 			if suitableZoneName == "" || len(zoneName) > len(suitableZoneName) {
diff --git a/registry/dynamodb.go b/registry/dynamodb.go
index 2088fda5..5b83ceeb 100644
--- a/registry/dynamodb.go
+++ b/registry/dynamodb.go
@@ -300,12 +300,12 @@ func (im *DynamoDBRegistry) ApplyChanges(ctx context.Context, changes *plan.Chan
 				if err != nil {
 					return err
 				}
-				for i, endpoint := range filteredChanges.Create {
-					if endpoint.Key() == key {
-						log.Infof("Skipping endpoint %v because owner does not match", endpoint)
+				for i, ep := range filteredChanges.Create {
+					if ep.Key() == key {
+						log.Infof("Skipping endpoint %v because owner does not match", ep)
 						filteredChanges.Create = append(filteredChanges.Create[:i], filteredChanges.Create[i+1:]...)
 						// The dynamodb insertion failed; remove from our cache.
-						im.removeFromCache(endpoint)
+						im.removeFromCache(ep)
 						delete(im.labels, key)
 						return nil
 					}
@@ -466,7 +466,7 @@ func toDynamoLabels(labels endpoint.Labels) dynamodbtypes.AttributeValue {
 	return &dynamodbtypes.AttributeValueMemberM{Value: labelMap}
 }
 
-func (im *DynamoDBRegistry) appendInsert(statements []dynamodbtypes.BatchStatementRequest, key endpoint.EndpointKey, new endpoint.Labels) []dynamodbtypes.BatchStatementRequest {
+func (im *DynamoDBRegistry) appendInsert(statements []dynamodbtypes.BatchStatementRequest, key endpoint.EndpointKey, newL endpoint.Labels) []dynamodbtypes.BatchStatementRequest {
 	return append(statements, dynamodbtypes.BatchStatementRequest{
 		Statement:      aws.String(fmt.Sprintf("INSERT INTO %q VALUE {'k':?, 'o':?, 'l':?}", im.table)),
 		ConsistentRead: aws.Bool(true),
@@ -475,16 +475,16 @@ func (im *DynamoDBRegistry) appendInsert(statements []dynamodbtypes.BatchStateme
 			&dynamodbtypes.AttributeValueMemberS{
 				Value: im.ownerID,
 			},
-			toDynamoLabels(new),
+			toDynamoLabels(newL),
 		},
 	})
 }
 
-func (im *DynamoDBRegistry) appendUpdate(statements []dynamodbtypes.BatchStatementRequest, key endpoint.EndpointKey, old endpoint.Labels, new endpoint.Labels) []dynamodbtypes.BatchStatementRequest {
-	if len(old) == len(new) {
+func (im *DynamoDBRegistry) appendUpdate(statements []dynamodbtypes.BatchStatementRequest, key endpoint.EndpointKey, old endpoint.Labels, newE endpoint.Labels) []dynamodbtypes.BatchStatementRequest {
+	if len(old) == len(newE) {
 		equal := true
 		for k, v := range old {
-			if newV, exists := new[k]; !exists || v != newV {
+			if newV, exists := newE[k]; !exists || v != newV {
 				equal = false
 				break
 			}
@@ -497,7 +497,7 @@ func (im *DynamoDBRegistry) appendUpdate(statements []dynamodbtypes.BatchStateme
 	return append(statements, dynamodbtypes.BatchStatementRequest{
 		Statement: aws.String(fmt.Sprintf("UPDATE %q SET \"l\"=? WHERE \"k\"=?", im.table)),
 		Parameters: []dynamodbtypes.AttributeValue{
-			toDynamoLabels(new),
+			toDynamoLabels(newE),
 			toDynamoKey(key),
 		},
 	})
diff --git a/scripts/install-tools.sh b/scripts/install-tools.sh
new file mode 100755
index 00000000..56b44077
--- /dev/null
+++ b/scripts/install-tools.sh
@@ -0,0 +1,95 @@
+#!/usr/bin/env bash
+
+# Copyright 2025 The Kubernetes Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# renovate: datasource=github-releases depName=kubernetes-sigs/controller-tools
+CONTROLLER_TOOLS_GENERATOR_VERSION=v0.15.0
+# renovate: datasource=github-releases depName=golangci/golangci-lint
+GOLANG_CI_LINTER_VERSION=v2.0.2
+
+# Execute
+# scripts/install-tools.sh
+# scripts/install-tools.sh -h
+# scripts/install-tools.sh --generator
+# scripts/install-tools.sh --golangci
+
+show_help() {
+cat << EOF
+'external-dns' helm linter helper commands
+
+Usage: $(basename "$0") <options>
+    -h, --help          Display help
+    --generator         Install generator
+    --golangci         Install golangci linter
+EOF
+}
+
+install_generator() {
+  # https://github.com/kubernetes-sigs/controller-tools/blob/main/cmd/controller-gen/main.go
+  local install=false
+  if [[ -x $(which controller-gen) ]]; then
+      local version=$(controller-gen --version | sed 's/Version: //')
+      if [[ "${version}" == "${CONTROLLER_TOOLS_GENERATOR_VERSION}" ]]; then
+          install=false
+        else
+          install=true
+      fi
+    else
+      install=true
+  fi
+  if [[ "$install" == true ]]; then
+      set -ex ;\
+	    go install sigs.k8s.io/controller-tools/cmd/controller-gen@${CONTROLLER_TOOLS_GENERATOR_VERSION} ;
+  fi
+}
+
+install_golangci() {
+  local install=false
+  if [[ -x $(which golangci-lint) ]]; then
+      local version=$(golangci-lint version --short)
+      if [[ "${version}" == "${GOLANG_CI_LINTER_VERSION#v}" ]]; then
+          install=false
+        else
+          install=true
+      fi
+    else
+      install=true
+  fi
+  if [[ "$install" == true ]]; then
+      curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/cc3567e3127d8530afb69be1b7bd20ba9ebcc7c1/install.sh \
+        | sh -s -- -b $(go env GOPATH)/bin "${GOLANG_CI_LINTER_VERSION}"
+  fi
+}
+
+function main() {
+  case $1 in
+    --generator)
+      install_generator
+      ;;
+    --golangci)
+      install_golangci
+      ;;
+    -h|--help)
+      show_help
+      ;;
+    *)
+      echo "unknown sub-command" >&2
+      show_help
+      exit 1
+      ;;
+  esac
+}
+
+main "$@"
diff --git a/source/ambassador_host.go b/source/ambassador_host.go
index cb050121..0ddc8911 100644
--- a/source/ambassador_host.go
+++ b/source/ambassador_host.go
@@ -18,12 +18,12 @@ package source
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"sort"
 	"strings"
 
 	ambassador "github.com/datawire/ambassador/pkg/api/getambassador.io/v2"
-	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -96,7 +96,7 @@ func NewAmbassadorHostSource(
 
 	uc, err := newUnstructuredConverter()
 	if err != nil {
-		return nil, errors.Wrapf(err, "failed to setup Unstructured Converter")
+		return nil, fmt.Errorf("failed to setup Unstructured Converter: %w", err)
 	}
 
 	return &ambassadorHostSource{
@@ -137,10 +137,10 @@ func (sc *ambassadorHostSource) Endpoints(ctx context.Context) ([]*endpoint.Endp
 	// Filter Ambassador Hosts
 	ambassadorHosts, err = sc.filterByAnnotations(ambassadorHosts)
 	if err != nil {
-		return nil, errors.Wrap(err, "failed to filter Ambassador Hosts by annotation")
+		return nil, fmt.Errorf("failed to filter Ambassador Hosts by annotation: %w", err)
 	}
 
-	endpoints := []*endpoint.Endpoint{}
+	var endpoints []*endpoint.Endpoint
 
 	for _, host := range ambassadorHosts {
 		fullname := fmt.Sprintf("%s/%s", host.Namespace, host.Name)
@@ -260,7 +260,7 @@ func parseAmbLoadBalancerService(service string) (namespace, name string, err er
 	}
 
 	// If we got here, this string is simply ill-formatted. Return an error.
-	return "", "", errors.New(fmt.Sprintf("invalid external-dns service: %s", service))
+	return "", "", fmt.Errorf("invalid external-dns service: %s", service)
 }
 
 func (sc *ambassadorHostSource) AddEventHandler(ctx context.Context, handler func()) {
diff --git a/source/contour_httpproxy.go b/source/contour_httpproxy.go
index fb028dc6..823b91e3 100644
--- a/source/contour_httpproxy.go
+++ b/source/contour_httpproxy.go
@@ -18,11 +18,11 @@ package source
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"sort"
 	"text/template"
 
-	"github.com/pkg/errors"
 	projectcontour "github.com/projectcontour/contour/apis/projectcontour/v1"
 	log "github.com/sirupsen/logrus"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -87,7 +87,7 @@ func NewContourHTTPProxySource(
 
 	uc, err := NewUnstructuredConverter()
 	if err != nil {
-		return nil, errors.Wrap(err, "failed to setup Unstructured Converter")
+		return nil, fmt.Errorf("failed to setup Unstructured Converter: %w", err)
 	}
 
 	return &httpProxySource{
@@ -121,14 +121,14 @@ func (sc *httpProxySource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint,
 		hpConverted := &projectcontour.HTTPProxy{}
 		err := sc.unstructuredConverter.scheme.Convert(unstructuredHP, hpConverted, nil)
 		if err != nil {
-			return nil, errors.Wrap(err, "failed to convert to HTTPProxy")
+			return nil, fmt.Errorf("failed to convert to HTTPProxy: %w", err)
 		}
 		httpProxies = append(httpProxies, hpConverted)
 	}
 
 	httpProxies, err = sc.filterByAnnotations(httpProxies)
 	if err != nil {
-		return nil, errors.Wrap(err, "failed to filter HTTPProxies")
+		return nil, fmt.Errorf("failed to filter HTTPProxies: %w", err)
 	}
 
 	endpoints := []*endpoint.Endpoint{}
@@ -144,14 +144,14 @@ func (sc *httpProxySource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint,
 
 		hpEndpoints, err := sc.endpointsFromHTTPProxy(hp)
 		if err != nil {
-			return nil, errors.Wrap(err, "failed to get endpoints from HTTPProxy")
+			return nil, fmt.Errorf("failed to get endpoints from HTTPProxy: %w", err)
 		}
 
 		// apply template if fqdn is missing on HTTPProxy
 		if (sc.combineFQDNAnnotation || len(hpEndpoints) == 0) && sc.fqdnTemplate != nil {
 			tmplEndpoints, err := sc.endpointsFromTemplate(hp)
 			if err != nil {
-				return nil, errors.Wrap(err, "failed to get endpoints from template")
+				return nil, fmt.Errorf("failed to get endpoints from template: %w", err)
 			}
 
 			if sc.combineFQDNAnnotation {
diff --git a/source/crd.go b/source/crd.go
index 70a72407..31a775b0 100644
--- a/source/crd.go
+++ b/source/crd.go
@@ -148,7 +148,7 @@ func (cs *crdSource) AddEventHandler(ctx context.Context, handler func()) {
 				AddFunc: func(obj interface{}) {
 					handler()
 				},
-				UpdateFunc: func(old interface{}, new interface{}) {
+				UpdateFunc: func(old interface{}, newI interface{}) {
 					handler()
 				},
 				DeleteFunc: func(obj interface{}) {
diff --git a/source/f5_transportserver.go b/source/f5_transportserver.go
index 1c4a7cc8..d3042a58 100644
--- a/source/f5_transportserver.go
+++ b/source/f5_transportserver.go
@@ -18,10 +18,10 @@ package source
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"strings"
 
-	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -82,7 +82,7 @@ func NewF5TransportServerSource(
 
 	uc, err := newTSUnstructuredConverter()
 	if err != nil {
-		return nil, errors.Wrapf(err, "failed to setup unstructured converter")
+		return nil, fmt.Errorf("failed to setup unstructured converter: %w", err)
 	}
 
 	return &f5TransportServerSource{
@@ -120,7 +120,7 @@ func (ts *f5TransportServerSource) Endpoints(ctx context.Context) ([]*endpoint.E
 
 	transportServers, err = ts.filterByAnnotations(transportServers)
 	if err != nil {
-		return nil, errors.Wrap(err, "failed to filter TransportServers")
+		return nil, fmt.Errorf("failed to filter TransportServers: %w", err)
 	}
 
 	endpoints, err := ts.endpointsFromTransportServers(transportServers)
diff --git a/source/f5_virtualserver.go b/source/f5_virtualserver.go
index f4ada2f8..85b1538f 100644
--- a/source/f5_virtualserver.go
+++ b/source/f5_virtualserver.go
@@ -18,11 +18,11 @@ package source
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"sort"
 	"strings"
 
-	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -83,7 +83,7 @@ func NewF5VirtualServerSource(
 
 	uc, err := newVSUnstructuredConverter()
 	if err != nil {
-		return nil, errors.Wrapf(err, "failed to setup unstructured converter")
+		return nil, fmt.Errorf("failed to setup unstructured converter: %w", err)
 	}
 
 	return &f5VirtualServerSource{
@@ -121,7 +121,7 @@ func (vs *f5VirtualServerSource) Endpoints(ctx context.Context) ([]*endpoint.End
 
 	virtualServers, err = vs.filterByAnnotations(virtualServers)
 	if err != nil {
-		return nil, errors.Wrap(err, "failed to filter VirtualServers")
+		return nil, fmt.Errorf("failed to filter VirtualServers: %w", err)
 	}
 
 	endpoints, err := vs.endpointsFromVirtualServers(virtualServers)
diff --git a/source/gateway.go b/source/gateway.go
index 33ef3be3..2a713521 100644
--- a/source/gateway.go
+++ b/source/gateway.go
@@ -54,6 +54,8 @@ type gatewayRoute interface {
 	Metadata() *metav1.ObjectMeta
 	// Hostnames returns the route's specified hostnames.
 	Hostnames() []v1.Hostname
+	// ParentRefs returns the route's parent references as defined in the route spec.
+	ParentRefs() []v1.ParentReference
 	// Protocol returns the route's protocol type.
 	Protocol() v1.ProtocolType
 	// RouteStatus returns the route's common status.
@@ -294,10 +296,24 @@ func (c *gatewayRouteResolver) resolve(rt gatewayRoute) (map[string]endpoint.Tar
 	}
 	hostTargets := make(map[string]endpoint.Targets)
 
+	routeParentRefs := rt.ParentRefs()
+
+	if len(routeParentRefs) == 0 {
+		log.Debugf("No parent references found for %s %s/%s", c.src.rtKind, rt.Metadata().Namespace, rt.Metadata().Name)
+		return hostTargets, nil
+	}
+
 	meta := rt.Metadata()
 	for _, rps := range rt.RouteStatus().Parents {
 		// Confirm the Parent is the standard Gateway kind.
 		ref := rps.ParentRef
+		namespace := strVal((*string)(ref.Namespace), meta.Namespace)
+		// Ensure that the parent reference is in the routeParentRefs list
+		if !gwRouteHasParentRef(routeParentRefs, ref, meta) {
+			log.Debugf("Parent reference %s/%s not found in routeParentRefs for %s %s/%s", namespace, string(ref.Name), c.src.rtKind, meta.Namespace, meta.Name)
+			continue
+		}
+
 		group := strVal((*string)(ref.Group), gatewayGroup)
 		kind := strVal((*string)(ref.Kind), gatewayKind)
 		if group != gatewayGroup || kind != gatewayKind {
@@ -305,7 +321,6 @@ func (c *gatewayRouteResolver) resolve(rt gatewayRoute) (map[string]endpoint.Tar
 			continue
 		}
 		// Lookup the Gateway and its Listeners.
-		namespace := strVal((*string)(ref.Namespace), meta.Namespace)
 		gw, ok := c.gws[namespacedName(namespace, string(ref.Name))]
 		if !ok {
 			log.Debugf("Gateway %s/%s not found for %s %s/%s", namespace, ref.Name, c.src.rtKind, meta.Namespace, meta.Name)
@@ -316,6 +331,7 @@ func (c *gatewayRouteResolver) resolve(rt gatewayRoute) (map[string]endpoint.Tar
 			log.Debugf("Gateway %s/%s does not match %s %s/%s", namespace, ref.Name, c.src.gwName, meta.Namespace, meta.Name)
 			continue
 		}
+
 		// Confirm the Gateway has accepted the Route.
 		if !gwRouteIsAccepted(rps.Conditions) {
 			log.Debugf("Gateway %s/%s has not accepted %s %s/%s", namespace, ref.Name, c.src.rtKind, meta.Namespace, meta.Name)
@@ -458,6 +474,26 @@ func (c *gatewayRouteResolver) routeIsAllowed(gw *v1beta1.Gateway, lis *v1.Liste
 	return false
 }
 
+func gwRouteHasParentRef(routeParentRefs []v1.ParentReference, ref v1.ParentReference, meta *metav1.ObjectMeta) bool {
+	// Ensure that the parent reference is in the routeParentRefs list
+	namespace := strVal((*string)(ref.Namespace), meta.Namespace)
+	group := strVal((*string)(ref.Group), gatewayGroup)
+	kind := strVal((*string)(ref.Kind), gatewayKind)
+	for _, rpr := range routeParentRefs {
+		rprGroup := strVal((*string)(rpr.Group), gatewayGroup)
+		rprKind := strVal((*string)(rpr.Kind), gatewayKind)
+		if rprGroup != group || rprKind != kind {
+			continue
+		}
+		rprNamespace := strVal((*string)(rpr.Namespace), meta.Namespace)
+		if string(rpr.Name) != string(ref.Name) || rprNamespace != namespace {
+			continue
+		}
+		return true
+	}
+	return false
+}
+
 func gwRouteIsAccepted(conds []metav1.Condition) bool {
 	for _, c := range conds {
 		if v1.RouteConditionType(c.Type) == v1.RouteConditionAccepted {
diff --git a/source/gateway_grpcroute.go b/source/gateway_grpcroute.go
index de93a72d..f2253f2d 100644
--- a/source/gateway_grpcroute.go
+++ b/source/gateway_grpcroute.go
@@ -33,11 +33,12 @@ func NewGatewayGRPCRouteSource(clients ClientGenerator, config *Config) (Source,
 
 type gatewayGRPCRoute struct{ route v1.GRPCRoute } // NOTE: Must update TypeMeta in List when changing the APIVersion.
 
-func (rt *gatewayGRPCRoute) Object() kubeObject           { return &rt.route }
-func (rt *gatewayGRPCRoute) Metadata() *metav1.ObjectMeta { return &rt.route.ObjectMeta }
-func (rt *gatewayGRPCRoute) Hostnames() []v1.Hostname     { return rt.route.Spec.Hostnames }
-func (rt *gatewayGRPCRoute) Protocol() v1.ProtocolType    { return v1.HTTPSProtocolType }
-func (rt *gatewayGRPCRoute) RouteStatus() v1.RouteStatus  { return rt.route.Status.RouteStatus }
+func (rt *gatewayGRPCRoute) Object() kubeObject               { return &rt.route }
+func (rt *gatewayGRPCRoute) Metadata() *metav1.ObjectMeta     { return &rt.route.ObjectMeta }
+func (rt *gatewayGRPCRoute) Hostnames() []v1.Hostname         { return rt.route.Spec.Hostnames }
+func (rt *gatewayGRPCRoute) ParentRefs() []v1.ParentReference { return rt.route.Spec.ParentRefs }
+func (rt *gatewayGRPCRoute) Protocol() v1.ProtocolType        { return v1.HTTPSProtocolType }
+func (rt *gatewayGRPCRoute) RouteStatus() v1.RouteStatus      { return rt.route.Status.RouteStatus }
 
 type gatewayGRPCRouteInformer struct {
 	informers_v1.GRPCRouteInformer
diff --git a/source/gateway_httproute.go b/source/gateway_httproute.go
index 4c063d4d..ad3c4fcd 100644
--- a/source/gateway_httproute.go
+++ b/source/gateway_httproute.go
@@ -34,11 +34,12 @@ func NewGatewayHTTPRouteSource(clients ClientGenerator, config *Config) (Source,
 
 type gatewayHTTPRoute struct{ route v1.HTTPRoute } // NOTE: Must update TypeMeta in List when changing the APIVersion.
 
-func (rt *gatewayHTTPRoute) Object() kubeObject           { return &rt.route }
-func (rt *gatewayHTTPRoute) Metadata() *metav1.ObjectMeta { return &rt.route.ObjectMeta }
-func (rt *gatewayHTTPRoute) Hostnames() []v1.Hostname     { return rt.route.Spec.Hostnames }
-func (rt *gatewayHTTPRoute) Protocol() v1.ProtocolType    { return v1.HTTPProtocolType }
-func (rt *gatewayHTTPRoute) RouteStatus() v1.RouteStatus  { return rt.route.Status.RouteStatus }
+func (rt *gatewayHTTPRoute) Object() kubeObject               { return &rt.route }
+func (rt *gatewayHTTPRoute) Metadata() *metav1.ObjectMeta     { return &rt.route.ObjectMeta }
+func (rt *gatewayHTTPRoute) Hostnames() []v1.Hostname         { return rt.route.Spec.Hostnames }
+func (rt *gatewayHTTPRoute) ParentRefs() []v1.ParentReference { return rt.route.Spec.ParentRefs }
+func (rt *gatewayHTTPRoute) Protocol() v1.ProtocolType        { return v1.HTTPProtocolType }
+func (rt *gatewayHTTPRoute) RouteStatus() v1.RouteStatus      { return rt.route.Status.RouteStatus }
 
 type gatewayHTTPRouteInformer struct {
 	informers_v1beta1.HTTPRouteInformer
diff --git a/source/gateway_tcproute.go b/source/gateway_tcproute.go
index 863b4f62..57ca6a55 100644
--- a/source/gateway_tcproute.go
+++ b/source/gateway_tcproute.go
@@ -34,11 +34,12 @@ func NewGatewayTCPRouteSource(clients ClientGenerator, config *Config) (Source,
 
 type gatewayTCPRoute struct{ route v1alpha2.TCPRoute } // NOTE: Must update TypeMeta in List when changing the APIVersion.
 
-func (rt *gatewayTCPRoute) Object() kubeObject           { return &rt.route }
-func (rt *gatewayTCPRoute) Metadata() *metav1.ObjectMeta { return &rt.route.ObjectMeta }
-func (rt *gatewayTCPRoute) Hostnames() []v1.Hostname     { return nil }
-func (rt *gatewayTCPRoute) Protocol() v1.ProtocolType    { return v1.TCPProtocolType }
-func (rt *gatewayTCPRoute) RouteStatus() v1.RouteStatus  { return rt.route.Status.RouteStatus }
+func (rt *gatewayTCPRoute) Object() kubeObject               { return &rt.route }
+func (rt *gatewayTCPRoute) Metadata() *metav1.ObjectMeta     { return &rt.route.ObjectMeta }
+func (rt *gatewayTCPRoute) Hostnames() []v1.Hostname         { return nil }
+func (rt *gatewayTCPRoute) ParentRefs() []v1.ParentReference { return rt.route.Spec.ParentRefs }
+func (rt *gatewayTCPRoute) Protocol() v1.ProtocolType        { return v1.TCPProtocolType }
+func (rt *gatewayTCPRoute) RouteStatus() v1.RouteStatus      { return rt.route.Status.RouteStatus }
 
 type gatewayTCPRouteInformer struct {
 	informers_v1a2.TCPRouteInformer
diff --git a/source/gateway_tlsroute.go b/source/gateway_tlsroute.go
index 0c985588..9e77f3bc 100644
--- a/source/gateway_tlsroute.go
+++ b/source/gateway_tlsroute.go
@@ -34,11 +34,12 @@ func NewGatewayTLSRouteSource(clients ClientGenerator, config *Config) (Source,
 
 type gatewayTLSRoute struct{ route v1alpha2.TLSRoute } // NOTE: Must update TypeMeta in List when changing the APIVersion.
 
-func (rt *gatewayTLSRoute) Object() kubeObject           { return &rt.route }
-func (rt *gatewayTLSRoute) Metadata() *metav1.ObjectMeta { return &rt.route.ObjectMeta }
-func (rt *gatewayTLSRoute) Hostnames() []v1.Hostname     { return rt.route.Spec.Hostnames }
-func (rt *gatewayTLSRoute) Protocol() v1.ProtocolType    { return v1.TLSProtocolType }
-func (rt *gatewayTLSRoute) RouteStatus() v1.RouteStatus  { return rt.route.Status.RouteStatus }
+func (rt *gatewayTLSRoute) Object() kubeObject               { return &rt.route }
+func (rt *gatewayTLSRoute) Metadata() *metav1.ObjectMeta     { return &rt.route.ObjectMeta }
+func (rt *gatewayTLSRoute) Hostnames() []v1.Hostname         { return rt.route.Spec.Hostnames }
+func (rt *gatewayTLSRoute) ParentRefs() []v1.ParentReference { return rt.route.Spec.ParentRefs }
+func (rt *gatewayTLSRoute) Protocol() v1.ProtocolType        { return v1.TLSProtocolType }
+func (rt *gatewayTLSRoute) RouteStatus() v1.RouteStatus      { return rt.route.Status.RouteStatus }
 
 type gatewayTLSRouteInformer struct {
 	informers_v1a2.TLSRouteInformer
diff --git a/source/gateway_udproute.go b/source/gateway_udproute.go
index ffc0987f..82e213c5 100644
--- a/source/gateway_udproute.go
+++ b/source/gateway_udproute.go
@@ -34,11 +34,12 @@ func NewGatewayUDPRouteSource(clients ClientGenerator, config *Config) (Source,
 
 type gatewayUDPRoute struct{ route v1alpha2.UDPRoute } // NOTE: Must update TypeMeta in List when changing the APIVersion.
 
-func (rt *gatewayUDPRoute) Object() kubeObject           { return &rt.route }
-func (rt *gatewayUDPRoute) Metadata() *metav1.ObjectMeta { return &rt.route.ObjectMeta }
-func (rt *gatewayUDPRoute) Hostnames() []v1.Hostname     { return nil }
-func (rt *gatewayUDPRoute) Protocol() v1.ProtocolType    { return v1.UDPProtocolType }
-func (rt *gatewayUDPRoute) RouteStatus() v1.RouteStatus  { return rt.route.Status.RouteStatus }
+func (rt *gatewayUDPRoute) Object() kubeObject               { return &rt.route }
+func (rt *gatewayUDPRoute) Metadata() *metav1.ObjectMeta     { return &rt.route.ObjectMeta }
+func (rt *gatewayUDPRoute) Hostnames() []v1.Hostname         { return nil }
+func (rt *gatewayUDPRoute) ParentRefs() []v1.ParentReference { return rt.route.Spec.ParentRefs }
+func (rt *gatewayUDPRoute) Protocol() v1.ProtocolType        { return v1.UDPProtocolType }
+func (rt *gatewayUDPRoute) RouteStatus() v1.RouteStatus      { return rt.route.Status.RouteStatus }
 
 type gatewayUDPRouteInformer struct {
 	informers_v1a2.UDPRouteInformer
diff --git a/source/kong_tcpingress.go b/source/kong_tcpingress.go
index 7d81832b..bca023db 100644
--- a/source/kong_tcpingress.go
+++ b/source/kong_tcpingress.go
@@ -18,10 +18,10 @@ package source
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"sort"
 
-	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -82,7 +82,7 @@ func NewKongTCPIngressSource(ctx context.Context, dynamicKubeClient dynamic.Inte
 
 	uc, err := newKongUnstructuredConverter()
 	if err != nil {
-		return nil, errors.Wrapf(err, "failed to setup Unstructured Converter")
+		return nil, fmt.Errorf("failed to setup Unstructured Converter: %w", err)
 	}
 
 	return &kongTCPIngressSource{
@@ -121,7 +121,7 @@ func (sc *kongTCPIngressSource) Endpoints(ctx context.Context) ([]*endpoint.Endp
 
 	tcpIngresses, err = sc.filterByAnnotations(tcpIngresses)
 	if err != nil {
-		return nil, errors.Wrap(err, "failed to filter TCPIngresses")
+		return nil, fmt.Errorf("failed to filter TCPIngresses: %w", err)
 	}
 
 	var endpoints []*endpoint.Endpoint
diff --git a/source/node.go b/source/node.go
index c61c232b..a0e426f1 100644
--- a/source/node.go
+++ b/source/node.go
@@ -36,16 +36,17 @@ import (
 const warningMsg = "The default behavior of exposing internal IPv6 addresses will change in the next minor version. Use --no-expose-internal-ipv6 flag to opt-in to the new behavior."
 
 type nodeSource struct {
-	client             kubernetes.Interface
-	annotationFilter   string
-	fqdnTemplate       *template.Template
-	nodeInformer       coreinformers.NodeInformer
-	labelSelector      labels.Selector
-	exposeInternalIPV6 bool
+	client               kubernetes.Interface
+	annotationFilter     string
+	fqdnTemplate         *template.Template
+	nodeInformer         coreinformers.NodeInformer
+	labelSelector        labels.Selector
+	excludeUnschedulable bool
+	exposeInternalIPV6   bool
 }
 
 // NewNodeSource creates a new nodeSource with the given config.
-func NewNodeSource(ctx context.Context, kubeClient kubernetes.Interface, annotationFilter, fqdnTemplate string, labelSelector labels.Selector, exposeInternalIPv6 bool) (Source, error) {
+func NewNodeSource(ctx context.Context, kubeClient kubernetes.Interface, annotationFilter, fqdnTemplate string, labelSelector labels.Selector, exposeInternalIPv6 bool, excludeUnschedulable bool) (Source, error) {
 	tmpl, err := parseTemplate(fqdnTemplate)
 	if err != nil {
 		return nil, err
@@ -73,12 +74,13 @@ func NewNodeSource(ctx context.Context, kubeClient kubernetes.Interface, annotat
 	}
 
 	return &nodeSource{
-		client:             kubeClient,
-		annotationFilter:   annotationFilter,
-		fqdnTemplate:       tmpl,
-		nodeInformer:       nodeInformer,
-		labelSelector:      labelSelector,
-		exposeInternalIPV6: exposeInternalIPv6,
+		client:               kubeClient,
+		annotationFilter:     annotationFilter,
+		fqdnTemplate:         tmpl,
+		nodeInformer:         nodeInformer,
+		labelSelector:        labelSelector,
+		excludeUnschedulable: excludeUnschedulable,
+		exposeInternalIPV6:   exposeInternalIPv6,
 	}, nil
 }
 
@@ -106,7 +108,7 @@ func (ns *nodeSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, erro
 			continue
 		}
 
-		if node.Spec.Unschedulable {
+		if node.Spec.Unschedulable && ns.excludeUnschedulable {
 			log.Debugf("Skipping node %s because it is unschedulable", node.Name)
 			continue
 		}
diff --git a/source/source.go b/source/source.go
index 4641c056..4f0b69d4 100644
--- a/source/source.go
+++ b/source/source.go
@@ -72,6 +72,7 @@ const (
 	// The annotation used for determining if traffic will go through Cloudflare
 	CloudflareProxiedKey        = "external-dns.alpha.kubernetes.io/cloudflare-proxied"
 	CloudflareCustomHostnameKey = "external-dns.alpha.kubernetes.io/cloudflare-custom-hostname"
+	CloudflareRegionKey         = "external-dns.alpha.kubernetes.io/cloudflare-region-key"
 
 	SetIdentifierKey = "external-dns.alpha.kubernetes.io/set-identifier"
 )
@@ -202,6 +203,12 @@ func getProviderSpecificAnnotations(annotations map[string]string) (endpoint.Pro
 			Value: v,
 		})
 	}
+	if v, exists := annotations[CloudflareRegionKey]; exists {
+		providerSpecificAnnotations = append(providerSpecificAnnotations, endpoint.ProviderSpecificProperty{
+			Name:  CloudflareRegionKey,
+			Value: v,
+		})
+	}
 	if getAliasFromAnnotations(annotations) {
 		providerSpecificAnnotations = append(providerSpecificAnnotations, endpoint.ProviderSpecificProperty{
 			Name:  "alias",
diff --git a/source/store.go b/source/store.go
index 6c882ec9..8a9149ba 100644
--- a/source/store.go
+++ b/source/store.go
@@ -18,6 +18,8 @@ package source
 
 import (
 	"context"
+	"errors"
+	"fmt"
 	"net/http"
 	"os"
 	"strings"
@@ -27,7 +29,6 @@ import (
 	"github.com/cloudfoundry-community/go-cfclient"
 	"github.com/linki/instrumented_http"
 	openshift "github.com/openshift/client-go/route/clientset/versioned"
-	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 	istioclient "istio.io/client-go/pkg/clientset/versioned"
 	"k8s.io/apimachinery/pkg/labels"
@@ -82,6 +83,7 @@ type Config struct {
 	ResolveLoadBalancerHostname    bool
 	TraefikDisableLegacy           bool
 	TraefikDisableNew              bool
+	ExcludeUnschedulable           bool
 	ExposeInternalIPv6             bool
 }
 
@@ -126,6 +128,7 @@ func NewSourceConfig(cfg *externaldns.Config) *Config {
 		ResolveLoadBalancerHostname:    cfg.ResolveServiceLoadBalancerHostname,
 		TraefikDisableLegacy:           cfg.TraefikDisableLegacy,
 		TraefikDisableNew:              cfg.TraefikDisableNew,
+		ExcludeUnschedulable:           cfg.ExcludeUnschedulable,
 		ExposeInternalIPv6:             cfg.ExposeInternalIPV6,
 	}
 }
@@ -264,7 +267,7 @@ func BuildWithConfig(ctx context.Context, source string, p ClientGenerator, cfg
 		if err != nil {
 			return nil, err
 		}
-		return NewNodeSource(ctx, client, cfg.AnnotationFilter, cfg.FQDNTemplate, cfg.LabelFilter, cfg.ExposeInternalIPv6)
+		return NewNodeSource(ctx, client, cfg.AnnotationFilter, cfg.FQDNTemplate, cfg.LabelFilter, cfg.ExposeInternalIPv6, cfg.ExcludeUnschedulable)
 	case "service":
 		client, err := p.KubeClient()
 		if err != nil {
@@ -507,7 +510,7 @@ func NewIstioClient(kubeConfig string, apiServerURL string) (*istioclient.Client
 
 	ic, err := istioclient.NewForConfig(restCfg)
 	if err != nil {
-		return nil, errors.Wrap(err, "Failed to create istio client")
+		return nil, fmt.Errorf("failed to create istio client: %w", err)
 	}
 
 	return ic, nil
diff --git a/source/traefik_proxy.go b/source/traefik_proxy.go
index a63142ef..3a07ac91 100644
--- a/source/traefik_proxy.go
+++ b/source/traefik_proxy.go
@@ -18,12 +18,12 @@ package source
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"regexp"
 	"sort"
 	"strings"
 
-	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -151,7 +151,7 @@ func NewTraefikSource(ctx context.Context, dynamicKubeClient dynamic.Interface,
 
 	uc, err := newTraefikUnstructuredConverter()
 	if err != nil {
-		return nil, errors.Wrapf(err, "failed to setup Unstructured Converter")
+		return nil, fmt.Errorf("failed to setup Unstructured Converter: %w", err)
 	}
 
 	return &traefikSource{
@@ -249,7 +249,7 @@ func (ts *traefikSource) ingressRouteEndpoints() ([]*endpoint.Endpoint, error) {
 
 	ingressRoutes, err = ts.filterIngressRouteByAnnotation(ingressRoutes)
 	if err != nil {
-		return nil, errors.Wrap(err, "failed to filter IngressRoute")
+		return nil, fmt.Errorf("failed to filter IngressRoute: %w", err)
 	}
 
 	for _, ingressRoute := range ingressRoutes {
@@ -301,7 +301,7 @@ func (ts *traefikSource) ingressRouteTCPEndpoints() ([]*endpoint.Endpoint, error
 
 	ingressRouteTCPs, err = ts.filterIngressRouteTcpByAnnotations(ingressRouteTCPs)
 	if err != nil {
-		return nil, errors.Wrap(err, "failed to filter IngressRouteTCP")
+		return nil, fmt.Errorf("failed to filter IngressRouteTCP: %w", err)
 	}
 
 	for _, ingressRouteTCP := range ingressRouteTCPs {
@@ -353,7 +353,7 @@ func (ts *traefikSource) ingressRouteUDPEndpoints() ([]*endpoint.Endpoint, error
 
 	ingressRouteUDPs, err = ts.filterIngressRouteUdpByAnnotations(ingressRouteUDPs)
 	if err != nil {
-		return nil, errors.Wrap(err, "failed to filter IngressRouteUDP")
+		return nil, fmt.Errorf("failed to filter IngressRouteUDP: %w", err)
 	}
 
 	for _, ingressRouteUDP := range ingressRouteUDPs {
@@ -405,7 +405,7 @@ func (ts *traefikSource) oldIngressRouteEndpoints() ([]*endpoint.Endpoint, error
 
 	ingressRoutes, err = ts.filterIngressRouteByAnnotation(ingressRoutes)
 	if err != nil {
-		return nil, errors.Wrap(err, "failed to filter IngressRoute")
+		return nil, fmt.Errorf("failed to filter IngressRoute: %w", err)
 	}
 
 	for _, ingressRoute := range ingressRoutes {
@@ -457,7 +457,7 @@ func (ts *traefikSource) oldIngressRouteTCPEndpoints() ([]*endpoint.Endpoint, er
 
 	ingressRouteTCPs, err = ts.filterIngressRouteTcpByAnnotations(ingressRouteTCPs)
 	if err != nil {
-		return nil, errors.Wrap(err, "failed to filter IngressRouteTCP")
+		return nil, fmt.Errorf("failed to filter IngressRouteTCP: %w", err)
 	}
 
 	for _, ingressRouteTCP := range ingressRouteTCPs {
@@ -509,7 +509,7 @@ func (ts *traefikSource) oldIngressRouteUDPEndpoints() ([]*endpoint.Endpoint, er
 
 	ingressRouteUDPs, err = ts.filterIngressRouteUdpByAnnotations(ingressRouteUDPs)
 	if err != nil {
-		return nil, errors.Wrap(err, "failed to filter IngressRouteUDP")
+		return nil, fmt.Errorf("failed to filter IngressRouteUDP: %w", err)
 	}
 
 	for _, ingressRouteUDP := range ingressRouteUDPs {



Test patch:
diff --git a/charts/external-dns/tests/deployment-flags_test.yaml b/charts/external-dns/tests/deployment-flags_test.yaml
index 38a9567f..97e89a45 100644
--- a/charts/external-dns/tests/deployment-flags_test.yaml
+++ b/charts/external-dns/tests/deployment-flags_test.yaml
@@ -6,7 +6,6 @@ release:
 tests:
   - it: should provide expected default flags
     asserts:
-      # - matchSnapshot: {}
       - exists :
           path: spec.template.spec.containers[?(@.name == "external-dns")]
       - equal :
@@ -21,13 +20,10 @@ tests:
             - --registry=txt
             - --provider=aws
 
-  - it: should configure txtPrefix and ignore txtSuffix if not empty
+  - it: should configure 'txtSuffix' when not empty with 'txtPrefix' empty
     set:
-      provider:
-        name: cloudflare
-      txtPrefix: "test-prefix"
+      txtPrefix: ""
       txtSuffix: "test-suffix"
-      txtOwnerId: "testing"
     asserts:
       - exists :
           path: spec.template.spec.containers[?(@.name == "external-dns")]
@@ -41,35 +37,24 @@ tests:
             - --source=ingress
             - --policy=upsert-only
             - --registry=txt
-            - --txt-owner-id=testing
-            - --txt-prefix=test-prefix
-            - --provider=cloudflare
+            - --txt-suffix=test-suffix
+            - --provider=aws
       - notContains:
+          path: spec.template.spec.containers[?(@.name == "external-dns")].args
+          content: "--txt-prefix=test-prefix"
+      - contains:
           path: spec.template.spec.containers[?(@.name == "external-dns")].args
           content: "--txt-suffix=test-suffix"
 
-  - it: should configure 'txtSuffix' when not empty with 'txtPrefix' empty
+  - it: should configure 'txtSuffix' when set and 'txtPrefix' is not present
     set:
-      txtPrefix: ""
-      txtSuffix: "test-suffix"
+      txtSuffix: "custom-suffix"
     asserts:
       - exists :
           path: spec.template.spec.containers[?(@.name == "external-dns")]
-      - equal :
-          path: spec.template.spec.containers[?(@.name == "external-dns")].args
-          value:
-            - --log-level=info
-            - --log-format=text
-            - --interval=1m
-            - --source=service
-            - --source=ingress
-            - --policy=upsert-only
-            - --registry=txt
-            - --txt-suffix=test-suffix
-            - --provider=aws
-      - notContains:
+      - contains:
           path: spec.template.spec.containers[?(@.name == "external-dns")].args
-          content: "--txt-prefix=test-prefix"
+          content: "--txt-suffix=custom-suffix"
 
   - it: should be able configure multiple sources
     set:
@@ -117,3 +102,66 @@ tests:
             - --zone-id-filter=/hostedzone/Z00003
             - --zone-id-filter=/hostedzone/Z00004
             - --zone-id-filter=/hostedzone/Z00005
+
+
+  - it: should allow 'extraArgs' to be a slice
+    set:
+      extraArgs:
+       - --extraArgA=valueA
+       - --extraArgB=valueB
+       - --extraArgC=valueC-1
+       - --extraArgC=valueC-2
+
+    asserts:
+      - equal:
+          path: spec.template.spec.containers[?(@.name == "external-dns")].args
+          value:
+            - --log-level=info
+            - --log-format=text
+            - --interval=1m
+            - --source=service
+            - --source=ingress
+            - --policy=upsert-only
+            - --registry=txt
+            - --provider=aws
+            - --extraArgA=valueA
+            - --extraArgB=valueB
+            - --extraArgC=valueC-1
+            - --extraArgC=valueC-2
+
+
+  - it: should allow 'extraArgs' to be a map with its entries potentially being slices (lists) themselves
+    set:
+      extraArgs:
+        extraArgA: valueA
+        extraArgB: valueB
+        extraArgC:
+          - valueC-1
+          - valueC-2
+
+    asserts:
+      - equal:
+          path: spec.template.spec.containers[?(@.name == "external-dns")].args
+          value:
+            - --log-level=info
+            - --log-format=text
+            - --interval=1m
+            - --source=service
+            - --source=ingress
+            - --policy=upsert-only
+            - --registry=txt
+            - --provider=aws
+            - --extraArgA=valueA
+            - --extraArgB=valueB
+            - --extraArgC=valueC-1
+            - --extraArgC=valueC-2
+
+
+  - it: should throw error when txtPrefix and txtSuffix are set
+    set:
+        txtPrefix: "test-prefix"
+        txtSuffix: "test-suffix"
+    asserts:
+     - failedTemplate:
+          errorMessage: "'txtPrefix' and 'txtSuffix' are mutually exclusive"
+
diff --git a/charts/external-dns/tests/json-schema_test.yaml b/charts/external-dns/tests/json-schema_test.yaml
index 694e59d5..68b9b6ba 100644
--- a/charts/external-dns/tests/json-schema_test.yaml
+++ b/charts/external-dns/tests/json-schema_test.yaml
@@ -50,3 +50,15 @@ tests:
       labelFilter: "mydomain.io/enable-dns-record in (true)"
     asserts:
       - notFailedTemplate: {}
+
+  - it: should not fail when livenessProbe is null
+    set:
+      livenessProbe: null
+    asserts:
+      - notFailedTemplate: {}
+
+  - it: should not fail when readinessProbe is null
+    set:
+      readinessProbe: null
+    asserts:
+      - notFailedTemplate: {}
diff --git a/controller/execute_test.go b/controller/execute_test.go
index 8d761bcc..442e3d7b 100644
--- a/controller/execute_test.go
+++ b/controller/execute_test.go
@@ -18,6 +18,7 @@ package controller
 
 import (
 	"bytes"
+	"context"
 	"fmt"
 	"net"
 	"net/http"
@@ -29,10 +30,9 @@ import (
 	"testing"
 	"time"
 
-	"context"
-
 	log "github.com/sirupsen/logrus"
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 	"sigs.k8s.io/external-dns/endpoint"
 	"sigs.k8s.io/external-dns/pkg/apis/externaldns"
 	"sigs.k8s.io/external-dns/plan"
@@ -219,18 +219,45 @@ func TestHandleSigterm(t *testing.T) {
 	}
 }
 
-func TestServeMetrics(t *testing.T) {
-	l, _ := net.Listen("tcp", ":0")
-	_ = l.Close()
-	_, port, _ := net.SplitHostPort(l.Addr().String())
+func getRandomPort() (int, error) {
+	addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
+	if err != nil {
+		return 0, err
+	}
 
-	go serveMetrics(fmt.Sprintf(":%s", port))
-	resp, err := http.Get(fmt.Sprintf("http://localhost:%s", port) + "/healthz")
-	assert.NoError(t, err)
+	l, err := net.ListenTCP("tcp", addr)
+	if err != nil {
+		return 0, err
+	}
+	defer l.Close()
+	return l.Addr().(*net.TCPAddr).Port, nil
+}
+
+func TestServeMetrics(t *testing.T) {
+	t.Parallel()
+
+	port, err := getRandomPort()
+	require.NoError(t, err)
+	addresse := fmt.Sprintf("localhost:%d", port)
+
+	go serveMetrics(fmt.Sprintf(":%d", port))
+
+	// Wait for the TCP socket to be ready
+	require.Eventually(t, func() bool {
+		conn, err := net.Dial("tcp", addresse)
+		if err != nil {
+			return false
+		}
+		_ = conn.Close()
+		return true
+	}, 1*time.Second, 5*time.Millisecond, "server not ready with port open in time")
+
+	resp, err := http.Get(fmt.Sprintf("http://%s/healthz", addresse))
+	require.NoError(t, err)
 	assert.Equal(t, http.StatusOK, resp.StatusCode)
 
-	resp, err = http.Get(fmt.Sprintf("http://localhost:%s", port) + "/metrics")
-	assert.NoError(t, err)
+	resp, err = http.Get(fmt.Sprintf("http://%s/metrics", addresse))
+	require.NoError(t, err)
 	assert.Equal(t, http.StatusOK, resp.StatusCode)
 }
 
@@ -308,7 +335,6 @@ func (m *MockProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error
 }
 
 func (p *MockProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error {
-
 	return nil
 }
 
diff --git a/internal/testutils/log.go b/internal/testutils/log.go
index 232ac78f..25b7a427 100644
--- a/internal/testutils/log.go
+++ b/internal/testutils/log.go
@@ -18,11 +18,9 @@ package testutils
 
 import (
 	"bytes"
-	"flag"
 	"testing"
 
 	log "github.com/sirupsen/logrus"
-	"k8s.io/klog/v2"
 )
 
 // LogsToBuffer redirects log(s) output to a buffer for testing purposes
@@ -38,12 +36,5 @@ func LogsToBuffer(level log.Level, t *testing.T) *bytes.Buffer {
 	buf := new(bytes.Buffer)
 	log.SetOutput(buf)
 	log.SetLevel(level)
-	klog.SetOutput(buf)
-	flags := &flag.FlagSet{}
-	klog.InitFlags(flags)
-	// make sure klog doesn't write to stderr by default in tests
-	_ = flags.Set("logtostderr", "false")
-	_ = flags.Set("alsologtostderr", "false")
-	_ = flags.Set("stderrthreshold", "4")
 	return buf
 }
diff --git a/pkg/apis/externaldns/types_test.go b/pkg/apis/externaldns/types_test.go
index 22973250..b9b257c8 100644
--- a/pkg/apis/externaldns/types_test.go
+++ b/pkg/apis/externaldns/types_test.go
@@ -132,6 +132,7 @@ var (
 		WebhookProviderURL:                            "http://localhost:8888",
 		WebhookProviderReadTimeout:                    5 * time.Second,
 		WebhookProviderWriteTimeout:                   10 * time.Second,
+		ExcludeUnschedulable:                          true,
 	}
 
 	overriddenConfig = &Config{
@@ -247,6 +248,7 @@ var (
 		WebhookProviderURL:                            "http://localhost:8888",
 		WebhookProviderReadTimeout:                    5 * time.Second,
 		WebhookProviderWriteTimeout:                   10 * time.Second,
+		ExcludeUnschedulable:                          false,
 	}
 )
 
@@ -386,6 +388,7 @@ func TestParseFlags(t *testing.T) {
 				"--managed-record-types=AAAA",
 				"--managed-record-types=CNAME",
 				"--managed-record-types=NS",
+				"--no-exclude-unschedulable",
 				"--rfc2136-batch-change-size=100",
 				"--rfc2136-load-balancing-strategy=round-robin",
 				"--rfc2136-host=rfc2136-host1",
@@ -505,6 +508,7 @@ func TestParseFlags(t *testing.T) {
 				"EXTERNAL_DNS_TRANSIP_KEYFILE":                                   "/path/to/transip.key",
 				"EXTERNAL_DNS_DIGITALOCEAN_API_PAGE_SIZE":                        "100",
 				"EXTERNAL_DNS_MANAGED_RECORD_TYPES":                              "A\nAAAA\nCNAME\nNS",
+				"EXTERNAL_DNS_EXCLUDE_UNSCHEDULABLE":                             "false",
 				"EXTERNAL_DNS_RFC2136_BATCH_CHANGE_SIZE":                         "100",
 				"EXTERNAL_DNS_RFC2136_LOAD_BALANCING_STRATEGY":                   "round-robin",
 				"EXTERNAL_DNS_RFC2136_HOST":                                      "rfc2136-host1\nrfc2136-host2",
diff --git a/plan/plan_test.go b/plan/plan_test.go
index 5aecc863..af1f5c2c 100644
--- a/plan/plan_test.go
+++ b/plan/plan_test.go
@@ -367,9 +367,22 @@ func (suite *PlanTestSuite) TestSyncSecondRoundWithProviderSpecificNoChange() {
 	}
 
 	changes := p.Calculate().Changes
-	if changes.HasChanges() {
-		suite.T().Fatal("test should not have changes")
+	suite.Assert().False(changes.HasChanges())
+}
+
+func (suite *PlanTestSuite) TestHasChanges() {
+	current := []*endpoint.Endpoint{suite.bar127AWithProviderSpecificTrue}
+	desired := []*endpoint.Endpoint{suite.bar127AWithProviderSpecificFalse}
+
+	p := &Plan{
+		Policies:       []Policy{&SyncPolicy{}},
+		Current:        current,
+		Desired:        desired,
+		ManagedRecords: []string{endpoint.RecordTypeA, endpoint.RecordTypeCNAME},
 	}
+
+	changes := p.Calculate().Changes
+	suite.Assert().True(changes.HasChanges())
 }
 
 func (suite *PlanTestSuite) TestSyncSecondRoundWithProviderSpecificRemoval() {
diff --git a/provider/alibabacloud/alibaba_cloud_test.go b/provider/alibabacloud/alibaba_cloud_test.go
index 8d4b4746..33774637 100644
--- a/provider/alibabacloud/alibaba_cloud_test.go
+++ b/provider/alibabacloud/alibaba_cloud_test.go
@@ -22,6 +22,7 @@ import (
 
 	"github.com/aliyun/alibaba-cloud-sdk-go/services/alidns"
 	"github.com/aliyun/alibaba-cloud-sdk-go/services/pvtz"
+	"github.com/stretchr/testify/assert"
 
 	"sigs.k8s.io/external-dns/endpoint"
 	"sigs.k8s.io/external-dns/plan"
@@ -223,18 +224,7 @@ func newTestAlibabaCloudProvider(private bool) *AlibabaCloudProvider {
 	cfg := alibabaCloudConfig{
 		VPCID: "vpc-xxxxxx",
 	}
-	//
-	//dnsClient, _ := alidns.NewClientWithAccessKey(
-	//	cfg.RegionID,
-	//	cfg.AccessKeyID,
-	//	cfg.AccessKeySecret,
-	//)
-	//
-	//pvtzClient, _ := pvtz.NewClientWithAccessKey(
-	//	"cn-hangzhou",
-	//	cfg.AccessKeyID,
-	//	cfg.AccessKeySecret,
-	//)
+
 	domainFilterTest := endpoint.NewDomainFilter([]string{"container-service.top.", "example.org"})
 
 	return &AlibabaCloudProvider{
@@ -256,8 +246,8 @@ func TestAlibabaCloudPrivateProvider_Records(t *testing.T) {
 		if len(endpoints) != 2 {
 			t.Errorf("Incorrect number of records: %d", len(endpoints))
 		}
-		for _, endpoint := range endpoints {
-			t.Logf("Endpoint for %++v", *endpoint)
+		for _, ep := range endpoints {
+			t.Logf("Endpoint for %++v", *ep)
 		}
 	}
 }
@@ -271,8 +261,8 @@ func TestAlibabaCloudProvider_Records(t *testing.T) {
 		if len(endpoints) != 2 {
 			t.Errorf("Incorrect number of records: %d", len(endpoints))
 		}
-		for _, endpoint := range endpoints {
-			t.Logf("Endpoint for %++v", *endpoint)
+		for _, ep := range endpoints {
+			t.Logf("Endpoint for %++v", *ep)
 		}
 	}
 }
@@ -282,7 +272,7 @@ func TestAlibabaCloudProvider_ApplyChanges(t *testing.T) {
 	defaultTtlPlan := &endpoint.Endpoint{
 		DNSName:    "ttl.container-service.top",
 		RecordType: "A",
-		RecordTTL:  defaultAlibabaCloudRecordTTL,
+		RecordTTL:  defaultTTL,
 		Targets:    endpoint.NewTargets("4.3.2.1"),
 	}
 	changes := plan.Changes{
@@ -313,7 +303,8 @@ func TestAlibabaCloudProvider_ApplyChanges(t *testing.T) {
 		},
 	}
 	ctx := context.Background()
-	p.ApplyChanges(ctx, &changes)
+	err := p.ApplyChanges(ctx, &changes)
+	assert.NoError(t, err)
 	endpoints, err := p.Records(ctx)
 	if err != nil {
 		t.Errorf("Failed to get records: %v", err)
@@ -321,8 +312,8 @@ func TestAlibabaCloudProvider_ApplyChanges(t *testing.T) {
 		if len(endpoints) != 3 {
 			t.Errorf("Incorrect number of records: %d", len(endpoints))
 		}
-		for _, endpoint := range endpoints {
-			t.Logf("Endpoint for %++v", *endpoint)
+		for _, ep := range endpoints {
+			t.Logf("Endpoint for %++v", *ep)
 		}
 	}
 	for _, ep := range endpoints {
@@ -343,8 +334,8 @@ func TestAlibabaCloudProvider_Records_PrivateZone(t *testing.T) {
 		if len(endpoints) != 2 {
 			t.Errorf("Incorrect number of records: %d", len(endpoints))
 		}
-		for _, endpoint := range endpoints {
-			t.Logf("Endpoint for %++v", *endpoint)
+		for _, ep := range endpoints {
+			t.Logf("Endpoint for %++v", *ep)
 		}
 	}
 }
@@ -378,7 +369,8 @@ func TestAlibabaCloudProvider_ApplyChanges_PrivateZone(t *testing.T) {
 		},
 	}
 	ctx := context.Background()
-	p.ApplyChanges(ctx, &changes)
+	err := p.ApplyChanges(ctx, &changes)
+	assert.NoError(t, err)
 	endpoints, err := p.Records(ctx)
 	if err != nil {
 		t.Errorf("Failed to get records: %v", err)
@@ -386,8 +378,8 @@ func TestAlibabaCloudProvider_ApplyChanges_PrivateZone(t *testing.T) {
 		if len(endpoints) != 2 {
 			t.Errorf("Incorrect number of records: %d", len(endpoints))
 		}
-		for _, endpoint := range endpoints {
-			t.Logf("Endpoint for %++v", *endpoint)
+		for _, ep := range endpoints {
+			t.Logf("Endpoint for %++v", *ep)
 		}
 	}
 }
diff --git a/provider/aws/aws_test.go b/provider/aws/aws_test.go
index 7305f064..c1719d17 100644
--- a/provider/aws/aws_test.go
+++ b/provider/aws/aws_test.go
@@ -400,37 +400,37 @@ func TestAWSRecords(t *testing.T) {
 		{
 			Name:            aws.String("list-test.zone-1.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeA,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}},
 		},
 		{
 			Name:            aws.String("list-test.zone-2.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeA,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.8.8")}},
 		},
 		{
 			Name:            aws.String(wildcardEscape("*.wildcard-test.zone-2.ext-dns-test-2.teapot.zalan.do.")),
 			Type:            route53types.RRTypeA,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.8.8")}},
 		},
 		{
 			Name:            aws.String(specialCharactersEscape("escape-%!s(<nil>)-codes.zone-2.ext-dns-test-2.teapot.zalan.do.")),
 			Type:            route53types.RRTypeCname,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("example")}},
 		},
 		{
 			Name:            aws.String(specialCharactersEscape("escape-%!s(<nil>)-codes-a.zone-2.ext-dns-test-2.teapot.zalan.do.")),
 			Type:            route53types.RRTypeA,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}},
 		},
 		{
 			Name: aws.String(specialCharactersEscape("escape-%!s(<nil>)-codes-alias.zone-2.ext-dns-test-2.teapot.zalan.do.")),
 			Type: route53types.RRTypeA,
-			TTL:  aws.Int64(recordTTL),
+			TTL:  aws.Int64(defaultTTL),
 			AliasTarget: &route53types.AliasTarget{
 				DNSName:              aws.String("escape-codes.eu-central-1.elb.amazonaws.com."),
 				EvaluateTargetHealth: false,
@@ -440,7 +440,7 @@ func TestAWSRecords(t *testing.T) {
 		{
 			Name: aws.String(specialCharactersEscape("escape-%!s(<nil>)-codes-alias.zone-2.ext-dns-test-2.teapot.zalan.do.")),
 			Type: route53types.RRTypeAaaa,
-			TTL:  aws.Int64(recordTTL),
+			TTL:  aws.Int64(defaultTTL),
 			AliasTarget: &route53types.AliasTarget{
 				DNSName:              aws.String("escape-codes.eu-central-1.elb.amazonaws.com."),
 				EvaluateTargetHealth: false,
@@ -504,19 +504,19 @@ func TestAWSRecords(t *testing.T) {
 		{
 			Name:            aws.String("list-test-multiple.zone-1.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeA,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.8.8")}, {Value: aws.String("8.8.4.4")}},
 		},
 		{
 			Name:            aws.String("prefix-*.wildcard.zone-1.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeTxt,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("random")}},
 		},
 		{
 			Name:            aws.String("weight-test.zone-1.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeA,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}},
 			SetIdentifier:   aws.String("test-set-1"),
 			Weight:          aws.Int64(10),
@@ -524,7 +524,7 @@ func TestAWSRecords(t *testing.T) {
 		{
 			Name:            aws.String("weight-test.zone-1.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeA,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("4.3.2.1")}},
 			SetIdentifier:   aws.String("test-set-2"),
 			Weight:          aws.Int64(20),
@@ -532,7 +532,7 @@ func TestAWSRecords(t *testing.T) {
 		{
 			Name:            aws.String("latency-test.zone-1.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeA,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}},
 			SetIdentifier:   aws.String("test-set"),
 			Region:          route53types.ResourceRecordSetRegionUsEast1,
@@ -540,7 +540,7 @@ func TestAWSRecords(t *testing.T) {
 		{
 			Name:            aws.String("failover-test.zone-1.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeA,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}},
 			SetIdentifier:   aws.String("test-set"),
 			Failover:        route53types.ResourceRecordSetFailoverPrimary,
@@ -548,7 +548,7 @@ func TestAWSRecords(t *testing.T) {
 		{
 			Name:             aws.String("multi-value-answer-test.zone-1.ext-dns-test-2.teapot.zalan.do."),
 			Type:             route53types.RRTypeA,
-			TTL:              aws.Int64(recordTTL),
+			TTL:              aws.Int64(defaultTTL),
 			ResourceRecords:  []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}},
 			SetIdentifier:    aws.String("test-set"),
 			MultiValueAnswer: aws.Bool(true),
@@ -556,7 +556,7 @@ func TestAWSRecords(t *testing.T) {
 		{
 			Name:            aws.String("geolocation-test.zone-1.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeA,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}},
 			SetIdentifier:   aws.String("test-set-1"),
 			GeoLocation: &route53types.GeoLocation{
@@ -566,7 +566,7 @@ func TestAWSRecords(t *testing.T) {
 		{
 			Name:            aws.String("geolocation-test.zone-1.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeA,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("4.3.2.1")}},
 			SetIdentifier:   aws.String("test-set-2"),
 			GeoLocation: &route53types.GeoLocation{
@@ -576,7 +576,7 @@ func TestAWSRecords(t *testing.T) {
 		{
 			Name:            aws.String("geolocation-subdivision-test.zone-1.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeA,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}},
 			SetIdentifier:   aws.String("test-set-1"),
 			GeoLocation: &route53types.GeoLocation{
@@ -586,7 +586,7 @@ func TestAWSRecords(t *testing.T) {
 		{
 			Name:            aws.String("healthcheck-test.zone-1.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeCname,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("foo.example.com")}},
 			SetIdentifier:   aws.String("test-set-1"),
 			HealthCheckId:   aws.String("foo-bar-healthcheck-id"),
@@ -595,7 +595,7 @@ func TestAWSRecords(t *testing.T) {
 		{
 			Name:            aws.String("healthcheck-test.zone-1.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeA,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("4.3.2.1")}},
 			SetIdentifier:   aws.String("test-set-2"),
 			HealthCheckId:   aws.String("abc-def-healthcheck-id"),
@@ -604,7 +604,7 @@ func TestAWSRecords(t *testing.T) {
 		{
 			Name:            aws.String("mail.zone-1.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeMx,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("10 mailhost1.example.com")}, {Value: aws.String("20 mailhost2.example.com")}},
 		},
 	})
@@ -613,32 +613,32 @@ func TestAWSRecords(t *testing.T) {
 	require.NoError(t, err)
 
 	validateEndpoints(t, provider, records, []*endpoint.Endpoint{
-		endpoint.NewEndpointWithTTL("list-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4"),
-		endpoint.NewEndpointWithTTL("list-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8"),
-		endpoint.NewEndpointWithTTL("*.wildcard-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8"),
-		endpoint.NewEndpointWithTTL("escape-%!s(<nil>)-codes.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "example").WithProviderSpecific(providerSpecificAlias, "false"),
-		endpoint.NewEndpointWithTTL("escape-%!s(<nil>)-codes-a.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4"),
-		endpoint.NewEndpointWithTTL("escape-%!s(<nil>)-codes-alias.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "escape-codes.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"),
-		endpoint.NewEndpointWithTTL("escape-%!s(<nil>)-codes-alias.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, endpoint.TTL(recordTTL), "escape-codes.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"),
-		endpoint.NewEndpointWithTTL("list-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"),
-		endpoint.NewEndpointWithTTL("list-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, endpoint.TTL(recordTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"),
-		endpoint.NewEndpointWithTTL("*.wildcard-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"),
-		endpoint.NewEndpointWithTTL("*.wildcard-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, endpoint.TTL(recordTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"),
-		endpoint.NewEndpointWithTTL("list-test-alias-evaluate.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true").WithProviderSpecific(providerSpecificAlias, "true"),
-		endpoint.NewEndpointWithTTL("list-test-alias-evaluate.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, endpoint.TTL(recordTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true").WithProviderSpecific(providerSpecificAlias, "true"),
-		endpoint.NewEndpointWithTTL("list-test-multiple.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8", "8.8.4.4"),
-		endpoint.NewEndpointWithTTL("prefix-*.wildcard.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeTXT, endpoint.TTL(recordTTL), "random"),
-		endpoint.NewEndpointWithTTL("weight-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4").WithSetIdentifier("test-set-1").WithProviderSpecific(providerSpecificWeight, "10"),
-		endpoint.NewEndpointWithTTL("weight-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "4.3.2.1").WithSetIdentifier("test-set-2").WithProviderSpecific(providerSpecificWeight, "20"),
-		endpoint.NewEndpointWithTTL("latency-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4").WithSetIdentifier("test-set").WithProviderSpecific(providerSpecificRegion, "us-east-1"),
-		endpoint.NewEndpointWithTTL("failover-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4").WithSetIdentifier("test-set").WithProviderSpecific(providerSpecificFailover, "PRIMARY"),
-		endpoint.NewEndpointWithTTL("multi-value-answer-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4").WithSetIdentifier("test-set").WithProviderSpecific(providerSpecificMultiValueAnswer, ""),
-		endpoint.NewEndpointWithTTL("geolocation-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4").WithSetIdentifier("test-set-1").WithProviderSpecific(providerSpecificGeolocationContinentCode, "EU"),
-		endpoint.NewEndpointWithTTL("geolocation-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "4.3.2.1").WithSetIdentifier("test-set-2").WithProviderSpecific(providerSpecificGeolocationCountryCode, "DE"),
-		endpoint.NewEndpointWithTTL("geolocation-subdivision-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4").WithSetIdentifier("test-set-1").WithProviderSpecific(providerSpecificGeolocationSubdivisionCode, "NY"),
-		endpoint.NewEndpointWithTTL("healthcheck-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "foo.example.com").WithSetIdentifier("test-set-1").WithProviderSpecific(providerSpecificWeight, "10").WithProviderSpecific(providerSpecificHealthCheckID, "foo-bar-healthcheck-id").WithProviderSpecific(providerSpecificAlias, "false"),
-		endpoint.NewEndpointWithTTL("healthcheck-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "4.3.2.1").WithSetIdentifier("test-set-2").WithProviderSpecific(providerSpecificWeight, "20").WithProviderSpecific(providerSpecificHealthCheckID, "abc-def-healthcheck-id"),
-		endpoint.NewEndpointWithTTL("mail.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeMX, endpoint.TTL(recordTTL), "10 mailhost1.example.com", "20 mailhost2.example.com"),
+		endpoint.NewEndpointWithTTL("list-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "1.2.3.4"),
+		endpoint.NewEndpointWithTTL("list-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "8.8.8.8"),
+		endpoint.NewEndpointWithTTL("*.wildcard-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "8.8.8.8"),
+		endpoint.NewEndpointWithTTL("escape-%!s(<nil>)-codes.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(defaultTTL), "example").WithProviderSpecific(providerSpecificAlias, "false"),
+		endpoint.NewEndpointWithTTL("escape-%!s(<nil>)-codes-a.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "1.2.3.4"),
+		endpoint.NewEndpointWithTTL("escape-%!s(<nil>)-codes-alias.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "escape-codes.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"),
+		endpoint.NewEndpointWithTTL("escape-%!s(<nil>)-codes-alias.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, endpoint.TTL(defaultTTL), "escape-codes.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"),
+		endpoint.NewEndpointWithTTL("list-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"),
+		endpoint.NewEndpointWithTTL("list-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, endpoint.TTL(defaultTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"),
+		endpoint.NewEndpointWithTTL("*.wildcard-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"),
+		endpoint.NewEndpointWithTTL("*.wildcard-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, endpoint.TTL(defaultTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"),
+		endpoint.NewEndpointWithTTL("list-test-alias-evaluate.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true").WithProviderSpecific(providerSpecificAlias, "true"),
+		endpoint.NewEndpointWithTTL("list-test-alias-evaluate.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeAAAA, endpoint.TTL(defaultTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true").WithProviderSpecific(providerSpecificAlias, "true"),
+		endpoint.NewEndpointWithTTL("list-test-multiple.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "8.8.8.8", "8.8.4.4"),
+		endpoint.NewEndpointWithTTL("prefix-*.wildcard.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeTXT, endpoint.TTL(defaultTTL), "random"),
+		endpoint.NewEndpointWithTTL("weight-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "1.2.3.4").WithSetIdentifier("test-set-1").WithProviderSpecific(providerSpecificWeight, "10"),
+		endpoint.NewEndpointWithTTL("weight-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "4.3.2.1").WithSetIdentifier("test-set-2").WithProviderSpecific(providerSpecificWeight, "20"),
+		endpoint.NewEndpointWithTTL("latency-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "1.2.3.4").WithSetIdentifier("test-set").WithProviderSpecific(providerSpecificRegion, "us-east-1"),
+		endpoint.NewEndpointWithTTL("failover-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "1.2.3.4").WithSetIdentifier("test-set").WithProviderSpecific(providerSpecificFailover, "PRIMARY"),
+		endpoint.NewEndpointWithTTL("multi-value-answer-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "1.2.3.4").WithSetIdentifier("test-set").WithProviderSpecific(providerSpecificMultiValueAnswer, ""),
+		endpoint.NewEndpointWithTTL("geolocation-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "1.2.3.4").WithSetIdentifier("test-set-1").WithProviderSpecific(providerSpecificGeolocationContinentCode, "EU"),
+		endpoint.NewEndpointWithTTL("geolocation-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "4.3.2.1").WithSetIdentifier("test-set-2").WithProviderSpecific(providerSpecificGeolocationCountryCode, "DE"),
+		endpoint.NewEndpointWithTTL("geolocation-subdivision-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "1.2.3.4").WithSetIdentifier("test-set-1").WithProviderSpecific(providerSpecificGeolocationSubdivisionCode, "NY"),
+		endpoint.NewEndpointWithTTL("healthcheck-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(defaultTTL), "foo.example.com").WithSetIdentifier("test-set-1").WithProviderSpecific(providerSpecificWeight, "10").WithProviderSpecific(providerSpecificHealthCheckID, "foo-bar-healthcheck-id").WithProviderSpecific(providerSpecificAlias, "false"),
+		endpoint.NewEndpointWithTTL("healthcheck-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "4.3.2.1").WithSetIdentifier("test-set-2").WithProviderSpecific(providerSpecificWeight, "20").WithProviderSpecific(providerSpecificHealthCheckID, "abc-def-healthcheck-id"),
+		endpoint.NewEndpointWithTTL("mail.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeMX, endpoint.TTL(defaultTTL), "10 mailhost1.example.com", "20 mailhost2.example.com"),
 	})
 }
 
@@ -647,7 +647,7 @@ func TestAWSRecordsSoftError(t *testing.T) {
 		{
 			Name:            aws.String("list-test.zone-1.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeA,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}},
 		},
 	})
@@ -710,55 +710,55 @@ func TestAWSApplyChanges(t *testing.T) {
 			{
 				Name:            aws.String("update-test.zone-1.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeA,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.8.8")}},
 			},
 			{
 				Name:            aws.String("update-test-aaaa.zone-1.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeAaaa,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("2606:4700:4700::1111")}},
 			},
 			{
 				Name:            aws.String("delete-test.zone-1.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeA,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.8.8")}},
 			},
 			{
 				Name:            aws.String("delete-test-aaaa.zone-1.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeAaaa,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("2606:4700:4700::1111")}},
 			},
 			{
 				Name:            aws.String("update-test.zone-2.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeA,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.4.4")}},
 			},
 			{
 				Name:            aws.String("update-test-aaaa.zone-2.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeAaaa,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("2606:4700:4700::1001")}},
 			},
 			{
 				Name:            aws.String("delete-test.zone-2.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeA,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.4.4")}},
 			},
 			{
 				Name:            aws.String("delete-test-aaaa.zone-2.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeAaaa,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("2606:4700:4700::1001")}},
 			},
 			{
 				Name:            aws.String("update-test-a-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeA,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.1.1.1")}},
 			},
 			{
@@ -782,7 +782,7 @@ func TestAWSApplyChanges(t *testing.T) {
 			{
 				Name:            aws.String("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeCname,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("bar.elb.amazonaws.com")}},
 			},
 			{
@@ -806,7 +806,7 @@ func TestAWSApplyChanges(t *testing.T) {
 			{
 				Name:            aws.String("delete-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeCname,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("qux.elb.amazonaws.com")}},
 			},
 			{
@@ -830,25 +830,25 @@ func TestAWSApplyChanges(t *testing.T) {
 			{
 				Name:            aws.String("update-test-multiple.zone-2.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeA,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.8.8")}, {Value: aws.String("8.8.4.4")}},
 			},
 			{
 				Name:            aws.String("delete-test-multiple.zone-2.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeA,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}, {Value: aws.String("4.3.2.1")}},
 			},
 			{
 				Name:            aws.String("delete-test-multiple-aaaa.zone-2.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeAaaa,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("2606:4700:4700::1111")}, {Value: aws.String("2606:4700:4700::1001")}},
 			},
 			{
 				Name:            aws.String("weighted-to-simple.zone-1.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeA,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}},
 				SetIdentifier:   aws.String("weighted-to-simple"),
 				Weight:          aws.Int64(10),
@@ -856,13 +856,13 @@ func TestAWSApplyChanges(t *testing.T) {
 			{
 				Name:            aws.String("simple-to-weighted.zone-1.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeA,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}},
 			},
 			{
 				Name:            aws.String("policy-change.zone-1.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeA,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}},
 				SetIdentifier:   aws.String("policy-change"),
 				Weight:          aws.Int64(10),
@@ -870,7 +870,7 @@ func TestAWSApplyChanges(t *testing.T) {
 			{
 				Name:            aws.String("set-identifier-change.zone-1.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeA,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}},
 				SetIdentifier:   aws.String("before"),
 				Weight:          aws.Int64(10),
@@ -878,7 +878,7 @@ func TestAWSApplyChanges(t *testing.T) {
 			{
 				Name:            aws.String("set-identifier-no-change.zone-1.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeA,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}},
 				SetIdentifier:   aws.String("no-change"),
 				Weight:          aws.Int64(10),
@@ -886,19 +886,19 @@ func TestAWSApplyChanges(t *testing.T) {
 			{
 				Name:            aws.String("update-test-mx.zone-2.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeMx,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("10 mailhost2.bar.elb.amazonaws.com")}},
 			},
 			{
 				Name:            aws.String("delete-test-mx.zone-2.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeMx,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("30 mailhost1.foo.elb.amazonaws.com")}},
 			},
 			{
 				Name:            aws.String(specialCharactersEscape("escape-%!s(<nil>)-codes.zone-2.ext-dns-test-2.teapot.zalan.do.")),
 				Type:            route53types.RRTypeA,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}},
 				SetIdentifier:   aws.String("no-change"),
 				Weight:          aws.Int64(10),
@@ -993,25 +993,25 @@ func TestAWSApplyChanges(t *testing.T) {
 			{
 				Name:            aws.String("create-test.zone-1.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeA,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.8.8")}},
 			},
 			{
 				Name:            aws.String("create-test-aaaa.zone-1.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeAaaa,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("2606:4700:4700::1111")}},
 			},
 			{
 				Name:            aws.String("update-test.zone-1.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeA,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}},
 			},
 			{
 				Name:            aws.String("update-test-aaaa.zone-1.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeAaaa,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("2606:4700:4700::1001")}},
 			},
 			{
@@ -1035,25 +1035,25 @@ func TestAWSApplyChanges(t *testing.T) {
 			{
 				Name:            aws.String("update-test-alias-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeCname,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("my-internal-host.example.com")}},
 			},
 			{
 				Name:            aws.String("create-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeCname,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("foo.elb.amazonaws.com")}},
 			},
 			{
 				Name:            aws.String("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeCname,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("baz.elb.amazonaws.com")}},
 			},
 			{
 				Name:            aws.String("create-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeCname,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("foo.elb.amazonaws.com")}},
 			},
 			{
@@ -1077,13 +1077,13 @@ func TestAWSApplyChanges(t *testing.T) {
 			{
 				Name:            aws.String("weighted-to-simple.zone-1.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeA,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}},
 			},
 			{
 				Name:            aws.String("simple-to-weighted.zone-1.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeA,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}},
 				SetIdentifier:   aws.String("simple-to-weighted"),
 				Weight:          aws.Int64(10),
@@ -1091,7 +1091,7 @@ func TestAWSApplyChanges(t *testing.T) {
 			{
 				Name:            aws.String("policy-change.zone-1.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeA,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}},
 				SetIdentifier:   aws.String("policy-change"),
 				Region:          route53types.ResourceRecordSetRegionUsEast1,
@@ -1099,7 +1099,7 @@ func TestAWSApplyChanges(t *testing.T) {
 			{
 				Name:            aws.String("set-identifier-change.zone-1.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeA,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}},
 				SetIdentifier:   aws.String("after"),
 				Weight:          aws.Int64(10),
@@ -1107,7 +1107,7 @@ func TestAWSApplyChanges(t *testing.T) {
 			{
 				Name:            aws.String("set-identifier-no-change.zone-1.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeA,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}},
 				SetIdentifier:   aws.String("no-change"),
 				Weight:          aws.Int64(20),
@@ -1115,7 +1115,7 @@ func TestAWSApplyChanges(t *testing.T) {
 			{
 				Name:            aws.String("create-test-mx.zone-1.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeMx,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("10 mailhost1.foo.elb.amazonaws.com")}},
 			},
 		})
@@ -1123,7 +1123,7 @@ func TestAWSApplyChanges(t *testing.T) {
 			{
 				Name:            aws.String("escape-\\045\\041s\\050\\074nil\\076\\051-codes.zone-2.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeA,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}},
 				SetIdentifier:   aws.String("no-change"),
 				Weight:          aws.Int64(10),
@@ -1131,55 +1131,55 @@ func TestAWSApplyChanges(t *testing.T) {
 			{
 				Name:            aws.String("create-test.zone-2.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeA,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.4.4")}},
 			},
 			{
 				Name:            aws.String("create-test-aaaa.zone-2.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeAaaa,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("2606:4700:4700::1001")}},
 			},
 			{
 				Name:            aws.String("update-test.zone-2.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeA,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("4.3.2.1")}},
 			},
 			{
 				Name:            aws.String("update-test-aaaa.zone-2.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeAaaa,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("2606:4700:4700::1111")}},
 			},
 			{
 				Name:            aws.String("create-test-multiple.zone-2.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeA,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.8.8")}, {Value: aws.String("8.8.4.4")}},
 			},
 			{
 				Name:            aws.String("create-test-multiple-aaaa.zone-2.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeAaaa,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("2606:4700:4700::1111")}, {Value: aws.String("2606:4700:4700::1001")}},
 			},
 			{
 				Name:            aws.String("update-test-multiple.zone-2.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeA,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}, {Value: aws.String("4.3.2.1")}},
 			},
 			{
 				Name:            aws.String("update-test-multiple-aaaa.zone-2.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeAaaa,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("2606:4700:4700::1001")}, {Value: aws.String("2606:4700:4700::1111")}},
 			},
 			{
 				Name:            aws.String("update-test-mx.zone-2.ext-dns-test-2.teapot.zalan.do."),
 				Type:            route53types.RRTypeMx,
-				TTL:             aws.Int64(recordTTL),
+				TTL:             aws.Int64(defaultTTL),
 				ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("20 mailhost3.foo.elb.amazonaws.com")}},
 			},
 		})
@@ -1191,79 +1191,79 @@ func TestAWSApplyChangesDryRun(t *testing.T) {
 		{
 			Name:            aws.String("update-test.zone-1.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeA,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.8.8")}},
 		},
 		{
 			Name:            aws.String("delete-test.zone-1.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeA,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.8.8")}},
 		},
 		{
 			Name:            aws.String("update-test.zone-2.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeA,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.4.4")}},
 		},
 		{
 			Name:            aws.String("delete-test.zone-2.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeA,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.4.4")}},
 		},
 		{
 			Name:            aws.String("update-test-a-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeA,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.1.1.1")}},
 		},
 		{
 			Name:            aws.String("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeCname,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("bar.elb.amazonaws.com")}},
 		},
 		{
 			Name:            aws.String("delete-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeCname,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("qux.elb.amazonaws.com")}},
 		},
 		{
 			Name:            aws.String("update-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeCname,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("bar.elb.amazonaws.com")}},
 		},
 		{
 			Name:            aws.String("delete-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeCname,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("qux.elb.amazonaws.com")}},
 		},
 		{
 			Name:            aws.String("update-test-multiple.zone-2.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeA,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("8.8.8.8")}, {Value: aws.String("8.8.4.4")}},
 		},
 		{
 			Name:            aws.String("delete-test-multiple.zone-2.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeA,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("1.2.3.4")}, {Value: aws.String("4.3.2.1")}},
 		},
 		{
 			Name:            aws.String("update-test-mx.zone-1.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeMx,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("20 mail.foo.elb.amazonaws.com")}},
 		},
 		{
 			Name:            aws.String("delete-test-mx.zone-2.ext-dns-test-2.teapot.zalan.do."),
 			Type:            route53types.RRTypeMx,
-			TTL:             aws.Int64(recordTTL),
+			TTL:             aws.Int64(defaultTTL),
 			ResourceRecords: []route53types.ResourceRecord{{Value: aws.String("10 mail.bar.elb.amazonaws.com")}},
 		},
 	}
@@ -1464,7 +1464,7 @@ func TestAWSsubmitChanges(t *testing.T) {
 		for j := 1; j < (hosts + 1); j++ {
 			hostname := fmt.Sprintf("subnet%dhost%d.zone-1.ext-dns-test-2.teapot.zalan.do", i, j)
 			ip := fmt.Sprintf("1.1.%d.%d", i, j)
-			ep := endpoint.NewEndpointWithTTL(hostname, endpoint.RecordTypeA, endpoint.TTL(recordTTL), ip)
+			ep := endpoint.NewEndpointWithTTL(hostname, endpoint.RecordTypeA, endpoint.TTL(defaultTTL), ip)
 			endpoints = append(endpoints, ep)
 		}
 	}
@@ -1491,7 +1491,7 @@ func TestAWSsubmitChangesError(t *testing.T) {
 	zones, err := provider.zones(ctx)
 	require.NoError(t, err)
 
-	ep := endpoint.NewEndpointWithTTL("fail.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.0.0.1")
+	ep := endpoint.NewEndpointWithTTL("fail.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "1.0.0.1")
 	cs := provider.newChanges(route53types.ChangeActionCreate, []*endpoint.Endpoint{ep})
 
 	require.Error(t, provider.submitChanges(ctx, cs, zones))
@@ -1504,11 +1504,11 @@ func TestAWSsubmitChangesRetryOnError(t *testing.T) {
 	zones, err := provider.zones(ctx)
 	require.NoError(t, err)
 
-	ep1 := endpoint.NewEndpointWithTTL("success.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.0.0.1")
-	ep2 := endpoint.NewEndpointWithTTL("fail.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.0.0.2")
-	ep3 := endpoint.NewEndpointWithTTL("success2.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.0.0.3")
+	ep1 := endpoint.NewEndpointWithTTL("success.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "1.0.0.1")
+	ep2 := endpoint.NewEndpointWithTTL("fail.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "1.0.0.2")
+	ep3 := endpoint.NewEndpointWithTTL("success2.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "1.0.0.3")
 
-	ep2txt := endpoint.NewEndpointWithTTL("fail__edns_housekeeping.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeTXT, endpoint.TTL(recordTTL), "something") // "__edns_housekeeping" is the TXT suffix
+	ep2txt := endpoint.NewEndpointWithTTL("fail__edns_housekeeping.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeTXT, endpoint.TTL(defaultTTL), "something") // "__edns_housekeeping" is the TXT suffix
 	ep2txt.Labels = map[string]string{
 		endpoint.OwnedRecordLabelKey: "fail.zone-1.ext-dns-test-2.teapot.zalan.do",
 	}
@@ -2315,26 +2315,26 @@ func containsRecordWithDNSName(records []*endpoint.Endpoint, dnsName string) boo
 func TestRequiresDeleteCreate(t *testing.T) {
 	provider, _ := newAWSProvider(t, endpoint.NewDomainFilter([]string{"foo.bar."}), provider.NewZoneIDFilter([]string{}), provider.NewZoneTypeFilter(""), defaultEvaluateTargetHealth, false, nil)
 
-	oldRecordType := endpoint.NewEndpointWithTTL("recordType", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8")
-	newRecordType := endpoint.NewEndpointWithTTL("recordType", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "bar").WithProviderSpecific(providerSpecificAlias, "false")
+	oldRecordType := endpoint.NewEndpointWithTTL("recordType", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "8.8.8.8")
+	newRecordType := endpoint.NewEndpointWithTTL("recordType", endpoint.RecordTypeCNAME, endpoint.TTL(defaultTTL), "bar").WithProviderSpecific(providerSpecificAlias, "false")
 
 	assert.False(t, provider.requiresDeleteCreate(oldRecordType, oldRecordType), "actual and expected endpoints don't match. %+v:%+v", oldRecordType, oldRecordType)
 	assert.True(t, provider.requiresDeleteCreate(oldRecordType, newRecordType), "actual and expected endpoints don't match. %+v:%+v", oldRecordType, newRecordType)
 
-	oldAtoAlias := endpoint.NewEndpointWithTTL("AtoAlias", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.1.1.1")
-	newAtoAlias := endpoint.NewEndpointWithTTL("AtoAlias", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "bar.us-east-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true")
+	oldAtoAlias := endpoint.NewEndpointWithTTL("AtoAlias", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "1.1.1.1")
+	newAtoAlias := endpoint.NewEndpointWithTTL("AtoAlias", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "bar.us-east-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true")
 
 	assert.False(t, provider.requiresDeleteCreate(oldAtoAlias, oldAtoAlias), "actual and expected endpoints don't match. %+v:%+v", oldAtoAlias, oldAtoAlias.DNSName)
 	assert.True(t, provider.requiresDeleteCreate(oldAtoAlias, newAtoAlias), "actual and expected endpoints don't match. %+v:%+v", oldAtoAlias, newAtoAlias)
 
-	oldPolicy := endpoint.NewEndpointWithTTL("policy", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8").WithSetIdentifier("nochange").WithProviderSpecific(providerSpecificRegion, "us-east-1")
-	newPolicy := endpoint.NewEndpointWithTTL("policy", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8").WithSetIdentifier("nochange").WithProviderSpecific(providerSpecificWeight, "10")
+	oldPolicy := endpoint.NewEndpointWithTTL("policy", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "8.8.8.8").WithSetIdentifier("nochange").WithProviderSpecific(providerSpecificRegion, "us-east-1")
+	newPolicy := endpoint.NewEndpointWithTTL("policy", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "8.8.8.8").WithSetIdentifier("nochange").WithProviderSpecific(providerSpecificWeight, "10")
 
 	assert.False(t, provider.requiresDeleteCreate(oldPolicy, oldPolicy), "actual and expected endpoints don't match. %+v:%+v", oldPolicy, oldPolicy)
 	assert.True(t, provider.requiresDeleteCreate(oldPolicy, newPolicy), "actual and expected endpoints don't match. %+v:%+v", oldPolicy, newPolicy)
 
-	oldSetIdentifier := endpoint.NewEndpointWithTTL("setIdentifier", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8").WithSetIdentifier("old")
-	newSetIdentifier := endpoint.NewEndpointWithTTL("setIdentifier", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8").WithSetIdentifier("new")
+	oldSetIdentifier := endpoint.NewEndpointWithTTL("setIdentifier", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "8.8.8.8").WithSetIdentifier("old")
+	newSetIdentifier := endpoint.NewEndpointWithTTL("setIdentifier", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "8.8.8.8").WithSetIdentifier("new")
 
 	assert.False(t, provider.requiresDeleteCreate(oldSetIdentifier, oldSetIdentifier), "actual and expected endpoints don't match. %+v:%+v", oldSetIdentifier, oldSetIdentifier)
 	assert.True(t, provider.requiresDeleteCreate(oldSetIdentifier, newSetIdentifier), "actual and expected endpoints don't match. %+v:%+v", oldSetIdentifier, newSetIdentifier)
diff --git a/provider/aws/aws_utils_test.go b/provider/aws/aws_utils_test.go
index a7c7e2aa..eddb8dc8 100644
--- a/provider/aws/aws_utils_test.go
+++ b/provider/aws/aws_utils_test.go
@@ -24,8 +24,8 @@ import (
 
 	"github.com/aws/aws-sdk-go-v2/service/route53"
 	route53types "github.com/aws/aws-sdk-go-v2/service/route53/types"
+	yaml "github.com/goccy/go-yaml"
 	"github.com/stretchr/testify/assert"
-	"gopkg.in/yaml.v3"
 	"sigs.k8s.io/external-dns/endpoint"
 	"sigs.k8s.io/external-dns/provider"
 )
diff --git a/provider/azure/config_test.go b/provider/azure/config_test.go
index 1099515d..956599a9 100644
--- a/provider/azure/config_test.go
+++ b/provider/azure/config_test.go
@@ -50,7 +50,7 @@ func TestGetCloudConfiguration(t *testing.T) {
 
 func TestOverrideConfiguration(t *testing.T) {
 	_, filename, _, _ := runtime.Caller(0)
-	configFile := path.Join(path.Dir(filename), "config_test.json")
+	configFile := path.Join(path.Dir(filename), "fixtures/config_test.json")
 	cfg, err := getConfig(configFile, "subscription-override", "rg-override", "", "aad-endpoint-override")
 	if err != nil {
 		t.Errorf("got unexpected err %v", err)
diff --git a/provider/cloudflare/cloudflare_test.go b/provider/cloudflare/cloudflare_test.go
index 1c02abd9..f5094014 100644
--- a/provider/cloudflare/cloudflare_test.go
+++ b/provider/cloudflare/cloudflare_test.go
@@ -21,16 +21,16 @@ import (
 	"errors"
 	"fmt"
 	"os"
+	"reflect"
 	"slices"
 	"sort"
 	"strings"
 	"testing"
 
 	cloudflare "github.com/cloudflare/cloudflare-go"
+	"github.com/maxatome/go-testdeep/td"
 	log "github.com/sirupsen/logrus"
 	"github.com/stretchr/testify/assert"
-
-	"github.com/maxatome/go-testdeep/td"
 	"sigs.k8s.io/external-dns/endpoint"
 	"sigs.k8s.io/external-dns/internal/testutils"
 	"sigs.k8s.io/external-dns/plan"
@@ -38,10 +38,11 @@ import (
 )
 
 type MockAction struct {
-	Name       string
-	ZoneId     string
-	RecordId   string
-	RecordData cloudflare.DNSRecord
+	Name             string
+	ZoneId           string
+	RecordId         string
+	RecordData       cloudflare.DNSRecord
+	RegionalHostname cloudflare.RegionalHostname
 }
 
 type mockCloudFlareClient struct {
@@ -50,6 +51,7 @@ type mockCloudFlareClient struct {
 	Records               map[string]map[string]cloudflare.DNSRecord
 	Actions               []MockAction
 	listZonesError        error
+	zoneDetailsError      error
 	listZonesContextError error
 	dnsRecordsError       error
 	customHostnames       map[string][]cloudflare.CustomHostname
@@ -225,6 +227,19 @@ func (m *mockCloudFlareClient) UpdateDNSRecord(ctx context.Context, rc *cloudfla
 	return nil
 }
 
+func (m *mockCloudFlareClient) CreateDataLocalizationRegionalHostname(ctx context.Context, rc *cloudflare.ResourceContainer, rp cloudflare.CreateDataLocalizationRegionalHostnameParams) error {
+	m.Actions = append(m.Actions, MockAction{
+		Name:     "CreateDataLocalizationRegionalHostname",
+		ZoneId:   rc.Identifier,
+		RecordId: "",
+		RegionalHostname: cloudflare.RegionalHostname{
+			Hostname:  rp.Hostname,
+			RegionKey: rp.RegionKey,
+		},
+	})
+	return nil
+}
+
 func (m *mockCloudFlareClient) UpdateDataLocalizationRegionalHostname(ctx context.Context, rc *cloudflare.ResourceContainer, rp cloudflare.UpdateDataLocalizationRegionalHostnameParams) error {
 	m.Actions = append(m.Actions, MockAction{
 		Name:     "UpdateDataLocalizationRegionalHostname",
@@ -237,6 +252,18 @@ func (m *mockCloudFlareClient) UpdateDataLocalizationRegionalHostname(ctx contex
 	return nil
 }
 
+func (m *mockCloudFlareClient) DeleteDataLocalizationRegionalHostname(ctx context.Context, rc *cloudflare.ResourceContainer, hostname string) error {
+	m.Actions = append(m.Actions, MockAction{
+		Name:     "DeleteDataLocalizationRegionalHostname",
+		ZoneId:   rc.Identifier,
+		RecordId: "",
+		RecordData: cloudflare.DNSRecord{
+			Name: hostname,
+		},
+	})
+	return nil
+}
+
 func (m *mockCloudFlareClient) DeleteDNSRecord(ctx context.Context, rc *cloudflare.ResourceContainer, recordID string) error {
 	m.Actions = append(m.Actions, MockAction{
 		Name:     "Delete",
@@ -384,6 +411,10 @@ func (m *mockCloudFlareClient) ListZonesContext(ctx context.Context, opts ...clo
 }
 
 func (m *mockCloudFlareClient) ZoneDetails(ctx context.Context, zoneID string) (cloudflare.Zone, error) {
+	if m.zoneDetailsError != nil {
+		return cloudflare.Zone{}, m.zoneDetailsError
+	}
+
 	for id, zoneName := range m.Zones {
 		if zoneID == id {
 			return cloudflare.Zone{
@@ -405,16 +436,6 @@ func getCustomHostnameIdxByID(chs []cloudflare.CustomHostname, customHostnameID
 	return -1
 }
 
-func getCustomHostnameIDbyCustomHostnameAndOrigin(chs CustomHostnamesMap, customHostname string, origin string) (string, string) {
-	for _, ch := range chs {
-		if ch.Hostname == customHostname && ch.CustomOriginServer == origin {
-			return ch.ID, ch.Hostname
-
-		}
-	}
-	return "", ""
-}
-
 func AssertActions(t *testing.T, provider *CloudFlareProvider, endpoints []*endpoint.Endpoint, actions []MockAction, managedRecords []string, args ...interface{}) {
 	t.Helper()
 
@@ -755,6 +776,110 @@ func TestCloudflareSetProxied(t *testing.T) {
 	}
 }
 
+func TestCloudflareRegionalHostname(t *testing.T) {
+	endpoints := []*endpoint.Endpoint{
+		{
+			RecordType: "A",
+			DNSName:    "bar.com",
+			Targets:    endpoint.Targets{"127.0.0.1", "127.0.0.2"},
+			ProviderSpecific: endpoint.ProviderSpecific{
+				{
+					Name:  "external-dns.alpha.kubernetes.io/cloudflare-region-key",
+					Value: "eu",
+				},
+			},
+		},
+	}
+
+	AssertActions(t, &CloudFlareProvider{RegionKey: "us"}, endpoints, []MockAction{
+		{
+			Name:     "Create",
+			ZoneId:   "001",
+			RecordId: generateDNSRecordID("A", "bar.com", "127.0.0.1"),
+			RecordData: cloudflare.DNSRecord{
+				ID:      generateDNSRecordID("A", "bar.com", "127.0.0.1"),
+				Type:    "A",
+				Name:    "bar.com",
+				Content: "127.0.0.1",
+				TTL:     1,
+				Proxied: proxyDisabled,
+			},
+		},
+		{
+			Name:     "Create",
+			ZoneId:   "001",
+			RecordId: generateDNSRecordID("A", "bar.com", "127.0.0.2"),
+			RecordData: cloudflare.DNSRecord{
+				ID:      generateDNSRecordID("A", "bar.com", "127.0.0.2"),
+				Type:    "A",
+				Name:    "bar.com",
+				Content: "127.0.0.2",
+				TTL:     1,
+				Proxied: proxyDisabled,
+			},
+		},
+		{
+			Name:   "CreateDataLocalizationRegionalHostname",
+			ZoneId: "001",
+			RegionalHostname: cloudflare.RegionalHostname{
+				Hostname:  "bar.com",
+				RegionKey: "eu",
+			},
+		},
+	},
+		[]string{endpoint.RecordTypeA, endpoint.RecordTypeCNAME},
+	)
+}
+
+func TestCloudflareRegionalHostnameDefaults(t *testing.T) {
+	endpoints := []*endpoint.Endpoint{
+		{
+			RecordType: "A",
+			DNSName:    "bar.com",
+			Targets:    endpoint.Targets{"127.0.0.1", "127.0.0.2"},
+		},
+	}
+
+	AssertActions(t, &CloudFlareProvider{RegionKey: "us"}, endpoints, []MockAction{
+		{
+			Name:     "Create",
+			ZoneId:   "001",
+			RecordId: generateDNSRecordID("A", "bar.com", "127.0.0.1"),
+			RecordData: cloudflare.DNSRecord{
+				ID:      generateDNSRecordID("A", "bar.com", "127.0.0.1"),
+				Type:    "A",
+				Name:    "bar.com",
+				Content: "127.0.0.1",
+				TTL:     1,
+				Proxied: proxyDisabled,
+			},
+		},
+		{
+			Name:     "Create",
+			ZoneId:   "001",
+			RecordId: generateDNSRecordID("A", "bar.com", "127.0.0.2"),
+			RecordData: cloudflare.DNSRecord{
+				ID:      generateDNSRecordID("A", "bar.com", "127.0.0.2"),
+				Type:    "A",
+				Name:    "bar.com",
+				Content: "127.0.0.2",
+				TTL:     1,
+				Proxied: proxyDisabled,
+			},
+		},
+		{
+			Name:   "CreateDataLocalizationRegionalHostname",
+			ZoneId: "001",
+			RegionalHostname: cloudflare.RegionalHostname{
+				Hostname:  "bar.com",
+				RegionKey: "us",
+			},
+		},
+	},
+		[]string{endpoint.RecordTypeA, endpoint.RecordTypeCNAME},
+	)
+}
+
 func TestCloudflareZones(t *testing.T) {
 	provider := &CloudFlareProvider{
 		Client:       NewMockCloudFlareClient(),
@@ -771,6 +896,24 @@ func TestCloudflareZones(t *testing.T) {
 	assert.Equal(t, "bar.com", zones[0].Name)
 }
 
+// test failures on zone lookup
+func TestCloudflareZonesFailed(t *testing.T) {
+
+	client := NewMockCloudFlareClient()
+	client.zoneDetailsError = errors.New("zone lookup failed")
+
+	provider := &CloudFlareProvider{
+		Client:       client,
+		domainFilter: endpoint.NewDomainFilter([]string{"bar.com"}),
+		zoneIDFilter: provider.NewZoneIDFilter([]string{"001"}),
+	}
+
+	_, err := provider.Zones(context.Background())
+	if err == nil {
+		t.Errorf("should fail, %s", err)
+	}
+}
+
 func TestCloudFlareZonesWithIDFilter(t *testing.T) {
 	client := NewMockCloudFlareClient()
 	client.listZonesError = errors.New("shouldn't need to list zones when ZoneIDFilter in use")
@@ -882,64 +1025,88 @@ func TestCloudflareRecords(t *testing.T) {
 }
 
 func TestCloudflareProvider(t *testing.T) {
-	_ = os.Setenv("CF_API_TOKEN", "abc123def")
-	_, err := NewCloudFlareProvider(
-		endpoint.NewDomainFilter([]string{"bar.com"}),
-		provider.NewZoneIDFilter([]string{""}),
-		false,
-		true,
-		5000,
-		"",
-		CustomHostnamesConfig{Enabled: false})
-	if err != nil {
-		t.Errorf("should not fail, %s", err)
+	var err error
+
+	type EnvVar struct {
+		Key   string
+		Value string
 	}
 
-	_ = os.Unsetenv("CF_API_TOKEN")
 	tokenFile := "/tmp/cf_api_token"
 	if err := os.WriteFile(tokenFile, []byte("abc123def"), 0o644); err != nil {
 		t.Errorf("failed to write token file, %s", err)
 	}
-	_ = os.Setenv("CF_API_TOKEN", tokenFile)
-	_, err = NewCloudFlareProvider(
-		endpoint.NewDomainFilter([]string{"bar.com"}),
-		provider.NewZoneIDFilter([]string{""}),
-		false,
-		true,
-		5000,
-		"",
-		CustomHostnamesConfig{Enabled: false})
-	if err != nil {
-		t.Errorf("should not fail, %s", err)
-	}
 
-	_ = os.Unsetenv("CF_API_TOKEN")
-	_ = os.Setenv("CF_API_KEY", "xxxxxxxxxxxxxxxxx")
-	_ = os.Setenv("CF_API_EMAIL", "test@test.com")
-	_, err = NewCloudFlareProvider(
-		endpoint.NewDomainFilter([]string{"bar.com"}),
-		provider.NewZoneIDFilter([]string{""}),
-		false,
-		true,
-		5000,
-		"",
-		CustomHostnamesConfig{Enabled: false})
-	if err != nil {
-		t.Errorf("should not fail, %s", err)
+	testCases := []struct {
+		Name        string
+		Environment []EnvVar
+		ShouldFail  bool
+	}{
+		{
+			Name: "use_api_token",
+			Environment: []EnvVar{
+				{Key: "CF_API_TOKEN", Value: "abc123def"},
+			},
+			ShouldFail: false,
+		},
+		{
+			Name: "use_api_token_file_contents",
+			Environment: []EnvVar{
+				{Key: "CF_API_TOKEN", Value: tokenFile},
+			},
+			ShouldFail: false,
+		},
+		{
+			Name: "use_email_and_key",
+			Environment: []EnvVar{
+				{Key: "CF_API_KEY", Value: "xxxxxxxxxxxxxxxxx"},
+				{Key: "CF_API_EMAIL", Value: "test@test.com"},
+			},
+			ShouldFail: false,
+		},
+		{
+			Name:        "no_use_email_and_key",
+			Environment: []EnvVar{},
+			ShouldFail:  true,
+		},
+		{
+			Name: "use_credentials_in_missing_file",
+			Environment: []EnvVar{
+				{Key: "CF_API_TOKEN", Value: "file://abc"},
+			},
+			ShouldFail: true,
+		},
+		{
+			Name: "use_credentials_in_missing_file",
+			Environment: []EnvVar{
+				{Key: "CF_API_TOKEN", Value: "file:/tmp/cf_api_token"},
+			},
+			ShouldFail: false,
+		},
 	}
 
-	_ = os.Unsetenv("CF_API_KEY")
-	_ = os.Unsetenv("CF_API_EMAIL")
-	_, err = NewCloudFlareProvider(
-		endpoint.NewDomainFilter([]string{"bar.com"}),
-		provider.NewZoneIDFilter([]string{""}),
-		false,
-		true,
-		5000,
-		"",
-		CustomHostnamesConfig{Enabled: false})
-	if err == nil {
-		t.Errorf("expected to fail")
+	for _, tc := range testCases {
+		t.Run(tc.Name, func(t *testing.T) {
+			for _, env := range tc.Environment {
+				t.Setenv(env.Key, env.Value)
+			}
+
+			_, err = NewCloudFlareProvider(
+				endpoint.NewDomainFilter([]string{"bar.com"}),
+				provider.NewZoneIDFilter([]string{""}),
+				false,
+				true,
+				5000,
+				"",
+				CustomHostnamesConfig{Enabled: false})
+			if err != nil && !tc.ShouldFail {
+				t.Errorf("should not fail, %s", err)
+			}
+			if err == nil && tc.ShouldFail {
+				t.Errorf("should fail, %s", err)
+			}
+		})
+
 	}
 }
 
@@ -1012,6 +1179,30 @@ func TestCloudflareApplyChanges(t *testing.T) {
 	}
 }
 
+func TestCloudflareDryRunApplyChanges(t *testing.T) {
+	changes := &plan.Changes{}
+	client := NewMockCloudFlareClient()
+
+	provider := &CloudFlareProvider{
+		Client: client,
+		DryRun: true,
+	}
+	changes.Create = []*endpoint.Endpoint{{
+		DNSName: "new.bar.com",
+		Targets: endpoint.Targets{"target"},
+	}}
+	err := provider.ApplyChanges(context.Background(), changes)
+	if err != nil {
+		t.Errorf("should not fail, %s", err)
+	}
+	ctx := context.Background()
+	records, err := provider.Records(ctx)
+	if err != nil {
+		t.Errorf("should not fail, %s", err)
+	}
+	assert.Equal(t, 0, len(records), "should not have any records")
+}
+
 func TestCloudflareApplyChangesError(t *testing.T) {
 	changes := &plan.Changes{}
 	client := NewMockCloudFlareClient()
@@ -1097,7 +1288,7 @@ func TestCloudflareGroupByNameAndType(t *testing.T) {
 					Name:    "foo.com",
 					Type:    endpoint.RecordTypeA,
 					Content: "10.10.10.1",
-					TTL:     defaultCloudFlareRecordTTL,
+					TTL:     defaultTTL,
 					Proxied: proxyDisabled,
 				},
 			},
@@ -1106,7 +1297,7 @@ func TestCloudflareGroupByNameAndType(t *testing.T) {
 					DNSName:    "foo.com",
 					Targets:    endpoint.Targets{"10.10.10.1"},
 					RecordType: endpoint.RecordTypeA,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 					ProviderSpecific: endpoint.ProviderSpecific{
 						{
@@ -1124,14 +1315,14 @@ func TestCloudflareGroupByNameAndType(t *testing.T) {
 					Name:    "foo.com",
 					Type:    endpoint.RecordTypeA,
 					Content: "10.10.10.1",
-					TTL:     defaultCloudFlareRecordTTL,
+					TTL:     defaultTTL,
 					Proxied: proxyDisabled,
 				},
 				{
 					Name:    "foo.com",
 					Type:    endpoint.RecordTypeA,
 					Content: "10.10.10.2",
-					TTL:     defaultCloudFlareRecordTTL,
+					TTL:     defaultTTL,
 					Proxied: proxyDisabled,
 				},
 			},
@@ -1140,7 +1331,7 @@ func TestCloudflareGroupByNameAndType(t *testing.T) {
 					DNSName:    "foo.com",
 					Targets:    endpoint.Targets{"10.10.10.1", "10.10.10.2"},
 					RecordType: endpoint.RecordTypeA,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 					ProviderSpecific: endpoint.ProviderSpecific{
 						{
@@ -1158,28 +1349,28 @@ func TestCloudflareGroupByNameAndType(t *testing.T) {
 					Name:    "foo.com",
 					Type:    endpoint.RecordTypeA,
 					Content: "10.10.10.1",
-					TTL:     defaultCloudFlareRecordTTL,
+					TTL:     defaultTTL,
 					Proxied: proxyDisabled,
 				},
 				{
 					Name:    "foo.com",
 					Type:    endpoint.RecordTypeA,
 					Content: "10.10.10.2",
-					TTL:     defaultCloudFlareRecordTTL,
+					TTL:     defaultTTL,
 					Proxied: proxyDisabled,
 				},
 				{
 					Name:    "bar.de",
 					Type:    endpoint.RecordTypeA,
 					Content: "10.10.10.1",
-					TTL:     defaultCloudFlareRecordTTL,
+					TTL:     defaultTTL,
 					Proxied: proxyDisabled,
 				},
 				{
 					Name:    "bar.de",
 					Type:    endpoint.RecordTypeA,
 					Content: "10.10.10.2",
-					TTL:     defaultCloudFlareRecordTTL,
+					TTL:     defaultTTL,
 					Proxied: proxyDisabled,
 				},
 			},
@@ -1188,7 +1379,7 @@ func TestCloudflareGroupByNameAndType(t *testing.T) {
 					DNSName:    "foo.com",
 					Targets:    endpoint.Targets{"10.10.10.1", "10.10.10.2"},
 					RecordType: endpoint.RecordTypeA,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 					ProviderSpecific: endpoint.ProviderSpecific{
 						{
@@ -1201,7 +1392,7 @@ func TestCloudflareGroupByNameAndType(t *testing.T) {
 					DNSName:    "bar.de",
 					Targets:    endpoint.Targets{"10.10.10.1", "10.10.10.2"},
 					RecordType: endpoint.RecordTypeA,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 					ProviderSpecific: endpoint.ProviderSpecific{
 						{
@@ -1219,21 +1410,21 @@ func TestCloudflareGroupByNameAndType(t *testing.T) {
 					Name:    "foo.com",
 					Type:    endpoint.RecordTypeA,
 					Content: "10.10.10.1",
-					TTL:     defaultCloudFlareRecordTTL,
+					TTL:     defaultTTL,
 					Proxied: proxyDisabled,
 				},
 				{
 					Name:    "foo.com",
 					Type:    endpoint.RecordTypeA,
 					Content: "10.10.10.2",
-					TTL:     defaultCloudFlareRecordTTL,
+					TTL:     defaultTTL,
 					Proxied: proxyDisabled,
 				},
 				{
 					Name:    "bar.de",
 					Type:    endpoint.RecordTypeA,
 					Content: "10.10.10.1",
-					TTL:     defaultCloudFlareRecordTTL,
+					TTL:     defaultTTL,
 					Proxied: proxyDisabled,
 				},
 			},
@@ -1242,7 +1433,7 @@ func TestCloudflareGroupByNameAndType(t *testing.T) {
 					DNSName:    "foo.com",
 					Targets:    endpoint.Targets{"10.10.10.1", "10.10.10.2"},
 					RecordType: endpoint.RecordTypeA,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 					ProviderSpecific: endpoint.ProviderSpecific{
 						{
@@ -1255,7 +1446,7 @@ func TestCloudflareGroupByNameAndType(t *testing.T) {
 					DNSName:    "bar.de",
 					Targets:    endpoint.Targets{"10.10.10.1"},
 					RecordType: endpoint.RecordTypeA,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 					ProviderSpecific: endpoint.ProviderSpecific{
 						{
@@ -1273,21 +1464,21 @@ func TestCloudflareGroupByNameAndType(t *testing.T) {
 					Name:    "foo.com",
 					Type:    endpoint.RecordTypeA,
 					Content: "10.10.10.1",
-					TTL:     defaultCloudFlareRecordTTL,
+					TTL:     defaultTTL,
 					Proxied: proxyDisabled,
 				},
 				{
 					Name:    "foo.com",
 					Type:    endpoint.RecordTypeA,
 					Content: "10.10.10.2",
-					TTL:     defaultCloudFlareRecordTTL,
+					TTL:     defaultTTL,
 					Proxied: proxyDisabled,
 				},
 				{
 					Name:    "bar.de",
 					Type:    "NOT SUPPORTED",
 					Content: "10.10.10.1",
-					TTL:     defaultCloudFlareRecordTTL,
+					TTL:     defaultTTL,
 					Proxied: proxyDisabled,
 				},
 			},
@@ -1296,7 +1487,7 @@ func TestCloudflareGroupByNameAndType(t *testing.T) {
 					DNSName:    "foo.com",
 					Targets:    endpoint.Targets{"10.10.10.1", "10.10.10.2"},
 					RecordType: endpoint.RecordTypeA,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 					ProviderSpecific: endpoint.ProviderSpecific{
 						{
@@ -1448,7 +1639,7 @@ func TestCloudflareComplexUpdate(t *testing.T) {
 			DNSName:    "foobar.bar.com",
 			Targets:    endpoint.Targets{"1.2.3.4", "2.3.4.5"},
 			RecordType: endpoint.RecordTypeA,
-			RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+			RecordTTL:  endpoint.TTL(defaultTTL),
 			Labels:     endpoint.Labels{},
 			ProviderSpecific: endpoint.ProviderSpecific{
 				{
@@ -1585,24 +1776,6 @@ func TestCloudFlareProvider_Region(t *testing.T) {
 	}
 }
 
-func TestCloudFlareProvider_updateDataLocalizationRegionalHostnameParams(t *testing.T) {
-	change := &cloudFlareChange{
-		RegionalHostname: cloudflare.RegionalHostname{
-			Hostname:  "example.com",
-			RegionKey: "us",
-		},
-	}
-
-	params := updateDataLocalizationRegionalHostnameParams(*change)
-	if params.Hostname != "example.com" {
-		t.Errorf("expected hostname to be 'example.com', but got '%s'", params.Hostname)
-	}
-
-	if params.RegionKey != "us" {
-		t.Errorf("expected region key to be 'us', but got '%s'", params.RegionKey)
-	}
-}
-
 func TestCloudFlareProvider_newCloudFlareChange(t *testing.T) {
 	_ = os.Setenv("CF_API_KEY", "xxxxxxxxxxxxxxxxx")
 	_ = os.Setenv("CF_API_EMAIL", "test@test.com")
@@ -1619,8 +1792,9 @@ func TestCloudFlareProvider_newCloudFlareChange(t *testing.T) {
 	}
 
 	endpoint := &endpoint.Endpoint{
-		DNSName: "example.com",
-		Targets: []string{"192.0.2.1"},
+		DNSName:    "example.com",
+		RecordType: "A",
+		Targets:    []string{"192.0.2.1"},
 	}
 
 	change := provider.newCloudFlareChange(cloudFlareCreate, endpoint, endpoint.Targets[0], nil)
@@ -1772,6 +1946,44 @@ func TestCloudflareZoneRecordsFail(t *testing.T) {
 	}
 }
 
+// TestCloudflareLongRecordsErrorLog checks if the error is logged when a record name exceeds 63 characters
+// it's not likely to happen in practice, as the Cloudflare API should reject having it
+func TestCloudflareLongRecordsErrorLog(t *testing.T) {
+	client := NewMockCloudFlareClientWithRecords(map[string][]cloudflare.DNSRecord{
+		"001": {
+			{
+				ID:      "1234567890",
+				Name:    "very-very-very-very-very-very-very-long-name-more-than-63-bytes-long.bar.com",
+				Type:    endpoint.RecordTypeTXT,
+				TTL:     120,
+				Content: "some-content",
+			},
+		},
+	})
+	b := testutils.LogsToBuffer(log.InfoLevel, t)
+	p := &CloudFlareProvider{
+		Client:                client,
+		CustomHostnamesConfig: CustomHostnamesConfig{Enabled: true},
+	}
+	ctx := context.Background()
+	_, err := p.Records(ctx)
+	if err != nil {
+		t.Errorf("should not fail - too long record, %s", err)
+	}
+	assert.Contains(t, b.String(), "is longer than 63 characters. Cannot create endpoint")
+}
+
+// check if the error is expected
+func checkFailed(name string, err error, shouldFail bool) error {
+	if errors.Is(err, nil) && shouldFail {
+		return fmt.Errorf("should fail - %q", name)
+	}
+	if !errors.Is(err, nil) && !shouldFail {
+		return fmt.Errorf("should not fail - %q, %v", name, err)
+	}
+	return nil
+}
+
 func TestCloudflareDNSRecordsOperationsFail(t *testing.T) {
 	client := NewMockCloudFlareClient()
 	provider := &CloudFlareProvider{
@@ -1794,23 +2006,28 @@ func TestCloudflareDNSRecordsOperationsFail(t *testing.T) {
 					DNSName:    "newerror.bar.com",
 					Targets:    endpoint.Targets{"1.2.3.4"},
 					RecordType: endpoint.RecordTypeA,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 				},
 			},
 			shouldFail: true,
 		},
 		{
-			Name: "failing to list DNS record",
+			Name: "adding failing to list DNS record",
 			Endpoints: []*endpoint.Endpoint{
 				{
 					DNSName:    "newerror-list-1.foo.bar.com",
 					Targets:    endpoint.Targets{"1.2.3.4"},
 					RecordType: endpoint.RecordTypeA,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 				},
 			},
+			shouldFail: false,
+		},
+		{
+			Name:       "causing to list failing to list DNS record",
+			Endpoints:  []*endpoint.Endpoint{},
 			shouldFail: true,
 		},
 		{
@@ -1820,7 +2037,7 @@ func TestCloudflareDNSRecordsOperationsFail(t *testing.T) {
 					DNSName:    "newerror-update-1.foo.bar.com",
 					Targets:    endpoint.Targets{"1.2.3.4"},
 					RecordType: endpoint.RecordTypeA,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 				},
 			},
@@ -1860,28 +2077,25 @@ func TestCloudflareDNSRecordsOperationsFail(t *testing.T) {
 	}
 
 	for _, tc := range testFailCases {
-		records, err := provider.Records(ctx)
-		if err != nil {
-			t.Errorf("should not fail, %s", err)
-		}
+		var err error
+		var records, endpoints []*endpoint.Endpoint
 
-		endpoints, err := provider.AdjustEndpoints(tc.Endpoints)
-
-		assert.NoError(t, err)
-		plan := &plan.Plan{
-			Current:        records,
-			Desired:        endpoints,
-			DomainFilter:   endpoint.MatchAllDomainFilters{&domainFilter},
-			ManagedRecords: []string{endpoint.RecordTypeA, endpoint.RecordTypeCNAME},
+		records, err = provider.Records(ctx)
+		if errors.Is(err, nil) {
+			endpoints, err = provider.AdjustEndpoints(tc.Endpoints)
 		}
-
-		planned := plan.Calculate()
-
-		err = provider.ApplyChanges(context.Background(), planned.Changes)
-		if err == nil && tc.shouldFail {
-			t.Errorf("should fail - %q, %v", tc.Name, err)
-		} else if err != nil && !tc.shouldFail {
-			t.Errorf("should not fail - %q, %v", tc.Name, err)
+		if errors.Is(err, nil) {
+			plan := &plan.Plan{
+				Current:        records,
+				Desired:        endpoints,
+				DomainFilter:   endpoint.MatchAllDomainFilters{&domainFilter},
+				ManagedRecords: []string{endpoint.RecordTypeA, endpoint.RecordTypeCNAME},
+			}
+			planned := plan.Calculate()
+			err = provider.ApplyChanges(context.Background(), planned.Changes)
+		}
+		if e := checkFailed(tc.Name, err, tc.shouldFail); !errors.Is(e, nil) {
+			t.Error(e)
 		}
 	}
 }
@@ -1896,10 +2110,9 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
 	domainFilter := endpoint.NewDomainFilter([]string{"bar.com"})
 
 	testFailCases := []struct {
-		Name                    string
-		Endpoints               []*endpoint.Endpoint
-		ExpectedCustomHostnames map[string]string
-		shouldFail              bool
+		Name       string
+		Endpoints  []*endpoint.Endpoint
+		shouldFail bool
 	}{
 		{
 			Name: "failing to create custom hostname on record creation",
@@ -1908,7 +2121,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
 					DNSName:    "create.foo.bar.com",
 					Targets:    endpoint.Targets{"1.2.3.4"},
 					RecordType: endpoint.RecordTypeA,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 					ProviderSpecific: endpoint.ProviderSpecific{
 						{
@@ -1921,13 +2134,13 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
 			shouldFail: true,
 		},
 		{
-			Name: "custom hostname to the same origin",
+			Name: "same custom hostname to the same origin",
 			Endpoints: []*endpoint.Endpoint{
 				{
 					DNSName:    "origin.foo.bar.com",
 					Targets:    endpoint.Targets{"1.2.3.4", "2.3.4.5"},
 					RecordType: endpoint.RecordTypeA,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 					ProviderSpecific: endpoint.ProviderSpecific{
 						{
@@ -1936,17 +2149,11 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
 						},
 					},
 				},
-			},
-			shouldFail: false,
-		},
-		{
-			Name: "same custom hostname to the another origin",
-			Endpoints: []*endpoint.Endpoint{
 				{
 					DNSName:    "another-origin.foo.bar.com",
 					Targets:    endpoint.Targets{"3.4.5.6"},
 					RecordType: endpoint.RecordTypeA,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 					ProviderSpecific: endpoint.ProviderSpecific{
 						{
@@ -1965,7 +2172,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
 					DNSName:    "c.foo.bar.com",
 					Targets:    endpoint.Targets{"c.cname.foo.bar.com"},
 					RecordType: endpoint.RecordTypeCNAME,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 					ProviderSpecific: endpoint.ProviderSpecific{
 						{
@@ -1986,7 +2193,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
 						"heritage=external-dns,external-dns/owner=default,external-dns/resource=service/external-dns/my-domain-here-app",
 					},
 					RecordType: endpoint.RecordTypeTXT,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 					ProviderSpecific: endpoint.ProviderSpecific{
 						{
@@ -2005,7 +2212,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
 					DNSName:    "fail.foo.bar.com",
 					Targets:    endpoint.Targets{"1.2.3.4"},
 					RecordType: endpoint.RecordTypeA,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 					ProviderSpecific: endpoint.ProviderSpecific{
 						{
@@ -2024,7 +2231,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
 					DNSName:    "fail.list.foo.bar.com",
 					Targets:    endpoint.Targets{"1.2.3.4"},
 					RecordType: endpoint.RecordTypeA,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 					ProviderSpecific: endpoint.ProviderSpecific{
 						{
@@ -2034,6 +2241,11 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
 					},
 				},
 			},
+			shouldFail: false,
+		},
+		{
+			Name:       "causing to list failing to list custom hostname",
+			Endpoints:  []*endpoint.Endpoint{},
 			shouldFail: true,
 		},
 		{
@@ -2043,7 +2255,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
 					DNSName:    "b.foo.bar.com",
 					Targets:    endpoint.Targets{"1.2.3.4"},
 					RecordType: endpoint.RecordTypeA,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 					ProviderSpecific: endpoint.ProviderSpecific{
 						{
@@ -2062,7 +2274,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
 					DNSName:    "b.foo.bar.com",
 					Targets:    endpoint.Targets{"1.2.3.4"},
 					RecordType: endpoint.RecordTypeA,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 					ProviderSpecific: endpoint.ProviderSpecific{
 						{
@@ -2081,7 +2293,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
 					DNSName:    "b.foo.bar.com",
 					Targets:    endpoint.Targets{"1.2.3.4"},
 					RecordType: endpoint.RecordTypeA,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 					ProviderSpecific: endpoint.ProviderSpecific{
 						{
@@ -2100,7 +2312,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
 					DNSName:    "b.foo.bar.com",
 					Targets:    endpoint.Targets{"1.2.3.4"},
 					RecordType: endpoint.RecordTypeA,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 				},
 			},
@@ -2113,7 +2325,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
 					DNSName:    "b.foo.bar.com",
 					Targets:    endpoint.Targets{"1.2.3.4"},
 					RecordType: endpoint.RecordTypeA,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 					ProviderSpecific: endpoint.ProviderSpecific{
 						{
@@ -2144,13 +2356,11 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
 					DNSName:    "nocustomhostname.foo.bar.com",
 					Targets:    endpoint.Targets{"1.2.3.4"},
 					RecordType: endpoint.RecordTypeA,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 				},
 			},
-			ExpectedCustomHostnames: map[string]string{
-				"nocustomhostname.foo.bar.com": "",
-			},
+			ExpectedCustomHostnames: map[string]string{},
 		},
 		{
 			Name: "add custom hostname",
@@ -2159,7 +2369,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
 					DNSName:    "a.foo.bar.com",
 					Targets:    endpoint.Targets{"1.2.3.4"},
 					RecordType: endpoint.RecordTypeA,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 					ProviderSpecific: endpoint.ProviderSpecific{
 						{
@@ -2172,7 +2382,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
 					DNSName:    "txt.foo.bar.com",
 					Targets:    endpoint.Targets{"value"},
 					RecordType: endpoint.RecordTypeTXT,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 					ProviderSpecific: endpoint.ProviderSpecific{
 						{
@@ -2183,8 +2393,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
 				},
 			},
 			ExpectedCustomHostnames: map[string]string{
-				"a.foo.bar.com":   "a.foo.fancybar.com",
-				"txt.foo.bar.com": "",
+				"a.foo.fancybar.com": "a.foo.bar.com",
 			},
 		},
 		{
@@ -2194,7 +2403,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
 					DNSName:    "a.foo.bar.com",
 					Targets:    endpoint.Targets{"1.2.3.4"},
 					RecordType: endpoint.RecordTypeA,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 					ProviderSpecific: endpoint.ProviderSpecific{
 						{
@@ -2205,28 +2414,116 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
 				},
 			},
 			ExpectedCustomHostnames: map[string]string{
-				"a.foo.bar.com": "a2.foo.fancybar.com",
+				"a2.foo.fancybar.com": "a.foo.bar.com",
 			},
 		},
 		{
-			Name: "delete custom hostname",
+			Name: "add another unsorted custom hostnames",
+			Endpoints: []*endpoint.Endpoint{
+				{
+					DNSName:    "a.foo.bar.com",
+					Targets:    endpoint.Targets{"1.2.3.4"},
+					RecordType: endpoint.RecordTypeA,
+					RecordTTL:  endpoint.TTL(defaultTTL),
+					Labels:     endpoint.Labels{},
+					ProviderSpecific: endpoint.ProviderSpecific{
+						{
+							Name:  "external-dns.alpha.kubernetes.io/cloudflare-custom-hostname",
+							Value: "a3.foo.fancybar.com,a4.foo.fancybar.com,a2.foo.fancybar.com",
+						},
+					},
+				},
+			},
+			ExpectedCustomHostnames: map[string]string{
+				"a2.foo.fancybar.com": "a.foo.bar.com",
+				"a3.foo.fancybar.com": "a.foo.bar.com",
+				"a4.foo.fancybar.com": "a.foo.bar.com",
+			},
+		},
+		{
+			Name: "rename custom hostnames",
+			Endpoints: []*endpoint.Endpoint{
+				{
+					DNSName:    "a.foo.bar.com",
+					Targets:    endpoint.Targets{"1.2.3.4"},
+					RecordType: endpoint.RecordTypeA,
+					RecordTTL:  endpoint.TTL(defaultTTL),
+					Labels:     endpoint.Labels{},
+					ProviderSpecific: endpoint.ProviderSpecific{
+						{
+							Name:  "external-dns.alpha.kubernetes.io/cloudflare-custom-hostname",
+							Value: "a3.foo.fancybar.com,a44.foo.fancybar.com,a22.foo.fancybar.com",
+						},
+					},
+				},
+			},
+			ExpectedCustomHostnames: map[string]string{
+				"a22.foo.fancybar.com": "a.foo.bar.com",
+				"a3.foo.fancybar.com":  "a.foo.bar.com",
+				"a44.foo.fancybar.com": "a.foo.bar.com",
+			},
+		},
+		{
+			Name: "remove some custom hostnames",
 			Endpoints: []*endpoint.Endpoint{
-
 				{
 					DNSName:    "a.foo.bar.com",
 					Targets:    endpoint.Targets{"1.2.3.4"},
 					RecordType: endpoint.RecordTypeA,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
+					ProviderSpecific: endpoint.ProviderSpecific{
+						{
+							Name:  "external-dns.alpha.kubernetes.io/cloudflare-custom-hostname",
+							Value: "a3.foo.fancybar.com",
+						},
+					},
 				},
 			},
 			ExpectedCustomHostnames: map[string]string{
-				"a.foo.bar.com": "",
+				"a3.foo.fancybar.com": "a.foo.bar.com",
 			},
 		},
+		{
+			Name: "delete custom hostnames",
+			Endpoints: []*endpoint.Endpoint{
+				{
+					DNSName:    "a.foo.bar.com",
+					Targets:    endpoint.Targets{"1.2.3.4"},
+					RecordType: endpoint.RecordTypeA,
+					RecordTTL:  endpoint.TTL(defaultTTL),
+					Labels:     endpoint.Labels{},
+				},
+			},
+			ExpectedCustomHostnames: map[string]string{},
+		},
 	}
 
 	for _, tc := range testFailCases {
+		var err error
+		var records, endpoints []*endpoint.Endpoint
+
+		records, err = provider.Records(ctx)
+		if errors.Is(err, nil) {
+			endpoints, err = provider.AdjustEndpoints(tc.Endpoints)
+		}
+		if errors.Is(err, nil) {
+			plan := &plan.Plan{
+				Current:        records,
+				Desired:        endpoints,
+				DomainFilter:   endpoint.MatchAllDomainFilters{&domainFilter},
+				ManagedRecords: []string{endpoint.RecordTypeA, endpoint.RecordTypeCNAME, endpoint.RecordTypeTXT},
+			}
+			planned := plan.Calculate()
+			err = provider.ApplyChanges(context.Background(), planned.Changes)
+
+		}
+		if e := checkFailed(tc.Name, err, tc.shouldFail); !errors.Is(e, nil) {
+			t.Error(e)
+		}
+	}
+
+	for _, tc := range testCases {
 		records, err := provider.Records(ctx)
 		if err != nil {
 			t.Errorf("should not fail, %v", err)
@@ -2239,17 +2536,121 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
 			Current:        records,
 			Desired:        endpoints,
 			DomainFilter:   endpoint.MatchAllDomainFilters{&domainFilter},
-			ManagedRecords: []string{endpoint.RecordTypeA, endpoint.RecordTypeCNAME, endpoint.RecordTypeTXT},
+			ManagedRecords: []string{endpoint.RecordTypeA, endpoint.RecordTypeCNAME},
 		}
 
 		planned := plan.Calculate()
 
 		err = provider.ApplyChanges(context.Background(), planned.Changes)
-		if err == nil && tc.shouldFail {
-			t.Errorf("should fail - %q, %v", tc.Name, err)
-		} else if err != nil && !tc.shouldFail {
-			t.Errorf("should not fail - %q, %v", tc.Name, err)
+		if e := checkFailed(tc.Name, err, false); !errors.Is(e, nil) {
+			t.Error(e)
 		}
+
+		chs, chErr := provider.listCustomHostnamesWithPagination(ctx, "001")
+		if e := checkFailed(tc.Name, chErr, false); !errors.Is(e, nil) {
+			t.Error(e)
+		}
+
+		actualCustomHostnames := map[string]string{}
+		for _, ch := range chs {
+			actualCustomHostnames[ch.Hostname] = ch.CustomOriginServer
+		}
+		assert.Equal(t, tc.ExpectedCustomHostnames, actualCustomHostnames, "custom hostnames should be the same")
+	}
+}
+
+func TestCloudflareDisabledCustomHostnameOperations(t *testing.T) {
+	client := NewMockCloudFlareClient()
+	provider := &CloudFlareProvider{
+		Client:                client,
+		CustomHostnamesConfig: CustomHostnamesConfig{Enabled: false},
+	}
+	ctx := context.Background()
+	domainFilter := endpoint.NewDomainFilter([]string{"bar.com"})
+
+	testCases := []struct {
+		Name        string
+		Endpoints   []*endpoint.Endpoint
+		testChanges bool
+	}{
+		{
+			Name: "add custom hostname",
+			Endpoints: []*endpoint.Endpoint{
+				{
+					DNSName:    "a.foo.bar.com",
+					Targets:    endpoint.Targets{"1.2.3.11"},
+					RecordType: endpoint.RecordTypeA,
+					RecordTTL:  endpoint.TTL(defaultTTL),
+					Labels:     endpoint.Labels{},
+					ProviderSpecific: endpoint.ProviderSpecific{
+						{
+							Name:  "external-dns.alpha.kubernetes.io/cloudflare-custom-hostname",
+							Value: "a.foo.fancybar.com",
+						},
+					},
+				},
+				{
+					DNSName:    "b.foo.bar.com",
+					Targets:    endpoint.Targets{"1.2.3.12"},
+					RecordType: endpoint.RecordTypeA,
+					RecordTTL:  endpoint.TTL(defaultTTL),
+					Labels:     endpoint.Labels{},
+				},
+				{
+					DNSName:    "c.foo.bar.com",
+					Targets:    endpoint.Targets{"1.2.3.13"},
+					RecordType: endpoint.RecordTypeA,
+					RecordTTL:  endpoint.TTL(defaultTTL),
+					Labels:     endpoint.Labels{},
+					ProviderSpecific: endpoint.ProviderSpecific{
+						{
+							Name:  "external-dns.alpha.kubernetes.io/cloudflare-custom-hostname",
+							Value: "c1.foo.fancybar.com",
+						},
+					},
+				},
+			},
+			testChanges: false,
+		},
+		{
+			Name: "add custom hostname",
+			Endpoints: []*endpoint.Endpoint{
+				{
+					DNSName:    "a.foo.bar.com",
+					Targets:    endpoint.Targets{"1.2.3.11"},
+					RecordType: endpoint.RecordTypeA,
+					RecordTTL:  endpoint.TTL(defaultTTL),
+					Labels:     endpoint.Labels{},
+				},
+				{
+					DNSName:    "b.foo.bar.com",
+					Targets:    endpoint.Targets{"1.2.3.12"},
+					RecordType: endpoint.RecordTypeA,
+					RecordTTL:  endpoint.TTL(defaultTTL),
+					Labels:     endpoint.Labels{},
+					ProviderSpecific: endpoint.ProviderSpecific{
+						{
+							Name:  "external-dns.alpha.kubernetes.io/cloudflare-custom-hostname",
+							Value: "b.foo.fancybar.com",
+						},
+					},
+				},
+				{
+					DNSName:    "c.foo.bar.com",
+					Targets:    endpoint.Targets{"1.2.3.13"},
+					RecordType: endpoint.RecordTypeA,
+					RecordTTL:  endpoint.TTL(defaultTTL),
+					Labels:     endpoint.Labels{},
+					ProviderSpecific: endpoint.ProviderSpecific{
+						{
+							Name:  "external-dns.alpha.kubernetes.io/cloudflare-custom-hostname",
+							Value: "c2.foo.fancybar.com",
+						},
+					},
+				},
+			},
+			testChanges: true,
+		},
 	}
 
 	for _, tc := range testCases {
@@ -2267,22 +2668,13 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
 			DomainFilter:   endpoint.MatchAllDomainFilters{&domainFilter},
 			ManagedRecords: []string{endpoint.RecordTypeA, endpoint.RecordTypeCNAME},
 		}
-
 		planned := plan.Calculate()
-
 		err = provider.ApplyChanges(context.Background(), planned.Changes)
-		if err != nil {
-			t.Errorf("should not fail - %q, %v", tc.Name, err)
+		if e := checkFailed(tc.Name, err, false); !errors.Is(e, nil) {
+			t.Error(e)
 		}
-
-		chs, chErr := provider.listCustomHostnamesWithPagination(ctx, "001")
-		if chErr != nil {
-			t.Errorf("should not fail - %q, %v", tc.Name, chErr)
-		}
-
-		for expectedOrigin, expectedCustomHostname := range tc.ExpectedCustomHostnames {
-			_, ch := getCustomHostnameIDbyCustomHostnameAndOrigin(chs, expectedCustomHostname, expectedOrigin)
-			assert.Equal(t, expectedCustomHostname, ch)
+		if tc.testChanges {
+			assert.Equal(t, planned.Changes.HasChanges(), false, "no new changes should be here")
 		}
 	}
 }
@@ -2311,7 +2703,7 @@ func TestCloudflareCustomHostnameNotFoundOnRecordDeletion(t *testing.T) {
 					DNSName:    "create.foo.bar.com",
 					Targets:    endpoint.Targets{"1.2.3.4"},
 					RecordType: endpoint.RecordTypeA,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 					ProviderSpecific: endpoint.ProviderSpecific{
 						{
@@ -2343,7 +2735,7 @@ func TestCloudflareCustomHostnameNotFoundOnRecordDeletion(t *testing.T) {
 					DNSName:    "a.foo.bar.com",
 					Targets:    endpoint.Targets{"1.2.3.4"},
 					RecordType: endpoint.RecordTypeA,
-					RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+					RecordTTL:  endpoint.TTL(defaultTTL),
 					Labels:     endpoint.Labels{},
 					ProviderSpecific: endpoint.ProviderSpecific{
 						{
@@ -2381,11 +2773,11 @@ func TestCloudflareCustomHostnameNotFoundOnRecordDeletion(t *testing.T) {
 		// manually corrupt custom hostname before the deletion step
 		// the purpose is to cause getCustomHostnameOrigin() to fail on change.Action == cloudFlareDelete
 		chs, chErr := provider.listCustomHostnamesWithPagination(ctx, zoneID)
-		if chErr != nil {
-			t.Errorf("should not fail - %q, %v", tc.Name, chErr)
+		if e := checkFailed(tc.Name, chErr, false); !errors.Is(e, nil) {
+			t.Error(e)
 		}
 		if tc.preApplyHook == "corrupt" {
-			if ch, err := getCustomHostname(chs, "newerror-getCustomHostnameOrigin.foo.fancybar.com"); err == nil {
+			if ch, err := getCustomHostname(chs, "newerror-getCustomHostnameOrigin.foo.fancybar.com"); errors.Is(err, nil) {
 				chID := ch.ID
 				t.Logf("corrupting custom hostname %q", chID)
 				oldIdx := getCustomHostnameIdxByID(client.customHostnames[zoneID], chID)
@@ -2398,7 +2790,6 @@ func TestCloudflareCustomHostnameNotFoundOnRecordDeletion(t *testing.T) {
 				client.customHostnames[zoneID][oldIdx] = ch
 			}
 		} else if tc.preApplyHook == "duplicate" { // manually inject duplicating custom hostname with the same name and origin
-
 			ch := cloudflare.CustomHostname{
 				ID:                 "ID-random-123",
 				Hostname:           "a.foo.fancybar.com",
@@ -2407,8 +2798,8 @@ func TestCloudflareCustomHostnameNotFoundOnRecordDeletion(t *testing.T) {
 			client.customHostnames[zoneID] = append(client.customHostnames[zoneID], ch)
 		}
 		err = provider.ApplyChanges(context.Background(), planned.Changes)
-		if err != nil {
-			t.Errorf("should not fail - %q, %v", tc.Name, err)
+		if e := checkFailed(tc.Name, err, false); !errors.Is(e, nil) {
+			t.Error(e)
 		}
 		assert.Contains(t, b.String(), tc.logOutput)
 	}
@@ -2431,7 +2822,7 @@ func TestCloudflareListCustomHostnamesWithPagionation(t *testing.T) {
 				DNSName:    fmt.Sprintf("host-%d.foo.bar.com", i),
 				Targets:    endpoint.Targets{fmt.Sprintf("cname-%d.foo.bar.com", i)},
 				RecordType: endpoint.RecordTypeCNAME,
-				RecordTTL:  endpoint.TTL(defaultCloudFlareRecordTTL),
+				RecordTTL:  endpoint.TTL(defaultTTL),
 				Labels:     endpoint.Labels{},
 				ProviderSpecific: endpoint.ProviderSpecific{
 					{
@@ -2472,3 +2863,334 @@ func TestCloudflareListCustomHostnamesWithPagionation(t *testing.T) {
 	}
 	assert.Equal(t, len(chs), CustomHostnamesNumber)
 }
+
+func Test_getRegionKey(t *testing.T) {
+	type args struct {
+		endpoint         *endpoint.Endpoint
+		defaultRegionKey string
+	}
+	tests := []struct {
+		name string
+		args args
+		want string
+	}{
+		{
+			name: "no region key",
+			args: args{
+				endpoint: &endpoint.Endpoint{
+					RecordType: "A",
+				},
+				defaultRegionKey: "",
+			},
+			want: "",
+		},
+		{
+			name: "default region key",
+			args: args{
+				endpoint: &endpoint.Endpoint{
+					RecordType: "A",
+				},
+				defaultRegionKey: "us",
+			},
+			want: "us",
+		},
+		{
+			name: "endpoint with region key",
+			args: args{
+				endpoint: &endpoint.Endpoint{
+					RecordType: "A",
+					ProviderSpecific: endpoint.ProviderSpecific{
+						{
+							Name:  "external-dns.alpha.kubernetes.io/cloudflare-region-key",
+							Value: "eu",
+						},
+					},
+				},
+				defaultRegionKey: "us",
+			},
+			want: "eu",
+		},
+		{
+			name: "endpoint with empty region key",
+			args: args{
+				endpoint: &endpoint.Endpoint{
+					RecordType: "A",
+					ProviderSpecific: endpoint.ProviderSpecific{
+						{
+							Name:  "external-dns.alpha.kubernetes.io/cloudflare-region-key",
+							Value: "",
+						},
+					},
+				},
+				defaultRegionKey: "us",
+			},
+			want: "",
+		},
+		{
+			name: "unsupported record type",
+			args: args{
+				endpoint: &endpoint.Endpoint{
+					RecordType: "TXT",
+					ProviderSpecific: endpoint.ProviderSpecific{
+						{
+							Name:  "external-dns.alpha.kubernetes.io/cloudflare-region-key",
+							Value: "eu",
+						},
+					},
+				},
+				defaultRegionKey: "us",
+			},
+			want: "",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := getRegionKey(tt.args.endpoint, tt.args.defaultRegionKey); got != tt.want {
+				t.Errorf("getRegionKey() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func Test_dataLocalizationRegionalHostnamesChanges(t *testing.T) {
+	cmpDataLocalizationRegionalHostnameChange := func(i, j DataLocalizationRegionalHostnameChange) int {
+		if i.Action == j.Action {
+			return 0
+		}
+		if i.Hostname < j.Hostname {
+			return -1
+		}
+		return 1
+	}
+	type args struct {
+		changes []*cloudFlareChange
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    []DataLocalizationRegionalHostnameChange
+		wantErr bool
+	}{
+		{
+			name: "empty input",
+			args: args{
+				changes: []*cloudFlareChange{},
+			},
+			want:    nil,
+			wantErr: false,
+		},
+		{
+			name: "changes without RegionalHostname",
+			args: args{
+				changes: []*cloudFlareChange{
+					{
+						Action: cloudFlareCreate,
+						ResourceRecord: cloudflare.DNSRecord{
+							Name: "example.com",
+						},
+						RegionalHostname: cloudflare.RegionalHostname{}, // Empty
+					},
+				},
+			},
+			want:    nil,
+			wantErr: false,
+		},
+		{
+			name: "change with empty RegionKey",
+			args: args{
+				changes: []*cloudFlareChange{
+					{
+						Action: cloudFlareCreate,
+						ResourceRecord: cloudflare.DNSRecord{
+							Name: "example.com",
+						},
+						RegionalHostname: cloudflare.RegionalHostname{
+							Hostname:  "example.com",
+							RegionKey: "", // Empty region key
+						},
+					},
+				},
+			},
+			wantErr: true,
+		},
+		{
+			name: "conflicting region keys",
+			args: args{
+				changes: []*cloudFlareChange{
+					{
+						Action: cloudFlareCreate,
+						RegionalHostname: cloudflare.RegionalHostname{
+							Hostname:  "example.com",
+							RegionKey: "eu",
+						},
+					},
+					{
+						Action: cloudFlareCreate,
+						RegionalHostname: cloudflare.RegionalHostname{
+							Hostname:  "example.com",
+							RegionKey: "us", // Different region key for same hostname
+						},
+					},
+				},
+			},
+			wantErr: true,
+		},
+		{
+			name: "update takes precedence over create & delete",
+			args: args{
+				changes: []*cloudFlareChange{
+					{
+						Action: cloudFlareCreate,
+						RegionalHostname: cloudflare.RegionalHostname{
+							Hostname:  "example.com",
+							RegionKey: "eu",
+						},
+					},
+					{
+						Action: cloudFlareUpdate,
+						RegionalHostname: cloudflare.RegionalHostname{
+							Hostname:  "example.com",
+							RegionKey: "eu",
+						},
+					},
+					{
+						Action: cloudFlareDelete,
+						RegionalHostname: cloudflare.RegionalHostname{
+							Hostname:  "example.com",
+							RegionKey: "eu",
+						},
+					},
+				},
+			},
+			want: []DataLocalizationRegionalHostnameChange{
+				{
+					Action: cloudFlareUpdate,
+					RegionalHostname: cloudflare.RegionalHostname{
+						Hostname:  "example.com",
+						RegionKey: "eu",
+					},
+				},
+			},
+			wantErr: false,
+		},
+		{
+			name: "create after delete becomes update",
+			args: args{
+				changes: []*cloudFlareChange{
+					{
+						Action: cloudFlareDelete,
+						RegionalHostname: cloudflare.RegionalHostname{
+							Hostname:  "example.com",
+							RegionKey: "eu",
+						},
+					},
+					{
+						Action: cloudFlareCreate,
+						RegionalHostname: cloudflare.RegionalHostname{
+							Hostname:  "example.com",
+							RegionKey: "eu",
+						},
+					},
+				},
+			},
+			want: []DataLocalizationRegionalHostnameChange{
+				{
+					Action: cloudFlareUpdate,
+					RegionalHostname: cloudflare.RegionalHostname{
+						Hostname:  "example.com",
+						RegionKey: "eu",
+					},
+				},
+			},
+			wantErr: false,
+		},
+		{
+			name: "consolidate mixed actions for different hostnames",
+			args: args{
+				changes: []*cloudFlareChange{
+					{
+						Action: cloudFlareCreate,
+						RegionalHostname: cloudflare.RegionalHostname{
+							Hostname:  "example1.com",
+							RegionKey: "eu",
+						},
+					},
+					{
+						Action: cloudFlareUpdate,
+						RegionalHostname: cloudflare.RegionalHostname{
+							Hostname:  "example2.com",
+							RegionKey: "us",
+						},
+					},
+					{
+						Action: cloudFlareDelete,
+						RegionalHostname: cloudflare.RegionalHostname{
+							Hostname:  "example3.com",
+							RegionKey: "ap",
+						},
+					},
+					// duplicated actions
+					{
+						Action: cloudFlareCreate,
+						RegionalHostname: cloudflare.RegionalHostname{
+							Hostname:  "example1.com",
+							RegionKey: "eu",
+						},
+					},
+					{
+						Action: cloudFlareUpdate,
+						RegionalHostname: cloudflare.RegionalHostname{
+							Hostname:  "example2.com",
+							RegionKey: "us",
+						},
+					},
+					{
+						Action: cloudFlareDelete,
+						RegionalHostname: cloudflare.RegionalHostname{
+							Hostname:  "example3.com",
+							RegionKey: "ap",
+						},
+					},
+				},
+			},
+			want: []DataLocalizationRegionalHostnameChange{
+				{
+					Action: cloudFlareCreate,
+					RegionalHostname: cloudflare.RegionalHostname{
+						Hostname:  "example1.com",
+						RegionKey: "eu",
+					},
+				},
+				{
+					Action: cloudFlareUpdate,
+					RegionalHostname: cloudflare.RegionalHostname{
+						Hostname:  "example2.com",
+						RegionKey: "us",
+					},
+				},
+				{
+					Action: cloudFlareDelete,
+					RegionalHostname: cloudflare.RegionalHostname{
+						Hostname:  "example3.com",
+						RegionKey: "ap",
+					},
+				},
+			},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := dataLocalizationRegionalHostnamesChanges(tt.args.changes)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("dataLocalizationRegionalHostnamesChanges() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			slices.SortFunc(got, cmpDataLocalizationRegionalHostnameChange)
+			slices.SortFunc(tt.want, cmpDataLocalizationRegionalHostnameChange)
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("dataLocalizationRegionalHostnamesChanges() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff --git a/provider/digitalocean/digital_ocean_test.go b/provider/digitalocean/digital_ocean_test.go
index cd5555b3..7088b092 100644
--- a/provider/digitalocean/digital_ocean_test.go
+++ b/provider/digitalocean/digital_ocean_test.go
@@ -309,32 +309,32 @@ func TestDigitalOceanZones(t *testing.T) {
 func TestDigitalOceanMakeDomainEditRequest(t *testing.T) {
 	// Ensure that records at the root of the zone get `@` as the name.
 	r1 := makeDomainEditRequest("example.com", "example.com", endpoint.RecordTypeA,
-		"1.2.3.4", digitalOceanRecordTTL)
+		"1.2.3.4", defaultTTL)
 	assert.Equal(t, &godo.DomainRecordEditRequest{
 		Type: endpoint.RecordTypeA,
 		Name: "@",
 		Data: "1.2.3.4",
-		TTL:  digitalOceanRecordTTL,
+		TTL:  defaultTTL,
 	}, r1)
 
 	// Ensure the CNAME records have a `.` appended.
 	r2 := makeDomainEditRequest("example.com", "foo.example.com", endpoint.RecordTypeCNAME,
-		"bar.example.com", digitalOceanRecordTTL)
+		"bar.example.com", defaultTTL)
 	assert.Equal(t, &godo.DomainRecordEditRequest{
 		Type: endpoint.RecordTypeCNAME,
 		Name: "foo",
 		Data: "bar.example.com.",
-		TTL:  digitalOceanRecordTTL,
+		TTL:  defaultTTL,
 	}, r2)
 
 	// Ensure that CNAME records do not have an extra `.` appended if they already have a `.`
 	r3 := makeDomainEditRequest("example.com", "foo.example.com", endpoint.RecordTypeCNAME,
-		"bar.example.com.", digitalOceanRecordTTL)
+		"bar.example.com.", defaultTTL)
 	assert.Equal(t, &godo.DomainRecordEditRequest{
 		Type: endpoint.RecordTypeCNAME,
 		Name: "foo",
 		Data: "bar.example.com.",
-		TTL:  digitalOceanRecordTTL,
+		TTL:  defaultTTL,
 	}, r3)
 
 	// Ensure that custom TTLs can be set
@@ -350,24 +350,24 @@ func TestDigitalOceanMakeDomainEditRequest(t *testing.T) {
 
 	// Ensure that MX records have `.` appended.
 	r5 := makeDomainEditRequest("example.com", "foo.example.com", endpoint.RecordTypeMX,
-		"10 mx.example.com", digitalOceanRecordTTL)
+		"10 mx.example.com", defaultTTL)
 	assert.Equal(t, &godo.DomainRecordEditRequest{
 		Type:     endpoint.RecordTypeMX,
 		Name:     "foo",
 		Data:     "mx.example.com.",
 		Priority: 10,
-		TTL:      digitalOceanRecordTTL,
+		TTL:      defaultTTL,
 	}, r5)
 
 	// Ensure that MX records do not have an extra `.` appended if they already have a `.`
 	r6 := makeDomainEditRequest("example.com", "foo.example.com", endpoint.RecordTypeMX,
-		"10 mx.example.com.", digitalOceanRecordTTL)
+		"10 mx.example.com.", defaultTTL)
 	assert.Equal(t, &godo.DomainRecordEditRequest{
 		Type:     endpoint.RecordTypeMX,
 		Name:     "foo",
 		Data:     "mx.example.com.",
 		Priority: 10,
-		TTL:      digitalOceanRecordTTL,
+		TTL:      defaultTTL,
 	}, r6)
 }
 
@@ -420,7 +420,7 @@ func TestDigitalOceanProcessCreateActions(t *testing.T) {
 				Name: "foo",
 				Type: endpoint.RecordTypeA,
 				Data: "1.2.3.4",
-				TTL:  digitalOceanRecordTTL,
+				TTL:  defaultTTL,
 			},
 		},
 		{
@@ -429,7 +429,7 @@ func TestDigitalOceanProcessCreateActions(t *testing.T) {
 				Name: "@",
 				Type: endpoint.RecordTypeCNAME,
 				Data: "foo.example.com.",
-				TTL:  digitalOceanRecordTTL,
+				TTL:  defaultTTL,
 			},
 		},
 		{
@@ -439,7 +439,7 @@ func TestDigitalOceanProcessCreateActions(t *testing.T) {
 				Type:     endpoint.RecordTypeMX,
 				Priority: 10,
 				Data:     "mx.example.com.",
-				TTL:      digitalOceanRecordTTL,
+				TTL:      defaultTTL,
 			},
 		},
 		{
@@ -448,7 +448,7 @@ func TestDigitalOceanProcessCreateActions(t *testing.T) {
 				Name: "@",
 				Type: endpoint.RecordTypeTXT,
 				Data: "SOME-TXT-TEXT",
-				TTL:  digitalOceanRecordTTL,
+				TTL:  defaultTTL,
 			},
 		},
 	}
@@ -466,21 +466,21 @@ func TestDigitalOceanProcessUpdateActions(t *testing.T) {
 				Name: "foo",
 				Type: endpoint.RecordTypeA,
 				Data: "1.2.3.4",
-				TTL:  digitalOceanRecordTTL,
+				TTL:  defaultTTL,
 			},
 			{
 				ID:   2,
 				Name: "foo",
 				Type: endpoint.RecordTypeA,
 				Data: "5.6.7.8",
-				TTL:  digitalOceanRecordTTL,
+				TTL:  defaultTTL,
 			},
 			{
 				ID:   3,
 				Name: "@",
 				Type: endpoint.RecordTypeCNAME,
 				Data: "foo.example.com.",
-				TTL:  digitalOceanRecordTTL,
+				TTL:  defaultTTL,
 			},
 			{
 				ID:       4,
@@ -488,7 +488,7 @@ func TestDigitalOceanProcessUpdateActions(t *testing.T) {
 				Type:     endpoint.RecordTypeMX,
 				Data:     "mx1.example.com.",
 				Priority: 10,
-				TTL:      digitalOceanRecordTTL,
+				TTL:      defaultTTL,
 			},
 			{
 				ID:       5,
@@ -496,14 +496,14 @@ func TestDigitalOceanProcessUpdateActions(t *testing.T) {
 				Type:     endpoint.RecordTypeMX,
 				Data:     "mx2.example.com.",
 				Priority: 10,
-				TTL:      digitalOceanRecordTTL,
+				TTL:      defaultTTL,
 			},
 			{
 				ID:   6,
 				Name: "@",
 				Type: endpoint.RecordTypeTXT,
 				Data: "SOME_TXTX_TEXT",
-				TTL:  digitalOceanRecordTTL,
+				TTL:  defaultTTL,
 			},
 		},
 	}
@@ -532,7 +532,7 @@ func TestDigitalOceanProcessUpdateActions(t *testing.T) {
 				Name: "foo",
 				Type: endpoint.RecordTypeA,
 				Data: "10.11.12.13",
-				TTL:  digitalOceanRecordTTL,
+				TTL:  defaultTTL,
 			},
 		},
 		{
@@ -541,7 +541,7 @@ func TestDigitalOceanProcessUpdateActions(t *testing.T) {
 				Name: "@",
 				Type: endpoint.RecordTypeCNAME,
 				Data: "bar.example.com.",
-				TTL:  digitalOceanRecordTTL,
+				TTL:  defaultTTL,
 			},
 		},
 		{
@@ -551,7 +551,7 @@ func TestDigitalOceanProcessUpdateActions(t *testing.T) {
 				Type:     endpoint.RecordTypeMX,
 				Data:     "mx3.example.com.",
 				Priority: 10,
-				TTL:      digitalOceanRecordTTL,
+				TTL:      defaultTTL,
 			},
 		},
 		{
@@ -560,7 +560,7 @@ func TestDigitalOceanProcessUpdateActions(t *testing.T) {
 				Name: "@",
 				Type: endpoint.RecordTypeTXT,
 				Data: "ANOTHER-TXT",
-				TTL:  digitalOceanRecordTTL,
+				TTL:  defaultTTL,
 			},
 		},
 	}
@@ -609,7 +609,7 @@ func TestDigitalOceanProcessDeleteActions(t *testing.T) {
 				Name: "foo",
 				Type: endpoint.RecordTypeA,
 				Data: "1.2.3.4",
-				TTL:  digitalOceanRecordTTL,
+				TTL:  defaultTTL,
 			},
 			// This record will not be deleted because it represents a target not specified to be deleted.
 			{
@@ -617,14 +617,14 @@ func TestDigitalOceanProcessDeleteActions(t *testing.T) {
 				Name: "foo",
 				Type: endpoint.RecordTypeA,
 				Data: "5.6.7.8",
-				TTL:  digitalOceanRecordTTL,
+				TTL:  defaultTTL,
 			},
 			{
 				ID:   3,
 				Name: "@",
 				Type: endpoint.RecordTypeCNAME,
 				Data: "foo.example.com.",
-				TTL:  digitalOceanRecordTTL,
+				TTL:  defaultTTL,
 			},
 		},
 	}
diff --git a/provider/godaddy/godaddy_test.go b/provider/godaddy/godaddy_test.go
index 22107df1..57e04e21 100644
--- a/provider/godaddy/godaddy_test.go
+++ b/provider/godaddy/godaddy_test.go
@@ -138,13 +138,13 @@ func TestGoDaddyZoneRecords(t *testing.T) {
 		{
 			Name: "godaddy",
 			Type: "NS",
-			TTL:  gdMinimalTTL,
+			TTL:  defaultTTL,
 			Data: "203.0.113.42",
 		},
 		{
 			Name: "godaddy",
 			Type: "A",
-			TTL:  gdMinimalTTL,
+			TTL:  defaultTTL,
 			Data: "203.0.113.42",
 		},
 	}, nil).Once()
@@ -164,13 +164,13 @@ func TestGoDaddyZoneRecords(t *testing.T) {
 				{
 					Name: "godaddy",
 					Type: "NS",
-					TTL:  gdMinimalTTL,
+					TTL:  defaultTTL,
 					Data: "203.0.113.42",
 				},
 				{
 					Name: "godaddy",
 					Type: "A",
-					TTL:  gdMinimalTTL,
+					TTL:  defaultTTL,
 					Data: "203.0.113.42",
 				},
 			},
@@ -240,13 +240,13 @@ func TestGoDaddyRecords(t *testing.T) {
 		{
 			Name: "@",
 			Type: "A",
-			TTL:  gdMinimalTTL,
+			TTL:  defaultTTL,
 			Data: "203.0.113.42",
 		},
 		{
 			Name: "www",
 			Type: "CNAME",
-			TTL:  gdMinimalTTL,
+			TTL:  defaultTTL,
 			Data: "example.org",
 		},
 	}, nil).Once()
@@ -255,13 +255,13 @@ func TestGoDaddyRecords(t *testing.T) {
 		{
 			Name: "godaddy",
 			Type: "A",
-			TTL:  gdMinimalTTL,
+			TTL:  defaultTTL,
 			Data: "203.0.113.42",
 		},
 		{
 			Name: "godaddy",
 			Type: "A",
-			TTL:  gdMinimalTTL,
+			TTL:  defaultTTL,
 			Data: "203.0.113.43",
 		},
 	}, nil).Once()
@@ -278,7 +278,7 @@ func TestGoDaddyRecords(t *testing.T) {
 		{
 			DNSName:    "godaddy.example.net",
 			RecordType: "A",
-			RecordTTL:  gdMinimalTTL,
+			RecordTTL:  defaultTTL,
 			Labels:     endpoint.NewLabels(),
 			Targets: []string{
 				"203.0.113.42",
@@ -288,7 +288,7 @@ func TestGoDaddyRecords(t *testing.T) {
 		{
 			DNSName:    "example.org",
 			RecordType: "A",
-			RecordTTL:  gdMinimalTTL,
+			RecordTTL:  defaultTTL,
 			Labels:     endpoint.NewLabels(),
 			Targets: []string{
 				"203.0.113.42",
@@ -297,7 +297,7 @@ func TestGoDaddyRecords(t *testing.T) {
 		{
 			DNSName:    "www.example.org",
 			RecordType: "CNAME",
-			RecordTTL:  gdMinimalTTL,
+			RecordTTL:  defaultTTL,
 			Labels:     endpoint.NewLabels(),
 			Targets: []string{
 				"example.org",
@@ -327,7 +327,7 @@ func TestGoDaddyChange(t *testing.T) {
 			{
 				DNSName:    ".example.net",
 				RecordType: "A",
-				RecordTTL:  gdMinimalTTL,
+				RecordTTL:  defaultTTL,
 				Targets: []string{
 					"203.0.113.42",
 				},
@@ -356,7 +356,7 @@ func TestGoDaddyChange(t *testing.T) {
 		{
 			Name: "godaddy",
 			Type: "A",
-			TTL:  gdMinimalTTL,
+			TTL:  defaultTTL,
 			Data: "203.0.113.43",
 		},
 	}, nil).Once()
@@ -366,7 +366,7 @@ func TestGoDaddyChange(t *testing.T) {
 		{
 			Name: "@",
 			Type: "A",
-			TTL:  gdMinimalTTL,
+			TTL:  defaultTTL,
 			Data: "203.0.113.42",
 		},
 	}).Return(nil, nil).Once()
@@ -398,7 +398,7 @@ func TestGoDaddyErrorResponse(t *testing.T) {
 			{
 				DNSName:    ".example.net",
 				RecordType: "A",
-				RecordTTL:  gdMinimalTTL,
+				RecordTTL:  defaultTTL,
 				Targets: []string{
 					"203.0.113.42",
 				},
@@ -427,7 +427,7 @@ func TestGoDaddyErrorResponse(t *testing.T) {
 		{
 			Name: "godaddy",
 			Type: "A",
-			TTL:  gdMinimalTTL,
+			TTL:  defaultTTL,
 			Data: "203.0.113.43",
 		},
 	}, nil).Once()
diff --git a/provider/google/google_test.go b/provider/google/google_test.go
index 0cec40a3..45724321 100644
--- a/provider/google/google_test.go
+++ b/provider/google/google_test.go
@@ -279,12 +279,12 @@ func TestGoogleRecords(t *testing.T) {
 
 func TestGoogleRecordsFilter(t *testing.T) {
 	originalEndpoints := []*endpoint.Endpoint{
-		endpoint.NewEndpointWithTTL("update-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, googleRecordTTL, "8.8.8.8"),
-		endpoint.NewEndpointWithTTL("delete-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, googleRecordTTL, "8.8.8.8"),
-		endpoint.NewEndpointWithTTL("update-test.zone-2.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, googleRecordTTL, "8.8.4.4"),
-		endpoint.NewEndpointWithTTL("delete-test.zone-2.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, googleRecordTTL, "8.8.4.4"),
-		endpoint.NewEndpointWithTTL("update-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, googleRecordTTL, "bar.elb.amazonaws.com"),
-		endpoint.NewEndpointWithTTL("delete-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, googleRecordTTL, "qux.elb.amazonaws.com"),
+		endpoint.NewEndpointWithTTL("update-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, defaultTTL, "8.8.8.8"),
+		endpoint.NewEndpointWithTTL("delete-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, defaultTTL, "8.8.8.8"),
+		endpoint.NewEndpointWithTTL("update-test.zone-2.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, defaultTTL, "8.8.4.4"),
+		endpoint.NewEndpointWithTTL("delete-test.zone-2.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, defaultTTL, "8.8.4.4"),
+		endpoint.NewEndpointWithTTL("update-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, defaultTTL, "bar.elb.amazonaws.com"),
+		endpoint.NewEndpointWithTTL("delete-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, defaultTTL, "qux.elb.amazonaws.com"),
 	}
 
 	provider := newGoogleProvider(
@@ -339,12 +339,12 @@ func TestGoogleApplyChanges(t *testing.T) {
 		provider.NewZoneIDFilter([]string{""}),
 		false,
 		[]*endpoint.Endpoint{
-			endpoint.NewEndpointWithTTL("update-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, googleRecordTTL, "8.8.8.8"),
-			endpoint.NewEndpointWithTTL("delete-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, googleRecordTTL, "8.8.8.8"),
+			endpoint.NewEndpointWithTTL("update-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, defaultTTL, "8.8.8.8"),
+			endpoint.NewEndpointWithTTL("delete-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, defaultTTL, "8.8.8.8"),
 			endpoint.NewEndpointWithTTL("update-test-ttl.zone-2.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, endpoint.TTL(10), "8.8.4.4"),
-			endpoint.NewEndpointWithTTL("delete-test.zone-2.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, googleRecordTTL, "8.8.4.4"),
-			endpoint.NewEndpointWithTTL("update-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, googleRecordTTL, "bar.elb.amazonaws.com"),
-			endpoint.NewEndpointWithTTL("delete-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, googleRecordTTL, "qux.elb.amazonaws.com"),
+			endpoint.NewEndpointWithTTL("delete-test.zone-2.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, defaultTTL, "8.8.4.4"),
+			endpoint.NewEndpointWithTTL("update-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, defaultTTL, "bar.elb.amazonaws.com"),
+			endpoint.NewEndpointWithTTL("delete-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, defaultTTL, "qux.elb.amazonaws.com"),
 		},
 		nil,
 		nil,
@@ -393,23 +393,23 @@ func TestGoogleApplyChanges(t *testing.T) {
 	require.NoError(t, err)
 
 	validateEndpoints(t, records, []*endpoint.Endpoint{
-		endpoint.NewEndpointWithTTL("create-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, googleRecordTTL, "8.8.8.8"),
-		endpoint.NewEndpointWithTTL("update-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, googleRecordTTL, "1.2.3.4"),
+		endpoint.NewEndpointWithTTL("create-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, defaultTTL, "8.8.8.8"),
+		endpoint.NewEndpointWithTTL("update-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, defaultTTL, "1.2.3.4"),
 		endpoint.NewEndpointWithTTL("create-test-ttl.zone-2.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, endpoint.TTL(15), "8.8.4.4"),
 		endpoint.NewEndpointWithTTL("update-test-ttl.zone-2.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, endpoint.TTL(25), "4.3.2.1"),
-		endpoint.NewEndpointWithTTL("create-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, googleRecordTTL, "foo.elb.amazonaws.com"),
-		endpoint.NewEndpointWithTTL("update-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, googleRecordTTL, "baz.elb.amazonaws.com"),
+		endpoint.NewEndpointWithTTL("create-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, defaultTTL, "foo.elb.amazonaws.com"),
+		endpoint.NewEndpointWithTTL("update-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, defaultTTL, "baz.elb.amazonaws.com"),
 	})
 }
 
 func TestGoogleApplyChangesDryRun(t *testing.T) {
 	originalEndpoints := []*endpoint.Endpoint{
-		endpoint.NewEndpointWithTTL("update-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, googleRecordTTL, "8.8.8.8"),
-		endpoint.NewEndpointWithTTL("delete-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, googleRecordTTL, "8.8.8.8"),
-		endpoint.NewEndpointWithTTL("update-test.zone-2.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, googleRecordTTL, "8.8.4.4"),
-		endpoint.NewEndpointWithTTL("delete-test.zone-2.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, googleRecordTTL, "8.8.4.4"),
-		endpoint.NewEndpointWithTTL("update-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, googleRecordTTL, "bar.elb.amazonaws.com"),
-		endpoint.NewEndpointWithTTL("delete-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, googleRecordTTL, "qux.elb.amazonaws.com"),
+		endpoint.NewEndpointWithTTL("update-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, defaultTTL, "8.8.8.8"),
+		endpoint.NewEndpointWithTTL("delete-test.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, defaultTTL, "8.8.8.8"),
+		endpoint.NewEndpointWithTTL("update-test.zone-2.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, defaultTTL, "8.8.4.4"),
+		endpoint.NewEndpointWithTTL("delete-test.zone-2.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeA, defaultTTL, "8.8.4.4"),
+		endpoint.NewEndpointWithTTL("update-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, defaultTTL, "bar.elb.amazonaws.com"),
+		endpoint.NewEndpointWithTTL("delete-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", endpoint.RecordTypeCNAME, defaultTTL, "qux.elb.amazonaws.com"),
 	}
 
 	provider := newGoogleProvider(t, endpoint.NewDomainFilter([]string{"ext-dns-test-2.gcp.zalan.do."}), provider.NewZoneIDFilter([]string{""}), true, originalEndpoints, nil, nil)
diff --git a/provider/oci/oci_test.go b/provider/oci/oci_test.go
index 7906951a..427f713d 100644
--- a/provider/oci/oci_test.go
+++ b/provider/oci/oci_test.go
@@ -18,6 +18,8 @@ package oci
 
 import (
 	"context"
+	"errors"
+	"fmt"
 	"sort"
 	"strings"
 	"testing"
@@ -25,7 +27,6 @@ import (
 
 	"github.com/oracle/oci-go-sdk/v65/common"
 	"github.com/oracle/oci-go-sdk/v65/dns"
-	"github.com/pkg/errors"
 	"github.com/stretchr/testify/require"
 
 	"sigs.k8s.io/external-dns/endpoint"
@@ -93,12 +94,12 @@ func (c *mockOCIDNSClient) GetZoneRecords(ctx context.Context, request dns.GetZo
 				Domain: common.String("foo.foo.com"),
 				Rdata:  common.String("127.0.0.1"),
 				Rtype:  common.String(endpoint.RecordTypeA),
-				Ttl:    common.Int(ociRecordTTL),
+				Ttl:    common.Int(defaultTTL),
 			}, {
 				Domain: common.String("foo.foo.com"),
 				Rdata:  common.String("heritage=external-dns,external-dns/owner=default,external-dns/resource=service/default/my-svc"),
 				Rtype:  common.String(endpoint.RecordTypeTXT),
-				Ttl:    common.Int(ociRecordTTL),
+				Ttl:    common.Int(defaultTTL),
 			}}
 			response.OpcNextPage = common.String("1")
 		} else {
@@ -106,7 +107,7 @@ func (c *mockOCIDNSClient) GetZoneRecords(ctx context.Context, request dns.GetZo
 				Domain: common.String("bar.foo.com"),
 				Rdata:  common.String("bar.com."),
 				Rtype:  common.String(endpoint.RecordTypeCNAME),
-				Ttl:    common.Int(ociRecordTTL),
+				Ttl:    common.Int(defaultTTL),
 			}}
 		}
 	case "ocid1.dns-zone.oc1..502aeddba262b92fd13ed7874f6f1404":
@@ -115,7 +116,7 @@ func (c *mockOCIDNSClient) GetZoneRecords(ctx context.Context, request dns.GetZo
 				Domain: common.String("foo.bar.com"),
 				Rdata:  common.String("127.0.0.1"),
 				Rtype:  common.String(endpoint.RecordTypeA),
-				Ttl:    common.Int(ociRecordTTL),
+				Ttl:    common.Int(defaultTTL),
 			}}
 		}
 	}
@@ -329,26 +330,26 @@ func TestOCIRecords(t *testing.T) {
 			domainFilter: endpoint.NewDomainFilter([]string{""}),
 			zoneIDFilter: provider.NewZoneIDFilter([]string{""}),
 			expected: []*endpoint.Endpoint{
-				endpoint.NewEndpointWithTTL("foo.foo.com", endpoint.RecordTypeA, endpoint.TTL(ociRecordTTL), "127.0.0.1"),
-				endpoint.NewEndpointWithTTL("foo.foo.com", endpoint.RecordTypeTXT, endpoint.TTL(ociRecordTTL), "heritage=external-dns,external-dns/owner=default,external-dns/resource=service/default/my-svc"),
-				endpoint.NewEndpointWithTTL("bar.foo.com", endpoint.RecordTypeCNAME, endpoint.TTL(ociRecordTTL), "bar.com."),
-				endpoint.NewEndpointWithTTL("foo.bar.com", endpoint.RecordTypeA, endpoint.TTL(ociRecordTTL), "127.0.0.1"),
+				endpoint.NewEndpointWithTTL("foo.foo.com", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "127.0.0.1"),
+				endpoint.NewEndpointWithTTL("foo.foo.com", endpoint.RecordTypeTXT, endpoint.TTL(defaultTTL), "heritage=external-dns,external-dns/owner=default,external-dns/resource=service/default/my-svc"),
+				endpoint.NewEndpointWithTTL("bar.foo.com", endpoint.RecordTypeCNAME, endpoint.TTL(defaultTTL), "bar.com."),
+				endpoint.NewEndpointWithTTL("foo.bar.com", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "127.0.0.1"),
 			},
 		}, {
 			name:         "DomainFilter_foo.com",
 			domainFilter: endpoint.NewDomainFilter([]string{"foo.com"}),
 			zoneIDFilter: provider.NewZoneIDFilter([]string{""}),
 			expected: []*endpoint.Endpoint{
-				endpoint.NewEndpointWithTTL("foo.foo.com", endpoint.RecordTypeA, endpoint.TTL(ociRecordTTL), "127.0.0.1"),
-				endpoint.NewEndpointWithTTL("foo.foo.com", endpoint.RecordTypeTXT, endpoint.TTL(ociRecordTTL), "heritage=external-dns,external-dns/owner=default,external-dns/resource=service/default/my-svc"),
-				endpoint.NewEndpointWithTTL("bar.foo.com", endpoint.RecordTypeCNAME, endpoint.TTL(ociRecordTTL), "bar.com."),
+				endpoint.NewEndpointWithTTL("foo.foo.com", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "127.0.0.1"),
+				endpoint.NewEndpointWithTTL("foo.foo.com", endpoint.RecordTypeTXT, endpoint.TTL(defaultTTL), "heritage=external-dns,external-dns/owner=default,external-dns/resource=service/default/my-svc"),
+				endpoint.NewEndpointWithTTL("bar.foo.com", endpoint.RecordTypeCNAME, endpoint.TTL(defaultTTL), "bar.com."),
 			},
 		}, {
 			name:         "ZoneIDFilter_ocid1.dns-zone.oc1..502aeddba262b92fd13ed7874f6f1404",
 			domainFilter: endpoint.NewDomainFilter([]string{""}),
 			zoneIDFilter: provider.NewZoneIDFilter([]string{"ocid1.dns-zone.oc1..502aeddba262b92fd13ed7874f6f1404"}),
 			expected: []*endpoint.Endpoint{
-				endpoint.NewEndpointWithTTL("foo.bar.com", endpoint.RecordTypeA, endpoint.TTL(ociRecordTTL), "127.0.0.1"),
+				endpoint.NewEndpointWithTTL("foo.bar.com", endpoint.RecordTypeA, endpoint.TTL(defaultTTL), "127.0.0.1"),
 			},
 		},
 	}
@@ -375,7 +376,7 @@ func TestNewRecordOperation(t *testing.T) {
 			ep: endpoint.NewEndpointWithTTL(
 				"foo.foo.com",
 				endpoint.RecordTypeA,
-				endpoint.TTL(ociRecordTTL),
+				endpoint.TTL(defaultTTL),
 				"127.0.0.1"),
 			expected: dns.RecordOperation{
 				Domain:    common.String("foo.foo.com"),
@@ -390,7 +391,7 @@ func TestNewRecordOperation(t *testing.T) {
 			ep: endpoint.NewEndpointWithTTL(
 				"foo.foo.com",
 				endpoint.RecordTypeTXT,
-				endpoint.TTL(ociRecordTTL),
+				endpoint.TTL(defaultTTL),
 				"heritage=external-dns,external-dns/owner=default,external-dns/resource=service/default/my-svc"),
 			expected: dns.RecordOperation{
 				Domain:    common.String("foo.foo.com"),
@@ -405,7 +406,7 @@ func TestNewRecordOperation(t *testing.T) {
 			ep: endpoint.NewEndpointWithTTL(
 				"foo.foo.com",
 				endpoint.RecordTypeCNAME,
-				endpoint.TTL(ociRecordTTL),
+				endpoint.TTL(defaultTTL),
 				"bar.com."),
 			expected: dns.RecordOperation{
 				Domain:    common.String("foo.foo.com"),
@@ -621,7 +622,7 @@ func (c *mutableMockOCIDNSClient) PatchZoneRecords(ctx context.Context, request
 		case dns.RecordOperationOperationRemove:
 			delete(records, k)
 		default:
-			err = errors.Errorf("unsupported operation %q", op.Operation)
+			err = fmt.Errorf("unsupported operation %q", op.Operation)
 			return
 		}
 	}
@@ -640,12 +641,12 @@ func TestMutableMockOCIDNSClient(t *testing.T) {
 			Domain: common.String("foo.foo.com"),
 			Rdata:  common.String("127.0.0.1"),
 			Rtype:  common.String(endpoint.RecordTypeA),
-			Ttl:    common.Int(ociRecordTTL),
+			Ttl:    common.Int(defaultTTL),
 		}, {
 			Domain: common.String("foo.foo.com"),
 			Rdata:  common.String("heritage=external-dns,external-dns/owner=default,external-dns/resource=service/default/my-svc"),
 			Rtype:  common.String(endpoint.RecordTypeTXT),
-			Ttl:    common.Int(ociRecordTTL),
+			Ttl:    common.Int(defaultTTL),
 		}},
 	}
 	client := newMutableMockOCIDNSClient(zones, records)
@@ -732,14 +733,14 @@ func TestOCIApplyChanges(t *testing.T) {
 				Create: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL(
 					"foo.foo.com",
 					endpoint.RecordTypeA,
-					endpoint.TTL(ociRecordTTL),
+					endpoint.TTL(defaultTTL),
 					"127.0.0.1",
 				)},
 			},
 			expectedEndpoints: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL(
 				"foo.foo.com",
 				endpoint.RecordTypeA,
-				endpoint.TTL(ociRecordTTL),
+				endpoint.TTL(defaultTTL),
 				"127.0.0.1",
 			)},
 		}, {
@@ -753,26 +754,26 @@ func TestOCIApplyChanges(t *testing.T) {
 					Domain: common.String("foo.foo.com"),
 					Rdata:  common.String("127.0.0.1"),
 					Rtype:  common.String(endpoint.RecordTypeA),
-					Ttl:    common.Int(ociRecordTTL),
+					Ttl:    common.Int(defaultTTL),
 				}, {
 					Domain: common.String("foo.foo.com"),
 					Rdata:  common.String("heritage=external-dns,external-dns/owner=default,external-dns/resource=service/default/my-svc"),
 					Rtype:  common.String(endpoint.RecordTypeTXT),
-					Ttl:    common.Int(ociRecordTTL),
+					Ttl:    common.Int(defaultTTL),
 				}},
 			},
 			changes: &plan.Changes{
 				Delete: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL(
 					"foo.foo.com",
 					endpoint.RecordTypeTXT,
-					endpoint.TTL(ociRecordTTL),
+					endpoint.TTL(defaultTTL),
 					"127.0.0.1",
 				)},
 			},
 			expectedEndpoints: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL(
 				"foo.foo.com",
 				endpoint.RecordTypeA,
-				endpoint.TTL(ociRecordTTL),
+				endpoint.TTL(defaultTTL),
 				"127.0.0.1",
 			)},
 		}, {
@@ -786,27 +787,27 @@ func TestOCIApplyChanges(t *testing.T) {
 					Domain: common.String("foo.foo.com"),
 					Rdata:  common.String("127.0.0.1"),
 					Rtype:  common.String(endpoint.RecordTypeA),
-					Ttl:    common.Int(ociRecordTTL),
+					Ttl:    common.Int(defaultTTL),
 				}},
 			},
 			changes: &plan.Changes{
 				UpdateOld: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL(
 					"foo.foo.com",
 					endpoint.RecordTypeA,
-					endpoint.TTL(ociRecordTTL),
+					endpoint.TTL(defaultTTL),
 					"127.0.0.1",
 				)},
 				UpdateNew: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL(
 					"foo.foo.com",
 					endpoint.RecordTypeA,
-					endpoint.TTL(ociRecordTTL),
+					endpoint.TTL(defaultTTL),
 					"10.0.0.1",
 				)},
 			},
 			expectedEndpoints: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL(
 				"foo.foo.com",
 				endpoint.RecordTypeA,
-				endpoint.TTL(ociRecordTTL),
+				endpoint.TTL(defaultTTL),
 				"10.0.0.1",
 			)},
 		}, {
@@ -820,14 +821,14 @@ func TestOCIApplyChanges(t *testing.T) {
 					Domain: common.String("foo.foo.com"),
 					Rdata:  common.String("127.0.0.1"),
 					Rtype:  common.String(endpoint.RecordTypeA),
-					Ttl:    common.Int(ociRecordTTL),
+					Ttl:    common.Int(defaultTTL),
 				}},
 			},
 			changes: &plan.Changes{
 				Delete: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL(
 					"foo.foo.com",
 					endpoint.RecordTypeA,
-					endpoint.TTL(ociRecordTTL),
+					endpoint.TTL(defaultTTL),
 					"127.0.0.1",
 				)},
 			},
@@ -835,7 +836,7 @@ func TestOCIApplyChanges(t *testing.T) {
 			expectedEndpoints: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL(
 				"foo.foo.com",
 				endpoint.RecordTypeA,
-				endpoint.TTL(ociRecordTTL),
+				endpoint.TTL(defaultTTL),
 				"127.0.0.1",
 			)},
 		}, {
@@ -849,42 +850,42 @@ func TestOCIApplyChanges(t *testing.T) {
 					Domain: common.String("foo.foo.com"),
 					Rdata:  common.String("127.0.0.1"),
 					Rtype:  common.String(endpoint.RecordTypeA),
-					Ttl:    common.Int(ociRecordTTL),
+					Ttl:    common.Int(defaultTTL),
 				}, {
 					Domain: common.String("car.foo.com"),
 					Rdata:  common.String("bar.com."),
 					Rtype:  common.String(endpoint.RecordTypeCNAME),
-					Ttl:    common.Int(ociRecordTTL),
+					Ttl:    common.Int(defaultTTL),
 				}, {
 					Domain: common.String("bar.foo.com"),
 					Rdata:  common.String("baz.com."),
 					Rtype:  common.String(endpoint.RecordTypeCNAME),
-					Ttl:    common.Int(ociRecordTTL),
+					Ttl:    common.Int(defaultTTL),
 				}},
 			},
 			changes: &plan.Changes{
 				Delete: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL(
 					"foo.foo.com",
 					endpoint.RecordTypeA,
-					endpoint.TTL(ociRecordTTL),
+					endpoint.TTL(defaultTTL),
 					"127.0.0.1",
 				)},
 				UpdateOld: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL(
 					"car.foo.com",
 					endpoint.RecordTypeCNAME,
-					endpoint.TTL(ociRecordTTL),
+					endpoint.TTL(defaultTTL),
 					"baz.com.",
 				)},
 				UpdateNew: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL(
 					"bar.foo.com",
 					endpoint.RecordTypeCNAME,
-					endpoint.TTL(ociRecordTTL),
+					endpoint.TTL(defaultTTL),
 					"foo.bar.com.",
 				)},
 				Create: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL(
 					"baz.foo.com",
 					endpoint.RecordTypeA,
-					endpoint.TTL(ociRecordTTL),
+					endpoint.TTL(defaultTTL),
 					"127.0.0.1",
 				)},
 			},
@@ -892,13 +893,13 @@ func TestOCIApplyChanges(t *testing.T) {
 				endpoint.NewEndpointWithTTL(
 					"bar.foo.com",
 					endpoint.RecordTypeCNAME,
-					endpoint.TTL(ociRecordTTL),
+					endpoint.TTL(defaultTTL),
 					"foo.bar.com.",
 				),
 				endpoint.NewEndpointWithTTL(
 					"baz.foo.com",
 					endpoint.RecordTypeA,
-					endpoint.TTL(ociRecordTTL),
+					endpoint.TTL(defaultTTL),
 					"127.0.0.1"),
 			},
 		},
@@ -913,19 +914,19 @@ func TestOCIApplyChanges(t *testing.T) {
 				Create: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL(
 					"foo.foo.com",
 					endpoint.RecordTypeA,
-					endpoint.TTL(ociRecordTTL),
+					endpoint.TTL(defaultTTL),
 					"192.168.1.2",
 				), endpoint.NewEndpointWithTTL(
 					"foo.foo.com",
 					endpoint.RecordTypeA,
-					endpoint.TTL(ociRecordTTL),
+					endpoint.TTL(defaultTTL),
 					"192.168.2.5",
 				)},
 			},
 			expectedEndpoints: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL(
 				"foo.foo.com",
 				endpoint.RecordTypeA,
-				endpoint.TTL(ociRecordTTL), "192.168.1.2", "192.168.2.5",
+				endpoint.TTL(defaultTTL), "192.168.1.2", "192.168.2.5",
 			)},
 		},
 		{
@@ -939,26 +940,26 @@ func TestOCIApplyChanges(t *testing.T) {
 					Domain: common.String("foo.foo.com"),
 					Rdata:  common.String("192.168.1.2"),
 					Rtype:  common.String(endpoint.RecordTypeA),
-					Ttl:    common.Int(ociRecordTTL),
+					Ttl:    common.Int(defaultTTL),
 				}, {
 					Domain: common.String("foo.foo.com"),
 					Rdata:  common.String("192.168.2.5"),
 					Rtype:  common.String(endpoint.RecordTypeA),
-					Ttl:    common.Int(ociRecordTTL),
+					Ttl:    common.Int(defaultTTL),
 				}},
 			},
 			changes: &plan.Changes{
 				Delete: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL(
 					"foo.foo.com",
 					endpoint.RecordTypeA,
-					endpoint.TTL(ociRecordTTL),
+					endpoint.TTL(defaultTTL),
 					"192.168.1.2",
 				)},
 			},
 			expectedEndpoints: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL(
 				"foo.foo.com",
 				endpoint.RecordTypeA,
-				endpoint.TTL(ociRecordTTL), "192.168.2.5",
+				endpoint.TTL(defaultTTL), "192.168.2.5",
 			)},
 		},
 		{
@@ -972,27 +973,27 @@ func TestOCIApplyChanges(t *testing.T) {
 					Domain: common.String("first.foo.com"),
 					Rdata:  common.String("10.77.4.5"),
 					Rtype:  common.String(endpoint.RecordTypeA),
-					Ttl:    common.Int(ociRecordTTL),
+					Ttl:    common.Int(defaultTTL),
 				}},
 			},
 			changes: &plan.Changes{
 				UpdateOld: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL(
 					"first.foo.com",
 					endpoint.RecordTypeA,
-					endpoint.TTL(ociRecordTTL),
+					endpoint.TTL(defaultTTL),
 					"10.77.4.5",
 				)},
 				UpdateNew: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL(
 					"first.foo.com",
 					endpoint.RecordTypeA,
-					endpoint.TTL(ociRecordTTL),
+					endpoint.TTL(defaultTTL),
 					"10.77.6.10",
 				)},
 			},
 			expectedEndpoints: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL(
 				"first.foo.com",
 				endpoint.RecordTypeA,
-				endpoint.TTL(ociRecordTTL),
+				endpoint.TTL(defaultTTL),
 				"10.77.6.10",
 			)},
 		},
@@ -1007,21 +1008,21 @@ func TestOCIApplyChanges(t *testing.T) {
 					Domain: common.String("first.foo.com"),
 					Rdata:  common.String("10.77.4.5"),
 					Rtype:  common.String(endpoint.RecordTypeA),
-					Ttl:    common.Int(ociRecordTTL),
+					Ttl:    common.Int(defaultTTL),
 				}},
 			},
 			changes: &plan.Changes{
 				Create: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL(
 					"first.foo.com",
 					endpoint.RecordTypeA,
-					endpoint.TTL(ociRecordTTL),
+					endpoint.TTL(defaultTTL),
 					"10.77.6.10",
 				)},
 			},
 			expectedEndpoints: []*endpoint.Endpoint{endpoint.NewEndpointWithTTL(
 				"first.foo.com",
 				endpoint.RecordTypeA,
-				endpoint.TTL(ociRecordTTL),
+				endpoint.TTL(defaultTTL),
 				"10.77.4.5", "10.77.6.10",
 			)},
 		},
diff --git a/provider/ovh/ovh_test.go b/provider/ovh/ovh_test.go
index fef1f320..2e69d7a5 100644
--- a/provider/ovh/ovh_test.go
+++ b/provider/ovh/ovh_test.go
@@ -371,8 +371,8 @@ func TestOvhNewChange(t *testing.T) {
 	changes, _ := provider.newOvhChangeCreateDelete(ovhCreate, endpoints, "example.net", []ovhRecord{})
 	td.Cmp(t, changes, []ovhChange{
 		{Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "", TTL: 10, Target: "203.0.113.42"}}}},
-		{Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh", TTL: ovhDefaultTTL, Target: "203.0.113.43"}}}},
-		{Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "CNAME", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh2", TTL: ovhDefaultTTL, Target: "ovh.example.net."}}}},
+		{Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh", TTL: defaultTTL, Target: "203.0.113.43"}}}},
+		{Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "CNAME", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh2", TTL: defaultTTL, Target: "ovh.example.net."}}}},
 	})
 
 	// Delete change
@@ -386,9 +386,9 @@ func TestOvhNewChange(t *testing.T) {
 	}
 	changes, _ = provider.newOvhChangeCreateDelete(ovhDelete, endpoints, "example.net", records)
 	td.Cmp(t, changes, []ovhChange{
-		{Action: ovhDelete, ovhRecord: ovhRecord{ID: 42, Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh", TTL: ovhDefaultTTL, Target: "203.0.113.42"}}}},
-		{Action: ovhDelete, ovhRecord: ovhRecord{ID: 43, Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh", TTL: ovhDefaultTTL, Target: "203.0.113.42"}}}},
-		{Action: ovhDelete, ovhRecord: ovhRecord{ID: 44, Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh", TTL: ovhDefaultTTL, Target: "203.0.113.42"}}}},
+		{Action: ovhDelete, ovhRecord: ovhRecord{ID: 42, Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh", TTL: defaultTTL, Target: "203.0.113.42"}}}},
+		{Action: ovhDelete, ovhRecord: ovhRecord{ID: 43, Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh", TTL: defaultTTL, Target: "203.0.113.42"}}}},
+		{Action: ovhDelete, ovhRecord: ovhRecord{ID: 44, Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh", TTL: defaultTTL, Target: "203.0.113.42"}}}},
 	})
 
 	// Create change with CNAME relative
@@ -403,8 +403,8 @@ func TestOvhNewChange(t *testing.T) {
 	changes, _ = provider.newOvhChangeCreateDelete(ovhCreate, endpoints, "example.net", []ovhRecord{})
 	td.Cmp(t, changes, []ovhChange{
 		{Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "", TTL: 10, Target: "203.0.113.42"}}}},
-		{Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh", TTL: ovhDefaultTTL, Target: "203.0.113.43"}}}},
-		{Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "CNAME", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh2", TTL: ovhDefaultTTL, Target: "ovh"}}}},
+		{Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh", TTL: defaultTTL, Target: "203.0.113.43"}}}},
+		{Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "CNAME", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh2", TTL: defaultTTL, Target: "ovh"}}}},
 	})
 
 	// Test with CNAME when target has already final dot
@@ -419,8 +419,8 @@ func TestOvhNewChange(t *testing.T) {
 	changes, _ = provider.newOvhChangeCreateDelete(ovhCreate, endpoints, "example.net", []ovhRecord{})
 	td.Cmp(t, changes, []ovhChange{
 		{Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "", TTL: 10, Target: "203.0.113.42"}}}},
-		{Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh", TTL: ovhDefaultTTL, Target: "203.0.113.43"}}}},
-		{Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "CNAME", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh2", TTL: ovhDefaultTTL, Target: "ovh.example.com."}}}},
+		{Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh", TTL: defaultTTL, Target: "203.0.113.43"}}}},
+		{Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "CNAME", ovhRecordFieldUpdate: ovhRecordFieldUpdate{SubDomain: "ovh2", TTL: defaultTTL, Target: "ovh.example.com."}}}},
 	})
 }
 
diff --git a/provider/pihole/clientV6_test.go b/provider/pihole/clientV6_test.go
index 664d88aa..69757179 100644
--- a/provider/pihole/clientV6_test.go
+++ b/provider/pihole/clientV6_test.go
@@ -29,6 +29,62 @@ import (
 	"sigs.k8s.io/external-dns/endpoint"
 )
 
+func TestIsValidIPv4(t *testing.T) {
+	tests := []struct {
+		ip       string
+		expected bool
+	}{
+		{"192.168.1.1", true},
+		{"255.255.255.255", true},
+		{"0.0.0.0", true},
+		{"", false},
+		{"256.256.256.256", false},
+		{"192.168.0.1/22", false},
+		{"192.168.1", false},
+		{"abc.def.ghi.jkl", false},
+		{"::ffff:192.168.20.3", false},
+	}
+
+	for _, test := range tests {
+		t.Run(test.ip, func(t *testing.T) {
+			if got := isValidIPv4(test.ip); got != test.expected {
+				t.Errorf("isValidIPv4(%s) = %v; want %v", test.ip, got, test.expected)
+			}
+		})
+	}
+}
+
+func TestIsValidIPv6(t *testing.T) {
+	tests := []struct {
+		ip       string
+		expected bool
+	}{
+		{"2001:0db8:85a3:0000:0000:8a2e:0370:7334", true},
+		{"2001:db8:85a3::8a2e:370:7334", true},
+		//IPV6 dual, the format is y:y:y:y:y:y:x.x.x.x.
+		{"::ffff:192.168.20.3", true},
+		{"::1", true},
+		{"::", true},
+		{"2001:db8::", true},
+		{"", false},
+		{":", false},
+		{"::ffff:", false},
+		{"192.168.20.3", false},
+		{"2001:db8:85a3:0:0:8a2e:370:7334:1234", false},
+		{"2001:db8:85a3::8a2e:370g:7334", false},
+		{"2001:db8:85a3::8a2e:370:7334::", false},
+		{"2001:db8:85a3::8a2e:370:7334::1", false},
+	}
+
+	for _, test := range tests {
+		t.Run(test.ip, func(t *testing.T) {
+			if got := isValidIPv6(test.ip); got != test.expected {
+				t.Errorf("isValidIPv6(%s) = %v; want %v", test.ip, got, test.expected)
+			}
+		})
+	}
+}
+
 func newTestServerV6(t *testing.T, hdlr http.HandlerFunc) *httptest.Server {
 	t.Helper()
 	svr := httptest.NewServer(hdlr)
@@ -137,7 +193,9 @@ func TestListRecordsV6(t *testing.T) {
 							"192.168.178.34 service3.example.com",
 							"fc00::1:192:168:1:1 service4.example.com",
 							"fc00::1:192:168:1:2 service5.example.com",
-							"fc00::1:192:168:1:3 service6.example.com"
+							"fc00::1:192:168:1:3 service6.example.com",
+							"::ffff:192.168.20.3 service7.example.com",
+							"192.168.20.3 service7.example.com"
 						]
 					}
 				},
@@ -177,20 +235,22 @@ func TestListRecordsV6(t *testing.T) {
 		t.Fatal(err)
 	}
 
+	// Ensure A records were parsed correctly
+	expected := [][]string{
+		{"service1.example.com", "192.168.178.33"},
+		{"service2.example.com", "192.168.178.34"},
+		{"service3.example.com", "192.168.178.34"},
+		{"service7.example.com", "192.168.20.3"},
+	}
 	// Test retrieve A records unfiltered
 	arecs, err := cl.listRecords(context.Background(), endpoint.RecordTypeA)
 	if err != nil {
 		t.Fatal(err)
 	}
-	if len(arecs) != 3 {
-		t.Fatal("Expected 3 A records returned, got:", len(arecs))
-	}
-	// Ensure records were parsed correctly
-	expected := [][]string{
-		{"service1.example.com", "192.168.178.33"},
-		{"service2.example.com", "192.168.178.34"},
-		{"service3.example.com", "192.168.178.34"},
+	if len(arecs) != len(expected) {
+		t.Fatalf("Expected %d A records returned, got: %d", len(expected), len(arecs))
 	}
+
 	for idx, rec := range arecs {
 		if rec.DNSName != expected[idx][0] {
 			t.Error("Got invalid DNS Name:", rec.DNSName, "expected:", expected[idx][0])
@@ -200,20 +260,23 @@ func TestListRecordsV6(t *testing.T) {
 		}
 	}
 
+	// Ensure AAAA records were parsed correctly
+	expected = [][]string{
+		{"service4.example.com", "fc00::1:192:168:1:1"},
+		{"service5.example.com", "fc00::1:192:168:1:2"},
+		{"service6.example.com", "fc00::1:192:168:1:3"},
+		{"service7.example.com", "::ffff:192.168.20.3"},
+	}
 	// Test retrieve AAAA records unfiltered
 	arecs, err = cl.listRecords(context.Background(), endpoint.RecordTypeAAAA)
 	if err != nil {
 		t.Fatal(err)
 	}
-	if len(arecs) != 3 {
-		t.Fatal("Expected 3 AAAA records returned, got:", len(arecs))
-	}
-	// Ensure records were parsed correctly
-	expected = [][]string{
-		{"service4.example.com", "fc00::1:192:168:1:1"},
-		{"service5.example.com", "fc00::1:192:168:1:2"},
-		{"service6.example.com", "fc00::1:192:168:1:3"},
+
+	if len(arecs) != len(expected) {
+		t.Fatalf("Expected %d AAAA records returned, got: %d", len(expected), len(arecs))
 	}
+
 	for idx, rec := range arecs {
 		if rec.DNSName != expected[idx][0] {
 			t.Error("Got invalid DNS Name:", rec.DNSName, "expected:", expected[idx][0])
@@ -223,20 +286,22 @@ func TestListRecordsV6(t *testing.T) {
 		}
 	}
 
+	// Ensure CNAME records were parsed correctly
+	expected = [][]string{
+		{"source1.example.com", "target1.domain.com", "1000"},
+		{"source2.example.com", "target2.domain.com", "50"},
+		{"source3.example.com", "target3.domain.com"},
+	}
+
 	// Test retrieve CNAME records unfiltered
 	cnamerecs, err := cl.listRecords(context.Background(), endpoint.RecordTypeCNAME)
 	if err != nil {
 		t.Fatal(err)
 	}
-	if len(cnamerecs) != 3 {
-		t.Fatal("Expected 3 CAME records returned, got:", len(cnamerecs))
-	}
-	// Ensure records were parsed correctly
-	expected = [][]string{
-		{"source1.example.com", "target1.domain.com", "1000"},
-		{"source2.example.com", "target2.domain.com", "50"},
-		{"source3.example.com", "target3.domain.com"},
+	if len(cnamerecs) != len(expected) {
+		t.Fatalf("Expected %d CAME records returned, got: %d", len(expected), len(cnamerecs))
 	}
+
 	for idx, rec := range cnamerecs {
 		if rec.DNSName != expected[idx][0] {
 			t.Error("Got invalid DNS Name:", rec.DNSName, "expected:", expected[idx][0])
@@ -261,6 +326,7 @@ func TestListRecordsV6(t *testing.T) {
 		t.Fatal("Expected error for using unsupported record type")
 	}
 }
+
 func TestErrorsV6(t *testing.T) {
 	//Error test cases
 
diff --git a/provider/tencentcloud/tencent_cloud_test.go b/provider/tencentcloud/tencent_cloud_test.go
index b9ee4857..06355a39 100644
--- a/provider/tencentcloud/tencent_cloud_test.go
+++ b/provider/tencentcloud/tencent_cloud_test.go
@@ -32,8 +32,6 @@ import (
 
 func NewMockTencentCloudProvider(domainFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, zoneType string) *TencentCloudProvider {
 	cfg := tencentCloudConfig{
-		// SecretId:  "",
-		// SecretKey: "",
 		RegionId: "ap-shanghai",
 		VPCId:    "vpc-abcdefg",
 	}
diff --git a/provider/transip/transip_test.go b/provider/transip/transip_test.go
index 31d13cb4..76e4189d 100644
--- a/provider/transip/transip_test.go
+++ b/provider/transip/transip_test.go
@@ -94,15 +94,15 @@ func TestTransIPDnsEntriesAreEqual(t *testing.T) {
 func TestTransIPGetMinimalValidTTL(t *testing.T) {
 	// test with 'unconfigured' TTL
 	ep := &endpoint.Endpoint{}
-	assert.EqualValues(t, transipMinimalValidTTL, getMinimalValidTTL(ep))
+	assert.EqualValues(t, defaultTTL, getMinimalValidTTL(ep))
 
 	// test with lower than minimal ttl
-	ep.RecordTTL = (transipMinimalValidTTL - 1)
-	assert.EqualValues(t, transipMinimalValidTTL, getMinimalValidTTL(ep))
+	ep.RecordTTL = (defaultTTL - 1)
+	assert.EqualValues(t, defaultTTL, getMinimalValidTTL(ep))
 
 	// test with higher than minimal ttl
-	ep.RecordTTL = (transipMinimalValidTTL + 1)
-	assert.EqualValues(t, transipMinimalValidTTL+1, getMinimalValidTTL(ep))
+	ep.RecordTTL = (defaultTTL + 1)
+	assert.EqualValues(t, defaultTTL+1, getMinimalValidTTL(ep))
 }
 
 func TestTransIPRecordNameForEndpoint(t *testing.T) {
diff --git a/provider/webhook/api/httpapi_test.go b/provider/webhook/api/httpapi_test.go
index a15efec4..1fa51f46 100644
--- a/provider/webhook/api/httpapi_test.go
+++ b/provider/webhook/api/httpapi_test.go
@@ -77,7 +77,7 @@ func TestMain(m *testing.M) {
 }
 
 func TestRecordsHandlerRecords(t *testing.T) {
-	req := httptest.NewRequest(http.MethodGet, "/records", nil)
+	req := httptest.NewRequest(http.MethodGet, UrlRecords, nil)
 	w := httptest.NewRecorder()
 
 	providerAPIServer := &WebhookServer{
@@ -99,7 +99,7 @@ func TestRecordsHandlerRecords(t *testing.T) {
 }
 
 func TestRecordsHandlerRecordsWithErrors(t *testing.T) {
-	req := httptest.NewRequest(http.MethodGet, "/records", nil)
+	req := httptest.NewRequest(http.MethodGet, UrlRecords, nil)
 	w := httptest.NewRecorder()
 
 	providerAPIServer := &WebhookServer{
@@ -139,7 +139,7 @@ func TestRecordsHandlerApplyChangesWithValidRequest(t *testing.T) {
 
 	reader := bytes.NewReader(j)
 
-	req := httptest.NewRequest(http.MethodPost, "/applychanges", reader)
+	req := httptest.NewRequest(http.MethodPost, UrlApplyChanges, reader)
 	w := httptest.NewRecorder()
 
 	providerAPIServer := &WebhookServer{
@@ -165,7 +165,7 @@ func TestRecordsHandlerApplyChangesWithErrors(t *testing.T) {
 
 	reader := bytes.NewReader(j)
 
-	req := httptest.NewRequest(http.MethodPost, "/applychanges", reader)
+	req := httptest.NewRequest(http.MethodPost, UrlApplyChanges, reader)
 	w := httptest.NewRecorder()
 
 	providerAPIServer := &WebhookServer{
@@ -191,7 +191,7 @@ func TestRecordsHandlerWithWrongHTTPMethod(t *testing.T) {
 }
 
 func TestAdjustEndpointsHandlerWithInvalidRequest(t *testing.T) {
-	req := httptest.NewRequest(http.MethodPost, "/adjustendpoints", nil)
+	req := httptest.NewRequest(http.MethodPost, UrlAdjustEndpoints, nil)
 	w := httptest.NewRecorder()
 
 	providerAPIServer := &WebhookServer{
@@ -201,7 +201,7 @@ func TestAdjustEndpointsHandlerWithInvalidRequest(t *testing.T) {
 	res := w.Result()
 	require.Equal(t, http.StatusBadRequest, res.StatusCode)
 
-	req = httptest.NewRequest(http.MethodGet, "/adjustendpoints", nil)
+	req = httptest.NewRequest(http.MethodGet, UrlAdjustEndpoints, nil)
 
 	providerAPIServer.AdjustEndpointsHandler(w, req)
 	res = w.Result()
@@ -222,7 +222,7 @@ func TestAdjustEndpointsHandlerWithValidRequest(t *testing.T) {
 	require.NoError(t, err)
 
 	reader := bytes.NewReader(j)
-	req := httptest.NewRequest(http.MethodPost, "/adjustendpoints", reader)
+	req := httptest.NewRequest(http.MethodPost, UrlAdjustEndpoints, reader)
 	w := httptest.NewRecorder()
 
 	providerAPIServer := &WebhookServer{
@@ -248,7 +248,7 @@ func TestAdjustEndpointsHandlerWithError(t *testing.T) {
 	require.NoError(t, err)
 
 	reader := bytes.NewReader(j)
-	req := httptest.NewRequest(http.MethodPost, "/adjustendpoints", reader)
+	req := httptest.NewRequest(http.MethodPost, UrlAdjustEndpoints, reader)
 	w := httptest.NewRecorder()
 
 	providerAPIServer := &WebhookServer{
diff --git a/provider/webhook/webhook_test.go b/provider/webhook/webhook_test.go
index 999cdc3b..f4a0ea39 100644
--- a/provider/webhook/webhook_test.go
+++ b/provider/webhook/webhook_test.go
@@ -22,8 +22,11 @@ import (
 	"io"
 	"net/http"
 	"net/http/httptest"
+	"net/url"
 	"testing"
+	"time"
 
+	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 	"sigs.k8s.io/external-dns/endpoint"
 	"sigs.k8s.io/external-dns/plan"
@@ -31,6 +34,55 @@ import (
 	webhookapi "sigs.k8s.io/external-dns/provider/webhook/api"
 )
 
+func TestNewWebhookProvider_InvalidURL(t *testing.T) {
+	_, err := NewWebhookProvider("://invalid-url")
+	require.Error(t, err)
+}
+
+func TestNewWebhookProvider_HTTPRequestFailure(t *testing.T) {
+	_, err := NewWebhookProvider("http://nonexistent.url")
+	require.Error(t, err)
+}
+
+func TestNewWebhookProvider_InvalidResponseBody(t *testing.T) {
+	svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set(webhookapi.ContentTypeHeader, webhookapi.MediaTypeFormatAndVersion)
+		w.WriteHeader(http.StatusOK)
+		w.Write([]byte("invalid-json")) // Invalid JSON
+	}))
+	defer svr.Close()
+
+	_, err := NewWebhookProvider(svr.URL)
+	require.Error(t, err)
+	require.Contains(t, err.Error(), "failed to unmarshal response body of DomainFilter")
+}
+
+func TestNewWebhookProvider_Non2XXStatusCode(t *testing.T) {
+	svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.WriteHeader(http.StatusBadRequest)
+	}))
+	defer svr.Close()
+
+	_, err := NewWebhookProvider(svr.URL)
+	require.Error(t, err)
+	require.Contains(t, err.Error(), "status code < 500")
+}
+
+func TestNewWebhookProvider_WrongContentTypeHeader(t *testing.T) {
+	svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		if r.URL.Path == "/" {
+			w.Header().Set(webhookapi.ContentTypeHeader, webhookapi.MediaTypeFormatAndVersion+"wrong")
+			_, _ = w.Write([]byte(`{}`))
+			return
+		}
+	}))
+	defer svr.Close()
+
+	_, err := NewWebhookProvider(svr.URL)
+	require.Error(t, err)
+	require.Contains(t, err.Error(), "wrong content type returned from server")
+}
+
 func TestInvalidDomainFilter(t *testing.T) {
 	svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		if r.URL.Path == "/" {
@@ -108,6 +160,68 @@ func TestRecordsWithErrors(t *testing.T) {
 	require.ErrorIs(t, err, provider.SoftError)
 }
 
+func TestRecords_HTTPRequestErrorMissingHost0(t *testing.T) {
+	wpr := WebhookProvider{
+		remoteServerURL: &url.URL{Scheme: "http", Host: "example\\x00.com", Path: "\\x00"},
+		client:          &http.Client{},
+	}
+
+	_, err := wpr.Records(nil)
+	require.Error(t, err)
+	require.Contains(t, err.Error(), "invalid URL escape")
+}
+
+func TestRecords_HTTPRequestErrorMissingHost(t *testing.T) {
+	wpr := WebhookProvider{
+		remoteServerURL: &url.URL{Host: "example.com", Path: "\\x00"},
+		client:          &http.Client{},
+	}
+
+	_, err := wpr.Records(nil)
+	require.Error(t, err)
+	require.Contains(t, err.Error(), "unsupported protocol scheme")
+}
+
+func TestRecords_DecodeError(t *testing.T) {
+	svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		if r.URL.Path == webhookapi.UrlRecords {
+			w.WriteHeader(http.StatusOK)
+			_, _ = w.Write([]byte("invalid-json")) // Simulate invalid JSON response
+			return
+		}
+	}))
+	defer svr.Close()
+
+	parsedURL, _ := url.Parse(svr.URL)
+	p := WebhookProvider{
+		remoteServerURL: parsedURL,
+		client:          &http.Client{},
+	}
+
+	_, err := p.Records(context.Background())
+	require.Error(t, err)
+	require.Contains(t, err.Error(), "invalid character 'i' looking for beginning of value")
+}
+
+func TestRecords_NonOKStatusCode(t *testing.T) {
+	svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.WriteHeader(http.StatusNetworkAuthenticationRequired)
+		return
+	}))
+	defer svr.Close()
+
+	parsedURL, _ := url.Parse(svr.URL)
+
+	p := WebhookProvider{
+		remoteServerURL: &url.URL{Scheme: parsedURL.Scheme, Host: parsedURL.Host},
+		client:          &http.Client{},
+	}
+
+	_, err := p.Records(nil)
+	require.Error(t, err)
+	assert.Contains(t, err.Error(), "failed to get records with code 511")
+}
+
 func TestApplyChanges(t *testing.T) {
 	successfulApplyChanges := true
 	svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -137,6 +251,49 @@ func TestApplyChanges(t *testing.T) {
 	require.ErrorIs(t, err, provider.SoftError)
 }
 
+func TestApplyChanges_HTTPNewRequestErrorWrongHost(t *testing.T) {
+	wpr := WebhookProvider{
+		remoteServerURL: &url.URL{Host: "exa\\x00mple.com"},
+		client:          &http.Client{},
+	}
+
+	err := wpr.ApplyChanges(context.Background(), nil)
+	require.Error(t, err)
+	require.Contains(t, err.Error(), "invalid URL escape")
+}
+
+func TestApplyChanges_GetFailed(t *testing.T) {
+	p := WebhookProvider{
+		remoteServerURL: &url.URL{Host: "localhost"},
+		client:          &http.Client{},
+	}
+
+	err := p.ApplyChanges(context.TODO(), &plan.Changes{})
+	require.Error(t, err)
+	assert.Contains(t, err.Error(), "unsupported protocol scheme")
+}
+
+func TestApplyChanges_StatusCodeError(t *testing.T) {
+	svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		if r.URL.Path == "/" {
+			w.Header().Set(webhookapi.ContentTypeHeader, webhookapi.MediaTypeFormatAndVersion)
+			w.Write([]byte(`{}`))
+			return
+		}
+		require.Equal(t, webhookapi.UrlRecords, r.URL.Path)
+		w.WriteHeader(http.StatusNetworkAuthenticationRequired)
+	}))
+	defer svr.Close()
+
+	p, err := NewWebhookProvider(svr.URL)
+	require.NoError(t, err)
+
+	err = p.ApplyChanges(context.TODO(), nil)
+	require.NotNil(t, err)
+	require.NotErrorIs(t, err, provider.SoftError)
+	assert.Contains(t, err.Error(), "failed to apply changes with code 511")
+}
+
 func TestAdjustEndpoints(t *testing.T) {
 	svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		if r.URL.Path == "/" {
@@ -144,7 +301,7 @@ func TestAdjustEndpoints(t *testing.T) {
 			w.Write([]byte(`{}`))
 			return
 		}
-		require.Equal(t, "/adjustendpoints", r.URL.Path)
+		require.Equal(t, webhookapi.UrlAdjustEndpoints, r.URL.Path)
 
 		var endpoints []*endpoint.Endpoint
 		defer r.Body.Close()
@@ -162,7 +319,6 @@ func TestAdjustEndpoints(t *testing.T) {
 		}
 		j, _ := json.Marshal(endpoints)
 		w.Write(j)
-
 	}))
 	defer svr.Close()
 
@@ -197,7 +353,7 @@ func TestAdjustendpointsWithError(t *testing.T) {
 			w.Write([]byte(`{}`))
 			return
 		}
-		require.Equal(t, "/adjustendpoints", r.URL.Path)
+		require.Equal(t, webhookapi.UrlAdjustEndpoints, r.URL.Path)
 		w.WriteHeader(http.StatusInternalServerError)
 	}))
 	defer svr.Close()
@@ -269,3 +425,108 @@ func TestApplyChangesWithProviderSpecificProperty(t *testing.T) {
 	})
 	require.NoError(t, err)
 }
+
+func TestAdjustEndpoints_JoinPathError(t *testing.T) {
+	wpr := WebhookProvider{
+		remoteServerURL: &url.URL{Scheme: "http", Host: "example\\x00.com"},
+	}
+
+	_, err := wpr.AdjustEndpoints(nil)
+	require.Error(t, err)
+	require.Contains(t, err.Error(), "invalid URL escape")
+}
+
+func TestAdjustEndpoints_HTTPRequestErrorMissingHost(t *testing.T) {
+	wpr := WebhookProvider{
+		remoteServerURL: &url.URL{Host: "example.com", Path: "\\x00"},
+		client:          &http.Client{},
+	}
+
+	_, err := wpr.AdjustEndpoints(nil)
+	require.Error(t, err)
+	require.Contains(t, err.Error(), "unsupported protocol scheme") // Ensure the "BINGO" log is triggered
+}
+
+func TestAdjustEndpoints_NonOKStatusCode(t *testing.T) {
+	svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.WriteHeader(http.StatusNetworkAuthenticationRequired)
+		return
+	}))
+	defer svr.Close()
+
+	parsedURL, _ := url.Parse(svr.URL)
+
+	p := WebhookProvider{
+		remoteServerURL: &url.URL{Scheme: parsedURL.Scheme, Host: parsedURL.Host},
+		client:          &http.Client{},
+	}
+
+	endpoints := []*endpoint.Endpoint{
+		{
+			DNSName:    "test.example.com",
+			RecordTTL:  10,
+			RecordType: "A",
+			Targets:    endpoint.Targets{""},
+		},
+	}
+
+	_, err := p.AdjustEndpoints(endpoints)
+	require.Error(t, err)
+	assert.Contains(t, err.Error(), "failed to AdjustEndpoints with code  511")
+}
+
+func TestAdjustEndpoints_DecodeError(t *testing.T) {
+	svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		if r.URL.Path == webhookapi.UrlAdjustEndpoints {
+			w.Header().Set(webhookapi.ContentTypeHeader, webhookapi.MediaTypeFormatAndVersion)
+			w.WriteHeader(http.StatusOK)
+			_, _ = w.Write([]byte("invalid-json")) // Simulate invalid JSON response
+			return
+		}
+	}))
+	defer svr.Close()
+
+	parsedURL, _ := url.Parse(svr.URL)
+	p := WebhookProvider{
+		remoteServerURL: parsedURL,
+		client:          &http.Client{},
+	}
+
+	var endpoints []*endpoint.Endpoint
+
+	_, err := p.AdjustEndpoints(endpoints)
+	require.Error(t, err)
+	require.Contains(t, err.Error(), "invalid character 'i' looking for beginning of value")
+}
+
+func TestRequestWithRetry_Success(t *testing.T) {
+	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.WriteHeader(http.StatusOK)
+		io.WriteString(w, "ok")
+	}))
+	defer server.Close()
+
+	client := &http.Client{Timeout: 2 * time.Second}
+	req, err := http.NewRequest(http.MethodGet, server.URL, nil)
+	require.NoError(t, err)
+
+	resp, err := requestWithRetry(client, req)
+	require.NoError(t, err)
+	require.NotNil(t, resp)
+	require.Equal(t, http.StatusOK, resp.StatusCode)
+}
+
+func TestRequestWithRetry_NonRetriableStatus(t *testing.T) {
+	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.WriteHeader(http.StatusBadRequest)
+	}))
+	defer server.Close()
+
+	client := &http.Client{Timeout: 2 * time.Second}
+	req, err := http.NewRequest(http.MethodGet, server.URL, nil)
+	require.NoError(t, err)
+
+	resp, err := requestWithRetry(client, req)
+	require.Error(t, err)
+	require.Nil(t, resp)
+}
diff --git a/provider/zonefinder_test.go b/provider/zonefinder_test.go
index 0037edad..8b33f566 100644
--- a/provider/zonefinder_test.go
+++ b/provider/zonefinder_test.go
@@ -30,11 +30,15 @@ func TestZoneIDName(t *testing.T) {
 	z.Add("123456", "qux.baz")
 	z.Add("654321", "foo.qux.baz")
 	z.Add("987654", "エイミー.みんな")
+	z.Add("123123", "_metadata.example.com")
+	z.Add("456456", "_metadata.エイミー.みんな")
 
 	assert.Equal(t, ZoneIDName{
 		"123456": "qux.baz",
 		"654321": "foo.qux.baz",
 		"987654": "エイミー.みんな",
+		"123123": "_metadata.example.com",
+		"456456": "_metadata.エイミー.みんな",
 	}, z)
 
 	// simple entry in a domain
@@ -73,6 +77,6 @@ func TestZoneIDName(t *testing.T) {
 	assert.Equal(t, "987654", zoneID)
 
 	b := testutils.LogsToBuffer(log.WarnLevel, t)
-	zoneID, zoneName = z.FindZone("???")
-	assert.Contains(t, b.String(), "level=warning msg=\"Failed to convert hostname '???' to its Unicode form: idna: disallowed rune U+003F\"")
+	_, _ = z.FindZone("???")
+	assert.Contains(t, b.String(), "level=warning msg=\"Failed to convert label '???' of hostname '???' to its Unicode form: idna: disallowed rune U+003F\"")
 }
diff --git a/source/contour_httpproxy_test.go b/source/contour_httpproxy_test.go
index 895adeaa..f26afdcd 100644
--- a/source/contour_httpproxy_test.go
+++ b/source/contour_httpproxy_test.go
@@ -18,11 +18,11 @@ package source
 
 import (
 	"context"
+	"errors"
 	"testing"
 
 	fakeDynamic "k8s.io/client-go/dynamic/fake"
 
-	"github.com/pkg/errors"
 	projectcontour "github.com/projectcontour/contour/apis/projectcontour/v1"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
diff --git a/source/gateway_grpcroute_test.go b/source/gateway_grpcroute_test.go
index f92070eb..a794c379 100644
--- a/source/gateway_grpcroute_test.go
+++ b/source/gateway_grpcroute_test.go
@@ -74,6 +74,11 @@ func TestGatewayGRPCRouteSourceEndpoints(t *testing.T) {
 		},
 		Spec: v1.GRPCRouteSpec{
 			Hostnames: []v1.Hostname{"api-hostnames.foobar.internal"},
+			CommonRouteSpec: v1.CommonRouteSpec{
+				ParentRefs: []v1.ParentReference{
+					gwParentRef("default", "internal"),
+				},
+			},
 		},
 		Status: v1.GRPCRouteStatus{
 			RouteStatus: gwRouteStatus(gwParentRef("default", "internal")),
diff --git a/source/gateway_httproute_test.go b/source/gateway_httproute_test.go
index 629a9e58..19f009fb 100644
--- a/source/gateway_httproute_test.go
+++ b/source/gateway_httproute_test.go
@@ -17,7 +17,6 @@ limitations under the License.
 package source
 
 import (
-	"bytes"
 	"context"
 	"testing"
 
@@ -174,6 +173,12 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 				ObjectMeta: objectMeta("route-namespace", "test"),
 				Spec: v1.HTTPRouteSpec{
 					Hostnames: hostnames("test.example.internal"),
+					CommonRouteSpec: v1.CommonRouteSpec{
+						ParentRefs: []v1.ParentReference{
+							gwParentRef("gateway-namespace", "gateway-name"),
+							gwParentRef("gateway-namespace", "not-gateway-name"),
+						},
+					},
 				},
 				Status: httpRouteStatus( // The route is attached to both gateways.
 					gwParentRef("gateway-namespace", "gateway-name"),
@@ -216,6 +221,12 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 				ObjectMeta: objectMeta("route-namespace", "test"),
 				Spec: v1.HTTPRouteSpec{
 					Hostnames: hostnames("test.example.internal"),
+					CommonRouteSpec: v1.CommonRouteSpec{
+						ParentRefs: []v1.ParentReference{
+							gwParentRef("gateway-namespace", "test"),
+							gwParentRef("not-gateway-namespace", "test"),
+						},
+					},
 				},
 				Status: httpRouteStatus( // The route is attached to both gateways.
 					gwParentRef("gateway-namespace", "test"),
@@ -247,6 +258,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 					ObjectMeta: objectMeta("route-namespace", "test"),
 					Spec: v1.HTTPRouteSpec{
 						Hostnames: hostnames("route-namespace.example.internal"),
+						CommonRouteSpec: v1.CommonRouteSpec{
+							ParentRefs: []v1.ParentReference{
+								gwParentRef("gateway-namespace", "test"),
+							},
+						},
 					},
 					Status: httpRouteStatus(gwParentRef("gateway-namespace", "test")),
 				},
@@ -296,6 +312,12 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 				ObjectMeta: objectMeta("default", "test"),
 				Spec: v1.HTTPRouteSpec{
 					Hostnames: hostnames("test.example.internal"),
+					CommonRouteSpec: v1.CommonRouteSpec{
+						ParentRefs: []v1.ParentReference{
+							gwParentRef("default", "labels-match"),
+							gwParentRef("default", "labels-dont-match"),
+						},
+					},
 				},
 				Status: httpRouteStatus( // The route is attached to both gateways.
 					gwParentRef("default", "labels-match"),
@@ -328,6 +350,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 					},
 					Spec: v1.HTTPRouteSpec{
 						Hostnames: hostnames("labels-match.example.internal"),
+						CommonRouteSpec: v1.CommonRouteSpec{
+							ParentRefs: []v1.ParentReference{
+								gwParentRef("default", "test"),
+							},
+						},
 					},
 					Status: httpRouteStatus(gwParentRef("default", "test")),
 				},
@@ -339,6 +366,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 					},
 					Spec: v1.HTTPRouteSpec{
 						Hostnames: hostnames("labels-dont-match.example.internal"),
+						CommonRouteSpec: v1.CommonRouteSpec{
+							ParentRefs: []v1.ParentReference{
+								gwParentRef("default", "test"),
+							},
+						},
 					},
 					Status: httpRouteStatus(gwParentRef("default", "test")),
 				},
@@ -369,6 +401,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 					},
 					Spec: v1.HTTPRouteSpec{
 						Hostnames: hostnames("annotations-match.example.internal"),
+						CommonRouteSpec: v1.CommonRouteSpec{
+							ParentRefs: []v1.ParentReference{
+								gwParentRef("default", "test"),
+							},
+						},
 					},
 					Status: httpRouteStatus(gwParentRef("default", "test")),
 				},
@@ -380,6 +417,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 					},
 					Spec: v1.HTTPRouteSpec{
 						Hostnames: hostnames("annotations-dont-match.example.internal"),
+						CommonRouteSpec: v1.CommonRouteSpec{
+							ParentRefs: []v1.ParentReference{
+								gwParentRef("default", "test"),
+							},
+						},
 					},
 					Status: httpRouteStatus(gwParentRef("default", "test")),
 				},
@@ -408,6 +450,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 					},
 				},
 				Spec: v1.HTTPRouteSpec{
+					CommonRouteSpec: v1.CommonRouteSpec{
+						ParentRefs: []v1.ParentReference{
+							gwParentRef("default", "test"),
+						},
+					},
 					Hostnames: hostnames("api.example.internal"),
 				},
 				Status: httpRouteStatus(gwParentRef("default", "test")),
@@ -438,6 +485,12 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 				ObjectMeta: objectMeta("default", "test"),
 				Spec: v1.HTTPRouteSpec{
 					Hostnames: hostnames("test.example.internal"),
+					CommonRouteSpec: v1.CommonRouteSpec{
+						ParentRefs: []v1.ParentReference{
+							gwParentRef("default", "one"),
+							gwParentRef("default", "two"),
+						},
+					},
 				},
 				Status: httpRouteStatus(
 					gwParentRef("default", "one"),
@@ -474,6 +527,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 				ObjectMeta: objectMeta("default", "test"),
 				Spec: v1.HTTPRouteSpec{
 					Hostnames: hostnames("*.example.internal"),
+					CommonRouteSpec: v1.CommonRouteSpec{
+						ParentRefs: []v1.ParentReference{
+							gwParentRef("default", "one"),
+						},
+					},
 				},
 				Status: httpRouteStatus(
 					gwParentRef("default", "one"),
@@ -510,6 +568,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 				ObjectMeta: objectMeta("default", "test"),
 				Spec: v1.HTTPRouteSpec{
 					Hostnames: hostnames("*.example.internal"),
+					CommonRouteSpec: v1.CommonRouteSpec{
+						ParentRefs: []v1.ParentReference{
+							gwParentRef("default", "test", withSectionName("foo")),
+						},
+					},
 				},
 				Status: httpRouteStatus(
 					gwParentRef("default", "test", withSectionName("foo")),
@@ -554,6 +617,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 				ObjectMeta: objectMeta("default", "test"),
 				Spec: v1.HTTPRouteSpec{
 					Hostnames: hostnames("*.example.internal"),
+					CommonRouteSpec: v1.CommonRouteSpec{
+						ParentRefs: []v1.ParentReference{
+							gwParentRef("default", "test", withPortNumber(80)),
+						},
+					},
 				},
 				Status: httpRouteStatus(
 					gwParentRef("default", "test", withPortNumber(80)),
@@ -581,6 +649,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 			routes: []*v1beta1.HTTPRoute{{
 				ObjectMeta: objectMeta("default", "no-hostname"),
 				Spec: v1.HTTPRouteSpec{
+					CommonRouteSpec: v1.CommonRouteSpec{
+						ParentRefs: []v1.ParentReference{
+							gwParentRef("default", "test"),
+						},
+					},
 					Hostnames: []v1.Hostname{
 						"foo.example.internal",
 					},
@@ -608,6 +681,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 			routes: []*v1beta1.HTTPRoute{{
 				ObjectMeta: objectMeta("default", "no-hostname"),
 				Spec: v1.HTTPRouteSpec{
+					CommonRouteSpec: v1.CommonRouteSpec{
+						ParentRefs: []v1.ParentReference{
+							gwParentRef("default", "test"),
+						},
+					},
 					Hostnames: []v1.Hostname{
 						"*.example.internal",
 					},
@@ -635,6 +713,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 			routes: []*v1beta1.HTTPRoute{{
 				ObjectMeta: objectMeta("default", "no-hostname"),
 				Spec: v1.HTTPRouteSpec{
+					CommonRouteSpec: v1.CommonRouteSpec{
+						ParentRefs: []v1.ParentReference{
+							gwParentRef("default", "test"),
+						},
+					},
 					Hostnames: []v1.Hostname{
 						"*.example.internal",
 					},
@@ -662,6 +745,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 			routes: []*v1beta1.HTTPRoute{{
 				ObjectMeta: objectMeta("default", "no-hostname"),
 				Spec: v1.HTTPRouteSpec{
+					CommonRouteSpec: v1.CommonRouteSpec{
+						ParentRefs: []v1.ParentReference{
+							gwParentRef("default", "test"),
+						},
+					},
 					Hostnames: nil,
 				},
 				Status: httpRouteStatus(gwParentRef("default", "test")),
@@ -679,6 +767,9 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 				ObjectMeta: objectMeta("default", "test"),
 				Spec: v1.HTTPRouteSpec{
 					Hostnames: hostnames("example.internal"),
+					CommonRouteSpec: v1.CommonRouteSpec{
+						ParentRefs: []v1.ParentReference{},
+					},
 				},
 				Status: httpRouteStatus(),
 			}},
@@ -698,6 +789,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 			routes: []*v1beta1.HTTPRoute{{
 				ObjectMeta: objectMeta("default", "no-hostname"),
 				Spec: v1.HTTPRouteSpec{
+					CommonRouteSpec: v1.CommonRouteSpec{
+						ParentRefs: []v1.ParentReference{
+							gwParentRef("default", "test"),
+						},
+					},
 					Hostnames: nil,
 				},
 				Status: httpRouteStatus(gwParentRef("default", "test")),
@@ -725,6 +821,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 						},
 					},
 					Spec: v1.HTTPRouteSpec{
+						CommonRouteSpec: v1.CommonRouteSpec{
+							ParentRefs: []v1.ParentReference{
+								gwParentRef("default", "test"),
+							},
+						},
 						Hostnames: nil,
 					},
 					Status: httpRouteStatus(gwParentRef("default", "test")),
@@ -738,6 +839,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 						},
 					},
 					Spec: v1.HTTPRouteSpec{
+						CommonRouteSpec: v1.CommonRouteSpec{
+							ParentRefs: []v1.ParentReference{
+								gwParentRef("default", "test"),
+							},
+						},
 						Hostnames: hostnames("with-hostname.internal"),
 					},
 					Status: httpRouteStatus(gwParentRef("default", "test")),
@@ -772,6 +878,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 				},
 				Spec: v1.HTTPRouteSpec{
 					Hostnames: hostnames("with-hostname.internal"),
+					CommonRouteSpec: v1.CommonRouteSpec{
+						ParentRefs: []v1.ParentReference{
+							gwParentRef("default", "test"),
+						},
+					},
 				},
 				Status: httpRouteStatus(gwParentRef("default", "test")),
 			}},
@@ -797,12 +908,22 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 					ObjectMeta: objectMeta("default", "fqdn-with-hostnames"),
 					Spec: v1.HTTPRouteSpec{
 						Hostnames: hostnames("fqdn-with-hostnames.internal"),
+						CommonRouteSpec: v1.CommonRouteSpec{
+							ParentRefs: []v1.ParentReference{
+								gwParentRef("default", "test"),
+							},
+						},
 					},
 					Status: httpRouteStatus(gwParentRef("default", "test")),
 				},
 				{
 					ObjectMeta: objectMeta("default", "fqdn-without-hostnames"),
 					Spec: v1.HTTPRouteSpec{
+						CommonRouteSpec: v1.CommonRouteSpec{
+							ParentRefs: []v1.ParentReference{
+								gwParentRef("default", "test"),
+							},
+						},
 						Hostnames: nil,
 					},
 					Status: httpRouteStatus(gwParentRef("default", "test")),
@@ -832,6 +953,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 			routes: []*v1beta1.HTTPRoute{{
 				ObjectMeta: objectMeta("default", "fqdn-with-hostnames"),
 				Spec: v1.HTTPRouteSpec{
+					CommonRouteSpec: v1.CommonRouteSpec{
+						ParentRefs: []v1.ParentReference{
+							gwParentRef("default", "test"),
+						},
+					},
 					Hostnames: hostnames("fqdn-with-hostnames.internal"),
 				},
 				Status: httpRouteStatus(gwParentRef("default", "test")),
@@ -861,6 +987,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 					},
 					Spec: v1.HTTPRouteSpec{
 						Hostnames: hostnames("valid-ttl.internal"),
+						CommonRouteSpec: v1.CommonRouteSpec{
+							ParentRefs: []v1.ParentReference{
+								gwParentRef("default", "test"),
+							},
+						},
 					},
 					Status: httpRouteStatus(gwParentRef("default", "test")),
 				},
@@ -872,6 +1003,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 					},
 					Spec: v1.HTTPRouteSpec{
 						Hostnames: hostnames("invalid-ttl.internal"),
+						CommonRouteSpec: v1.CommonRouteSpec{
+							ParentRefs: []v1.ParentReference{
+								gwParentRef("default", "test"),
+							},
+						},
 					},
 					Status: httpRouteStatus(gwParentRef("default", "test")),
 				},
@@ -902,6 +1038,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 					},
 				},
 				Spec: v1.HTTPRouteSpec{
+					CommonRouteSpec: v1.CommonRouteSpec{
+						ParentRefs: []v1.ParentReference{
+							gwParentRef("default", "test"),
+						},
+					},
 					Hostnames: hostnames("provider-annotations.com"),
 				},
 				Status: httpRouteStatus(gwParentRef("default", "test")),
@@ -941,6 +1082,12 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 			routes: []*v1beta1.HTTPRoute{{
 				ObjectMeta: objectMeta("default", "test"),
 				Spec: v1.HTTPRouteSpec{
+					CommonRouteSpec: v1.CommonRouteSpec{
+						ParentRefs: []v1.ParentReference{
+							gwParentRef("default", "one"),
+							gwParentRef("default", "two"),
+						},
+					},
 					Hostnames: hostnames("test.one.internal", "test.two.internal"),
 				},
 				Status: httpRouteStatus(
@@ -976,6 +1123,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 					ObjectMeta: objectMeta("same-namespace", "test"),
 					Spec: v1.HTTPRouteSpec{
 						Hostnames: hostnames("same-namespace.example.internal"),
+						CommonRouteSpec: v1.CommonRouteSpec{
+							ParentRefs: []v1.ParentReference{
+								gwParentRef("same-namespace", "test"),
+							},
+						},
 					},
 					Status: httpRouteStatus(gwParentRef("same-namespace", "test")),
 				},
@@ -983,6 +1135,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 					ObjectMeta: objectMeta("other-namespace", "test"),
 					Spec: v1.HTTPRouteSpec{
 						Hostnames: hostnames("other-namespace.example.internal"),
+						CommonRouteSpec: v1.CommonRouteSpec{
+							ParentRefs: []v1.ParentReference{
+								gwParentRef("same-namespace", "test"),
+							},
+						},
 					},
 					Status: httpRouteStatus(gwParentRef("same-namespace", "test")),
 				},
@@ -1035,6 +1192,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 					ObjectMeta: objectMeta("foo", "test"),
 					Spec: v1.HTTPRouteSpec{
 						Hostnames: hostnames("foo.example.internal"),
+						CommonRouteSpec: v1.CommonRouteSpec{
+							ParentRefs: []v1.ParentReference{
+								gwParentRef("default", "test"),
+							},
+						},
 					},
 					Status: httpRouteStatus(gwParentRef("default", "test")),
 				},
@@ -1042,6 +1204,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 					ObjectMeta: objectMeta("bar", "test"),
 					Spec: v1.HTTPRouteSpec{
 						Hostnames: hostnames("bar.example.internal"),
+						CommonRouteSpec: v1.CommonRouteSpec{
+							ParentRefs: []v1.ParentReference{
+								gwParentRef("default", "test"),
+							},
+						},
 					},
 					Status: httpRouteStatus(gwParentRef("default", "test")),
 				},
@@ -1075,6 +1242,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 			routes: []*v1beta1.HTTPRoute{{
 				ObjectMeta: objectMeta("default", "test"),
 				Spec: v1.HTTPRouteSpec{
+					CommonRouteSpec: v1.CommonRouteSpec{
+						ParentRefs: []v1.ParentReference{
+							gwParentRef("default", "test"),
+						},
+					},
 					Hostnames: hostnames("example.internal"),
 				},
 				Status: httpRouteStatus(gwParentRef("default", "test")),
@@ -1109,6 +1281,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 				ObjectMeta: objectMeta("route-namespace", "test"),
 				Spec: v1.HTTPRouteSpec{
 					Hostnames: hostnames("test.example.internal"),
+					CommonRouteSpec: v1.CommonRouteSpec{
+						ParentRefs: []v1.ParentReference{
+							gwParentRef("gateway-namespace", "overriden-gateway"),
+						},
+					},
 				},
 				Status: httpRouteStatus( // The route is attached to both gateways.
 					gwParentRef("gateway-namespace", "overriden-gateway"),
@@ -1156,8 +1333,14 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 				ObjectMeta: objectMeta("route-namespace", "test"),
 				Spec: v1.HTTPRouteSpec{
 					Hostnames: hostnames("test.example.internal"),
+					CommonRouteSpec: v1.CommonRouteSpec{
+						ParentRefs: []v1.ParentReference{
+							gwParentRef("gateway-namespace", "overriden-gateway"),
+							gwParentRef("gateway-namespace", "test"),
+						},
+					},
 				},
-				Status: httpRouteStatus( // The route is attached to both gateways.
+				Status: httpRouteStatus(
 					gwParentRef("gateway-namespace", "overriden-gateway"),
 					gwParentRef("gateway-namespace", "test"),
 				),
@@ -1191,6 +1374,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 					ObjectMeta: objectMeta("default", "one"),
 					Spec: v1.HTTPRouteSpec{
 						Hostnames: hostnames("test.one.internal"),
+						CommonRouteSpec: v1.CommonRouteSpec{
+							ParentRefs: []v1.ParentReference{
+								gwParentRef("default", "one"),
+							},
+						},
 					},
 					Status: httpRouteStatus(
 						gwParentRef("default", "one"),
@@ -1200,6 +1388,11 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 					ObjectMeta: objectMeta("default", "two"),
 					Spec: v1.HTTPRouteSpec{
 						Hostnames: hostnames("test.two.internal"),
+						CommonRouteSpec: v1.CommonRouteSpec{
+							ParentRefs: []v1.ParentReference{
+								gwParentRef("default", "two"),
+							},
+						},
 					},
 					Status: httpRouteStatus(
 						gwParentRef("default", "two"),
@@ -1215,6 +1408,71 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 				"level=debug msg=\"Endpoints generated from HTTPRoute default/two: [test.two.internal 0 IN A  2.3.4.5 []]\"",
 			},
 		},
+		{
+			title: "NoParentRefs",
+			config: Config{
+				GatewayNamespace: "gateway-namespace",
+			},
+			namespaces: namespaces("gateway-namespace", "route-namespace"),
+			gateways: []*v1beta1.Gateway{
+				{
+					ObjectMeta: objectMeta("gateway-namespace", "test"),
+					Spec: v1.GatewaySpec{
+						Listeners: []v1.Listener{{
+							Protocol:      v1.HTTPProtocolType,
+							AllowedRoutes: allowAllNamespaces,
+						}},
+					},
+					Status: gatewayStatus("1.2.3.4"),
+				},
+			},
+			routes: []*v1beta1.HTTPRoute{{
+				ObjectMeta: objectMeta("route-namespace", "test"),
+				Spec: v1.HTTPRouteSpec{
+					Hostnames: hostnames("test.example.internal"),
+				},
+				Status: httpRouteStatus(gwParentRef("gateway-namespace", "test")),
+			}},
+			endpoints: []*endpoint.Endpoint{},
+			logExpectations: []string{
+				"level=debug msg=\"No parent references found for HTTPRoute route-namespace/test\"",
+			},
+		},
+		{
+			title: "ParentRefsMismatch",
+			config: Config{
+				GatewayNamespace: "gateway-namespace",
+			},
+			namespaces: namespaces("gateway-namespace", "route-namespace"),
+			gateways: []*v1beta1.Gateway{
+				{
+					ObjectMeta: objectMeta("gateway-namespace", "test"),
+					Spec: v1.GatewaySpec{
+						Listeners: []v1.Listener{{
+							Protocol:      v1.HTTPProtocolType,
+							AllowedRoutes: allowAllNamespaces,
+						}},
+					},
+					Status: gatewayStatus("1.2.3.4"),
+				},
+			},
+			routes: []*v1beta1.HTTPRoute{{
+				ObjectMeta: objectMeta("route-namespace", "test"),
+				Spec: v1.HTTPRouteSpec{
+					Hostnames: hostnames("test.example.internal"),
+					CommonRouteSpec: v1.CommonRouteSpec{
+						ParentRefs: []v1.ParentReference{
+							gwParentRef("gateway-namespace", "default-gateway"),
+						},
+					},
+				},
+				Status: httpRouteStatus(gwParentRef("gateway-namespace", "other-gateway")),
+			}},
+			endpoints: []*endpoint.Endpoint{},
+			logExpectations: []string{
+				"level=debug msg=\"Parent reference gateway-namespace/other-gateway not found in routeParentRefs for HTTPRoute route-namespace/test\"",
+			},
+		},
 	}
 	for _, tt := range tests {
 		tt := tt
@@ -1247,10 +1505,8 @@ func TestGatewayHTTPRouteSourceEndpoints(t *testing.T) {
 			src, err := NewGatewayHTTPRouteSource(clients, &tt.config)
 			require.NoError(t, err, "failed to create Gateway HTTPRoute Source")
 
-			var b *bytes.Buffer
-			if len(tt.logExpectations) > 0 {
-				b = testutils.LogsToBuffer(log.DebugLevel, t)
-			}
+			b := testutils.LogsToBuffer(log.DebugLevel, t)
+
 			endpoints, err := src.Endpoints(ctx)
 			require.NoError(t, err, "failed to get Endpoints")
 			validateEndpoints(t, endpoints, tt.endpoints)
diff --git a/source/gateway_tcproute_test.go b/source/gateway_tcproute_test.go
index a6039ebf..417ac788 100644
--- a/source/gateway_tcproute_test.go
+++ b/source/gateway_tcproute_test.go
@@ -73,7 +73,13 @@ func TestGatewayTCPRouteSourceEndpoints(t *testing.T) {
 				hostnameAnnotationKey: "api-annotation.foobar.internal",
 			},
 		},
-		Spec: v1alpha2.TCPRouteSpec{},
+		Spec: v1alpha2.TCPRouteSpec{
+			CommonRouteSpec: v1.CommonRouteSpec{
+				ParentRefs: []v1.ParentReference{
+					gwParentRef("default", "internal"),
+				},
+			},
+		},
 		Status: v1alpha2.TCPRouteStatus{
 			RouteStatus: gwRouteStatus(gwParentRef("default", "internal")),
 		},
diff --git a/source/gateway_tlsroute_test.go b/source/gateway_tlsroute_test.go
index e6d4660e..238b6259 100644
--- a/source/gateway_tlsroute_test.go
+++ b/source/gateway_tlsroute_test.go
@@ -75,6 +75,11 @@ func TestGatewayTLSRouteSourceEndpoints(t *testing.T) {
 		},
 		Spec: v1alpha2.TLSRouteSpec{
 			Hostnames: []v1.Hostname{"api-hostnames.foobar.internal"},
+			CommonRouteSpec: v1.CommonRouteSpec{
+				ParentRefs: []v1.ParentReference{
+					gwParentRef("default", "internal"),
+				},
+			},
 		},
 		Status: v1alpha2.TLSRouteStatus{
 			RouteStatus: gwRouteStatus(gwParentRef("default", "internal")),
diff --git a/source/gateway_udproute_test.go b/source/gateway_udproute_test.go
index 570e3d10..161de45f 100644
--- a/source/gateway_udproute_test.go
+++ b/source/gateway_udproute_test.go
@@ -73,7 +73,13 @@ func TestGatewayUDPRouteSourceEndpoints(t *testing.T) {
 				hostnameAnnotationKey: "api-annotation.foobar.internal",
 			},
 		},
-		Spec: v1alpha2.UDPRouteSpec{},
+		Spec: v1alpha2.UDPRouteSpec{
+			CommonRouteSpec: v1.CommonRouteSpec{
+				ParentRefs: []v1.ParentReference{
+					gwParentRef("default", "internal"),
+				},
+			},
+		},
 		Status: v1alpha2.UDPRouteStatus{
 			RouteStatus: gwRouteStatus(gwParentRef("default", "internal")),
 		},
diff --git a/source/istio_gateway_test.go b/source/istio_gateway_test.go
index 9c74d7a7..43120ff3 100644
--- a/source/istio_gateway_test.go
+++ b/source/istio_gateway_test.go
@@ -18,9 +18,9 @@ package source
 
 import (
 	"context"
+	"errors"
 	"testing"
 
-	"github.com/pkg/errors"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 	"github.com/stretchr/testify/suite"
diff --git a/source/istio_virtualservice_test.go b/source/istio_virtualservice_test.go
index c56dce70..32482781 100644
--- a/source/istio_virtualservice_test.go
+++ b/source/istio_virtualservice_test.go
@@ -18,10 +18,10 @@ package source
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"testing"
 
-	"github.com/pkg/errors"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 	"github.com/stretchr/testify/suite"
diff --git a/source/node_test.go b/source/node_test.go
index c944c640..9746bbab 100644
--- a/source/node_test.go
+++ b/source/node_test.go
@@ -83,6 +83,7 @@ func testNodeSourceNewNodeSource(t *testing.T) {
 				ti.fqdnTemplate,
 				labels.Everything(),
 				true,
+				true,
 			)
 
 			if ti.expectError {
@@ -96,21 +97,22 @@ func testNodeSourceNewNodeSource(t *testing.T) {
 
 // testNodeSourceEndpoints tests that various node generate the correct endpoints.
 func testNodeSourceEndpoints(t *testing.T) {
-	t.Parallel()
-
 	for _, tc := range []struct {
-		title              string
-		annotationFilter   string
-		labelSelector      string
-		fqdnTemplate       string
-		nodeName           string
-		nodeAddresses      []v1.NodeAddress
-		labels             map[string]string
-		annotations        map[string]string
-		exposeInternalIPv6 bool // default to true for this version. Change later when the next minor version is released.
-		unschedulable      bool // default to false
-		expected           []*endpoint.Endpoint
-		expectError        bool
+		title                string
+		annotationFilter     string
+		labelSelector        string
+		fqdnTemplate         string
+		nodeName             string
+		nodeAddresses        []v1.NodeAddress
+		labels               map[string]string
+		annotations          map[string]string
+		excludeUnschedulable bool // default to false
+		exposeInternalIPv6   bool // default to true for this version. Change later when the next minor version is released.
+		unschedulable        bool // default to false
+		expected             []*endpoint.Endpoint
+		expectError          bool
+		expectedLogs         []string
+		expectedAbsentLogs   []string
 	}{
 		{
 			title:              "node with short hostname returns one endpoint",
@@ -363,16 +365,34 @@ func testNodeSourceEndpoints(t *testing.T) {
 			},
 		},
 		{
-			title:              "unschedulable node return nothing",
-			nodeName:           "node1",
-			exposeInternalIPv6: true,
-			nodeAddresses:      []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}},
-			unschedulable:      true,
-			expected:           []*endpoint.Endpoint{},
+			title:                "unschedulable node return nothing with excludeUnschedulable=true",
+			nodeName:             "node1",
+			exposeInternalIPv6:   true,
+			nodeAddresses:        []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}},
+			unschedulable:        true,
+			excludeUnschedulable: true,
+			expected:             []*endpoint.Endpoint{},
+			expectedLogs: []string{
+				"Skipping node node1 because it is unschedulable",
+			},
+		},
+		{
+			title:                "unschedulable node returns node with excludeUnschedulable=false",
+			nodeName:             "node1",
+			nodeAddresses:        []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}},
+			unschedulable:        true,
+			excludeUnschedulable: false,
+			expected: []*endpoint.Endpoint{
+				{RecordType: "A", DNSName: "node1", Targets: endpoint.Targets{"1.2.3.4"}},
+			},
+			expectedAbsentLogs: []string{
+				"Skipping node node1 because it is unschedulable",
+			},
 		},
 	} {
-		tc := tc
 		t.Run(tc.title, func(t *testing.T) {
+			buf := testutils.LogsToBuffer(log.DebugLevel, t)
+
 			labelSelector := labels.Everything()
 			if tc.labelSelector != "" {
 				var err error
@@ -408,6 +428,7 @@ func testNodeSourceEndpoints(t *testing.T) {
 				tc.fqdnTemplate,
 				labelSelector,
 				tc.exposeInternalIPv6,
+				tc.excludeUnschedulable,
 			)
 			require.NoError(t, err)
 
@@ -420,24 +441,33 @@ func testNodeSourceEndpoints(t *testing.T) {
 
 			// Validate returned endpoints against desired endpoints.
 			validateEndpoints(t, endpoints, tc.expected)
+
+			for _, entry := range tc.expectedLogs {
+				assert.Contains(t, buf.String(), entry)
+			}
+
+			for _, entry := range tc.expectedAbsentLogs {
+				assert.NotContains(t, buf.String(), entry)
+			}
 		})
 	}
 }
 
 func testNodeEndpointsWithIPv6(t *testing.T) {
 	for _, tc := range []struct {
-		title              string
-		annotationFilter   string
-		labelSelector      string
-		fqdnTemplate       string
-		nodeName           string
-		nodeAddresses      []v1.NodeAddress
-		labels             map[string]string
-		annotations        map[string]string
-		exposeInternalIPv6 bool // default to true for this version. Change later when the next minor version is released.
-		unschedulable      bool // default to false
-		expected           []*endpoint.Endpoint
-		expectError        bool
+		title                string
+		annotationFilter     string
+		labelSelector        string
+		fqdnTemplate         string
+		nodeName             string
+		nodeAddresses        []v1.NodeAddress
+		labels               map[string]string
+		annotations          map[string]string
+		excludeUnschedulable bool // defaults to false
+		exposeInternalIPv6   bool // default to true for this version. Change later when the next minor version is released.
+		unschedulable        bool // default to false
+		expected             []*endpoint.Endpoint
+		expectError          bool
 	}{
 		{
 			title:              "node with only internal IPs should return internal IPvs irrespective of exposeInternalIPv6",
@@ -516,6 +546,7 @@ func testNodeEndpointsWithIPv6(t *testing.T) {
 			tc.fqdnTemplate,
 			labelSelector,
 			tc.exposeInternalIPv6,
+			tc.excludeUnschedulable,
 		)
 		require.NoError(t, err)
 
diff --git a/source/skipper_routegroup_test.go b/source/skipper_routegroup_test.go
index 68f70bc4..03650b3a 100644
--- a/source/skipper_routegroup_test.go
+++ b/source/skipper_routegroup_test.go
@@ -18,9 +18,9 @@ package source
 
 import (
 	"context"
+	"errors"
 	"testing"
 
-	"github.com/pkg/errors"
 	"github.com/stretchr/testify/assert"
 	"sigs.k8s.io/external-dns/endpoint"
 )
diff --git a/source/source_test.go b/source/source_test.go
index 154650d4..413995a6 100644
--- a/source/source_test.go
+++ b/source/source_test.go
@@ -174,6 +174,41 @@ func TestGetProviderSpecificCloudflareAnnotations(t *testing.T) {
 			t.Errorf("Cloudflare provider specific annotation %s is not set correctly to %s", tc.expectedKey, tc.expectedValue)
 		})
 	}
+
+	for _, tc := range []struct {
+		title         string
+		annotations   map[string]string
+		expectedKey   string
+		expectedValue string
+	}{
+		{
+			title:         "Cloudflare region key annotation is set correctly",
+			annotations:   map[string]string{CloudflareRegionKey: "us"},
+			expectedKey:   CloudflareRegionKey,
+			expectedValue: "us",
+		},
+		{
+			title: "Cloudflare region key annotation among another annotations is set correctly",
+			annotations: map[string]string{
+				"random annotation 1": "random value 1",
+				CloudflareRegionKey:   "us",
+				"random annotation 2": "random value 2",
+			},
+			expectedKey:   CloudflareRegionKey,
+			expectedValue: "us",
+		},
+	} {
+		t.Run(tc.title, func(t *testing.T) {
+			providerSpecificAnnotations, _ := getProviderSpecificAnnotations(tc.annotations)
+			for _, providerSpecificAnnotation := range providerSpecificAnnotations {
+				if providerSpecificAnnotation.Name == tc.expectedKey {
+					assert.Equal(t, tc.expectedValue, providerSpecificAnnotation.Value)
+					return
+				}
+			}
+			t.Errorf("Cloudflare provider specific annotation %s is not set correctly to %v", tc.expectedKey, tc.expectedValue)
+		})
+	}
 }
 
 func TestGetProviderSpecificAliasAnnotations(t *testing.T) {
diff --git a/source/traefik_proxy_test.go b/source/traefik_proxy_test.go
index 730d833a..88cefb51 100644
--- a/source/traefik_proxy_test.go
+++ b/source/traefik_proxy_test.go
@@ -19,9 +19,10 @@ package source
 import (
 	"context"
 	"encoding/json"
-	"k8s.io/apimachinery/pkg/runtime/schema"
 	"testing"
 
+	"k8s.io/apimachinery/pkg/runtime/schema"
+
 	"github.com/stretchr/testify/assert"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"