yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/aliyun/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 aliyun 16 17 import ( 18 "fmt" 19 "strings" 20 "time" 21 22 "github.com/aliyun/alibaba-cloud-sdk-go/sdk" 23 "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" 24 "github.com/aliyun/aliyun-oss-go-sdk/oss" 25 26 "yunion.io/x/jsonutils" 27 "yunion.io/x/log" 28 "yunion.io/x/pkg/errors" 29 "yunion.io/x/pkg/util/regutils" 30 "yunion.io/x/pkg/utils" 31 32 api "yunion.io/x/cloudmux/pkg/apis/compute" 33 "yunion.io/x/cloudmux/pkg/cloudprovider" 34 "yunion.io/x/cloudmux/pkg/multicloud" 35 ) 36 37 type SRegion struct { 38 multicloud.SRegion 39 40 client *SAliyunClient 41 sdkClient *sdk.Client 42 ossClient *oss.Client 43 mongoSkus map[string]struct { 44 CpuCount int 45 MemSizeGb int 46 } 47 48 RegionId string 49 LocalName string 50 51 RegionEndpoint string 52 53 izones []cloudprovider.ICloudZone 54 55 ivpcs []cloudprovider.ICloudVpc 56 57 lbEndpints map[string]string 58 59 storageCache *SStoragecache 60 61 instanceTypes []SInstanceType 62 63 latitude float64 64 longitude float64 65 fetchLocation bool 66 } 67 68 func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { 69 return nil, cloudprovider.ErrNotImplemented 70 } 71 72 func (self *SRegion) GetClient() *SAliyunClient { 73 return self.client 74 } 75 76 func (self *SRegion) getSdkClient() (*sdk.Client, error) { 77 if self.sdkClient == nil { 78 cli, err := self.client.getSdkClient(self.RegionId) 79 if err != nil { 80 return nil, err 81 } 82 self.sdkClient = cli 83 } 84 return self.sdkClient, nil 85 } 86 87 func (self *SRegion) getEcsClient() (*ecs.Client, error) { 88 sdkClient, err := self.getSdkClient() 89 if err != nil { 90 return nil, errors.Wrap(err, "getSdkClient") 91 } 92 ecsClient := &ecs.Client{ 93 Client: *sdkClient, 94 } 95 return ecsClient, nil 96 } 97 98 func (self *SRegion) getOSSExternalDomain() string { 99 return getOSSExternalDomain(self.RegionId) 100 } 101 102 func (self *SRegion) getOSSInternalDomain() string { 103 return getOSSInternalDomain(self.RegionId) 104 } 105 106 func (self *SRegion) getRegionId() string { 107 if self.client.cloudEnv == ALIYUN_FINANCE_CLOUDENV { 108 switch self.RegionId { 109 case "cn-hangzhou": 110 return "cn-hzfinance" 111 case "cn-shanghai-finance-1": 112 return "cn-shanghai-finance-1-pub" 113 case "cn-shenzhen-finance-1": 114 return "cn-szfinance" 115 } 116 } 117 return self.RegionId 118 } 119 120 func (self *SRegion) GetOssClient() (*oss.Client, error) { 121 if self.ossClient == nil { 122 cli, err := self.client.getOssClient(self.getRegionId()) 123 if err != nil { 124 return nil, errors.Wrap(err, "self.client.getOssClient") 125 } 126 self.ossClient = cli 127 } 128 return self.ossClient, nil 129 } 130 131 func (self *SRegion) ecsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { 132 client, err := self.getSdkClient() 133 if err != nil { 134 return nil, err 135 } 136 endpoint := self.RegionEndpoint 137 if len(endpoint) == 0 { 138 endpoint = "ecs.aliyuncs.com" 139 } 140 params = self.client.SetResourceGropuId(params) 141 return jsonRequest(client, endpoint, ALIYUN_API_VERSION, apiName, params, self.client.debug) 142 } 143 144 func (self *SRegion) wafRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { 145 client, err := self.getSdkClient() 146 if err != nil { 147 return nil, err 148 } 149 if self.RegionId != "cn-hangzhou" && self.RegionId != "ap-southeast-1" { 150 return nil, cloudprovider.ErrNotSupported 151 } 152 params = self.client.SetResourceGropuId(params) 153 endpoint := fmt.Sprintf("wafopenapi.%s.aliyuncs.com", self.RegionId) 154 return jsonRequest(client, endpoint, ALIYUN_WAF_API_VERSION, apiName, params, self.client.debug) 155 } 156 157 func (self *SRegion) esRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { 158 client, err := self.getSdkClient() 159 if err != nil { 160 return nil, err 161 } 162 params = self.client.SetResourceGropuId(params) 163 domain := fmt.Sprintf("elasticsearch.%s.aliyuncs.com", self.RegionId) 164 return jsonRequest(client, domain, ALIYUN_ES_API_VERSION, apiName, params, self.client.debug) 165 } 166 167 func (self *SRegion) kafkaRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { 168 client, err := self.getSdkClient() 169 if err != nil { 170 return nil, err 171 } 172 params = self.client.SetResourceGropuId(params) 173 domain := fmt.Sprintf("alikafka.%s.aliyuncs.com", self.RegionId) 174 return jsonRequest(client, domain, ALIYUN_KAFKA_API_VERSION, apiName, params, self.client.debug) 175 } 176 177 func (self *SRegion) rdsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { 178 client, err := self.getSdkClient() 179 if err != nil { 180 return nil, err 181 } 182 params = self.client.SetResourceGropuId(params) 183 return jsonRequest(client, "rds.aliyuncs.com", ALIYUN_RDS_API_VERSION, apiName, params, self.client.debug) 184 } 185 186 func (self *SRegion) k8sRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { 187 client, err := self.getSdkClient() 188 if err != nil { 189 return nil, err 190 } 191 params = self.client.SetResourceGropuId(params) 192 return jsonRequest(client, fmt.Sprintf("cs.%s.aliyuncs.com", self.RegionId), ALIYUN_K8S_API_VERSION, apiName, params, self.client.debug) 193 } 194 195 func (self *SRegion) mongodbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { 196 client, err := self.getSdkClient() 197 if err != nil { 198 return nil, err 199 } 200 params = self.client.SetResourceGropuId(params) 201 return jsonRequest(client, "mongodb.aliyuncs.com", ALIYUN_MONGO_DB_API_VERSION, apiName, params, self.client.debug) 202 } 203 204 func (self *SRegion) vpcRequest(action string, params map[string]string) (jsonutils.JSONObject, error) { 205 client, err := self.getSdkClient() 206 if err != nil { 207 return nil, err 208 } 209 params = self.client.SetResourceGropuId(params) 210 endpoint := self.GetClient().getVpcEndpoint(self.RegionId) 211 return jsonRequest(client, endpoint, ALIYUN_API_VERSION_VPC, action, params, self.client.debug) 212 } 213 214 func (self *SRegion) nasRequest(action string, params map[string]string) (jsonutils.JSONObject, error) { 215 client, err := self.getSdkClient() 216 if err != nil { 217 return nil, err 218 } 219 switch self.GetCloudEnv() { 220 case ALIYUN_FINANCE_CLOUDENV: 221 if strings.Contains(action, "FileSystem") { 222 if self.RegionId == "cn-hangzhou" { 223 params["RegionId"] = "cn-hangzhou-dg-a01" 224 } 225 } 226 if strings.Contains(action, "Access") || strings.Contains(action, "MountTarget") { 227 if self.RegionId == "cn-hangzhou" { 228 params["RegionId"] = "cn-hangzhou-finance" 229 } 230 } 231 } 232 233 params = self.client.SetResourceGropuId(params) 234 endpint := self.GetClient().getNasEndpoint(self.RegionId) 235 return jsonRequest(client, endpint, ALIYUN_NAS_API_VERSION, action, params, self.client.debug) 236 } 237 238 func (self *SRegion) kvsRequest(action string, params map[string]string) (jsonutils.JSONObject, error) { 239 client, err := self.getSdkClient() 240 if err != nil { 241 return nil, err 242 } 243 244 if _, ok := params["RegionId"]; ok { 245 params["RegionId"] = transRegionIdFromEcsRegionId(self, "redis") 246 } 247 248 params = self.client.SetResourceGropuId(params) 249 return jsonRequest(client, "r-kvstore.aliyuncs.com", ALIYUN_API_VERSION_KVS, action, params, self.client.debug) 250 } 251 252 type LBRegion struct { 253 RegionEndpoint string 254 RegionId string 255 } 256 257 func (self *SRegion) fetchLBRegions(client *sdk.Client) error { 258 if len(self.lbEndpints) > 0 { 259 return nil 260 } 261 params := map[string]string{} 262 result, err := self._lbRequest(client, "DescribeRegions", "slb.aliyuncs.com", params) 263 if err != nil { 264 return err 265 } 266 self.lbEndpints = map[string]string{} 267 regions := []LBRegion{} 268 if err := result.Unmarshal(®ions, "Regions", "Region"); err != nil { 269 return err 270 } 271 for _, region := range regions { 272 self.lbEndpints[region.RegionId] = region.RegionEndpoint 273 } 274 return nil 275 } 276 277 func (self *SRegion) lbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { 278 client, err := self.getSdkClient() 279 if err != nil { 280 return nil, err 281 } 282 domain := "slb.aliyuncs.com" 283 if !utils.IsInStringArray(apiName, []string{"DescribeRegions", "DescribeZones"}) { 284 if regionId, ok := params["RegionId"]; ok { 285 if err := self.fetchLBRegions(client); err != nil { 286 return nil, err 287 } 288 endpoint, ok := self.lbEndpints[regionId] 289 if !ok { 290 return nil, fmt.Errorf("failed to find endpoint for lb region %s", regionId) 291 } 292 domain = endpoint 293 } 294 } 295 params = self.client.SetResourceGropuId(params) 296 return self._lbRequest(client, apiName, domain, params) 297 } 298 299 func (self *SRegion) _lbRequest(client *sdk.Client, apiName string, domain string, params map[string]string) (jsonutils.JSONObject, error) { 300 return jsonRequest(client, domain, ALIYUN_API_VERSION_LB, apiName, params, self.client.debug) 301 } 302 303 ///////////////////////////////////////////////////////////////////////////// 304 func (self *SRegion) GetId() string { 305 return self.RegionId 306 } 307 308 func (self *SRegion) GetName() string { 309 if self.GetCloudEnv() == ALIYUN_FINANCE_CLOUDENV && !strings.Contains(self.LocalName, "金融") { 310 return fmt.Sprintf("%s %s %s", CLOUD_PROVIDER_ALIYUN_CN, self.LocalName, "金融云") 311 } else { 312 return fmt.Sprintf("%s %s", CLOUD_PROVIDER_ALIYUN_CN, self.LocalName) 313 } 314 } 315 316 func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { 317 en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_ALIYUN_EN, self.LocalName) 318 table := cloudprovider.SModelI18nTable{} 319 table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) 320 return table 321 } 322 323 func (self *SRegion) GetGlobalId() string { 324 return fmt.Sprintf("%s/%s", self.client.GetAccessEnv(), self.RegionId) 325 } 326 327 func (self *SRegion) IsEmulated() bool { 328 return false 329 } 330 331 func (self *SRegion) GetProvider() string { 332 return CLOUD_PROVIDER_ALIYUN 333 } 334 335 func (self *SRegion) GetCloudEnv() string { 336 return self.client.cloudEnv 337 } 338 339 func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { 340 if info, ok := LatitudeAndLongitude[self.RegionId]; ok { 341 return info 342 } 343 return cloudprovider.SGeographicInfo{} 344 } 345 346 func (self *SRegion) GetStatus() string { 347 return api.CLOUD_REGION_STATUS_INSERVER 348 } 349 350 func (self *SRegion) Refresh() error { 351 // do nothing 352 return nil 353 } 354 355 func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { 356 if self.izones == nil { 357 var err error 358 err = self.fetchInfrastructure() 359 if err != nil { 360 return nil, err 361 } 362 } 363 return self.izones, nil 364 } 365 366 func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { 367 izones, err := self.GetIZones() 368 if err != nil { 369 return nil, err 370 } 371 for i := 0; i < len(izones); i += 1 { 372 if izones[i].GetGlobalId() == id { 373 return izones[i], nil 374 } 375 } 376 return nil, cloudprovider.ErrNotFound 377 } 378 379 func (self *SRegion) getStoragecache() *SStoragecache { 380 if self.storageCache == nil { 381 self.storageCache = &SStoragecache{region: self} 382 } 383 return self.storageCache 384 } 385 386 func (self *SRegion) _fetchZones(chargeType TChargeType, spotStrategy SpotStrategyType) error { 387 params := make(map[string]string) 388 params["RegionId"] = self.RegionId 389 if len(chargeType) > 0 { 390 params["InstanceChargeType"] = string(chargeType) 391 } 392 if len(spotStrategy) > 0 { 393 params["SpotStrategy"] = string(spotStrategy) 394 } 395 body, err := self.ecsRequest("DescribeZones", params) 396 if err != nil { 397 return err 398 } 399 400 zones := make([]SZone, 0) 401 err = body.Unmarshal(&zones, "Zones", "Zone") 402 if err != nil { 403 return err 404 } 405 406 self.izones = make([]cloudprovider.ICloudZone, len(zones)) 407 408 for i := 0; i < len(zones); i += 1 { 409 zones[i].region = self 410 self.izones[i] = &zones[i] 411 } 412 413 return nil 414 } 415 416 func (self *SRegion) getZoneById(id string) (*SZone, error) { 417 izones, err := self.GetIZones() 418 if err != nil { 419 return nil, err 420 } 421 for i := 0; i < len(izones); i += 1 { 422 zone := izones[i].(*SZone) 423 if zone.ZoneId == id { 424 return zone, nil 425 } 426 } 427 return nil, fmt.Errorf("no such zone %s", id) 428 } 429 430 func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { 431 return self.GetInstance(id) 432 } 433 434 func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { 435 return self.getDisk(id) 436 } 437 438 func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { 439 if self.ivpcs == nil { 440 err := self.fetchInfrastructure() 441 if err != nil { 442 return nil, err 443 } 444 } 445 return self.ivpcs, nil 446 } 447 448 func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { 449 ivpcs, err := self.GetIVpcs() 450 if err != nil { 451 return nil, err 452 } 453 for i := 0; i < len(ivpcs); i += 1 { 454 if ivpcs[i].GetGlobalId() == id { 455 return ivpcs[i], nil 456 } 457 } 458 return nil, cloudprovider.ErrNotFound 459 } 460 461 func (self *SRegion) fetchIVpcs() error { 462 vpcs := make([]SVpc, 0) 463 for { 464 part, total, err := self.GetVpcs(nil, len(vpcs), 50) 465 if err != nil { 466 return err 467 } 468 vpcs = append(vpcs, part...) 469 if len(vpcs) >= total { 470 break 471 } 472 } 473 self.ivpcs = make([]cloudprovider.ICloudVpc, len(vpcs)) 474 for i := 0; i < len(vpcs); i += 1 { 475 vpcs[i].region = self 476 self.ivpcs[i] = &vpcs[i] 477 } 478 return nil 479 } 480 481 func (self *SRegion) fetchInfrastructure() error { 482 err := self._fetchZones(PostPaidInstanceChargeType, NoSpotStrategy) 483 if err != nil { 484 return err 485 } 486 err = self.fetchIVpcs() 487 if err != nil { 488 return err 489 } 490 for i := 0; i < len(self.ivpcs); i += 1 { 491 for j := 0; j < len(self.izones); j += 1 { 492 zone := self.izones[j].(*SZone) 493 vpc := self.ivpcs[i].(*SVpc) 494 wire := SWire{zone: zone, vpc: vpc} 495 zone.addWire(&wire) 496 vpc.addWire(&wire) 497 } 498 } 499 return nil 500 } 501 502 func (self *SRegion) GetVpcs(vpcId []string, offset int, limit int) ([]SVpc, int, error) { 503 if limit > 50 || limit <= 0 { 504 limit = 50 505 } 506 params := make(map[string]string) 507 params["RegionId"] = self.RegionId 508 params["PageSize"] = fmt.Sprintf("%d", limit) 509 params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) 510 511 if vpcId != nil && len(vpcId) > 0 { 512 params["VpcId"] = strings.Join(vpcId, ",") 513 } 514 515 body, err := self.vpcRequest("DescribeVpcs", params) 516 if err != nil { 517 log.Errorf("GetVpcs fail %s", err) 518 return nil, 0, err 519 } 520 521 vpcs := make([]SVpc, 0) 522 err = body.Unmarshal(&vpcs, "Vpcs", "Vpc") 523 if err != nil { 524 log.Errorf("Unmarshal vpc fail %s", err) 525 return nil, 0, err 526 } 527 total, _ := body.Int("TotalCount") 528 return vpcs, int(total), nil 529 } 530 531 func (self *SRegion) getVpc(vpcId string) (*SVpc, error) { 532 vpcs, total, err := self.GetVpcs([]string{vpcId}, 0, 1) 533 if err != nil { 534 return nil, err 535 } 536 if total != 1 { 537 return nil, cloudprovider.ErrNotFound 538 } 539 vpcs[0].region = self 540 return &vpcs[0], nil 541 } 542 543 func (self *SRegion) GetVRouters(offset int, limit int) ([]SVRouter, int, error) { 544 if limit > 50 || limit <= 0 { 545 limit = 50 546 } 547 params := make(map[string]string) 548 params["RegionId"] = self.RegionId 549 params["PageSize"] = fmt.Sprintf("%d", limit) 550 params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) 551 552 body, err := self.ecsRequest("DescribeVRouters", params) 553 if err != nil { 554 log.Errorf("GetVRouters fail %s", err) 555 return nil, 0, err 556 } 557 558 vrouters := make([]SVRouter, 0) 559 err = body.Unmarshal(&vrouters, "VRouters", "VRouter") 560 if err != nil { 561 log.Errorf("Unmarshal vrouter fail %s", err) 562 return nil, 0, err 563 } 564 total, _ := body.Int("TotalCount") 565 return vrouters, int(total), nil 566 } 567 568 func (self *SRegion) GetRouteTables(ids []string, offset int, limit int) ([]SRouteTable, int, error) { 569 if limit > 50 || limit <= 0 { 570 limit = 50 571 } 572 params := make(map[string]string) 573 params["RegionId"] = self.RegionId 574 params["PageSize"] = fmt.Sprintf("%d", limit) 575 params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) 576 if ids != nil && len(ids) > 0 { 577 params["RouteTableId"] = strings.Join(ids, ",") 578 } 579 580 body, err := self.ecsRequest("DescribeRouteTables", params) 581 if err != nil { 582 log.Errorf("GetRouteTables fail %s", err) 583 return nil, 0, err 584 } 585 586 routetables := make([]SRouteTable, 0) 587 err = body.Unmarshal(&routetables, "RouteTables", "RouteTable") 588 if err != nil { 589 log.Errorf("Unmarshal routetables fail %s", err) 590 return nil, 0, err 591 } 592 total, _ := body.Int("TotalCount") 593 return routetables, int(total), nil 594 } 595 596 func (self *SRegion) GetMatchInstanceTypes(cpu int, memMB int, gpu int, zoneId string) ([]SInstanceType, error) { 597 if self.instanceTypes == nil { 598 types, err := self.GetInstanceTypes() 599 if err != nil { 600 log.Errorf("GetInstanceTypes %s", err) 601 return nil, err 602 } 603 self.instanceTypes = types 604 } 605 var available []string 606 if len(zoneId) > 0 { 607 zone, err := self.getZoneById(zoneId) 608 if err != nil { 609 return nil, err 610 } 611 available = zone.AvailableInstanceTypes.InstanceTypes 612 } 613 ret := make([]SInstanceType, 0) 614 for _, t := range self.instanceTypes { 615 if t.CpuCoreCount == cpu && memMB == t.memoryMB() && gpu == t.GPUAmount { 616 if available == nil || utils.IsInStringArray(t.InstanceTypeId, available) { 617 ret = append(ret, t) 618 } 619 } 620 } 621 return ret, nil 622 } 623 624 func (self *SRegion) CreateInstanceSimple(name string, imgId string, cpu int, memGB int, storageType string, dataDiskSizesGB []int, vswitchId string, passwd string, publicKey string) (*SInstance, error) { 625 izones, err := self.GetIZones() 626 if err != nil { 627 return nil, err 628 } 629 for i := 0; i < len(izones); i += 1 { 630 z := izones[i].(*SZone) 631 log.Debugf("Search in zone %s", z.LocalName) 632 net := z.getNetworkById(vswitchId) 633 if net != nil { 634 desc := &cloudprovider.SManagedVMCreateConfig{ 635 Name: name, 636 ExternalImageId: imgId, 637 SysDisk: cloudprovider.SDiskInfo{SizeGB: 0, StorageType: storageType}, 638 Cpu: cpu, 639 MemoryMB: memGB * 1024, 640 ExternalNetworkId: vswitchId, 641 Password: passwd, 642 DataDisks: []cloudprovider.SDiskInfo{}, 643 PublicKey: publicKey, 644 } 645 for _, sizeGB := range dataDiskSizesGB { 646 desc.DataDisks = append(desc.DataDisks, cloudprovider.SDiskInfo{SizeGB: sizeGB, StorageType: storageType}) 647 } 648 inst, err := z.getHost().CreateVM(desc) 649 if err != nil { 650 return nil, err 651 } 652 return inst.(*SInstance), nil 653 } 654 } 655 return nil, fmt.Errorf("cannot find vswitch %s", vswitchId) 656 } 657 658 func (self *SRegion) instanceOperation(instanceId string, opname string, extra map[string]string) error { 659 params := make(map[string]string) 660 params["RegionId"] = self.RegionId 661 params["InstanceId"] = instanceId 662 if extra != nil && len(extra) > 0 { 663 for k, v := range extra { 664 params[k] = v 665 } 666 } 667 _, err := self.ecsRequest(opname, params) 668 return err 669 } 670 671 func (self *SRegion) GetInstanceStatus(instanceId string) (string, error) { 672 instance, err := self.GetInstance(instanceId) 673 if err != nil { 674 return "", err 675 } 676 return instance.Status, nil 677 } 678 679 func (self *SRegion) GetInstanceVNCUrl(instanceId string) (string, error) { 680 params := make(map[string]string) 681 params["RegionId"] = self.RegionId 682 params["InstanceId"] = instanceId 683 body, err := self.ecsRequest("DescribeInstanceVncUrl", params) 684 if err != nil { 685 return "", err 686 } 687 return body.GetString("VncUrl") 688 } 689 690 func (self *SRegion) ModifyInstanceVNCUrlPassword(instanceId string, passwd string) error { 691 params := make(map[string]string) 692 params["RegionId"] = self.RegionId 693 params["InstanceId"] = instanceId 694 params["VncPassword"] = passwd // must be 6 digital + alphabet 695 _, err := self.ecsRequest("ModifyInstanceVncPasswd", params) 696 return err 697 } 698 699 func (self *SRegion) CreateVpc(opts *cloudprovider.VpcCreateOptions) (*SVpc, error) { 700 params := make(map[string]string) 701 if len(opts.CIDR) > 0 { 702 params["CidrBlock"] = opts.CIDR 703 } 704 if len(opts.NAME) > 0 { 705 params["VpcName"] = opts.NAME 706 } 707 if len(opts.Desc) > 0 { 708 params["Description"] = opts.Desc 709 } 710 params["ClientToken"] = utils.GenRequestId(20) 711 body, err := self.ecsRequest("CreateVpc", params) 712 if err != nil { 713 return nil, err 714 } 715 vpcId, err := body.GetString("VpcId") 716 if err != nil { 717 return nil, err 718 } 719 err = self.fetchInfrastructure() 720 if err != nil { 721 return nil, err 722 } 723 return self.getVpc(vpcId) 724 } 725 726 func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { 727 vpc, err := self.CreateVpc(opts) 728 if err != nil { 729 return nil, err 730 } 731 return vpc, nil 732 } 733 734 func (self *SRegion) DeleteVpc(vpcId string) error { 735 params := make(map[string]string) 736 params["VpcId"] = vpcId 737 738 _, err := self.ecsRequest("DeleteVpc", params) 739 return err 740 } 741 742 func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { 743 izones, err := self.GetIZones() 744 if err != nil { 745 return nil, err 746 } 747 for i := 0; i < len(izones); i += 1 { 748 ihost, err := izones[i].GetIHostById(id) 749 if err == nil { 750 return ihost, nil 751 } else if errors.Cause(err) != cloudprovider.ErrNotFound { 752 return nil, err 753 } 754 } 755 return nil, cloudprovider.ErrNotFound 756 } 757 758 func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { 759 izones, err := self.GetIZones() 760 if err != nil { 761 return nil, err 762 } 763 for i := 0; i < len(izones); i += 1 { 764 istore, err := izones[i].GetIStorageById(id) 765 if err == nil { 766 return istore, nil 767 } else if errors.Cause(err) != cloudprovider.ErrNotFound { 768 return nil, err 769 } 770 } 771 return nil, cloudprovider.ErrNotFound 772 } 773 774 func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { 775 iHosts := make([]cloudprovider.ICloudHost, 0) 776 777 izones, err := self.GetIZones() 778 if err != nil { 779 return nil, err 780 } 781 for i := 0; i < len(izones); i += 1 { 782 iZoneHost, err := izones[i].GetIHosts() 783 if err != nil { 784 return nil, err 785 } 786 iHosts = append(iHosts, iZoneHost...) 787 } 788 return iHosts, nil 789 } 790 791 func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { 792 iStores := make([]cloudprovider.ICloudStorage, 0) 793 794 izones, err := self.GetIZones() 795 if err != nil { 796 return nil, err 797 } 798 for i := 0; i < len(izones); i += 1 { 799 iZoneStores, err := izones[i].GetIStorages() 800 if err != nil { 801 return nil, err 802 } 803 iStores = append(iStores, iZoneStores...) 804 } 805 return iStores, nil 806 } 807 808 func (self *SRegion) updateInstance(instId string, name, desc, passwd, hostname, userData string) error { 809 params := make(map[string]string) 810 params["InstanceId"] = instId 811 if len(name) > 0 { 812 params["InstanceName"] = name 813 } 814 if len(desc) > 0 { 815 params["Description"] = desc 816 } 817 if len(passwd) > 0 { 818 params["Password"] = passwd 819 } 820 if len(hostname) > 0 { 821 params["HostName"] = hostname 822 } 823 if len(userData) > 0 { 824 params["UserData"] = userData 825 } 826 _, err := self.ecsRequest("ModifyInstanceAttribute", params) 827 return err 828 } 829 830 func (self *SRegion) UpdateInstancePassword(instId string, passwd string) error { 831 return self.updateInstance(instId, "", "", passwd, "", "") 832 } 833 834 // func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { 835 // eips, total, err := self.GetSnapshots("", 0, 50) 836 // if err != nil { 837 // return nil, err 838 // } 839 // for len(eips) < total { 840 // var parts []SEipAddress 841 // parts, total, err = self.GetEips("", len(eips), 50) 842 // if err != nil { 843 // return nil, err 844 // } 845 // eips = append(eips, parts...) 846 // } 847 // ret := make([]cloudprovider.ICloudEIP, len(eips)) 848 // for i := 0; i < len(eips); i += 1 { 849 // ret[i] = &eips[i] 850 // } 851 // return ret, nil 852 // } 853 854 func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { 855 eips, total, err := self.GetEips("", "", "", 0, 50) 856 if err != nil { 857 return nil, err 858 } 859 for len(eips) < total { 860 var parts []SEipAddress 861 parts, total, err = self.GetEips("", "", "", len(eips), 50) 862 if err != nil { 863 return nil, err 864 } 865 eips = append(eips, parts...) 866 } 867 ret := make([]cloudprovider.ICloudEIP, len(eips)) 868 for i := 0; i < len(eips); i += 1 { 869 ret[i] = &eips[i] 870 } 871 return ret, nil 872 } 873 874 func (self *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) { 875 eips, total, err := self.GetEips(eipId, "", "", 0, 1) 876 if err != nil { 877 return nil, err 878 } 879 if total == 0 { 880 return nil, cloudprovider.ErrNotFound 881 } 882 if total > 1 { 883 return nil, cloudprovider.ErrDuplicateId 884 } 885 return &eips[0], nil 886 } 887 888 func (region *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { 889 secgroup, err := region.GetSecurityGroupDetails(secgroupId) 890 if err != nil { 891 return nil, err 892 } 893 vpc, err := region.getVpc(secgroup.VpcId) 894 if err != nil { 895 return nil, errors.Wrapf(err, "region.getVpc(%s)", secgroup.VpcId) 896 } 897 secgroup.vpc = vpc 898 return secgroup, nil 899 } 900 901 func (region *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { 902 secgroups, total, err := region.GetSecurityGroups(opts.VpcId, opts.Name, []string{}, 0, 0) 903 if err != nil { 904 return nil, err 905 } 906 if total == 0 { 907 return nil, cloudprovider.ErrNotFound 908 } 909 if total > 1 { 910 return nil, cloudprovider.ErrDuplicateId 911 } 912 return &secgroups[0], nil 913 } 914 915 func (region *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { 916 externalId, err := region.CreateSecurityGroup(conf.VpcId, conf.Name, conf.Desc) 917 if err != nil { 918 return nil, err 919 } 920 return region.GetISecurityGroupById(externalId) 921 } 922 923 func (region *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { 924 lbs, err := region.GetLoadbalancers(nil) 925 if err != nil { 926 return nil, err 927 } 928 ilbs := []cloudprovider.ICloudLoadbalancer{} 929 for i := 0; i < len(lbs); i++ { 930 lbs[i].region = region 931 ilbs = append(ilbs, &lbs[i]) 932 } 933 return ilbs, nil 934 } 935 936 func (region *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) { 937 return region.GetLoadbalancerDetail(loadbalancerId) 938 } 939 940 func (region *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { 941 certs, err := region.GetLoadbalancerServerCertificates() 942 if err != nil { 943 return nil, err 944 } 945 for i := 0; i < len(certs); i++ { 946 if certs[i].GetGlobalId() == certId { 947 certs[i].region = region 948 return &certs[i], nil 949 } 950 } 951 return nil, cloudprovider.ErrNotFound 952 } 953 954 func (region *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) { 955 params := map[string]string{} 956 params["RegionId"] = region.RegionId 957 params["ServerCertificateName"] = cert.Name 958 params["PrivateKey"] = cert.PrivateKey 959 params["ServerCertificate"] = cert.Certificate 960 body, err := region.lbRequest("UploadServerCertificate", params) 961 if err != nil { 962 return nil, err 963 } 964 certID, err := body.GetString("ServerCertificateId") 965 if err != nil { 966 return nil, err 967 } 968 return region.GetILoadBalancerCertificateById(certID) 969 } 970 971 func (region *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) { 972 return region.GetLoadbalancerAclDetail(aclId) 973 } 974 975 func (region *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) { 976 acls, err := region.GetLoadBalancerAcls() 977 if err != nil { 978 return nil, err 979 } 980 iAcls := []cloudprovider.ICloudLoadbalancerAcl{} 981 for i := 0; i < len(acls); i++ { 982 acls[i].region = region 983 iAcls = append(iAcls, &acls[i]) 984 } 985 return iAcls, nil 986 } 987 988 func (region *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { 989 certificates, err := region.GetLoadbalancerServerCertificates() 990 if err != nil { 991 return nil, err 992 } 993 iCertificates := []cloudprovider.ICloudLoadbalancerCertificate{} 994 for i := 0; i < len(certificates); i++ { 995 certificates[i].region = region 996 iCertificates = append(iCertificates, &certificates[i]) 997 } 998 return iCertificates, nil 999 } 1000 1001 func (region *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) { 1002 params := map[string]string{} 1003 params["RegionId"] = region.RegionId 1004 params["LoadBalancerName"] = loadbalancer.Name 1005 if len(loadbalancer.ZoneID) > 0 { 1006 params["MasterZoneId"] = transZoneIdFromEcsZoneId(region, "elb", loadbalancer.ZoneID) 1007 } 1008 1009 if len(loadbalancer.VpcID) > 0 { 1010 params["VpcId"] = loadbalancer.VpcID 1011 } 1012 1013 if len(loadbalancer.NetworkIDs) > 0 { 1014 params["VSwitchId"] = loadbalancer.NetworkIDs[0] 1015 } 1016 1017 if len(loadbalancer.Address) > 0 { 1018 params["Address"] = loadbalancer.Address 1019 } 1020 1021 if len(loadbalancer.AddressType) > 0 { 1022 params["AddressType"] = loadbalancer.AddressType 1023 } 1024 1025 if len(loadbalancer.LoadbalancerSpec) > 0 { 1026 params["LoadBalancerSpec"] = loadbalancer.LoadbalancerSpec 1027 } 1028 1029 if len(loadbalancer.ChargeType) > 0 { 1030 params["InternetChargeType"] = "payby" + loadbalancer.ChargeType 1031 } 1032 1033 if len(loadbalancer.ProjectId) > 0 { 1034 params["ResourceGroupId"] = loadbalancer.ProjectId 1035 } 1036 1037 if loadbalancer.ChargeType == api.LB_CHARGE_TYPE_BY_BANDWIDTH && loadbalancer.EgressMbps > 0 { 1038 params["Bandwidth"] = fmt.Sprintf("%d", loadbalancer.EgressMbps) 1039 } 1040 1041 body, err := region.lbRequest("CreateLoadBalancer", params) 1042 if err != nil { 1043 return nil, err 1044 } 1045 loadBalancerID, err := body.GetString("LoadBalancerId") 1046 if err != nil { 1047 return nil, err 1048 } 1049 region.SetResourceTags(ALIYUN_SERVICE_SLB, "instance", loadBalancerID, loadbalancer.Tags, false) 1050 iLoadbalancer, err := region.GetLoadbalancerDetail(loadBalancerID) 1051 if err != nil { 1052 return nil, err 1053 } 1054 return iLoadbalancer, cloudprovider.WaitStatus(iLoadbalancer, api.LB_STATUS_ENABLED, time.Second*5, time.Minute*5) 1055 } 1056 1057 func (region *SRegion) AddAccessControlListEntry(aclId string, entrys []cloudprovider.SLoadbalancerAccessControlListEntry) error { 1058 params := map[string]string{} 1059 params["RegionId"] = region.RegionId 1060 params["AclId"] = aclId 1061 aclArray := jsonutils.NewArray() 1062 for i := 0; i < len(entrys); i++ { 1063 //阿里云AclEntrys参数必须是CIDR格式的。 1064 if regutils.MatchIPAddr(entrys[i].CIDR) { 1065 entrys[i].CIDR += "/32" 1066 } 1067 aclArray.Add(jsonutils.Marshal(map[string]string{"entry": entrys[i].CIDR, "comment": entrys[i].Comment})) 1068 } 1069 if aclArray.Length() == 0 { 1070 return nil 1071 } 1072 params["AclEntrys"] = aclArray.String() 1073 _, err := region.lbRequest("AddAccessControlListEntry", params) 1074 return err 1075 } 1076 1077 func (region *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) { 1078 params := map[string]string{} 1079 params["RegionId"] = region.RegionId 1080 params["AclName"] = acl.Name 1081 body, err := region.lbRequest("CreateAccessControlList", params) 1082 if err != nil { 1083 return nil, err 1084 } 1085 aclId, err := body.GetString("AclId") 1086 if err != nil { 1087 return nil, err 1088 } 1089 iAcl, err := region.GetLoadbalancerAclDetail(aclId) 1090 if err != nil { 1091 return nil, err 1092 } 1093 return iAcl, region.AddAccessControlListEntry(aclId, acl.Entrys) 1094 } 1095 1096 func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) { 1097 iBuckets, err := region.client.getIBuckets() 1098 if err != nil { 1099 return nil, errors.Wrap(err, "getIBuckets") 1100 } 1101 ret := make([]cloudprovider.ICloudBucket, 0) 1102 for i := range iBuckets { 1103 if iBuckets[i].GetIRegion().GetId() != region.GetId() { 1104 continue 1105 } 1106 ret = append(ret, iBuckets[i]) 1107 } 1108 return ret, nil 1109 } 1110 1111 func str2StorageClass(storageClassStr string) (oss.StorageClassType, error) { 1112 storageClass := oss.StorageStandard 1113 if strings.EqualFold(storageClassStr, string(oss.StorageStandard)) { 1114 // 1115 } else if strings.EqualFold(storageClassStr, string(oss.StorageIA)) { 1116 storageClass = oss.StorageIA 1117 } else if strings.EqualFold(storageClassStr, string(oss.StorageArchive)) { 1118 storageClass = oss.StorageArchive 1119 } else { 1120 return storageClass, errors.Error("not supported storageClass") 1121 } 1122 return storageClass, nil 1123 } 1124 1125 func str2Acl(aclStr string) (oss.ACLType, error) { 1126 acl := oss.ACLPrivate 1127 if strings.EqualFold(aclStr, string(oss.ACLPrivate)) { 1128 // private, default 1129 } else if strings.EqualFold(aclStr, string(oss.ACLPublicRead)) { 1130 acl = oss.ACLPublicRead 1131 } else if strings.EqualFold(aclStr, string(oss.ACLPublicReadWrite)) { 1132 acl = oss.ACLPublicReadWrite 1133 } else { 1134 return acl, errors.Error("not supported acl") 1135 } 1136 return acl, nil 1137 } 1138 1139 func (region *SRegion) CreateIBucket(name string, storageClassStr string, aclStr string) error { 1140 osscli, err := region.GetOssClient() 1141 if err != nil { 1142 return errors.Wrap(err, "region.GetOssClient") 1143 } 1144 opts := make([]oss.Option, 0) 1145 if len(storageClassStr) > 0 { 1146 storageClass, err := str2StorageClass(storageClassStr) 1147 if err != nil { 1148 return err 1149 } 1150 opts = append(opts, oss.StorageClass(storageClass)) 1151 } 1152 if len(aclStr) > 0 { 1153 acl, err := str2Acl(aclStr) 1154 if err != nil { 1155 return err 1156 } 1157 opts = append(opts, oss.ACL(acl)) 1158 } 1159 err = osscli.CreateBucket(name, opts...) 1160 if err != nil { 1161 return errors.Wrap(err, "oss.CreateBucket") 1162 } 1163 region.client.invalidateIBuckets() 1164 return nil 1165 } 1166 1167 func ossErrorCode(err error) int { 1168 if srvErr, ok := err.(oss.ServiceError); ok { 1169 return srvErr.StatusCode 1170 } 1171 if srvErr, ok := err.(*oss.ServiceError); ok { 1172 return srvErr.StatusCode 1173 } 1174 return -1 1175 } 1176 1177 func (region *SRegion) DeleteIBucket(name string) error { 1178 osscli, err := region.GetOssClient() 1179 if err != nil { 1180 return errors.Wrap(err, "region.GetOssClient") 1181 } 1182 err = osscli.DeleteBucket(name) 1183 if err != nil { 1184 if ossErrorCode(err) == 404 { 1185 return nil 1186 } 1187 return errors.Wrap(err, "DeleteBucket") 1188 } 1189 region.client.invalidateIBuckets() 1190 return nil 1191 } 1192 1193 func (region *SRegion) IBucketExist(name string) (bool, error) { 1194 osscli, err := region.GetOssClient() 1195 if err != nil { 1196 return false, errors.Wrap(err, "region.GetOssClient") 1197 } 1198 exist, err := osscli.IsBucketExist(name) 1199 if err != nil { 1200 return false, errors.Wrap(err, "IsBucketExist") 1201 } 1202 return exist, nil 1203 } 1204 1205 func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) { 1206 osscli, err := region.GetOssClient() 1207 if err != nil { 1208 return nil, errors.Wrap(err, "region.GetOssClient") 1209 } 1210 bi, err := osscli.GetBucketInfo(name) 1211 if err != nil { 1212 return nil, errors.Wrap(err, "Bucket") 1213 } 1214 bInfo := bi.BucketInfo 1215 b := SBucket{ 1216 region: region, 1217 Name: bInfo.Name, 1218 Location: bInfo.Location, 1219 CreationDate: bInfo.CreationDate, 1220 StorageClass: bInfo.StorageClass, 1221 } 1222 return &b, nil 1223 } 1224 1225 func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { 1226 return region.GetIBucketById(name) 1227 } 1228 1229 func (self *SRegion) GetIElasticcaches() ([]cloudprovider.ICloudElasticcache, error) { 1230 caches, err := self.GetElasticCaches(nil) 1231 if err != nil { 1232 return nil, err 1233 } 1234 1235 icaches := make([]cloudprovider.ICloudElasticcache, len(caches)) 1236 for i := range caches { 1237 caches[i].region = self 1238 icaches[i] = &caches[i] 1239 } 1240 1241 return icaches, nil 1242 } 1243 1244 func (region *SRegion) GetCapabilities() []string { 1245 return region.client.GetCapabilities() 1246 } 1247 1248 func (self *SRegion) trialRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { 1249 client, err := self.getSdkClient() 1250 if err != nil { 1251 return nil, err 1252 } 1253 domain := fmt.Sprintf("actiontrail.%s.aliyuncs.com", self.RegionId) 1254 return jsonRequest(client, domain, ALIYUN_API_VERSION_TRIAL, apiName, params, self.client.debug) 1255 }