Skip to content

NEW PROVIDER: Tencent Cloud DNS (TENCENTDNS/DNSPOD) provider and registrar#4237

Open
cylonchau wants to merge 4 commits into
DNSControl:mainfrom
cylonchau:feat/tencentdns
Open

NEW PROVIDER: Tencent Cloud DNS (TENCENTDNS/DNSPOD) provider and registrar#4237
cylonchau wants to merge 4 commits into
DNSControl:mainfrom
cylonchau:feat/tencentdns

Conversation

@cylonchau
Copy link
Copy Markdown

@cylonchau cylonchau commented May 9, 2026

Summary

Hey! This PR adds support for Tencent Cloud DNS (tencentdns also known as dnspod)for DNS hosting and Tencent Domain for registrar/nameserver management.

Tencent Cloud is one of the major cloud providers in China, and DNSPod is widely used by Chinese users and companies. I also rely on DNSControl in my own projects to manage domain records for real business services, so having native Tencent Cloud support would make DNSControl much more useful for users who need to manage domains across Cloudflare, Tencent Cloud, Aliyun, and other providers in one workflow.

This provider supports both DNS and registrar use cases:

  • DNS record management for common record types: A, AAAA, CNAME, MX, NS, TXT, SRV, and CAA
  • Registrar-side nameserver delegation for domains registered with Tencent Cloud
  • ALIAS support for Tencent DNSPod's apex CNAME behavior while keeping DNSControl validation happy
  • Zone provisioning through EnsureZoneExists
  • Provider-specific validation through RecordAuditor
  • Automatic handling of DNSPod free-tier TTL limits, where the minimum TTL is 600 seconds
  • Other own files test files and documents

The implementation uses Tencent Cloud's official Go SDK with the modern API 3.0 endpoints:

  • DNSPod API: v20210323 (Tencent still continue maintain this sdk, date only a lable, this version is latest)
  • Domain API: v20180808 (Tencent still continue maintain this sdk, date only a lable, this version is latest)

Fixes #4171

Test record

$ go mod tidy
$ go build -o dnscontrol .
$ go test -v ./providers/tencentdns/...
=== RUN   TestNativeToRecord
=== RUN   TestNativeToRecord/Basic_A_record
=== RUN   TestNativeToRecord/CNAME_record
=== RUN   TestNativeToRecord/MX_record
--- PASS: TestNativeToRecord (0.00s)
    --- PASS: TestNativeToRecord/Basic_A_record (0.00s)
    --- PASS: TestNativeToRecord/CNAME_record (0.00s)
    --- PASS: TestNativeToRecord/MX_record (0.00s)
=== RUN   TestRecordToCreateRequest
--- PASS: TestRecordToCreateRequest (0.00s)
=== RUN   TestRecordToCreateRequest_MX
--- PASS: TestRecordToCreateRequest_MX (0.00s)
=== RUN   TestNewTencentDNS
--- PASS: TestNewTencentDNS (0.00s)
=== RUN   TestNewTencentDNS_MissingCreds
--- PASS: TestNewTencentDNS_MissingCreds (0.00s)
PASS
ok      github.com/DNSControl/dnscontrol/v4/providers/tencentdns        (cached) 

add record test

