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 }