Skip to content

Conversation

mrshaun13
Copy link

What does it do ?

Fixes SRV record handling in the Cloudflare provider by:

  • Fixing SRV record ID generation to include target information
  • Properly handling the Data field for SRV records in the mock client
  • Adding test coverage for SRV records
  • Removing parallel test execution that was causing flakiness

Fixes #4751

Motivation

The current implementation has issues with SRV record handling in the Cloudflare provider, particularly around record identification and data field management. This PR addresses these issues to ensure reliable SRV record management.

More

  • Yes, this PR title follows Conventional Commits
  • Yes, I added unit tests
  • No documentation changes needed (internal implementation improvements only)

Testing

  • All existing tests pass
  • Added new test cases for SRV record handling
  • Verified behavior against actual Cloudflare API responses

Test output:

$ go test -v -count=1
=== RUN   TestCloudflareRegionalHostnameActions
=== RUN   TestCloudflareRegionalHostnameActions/create
=== RUN   TestCloudflareRegionalHostnameActions/Update
=== RUN   TestCloudflareRegionalHostnameActions/Delete
=== RUN   TestCloudflareRegionalHostnameActions/No_change
--- PASS: TestCloudflareRegionalHostnameActions (0.00s)
    --- PASS: TestCloudflareRegionalHostnameActions/create (0.00s)
    --- PASS: TestCloudflareRegionalHostnameActions/Update (0.00s)
    --- PASS: TestCloudflareRegionalHostnameActions/Delete (0.00s)
    --- PASS: TestCloudflareRegionalHostnameActions/No_change (0.00s)
=== RUN   TestCloudflareRegionalHostnameDefaults
--- PASS: TestCloudflareRegionalHostnameDefaults (0.00s)
=== RUN   Test_regionalHostname
=== RUN   Test_regionalHostname/no_region_key
=== RUN   Test_regionalHostname/default_region_key
=== RUN   Test_regionalHostname/endpoint_with_region_key
=== RUN   Test_regionalHostname/endpoint_with_empty_region_key
=== RUN   Test_regionalHostname/unsupported_record_type
=== RUN   Test_regionalHostname/disabled
--- PASS: Test_regionalHostname (0.00s)
    --- PASS: Test_regionalHostname/no_region_key (0.00s)
    --- PASS: Test_regionalHostname/default_region_key (0.00s)
    --- PASS: Test_regionalHostname/endpoint_with_region_key (0.00s)
    --- PASS: Test_regionalHostname/endpoint_with_empty_region_key (0.00s)
    --- PASS: Test_regionalHostname/unsupported_record_type (0.00s)
    --- PASS: Test_regionalHostname/disabled (0.00s)
=== RUN   Test_desiredDataLocalizationRegionalHostnames
=== RUN   Test_desiredDataLocalizationRegionalHostnames/empty_input
=== RUN   Test_desiredDataLocalizationRegionalHostnames/change_without_regional_hostname_config
=== RUN   Test_desiredDataLocalizationRegionalHostnames/changes_with_same_hostname_and_region_key
=== RUN   Test_desiredDataLocalizationRegionalHostnames/changes_with_same_hostname_but_different_region_keys
=== RUN   Test_desiredDataLocalizationRegionalHostnames/changes_with_different_hostnames
=== RUN   Test_desiredDataLocalizationRegionalHostnames/change_with_empty_region_key
=== RUN   Test_desiredDataLocalizationRegionalHostnames/empty_region_key_followed_by_region_key
=== RUN   Test_desiredDataLocalizationRegionalHostnames/region_key_followed_by_empty_region_key
=== RUN   Test_desiredDataLocalizationRegionalHostnames/delete_followed_by_create_for_the_same_hostname
=== RUN   Test_desiredDataLocalizationRegionalHostnames/create_followed_by_delete_for_the_same_hostname
--- PASS: Test_desiredDataLocalizationRegionalHostnames (0.00s)
    --- PASS: Test_desiredDataLocalizationRegionalHostnames/empty_input (0.00s)
    --- PASS: Test_desiredDataLocalizationRegionalHostnames/change_without_regional_hostname_config (0.00s)
    --- PASS: Test_desiredDataLocalizationRegionalHostnames/changes_with_same_hostname_and_region_key (0.00s)
    --- PASS: Test_desiredDataLocalizationRegionalHostnames/changes_with_same_hostname_but_different_region_keys (0.00s)
    --- PASS: Test_desiredDataLocalizationRegionalHostnames/changes_with_different_hostnames (0.00s)
    --- PASS: Test_desiredDataLocalizationRegionalHostnames/change_with_empty_region_key (0.00s)
    --- PASS: Test_desiredDataLocalizationRegionalHostnames/empty_region_key_followed_by_region_key (0.00s)
    --- PASS: Test_desiredDataLocalizationRegionalHostnames/region_key_followed_by_empty_region_key (0.00s)
    --- PASS: Test_desiredDataLocalizationRegionalHostnames/delete_followed_by_create_for_the_same_hostname (0.00s)
    --- PASS: Test_desiredDataLocalizationRegionalHostnames/create_followed_by_delete_for_the_same_hostname (0.00s)