$ dnscontrol % ./dnscontrol push
INFO: In dnsconfig.js NewRegistrar("tencentdns", "TENCENTDNS") can be simplified to NewRegistrar("tencentdns") (See https://docs.dnscontrol.org/commands/creds-json#cleanup)
INFO: In dnsconfig.js NewDnsProvider("tencentdns", "TENCENTDNS") can be simplified to NewDnsProvider("tencentdns") (See https://docs.dnscontrol.org/commands/creds-json#cleanup)
CONCURRENTLY checking for 0 zone(s)
SERIALLY checking for 1 zone(s)
Serially checking for zone: "oomkill.com"
CONCURRENTLY gathering records of 0 zone(s)
SERIALLY gathering records of 1 zone(s)
Serially Gathering: "oomkill.com"
******************** Domain: oomkill.com
9 corrections (tencentdns)
INFO#1: 5 records not being deleted because of NO_PURGE:
    CNAME("www.oomkill.com.", "www.oomkill.com.cdn.dnsv1.com."),
    CNAME("k8s-origin.web.oomkill.com.", "lb-fhodvg4u-64alogb8n2k1vt79.clb.sg-tencentclb.com."),
    CNAME("oomkill.com.", "oomkill.com.cdn.dnsv1.com."),
    TXT("_dnsauth.oomkill.com.", "202605010943194753vkhn1adx9mtpvjc4blyg48wfpzs0b15zy3sf7oc9qrxqq2"),
    TXT("_dnsauth.oomkill.com.", "202605010944363rbshgzl45kt0jwze9ydfasfzgijk2jarurfzm57mnigmz63sj"),
#1: + CREATE oomkill.com NS a.dnspod.com. ttl=300
FAILURE! [TencentCloudSDKError] Code=LimitExceeded.RecordTtlLimit, Message=记录的TTL值超出了限制。, RequestId=b88d8aa1-1061-47f0-9fc6-690d76e2488f
#2: + CREATE oomkill.com NS b.dnspod.com. ttl=300
FAILURE! [TencentCloudSDKError] Code=LimitExceeded.RecordTtlLimit, Message=记录的TTL值超出了限制。, RequestId=dd59d7e8-53e1-429c-a2fb-78c065abc933
#3: + CREATE oomkill.com NS c.dnspod.com. ttl=300
FAILURE! [TencentCloudSDKError] Code=LimitExceeded.RecordTtlLimit, Message=记录的TTL值超出了限制。, RequestId=98c2cd8e-392d-46ca-80a3-cb61982097f0
#4: + CREATE oomkill.com MX 10 mail.yourtestdomain.com. ttl=300
FAILURE! [TencentCloudSDKError] Code=LimitExceeded.RecordTtlLimit, Message=记录的TTL值超出了限制。, RequestId=95e5677e-cda4-47d0-a62e-7621a67e6071
#5: + CREATE blog.oomkill.com CNAME yourtestdomain.com. ttl=300
FAILURE! [TencentCloudSDKError] Code=LimitExceeded.RecordTtlLimit, Message=记录的TTL值超出了限制。, RequestId=5410d07a-9d4f-4fea-8475-efccd5d3149f
#6: + CREATE ksss.oomkill.com A 1.2.3.4 ttl=300
FAILURE! [TencentCloudSDKError] Code=LimitExceeded.RecordTtlLimit, Message=记录的TTL值超出了限制。, RequestId=82d30e87-041e-41d9-b605-971b53d05ef2
#7: + CREATE test.oomkill.com A 5.6.7.8 ttl=300
FAILURE! [TencentCloudSDKError] Code=LimitExceeded.RecordTtlLimit, Message=记录的TTL值超出了限制。, RequestId=7b75f910-4a2a-4847-b685-6a561202aa63
#8: + CREATE verif.oomkill.com TXT "dnscontrol-test-123" ttl=300
FAILURE! [TencentCloudSDKError] Code=LimitExceeded.RecordTtlLimit, Message=记录的TTL值超出了限制。, RequestId=64ff1cbe-3fe3-469d-bbba-417517a9f4bd
#9: Update nameservers A.DNSPOD.COM,B.DNSPOD.COM,C.DNSPOD.COM -> a.dnspod.com,b.dnspod.com,c.dnspod.com
SUCCESS!
Done. 9 corrections.
completed with errors

delete record test

$ % ./dnscontrol push       
INFO: In dnsconfig.js NewRegistrar("tencentdns", "TENCENTDNS") can be simplified to NewRegistrar("tencentdns") (See https://docs.dnscontrol.org/commands/creds-json#cleanup)
INFO: In dnsconfig.js NewDnsProvider("tencentdns", "TENCENTDNS") can be simplified to NewDnsProvider("tencentdns") (See https://docs.dnscontrol.org/commands/creds-json#cleanup)
CONCURRENTLY checking for 0 zone(s)
SERIALLY checking for 1 zone(s)
Serially checking for zone: "oomkill.com"
CONCURRENTLY gathering records of 0 zone(s)
SERIALLY gathering records of 1 zone(s)
Serially Gathering: "oomkill.com"
******************** Domain: oomkill.com
9 corrections (tencentdns)
INFO#1: 5 records not being deleted because of NO_PURGE:
    CNAME("www.oomkill.com.", "www.oomkill.com.cdn.dnsv1.com."),
    CNAME("k8s-origin.web.oomkill.com.", "lb-fhodvg4u-64alogb8n2k1vt79.clb.sg-tencentclb.com."),
    CNAME("oomkill.com.", "oomkill.com.cdn.dnsv1.com."),
    TXT("_dnsauth.oomkill.com.", "202605010943194753vkhn1adx9mtpvjc4blyg48wfpzs0b15zy3sf7oc9qrxqq2"),
    TXT("_dnsauth.oomkill.com.", "202605010944363rbshgzl45kt0jwze9ydfasfzgijk2jarurfzm57mnigmz63sj"),
#1: + CREATE oomkill.com NS a.dnspod.com. ttl=300
FAILURE! [TencentCloudSDKError] Code=LimitExceeded.RecordTtlLimit, Message=记录的TTL值超出了限制。, RequestId=04552fc0-9af2-429b-bb97-d48b56fae223
#2: + CREATE oomkill.com NS b.dnspod.com. ttl=300
FAILURE! [TencentCloudSDKError] Code=LimitExceeded.RecordTtlLimit, Message=记录的TTL值超出了限制。, RequestId=f2c383c9-4dda-4ac4-8499-9c0a2bc26456
#3: + CREATE oomkill.com NS c.dnspod.com. ttl=300
FAILURE! [TencentCloudSDKError] Code=LimitExceeded.RecordTtlLimit, Message=记录的TTL值超出了限制。, RequestId=83aff47e-514b-4273-9e94-8fb1080333fb
#4: + CREATE oomkill.com MX 10 mail.yourtestdomain.com. ttl=600
SUCCESS!
#5: + CREATE blog.oomkill.com CNAME yourtestdomain.com. ttl=600
SUCCESS!
#6: + CREATE ksss.oomkill.com A 1.2.3.4 ttl=600
SUCCESS!
#7: + CREATE test.oomkill.com A 5.6.7.8 ttl=600
SUCCESS!
#8: + CREATE verif.oomkill.com TXT "dnscontrol-test-123" ttl=600
SUCCESS!
#9: Update nameservers A.DNSPOD.COM,B.DNSPOD.COM,C.DNSPOD.COM -> a.dnspod.com,b.dnspod.com,c.dnspod.com
SUCCESS!
Done. 9 corrections.
completed with errors

add zone test

$ dnscontrol % ./dnscontrol preview
INFO: In dnsconfig.js NewRegistrar("tencentdns", "TENCENTDNS") can be simplified to NewRegistrar("tencentdns") (See https://docs.dnscontrol.org/commands/creds-json#cleanup)
INFO: In dnsconfig.js NewDnsProvider("tencentdns", "TENCENTDNS") can be simplified to NewDnsProvider("tencentdns") (See https://docs.dnscontrol.org/commands/creds-json#cleanup)
CONCURRENTLY checking for 0 zone(s)
SERIALLY checking for 1 zone(s)
Serially checking for zone: "oomkill.com"
******************** Domain: oomkill.com
1 correction (tencentdns)
#1: Ensuring zone "oomkill.com" exists in "tencentdns"
CONCURRENTLY gathering records of 0 zone(s)
SERIALLY gathering records of 1 zone(s)
Serially Gathering: "oomkill.com"
******************** Domain: oomkill.com
1 correction (tencentdns)
#1: + CREATE oomkill.com A 127.0.0.1 ttl=600
INFO#1: Skipping registrar "tencentdns": No nameservers declared for domain "oomkill.com". Add {no_ns: 'true'} to force
Done. 2 corrections.

$ % ./dnscontrol push   
INFO: In dnsconfig.js NewRegistrar("tencentdns", "TENCENTDNS") can be simplified to NewRegistrar("tencentdns") (See https://docs.dnscontrol.org/commands/creds-json#cleanup)
INFO: In dnsconfig.js NewDnsProvider("tencentdns", "TENCENTDNS") can be simplified to NewDnsProvider("tencentdns") (See https://docs.dnscontrol.org/commands/creds-json#cleanup)
CONCURRENTLY checking for 0 zone(s)
SERIALLY checking for 1 zone(s)
Serially checking for zone: "oomkill.com"
******************** Domain: oomkill.com
1 correction (tencentdns)
#1: Ensuring zone "oomkill.com" exists in "tencentdns"
SUCCESS!
CONCURRENTLY gathering records of 0 zone(s)
SERIALLY gathering records of 1 zone(s)
Serially Gathering: "oomkill.com"
******************** Domain: oomkill.com
5 corrections (tencentdns)
#1: ± MODIFY-TTL oomkill.com NS ttl=(86400->300) a.dnspod.com.
FAILURE! [TencentCloudSDKError] Code=LimitExceeded.RecordTtlLimit, Message=记录的TTL值超出了限制。, RequestId=9aa40b9a-108e-4195-9cd5-a295b745cbc1
#2: ± MODIFY-TTL oomkill.com NS ttl=(86400->300) b.dnspod.com.
FAILURE! [TencentCloudSDKError] Code=LimitExceeded.RecordTtlLimit, Message=记录的TTL值超出了限制。, RequestId=5d6f3be1-4243-408e-98fb-07771a104053
#3: ± MODIFY-TTL oomkill.com NS ttl=(86400->300) c.dnspod.com.
FAILURE! [TencentCloudSDKError] Code=LimitExceeded.RecordTtlLimit, Message=记录的TTL值超出了限制。, RequestId=d9695fcf-b48a-4845-ba05-2926530a4f70
#4: + CREATE oomkill.com A 127.0.0.1 ttl=600
SUCCESS!
#5: Update nameservers dns1.registrar-servers.com,dns2.registrar-servers.com -> a.dnspod.com,b.dnspod.com,c.dnspod.com
SUCCESS!
Done. 6 corrections.

@TomOnTime
Copy link
Copy Markdown
Collaborator

Greetings! Thank you for your patience while we migrated to the new GitHub org.

Now that the migration is complete, please rebase. Thank you.

@cafferata cafferata added the provider-TENCENTDNS Tencent Cloud DNS provider label May 13, 2026
@cylonchau
Copy link
Copy Markdown
Author

Greetings! Thank you for your patience while we migrated to the new GitHub org.

Now that the migration is complete, please rebase. Thank you.

Hi, thanks for the reply.

Could you please confirm which branch I should rebase onto? Should I rebase against the latest main branch or is there another target branch I should use?

@TomOnTime
Copy link
Copy Markdown
Collaborator

Greetings! Thank you for your patience while we migrated to the new GitHub org.
Now that the migration is complete, please rebase. Thank you.

Hi, thanks for the reply.

Could you please confirm which branch I should rebase onto? Should I rebase against the latest main branch or is there another target branch I should use?

Excellent question! Please rebase to main.

@SukkaW
Copy link
Copy Markdown
Contributor

SukkaW commented May 14, 2026

@cylonchau I noticed that there are many FAILURE! and 记录的TTL值超出了限制 (record TTL is invalid) error here.

This error should be properly handled, either with a validator rejecting invalid TTL, or silently rewritten the TTL to the valid value before feed them to diff2 (that's what I have done with VERCEL provider).

Copy link
Copy Markdown
Contributor

@SukkaW SukkaW left a comment

Choose a reason for hiding this comment

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

Handle invalid TTL, either with a validator rejectIf to reject invalid TTL, or silently re-write TTL before feeding records to diff2.

@cafferata
Copy link
Copy Markdown
Member

Optionally: since #4208 landed before this PR, would you be open to implementing RegisterCredsMetadata()? That would make Tencent Cloud DNS available in dnscontrol init. The PR has examples for simple providers like BIND and more complex ones like TransIP.

@cylonchau
Copy link
Copy Markdown
Author

@cylonchau I noticed that there are many FAILURE! and 记录的TTL值超出了限制 (record TTL is invalid) error here.

This error should be properly handled, either with a validator rejecting invalid TTL, or silently rewritten the TTL to the valid value before feed them to diff2 (that's what I have done with VERCEL provider).

@cylonchau I noticed that there are many FAILURE! and 记录的TTL值超出了限制 (record TTL is invalid) error here.

This error should be properly handled, either with a validator rejecting invalid TTL, or silently rewritten the TTL to the valid value before feed them to diff2 (that's what I have done with VERCEL provider).

Thanks your suggestion.

dnspod free plan requires a minimum TTL of 600 seconds. if user fill a number less than 600, then notice this message 记录的TTL值超出了限制 provider will reset to 600. i will fix the issue

@TomOnTime
Copy link
Copy Markdown
Collaborator

dnspod free plan requires a minimum TTL of 600 seconds. if user fill a number less than 600, then notice this message 记录的TTL值超出了限制 provider will reset to 600. i will fix the issue

Hello friend!

I'd like to make a suggestion.

This is a common question. Many providers require a minimum TTL or only specific TTL values. The best way to fix this is when converting the RecordConfig to the native record type.

In this PR, that means updating GetZoneRecordsCorrections() to iterate over existingRecords and fix any invalid TTLs.

You can look at other providers as examples. Most have a function called fixTTL().

@cylonchau
Copy link
Copy Markdown
Author

cylonchau commented May 15, 2026

Hi all, thanks for the reviews and helpful suggestions.

new submit i am fix some issue and suggestion

  • Suggestion for @SukkaW and @TomOnTime (record TTL is invalid)
  • Implementing RegisterCredsMetadata for @cafferata
  • Supports both Tencent Cloud China (cn) and International (inpl) APIs for dns record and registar.
  • Updated the provider docs.

Tested with (intl) :

Add zone and some record

create-zone.js

var REG_TENCENT = NewRegistrar("tencentdns");
var DSP_TENCENT = NewDnsProvider("tencentdns");

D("oomkill.net", REG_TENCENT, DnsProvider(DSP_TENCENT),
  NAMESERVER("ns1.dnspod.net."),
  NAMESERVER("ns2.dnspod.net."),

  A("@", "1.2.3.4", TTL(300)),
  TXT("txt", "hello")
);

preview

goldstains@goldsaintsMacBook-Pro dnscontrol % ./dnscontrol preview --config create-zone.js --creds creds.json
CONCURRENTLY checking for 0 zone(s)
SERIALLY checking for 1 zone(s)
Serially checking for zone: "oomkill.net"
******************** Domain: oomkill.net
1 correction (tencentdns)
#1: Ensuring zone "oomkill.net" exists in "tencentdns"
CONCURRENTLY gathering records of 0 zone(s)
SERIALLY gathering records of 1 zone(s)
Serially Gathering: "oomkill.net"
******************** Domain: oomkill.net
1 correction (tencentdns)
INFO#1: Domain "oomkill.net" provider tencentdns Error: [TencentCloudSDKError] Code=InvalidParameterValue.DomainNotExists, Message=当前域名有误,请返回重新操作。, RequestId=0bbf6948-219e-4b74-bb8d-85ca4562826b
#1: Update nameservers fns1.42.pl,fns2.42.pl -> ns1.dnspod.net,ns2.dnspod.net
Done. 2 corrections.
completed with errors

push

goldstains@goldsaintsMacBook-Pro dnscontrol % ./dnscontrol push --config create-zone.js --creds creds.json
CONCURRENTLY checking for 0 zone(s)
SERIALLY checking for 1 zone(s)
Serially checking for zone: "oomkill.net"
******************** Domain: oomkill.net
1 correction (tencentdns)
#1: Ensuring zone "oomkill.net" exists in "tencentdns"
SUCCESS!
CONCURRENTLY gathering records of 0 zone(s)
SERIALLY gathering records of 1 zone(s)
Serially Gathering: "oomkill.net"
******************** Domain: oomkill.net
8 corrections (tencentdns)
#1: ± MODIFY-TTL oomkill.net NS ttl=(86400->600) a.dnspod.com.
SUCCESS!
#2: ± MODIFY-TTL oomkill.net NS ttl=(86400->600) b.dnspod.com.
SUCCESS!
#3: ± MODIFY-TTL oomkill.net NS ttl=(86400->600) c.dnspod.com.
SUCCESS!
#4: + CREATE oomkill.net NS ns1.dnspod.net. ttl=600
SUCCESS!
#5: + CREATE oomkill.net NS ns2.dnspod.net. ttl=600
SUCCESS!
#6: + CREATE oomkill.net A 1.2.3.4 ttl=600
SUCCESS!
#7: + CREATE www.oomkill.net CNAME dnscontroltest.com. ttl=600
SUCCESS!
#8: Update nameservers fns1.42.pl,fns2.42.pl -> a.dnspod.com,b.dnspod.com,c.dnspod.com,ns1.dnspod.net,ns2.dnspod.net
SUCCESS!
Done. 9 corrections.
goldstains@goldsaintsMacBook-Pro dnscontrol % 
圖片

Delete record

goldstains@goldsaintsMacBook-Pro dnscontrol % ./dnscontrol push --config create-zone.js --creds creds.json
CONCURRENTLY checking for 0 zone(s)
SERIALLY checking for 1 zone(s)
Serially checking for zone: "oomkill.net"
CONCURRENTLY gathering records of 0 zone(s)
SERIALLY gathering records of 1 zone(s)
Serially Gathering: "oomkill.net"
******************** Domain: oomkill.net
3 corrections (tencentdns)
#1: + CREATE txt.oomkill.net TXT "hello" ttl=600
SUCCESS!
#2: - DELETE www.oomkill.net CNAME dnscontroltest.com. ttl=600
SUCCESS!
#3: Update nameservers fns1.42.pl,fns2.42.pl -> a.dnspod.com,b.dnspod.com,c.dnspod.com,ns1.dnspod.net,ns2.dnspod.net
SUCCESS!
Done. 3 corrections.
圖片

If user filling TTL less than 600 and is free plan, will get default TTL for tencent cloud API and set to default TTL value (600)

func (c *tencentCloudClient) getMinTTL(domainName string) (uint32, error) {
	request := dnspod.NewDescribeDomainRequest()
	request.Domain = common.StringPtr(domainName)

	response, err := c.dnspodClient.DescribeDomain(request)
	if err != nil {
		return 0, err
	}
	if response.Response == nil || response.Response.DomainInfo == nil || response.Response.DomainInfo.Grade == nil {
		return defaultTTL, nil
	}
	grade := *response.Response.DomainInfo.Grade

	packageRequest := dnspod.NewDescribePackageDetailRequest()
	packageResponse, err := c.dnspodClient.DescribePackageDetail(packageRequest)
	if err != nil {
		return 0, err
	}
	if packageResponse.Response == nil {
		return defaultTTL, nil
	}

	return minTTLForGrade(grade, packageResponse.Response.Info), nil
}

default TTL value

const defaultTTL = uint32(600)

Change NS

The test domain contains sensitive information, so I have hidden part of it.

var REG_TENCENT = NewRegistrar("tencentdns");

D("xxxx.net", REG_TENCENT,
  NAMESERVER("dns7.hichina.com."),
  NAMESERVER("dns8.hichina.com.")
);

preview

goldstains@goldsaintsMacBook-Pro dnscontrol % ./dnscontrol preview --config change-ns.js --creds creds.json
CONCURRENTLY checking for 0 zone(s)
SERIALLY checking for 1 zone(s)
Serially checking for zone: "xxxx.net"
CONCURRENTLY gathering records of 0 zone(s)
SERIALLY gathering records of 1 zone(s)
Serially Gathering: "xxxx.net"
******************** Domain: xxxx.net
1 correction (tencentdns)
#1: Update nameservers NANCY.NS.CLOUDFLARE.COM,RUDY.NS.CLOUDFLARE.COM -> dns7.hichina.com,dns8.hichina.com
Done. 1 corrections.

push

goldstains@goldsaintsMacBook-Pro dnscontrol % ./dnscontrol push --config change-ns-recover.js --creds creds.json --debug
CONCURRENTLY checking for 0 zone(s)
SERIALLY checking for 1 zone(s)
Serially checking for zone: "xxx.net"
CONCURRENTLY gathering records of 0 zone(s)
SERIALLY gathering records of 1 zone(s)
Serially Gathering: "xxx.net"
******************** Domain: xxx.net
1 correction (tencentdns)
#1: Update nameservers dns7.hichina.com,dns8.hichina.com -> a.dnspod.com,b.dnspod.com,c.dnspod.com
SUCCESS!
Done. 1 corrections.
圖片

Registrar operations require the correct Tencent Cloud site. Use site: "cn" for Tencent Cloud China and site: "intl" for Tencent Cloud International; otherwise, nameserver updates may fail because the wrong registrar API will be called.

For example, user will enconter.

goldstains@goldsaintsMacBook-Pro dnscontrol % ./dnscontrol push --config change-ns.js --creds creds.json --debug
CONCURRENTLY checking for 0 zone(s)
SERIALLY checking for 1 zone(s)
Serially checking for zone: "xxx.net"
CONCURRENTLY gathering records of 0 zone(s)
SERIALLY gathering records of 1 zone(s)
Serially Gathering: "xxx.net"
******************** Domain: xxx.net
1 correction (tencentdns)
#1: Update nameservers a.dnspod.com,b.dnspod.com,c.dnspod.com -> dns7.hichina.com,dns8.hichina.com
FAILURE! tencent domain batch operation 104311325 failed for xxx.net: 该域名不属于当前账号,无法执行操作
Done. 1 corrections.
completed with errors

Copy link
Copy Markdown
Member

@cafferata cafferata left a comment

Choose a reason for hiding this comment

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

Thanks for addressing the feedback and adding the optional RegisterCredsMetadata()! Two small inline comments, otherwise LGTM from my side.

Comment thread .github/CODEOWNERS Outdated
Comment thread documentation/provider/tencentdns.md
@cylonchau
Copy link
Copy Markdown
Author

thanks for @cafferata, The new commit have been fixed, and generate-all.sh has been run to refresh some generated files.

Comment on lines +66 to +68
if rc.Type == "ALIAS" {
req.RecordType = new("CNAME")
}
Copy link
Copy Markdown
Contributor

@SukkaW SukkaW May 15, 2026

Choose a reason for hiding this comment

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

Better add a code comment about why converting ALIAS to CNAME here (ALIAS('@') instead of CNAME('@') for CNAME flattening only).

DNSPod itself doesn't support ALIAS record type in any way, you need to document this.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done. I updated the code comment.

const defaultTTL = uint32(600)

var features = providers.DocumentationNotes{
providers.CanUseAlias: providers.Can(),
Copy link
Copy Markdown
Contributor

@SukkaW SukkaW May 15, 2026

Choose a reason for hiding this comment

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

Better document that canUseALIAs is Can only because this is required to work with CNAME Flattening feature (writing ALIAS('@') instead of CNAME('@')). DNSPods itself doesn't support ALIAS record type at all.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done. I updated the CanUseAlias note

Copy link
Copy Markdown
Contributor

@SukkaW SukkaW May 15, 2026

Choose a reason for hiding this comment

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

Document how to use ALIAS('@') in the provider docs:

  • If you want to add CNAME at @
  • Configure CNAME flattening at the DNSPod dashboard manually
  • Write ALIAS('@') to dnsconfig.js
  • Explain why write ALIAS('@'). DNSControl requires this because it considers CNAME('@') invalid.
  • Under the hood, this provider overwrites ALIAS to CNAME
  • Explain that DNSPod doesn't support ALIAS at all, all CNAME flattening configurations must be done via the dashboard for now.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done. I updated the docs to clarify how to use ALIAS with the tencentdns provider.

@cylonchau cylonchau requested a review from SukkaW May 16, 2026 06:24
Copy link
Copy Markdown
Collaborator

@TomOnTime TomOnTime left a comment

Choose a reason for hiding this comment

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

Looks good so far! Some notes:

  1. Please run go fix ./...

  2. Please fix golangci-lint messages

These 2 messages only appeared after running go fix

==== Running golangci-lint run ./...
providers/tencentdns/convert.go:91:6: func commonStringPtr is unused (unused)
func commonStringPtr(s string) *string {
     ^
providers/tencentdns/convert.go:96:6: func commonUint64Ptr is unused (unused)
func commonUint64Ptr(u uint64) *uint64 {
     ^

3. Run `staticcheck ./...`

Please resolve these messages:

providers/tencentdns/api.go:32:16: func parameter secretId should be secretID (ST1003)
providers/tencentdns/api.go:321:62: method parameter recordId should be recordID (ST1003)
providers/tencentdns/convert.go:67:53: func parameter recordId should be recordID (ST1003)
providers/tencentdns/convert.go:91:6: func commonStringPtr is unused (U1000)
providers/tencentdns/convert.go:96:6: func commonUint64Ptr is unused (U1000)
providers/tencentdns/tencentdnsProvider.go:89:2: var secretId should be secretID (ST1003)
providers/tencentdns/tencentdnsProvider.go:224:4: var recordId should be recordID (ST1003)
providers/tencentdns/tencentdnsProvider.go:232:4: var recordId should be recordID (ST1003)

@TomOnTime
Copy link
Copy Markdown
Collaborator

Tip: Run bin/generate-all.sh (on Linux or MacOS) will report (and sometimes fix) many issues.

@cylonchau
Copy link
Copy Markdown
Author

Hi @TomOnTime

Thanks for you suggestion, The script didn't fully run before because the required local tools were missing from my environment. I installed them, reran the script, and fixed the these notes.

Copy link
Copy Markdown
Collaborator

@TomOnTime TomOnTime left a comment

Choose a reason for hiding this comment

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

Looks good! Thank you for contributing this new provider! I'm sure it will be popular!

Faisal Misle @fm is our “liaison to maintainers”. He'll be reaching out to you to collect contact info (don't be surprised when this mystery person asks you for your email address).

@TomOnTime TomOnTime requested a review from fm May 17, 2026 12:49
@fm
Copy link
Copy Markdown

fm commented May 18, 2026

Hi @cylonchau

Thank you for becoming the new maintainer for Tencent Cloud DNS.

We want to make sure this is the address you'd like to be reached at regarding maintainer communications. Your email will not be public and will only be used the the project team to send out maintainer communications. Can you email dnscontrol at faisal dot fm from your preferred address?

As a maintainer, we’d like to remind you of your role and expectations we have so that everyone has a positive experience using dnscontrol:

  • Maintainers are expected to support their provider. If a maintainer is no longer able to maintain a provider, they should suggest a replacement or if no replacement is available, the maintainer shall let the maintainer liaison know so they can put out a call for volunteers.
  • Maintainers must be responsible to bug reports and PRs for their provider.
  • Maintainers should set up test accounts and periodically verify that all tests pass (pkg/js/parse_tests and integrationTest), especially when new features are added or changed in the core product.
  • Contributors are encouraged to add new tests and refine old ones. (Test-driven development is encouraged.)

If there is anything we can help with, or help unblock, as you maintain your provider please don’t hesitate to reach out.

@cylonchau
Copy link
Copy Markdown
Author

Hi @fm

I’ve just sent the email from my preferred address. Thank you for the reminder and for the guidance.

@TomOnTime
Copy link
Copy Markdown
Collaborator

Please resolve conflicts and run bin/generate-all.sh so I can merge. Thx!

cylonchau added 4 commits May 20, 2026 09:53
…registrar

Add support for Tencent Cloud DNS (encentdns/dnspod) as both DNS provider
and registrar using the official Tencent Cloud API 3.0.
Features:
- DNS Provider: Full CRUD for A, AAAA, CNAME, MX, NS, TXT, CAA, SRV records
- Registrar: Nameserver delegation management at the registry level
- Apex CNAME support: Seamlessly maps ALIAS records to Tencent's apex CNAME
- Zone management: Supports automatic zone creation (EnsureZoneExists)
- Zone listing: Supports the get-zones command for easy migration
- Incremental updates: Full support for NO_PURGE and IGNORE via diff2 engine
Technical details:
- Based on tencentcloud-sdk-go (API 3.0)
- Implements RecordAuditor to comply with DNSControl v4 requirements
- Handles free-tier limitations (TTL minimum 600s) automatically
Documentation and CI/CD configuration (GitHub Actions profiles) included.
- Implement RegisterCredsMetadata for dnscontrol init
- Rewrite low TTLs before diff2 using dnspod package limits
- Add cn/intl site selection for dns and registrar API
- Poll registrar batch operations and surface failures
- Add docs and focused unit tests
- Add code comments explaining that DNSPod does not support a native ALIAS record
- Document how to use ALIAS for DNSPod CNAME flattening.
@cylonchau
Copy link
Copy Markdown
Author

Please resolve conflicts and run bin/generate-all.sh so I can merge. Thx!

The conflict has been resolved. Thanks for your reminder.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

provider-request provider-TENCENTDNS Tencent Cloud DNS provider

Development

Successfully merging this pull request may close these issues.

Add Tencent Cloud DNS

6 participants