Skip to content

feat(cloudflare): support batch API for DNS record changes#6208

Merged
k8s-ci-robot merged 7 commits intokubernetes-sigs:masterfrom
mooseracerPT:mooseracerpt/cloudflare-batch-dns
Mar 12, 2026
Merged

feat(cloudflare): support batch API for DNS record changes#6208
k8s-ci-robot merged 7 commits intokubernetes-sigs:masterfrom
mooseracerPT:mooseracerpt/cloudflare-batch-dns

Conversation

@mooseracerPT
Copy link
Copy Markdown
Contributor

@mooseracerPT mooseracerPT commented Feb 19, 2026

What does it do ?

All Cloudflare record changes are currently propagated via individual API calls, plus a redundant query of the entire zone, per record. With large and/or frequent change sets this will lead to being rate limited. This change is a refactor to instead use Cloudflare's batch API.

I've reduced the number of Cloudflare API calls per sync interval from 3 + 2N to 4 + X, where N is the number of records being changed and X is the number of batches needed. A batch can contain up to 200 records on the free plan and 3500 on paid.

Motivation

external-dns pods getting rate limited and crashing. We run a cluster that has grown to 3000-5000+ records in the zone, with frequent changes of 30-100 records at a time. external-dns is no longer reliably keeping up despite attempts to tweak polling intervals and the max records retrieved.

More

  • Yes, this PR title follows Conventional Commits
  • Yes, I added unit tests
  • Yes, I updated end user documentation accordingly

Batch API Error Handling

Failed batch submissions will result in retrying each change as individual API calls. They'll keep getting retried every sync interval, though batch operations are effectively blocked until the broken config is fixed. This is also how batch failures behave in the Google and AWS providers.

Initial service manifests

apiVersion: v1
kind: Service
metadata:
  name: test-record-cname
  namespace: mynamespace
  labels:
    app: dns-testing
    external-dns/cloudflare: enabled
  annotations:
    external-dns.alpha.kubernetes.io/hostname: cname.example.com
    external-dns.alpha.kubernetes.io/cloudflare-record-comment: "some comment"
spec:
  type: ExternalName
  externalName: somehost.example.com
---
apiVersion: v1
kind: Service
metadata:
  name: test-record-a
  namespace: mynamespace
  labels:
    app: dns-testing
    external-dns/cloudflare: enabled
  annotations:
    external-dns.alpha.kubernetes.io/hostname: a.example.com
    external-dns.alpha.kubernetes.io/target: "203.0.113.40"
spec:
  type: ExternalName
  externalName: somehost.example.com
---
apiVersion: v1
kind: Service
metadata:
  name: test-record-malformed
  namespace: mynamespace
  labels:
    app: dns-testing
    external-dns/cloudflare: enabled
  annotations:
    external-dns.alpha.kubernetes.io/hostname: malformed.example.com
    external-dns.alpha.kubernetes.io/target: "203.0.113.42"
    external-dns.alpha.kubernetes.io/cloudflare-tags: "t01:v01,t02:v02,t03:v03,t04:v04,t05:v05,t06:v06,t07:v07,t08:v08,t09:v09,t10:v10,t11:v11,t12:v12,t13:v13,t14:v14,t15:v15,t16:v16,t17:v17,t18:v18,t19:v19,t20:v20,t21:v21,t22:v22,t23:v23,t24:v24,t25:v25"
spec:
  type: ExternalName
  externalName: somehost.example.com

1.

We expect malformed.example.com to cause a failure. The entire batch set is not applied. fallbackIndividualChanges is invoked and the changes are sent through one-by-one, letting us get a useful error message from the API about what exactly is wrong with which record(s).