=== RUN   Test_dataLocalizationRegionalHostnamesChanges
=== RUN   Test_dataLocalizationRegionalHostnamesChanges/empty_desired_and_current_lists
=== RUN   Test_dataLocalizationRegionalHostnamesChanges/multiple_changes
--- PASS: Test_dataLocalizationRegionalHostnamesChanges (0.00s)
    --- PASS: Test_dataLocalizationRegionalHostnamesChanges/empty_desired_and_current_lists (0.00s)
    --- PASS: Test_dataLocalizationRegionalHostnamesChanges/multiple_changes (0.00s)
=== RUN   TestRecordsWithListRegionalHostnameFaillure
--- PASS: TestRecordsWithListRegionalHostnameFaillure (0.00s)
=== RUN   TestApplyChangesWithRegionalHostnamesFaillures
=== RUN   TestApplyChangesWithRegionalHostnamesFaillures/list_zone_fails
=== PAUSE TestApplyChangesWithRegionalHostnamesFaillures/list_zone_fails
=== RUN   TestApplyChangesWithRegionalHostnamesFaillures/create_fails
=== PAUSE TestApplyChangesWithRegionalHostnamesFaillures/create_fails
=== RUN   TestApplyChangesWithRegionalHostnamesFaillures/update_fails
=== PAUSE TestApplyChangesWithRegionalHostnamesFaillures/update_fails
=== RUN   TestApplyChangesWithRegionalHostnamesFaillures/delete_fails
=== PAUSE TestApplyChangesWithRegionalHostnamesFaillures/delete_fails
=== RUN   TestApplyChangesWithRegionalHostnamesFaillures/conflicting_regional_keys
=== PAUSE TestApplyChangesWithRegionalHostnamesFaillures/conflicting_regional_keys
=== CONT  TestApplyChangesWithRegionalHostnamesFaillures/list_zone_fails
=== CONT  TestApplyChangesWithRegionalHostnamesFaillures/delete_fails
=== CONT  TestApplyChangesWithRegionalHostnamesFaillures/update_fails
=== CONT  TestApplyChangesWithRegionalHostnamesFaillures/create_fails
=== CONT  TestApplyChangesWithRegionalHostnamesFaillures/conflicting_regional_keys
--- PASS: TestApplyChangesWithRegionalHostnamesFaillures (0.00s)
    --- PASS: TestApplyChangesWithRegionalHostnamesFaillures/list_zone_fails (0.00s)
    --- PASS: TestApplyChangesWithRegionalHostnamesFaillures/update_fails (0.00s)
    --- PASS: TestApplyChangesWithRegionalHostnamesFaillures/delete_fails (0.00s)
    --- PASS: TestApplyChangesWithRegionalHostnamesFaillures/create_fails (0.00s)
    --- PASS: TestApplyChangesWithRegionalHostnamesFaillures/conflicting_regional_keys (0.00s)
=== RUN   TestApplyChangesWithRegionalHostnamesDryRun
=== RUN   TestApplyChangesWithRegionalHostnamesDryRun/create_dry_run
=== PAUSE TestApplyChangesWithRegionalHostnamesDryRun/create_dry_run
=== RUN   TestApplyChangesWithRegionalHostnamesDryRun/update_fails
=== PAUSE TestApplyChangesWithRegionalHostnamesDryRun/update_fails
=== RUN   TestApplyChangesWithRegionalHostnamesDryRun/delete_fails
=== PAUSE TestApplyChangesWithRegionalHostnamesDryRun/delete_fails
=== CONT  TestApplyChangesWithRegionalHostnamesDryRun/create_dry_run
=== CONT  TestApplyChangesWithRegionalHostnamesDryRun/delete_fails
=== CONT  TestApplyChangesWithRegionalHostnamesDryRun/update_fails
--- PASS: TestApplyChangesWithRegionalHostnamesDryRun (0.00s)
    --- PASS: TestApplyChangesWithRegionalHostnamesDryRun/create_dry_run (0.00s)
    --- PASS: TestApplyChangesWithRegionalHostnamesDryRun/delete_fails (0.00s)
    --- PASS: TestApplyChangesWithRegionalHostnamesDryRun/update_fails (0.00s)
