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  }