time="2026-02-27T00:14:09Z" level=debug msg="Endpoints generated from service: mynamespace/test-record-cname: [cname.example.com 0 IN CNAME  somehost.example.com [{external-dns.alpha.kubernetes.io/cloudflare-record-comment my best comment}]]"
time="2026-02-27T00:14:09Z" level=debug msg="Endpoints generated from service: mynamespace/test-record-malformed: [malformed.example.com 0 IN A  203.0.113.42 [{external-dns.alpha.kubernetes.io/cloudflare-tags t01:v01,t02:v02,t03:v03,t04:v04,t05:v05,t06:v06,t07:v07,t08:v08,t09:v09,t10:v10,t11:v11,t12:v12,t13:v13,t14:v14,t15:v15,t16:v16,t17:v17,t18:v18,t19:v19,t20:v20,t21:v21,t22:v22,t23:v23,t24:v24,t25:v25}]]"
time="2026-02-27T00:14:09Z" level=debug msg="Endpoints generated from service: mynamespace/test-record-a: [a.example.com 0 IN A  203.0.113.40 []]"
time="2026-02-27T00:14:09Z" level=info msg="INSERT dynamodb record \"a.example.com#A#\""
time="2026-02-27T00:14:09Z" level=info msg="INSERT dynamodb record \"cname.example.com#CNAME#\""
time="2026-02-27T00:14:09Z" level=info msg="INSERT dynamodb record \"malformed.example.com#A#\""
time="2026-02-27T00:14:09Z" level=debug msg="zoneIDFilter configured. only looking up zone IDs defined"
time="2026-02-27T00:14:09Z" level=debug msg="looking up zone \"2832m...a9c10\""
time="2026-02-27T00:14:10Z" level=debug msg="adding zone for consideration" zoneID=2832m...a9c10 zoneName=example.com
time="2026-02-27T00:14:10Z" level=info msg="Changing record." action=CREATE record=a.example.com ttl=1 type=A zone=2832m...a9c10
time="2026-02-27T00:14:10Z" level=info msg="Changing record." action=CREATE record=cname.example.com ttl=1 type=CNAME zone=2832m...a9c10
time="2026-02-27T00:14:10Z" level=info msg="Changing record." action=CREATE record=malformed.example.com ttl=1 type=A zone=2832m...a9c10
time="2026-02-27T00:14:30Z" level=debug msg="Submitting batch DNS records for zone 2832m...a9c10 (chunk 1/1): 0 deletes, 3 creates, 0 updates"
time="2026-02-27T00:14:30Z" level=warning msg="Batch DNS operation failed for zone 2832m...a9c10 (chunk 1/1): POST \"https://api.cloudflare.com/client/v4/zones/2832m...a9c10/dns_records/batch\": 400 Bad Request {\"result\":null,\"success\":false,\"errors\":[{\"code\":9300,\"message\":\"failed to POST record with name malformed.example.com and type A. The error was: DNS record has 25 tags, exceeding the quota of 20.\"}],\"messages\":[]} — falling back to individual operations"
time="2026-02-27T00:14:30Z" level=debug msg="fallback: individual CREATE succeeded" action=CREATE content=203.0.113.40 record=a.example.com type=A zone=2832m...a9c10
time="2026-02-27T00:14:31Z" level=debug msg="fallback: individual CREATE succeeded" action=CREATE content=somehost.example.com record=cname.example.com type=CNAME zone=2832m...a9c10
time="2026-02-27T00:14:31Z" level=error msg="fallback: individual CREATE failed: POST \"https://api.cloudflare.com/client/v4/zones/2832m...a9c10/dns_records\": 400 Bad Request {\"result\":null,\"success\":false,\"errors\":[{\"code\":9300,\"message\":\"DNS record has 25 tags, exceeding the quota of 20.\"}],\"messages\":[]}" action=CREATE content=203.0.113.42 record=malformed.example.com type=A zone=2832m...a9c10
time="2026-02-27T00:14:31Z" level=error msg="Failed to do run once: soft error\nfailed to submit all changes for the following zones: [\"2832m...a9c10\"] (consecutive soft errors: 1)"

2.

We make a valid record change but leave the malformed record alone. As long as the malformed record configuration is present batch attempts will continue to fail, but the fallback allows other changes to continue working.

