yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/aliyun/dns_domain.go (about) 1 // Copyright 2019 Yunion 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package aliyun 16 17 import ( 18 "strconv" 19 20 "yunion.io/x/jsonutils" 21 "yunion.io/x/log" 22 "yunion.io/x/pkg/errors" 23 24 api "yunion.io/x/cloudmux/pkg/apis/compute" 25 "yunion.io/x/cloudmux/pkg/cloudprovider" 26 "yunion.io/x/cloudmux/pkg/multicloud" 27 ) 28 29 type SDomain struct { 30 multicloud.SResourceBase 31 AliyunTags 32 client *SAliyunClient 33 ttlMinValue int64 34 PunyCode string `json:"PunyCode"` 35 VersionCode string `json:"VersionCode"` 36 InstanceID string `json:"InstanceId"` 37 AliDomain bool `json:"AliDomain"` 38 DomainName string `json:"DomainName"` 39 DomainID string `json:"DomainId"` 40 DNSServers DNSServers `json:"DnsServers"` 41 GroupID string `json:"GroupId"` 42 } 43 44 type SDomains struct { 45 PageNumber int `json:"PageNumber"` 46 TotalCount int `json:"TotalCount"` 47 PageSize int `json:"PageSize"` 48 // RequestID string `json:"RequestId"` 49 Domains sDomains `json:"Domains"` 50 } 51 52 type DNSServers struct { 53 DNSServer []string `json:"DnsServer"` 54 } 55 56 type sDomains struct { 57 Domain []SDomain `json:"Domain"` 58 } 59 60 // https://help.aliyun.com/document_detail/29758.html?spm=a2c4g.11186623.6.653.2ad93b59euq4oF 61 type SDNSProduct struct { 62 client *SAliyunClient 63 InstanceID string `json:"InstanceId"` 64 VersionCode string `json:"VersionCode"` 65 VersionName string `json:"VersionName"` 66 StartTime int64 `json:"StartTime"` 67 EndTime int64 `json:"EndTime"` 68 Domain string `json:"Domain"` 69 BindCount int64 `json:"BindCount"` 70 BindUsedCount int64 `json:"BindUsedCount"` 71 TTLMinValue int64 `json:"TTLMinValue"` 72 SubDomainLevel int64 `json:"SubDomainLevel"` 73 DNSSLBCount int64 `json:"DnsSLBCount"` 74 URLForwardCount int64 `json:"URLForwardCount"` 75 DDosDefendFlow int64 `json:"DDosDefendFlow"` 76 DDosDefendQuery int64 `json:"DDosDefendQuery"` 77 OverseaDDosDefendFlow int64 `json:"OverseaDDosDefendFlow"` 78 SearchEngineLines string `json:"SearchEngineLines"` 79 ISPLines string `json:"ISPLines"` 80 ISPRegionLines string `json:"ISPRegionLines"` 81 OverseaLine string `json:"OverseaLine"` 82 } 83 84 type sDNSProducts struct { 85 DNSProduct []SDNSProduct `json:"DnsProduct"` 86 } 87 88 type SDNSProducts struct { 89 // RequestID string `json:"RequestId"` 90 TotalCount int `json:"TotalCount"` 91 PageNumber int `json:"PageNumber"` 92 PageSize int `json:"PageSize"` 93 DNSProducts sDNSProducts `json:"DnsProducts"` 94 } 95 96 // https://help.aliyun.com/document_detail/29758.html?spm=a2c4g.11186623.6.653.4b6d6970WphX2t 97 func (client *SAliyunClient) DescribeDnsProductInstances(pageNumber int, pageSize int) (SDNSProducts, error) { 98 sproducts := SDNSProducts{} 99 params := map[string]string{} 100 params["Action"] = "DescribeDnsProductInstances" 101 params["PageNumber"] = strconv.Itoa(pageNumber) 102 params["PageSize"] = strconv.Itoa(pageSize) 103 resp, err := client.alidnsRequest("DescribeDnsProductInstances", params) 104 if err != nil { 105 return sproducts, errors.Wrap(err, "DescribeDnsProductInstances") 106 } 107 err = resp.Unmarshal(&sproducts, "DnsProducts") 108 if err != nil { 109 return sproducts, errors.Wrap(err, "resp.Unmarshal") 110 } 111 return sproducts, nil 112 } 113 114 func (client *SAliyunClient) GetAllDnsProductInstances() ([]SDNSProduct, error) { 115 pageNumber := 0 116 sproducts := []SDNSProduct{} 117 for { 118 pageNumber++ 119 products, err := client.DescribeDnsProductInstances(pageNumber, 20) 120 if err != nil { 121 return nil, errors.Wrapf(err, "client.DescribeDnsProductInstances(%d, 20)", pageNumber) 122 } 123 sproducts = append(sproducts, products.DNSProducts.DNSProduct...) 124 if len(sproducts) >= products.TotalCount { 125 break 126 } 127 } 128 for i := 0; i < len(sproducts); i++ { 129 sproducts[i].client = client 130 } 131 return sproducts, nil 132 } 133 134 // https://help.aliyun.com/document_detail/29751.html?spm=a2c4g.11186623.6.638.55563230d00kzJ 135 func (client *SAliyunClient) DescribeDomains(pageNumber int, pageSize int) (SDomains, error) { 136 sdomains := SDomains{} 137 params := map[string]string{} 138 params["Action"] = "DescribeDomains" 139 params["PageNumber"] = strconv.Itoa(pageNumber) 140 params["PageSize"] = strconv.Itoa(pageSize) 141 resp, err := client.alidnsRequest("DescribeDomains", params) 142 if err != nil { 143 return sdomains, errors.Wrap(err, "DescribeDomains") 144 } 145 err = resp.Unmarshal(&sdomains) 146 if err != nil { 147 return sdomains, errors.Wrap(err, "resp.Unmarshal") 148 } 149 return sdomains, nil 150 } 151 152 func (client *SAliyunClient) GetAllDomains() ([]SDomain, error) { 153 pageNumber := 0 154 sdomains := []SDomain{} 155 for { 156 pageNumber += 1 157 domains, err := client.DescribeDomains(pageNumber, 20) 158 if err != nil { 159 return nil, errors.Wrapf(err, "client.DescribeDomains(%d, 20)", pageNumber) 160 } 161 sdomains = append(sdomains, domains.Domains.Domain...) 162 if len(sdomains) >= domains.TotalCount { 163 break 164 } 165 } 166 for i := 0; i < len(sdomains); i++ { 167 sdomains[i].client = client 168 } 169 return sdomains, nil 170 } 171 172 func (client *SAliyunClient) GetPublicICloudDnsZones() ([]cloudprovider.ICloudDnsZone, error) { 173 izones := []cloudprovider.ICloudDnsZone{} 174 sdomains, err := client.GetAllDomains() 175 if err != nil { 176 return nil, errors.Wrap(err, "client.GetAllDomains()") 177 } 178 for i := 0; i < len(sdomains); i++ { 179 izones = append(izones, &sdomains[i]) 180 } 181 return izones, nil 182 } 183 184 func (client *SAliyunClient) DescribeDomainInfo(domainName string) (*SDomain, error) { 185 sdomain := &SDomain{client: client} 186 params := map[string]string{} 187 params["Action"] = "DescribeDomainInfo" 188 params["DomainName"] = domainName 189 resp, err := client.alidnsRequest("DescribeDomainInfo", params) 190 if err != nil { 191 return sdomain, errors.Wrap(err, "DescribeDomainInfo") 192 } 193 err = resp.Unmarshal(sdomain) 194 if err != nil { 195 return sdomain, errors.Wrap(err, "resp.Unmarshal") 196 } 197 return sdomain, nil 198 } 199 200 func (client *SAliyunClient) GetPublicICloudDnsZoneById(id string) (cloudprovider.ICloudDnsZone, error) { 201 izones, err := client.GetPublicICloudDnsZones() 202 if err != nil { 203 return nil, errors.Wrapf(err, "client.DescribeDomainInfo(%s)", id) 204 } 205 for i := 0; i < len(izones); i++ { 206 if izones[i].GetGlobalId() == id { 207 return izones[i], nil 208 } 209 } 210 return nil, cloudprovider.ErrNotFound 211 } 212 213 func (client *SAliyunClient) AddDomain(domainName string) (*SDomain, error) { 214 sdomain := &SDomain{client: client} 215 params := map[string]string{} 216 params["Action"] = "AddDomain" 217 params["DomainName"] = domainName 218 resp, err := client.alidnsRequest("AddDomain", params) 219 if err != nil { 220 return sdomain, errors.Wrap(err, "AddDomain") 221 } 222 err = resp.Unmarshal(sdomain) 223 if err != nil { 224 return sdomain, errors.Wrapf(err, "%s:resp.Unmarshal()", resp) 225 } 226 return sdomain, nil 227 } 228 229 func (client *SAliyunClient) CreatePublicICloudDnsZone(opts *cloudprovider.SDnsZoneCreateOptions) (cloudprovider.ICloudDnsZone, error) { 230 sdomain, err := client.AddDomain(opts.Name) 231 if err != nil { 232 return nil, errors.Wrapf(err, "client.AddDomain(%s)", opts.Name) 233 } 234 return sdomain, nil 235 } 236 237 func (client *SAliyunClient) DeleteDomain(domainName string) error { 238 params := map[string]string{} 239 params["Action"] = "DeleteDomain" 240 params["DomainName"] = domainName 241 _, err := client.alidnsRequest("DeleteDomain", params) 242 if err != nil { 243 return errors.Wrap(err, "DeleteDomain") 244 } 245 return nil 246 } 247 248 func (self *SDomain) GetId() string { 249 return self.DomainID 250 } 251 252 func (self *SDomain) GetName() string { 253 if len(self.PunyCode) > 0 { 254 return self.PunyCode 255 } 256 return self.DomainName 257 } 258 259 func (self *SDomain) GetGlobalId() string { 260 return self.GetId() 261 } 262 263 func (self *SDomain) GetStatus() string { 264 return api.DNS_ZONE_STATUS_AVAILABLE 265 } 266 267 func (self *SDomain) Refresh() error { 268 sdomain, err := self.client.DescribeDomainInfo(self.DomainName) 269 if err != nil { 270 return errors.Wrapf(err, "self.client.DescribeDomainInfo(%s)", self.DomainName) 271 } 272 return jsonutils.Update(self, sdomain) 273 } 274 275 func (self *SDomain) GetZoneType() cloudprovider.TDnsZoneType { 276 return cloudprovider.PublicZone 277 } 278 func (self *SDomain) GetOptions() *jsonutils.JSONDict { 279 return nil 280 } 281 282 func (self *SDomain) GetICloudVpcIds() ([]string, error) { 283 return nil, nil 284 } 285 func (self *SDomain) AddVpc(vpc *cloudprovider.SPrivateZoneVpc) error { 286 return cloudprovider.ErrNotSupported 287 } 288 func (self *SDomain) RemoveVpc(vpc *cloudprovider.SPrivateZoneVpc) error { 289 return cloudprovider.ErrNotSupported 290 } 291 292 func (self *SDomain) GetIDnsRecordSets() ([]cloudprovider.ICloudDnsRecordSet, error) { 293 irecords := []cloudprovider.ICloudDnsRecordSet{} 294 records, err := self.client.GetAllDomainRecords(self.DomainName) 295 if err != nil { 296 return nil, errors.Wrapf(err, "self.client.GetAllDomainRecords(%s)", self.DomainName) 297 } 298 for i := 0; i < len(records); i++ { 299 irecords = append(irecords, &records[i]) 300 } 301 return irecords, nil 302 } 303 304 func (self *SDomain) SyncDnsRecordSets(common, add, del, update []cloudprovider.DnsRecordSet) error { 305 for i := 0; i < len(common); i++ { 306 if len(common[i].Desc) > 0 { 307 err := self.client.UpdateDomainRecordRemark(common[i].ExternalId, common[i].Desc) 308 if err != nil { 309 return errors.Wrapf(err, "UpdateDomainRecordRemark") 310 } 311 } 312 } 313 for i := 0; i < len(del); i++ { 314 err := self.client.DeleteDomainRecord(del[i].ExternalId) 315 if err != nil { 316 return errors.Wrapf(err, "self.client.DeleteDomainRecord(%s)", del[i].ExternalId) 317 } 318 } 319 320 for i := 0; i < len(add); i++ { 321 recordId, err := self.client.AddDomainRecord(self.DomainName, add[i]) 322 if err != nil { 323 return errors.Wrapf(err, "self.client.AddDomainRecord(%s,%s)", self.DomainName, jsonutils.Marshal(add[i]).String()) 324 } 325 if !add[i].Enabled { 326 // Enable: 启用解析 Disable: 暂停解析 327 err = self.client.SetDomainRecordStatus(recordId, "Disable") 328 if err != nil { 329 return errors.Wrapf(err, "self.client.SetDomainRecordStatus(%s,%t)", recordId, add[i].Enabled) 330 } 331 } 332 if len(add[i].Desc) > 0 { 333 err = self.client.UpdateDomainRecordRemark(recordId, add[i].Desc) 334 if err != nil { 335 return errors.Wrapf(err, "UpdateDomainRecordRemark") 336 } 337 } 338 } 339 340 for i := 0; i < len(update); i++ { 341 // Enable: 启用解析 Disable: 暂停解析 342 status := "Enable" 343 if !update[i].Enabled { 344 status = "Disable" 345 } 346 err := self.client.SetDomainRecordStatus(update[i].ExternalId, status) 347 if err != nil { 348 return errors.Wrapf(err, "self.client.SetDomainRecordStatus(%s,%t)", update[i].ExternalId, update[i].Enabled) 349 } 350 domainRecord, err := self.client.DescribeDomainRecordInfo(update[i].ExternalId) 351 if err != nil { 352 return errors.Wrapf(err, "self.client.DescribeDomainRecordInfo(%s)", update[i].ExternalId) 353 } 354 if !domainRecord.match(update[i]) { 355 err = self.client.UpdateDomainRecord(update[i]) 356 if err != nil { 357 return errors.Wrapf(err, "self.client.UpdateDomainRecord(%s)", jsonutils.Marshal(update[i]).String()) 358 } 359 } 360 if len(update[i].Desc) > 0 { 361 err = self.client.UpdateDomainRecordRemark(update[i].ExternalId, update[i].Desc) 362 if err != nil { 363 return errors.Wrapf(err, "UpdateDomainRecordRemark") 364 } 365 } 366 } 367 return nil 368 } 369 370 func (self *SDomain) Delete() error { 371 return self.client.DeleteDomain(self.DomainName) 372 } 373 374 func TDnsProductType(productName string) cloudprovider.TDnsProductType { 375 switch productName { 376 case "企业旗舰版": 377 return cloudprovider.DnsProductEnterpriseUltimate 378 case "企业标准版": 379 return cloudprovider.DnsProductEnterpriseStandard 380 case "个人版": 381 return cloudprovider.DnsProductPersonalProfessional 382 default: 383 return cloudprovider.DnsProductFree 384 } 385 } 386 387 func (self *SDomain) GetDnsProductType() cloudprovider.TDnsProductType { 388 sproducts, err := self.client.GetAllDnsProductInstances() 389 if err != nil { 390 log.Errorf("self.client.GetAllDnsProductInstances():%s", err) 391 return cloudprovider.DnsProductFree 392 } 393 // https://help.aliyun.com/document_detail/29806.html?spm=a2c4g.11186623.4.1.67728197c8SCN9 394 // 免费版,最低600 395 self.ttlMinValue = 600 396 for i := 0; i < len(sproducts); i++ { 397 if sproducts[i].Domain == self.DomainName { 398 return TDnsProductType(sproducts[i].VersionName) 399 } 400 } 401 return cloudprovider.DnsProductFree 402 } 403 404 func (self *SDomain) fetchTTLMinValue() (int64, error) { 405 if self.ttlMinValue != 0 { 406 return self.ttlMinValue, nil 407 } 408 sproducts, err := self.client.GetAllDnsProductInstances() 409 if err != nil { 410 return 0, errors.Wrap(err, "self.client.GetAllDnsProductInstances()") 411 } 412 // https://help.aliyun.com/document_detail/29806.html?spm=a2c4g.11186623.4.1.67728197c8SCN9 413 // 免费版,最低600 414 self.ttlMinValue = 600 415 for i := 0; i < len(sproducts); i++ { 416 if sproducts[i].Domain == self.DomainName { 417 self.ttlMinValue = sproducts[i].TTLMinValue 418 return self.ttlMinValue, nil 419 } 420 } 421 return self.ttlMinValue, nil 422 } 423 424 func (self *SDomain) GetProperlyTTL(ttl int64) int64 { 425 ttlMin, err := self.fetchTTLMinValue() 426 if err != nil { 427 log.Errorf("self.fetchTTLMinValue():%s", err) 428 ttlMin = 600 429 } 430 if ttl <= ttlMin { 431 return ttlMin 432 } 433 if ttl > 86400 { 434 return 86400 435 } 436 return ttl 437 }