=== RUN   TestCloudflareA
--- PASS: TestCloudflareA (0.00s)
=== RUN   TestCloudflareCname
--- PASS: TestCloudflareCname (0.00s)
=== RUN   TestCloudflareMx
--- PASS: TestCloudflareMx (0.00s)
=== RUN   TestCloudflareTxt
--- PASS: TestCloudflareTxt (0.00s)
=== RUN   TestCloudflareCustomTTL
--- PASS: TestCloudflareCustomTTL (0.00s)
=== RUN   TestCloudflareProxiedDefault
--- PASS: TestCloudflareProxiedDefault (0.00s)
=== RUN   TestCloudflareProxiedOverrideTrue
--- PASS: TestCloudflareProxiedOverrideTrue (0.00s)
=== RUN   TestCloudflareProxiedOverrideFalse
--- PASS: TestCloudflareProxiedOverrideFalse (0.00s)
=== RUN   TestCloudflareProxiedOverrideIllegal
--- PASS: TestCloudflareProxiedOverrideIllegal (0.00s)
=== RUN   TestCloudflareSetProxied
--- PASS: TestCloudflareSetProxied (0.00s)
=== RUN   TestCloudflareZones
--- PASS: TestCloudflareZones (0.00s)
=== RUN   TestCloudflareZonesFailed
--- PASS: TestCloudflareZonesFailed (0.00s)
=== RUN   TestCloudFlareZonesWithIDFilter
--- PASS: TestCloudFlareZonesWithIDFilter (0.00s)
=== RUN   TestCloudflareListZonesRateLimited
--- PASS: TestCloudflareListZonesRateLimited (0.00s)
=== RUN   TestCloudflareListZonesRateLimitedStringError
--- PASS: TestCloudflareListZonesRateLimitedStringError (0.00s)
=== RUN   TestCloudflareListZoneInternalErrors
    cloudflare_test.go:977: soft error
        
--- PASS: TestCloudflareListZoneInternalErrors (0.00s)
=== RUN   TestCloudflareRecords
--- PASS: TestCloudflareRecords (0.00s)
=== RUN   TestCloudflareProvider
=== RUN   TestCloudflareProvider/use_api_token
=== RUN   TestCloudflareProvider/use_api_token_file_contents
=== RUN   TestCloudflareProvider/use_email_and_key
=== RUN   TestCloudflareProvider/no_use_email_and_key
=== RUN   TestCloudflareProvider/use_credentials_in_missing_file
=== RUN   TestCloudflareProvider/use_credentials_in_missing_file#01
--- PASS: TestCloudflareProvider (0.00s)
    --- PASS: TestCloudflareProvider/use_api_token (0.00s)
    --- PASS: TestCloudflareProvider/use_api_token_file_contents (0.00s)
    --- PASS: TestCloudflareProvider/use_email_and_key (0.00s)
    --- PASS: TestCloudflareProvider/no_use_email_and_key (0.00s)
    --- PASS: TestCloudflareProvider/use_credentials_in_missing_file (0.00s)
    --- PASS: TestCloudflareProvider/use_credentials_in_missing_file#01 (0.00s)