time="2026-02-27T00:17:56Z" level=debug msg="zoneIDFilter configured. only looking up zone IDs defined"
time="2026-02-27T00:17:56Z" level=debug msg="looking up zone \"2832m...a9c10\""
time="2026-02-27T00:17:56Z" level=debug msg="adding zone for consideration" zoneID=2832m...a9c10 zoneName=example.com
time="2026-02-27T00:18:08Z" level=debug msg="dedupSource: collecting endpoints and removing duplicates"
time="2026-02-27T00:18:08Z" level=debug msg="multiSource: collecting endpoints from 2 child sources and removing duplicates"
time="2026-02-27T00:18:08Z" level=debug msg="Endpoints generated from service: mynamespace/test-record-a: [a.example.com 0 IN A  203.0.113.40 []]"
time="2026-02-27T00:18:08Z" level=debug msg="Endpoints generated from service: mynamespace/test-record-cname: [cname.example.com 0 IN CNAME  somehost.example.com [{external-dns.alpha.kubernetes.io/cloudflare-record-comment my worst comment}]]"
time="2026-02-27T00:18:08Z" level=debug msg="Endpoints generated from service: mynamespace/test-record-malformed: [malformed.example.com 0 IN A  203.0.113.42 [{external-dns.alpha.kubernetes.io/cloudflare-tags t01:v01,t02:v02,t03:v03,t04:v04,t05:v05,t06:v06,t07:v07,t08:v08,t09:v09,t10:v10,t11:v11,t12:v12,t13:v13,t14:v14,t15:v15,t16:v16,t17:v17,t18:v18,t19:v19,t20:v20,t21:v21,t22:v22,t23:v23,t24:v24,t25:v25}]]"
time="2026-02-27T00:18:08Z" level=debug msg="zoneIDFilter configured. only looking up zone IDs defined"
time="2026-02-27T00:18:08Z" level=debug msg="looking up zone \"2832m...a9c10\""
time="2026-02-27T00:18:09Z" level=debug msg="adding zone for consideration" zoneID=2832m...a9c10 zoneName=example.com
time="2026-02-27T00:18:09Z" level=info msg="Changing record." action=CREATE record=malformed.example.com ttl=1 type=A zone=2832m...a9c10
time="2026-02-27T00:18:09Z" level=info msg="Changing record." action=UPDATE record=cname.example.com ttl=1 type=CNAME zone=2832m...a9c10
time="2026-02-27T00:18:20Z" level=debug msg="Submitting batch DNS records for zone 2832m...a9c10 (chunk 1/1): 0 deletes, 1 creates, 1 updates"
time="2026-02-27T00:18:20Z" level=warning msg="Batch DNS operation failed for zone 2832m...a9c10 (chunk 1/1): POST \"https://api.cloudflare.com/client/v4/zones/2832m...a9c10/dns_records/batch\": 400 Bad Request {\"result\":null,\"success\":false,\"errors\":[{\"code\":9300,\"message\":\"failed to POST record with name malformed.example.com and type A. The error was: DNS record has 25 tags, exceeding the quota of 20.\"}],\"messages\":[]} — falling back to individual operations"
time="2026-02-27T00:18:20Z" level=debug msg="fallback: individual UPDATE succeeded" action=UPDATE content=somehost.example.com record=cname.example.com type=CNAME zone=2832m...a9c10
time="2026-02-27T00:18:25Z" level=error msg="fallback: individual CREATE failed: POST \"https://api.cloudflare.com/client/v4/zones/2832m...a9c10/dns_records\": 400 Bad Request {\"result\":null,\"success\":false,\"errors\":[{\"code\":9300,\"message\":\"DNS record has 25 tags, exceeding the quota of 20.\"}],\"messages\":[]}" action=CREATE content=203.0.113.42 record=malformed.example.com type=A zone=2832m...a9c10
time="2026-02-27T00:18:25Z" level=error msg="Failed to do run once: soft error\nfailed to submit all changes for the following zones: [\"2832m...a9c10\"] (consecutive soft errors: 1)"

3.

We make another valid record change and also delete the malformed record manifest. Batch succeeds.

time="2026-02-27T00:18:57Z" level=debug msg="zoneIDFilter configured. only looking up zone IDs defined"
time="2026-02-27T00:18:57Z" level=debug msg="looking up zone \"2832m...a9c10\""
time="2026-02-27T00:18:58Z" level=debug msg="adding zone for consideration" zoneID=2832m...a9c10 zoneName=example.com
time="2026-02-27T00:19:09Z" level=debug msg="dedupSource: collecting endpoints and removing duplicates"
time="2026-02-27T00:19:09Z" level=debug msg="multiSource: collecting endpoints from 2 child sources and removing duplicates"
time="2026-02-27T00:19:09Z" level=debug msg="Endpoints generated from service: mynamespace/test-record-cname: [cname.example.com 0 IN CNAME  somehost.example.com [{external-dns.alpha.kubernetes.io/cloudflare-record-comment my best comment}]]"
time="2026-02-27T00:19:09Z" level=debug msg="Endpoints generated from service: mynamespace/test-record-a: [a.example.com 0 IN A  203.0.113.40 []]"
time="2026-02-27T00:19:09Z" level=debug msg="zoneIDFilter configured. only looking up zone IDs defined"
time="2026-02-27T00:19:09Z" level=debug msg="looking up zone \"2832m...a9c10\""
time="2026-02-27T00:19:10Z" level=debug msg="adding zone for consideration" zoneID=2832m...a9c10 zoneName=example.com
time="2026-02-27T00:19:10Z" level=info msg="Changing record." action=UPDATE record=cname.example.com ttl=1 type=CNAME zone=2832m...a9c10
time="2026-02-27T00:19:30Z" level=debug msg="Submitting batch DNS records for zone 2832m...a9c10 (chunk 1/1): 0 deletes, 0 creates, 1 updates"
time="2026-02-27T00:19:30Z" level=debug msg="Successfully submitted batch DNS records for zone 2832m...a9c10 (chunk 1/1)"
time="2026-02-27T00:19:30Z" level=info msg="DELETE dynamodb record \"malformed.example.com#A#\""
time="2026-02-27T00:19:30Z" level=info msg="Reconciliation succeeded after 1 consecutive soft errors"

