NEW PROVIDER: Tencent Cloud DNS (TENCENTDNS/DNSPOD) provider and registrar#4237
NEW PROVIDER: Tencent Cloud DNS (TENCENTDNS/DNSPOD) provider and registrar#4237cylonchau wants to merge 4 commits into
Conversation
|
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. |
|
@cylonchau I noticed that there are many 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 |
SukkaW
left a comment
There was a problem hiding this comment.
Handle invalid TTL, either with a validator rejectIf to reject invalid TTL, or silently re-write TTL before feeding records to diff2.
|
Optionally: since #4208 landed before this PR, would you be open to implementing |
906689e to
936b39a
Compare
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 |
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 You can look at other providers as examples. Most have a function called fixTTL(). |
936b39a to
3332de9
Compare
|
Hi all, thanks for the reviews and helpful suggestions. new submit i am fix some issue and suggestion
Tested with (intl) : Add zone and some recordcreate-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 errorspush 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 recordgoldstains@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 NSThe 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 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 |
3332de9 to
a60c2c3
Compare
cafferata
left a comment
There was a problem hiding this comment.
Thanks for addressing the feedback and adding the optional RegisterCredsMetadata()! Two small inline comments, otherwise LGTM from my side.
a60c2c3 to
cb52553
Compare
|
thanks for @cafferata, The new commit have been fixed, and generate-all.sh has been run to refresh some generated files. |
| if rc.Type == "ALIAS" { | ||
| req.RecordType = new("CNAME") | ||
| } |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Done. I updated the code comment.
| const defaultTTL = uint32(600) | ||
|
|
||
| var features = providers.DocumentationNotes{ | ||
| providers.CanUseAlias: providers.Can(), |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Done. I updated the CanUseAlias note
There was a problem hiding this comment.
Document how to use ALIAS('@') in the provider docs:
- If you want to add
CNAMEat@ - Configure CNAME flattening at the DNSPod dashboard manually
- Write
ALIAS('@')todnsconfig.js - Explain why write
ALIAS('@'). DNSControl requires this because it considersCNAME('@')invalid. - Under the hood, this provider overwrites
ALIAStoCNAME - Explain that DNSPod doesn't support
ALIASat all, all CNAME flattening configurations must be done via the dashboard for now.
There was a problem hiding this comment.
Done. I updated the docs to clarify how to use ALIAS with the tencentdns provider.
TomOnTime
left a comment
There was a problem hiding this comment.
Looks good so far! Some notes:
-
Please run
go fix ./... -
Please fix
golangci-lintmessages
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)
|
Tip: Run |
ce238f3 to
d39f4a5
Compare
|
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. |
TomOnTime
left a comment
There was a problem hiding this comment.
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).
|
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:
If there is anything we can help with, or help unblock, as you maintain your provider please don’t hesitate to reach out. |
|
Hi @fm I’ve just sent the email from my preferred address. Thank you for the reminder and for the guidance. |
|
Please resolve conflicts and run |
…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.
d39f4a5 to
3a32648
Compare
The conflict has been resolved. Thanks for your reminder. |



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:
EnsureZoneExistsRecordAuditorThe implementation uses Tencent Cloud's official Go SDK with the modern API 3.0 endpoints:
v20210323(Tencent still continue maintain this sdk, date only a lable, this version is latest)v20180808(Tencent still continue maintain this sdk, date only a lable, this version is latest)Fixes #4171
Test record
add record test
delete record test
add zone test