=== RUN   TestCloudflareApplyChanges
--- PASS: TestCloudflareApplyChanges (0.00s)
=== RUN   TestCloudflareDryRunApplyChanges
--- PASS: TestCloudflareDryRunApplyChanges (0.00s)
=== RUN   TestCloudflareApplyChangesError
--- PASS: TestCloudflareApplyChangesError (0.00s)
=== RUN   TestCloudflareGetRecordID
--- PASS: TestCloudflareGetRecordID (0.00s)
=== RUN   TestCloudflareGroupByNameAndType
--- PASS: TestCloudflareGroupByNameAndType (0.00s)
=== RUN   TestGroupByNameAndTypeWithCustomHostnames_MX
--- PASS: TestGroupByNameAndTypeWithCustomHostnames_MX (0.00s)
=== RUN   TestProviderPropertiesIdempotency
=== RUN   TestProviderPropertiesIdempotency/ProxyDefault:_false,_ShouldBeProxied:_false,_ExpectUpdates:_false
=== RUN   TestProviderPropertiesIdempotency/ProxyDefault:_true,_ShouldBeProxied:_true,_ExpectUpdates:_false
=== RUN   TestProviderPropertiesIdempotency/ProxyDefault:_true,_ShouldBeProxied:_false,_ExpectUpdates:_true
=== RUN   TestProviderPropertiesIdempotency/ProxyDefault:_false,_ShouldBeProxied:_true,_ExpectUpdates:_true
--- PASS: TestProviderPropertiesIdempotency (0.00s)
    --- PASS: TestProviderPropertiesIdempotency/ProxyDefault:_false,_ShouldBeProxied:_false,_ExpectUpdates:_false (0.00s)
    --- PASS: TestProviderPropertiesIdempotency/ProxyDefault:_true,_ShouldBeProxied:_true,_ExpectUpdates:_false (0.00s)
    --- PASS: TestProviderPropertiesIdempotency/ProxyDefault:_true,_ShouldBeProxied:_false,_ExpectUpdates:_true (0.00s)
    --- PASS: TestProviderPropertiesIdempotency/ProxyDefault:_false,_ShouldBeProxied:_true,_ExpectUpdates:_true (0.00s)
=== RUN   TestCloudflareComplexUpdate
--- PASS: TestCloudflareComplexUpdate (0.00s)
=== RUN   TestCustomTTLWithEnabledProxyNotChanged
--- PASS: TestCustomTTLWithEnabledProxyNotChanged (0.00s)
=== RUN   TestCloudFlareProvider_Region
--- PASS: TestCloudFlareProvider_Region (0.00s)
=== RUN   TestCloudFlareProvider_newCloudFlareChange
=== RUN   TestCloudFlareProvider_newCloudFlareChange/For_free_Zone_respecting_comment_length,_expect_no_trimming
=== RUN   TestCloudFlareProvider_newCloudFlareChange/For_free_Zones_not_respecting_comment_length,_expect_trimmed_comments
=== RUN   TestCloudFlareProvider_newCloudFlareChange/For_paid_Zones_respecting_comment_length,_expect_no_trimming
=== RUN   TestCloudFlareProvider_newCloudFlareChange/For_paid_Zones_not_respecting_comment_length,_expect_trimmed_comments
--- PASS: TestCloudFlareProvider_newCloudFlareChange (0.20s)
    --- PASS: TestCloudFlareProvider_newCloudFlareChange/For_free_Zone_respecting_comment_length,_expect_no_trimming (0.00s)
    --- PASS: TestCloudFlareProvider_newCloudFlareChange/For_free_Zones_not_respecting_comment_length,_expect_trimmed_comments (0.20s)
    --- PASS: TestCloudFlareProvider_newCloudFlareChange/For_paid_Zones_respecting_comment_length,_expect_no_trimming (0.00s)
    --- PASS: TestCloudFlareProvider_newCloudFlareChange/For_paid_Zones_not_respecting_comment_length,_expect_trimmed_comments (0.00s)
=== RUN   TestCloudFlareProvider_submitChangesCNAME
--- PASS: TestCloudFlareProvider_submitChangesCNAME (0.00s)
=== RUN   TestCloudFlareProvider_submitChangesApex
--- PASS: TestCloudFlareProvider_submitChangesApex (0.00s)
=== RUN   TestCloudflareZoneRecordsFail
--- PASS: TestCloudflareZoneRecordsFail (0.00s)
=== RUN   TestCloudflareLongRecordsErrorLog
--- PASS: TestCloudflareLongRecordsErrorLog (0.00s)
=== RUN   TestCloudflareDNSRecordsOperationsFail
--- PASS: TestCloudflareDNSRecordsOperationsFail (0.00s)
=== RUN   TestCloudflareCustomHostnameOperations
--- PASS: TestCloudflareCustomHostnameOperations (0.00s)
=== RUN   TestCloudflareDisabledCustomHostnameOperations
--- PASS: TestCloudflareDisabledCustomHostnameOperations (0.00s)
=== RUN   TestCloudflareCustomHostnameNotFoundOnRecordDeletion
    cloudflare_test.go:2539: corrupting custom hostname "ID-newerror-getCustomHostnameOrigin.foo.fancybar.com"