@k8s-ci-robot k8s-ci-robot added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. provider Issues or PRs related to a provider labels Feb 19, 2026
@linux-foundation-easycla
Copy link
Copy Markdown

linux-foundation-easycla bot commented Feb 19, 2026

CLA Signed

The committers listed above are authorized under a signed CLA.

@k8s-ci-robot
Copy link
Copy Markdown
Contributor

Welcome @mooseracerPT!

It looks like this is your first PR to kubernetes-sigs/external-dns 🎉. Please refer to our pull request process documentation to help your PR have a smooth ride to approval.

You will be prompted by a bot to use commands during the review process. Do not be afraid to follow the prompts! It is okay to experiment. Here is the bot commands documentation.

You can also check if kubernetes-sigs/external-dns has its own contribution guidelines.

You may want to refer to our testing guide if you run into trouble with your tests not passing.

If you are having difficulty getting your pull request seen, please follow the recommended escalation practices. Also, for tips and tricks in the contribution process you may want to read the Kubernetes contributor cheat sheet. We want to make sure your contribution gets all the attention it needs!

Thank you, and welcome to Kubernetes. 😃

@k8s-ci-robot k8s-ci-robot added the needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. label Feb 19, 2026
@k8s-ci-robot
Copy link
Copy Markdown
Contributor

Hi @mooseracerPT. Thanks for your PR.

I'm waiting for a kubernetes-sigs member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@k8s-ci-robot k8s-ci-robot added cncf-cla: no Indicates the PR's author has not signed the CNCF CLA. size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels Feb 19, 2026
@ivankatliarchuk
Copy link
Copy Markdown
Member

ivankatliarchuk commented Feb 20, 2026

I'm not sure about the fix yet. What we should be doing

  1. 1st PR -> Add zone caching chore(provider): zone cache provider interface #6120
  2. 2nd PR -> this pull request, with default (maybe) + new flags --batch-change-size and --batch-change-interval

For all the changes, we expect confirmations of changes working #5085 (comment)

@ivankatliarchuk
Copy link
Copy Markdown
Member

And you need to sing EasyCLA

@vflaux
Copy link
Copy Markdown
Contributor

vflaux commented Feb 22, 2026

How do you handle errors from the API? Last time I tried, the API only returned the first error and did not apply the batch.

@mooseracerPT
Copy link
Copy Markdown
Contributor Author

How do you handle errors from the API? Last time I tried, the API only returned the first error and did not apply the batch.

That's still the case, the entire batch transaction is rolled back and goes in failedZones to be retried next sync. The error response is also vague; you don't get to know which particular record change was problematic.

We could try falling back to individual one-by-one API calls in the event of a failed batch, but it won't be pretty.

I also need to do some more with the chunking logic to handle edge cases where one chunk succeeds but another fails, and they've split multiple operations on the same record(s) between them.

@k8s-ci-robot k8s-ci-robot added cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. and removed cncf-cla: no Indicates the PR's author has not signed the CNCF CLA. labels Feb 23, 2026
@mooseracerPT mooseracerPT force-pushed the mooseracerpt/cloudflare-batch-dns branch from aeab3a7 to 167796d Compare February 25, 2026 02:23
@k8s-ci-robot k8s-ci-robot added apis Issues or PRs related to API change controller Issues or PRs related to the controller docs size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. and removed size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels Feb 25, 2026
@mooseracerPT
Copy link
Copy Markdown
Contributor Author

