yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/huawei/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 huawei
    16  
    17  import (
    18  	"fmt"
    19  	"net/url"
    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/huawei/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  
    57  	storageCache *SStoragecache
    58  }
    59  
    60  func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) {
    61  	return nil, cloudprovider.ErrNotImplemented
    62  }
    63  
    64  func (self *SRegion) GetClient() *SHuaweiClient {
    65  	return self.client
    66  }
    67  
    68  func (self *SRegion) getECSClient() (*client.Client, error) {
    69  	var err error
    70  
    71  	if len(self.client.projectId) > 0 {
    72  		project, err := self.client.GetProjectById(self.client.projectId)
    73  		if err != nil {
    74  			return nil, err
    75  		}
    76  
    77  		if !strings.Contains(project.Name, self.ID) {
    78  			return nil, errors.Errorf("region %s and project %s mismatch", self.ID, project.Name)
    79  		}
    80  	}
    81  
    82  	if self.ecsClient == nil {
    83  		self.ecsClient, err = self.client.newRegionAPIClient(self.ID)
    84  		if err != nil {
    85  			return nil, err
    86  		}
    87  	}
    88  
    89  	return self.ecsClient, err
    90  }
    91  
    92  func (self *SRegion) getOBSEndpoint() string {
    93  	return getOBSEndpoint(self.GetId())
    94  }
    95  
    96  func (self *SRegion) getOBSClient() (*obs.ObsClient, error) {
    97  	if self.obsClient == nil {
    98  		obsClient, err := self.client.getOBSClient(self.GetId())
    99  		if err != nil {
   100  			return nil, err
   101  		}
   102  
   103  		self.obsClient = obsClient
   104  	}
   105  
   106  	return self.obsClient, nil
   107  }
   108  
   109  func (self *SRegion) fetchZones() error {
   110  	zones := make([]SZone, 0)
   111  	err := doListAll(self.ecsClient.Zones.List, nil, &zones)
   112  	if err != nil {
   113  		return err
   114  	}
   115  
   116  	self.izones = make([]cloudprovider.ICloudZone, 0)
   117  	for i := range zones {
   118  		zone := zones[i]
   119  		zone.region = self
   120  		self.izones = append(self.izones, &zone)
   121  	}
   122  	return nil
   123  }
   124  
   125  func (self *SRegion) fetchIVpcs() error {
   126  	// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090625.html
   127  	vpcs := make([]SVpc, 0)
   128  	querys := map[string]string{
   129  		"limit": "2048",
   130  	}
   131  	err := doListAllWithMarker(self.ecsClient.Vpcs.List, querys, &vpcs)
   132  	if err != nil {
   133  		return err
   134  	}
   135  
   136  	self.ivpcs = make([]cloudprovider.ICloudVpc, 0)
   137  	for i := range vpcs {
   138  		vpc := vpcs[i]
   139  		vpc.region = self
   140  		self.ivpcs = append(self.ivpcs, &vpc)
   141  	}
   142  	return nil
   143  }
   144  
   145  func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) {
   146  	if len(id) == 0 {
   147  		return nil, errors.Wrap(cloudprovider.ErrNotFound, "SRegion.GetIVMById")
   148  	}
   149  
   150  	instance, err := self.GetInstanceByID(id)
   151  	if err != nil {
   152  		return nil, err
   153  	}
   154  	return &instance, err
   155  }
   156  
   157  func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) {
   158  	return self.GetDisk(id)
   159  }
   160  
   161  func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo {
   162  	if info, ok := LatitudeAndLongitude[self.ID]; ok {
   163  		return info
   164  	}
   165  	return cloudprovider.SGeographicInfo{}
   166  }
   167  
   168  func (self *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) {
   169  	elbs, err := self.GetLoadBalancers()
   170  	if err != nil {
   171  		return nil, err
   172  	}
   173  
   174  	ielbs := make([]cloudprovider.ICloudLoadbalancer, len(elbs))
   175  	for i := range elbs {
   176  		elbs[i].region = self
   177  		ielbs[i] = &elbs[i]
   178  	}
   179  
   180  	return ielbs, nil
   181  }
   182  
   183  func (self *SRegion) GetLoadBalancers() ([]SLoadbalancer, error) {
   184  	lbs := []SLoadbalancer{}
   185  	params := url.Values{}
   186  	return lbs, self.lbListAll("elb/loadbalancers", params, "loadbalancers", &lbs)
   187  }
   188  
   189  func (self *SRegion) GetILoadBalancerById(id string) (cloudprovider.ICloudLoadbalancer, error) {
   190  	elb, err := self.GetLoadbalancer(id)
   191  	if err != nil {
   192  		return nil, err
   193  	}
   194  	return elb, nil
   195  }
   196  
   197  func (self *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) {
   198  	acl, err := self.GetLoadBalancerAcl(aclId)
   199  	if err != nil {
   200  		return nil, err
   201  	}
   202  	return acl, nil
   203  }
   204  
   205  func (self *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) {
   206  	cert, err := self.GetLoadBalancerCertificate(certId)
   207  	if err != nil {
   208  		return nil, err
   209  	}
   210  	return cert, nil
   211  }
   212  
   213  func (self *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) {
   214  	ret, err := self.CreateLoadBalancerCertificate(cert)
   215  	if err != nil {
   216  		return nil, err
   217  	}
   218  	return ret, nil
   219  }
   220  
   221  func (self *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) {
   222  	ret, err := self.GetLoadBalancerAcls("")
   223  	if err != nil {
   224  		return nil, err
   225  	}
   226  
   227  	iret := make([]cloudprovider.ICloudLoadbalancerAcl, len(ret))
   228  	for i := range ret {
   229  		ret[i].region = self
   230  		iret[i] = &ret[i]
   231  	}
   232  	return iret, nil
   233  }
   234  
   235  func (self *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) {
   236  	ret, err := self.GetLoadBalancerCertificates()
   237  	if err != nil {
   238  		return nil, err
   239  	}
   240  
   241  	iret := make([]cloudprovider.ICloudLoadbalancerCertificate, len(ret))
   242  	for i := range ret {
   243  		ret[i].region = self
   244  		iret[i] = &ret[i]
   245  	}
   246  	return iret, nil
   247  }
   248  
   249  // https://support.huaweicloud.com/api-iam/zh-cn_topic_0057845622.html
   250  func (self *SRegion) GetId() string {
   251  	return self.ID
   252  }
   253  
   254  func (self *SRegion) GetName() string {
   255  	return fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_CN, self.Locales.ZhCN)
   256  }
   257  
   258  func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable {
   259  	en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_EN, self.Locales.EnUs)
   260  	table := cloudprovider.SModelI18nTable{}
   261  	table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en)
   262  	return table
   263  }
   264  
   265  func (self *SRegion) GetGlobalId() string {
   266  	return fmt.Sprintf("%s/%s", self.client.GetAccessEnv(), self.ID)
   267  }
   268  
   269  func (self *SRegion) GetStatus() string {
   270  	return api.CLOUD_REGION_STATUS_INSERVER
   271  }
   272  
   273  func (self *SRegion) Refresh() error {
   274  	return nil
   275  }
   276  
   277  func (self *SRegion) IsEmulated() bool {
   278  	return false
   279  }
   280  
   281  func (self *SRegion) GetLatitude() float32 {
   282  	if locationInfo, ok := LatitudeAndLongitude[self.ID]; ok {
   283  		return locationInfo.Latitude
   284  	}
   285  	return 0.0
   286  }
   287  
   288  func (self *SRegion) GetLongitude() float32 {
   289  	if locationInfo, ok := LatitudeAndLongitude[self.ID]; ok {
   290  		return locationInfo.Longitude
   291  	}
   292  	return 0.0
   293  }
   294  
   295  func (self *SRegion) fetchInfrastructure() error {
   296  	_, err := self.getECSClient()
   297  	if err != nil {
   298  		return err
   299  	}
   300  
   301  	if err := self.fetchZones(); err != nil {
   302  		return err
   303  	}
   304  
   305  	if err := self.fetchIVpcs(); err != nil {
   306  		return err
   307  	}
   308  
   309  	for i := 0; i < len(self.ivpcs); i += 1 {
   310  		vpc := self.ivpcs[i].(*SVpc)
   311  		wire := SWire{region: self, vpc: vpc}
   312  		vpc.addWire(&wire)
   313  
   314  		for j := 0; j < len(self.izones); j += 1 {
   315  			zone := self.izones[j].(*SZone)
   316  			zone.addWire(&wire)
   317  		}
   318  	}
   319  	return nil
   320  }
   321  
   322  func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) {
   323  	if self.izones == nil {
   324  		var err error
   325  		err = self.fetchInfrastructure()
   326  		if err != nil {
   327  			return nil, err
   328  		}
   329  	}
   330  	return self.izones, nil
   331  }
   332  
   333  func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) {
   334  	if self.ivpcs == nil {
   335  		err := self.fetchInfrastructure()
   336  		if err != nil {
   337  			return nil, err
   338  		}
   339  	}
   340  	return self.ivpcs, nil
   341  }
   342  
   343  func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) {
   344  	eips, err := self.GetEips("", nil)
   345  	if err != nil {
   346  		return nil, err
   347  	}
   348  
   349  	ret := []cloudprovider.ICloudEIP{}
   350  	for i := 0; i < len(eips); i += 1 {
   351  		eips[i].region = self
   352  		ret = append(ret, &eips[i])
   353  	}
   354  	return ret, nil
   355  }
   356  
   357  func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) {
   358  	ivpcs, err := self.GetIVpcs()
   359  	if err != nil {
   360  		return nil, err
   361  	}
   362  	for i := 0; i < len(ivpcs); i += 1 {
   363  		if ivpcs[i].GetGlobalId() == id {
   364  			return ivpcs[i], nil
   365  		}
   366  	}
   367  	return nil, cloudprovider.ErrNotFound
   368  }
   369  
   370  func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) {
   371  	izones, err := self.GetIZones()
   372  	if err != nil {
   373  		return nil, err
   374  	}
   375  	for i := 0; i < len(izones); i += 1 {
   376  		if izones[i].GetGlobalId() == id {
   377  			return izones[i], nil
   378  		}
   379  	}
   380  	return nil, cloudprovider.ErrNotFound
   381  }
   382  
   383  func (self *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) {
   384  	eip, err := self.GetEip(eipId)
   385  	if err != nil {
   386  		return nil, err
   387  	}
   388  	return eip, nil
   389  }
   390  
   391  // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0060595555.html
   392  func (self *SRegion) DeleteSecurityGroup(secgroupId string) error {
   393  	return DoDelete(self.ecsClient.SecurityGroups.Delete, secgroupId, nil, nil)
   394  }
   395  
   396  func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) {
   397  	return self.GetSecurityGroupDetails(secgroupId)
   398  }
   399  
   400  func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) {
   401  	secgroups, err := self.GetSecurityGroups(opts.VpcId, opts.Name)
   402  	if err != nil {
   403  		return nil, err
   404  	}
   405  	if len(secgroups) == 0 {
   406  		return nil, cloudprovider.ErrNotFound
   407  	}
   408  	if len(secgroups) > 1 {
   409  		return nil, cloudprovider.ErrDuplicateId
   410  	}
   411  	secgroups[0].region = self
   412  	return &secgroups[0], nil
   413  }
   414  
   415  func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) {
   416  	return self.CreateSecurityGroup(conf.VpcId, conf.Name, conf.Desc)
   417  }
   418  
   419  // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090608.html
   420  func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) {
   421  	return self.CreateVpc(opts.NAME, opts.CIDR, opts.Desc)
   422  }
   423  
   424  func (self *SRegion) CreateVpc(name, cidr, desc string) (*SVpc, error) {
   425  	params := map[string]interface{}{
   426  		"vpc": map[string]string{
   427  			"name":        name,
   428  			"cidr":        cidr,
   429  			"description": desc,
   430  		},
   431  	}
   432  	vpc := &SVpc{region: self}
   433  	return vpc, DoCreate(self.ecsClient.Vpcs.Create, jsonutils.Marshal(params), vpc)
   434  }
   435  
   436  // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090596.html
   437  // size: 1Mbit/s~2000Mbit/s
   438  // bgpType: 5_telcom,5_union,5_bgp,5_sbgp.
   439  // 东北-大连:5_telcom、5_union
   440  // 华南-广州:5_sbgp
   441  // 华东-上海二:5_sbgp
   442  // 华北-北京一:5_bgp、5_sbgp
   443  // 亚太-香港:5_bgp
   444  func (self *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) {
   445  	var ctype TInternetChargeType
   446  	switch eip.ChargeType {
   447  	case api.EIP_CHARGE_TYPE_BY_TRAFFIC:
   448  		ctype = InternetChargeByTraffic
   449  	case api.EIP_CHARGE_TYPE_BY_BANDWIDTH:
   450  		ctype = InternetChargeByBandwidth
   451  	}
   452  
   453  	// todo: 如何避免hardcode。集成到cloudmeta服务中?
   454  	if len(eip.BGPType) == 0 {
   455  		switch self.GetId() {
   456  		case "cn-north-1", "cn-east-2", "cn-south-1":
   457  			eip.BGPType = "5_sbgp"
   458  		case "cn-northeast-1":
   459  			eip.BGPType = "5_telcom"
   460  		case "cn-north-4", "ap-southeast-1", "ap-southeast-2", "eu-west-0":
   461  			eip.BGPType = "5_bgp"
   462  		case "cn-southwest-2":
   463  			eip.BGPType = "5_sbgp"
   464  		default:
   465  			eip.BGPType = "5_bgp"
   466  		}
   467  	}
   468  
   469  	// 华为云EIP名字最大长度64
   470  	if len(eip.Name) > 64 {
   471  		eip.Name = eip.Name[:64]
   472  	}
   473  
   474  	ieip, err := self.AllocateEIP(eip.Name, eip.BandwidthMbps, ctype, eip.BGPType, eip.ProjectId)
   475  	ieip.region = self
   476  	if err != nil {
   477  		return nil, err
   478  	}
   479  
   480  	err = cloudprovider.WaitStatus(ieip, api.EIP_STATUS_READY, 5*time.Second, 60*time.Second)
   481  	return ieip, err
   482  }
   483  
   484  func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) {
   485  	snapshots, err := self.GetSnapshots("", "")
   486  	if err != nil {
   487  		log.Errorf("self.GetSnapshots fail %s", err)
   488  		return nil, err
   489  	}
   490  
   491  	ret := make([]cloudprovider.ICloudSnapshot, len(snapshots))
   492  	for i := 0; i < len(snapshots); i += 1 {
   493  		snapshots[i].region = self
   494  		ret[i] = &snapshots[i]
   495  	}
   496  	return ret, nil
   497  }
   498  
   499  func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) {
   500  	snapshot, err := self.GetSnapshotById(snapshotId)
   501  	return &snapshot, err
   502  }
   503  
   504  func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) {
   505  	iHosts := make([]cloudprovider.ICloudHost, 0)
   506  
   507  	izones, err := self.GetIZones()
   508  	if err != nil {
   509  		return nil, err
   510  	}
   511  	for i := 0; i < len(izones); i += 1 {
   512  		iZoneHost, err := izones[i].GetIHosts()
   513  		if err != nil {
   514  			return nil, err
   515  		}
   516  		iHosts = append(iHosts, iZoneHost...)
   517  	}
   518  	return iHosts, nil
   519  }
   520  
   521  func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, 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  		ihost, err := izones[i].GetIHostById(id)
   528  		if err == nil {
   529  			return ihost, nil
   530  		} else if errors.Cause(err) != cloudprovider.ErrNotFound {
   531  			return nil, err
   532  		}
   533  	}
   534  	return nil, cloudprovider.ErrNotFound
   535  }
   536  
   537  func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
   538  	iStores := make([]cloudprovider.ICloudStorage, 0)
   539  
   540  	izones, err := self.GetIZones()
   541  	if err != nil {
   542  		return nil, err
   543  	}
   544  	for i := 0; i < len(izones); i += 1 {
   545  		iZoneStores, err := izones[i].GetIStorages()
   546  		if err != nil {
   547  			return nil, err
   548  		}
   549  		iStores = append(iStores, iZoneStores...)
   550  	}
   551  	return iStores, nil
   552  }
   553  
   554  func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
   555  	izones, err := self.GetIZones()
   556  	if err != nil {
   557  		return nil, err
   558  	}
   559  	for i := 0; i < len(izones); i += 1 {
   560  		istore, err := izones[i].GetIStorageById(id)
   561  		if err == nil {
   562  			return istore, nil
   563  		} else if errors.Cause(err) != cloudprovider.ErrNotFound {
   564  			return nil, err
   565  		}
   566  	}
   567  	return nil, cloudprovider.ErrNotFound
   568  }
   569  
   570  func (self *SRegion) GetProvider() string {
   571  	return CLOUD_PROVIDER_HUAWEI
   572  }
   573  
   574  func (self *SRegion) GetCloudEnv() string {
   575  	return self.client.cloudEnv
   576  }
   577  
   578  // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090615.html
   579  // 目前desc字段并没有用到
   580  func (self *SRegion) CreateSecurityGroup(vpcId string, name string, desc string) (*SSecurityGroup, error) {
   581  	// 华为不允许创建名称为default的安全组
   582  	if strings.ToLower(name) == "default" {
   583  		name = fmt.Sprintf("%s-%s", vpcId, name)
   584  	}
   585  
   586  	params := jsonutils.NewDict()
   587  	secgroupObj := jsonutils.NewDict()
   588  	secgroupObj.Add(jsonutils.NewString(name), "name")
   589  	if len(vpcId) > 0 && vpcId != api.NORMAL_VPC_ID {
   590  		secgroupObj.Add(jsonutils.NewString(vpcId), "vpc_id")
   591  	}
   592  	params.Add(secgroupObj, "security_group")
   593  
   594  	secgroup := SSecurityGroup{region: self}
   595  	err := DoCreate(self.ecsClient.SecurityGroups.Create, params, &secgroup)
   596  	return &secgroup, err
   597  }
   598  
   599  // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0087467071.html
   600  func (self *SRegion) delSecurityGroupRule(secGrpRuleId string) error {
   601  	_, err := self.ecsClient.SecurityGroupRules.DeleteInContextWithSpec(nil, secGrpRuleId, "", nil, nil, "")
   602  	return err
   603  }
   604  
   605  func (self *SRegion) DeleteSecurityGroupRule(ruleId string) error {
   606  	return self.delSecurityGroupRule(ruleId)
   607  }
   608  
   609  func (self *SRegion) CreateSecurityGroupRule(secgroupId string, rule cloudprovider.SecurityRule) error {
   610  	return self.addSecurityGroupRules(secgroupId, rule)
   611  }
   612  
   613  // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0087451723.html
   614  // icmp port对应关系:https://support.huaweicloud.com/api-vpc/zh-cn_topic_0024109590.html
   615  func (self *SRegion) addSecurityGroupRules(secGrpId string, rule cloudprovider.SecurityRule) error {
   616  	direction := ""
   617  	if rule.Direction == secrules.SecurityRuleIngress {
   618  		direction = "ingress"
   619  	} else {
   620  		direction = "egress"
   621  	}
   622  
   623  	protocal := rule.Protocol
   624  	if rule.Protocol == secrules.PROTO_ANY {
   625  		protocal = ""
   626  	}
   627  
   628  	// imcp协议默认为any
   629  	if rule.Protocol == secrules.PROTO_ICMP {
   630  		return self.addSecurityGroupRule(secGrpId, direction, "-1", "-1", protocal, rule.IPNet.String())
   631  	}
   632  
   633  	if len(rule.Ports) > 0 {
   634  		for _, port := range rule.Ports {
   635  			portStr := fmt.Sprintf("%d", port)
   636  			err := self.addSecurityGroupRule(secGrpId, direction, portStr, portStr, protocal, rule.IPNet.String())
   637  			if err != nil {
   638  				return err
   639  			}
   640  		}
   641  	} else {
   642  		portStart := fmt.Sprintf("%d", rule.PortStart)
   643  		portEnd := fmt.Sprintf("%d", rule.PortEnd)
   644  		err := self.addSecurityGroupRule(secGrpId, direction, portStart, portEnd, protocal, rule.IPNet.String())
   645  		if err != nil {
   646  			return err
   647  		}
   648  	}
   649  
   650  	return nil
   651  }
   652  
   653  func (self *SRegion) addSecurityGroupRule(secGrpId, direction, portStart, portEnd, protocol, ipNet string) error {
   654  	params := jsonutils.NewDict()
   655  	secgroupObj := jsonutils.NewDict()
   656  	secgroupObj.Add(jsonutils.NewString(secGrpId), "security_group_id")
   657  	secgroupObj.Add(jsonutils.NewString(direction), "direction")
   658  	secgroupObj.Add(jsonutils.NewString(ipNet), "remote_ip_prefix")
   659  	secgroupObj.Add(jsonutils.NewString("IPV4"), "ethertype")
   660  	// 端口为空或者1-65535
   661  	if len(portStart) > 0 && portStart != "0" && portStart != "-1" {
   662  		secgroupObj.Add(jsonutils.NewString(portStart), "port_range_min")
   663  	}
   664  	if len(portEnd) > 0 && portEnd != "0" && portEnd != "-1" {
   665  		secgroupObj.Add(jsonutils.NewString(portEnd), "port_range_max")
   666  	}
   667  	if len(protocol) > 0 {
   668  		secgroupObj.Add(jsonutils.NewString(protocol), "protocol")
   669  	}
   670  	params.Add(secgroupObj, "security_group_rule")
   671  
   672  	rule := SecurityGroupRule{}
   673  	return DoCreate(self.ecsClient.SecurityGroupRules.Create, params, &rule)
   674  }
   675  
   676  func (self *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) {
   677  	ret, err := self.CreateLoadBalancer(loadbalancer)
   678  	if err != nil {
   679  		return nil, err
   680  	}
   681  
   682  	return ret, nil
   683  }
   684  
   685  func (self *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) {
   686  	ret, err := self.CreateLoadBalancerAcl(acl)
   687  	if err != nil {
   688  		return nil, err
   689  	}
   690  
   691  	return ret, nil
   692  }
   693  
   694  func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) {
   695  	iBuckets, err := region.client.getIBuckets()
   696  	if err != nil {
   697  		return nil, errors.Wrap(err, "getIBuckets")
   698  	}
   699  	ret := make([]cloudprovider.ICloudBucket, 0)
   700  	for i := range iBuckets {
   701  		// huawei OBS is shared across projects
   702  		if iBuckets[i].GetLocation() == region.GetId() {
   703  			ret = append(ret, iBuckets[i])
   704  		}
   705  	}
   706  	return ret, nil
   707  }
   708  
   709  func str2StorageClass(storageClassStr string) (obs.StorageClassType, error) {
   710  	if strings.EqualFold(storageClassStr, string(obs.StorageClassStandard)) {
   711  		return obs.StorageClassStandard, nil
   712  	} else if strings.EqualFold(storageClassStr, string(obs.StorageClassWarm)) {
   713  		return obs.StorageClassWarm, nil
   714  	} else if strings.EqualFold(storageClassStr, string(obs.StorageClassCold)) {
   715  		return obs.StorageClassCold, nil
   716  	} else {
   717  		return obs.StorageClassStandard, errors.Error("unsupported storageClass")
   718  	}
   719  }
   720  
   721  func (region *SRegion) CreateIBucket(name string, storageClassStr string, aclStr string) error {
   722  	obsClient, err := region.getOBSClient()
   723  	if err != nil {
   724  		return errors.Wrap(err, "region.getOBSClient")
   725  	}
   726  	input := &obs.CreateBucketInput{}
   727  	input.Bucket = name
   728  	input.Location = region.GetId()
   729  	if len(aclStr) > 0 {
   730  		if strings.EqualFold(aclStr, string(obs.AclPrivate)) {
   731  			input.ACL = obs.AclPrivate
   732  		} else if strings.EqualFold(aclStr, string(obs.AclPublicRead)) {
   733  			input.ACL = obs.AclPublicRead
   734  		} else if strings.EqualFold(aclStr, string(obs.AclPublicReadWrite)) {
   735  			input.ACL = obs.AclPublicReadWrite
   736  		} else {
   737  			return errors.Error("unsupported acl")
   738  		}
   739  	}
   740  	if len(storageClassStr) > 0 {
   741  		input.StorageClass, err = str2StorageClass(storageClassStr)
   742  		if err != nil {
   743  			return err
   744  		}
   745  	}
   746  	_, err = obsClient.CreateBucket(input)
   747  	if err != nil {
   748  		return errors.Wrap(err, "obsClient.CreateBucket")
   749  	}
   750  	region.client.invalidateIBuckets()
   751  	return nil
   752  }
   753  
   754  func obsHttpCode(err error) int {
   755  	switch httpErr := err.(type) {
   756  	case obs.ObsError:
   757  		return httpErr.StatusCode
   758  	case *obs.ObsError:
   759  		return httpErr.StatusCode
   760  	}
   761  	return -1
   762  }
   763  
   764  func (region *SRegion) DeleteIBucket(name string) error {
   765  	obsClient, err := region.getOBSClient()
   766  	if err != nil {
   767  		return errors.Wrap(err, "region.getOBSClient")
   768  	}
   769  	_, err = obsClient.DeleteBucket(name)
   770  	if err != nil {
   771  		if obsHttpCode(err) == 404 {
   772  			return nil
   773  		}
   774  		log.Debugf("%#v %s", err, err)
   775  		return errors.Wrap(err, "DeleteBucket")
   776  	}
   777  	region.client.invalidateIBuckets()
   778  	return nil
   779  }
   780  
   781  func (region *SRegion) HeadBucket(name string) (*obs.BaseModel, error) {
   782  	obsClient, err := region.getOBSClient()
   783  	if err != nil {
   784  		return nil, errors.Wrap(err, "region.getOBSClient")
   785  	}
   786  	return obsClient.HeadBucket(name)
   787  }
   788  
   789  func (region *SRegion) IBucketExist(name string) (bool, error) {
   790  	_, err := region.HeadBucket(name)
   791  	if err != nil {
   792  		if obsHttpCode(err) == 404 {
   793  			return false, nil
   794  		} else {
   795  			return false, errors.Wrap(err, "HeadBucket")
   796  		}
   797  	}
   798  	return true, nil
   799  }
   800  
   801  func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) {
   802  	return cloudprovider.GetIBucketById(region, name)
   803  }
   804  
   805  func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) {
   806  	return region.GetIBucketById(name)
   807  }
   808  
   809  func (self *SRegion) GetSkus(zoneId string) ([]cloudprovider.ICloudSku, error) {
   810  	return nil, cloudprovider.ErrNotImplemented
   811  }
   812  
   813  func (self *SRegion) GetIElasticcaches() ([]cloudprovider.ICloudElasticcache, error) {
   814  	caches, err := self.GetElasticCaches()
   815  	if err != nil {
   816  		return nil, err
   817  	}
   818  
   819  	icaches := make([]cloudprovider.ICloudElasticcache, len(caches))
   820  	for i := range caches {
   821  		caches[i].region = self
   822  		icaches[i] = &caches[i]
   823  	}
   824  
   825  	return icaches, nil
   826  }
   827  
   828  func (region *SRegion) GetCapabilities() []string {
   829  	return region.client.GetCapabilities()
   830  }
   831  
   832  func (self *SRegion) GetDiskTypes() ([]SDiskType, error) {
   833  	ret, err := self.ecsClient.Disks.GetDiskTypes()
   834  	if err != nil {
   835  		return nil, errors.Wrap(err, "GetDiskTypes")
   836  	}
   837  
   838  	dts := []SDiskType{}
   839  	_ret := jsonutils.NewArray(ret.Data...)
   840  	err = _ret.Unmarshal(&dts)
   841  	if err != nil {
   842  		return nil, errors.Wrap(err, "Unmarshal")
   843  	}
   844  
   845  	return dts, nil
   846  }
   847  
   848  func (self *SRegion) GetZoneSupportedDiskTypes(zoneId string) ([]string, error) {
   849  	dts, err := self.GetDiskTypes()
   850  	if err != nil {
   851  		return nil, errors.Wrap(err, "GetDiskTypes")
   852  	}
   853  
   854  	ret := []string{}
   855  	for i := range dts {
   856  		if dts[i].IsAvaliableInZone(zoneId) {
   857  			ret = append(ret, dts[i].Name)
   858  		}
   859  	}
   860  
   861  	return ret, nil
   862  }