--- PASS: TestCloudflareCustomHostnameNotFoundOnRecordDeletion (0.00s)
=== RUN   TestCloudflareListCustomHostnamesWithPagionation
--- PASS: TestCloudflareListCustomHostnamesWithPagionation (0.03s)
=== RUN   TestZoneHasPaidPlan
--- PASS: TestZoneHasPaidPlan (0.00s)
=== RUN   TestCloudflareApplyChanges_AllErrorLogPaths
--- PASS: TestCloudflareApplyChanges_AllErrorLogPaths (0.00s)
=== RUN   TestCloudFlareProvider_SupportedAdditionalRecordTypes
=== RUN   TestCloudFlareProvider_SupportedAdditionalRecordTypes/MX
=== RUN   TestCloudFlareProvider_SupportedAdditionalRecordTypes/A
=== RUN   TestCloudFlareProvider_SupportedAdditionalRecordTypes/CNAME
=== RUN   TestCloudFlareProvider_SupportedAdditionalRecordTypes/TXT
=== RUN   TestCloudFlareProvider_SupportedAdditionalRecordTypes/NS
=== RUN   TestCloudFlareProvider_SupportedAdditionalRecordTypes/SRV
=== RUN   TestCloudFlareProvider_SupportedAdditionalRecordTypes/SPF
=== RUN   TestCloudFlareProvider_SupportedAdditionalRecordTypes/LOC
=== RUN   TestCloudFlareProvider_SupportedAdditionalRecordTypes/UNKNOWN
--- PASS: TestCloudFlareProvider_SupportedAdditionalRecordTypes (0.00s)
    --- PASS: TestCloudFlareProvider_SupportedAdditionalRecordTypes/MX (0.00s)
    --- PASS: TestCloudFlareProvider_SupportedAdditionalRecordTypes/A (0.00s)
    --- PASS: TestCloudFlareProvider_SupportedAdditionalRecordTypes/CNAME (0.00s)
    --- PASS: TestCloudFlareProvider_SupportedAdditionalRecordTypes/TXT (0.00s)
    --- PASS: TestCloudFlareProvider_SupportedAdditionalRecordTypes/NS (0.00s)
    --- PASS: TestCloudFlareProvider_SupportedAdditionalRecordTypes/SRV (0.00s)
    --- PASS: TestCloudFlareProvider_SupportedAdditionalRecordTypes/SPF (0.00s)
    --- PASS: TestCloudFlareProvider_SupportedAdditionalRecordTypes/LOC (0.00s)
    --- PASS: TestCloudFlareProvider_SupportedAdditionalRecordTypes/UNKNOWN (0.00s)
PASS
ok      sigs.k8s.io/external-dns/provider/cloudflare    0.250s

@k8s-ci-robot k8s-ci-robot added the do-not-merge/invalid-commit-message Indicates that a PR should not merge because it has an invalid commit message. label Jun 25, 2025
@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign szuecs for approval. For more information see the Code Review Process.

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

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 cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. provider Issues or PRs related to a provider labels Jun 25, 2025
@k8s-ci-robot
Copy link
Contributor

Hi @mrshaun13. 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.

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 needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Jun 25, 2025
- Parse SRV record content into structured Data map
- Clear Content field when Data is set for SRV records
- Handle Data field in mock client for SRV records
- Fix test cases and remove parallel test execution
- Add test coverage for SRV records
@mrshaun13 mrshaun13 force-pushed the fix/cloudflare-srv-record-handling branch from 83042e7 to 89fe195 Compare June 25, 2025 20:26
@k8s-ci-robot k8s-ci-robot removed the do-not-merge/invalid-commit-message Indicates that a PR should not merge because it has an invalid commit message. label Jun 25, 2025
@ivankatliarchuk
Copy link
Contributor

Hi. Could you share results of a smoke tests agains a cluster and CF provder?

/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 Jun 25, 2025
Comment on lines +184 to +197
parts := strings.Fields(recordData.Content)
if len(parts) >= 4 {
priority, _ := strconv.Atoi(parts[0])
weight, _ := strconv.Atoi(parts[1])
port, _ := strconv.Atoi(parts[2])
target := strings.Join(parts[3:], " ")
recordData.Data = map[string]interface{}{
"priority": priority,
"weight": weight,
"port": port,
"target": target,
}
recordData.Content = ""
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Wdyt about moving this part into a dedicated func ?
That would ease maintenance and readability.

@k8s-ci-robot
Copy link
Contributor

PR needs rebase.

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 the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Aug 14, 2025
@mloiseleur
Copy link
Collaborator

@mrshaun13 Do you think you can rebase this PR and takes first review comments into account ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. 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/L Denotes a PR that changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

SRV records cannot be created by the cloudflare provider
4 participants