@ivankatliarchuk / @vflaux I've made some significant changes to prevent a bad record config from blocking updates to the whole zone. And I added the flag for --cloudflare-batch-change-size but not for an interval (the Cloudflare SDK seems like it already handles that kinda thing).

The previous build has been running in my own busy cluster without issue, and I'll promote this one tomorrow.

Copy link
Copy Markdown
Member

@ivankatliarchuk ivankatliarchuk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docs needs a review + --batch-change-interval is required.

Comment thread pkg/apis/externaldns/types_test.go Outdated
Comment thread docs/flags.md Outdated
Comment thread provider/cloudflare/cloudflare_quarantine.go Outdated
@ivankatliarchuk
Copy link
Copy Markdown
Member

/ok-to-test

@k8s-ci-robot k8s-ci-robot added ok-to-test Indicates a non-member PR verified by an org member that is safe to test. and removed needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. labels Feb 25, 2026
@ivankatliarchuk
Copy link
Copy Markdown
Member

Still draft PR

@ivankatliarchuk
Copy link
Copy Markdown
Member

/retitle feat(cloudflare): support batch API for DNS record changes

@k8s-ci-robot k8s-ci-robot changed the title perf(cloudflare): use batch API for DNS record changes feat(cloudflare): support batch API for DNS record changes Feb 25, 2026
@mooseracerPT mooseracerPT marked this pull request as ready for review February 25, 2026 20:57
@k8s-ci-robot k8s-ci-robot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Feb 25, 2026
Comment thread provider/cloudflare/cloudflare_quarantine.go Outdated
Comment thread provider/cloudflare/cloudflare_batch.go Outdated
… flags

Adds two new global CLI flags for controlling batch DNS change behaviour:
- --batch-change-size (default 200): maximum number of DNS operations per batch
- --batch-change-interval (default 1s): pause between consecutive batch chunks

Wires the flags through Config into the Cloudflare provider's DNSRecordsConfig.
…back

Uses Cloudflare's Batch DNS Records API to submit all creates, updates, and
deletes for a zone in a single transactional API call per chunk, significantly
reducing the total number of requests made against the Cloudflare API.

- Batch size and interval are controlled via --batch-change-size / --batch-change-interval
- Record types unsupported by the batch PUT endpoint (e.g. SRV, CAA) are
  submitted individually via the standard API
- If a batch chunk is rejected by Cloudflare, ExternalDNS automatically retries
  each record change in that chunk individually so no changes are silently lost
- Adds cloudflare_batch.go with the core batching logic and full test coverage
@mooseracerPT mooseracerPT force-pushed the mooseracerpt/cloudflare-batch-dns branch from 03e4e71 to 568133f Compare February 26, 2026 23:51
@mooseracerPT
Copy link
Copy Markdown
Contributor Author

@ivankatliarchuk I've removed the quarantine feature and updated the PR comment with the new testing plan + results.

I also snuck in a soft error capture for unexpected EOF as per #3798, as we happened to see two of those this morning from Cloudflare (they're really rare) and that should never be a reason to fatal the pod.

Copy link
Copy Markdown
Member

@ivankatliarchuk ivankatliarchuk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice one. Seems fine. What is missing, for all lines changes we expect code coverage. AI could generate it, or manually does not matter. This will help us in case of bugs or follow up refactorings.

Please execute make cover-html and cover all the lines refactored/modified/added

I did some analysis as well

Most important gaps: The entire fallbackUpdates path (SRV/CAA records) and all buildBatchPutParam type branches except A-record have no tests. These are the most
  logic-heavy uncovered paths.
  ---
  buildBatchPutParam — only the A-record case is tested:
  - Lines 193–218: AAAA and CNAME cases
  - Lines 219–258: TXT, MX, NS cases
  - Lines 259–262: default branch → return nil, false

  buildBatchCollections:
  - Lines 301–303: recordID == "" guard for updates (record not found)
  - Lines 308–310: bc.fallbackUpdates = append(...) — the SRV/CAA fallback path

  submitDNSRecordChanges:
  - Lines 348–350: time.Sleep(BatchChangeInterval) — needs multiple chunks to trigger
  - Lines 353–366: entire fallbackUpdates loop (SRV/CAA individual updates + error path)

  fallbackIndividualChanges:
  - Lines 414–417: delete "record already gone" guard
  - Lines 425–428: update "record unexpectedly not found" guard

  tagsFromResponse:
  - Line 156: return nil path

  ---
  cloudflare.go — 7 uncovered blocks (all pre-existing code paths newly exercised by refactor)

  - Lines 539–541: error return from getDNSRecordsMap
  - Lines 543–545: error return from listCustomHostnamesWithPagination
  - Lines 549–551: processCustomHostnameChanges failure → failedChange = true
  - Lines 516–532: dry-run regional hostname error paths (3 blocks)

  ---
  cloudflare_custom_hostnames.go

  - Lines 297–299: processCustomHostnameChanges failure path (failed = true)

