mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2025-02-25 08:02:58 +08:00
174 lines
5 KiB
Go
174 lines
5 KiB
Go
package huaweicloud
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/StackExchange/dnscontrol/v4/models"
|
|
"github.com/StackExchange/dnscontrol/v4/pkg/printer"
|
|
"github.com/StackExchange/dnscontrol/v4/providers"
|
|
"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic"
|
|
"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/region"
|
|
dnssdk "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/dns/v2"
|
|
"github.com/huaweicloud/huaweicloud-sdk-go-v3/services/dns/v2/model"
|
|
dnsRegion "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/dns/v2/region"
|
|
)
|
|
|
|
// Support for Huawei Cloud DNS.
|
|
// API Documentation: https://www.huaweicloud.com/intl/en-us/product/dns.html
|
|
|
|
/*
|
|
Huaweicloud API DNS provider:
|
|
|
|
Info required in `creds.json`:
|
|
- KeyId
|
|
- SecretKey
|
|
- Region
|
|
|
|
Record level metadata available:
|
|
- hw_line (refer below Huawei Cloud DNS API documentation for available lines, default "default_view")
|
|
(https://support.huaweicloud.com/intl/en-us/api-dns/en-us_topic_0085546214.html)
|
|
- hw_weight (0-1000, default "1")
|
|
- hw_rrset_key (default "")
|
|
|
|
*/
|
|
|
|
type huaweicloudProvider struct {
|
|
client *dnssdk.DnsClient
|
|
domainByZoneID map[string]string
|
|
zoneIDByDomain map[string]string
|
|
region *region.Region
|
|
}
|
|
|
|
const (
|
|
metaWeight = "hw_weight"
|
|
metaLine = "hw_line"
|
|
metaKey = "hw_rrset_key"
|
|
defaultWeight = "1"
|
|
defaultLine = "default_view"
|
|
)
|
|
|
|
// newHuaweicloud creates the provider.
|
|
func newHuaweicloud(m map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) {
|
|
auth, err := basic.NewCredentialsBuilder().
|
|
WithAk(m["KeyId"]).
|
|
WithSk(m["SecretKey"]).
|
|
SafeBuild()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
region, err := dnsRegion.SafeValueOf(m["Region"])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
client, err := dnssdk.DnsClientBuilder().
|
|
WithRegion(region).
|
|
WithCredential(auth).
|
|
SafeBuild()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
c := &huaweicloudProvider{
|
|
client: dnssdk.NewDnsClient(client),
|
|
region: region,
|
|
}
|
|
|
|
return c, nil
|
|
}
|
|
|
|
var features = providers.DocumentationNotes{
|
|
// The default for unlisted capabilities is 'Cannot'.
|
|
// See providers/capabilities.go for the entire list of capabilities.
|
|
providers.CanAutoDNSSEC: providers.Unimplemented("No public api provided, but can be turned on manually in the console."),
|
|
providers.CanGetZones: providers.Can(),
|
|
providers.CanUseAlias: providers.Cannot(),
|
|
providers.CanUseCAA: providers.Can(),
|
|
providers.CanUseDS: providers.Cannot(),
|
|
providers.CanUseLOC: providers.Cannot(),
|
|
providers.CanUseNAPTR: providers.Cannot(),
|
|
providers.CanUsePTR: providers.Cannot(),
|
|
providers.CanUseSRV: providers.Can(),
|
|
providers.CanUseSSHFP: providers.Cannot(),
|
|
providers.CanUseTLSA: providers.Cannot(),
|
|
providers.CanUseHTTPS: providers.Cannot(),
|
|
providers.CanUseSVCB: providers.Cannot(),
|
|
providers.CanUseSOA: providers.Cannot(),
|
|
providers.DocCreateDomains: providers.Can(),
|
|
providers.DocDualHost: providers.Can(),
|
|
providers.DocOfficiallySupported: providers.Cannot(),
|
|
}
|
|
|
|
var defaultNameServerNames = []string{
|
|
// DNS server for regions in the Chinese mainland
|
|
"ns1.huaweicloud-dns.com.",
|
|
"ns1.huaweicloud-dns.cn.",
|
|
// DNS server for countries or regions outside the Chinese mainland
|
|
"ns1.huaweicloud-dns.net.",
|
|
"ns1.huaweicloud-dns.org.",
|
|
}
|
|
|
|
func init() {
|
|
const providerName = "HUAWEICLOUD"
|
|
const providerMaintainer = "@huihuimoe"
|
|
fns := providers.DspFuncs{
|
|
Initializer: newHuaweicloud,
|
|
RecordAuditor: AuditRecords,
|
|
}
|
|
providers.RegisterDomainServiceProviderType(providerName, fns, features)
|
|
providers.RegisterMaintainer(providerName, providerMaintainer)
|
|
}
|
|
|
|
// huaweicloud has request limiting like above.
|
|
// "The throttling threshold has been reached: policy user over ratelimit,limit:100,time:1 minute"
|
|
func withRetry(f func() error) {
|
|
const maxRetries = 23
|
|
const sleepTime = 5 * time.Second
|
|
var currentRetry int
|
|
for {
|
|
err := f()
|
|
if err == nil {
|
|
return
|
|
}
|
|
if strings.Contains(err.Error(), "over ratelimit") {
|
|
currentRetry++
|
|
if currentRetry >= maxRetries {
|
|
return
|
|
}
|
|
printer.Printf("Huaweicloud rate limit exceeded. Waiting %s to retry.\n", sleepTime)
|
|
time.Sleep(sleepTime)
|
|
} else {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// GetNameservers returns the nameservers for a domain.
|
|
func (c *huaweicloudProvider) GetNameservers(domain string) ([]*models.Nameserver, error) {
|
|
if err := c.getZones(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
payload := &model.ShowPublicZoneNameServerRequest{
|
|
ZoneId: c.zoneIDByDomain[domain],
|
|
}
|
|
res, err := c.client.ShowPublicZoneNameServer(payload)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
nameservers := []string{}
|
|
if res.Nameservers != nil {
|
|
for _, record := range *res.Nameservers {
|
|
if record.Hostname != nil {
|
|
nameservers = append(nameservers, *record.Hostname)
|
|
}
|
|
}
|
|
}
|
|
if len(nameservers) != 0 {
|
|
return models.ToNameserversStripTD(nameservers)
|
|
}
|
|
|
|
return models.ToNameserversStripTD(defaultNameServerNames)
|
|
}
|