diff --git a/dns/huawei.go b/dns/huawei.go index e648ffe..717f06e 100644 --- a/dns/huawei.go +++ b/dns/huawei.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "net/http" + "net/url" "strconv" "github.com/jeessy2/ddns-go/v6/config" @@ -46,6 +47,7 @@ type HuaweicloudRecordsets struct { Type string `json:"type"` TTL int `json:"ttl"` Records []string `json:"records"` + Weight int `json:"weight"` } // Init 初始化 @@ -82,38 +84,81 @@ func (hw *Huaweicloud) addUpdateDomainRecords(recordType string) { } for _, domain := range domains { + customParams := domain.GetCustomParams() + params := url.Values{} + params.Set("name", domain.String()) + params.Set("type", recordType) - var records HuaweicloudRecordsResp + // 如果有精准匹配 + // 详见 查询记录集 https://support.huaweicloud.com/api-dns/dns_api_64002.html + if customParams.Has("zone_id") && customParams.Has("recordset_id") { + var record HuaweicloudRecordsets + err := hw.request( + "GET", + fmt.Sprintf(huaweicloudEndpoint+"/v2.1/zones/%s/recordsets/%s", customParams.Get("zone_id"), customParams.Get("recordset_id")), + params, + &record, + ) - err := hw.request( - "GET", - fmt.Sprintf(huaweicloudEndpoint+"/v2/recordsets?type=%s&name=%s", recordType, domain), - nil, - &records, - ) + if err != nil { + util.Log("查询域名信息发生异常! %s", err) + domain.UpdateStatus = config.UpdatedFailed + return + } - if err != nil { - util.Log("查询域名信息发生异常! %s", err) - domain.UpdateStatus = config.UpdatedFailed - return - } + // 更新 + hw.modify(record, domain, ipAddr) - find := false - for _, record := range records.Recordsets { - // 名称相同才更新。华为云默认是模糊搜索 - if record.Name == domain.String()+"." { - // 更新 - hw.modify(record, domain, ipAddr) - find = true - break + } else { // 没有精准匹配,则支持更多的查询参数。详见 查询租户记录集列表 https://support.huaweicloud.com/api-dns/dns_api_64003.html + // 复制所有自定义参数 + util.CopyUrlParams(customParams, params, nil) + // 参数名修正 + if params.Has("recordset_id") { + params.Set("id", params.Get("recordset_id")) + params.Del("recordset_id") + } + + var records HuaweicloudRecordsResp + err := hw.request( + "GET", + huaweicloudEndpoint+"/v2.1/recordsets", + params, + &records, + ) + + if err != nil { + util.Log("查询域名信息发生异常! %s", err) + domain.UpdateStatus = config.UpdatedFailed + return + } + + find := false + for _, record := range records.Recordsets { + // 名称相同才更新。华为云默认是模糊搜索 + if record.Name == domain.String()+"." { + // 更新 + hw.modify(record, domain, ipAddr) + find = true + break + } + } + + if !find { + thIdParamName := "" + if customParams.Has("id") { + thIdParamName = "id" + } else if customParams.Has("recordset_id") { + thIdParamName = "recordset_id" + } + + if thIdParamName != "" { + util.Log("域名 %s 解析未找到,且因添加了参数 %s=%s 导致无法创建。本次更新已被忽略", domain, thIdParamName, customParams.Get(thIdParamName)) + } else { + // 新增 + hw.create(domain, recordType, ipAddr) + } } } - - if !find { - // 新增 - hw.create(domain, recordType, ipAddr) - } - } } @@ -145,11 +190,12 @@ func (hw *Huaweicloud) create(domain *config.Domain, recordType string, ipAddr s Name: domain.String() + ".", Records: []string{ipAddr}, TTL: hw.TTL, + Weight: 1, } var result HuaweicloudRecordsets err = hw.request( "POST", - fmt.Sprintf(huaweicloudEndpoint+"/v2/zones/%s/recordsets", zoneID), + fmt.Sprintf(huaweicloudEndpoint+"/v2.1/zones/%s/recordsets", zoneID), record, &result, ) @@ -178,7 +224,9 @@ func (hw *Huaweicloud) modify(record HuaweicloudRecordsets, domain *config.Domai return } - var request map[string]interface{} = make(map[string]interface{}) + var request = make(map[string]interface{}) + request["name"] = record.Name + request["type"] = record.Type request["records"] = []string{ipAddr} request["ttl"] = hw.TTL @@ -186,7 +234,7 @@ func (hw *Huaweicloud) modify(record HuaweicloudRecordsets, domain *config.Domai err := hw.request( "PUT", - fmt.Sprintf(huaweicloudEndpoint+"/v2/zones/%s/recordsets/%s", record.ZoneID, record.ID), + fmt.Sprintf(huaweicloudEndpoint+"/v2.1/zones/%s/recordsets/%s", record.ZoneID, record.ID), &request, &result, ) @@ -210,8 +258,8 @@ func (hw *Huaweicloud) modify(record HuaweicloudRecordsets, domain *config.Domai func (hw *Huaweicloud) getZones(domain *config.Domain) (result HuaweicloudZonesResp, err error) { err = hw.request( "GET", - fmt.Sprintf(huaweicloudEndpoint+"/v2/zones?name=%s", domain.DomainName), - nil, + huaweicloudEndpoint+"/v2/zones", + url.Values{"name": []string{domain.DomainName}}, &result, ) @@ -219,18 +267,32 @@ func (hw *Huaweicloud) getZones(domain *config.Domain) (result HuaweicloudZonesR } // request 统一请求接口 -func (hw *Huaweicloud) request(method string, url string, data interface{}, result interface{}) (err error) { - jsonStr := make([]byte, 0) - if data != nil { - jsonStr, _ = json.Marshal(data) - } - - req, err := http.NewRequest( - method, - url, - bytes.NewBuffer(jsonStr), +func (hw *Huaweicloud) request(method string, urlString string, data interface{}, result interface{}) (err error) { + var ( + req *http.Request ) + if method == "GET" { + req, err = http.NewRequest( + method, + urlString, + bytes.NewBuffer(nil), + ) + + req.URL.RawQuery = data.(url.Values).Encode() + } else { + jsonStr := make([]byte, 0) + if data != nil { + jsonStr, _ = json.Marshal(data) + } + + req, err = http.NewRequest( + method, + urlString, + bytes.NewBuffer(jsonStr), + ) + } + if err != nil { return } diff --git a/util/copy_url_params.go b/util/copy_url_params.go new file mode 100644 index 0000000..1347795 --- /dev/null +++ b/util/copy_url_params.go @@ -0,0 +1,18 @@ +package util + +import "net/url" + +func CopyUrlParams(src url.Values, dest url.Values, keys []string) { + if keys == nil || len(keys) == 0 { + for key := range src { + dest.Set(key, src.Get(key)) + } + } else { + for _, key := range keys { + val := src.Get(key) + if val != "" { + dest.Set(key, val) + } + } + } +} diff --git a/util/messages.go b/util/messages.go index af6eae2..984f7fc 100644 --- a/util/messages.go +++ b/util/messages.go @@ -79,6 +79,7 @@ func init() { // domains message.SetString(language.English, "域名: %s 不正确", "The domain %s is incorrect") message.SetString(language.English, "域名: %s 解析失败", "The domain %s resolution failed") + message.SetString(language.English, "域名 %s 解析未找到,且因添加了参数 %s=%s 导致无法创建。本次更新已被忽略", "DNS resolution for domain %s was not found, and the creation failed due to the added parameter %s=%s. This update has been ignored.") message.SetString(language.English, "IPv6未改变, 将等待 %d 次后与DNS服务商进行比对", "IPv6 has not changed, will wait %d times to compare with DNS provider") message.SetString(language.English, "IPv4未改变, 将等待 %d 次后与DNS服务商进行比对", "IPv4 has not changed, will wait %d times to compare with DNS provider")