Comment thread provider/cloudflare/cloudflare_batch.go
Comment thread provider/cloudflare/cloudflare_batch.go
Comment thread provider/cloudflare/cloudflare.go Outdated
@mooseracerPT
Copy link
Copy Markdown
Contributor Author

mooseracerPT commented Mar 1, 2026

Metrics from my own cluster that has been running various builds using the Batch API. (Record Changes is number of log lines matching %dynamodb%, to capture all changes.)

Testing caveats:

  • we don't do anything fancy with the record types, it's all proxied CNAME or A records with default settings
  • Cloudflare Enterprise using partial CNAME mode (i.e. our DNS authority is elsewhere)
image

@mooseracerPT
Copy link
Copy Markdown
Contributor Author

I've added more tests to improve code coverage. Addressing your points:

sigs.k8s.io/external-dns/provider/cloudflare/cloudflare_batch.go:67:                    BatchDNSRecords                                 100.0%
sigs.k8s.io/external-dns/provider/cloudflare/cloudflare_batch.go:72:                    getUpdateDNSRecordParam                         100.0%
sigs.k8s.io/external-dns/provider/cloudflare/cloudflare_batch.go:89:                    getCreateDNSRecordParam                         100.0%
sigs.k8s.io/external-dns/provider/cloudflare/cloudflare_batch.go:110:                   chunkBatchChanges                               100.0%
sigs.k8s.io/external-dns/provider/cloudflare/cloudflare_batch.go:152:                   tagsFromResponse                                100.0%
sigs.k8s.io/external-dns/provider/cloudflare/cloudflare_batch.go:160:                   buildBatchPostParam                             100.0%
sigs.k8s.io/external-dns/provider/cloudflare/cloudflare_batch.go:176:                   buildBatchPutParam                              100.0%
sigs.k8s.io/external-dns/provider/cloudflare/cloudflare_batch.go:269:                   buildBatchCollections                           100.0%
sigs.k8s.io/external-dns/provider/cloudflare/cloudflare_batch.go:323:                   submitDNSRecordChanges                          100.0%
sigs.k8s.io/external-dns/provider/cloudflare/cloudflare_batch.go:382:                   fallbackIndividualChanges                       100.0%
---
sigs.k8s.io/external-dns/provider/cloudflare/cloudflare.go:745:                         getDNSRecordsMap                                100.0%
sigs.k8s.io/external-dns/provider/cloudflare/cloudflare.go:237:                         convertCloudflareError                          100.0%
---
sigs.k8s.io/external-dns/provider/cloudflare/cloudflare_custom_hostnames.go:260:        listCustomHostnamesWithPagination               100.0%
sigs.k8s.io/external-dns/provider/cloudflare/cloudflare_custom_hostnames.go:282:        processCustomHostnameChanges                    100.0%

@ivankatliarchuk
Copy link
Copy Markdown
Member

kk. we need a second review

/approve

@k8s-ci-robot
Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: ivankatliarchuk

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Mar 1, 2026
@ivankatliarchuk
Copy link
Copy Markdown
Member

If you wanna do more improvements, I've opened a PR with some guidelines #6249. In follow-up, when this gets merged, in separate PRs

@mooseracerPT
Copy link
Copy Markdown
Contributor Author

Cool, thanks for the vote of confidence, and thanks for all your time getting this PR up to snuff.

@szuecs
Copy link
Copy Markdown
Contributor

szuecs commented Mar 12, 2026

/lgtm

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Mar 12, 2026
@k8s-ci-robot k8s-ci-robot merged commit ca58d99 into kubernetes-sigs:master Mar 12, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

apis Issues or PRs related to API change approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. controller Issues or PRs related to the controller docs lgtm "Looks good to me", indicates that a PR is ready to be merged. ok-to-test Indicates a non-member PR verified by an org member that is safe to test. provider Issues or PRs related to a provider size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants