yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/hcso/region.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 hcso
    16  
    17  import (
    18  	"fmt"
    19  	"net/http"
    20  	"strings"
    21  	"time"
    22  
    23  	"yunion.io/x/jsonutils"
    24  	"yunion.io/x/log"
    25  	"yunion.io/x/pkg/errors"
    26  	"yunion.io/x/pkg/util/secrules"
    27  
    28  	api "yunion.io/x/cloudmux/pkg/apis/compute"
    29  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    30  	"yunion.io/x/cloudmux/pkg/multicloud"
    31  	"yunion.io/x/cloudmux/pkg/multicloud/hcso/client"
    32  	"yunion.io/x/cloudmux/pkg/multicloud/huawei/obs"
    33  )
    34  
    35  type Locales struct {
    36  	EnUs string `json:"en-us"`
    37  	ZhCN string `json:"zh-cn"`
    38  }
    39  
    40  // https://support.huaweicloud.com/api-iam/zh-cn_topic_0067148043.html
    41  type SRegion struct {
    42  	multicloud.SRegion
    43  
    44  	client    *SHuaweiClient
    45  	ecsClient *client.Client
    46  	obsClient *obs.ObsClient // 对象存储client.请勿直接引用。
    47  
    48  	Description    string  `json:"description"`
    49  	ID             string  `json:"id"`
    50  	Locales        Locales `json:"locales"`
    51  	ParentRegionID string  `json:"parent_region_id"`
    52  	Type           string  `json:"type"`
    53  
    54  	izones []cloudprovider.ICloudZone
    55  	ivpcs  []cloudprovider.ICloudVpc
    56  	iskus  []cloudprovider.ICloudSku
    57  
    58  	storageCache *SStoragecache
    59  }
    60  
    61  func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) {
    62  	return nil, cloudprovider.ErrNotImplemented
    63  }
    64  
    65  func (self *SRegion) GetClient() *SHuaweiClient {
    66  	return self.client
    67  }
    68  
    69  func (self *SRegion) getECSClient() (*client.Client, error) {
    70  	var err error
    71  
    72  	if len(self.client.projectId) > 0 {
    73  		project, err := self.client.GetProjectById(self.client.projectId)
    74  		if err != nil {
    75  			return nil, err
    76  		}
    77  
    78  		regionId := strings.Split(project.Name, "_")[0]
    79  		if regionId != self.ID {
    80  			// log.Debugf("project %s not in region %s", self.client.ProjectId, self.ID)
    81  			return nil, errors.Error("region and project mismatch")
    82  		}
    83  	}
    84  
    85  	if self.ecsClient == nil {
    86  		self.ecsClient, err = self.client.newRegionAPIClient(self.ID)
    87  		if err != nil {
    88  			return nil, err
    89  		}
    90  	}
    91  
    92  	return self.ecsClient, err
    93  }
    94  
    95  func (self *SRegion) getOBSEndpoint() string {
    96  	return getOBSEndpoint(self.GetId())
    97  }
    98  
    99  func (self *SRegion) getOBSClient() (*obs.ObsClient, error) {
   100  	if self.obsClient == nil {
   101  		obsClient, err := self.client.getOBSClient(self.GetId())
   102  		if err != nil {
   103  			return nil, err
   104  		}
   105  
   106  		client := obsClient.GetClient()
   107  		ts, _ := client.Transport.(*http.Transport)
   108  		client.Transport = cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) {
   109  			if self.client.cpcfg.ReadOnly {
   110  				if req.Method == "GET" || req.Method == "HEAD" {
   111  					return nil, nil
   112  				}
   113  				return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
   114  			}
   115  			return nil, nil
   116  		})
   117  
   118  		self.obsClient = obsClient
   119  	}
   120  
   121  	return self.obsClient, nil
   122  }
   123  
   124  func (self *SRegion) fetchZones() error {
   125  	zones := make([]SZone, 0)
   126  	err := doListAll(self.ecsClient.Zones.List, nil, &zones)
   127  	if err != nil {
   128  		return err
   129  	}
   130  
   131  	self.izones = make([]cloudprovider.ICloudZone, 0)
   132  	for i := range zones {
   133  		zone := zones[i]
   134  		zone.region = self
   135  		self.izones = append(self.izones, &zone)
   136  	}
   137  	return nil
   138  }
   139  
   140  func (self *SRegion) fetchIVpcs() error {
   141  	// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090625.html
   142  	vpcs := make([]SVpc, 0)
   143  	querys := map[string]string{
   144  		"limit": "2048",
   145  	}
   146  	err := doListAllWithMarker(self.ecsClient.Vpcs.List, querys, &vpcs)
   147  	if err != nil {
   148  		return err
   149  	}
   150  
   151  	self.ivpcs = make([]cloudprovider.ICloudVpc, 0)
   152  	for i := range vpcs {
   153  		vpc := vpcs[i]
   154  		vpc.region = self
   155  		self.ivpcs = append(self.ivpcs, &vpc)
   156  	}
   157  	return nil
   158  }
   159  
   160  func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) {
   161  	if len(id) == 0 {
   162  		return nil, errors.Wrap(cloudprovider.ErrNotFound, "SRegion.GetIVMById")
   163  	}
   164  
   165  	instance, err := self.GetInstanceByID(id)
   166  	if err != nil {
   167  		return nil, err
   168  	}
   169  
   170  	zone, err := self.getZoneById(instance.OSEXTAZAvailabilityZone)
   171  	if err != nil {
   172  		return nil, errors.Wrap(err, "getZoneById")
   173  	}
   174  	instance.host = &SHost{
   175  		zone:      zone,
   176  		vms:       nil,
   177  		projectId: self.client.projectId,
   178  		Id:        instance.HostID,
   179  		Name:      instance.OSEXTSRVATTRHost,
   180  	}
   181  	return &instance, err
   182  }
   183  
   184  func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) {
   185  	return self.GetDisk(id)
   186  }
   187  
   188  func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo {
   189  	if info, ok := LatitudeAndLongitude[self.ID]; ok {
   190  		return info
   191  	}
   192  	return cloudprovider.SGeographicInfo{}
   193  }
   194  
   195  func (self *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) {
   196  	elbs, err := self.GetLoadBalancers()
   197  	if err != nil {
   198  		return nil, err
   199  	}
   200  
   201  	ielbs := make([]cloudprovider.ICloudLoadbalancer, len(elbs))
   202  	for i := range elbs {
   203  		ielbs[i] = &elbs[i]
   204  	}
   205  
   206  	return ielbs, nil
   207  }
   208  
   209  // https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561531.html
   210  func (self *SRegion) GetLoadBalancers() ([]SLoadbalancer, error) {
   211  	params := map[string]string{}
   212  	if len(self.client.projectId) > 0 {
   213  		params["project_id"] = self.client.projectId
   214  	}
   215  
   216  	ret := []SLoadbalancer{}
   217  	err := doListAll(self.ecsClient.Elb.List, params, &ret)
   218  	if err != nil {
   219  		return nil, err
   220  	}
   221  
   222  	for i := range ret {
   223  		ret[i].region = self
   224  	}
   225  
   226  	return ret, nil
   227  }
   228  
   229  func (self *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) {
   230  	elb, err := self.GetLoadBalancerById(loadbalancerId)
   231  	if err != nil {
   232  		return nil, err
   233  	}
   234  
   235  	return &elb, nil
   236  }
   237  
   238  func (self *SRegion) GetLoadBalancerById(loadbalancerId string) (SLoadbalancer, error) {
   239  	elb := SLoadbalancer{}
   240  	err := DoGet(self.ecsClient.Elb.Get, loadbalancerId, nil, &elb)
   241  	if err != nil {
   242  		return elb, err
   243  	}
   244  
   245  	elb.region = self
   246  	return elb, nil
   247  }
   248  
   249  func (self *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) {
   250  	acl, err := self.GetLoadBalancerAclById(aclId)
   251  	if err != nil {
   252  		return nil, err
   253  	}
   254  
   255  	return &acl, nil
   256  }
   257  
   258  func (self *SRegion) GetLoadBalancerAclById(aclId string) (SElbACL, error) {
   259  	acl := SElbACL{}
   260  	err := DoGet(self.ecsClient.ElbWhitelist.Get, aclId, nil, &acl)
   261  	if err != nil {
   262  		return acl, err
   263  	}
   264  
   265  	acl.region = self
   266  	return acl, nil
   267  }
   268  
   269  func (self *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) {
   270  	cert, err := self.GetLoadBalancerCertificateById(certId)
   271  	if err != nil {
   272  		return nil, err
   273  	}
   274  
   275  	return &cert, nil
   276  }
   277  
   278  func (self *SRegion) GetLoadBalancerCertificateById(certId string) (SElbCert, error) {
   279  	ret := SElbCert{}
   280  	err := DoGet(self.ecsClient.ElbCertificates.Get, certId, nil, &ret)
   281  	if err != nil {
   282  		return ret, err
   283  	}
   284  
   285  	ret.region = self
   286  	return ret, nil
   287  }
   288  
   289  func (self *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) {
   290  	ret, err := self.CreateLoadBalancerCertificate(cert)
   291  	if err != nil {
   292  		return nil, err
   293  	}
   294  
   295  	return &ret, nil
   296  }
   297  
   298  // https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561584.html
   299  func (self *SRegion) CreateLoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (SElbCert, error) {
   300  	params := jsonutils.NewDict()
   301  	params.Set("name", jsonutils.NewString(cert.Name))
   302  	params.Set("private_key", jsonutils.NewString(cert.PrivateKey))
   303  	params.Set("certificate", jsonutils.NewString(cert.Certificate))
   304  
   305  	ret := SElbCert{}
   306  	err := DoCreate(self.ecsClient.ElbCertificates.Create, params, &ret)
   307  	if err != nil {
   308  		return ret, err
   309  	}
   310  
   311  	ret.region = self
   312  	return ret, nil
   313  }
   314  
   315  func (self *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) {
   316  	ret, err := self.GetLoadBalancerAcls("")
   317  	if err != nil {
   318  		return nil, err
   319  	}
   320  
   321  	iret := make([]cloudprovider.ICloudLoadbalancerAcl, len(ret))
   322  	for i := range ret {
   323  		iret[i] = &ret[i]
   324  	}
   325  	return iret, nil
   326  }
   327  
   328  // https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561582.html
   329  func (self *SRegion) GetLoadBalancerAcls(listenerId string) ([]SElbACL, error) {
   330  	params := map[string]string{}
   331  	if len(listenerId) > 0 {
   332  		params["listener_id"] = listenerId
   333  	}
   334  
   335  	ret := []SElbACL{}
   336  	err := doListAll(self.ecsClient.ElbWhitelist.List, params, &ret)
   337  	if err != nil {
   338  		return nil, err
   339  	}
   340  
   341  	for i := range ret {
   342  		ret[i].region = self
   343  	}
   344  
   345  	return ret, nil
   346  }
   347  
   348  func (self *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) {
   349  	ret, err := self.GetLoadBalancerCertificates()
   350  	if err != nil {
   351  		return nil, err
   352  	}
   353  
   354  	iret := make([]cloudprovider.ICloudLoadbalancerCertificate, len(ret))
   355  	for i := range ret {
   356  		iret[i] = &ret[i]
   357  	}
   358  	return iret, nil
   359  }
   360  
   361  func (self *SRegion) GetLoadBalancerCertificates() ([]SElbCert, error) {
   362  	ret := []SElbCert{}
   363  	err := doListAll(self.ecsClient.ElbCertificates.List, nil, &ret)
   364  	if err != nil {
   365  		return nil, err
   366  	}
   367  
   368  	for i := range ret {
   369  		ret[i].region = self
   370  	}
   371  
   372  	return ret, nil
   373  }
   374  
   375  // https://support.huaweicloud.com/api-iam/zh-cn_topic_0057845622.html
   376  func (self *SRegion) GetId() string {
   377  	return self.ID
   378  }
   379  
   380  func (self *SRegion) GetName() string {
   381  	return fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_CN, self.Locales.ZhCN)
   382  }
   383  
   384  func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable {
   385  	en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_EN, self.Locales.EnUs)
   386  	table := cloudprovider.SModelI18nTable{}
   387  	table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en)
   388  	return table
   389  }
   390  
   391  func (self *SRegion) GetGlobalId() string {
   392  	return fmt.Sprintf("%s/%s", api.CLOUD_PROVIDER_HCSO, self.ID)
   393  }
   394  
   395  func (self *SRegion) GetStatus() string {
   396  	return api.CLOUD_REGION_STATUS_INSERVER
   397  }
   398  
   399  func (self *SRegion) Refresh() error {
   400  	return nil
   401  }
   402  
   403  func (self *SRegion) IsEmulated() bool {
   404  	return false
   405  }
   406  
   407  func (self *SRegion) GetLatitude() float32 {
   408  	if locationInfo, ok := LatitudeAndLongitude[self.ID]; ok {
   409  		return locationInfo.Latitude
   410  	}
   411  	return 0.0
   412  }
   413  
   414  func (self *SRegion) GetLongitude() float32 {
   415  	if locationInfo, ok := LatitudeAndLongitude[self.ID]; ok {
   416  		return locationInfo.Longitude
   417  	}
   418  	return 0.0
   419  }
   420  
   421  func (self *SRegion) fetchInfrastructure() error {
   422  	_, err := self.getECSClient()
   423  	if err != nil {
   424  		return err
   425  	}
   426  
   427  	if err := self.fetchZones(); err != nil {
   428  		return err
   429  	}
   430  
   431  	if err := self.fetchIVpcs(); err != nil {
   432  		return err
   433  	}
   434  
   435  	for i := 0; i < len(self.ivpcs); i += 1 {
   436  		vpc := self.ivpcs[i].(*SVpc)
   437  		wire := SWire{region: self, vpc: vpc}
   438  		vpc.addWire(&wire)
   439  
   440  		for j := 0; j < len(self.izones); j += 1 {
   441  			zone := self.izones[j].(*SZone)
   442  			zone.addWire(&wire)
   443  		}
   444  	}
   445  	return nil
   446  }
   447  
   448  func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) {
   449  	if self.izones == nil {
   450  		var err error
   451  		err = self.fetchInfrastructure()
   452  		if err != nil {
   453  			return nil, err
   454  		}
   455  	}
   456  	return self.izones, nil
   457  }
   458  
   459  func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) {
   460  	if self.ivpcs == nil {
   461  		err := self.fetchInfrastructure()
   462  		if err != nil {
   463  			return nil, err
   464  		}
   465  	}
   466  	return self.ivpcs, nil
   467  }
   468  
   469  func (self *SRegion) GetEipById(eipId string) (SEipAddress, error) {
   470  	var eip SEipAddress
   471  	err := DoGet(self.ecsClient.Eips.Get, eipId, nil, &eip)
   472  	eip.region = self
   473  	return eip, err
   474  }
   475  
   476  // 返回参数分别为eip 列表、列表长度、error。
   477  // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090598.html
   478  func (self *SRegion) GetEips() ([]SEipAddress, error) {
   479  	querys := make(map[string]string)
   480  
   481  	eips := make([]SEipAddress, 0)
   482  	err := doListAllWithMarker(self.ecsClient.Eips.List, querys, &eips)
   483  	for i := range eips {
   484  		eips[i].region = self
   485  	}
   486  	return eips, err
   487  }
   488  
   489  func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) {
   490  	_, err := self.getECSClient()
   491  	if err != nil {
   492  		return nil, err
   493  	}
   494  
   495  	eips, err := self.GetEips()
   496  	if err != nil {
   497  		return nil, err
   498  	}
   499  
   500  	ret := make([]cloudprovider.ICloudEIP, len(eips))
   501  	for i := 0; i < len(eips); i += 1 {
   502  		eips[i].region = self
   503  		ret[i] = &eips[i]
   504  	}
   505  	return ret, nil
   506  }
   507  
   508  func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) {
   509  	ivpcs, err := self.GetIVpcs()
   510  	if err != nil {
   511  		return nil, err
   512  	}
   513  	for i := 0; i < len(ivpcs); i += 1 {
   514  		if ivpcs[i].GetGlobalId() == id {
   515  			return ivpcs[i], nil
   516  		}
   517  	}
   518  	return nil, cloudprovider.ErrNotFound
   519  }
   520  
   521  func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) {
   522  	izones, err := self.GetIZones()
   523  	if err != nil {
   524  		return nil, err
   525  	}
   526  	for i := 0; i < len(izones); i += 1 {
   527  		if izones[i].GetGlobalId() == id {
   528  			return izones[i], nil
   529  		}
   530  	}
   531  	return nil, cloudprovider.ErrNotFound
   532  }
   533  
   534  func (self *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) {
   535  	eip, err := self.GetEipById(eipId)
   536  	return &eip, err
   537  }
   538  
   539  // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0060595555.html
   540  func (self *SRegion) DeleteSecurityGroup(secgroupId string) error {
   541  	return DoDelete(self.ecsClient.SecurityGroups.Delete, secgroupId, nil, nil)
   542  }
   543  
   544  func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) {
   545  	return self.GetSecurityGroupDetails(secgroupId)
   546  }
   547  
   548  func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) {
   549  	secgroups, err := self.GetSecurityGroups(opts.VpcId, opts.Name)
   550  	if err != nil {
   551  		return nil, err
   552  	}
   553  	if len(secgroups) == 0 {
   554  		return nil, cloudprovider.ErrNotFound
   555  	}
   556  	if len(secgroups) > 1 {
   557  		return nil, cloudprovider.ErrDuplicateId
   558  	}
   559  	secgroups[0].region = self
   560  	return &secgroups[0], nil
   561  }
   562  
   563  func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) {
   564  	return self.CreateSecurityGroup(conf.VpcId, conf.Name, conf.Desc)
   565  }
   566  
   567  // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090608.html
   568  func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) {
   569  	return self.CreateVpc(opts.NAME, opts.CIDR, opts.Desc)
   570  }
   571  
   572  func (self *SRegion) CreateVpc(name, cidr, desc string) (*SVpc, error) {
   573  	params := map[string]interface{}{
   574  		"vpc": map[string]string{
   575  			"name":        name,
   576  			"cidr":        cidr,
   577  			"description": desc,
   578  		},
   579  	}
   580  	vpc := &SVpc{region: self}
   581  	return vpc, DoCreate(self.ecsClient.Vpcs.Create, jsonutils.Marshal(params), vpc)
   582  }
   583  
   584  // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090596.html
   585  // size: 1Mbit/s~2000Mbit/s
   586  // bgpType: 5_telcom,5_union,5_bgp,5_sbgp.
   587  // 东北-大连:5_telcom、5_union
   588  // 华南-广州:5_sbgp
   589  // 华东-上海二:5_sbgp
   590  // 华北-北京一:5_bgp、5_sbgp
   591  // 亚太-香港:5_bgp
   592  func (self *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) {
   593  	var ctype TInternetChargeType
   594  	switch eip.ChargeType {
   595  	case api.EIP_CHARGE_TYPE_BY_TRAFFIC:
   596  		ctype = InternetChargeByTraffic
   597  	case api.EIP_CHARGE_TYPE_BY_BANDWIDTH:
   598  		ctype = InternetChargeByBandwidth
   599  	}
   600  
   601  	if len(eip.BGPType) == 0 {
   602  		eip.BGPType = "5_bgp"
   603  	}
   604  
   605  	// 华为云EIP名字最大长度64
   606  	if len(eip.Name) > 64 {
   607  		eip.Name = eip.Name[:64]
   608  	}
   609  
   610  	ieip, err := self.AllocateEIP(eip.Name, eip.BandwidthMbps, ctype, eip.BGPType, eip.ProjectId)
   611  	ieip.region = self
   612  	if err != nil {
   613  		return nil, err
   614  	}
   615  
   616  	err = cloudprovider.WaitStatus(ieip, api.EIP_STATUS_READY, 5*time.Second, 60*time.Second)
   617  	return ieip, err
   618  }
   619  
   620  func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) {
   621  	snapshots, err := self.GetSnapshots("", "")
   622  	if err != nil {
   623  		log.Errorf("self.GetSnapshots fail %s", err)
   624  		return nil, err
   625  	}
   626  
   627  	ret := make([]cloudprovider.ICloudSnapshot, len(snapshots))
   628  	for i := 0; i < len(snapshots); i += 1 {
   629  		snapshots[i].region = self
   630  		ret[i] = &snapshots[i]
   631  	}
   632  	return ret, nil
   633  }
   634  
   635  func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) {
   636  	snapshot, err := self.GetSnapshotById(snapshotId)
   637  	return &snapshot, err
   638  }
   639  
   640  func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) {
   641  	iHosts := make([]cloudprovider.ICloudHost, 0)
   642  
   643  	izones, err := self.GetIZones()
   644  	if err != nil {
   645  		return nil, err
   646  	}
   647  	for i := 0; i < len(izones); i += 1 {
   648  		iZoneHost, err := izones[i].GetIHosts()
   649  		if err != nil {
   650  			return nil, err
   651  		}
   652  		iHosts = append(iHosts, iZoneHost...)
   653  	}
   654  	return iHosts, nil
   655  }
   656  
   657  func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) {
   658  	izones, err := self.GetIZones()
   659  	if err != nil {
   660  		return nil, err
   661  	}
   662  	for i := 0; i < len(izones); i += 1 {
   663  		ihost, err := izones[i].GetIHostById(id)
   664  		if err == nil {
   665  			return ihost, nil
   666  		} else if errors.Cause(err) != cloudprovider.ErrNotFound {
   667  			return nil, err
   668  		}
   669  	}
   670  	return nil, cloudprovider.ErrNotFound
   671  }
   672  
   673  func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
   674  	iStores := make([]cloudprovider.ICloudStorage, 0)
   675  
   676  	izones, err := self.GetIZones()
   677  	if err != nil {
   678  		return nil, err
   679  	}
   680  	for i := 0; i < len(izones); i += 1 {
   681  		iZoneStores, err := izones[i].GetIStorages()
   682  		if err != nil {
   683  			return nil, err
   684  		}
   685  		iStores = append(iStores, iZoneStores...)
   686  	}
   687  	return iStores, nil
   688  }
   689  
   690  func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
   691  	izones, err := self.GetIZones()
   692  	if err != nil {
   693  		return nil, err
   694  	}
   695  	for i := 0; i < len(izones); i += 1 {
   696  		istore, err := izones[i].GetIStorageById(id)
   697  		if err == nil {
   698  			return istore, nil
   699  		} else if errors.Cause(err) != cloudprovider.ErrNotFound {
   700  			return nil, err
   701  		}
   702  	}
   703  	return nil, cloudprovider.ErrNotFound
   704  }
   705  
   706  func (self *SRegion) GetProvider() string {
   707  	return CLOUD_PROVIDER_HUAWEI
   708  }
   709  
   710  func (self *SRegion) GetCloudEnv() string {
   711  	return ""
   712  }
   713  
   714  // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090615.html
   715  // 目前desc字段并没有用到
   716  func (self *SRegion) CreateSecurityGroup(vpcId string, name string, desc string) (*SSecurityGroup, error) {
   717  	// 华为不允许创建名称为default的安全组
   718  	if strings.ToLower(name) == "default" {
   719  		name = fmt.Sprintf("%s-%s", vpcId, name)
   720  	}
   721  
   722  	params := jsonutils.NewDict()
   723  	secgroupObj := jsonutils.NewDict()
   724  	secgroupObj.Add(jsonutils.NewString(name), "name")
   725  	if len(vpcId) > 0 && vpcId != api.NORMAL_VPC_ID {
   726  		secgroupObj.Add(jsonutils.NewString(vpcId), "vpc_id")
   727  	}
   728  	params.Add(secgroupObj, "security_group")
   729  
   730  	secgroup := SSecurityGroup{region: self}
   731  	err := DoCreate(self.ecsClient.SecurityGroups.Create, params, &secgroup)
   732  	return &secgroup, err
   733  }
   734  
   735  // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0087467071.html
   736  func (self *SRegion) delSecurityGroupRule(secGrpRuleId string) error {
   737  	_, err := self.ecsClient.SecurityGroupRules.DeleteInContextWithSpec(nil, secGrpRuleId, "", nil, nil, "")
   738  	return err
   739  }
   740  
   741  func (self *SRegion) DeleteSecurityGroupRule(ruleId string) error {
   742  	return self.delSecurityGroupRule(ruleId)
   743  }
   744  
   745  func (self *SRegion) CreateSecurityGroupRule(secgroupId string, rule cloudprovider.SecurityRule) error {
   746  	return self.addSecurityGroupRules(secgroupId, rule)
   747  }
   748  
   749  // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0087451723.html
   750  // icmp port对应关系:https://support.huaweicloud.com/api-vpc/zh-cn_topic_0024109590.html
   751  func (self *SRegion) addSecurityGroupRules(secGrpId string, rule cloudprovider.SecurityRule) error {
   752  	direction := ""
   753  	if rule.Direction == secrules.SecurityRuleIngress {
   754  		direction = "ingress"
   755  	} else {
   756  		direction = "egress"
   757  	}
   758  
   759  	protocal := rule.Protocol
   760  	if rule.Protocol == secrules.PROTO_ANY {
   761  		protocal = ""
   762  	}
   763  
   764  	// imcp协议默认为any
   765  	if rule.Protocol == secrules.PROTO_ICMP {
   766  		return self.addSecurityGroupRule(secGrpId, direction, "-1", "-1", protocal, rule.IPNet.String())
   767  	}
   768  
   769  	if len(rule.Ports) > 0 {
   770  		for _, port := range rule.Ports {
   771  			portStr := fmt.Sprintf("%d", port)
   772  			err := self.addSecurityGroupRule(secGrpId, direction, portStr, portStr, protocal, rule.IPNet.String())
   773  			if err != nil {
   774  				return err
   775  			}
   776  		}
   777  	} else {
   778  		portStart := fmt.Sprintf("%d", rule.PortStart)
   779  		portEnd := fmt.Sprintf("%d", rule.PortEnd)
   780  		err := self.addSecurityGroupRule(secGrpId, direction, portStart, portEnd, protocal, rule.IPNet.String())
   781  		if err != nil {
   782  			return err
   783  		}
   784  	}
   785  
   786  	return nil
   787  }
   788  
   789  func (self *SRegion) addSecurityGroupRule(secGrpId, direction, portStart, portEnd, protocol, ipNet string) error {
   790  	params := jsonutils.NewDict()
   791  	secgroupObj := jsonutils.NewDict()
   792  	secgroupObj.Add(jsonutils.NewString(secGrpId), "security_group_id")
   793  	secgroupObj.Add(jsonutils.NewString(direction), "direction")
   794  	secgroupObj.Add(jsonutils.NewString(ipNet), "remote_ip_prefix")
   795  	secgroupObj.Add(jsonutils.NewString("IPV4"), "ethertype")
   796  	// 端口为空或者1-65535
   797  	if len(portStart) > 0 && portStart != "0" && portStart != "-1" {
   798  		secgroupObj.Add(jsonutils.NewString(portStart), "port_range_min")
   799  	}
   800  	if len(portEnd) > 0 && portEnd != "0" && portEnd != "-1" {
   801  		secgroupObj.Add(jsonutils.NewString(portEnd), "port_range_max")
   802  	}
   803  	if len(protocol) > 0 {
   804  		secgroupObj.Add(jsonutils.NewString(protocol), "protocol")
   805  	}
   806  	params.Add(secgroupObj, "security_group_rule")
   807  
   808  	rule := SecurityGroupRule{}
   809  	return DoCreate(self.ecsClient.SecurityGroupRules.Create, params, &rule)
   810  }
   811  
   812  func (self *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) {
   813  	ret, err := self.CreateLoadBalancer(loadbalancer)
   814  	if err != nil {
   815  		return nil, err
   816  	}
   817  
   818  	return &ret, nil
   819  }
   820  
   821  // https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561535.html
   822  func (self *SRegion) CreateLoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (SLoadbalancer, error) {
   823  	ret := SLoadbalancer{}
   824  	subnet, err := self.getNetwork(loadbalancer.NetworkIDs[0])
   825  	if err != nil {
   826  		return ret, errors.Wrap(err, "SRegion.CreateLoadBalancer.getNetwork")
   827  	}
   828  
   829  	params := jsonutils.NewDict()
   830  	elbObj := jsonutils.NewDict()
   831  	elbObj.Set("name", jsonutils.NewString(loadbalancer.Name))
   832  	elbObj.Set("vip_subnet_id", jsonutils.NewString(subnet.NeutronSubnetID))
   833  	if len(loadbalancer.Address) > 0 {
   834  		elbObj.Set("vip_address", jsonutils.NewString(loadbalancer.Address))
   835  	}
   836  	elbObj.Set("tenant_id", jsonutils.NewString(self.client.projectId))
   837  	params.Set("loadbalancer", elbObj)
   838  
   839  	err = DoCreate(self.ecsClient.Elb.Create, params, &ret)
   840  	if err != nil {
   841  		return ret, errors.Wrap(err, "SRegion.CreateLoadBalancer.DoCreate")
   842  	}
   843  
   844  	ret.region = self
   845  
   846  	// 创建公网类型ELB
   847  	if len(loadbalancer.EipID) > 0 {
   848  		err := self.AssociateEipWithPortId(loadbalancer.EipID, ret.VipPortID)
   849  		if err != nil {
   850  			return ret, errors.Wrap(err, "SRegion.CreateLoadBalancer.AssociateEipWithPortId")
   851  		}
   852  	}
   853  	return ret, nil
   854  }
   855  
   856  func (self *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) {
   857  	ret, err := self.CreateLoadBalancerAcl(acl)
   858  	if err != nil {
   859  		return nil, err
   860  	}
   861  
   862  	return &ret, nil
   863  }
   864  
   865  func (self *SRegion) CreateLoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (SElbACL, error) {
   866  	params := jsonutils.NewDict()
   867  	aclObj := jsonutils.NewDict()
   868  	aclObj.Set("listener_id", jsonutils.NewString(acl.ListenerId))
   869  	if len(acl.Entrys) > 0 {
   870  		whitelist := []string{}
   871  		for i := range acl.Entrys {
   872  			whitelist = append(whitelist, acl.Entrys[i].CIDR)
   873  		}
   874  
   875  		aclObj.Set("enable_whitelist", jsonutils.NewBool(acl.AccessControlEnable))
   876  		aclObj.Set("whitelist", jsonutils.NewString(strings.Join(whitelist, ",")))
   877  	} else {
   878  		aclObj.Set("enable_whitelist", jsonutils.NewBool(false))
   879  	}
   880  	params.Set("whitelist", aclObj)
   881  
   882  	ret := SElbACL{}
   883  	err := DoCreate(self.ecsClient.ElbWhitelist.Create, params, &ret)
   884  	if err != nil {
   885  		return ret, err
   886  	}
   887  
   888  	ret.region = self
   889  	return ret, nil
   890  }
   891  
   892  func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) {
   893  	iBuckets, err := region.client.getIBuckets()
   894  	if err != nil {
   895  		return nil, errors.Wrap(err, "getIBuckets")
   896  	}
   897  	ret := make([]cloudprovider.ICloudBucket, 0)
   898  	for i := range iBuckets {
   899  		// huawei OBS is shared across projects
   900  		if iBuckets[i].GetLocation() == region.GetId() {
   901  			ret = append(ret, iBuckets[i])
   902  		}
   903  	}
   904  	return ret, nil
   905  }
   906  
   907  func str2StorageClass(storageClassStr string) (obs.StorageClassType, error) {
   908  	if strings.EqualFold(storageClassStr, string(obs.StorageClassStandard)) {
   909  		return obs.StorageClassStandard, nil
   910  	} else if strings.EqualFold(storageClassStr, string(obs.StorageClassWarm)) {
   911  		return obs.StorageClassWarm, nil
   912  	} else if strings.EqualFold(storageClassStr, string(obs.StorageClassCold)) {
   913  		return obs.StorageClassCold, nil
   914  	} else {
   915  		return obs.StorageClassStandard, errors.Error("unsupported storageClass")
   916  	}
   917  }
   918  
   919  func (region *SRegion) CreateIBucket(name string, storageClassStr string, aclStr string) error {
   920  	obsClient, err := region.getOBSClient()
   921  	if err != nil {
   922  		return errors.Wrap(err, "region.getOBSClient")
   923  	}
   924  	input := &obs.CreateBucketInput{}
   925  	input.Bucket = name
   926  	input.Location = region.GetId()
   927  	if len(aclStr) > 0 {
   928  		if strings.EqualFold(aclStr, string(obs.AclPrivate)) {
   929  			input.ACL = obs.AclPrivate
   930  		} else if strings.EqualFold(aclStr, string(obs.AclPublicRead)) {
   931  			input.ACL = obs.AclPublicRead
   932  		} else if strings.EqualFold(aclStr, string(obs.AclPublicReadWrite)) {
   933  			input.ACL = obs.AclPublicReadWrite
   934  		} else {
   935  			return errors.Error("unsupported acl")
   936  		}
   937  	}
   938  	if len(storageClassStr) > 0 {
   939  		input.StorageClass, err = str2StorageClass(storageClassStr)
   940  		if err != nil {
   941  			return err
   942  		}
   943  	}
   944  	_, err = obsClient.CreateBucket(input)
   945  	if err != nil {
   946  		return errors.Wrap(err, "obsClient.CreateBucket")
   947  	}
   948  	region.client.invalidateIBuckets()
   949  	return nil
   950  }
   951  
   952  func obsHttpCode(err error) int {
   953  	switch httpErr := err.(type) {
   954  	case obs.ObsError:
   955  		return httpErr.StatusCode
   956  	case *obs.ObsError:
   957  		return httpErr.StatusCode
   958  	}
   959  	return -1
   960  }
   961  
   962  func (region *SRegion) DeleteIBucket(name string) error {
   963  	obsClient, err := region.getOBSClient()
   964  	if err != nil {
   965  		return errors.Wrap(err, "region.getOBSClient")
   966  	}
   967  	_, err = obsClient.DeleteBucket(name)
   968  	if err != nil {
   969  		if obsHttpCode(err) == 404 {
   970  			return nil
   971  		}
   972  		log.Debugf("%#v %s", err, err)
   973  		return errors.Wrap(err, "DeleteBucket")
   974  	}
   975  	region.client.invalidateIBuckets()
   976  	return nil
   977  }
   978  
   979  func (region *SRegion) HeadBucket(name string) (*obs.BaseModel, error) {
   980  	obsClient, err := region.getOBSClient()
   981  	if err != nil {
   982  		return nil, errors.Wrap(err, "region.getOBSClient")
   983  	}
   984  	return obsClient.HeadBucket(name)
   985  }
   986  
   987  func (region *SRegion) IBucketExist(name string) (bool, error) {
   988  	_, err := region.HeadBucket(name)
   989  	if err != nil {
   990  		if obsHttpCode(err) == 404 {
   991  			return false, nil
   992  		} else {
   993  			return false, errors.Wrap(err, "HeadBucket")
   994  		}
   995  	}
   996  	return true, nil
   997  }
   998  
   999  func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) {
  1000  	return cloudprovider.GetIBucketById(region, name)
  1001  }
  1002  
  1003  func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) {
  1004  	return region.GetIBucketById(name)
  1005  }
  1006  
  1007  func (self *SRegion) GetSkus(zoneId string) ([]cloudprovider.ICloudSku, error) {
  1008  	if self.iskus != nil {
  1009  		return self.iskus, nil
  1010  	}
  1011  
  1012  	ret := make([]cloudprovider.ICloudSku, 0)
  1013  	flavors, err := self.fetchInstanceTypes(zoneId)
  1014  	if err != nil {
  1015  		return nil, errors.Wrap(err, "fetchInstanceTypes")
  1016  	}
  1017  
  1018  	for i := range flavors {
  1019  		ret = append(ret, &flavors[i])
  1020  	}
  1021  
  1022  	self.iskus = ret
  1023  	return ret, nil
  1024  }
  1025  
  1026  func (self *SRegion) GetICloudSku(skuId string) (cloudprovider.ICloudSku, error) {
  1027  	skus, err := self.GetSkus("")
  1028  	if err != nil {
  1029  		return nil, err
  1030  	}
  1031  
  1032  	for i := range skus {
  1033  		if skus[i].GetId() == skuId {
  1034  			return skus[i], nil
  1035  		}
  1036  	}
  1037  
  1038  	return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetICloudSku")
  1039  }
  1040  
  1041  func (self *SRegion) GetIElasticcaches() ([]cloudprovider.ICloudElasticcache, error) {
  1042  	caches, err := self.GetElasticCaches()
  1043  	if err != nil {
  1044  		return nil, err
  1045  	}
  1046  
  1047  	icaches := make([]cloudprovider.ICloudElasticcache, len(caches))
  1048  	for i := range caches {
  1049  		caches[i].region = self
  1050  		icaches[i] = &caches[i]
  1051  	}
  1052  
  1053  	return icaches, nil
  1054  }
  1055  
  1056  func (region *SRegion) GetCapabilities() []string {
  1057  	return region.client.GetCapabilities()
  1058  }
  1059  
  1060  func (self *SRegion) GetDiskTypes() ([]SDiskType, error) {
  1061  	ret, err := self.ecsClient.Disks.GetDiskTypes()
  1062  	if err != nil {
  1063  		return nil, errors.Wrap(err, "GetDiskTypes")
  1064  	}
  1065  
  1066  	dts := []SDiskType{}
  1067  	_ret := jsonutils.NewArray(ret.Data...)
  1068  	err = _ret.Unmarshal(&dts)
  1069  	if err != nil {
  1070  		return nil, errors.Wrap(err, "Unmarshal")
  1071  	}
  1072  
  1073  	return dts, nil
  1074  }
  1075  
  1076  func (self *SRegion) GetZoneSupportedDiskTypes(zoneId string) ([]string, error) {
  1077  	dts, err := self.GetDiskTypes()
  1078  	if err != nil {
  1079  		return nil, errors.Wrap(err, "GetDiskTypes")
  1080  	}
  1081  
  1082  	ret := []string{}
  1083  	for i := range dts {
  1084  		if dts[i].IsAvaliableInZone(zoneId) {
  1085  			ret = append(ret, dts[i].Name)
  1086  		}
  1087  	}
  1088  
  1089  	return ret, nil
  1090  }
  1091  
  1092  func (self *SRegion) GetISkus() ([]cloudprovider.ICloudSku, error) {
  1093  	return self.GetSkus("")
  1094  }
  1095  
  1096  func (self *SRegion) GetEndpoints() ([]jsonutils.JSONObject, error) {
  1097  	endpoints := make([]jsonutils.JSONObject, 0)
  1098  	err := doListAll(self.ecsClient.Endpoints.List, nil, &endpoints)
  1099  	if err != nil {
  1100  		return nil, err
  1101  	}
  1102  
  1103  	return endpoints, nil
  1104  }
  1105  
  1106  func (self *SRegion) GetServices() ([]jsonutils.JSONObject, error) {
  1107  	services := make([]jsonutils.JSONObject, 0)
  1108  	err := doListAll(self.ecsClient.Services.List, nil, &services)
  1109  	if err != nil {
  1110  		return nil, err
  1111  	}
  1112  
  1113  	return services, nil
  1114  }