mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-19 10:46:58 +08:00
1098 lines
28 KiB
Go
1098 lines
28 KiB
Go
// Copyright 2019 Yunion
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package aws
|
|
|
|
import (
|
|
"encoding/xml"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"net/url"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
|
"github.com/aws/aws-sdk-go/aws/client"
|
|
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
|
"github.com/aws/aws-sdk-go/aws/request"
|
|
"github.com/aws/aws-sdk-go/aws/session"
|
|
v4 "github.com/aws/aws-sdk-go/aws/signer/v4"
|
|
"github.com/aws/aws-sdk-go/private/protocol/query"
|
|
"github.com/aws/aws-sdk-go/service/acm"
|
|
"github.com/aws/aws-sdk-go/service/cloudwatch"
|
|
"github.com/aws/aws-sdk-go/service/ec2"
|
|
"github.com/aws/aws-sdk-go/service/elbv2"
|
|
"github.com/aws/aws-sdk-go/service/iam"
|
|
"github.com/aws/aws-sdk-go/service/s3"
|
|
|
|
"yunion.io/x/jsonutils"
|
|
"yunion.io/x/log"
|
|
"yunion.io/x/pkg/errors"
|
|
|
|
api "yunion.io/x/onecloud/pkg/apis/compute"
|
|
"yunion.io/x/onecloud/pkg/cloudprovider"
|
|
"yunion.io/x/onecloud/pkg/multicloud"
|
|
)
|
|
|
|
var RegionLocations = map[string]string{
|
|
"us-east-2": "美国东部(俄亥俄州)",
|
|
"us-east-1": "美国东部(弗吉尼亚北部)",
|
|
"us-west-1": "美国西部(加利福尼亚北部)",
|
|
"us-west-2": "美国西部(俄勒冈)",
|
|
"ap-east-1": "亚太区域(香港)",
|
|
"ap-south-1": "亚太区域(孟买)",
|
|
"ap-northeast-3": "亚太区域(大阪-本地)",
|
|
"ap-northeast-2": "亚太区域(首尔)",
|
|
"ap-southeast-1": "亚太区域(新加坡)",
|
|
"ap-southeast-2": "亚太区域(悉尼)",
|
|
"ap-northeast-1": "亚太区域(东京)",
|
|
"ca-central-1": "加拿大(中部)",
|
|
"cn-north-1": "中国(北京)",
|
|
"cn-northwest-1": "中国(宁夏)",
|
|
"eu-central-1": "欧洲(法兰克福)",
|
|
"eu-west-1": "欧洲(爱尔兰)",
|
|
"eu-west-2": "欧洲(伦敦)",
|
|
"eu-west-3": "欧洲(巴黎)",
|
|
"eu-north-1": "欧洲(斯德哥尔摩)",
|
|
"me-south-1": "中东(巴林)",
|
|
"sa-east-1": "南美洲(圣保罗)",
|
|
"us-gov-west-1": "AWS GovCloud(美国西部)",
|
|
"us-gov-east-1": "AWS GovCloud(美国东部)",
|
|
}
|
|
|
|
const (
|
|
RDS_SERVICE_NAME = "rds"
|
|
RDS_SERVICE_ID = "RDS"
|
|
|
|
EC2_SERVICE_NAME = "ec2"
|
|
EC2_SERVICE_ID = "EC2"
|
|
|
|
CLOUDWATCH_SERVICE_NAME = "monitoring"
|
|
CLOUDWATCH_SERVICE_ID = "CloudWatch"
|
|
)
|
|
|
|
type SRegion struct {
|
|
multicloud.SRegion
|
|
|
|
client *SAwsClient
|
|
ec2Client *ec2.EC2
|
|
iamClient *iam.IAM
|
|
s3Client *s3.S3
|
|
elbv2Client *elbv2.ELBV2
|
|
acmClient *acm.ACM
|
|
|
|
izones []cloudprovider.ICloudZone
|
|
ivpcs []cloudprovider.ICloudVpc
|
|
|
|
storageCache *SStoragecache
|
|
|
|
RegionEndpoint string
|
|
RegionId string // 这里为保持一致沿用阿里云RegionId的叫法, 与AWS RegionName字段对应
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/* 请不要使用这个client(AWS_DEFAULT_REGION)跨region查信息.有可能导致查询返回的信息为空。比如DescribeAvailabilityZones*/
|
|
func (self *SRegion) GetClient() *SAwsClient {
|
|
return self.client
|
|
}
|
|
|
|
func (self *SRegion) getAwsSession() (*session.Session, error) {
|
|
return self.client.getAwsSession(self.RegionId)
|
|
}
|
|
|
|
func (self *SRegion) getEc2Client() (*ec2.EC2, error) {
|
|
if self.ec2Client == nil {
|
|
s, err := self.getAwsSession()
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
self.ec2Client = ec2.New(s)
|
|
return self.ec2Client, nil
|
|
}
|
|
|
|
return self.ec2Client, nil
|
|
}
|
|
|
|
func (self *SRegion) getIamClient() (*iam.IAM, error) {
|
|
if self.iamClient == nil {
|
|
s, err := self.getAwsSession()
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
self.iamClient = iam.New(s)
|
|
}
|
|
|
|
return self.iamClient, nil
|
|
}
|
|
|
|
func (self *SRegion) GetS3Client() (*s3.S3, error) {
|
|
if self.s3Client == nil {
|
|
s, err := self.getAwsSession()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
self.s3Client = s3.New(s)
|
|
}
|
|
return self.s3Client, nil
|
|
}
|
|
|
|
var UnmarshalHandler = request.NamedHandler{Name: "yunion.query.Unmarshal", Fn: Unmarshal}
|
|
|
|
func Unmarshal(r *request.Request) {
|
|
defer r.HTTPResponse.Body.Close()
|
|
if r.DataFilled() {
|
|
var decoder *xml.Decoder
|
|
if DEBUG {
|
|
body, err := ioutil.ReadAll(r.HTTPResponse.Body)
|
|
if err != nil {
|
|
r.Error = awserr.NewRequestFailure(
|
|
awserr.New("ioutil.ReadAll", "read response body", err),
|
|
r.HTTPResponse.StatusCode,
|
|
r.RequestID,
|
|
)
|
|
return
|
|
}
|
|
log.Debugf("response: \n%s", string(body))
|
|
decoder = xml.NewDecoder(strings.NewReader(string(body)))
|
|
} else {
|
|
decoder = xml.NewDecoder(r.HTTPResponse.Body)
|
|
}
|
|
if r.ClientInfo.ServiceID == EC2_SERVICE_ID {
|
|
err := decoder.Decode(r.Data)
|
|
if err != nil {
|
|
r.Error = awserr.NewRequestFailure(
|
|
awserr.New("SerializationError", "failed decoding EC2 Query response", err),
|
|
r.HTTPResponse.StatusCode,
|
|
r.RequestID,
|
|
)
|
|
}
|
|
return
|
|
}
|
|
for {
|
|
tok, err := decoder.Token()
|
|
if err != nil {
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
r.Error = awserr.NewRequestFailure(
|
|
awserr.New("decoder.Token()", "get token", err),
|
|
r.HTTPResponse.StatusCode,
|
|
r.RequestID,
|
|
)
|
|
return
|
|
}
|
|
|
|
if tok == nil {
|
|
break
|
|
}
|
|
|
|
switch typed := tok.(type) {
|
|
case xml.CharData:
|
|
continue
|
|
case xml.StartElement:
|
|
if typed.Name.Local == r.Operation.Name+"Result" {
|
|
err = decoder.DecodeElement(r.Data, &typed)
|
|
if err != nil {
|
|
r.Error = awserr.NewRequestFailure(
|
|
awserr.New("DecodeElement", "failed decoding Query response", err),
|
|
r.HTTPResponse.StatusCode,
|
|
r.RequestID,
|
|
)
|
|
}
|
|
return
|
|
}
|
|
case xml.EndElement:
|
|
break
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
var buildHandler = request.NamedHandler{Name: "yunion.query.Build", Fn: Build}
|
|
|
|
func Build(r *request.Request) {
|
|
body := url.Values{
|
|
"Action": {r.Operation.Name},
|
|
"Version": {r.ClientInfo.APIVersion},
|
|
}
|
|
if r.Params != nil {
|
|
if params, ok := r.Params.(map[string]string); ok {
|
|
for k, v := range params {
|
|
body.Add(k, v)
|
|
}
|
|
}
|
|
}
|
|
|
|
if DEBUG {
|
|
log.Debugf("params: %s", body.Encode())
|
|
}
|
|
|
|
if !r.IsPresigned() {
|
|
r.HTTPRequest.Method = "POST"
|
|
r.HTTPRequest.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=utf-8")
|
|
r.SetBufferBody([]byte(body.Encode()))
|
|
} else { // This is a pre-signed request
|
|
r.HTTPRequest.Method = "GET"
|
|
r.HTTPRequest.URL.RawQuery = body.Encode()
|
|
}
|
|
}
|
|
|
|
func (self *SRegion) rdsRequest(apiName string, params map[string]string, retval interface{}) error {
|
|
session, err := self.getAwsSession()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
c := session.ClientConfig(RDS_SERVICE_NAME)
|
|
metadata := metadata.ClientInfo{
|
|
ServiceName: RDS_SERVICE_NAME,
|
|
ServiceID: RDS_SERVICE_ID,
|
|
SigningName: c.SigningName,
|
|
SigningRegion: c.SigningRegion,
|
|
Endpoint: c.Endpoint,
|
|
APIVersion: "2014-10-31",
|
|
}
|
|
|
|
if self.client.debug {
|
|
logLevel := aws.LogLevelType(uint(aws.LogDebugWithRequestErrors) + uint(aws.LogDebugWithHTTPBody))
|
|
c.Config.LogLevel = &logLevel
|
|
}
|
|
|
|
client := client.New(*c.Config, metadata, c.Handlers)
|
|
client.Handlers.Sign.PushBackNamed(v4.SignRequestHandler)
|
|
client.Handlers.Build.PushBackNamed(buildHandler)
|
|
client.Handlers.Unmarshal.PushBackNamed(UnmarshalHandler)
|
|
client.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler)
|
|
client.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler)
|
|
return jsonRequest(client, apiName, params, retval, true)
|
|
}
|
|
|
|
func (self *SRegion) ec2Request(apiName string, params map[string]string, retval interface{}) error {
|
|
session, err := self.getAwsSession()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
c := session.ClientConfig(EC2_SERVICE_NAME)
|
|
metadata := metadata.ClientInfo{
|
|
ServiceName: EC2_SERVICE_NAME,
|
|
ServiceID: EC2_SERVICE_ID,
|
|
SigningName: c.SigningName,
|
|
SigningRegion: c.SigningRegion,
|
|
Endpoint: c.Endpoint,
|
|
APIVersion: "2016-11-15",
|
|
}
|
|
|
|
requestErr := aws.LogDebugWithRequestErrors
|
|
|
|
c.Config.LogLevel = &requestErr
|
|
|
|
client := client.New(*c.Config, metadata, c.Handlers)
|
|
client.Handlers.Sign.PushBackNamed(v4.SignRequestHandler)
|
|
client.Handlers.Build.PushBackNamed(buildHandler)
|
|
client.Handlers.Unmarshal.PushBackNamed(UnmarshalHandler)
|
|
client.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler)
|
|
client.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler)
|
|
return jsonRequest(client, apiName, params, retval, true)
|
|
}
|
|
|
|
func (self *SRegion) cloudWatchRequest(apiName string, params *cloudwatch.GetMetricStatisticsInput,
|
|
retval interface{}) error {
|
|
session, err := self.getAwsSession()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
c := session.ClientConfig(CLOUDWATCH_SERVICE_NAME)
|
|
metadata := metadata.ClientInfo{
|
|
ServiceName: CLOUDWATCH_SERVICE_NAME,
|
|
ServiceID: CLOUDWATCH_SERVICE_ID,
|
|
SigningName: c.SigningName,
|
|
SigningRegion: c.SigningRegion,
|
|
Endpoint: c.Endpoint,
|
|
APIVersion: "2010-08-01",
|
|
}
|
|
|
|
requestErr := aws.LogDebugWithRequestErrors
|
|
|
|
c.Config.LogLevel = &requestErr
|
|
|
|
client := client.New(*c.Config, metadata, c.Handlers)
|
|
client.Handlers.Sign.PushBackNamed(v4.SignRequestHandler)
|
|
client.Handlers.Build.PushBackNamed(query.BuildHandler)
|
|
client.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler)
|
|
client.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler)
|
|
client.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler)
|
|
return cloudWatchRequest(client, apiName, params, retval, true)
|
|
}
|
|
|
|
func (self *SRegion) GetElbV2Client() (*elbv2.ELBV2, error) {
|
|
if self.elbv2Client == nil {
|
|
s, err := self.getAwsSession()
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
self.elbv2Client = elbv2.New(s)
|
|
}
|
|
|
|
return self.elbv2Client, nil
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
func (self *SRegion) fetchZones() error {
|
|
// todo: 这里将过滤出指定region下全部的zones。是否只过滤出可用的zone即可? The state of the Availability Zone (available | information | impaired | unavailable)
|
|
zones, err := self.ec2Client.DescribeAvailabilityZones(&ec2.DescribeAvailabilityZonesInput{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = FillZero(zones)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
self.izones = make([]cloudprovider.ICloudZone, 0)
|
|
for _, zone := range zones.AvailabilityZones {
|
|
self.izones = append(self.izones, &SZone{ZoneId: *zone.ZoneName, State: *zone.State, LocalName: *zone.ZoneName, region: self})
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (self *SRegion) fetchIVpcs() error {
|
|
vpcs, err := self.ec2Client.DescribeVpcs(&ec2.DescribeVpcsInput{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
self.ivpcs = make([]cloudprovider.ICloudVpc, 0)
|
|
for _, vpc := range vpcs.Vpcs {
|
|
tags := make(map[string]string, 0)
|
|
for _, tag := range vpc.Tags {
|
|
tags[*tag.Key] = *tag.Value
|
|
}
|
|
|
|
self.ivpcs = append(self.ivpcs, &SVpc{region: self,
|
|
CidrBlock: *vpc.CidrBlock,
|
|
Tags: tags,
|
|
IsDefault: *vpc.IsDefault,
|
|
RegionId: self.RegionId,
|
|
Status: *vpc.State,
|
|
VpcId: *vpc.VpcId,
|
|
VpcName: tags["Name"],
|
|
InstanceTenancy: *vpc.InstanceTenancy,
|
|
})
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (self *SRegion) fetchInfrastructure() error {
|
|
if _, err := self.getEc2Client(); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := self.fetchZones(); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := self.fetchIVpcs(); err != nil {
|
|
return err
|
|
}
|
|
|
|
for i := 0; i < len(self.ivpcs); i += 1 {
|
|
for j := 0; j < len(self.izones); j += 1 {
|
|
zone := self.izones[j].(*SZone)
|
|
vpc := self.ivpcs[i].(*SVpc)
|
|
wire := SWire{zone: zone, vpc: vpc}
|
|
zone.addWire(&wire)
|
|
vpc.addWire(&wire)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (self *SRegion) GetId() string {
|
|
return self.RegionId
|
|
}
|
|
|
|
func (self *SRegion) GetName() string {
|
|
if localName, ok := RegionLocations[self.RegionId]; ok {
|
|
return fmt.Sprintf("%s %s", CLOUD_PROVIDER_AWS_CN, localName)
|
|
}
|
|
|
|
return fmt.Sprintf("%s %s", CLOUD_PROVIDER_AWS_CN, self.RegionId)
|
|
}
|
|
|
|
func (self *SRegion) GetGlobalId() string {
|
|
return fmt.Sprintf("%s/%s", self.client.GetAccessEnv(), self.RegionId)
|
|
}
|
|
|
|
func (self *SRegion) GetStatus() string {
|
|
return api.CLOUD_REGION_STATUS_INSERVER
|
|
}
|
|
|
|
func (self *SRegion) Refresh() error {
|
|
return nil
|
|
}
|
|
|
|
func (self *SRegion) IsEmulated() bool {
|
|
return false
|
|
}
|
|
|
|
func (self *SRegion) GetMetadata() *jsonutils.JSONDict {
|
|
return nil
|
|
}
|
|
|
|
func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo {
|
|
if info, ok := LatitudeAndLongitude[self.RegionId]; ok {
|
|
return info
|
|
}
|
|
return cloudprovider.SGeographicInfo{}
|
|
}
|
|
|
|
func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) {
|
|
if self.izones == nil {
|
|
if err := self.fetchInfrastructure(); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return self.izones, nil
|
|
}
|
|
|
|
func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) {
|
|
if self.ivpcs == nil {
|
|
err := self.fetchInfrastructure()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return self.ivpcs, nil
|
|
}
|
|
|
|
func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) {
|
|
return self.GetInstance(id)
|
|
}
|
|
|
|
func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) {
|
|
return self.GetDisk(id)
|
|
}
|
|
|
|
func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) {
|
|
_, err := self.getEc2Client()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
eips, total, err := self.GetEips("", "", 0, 0)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ret := make([]cloudprovider.ICloudEIP, total)
|
|
for i := 0; i < len(eips); i += 1 {
|
|
ret[i] = &eips[i]
|
|
}
|
|
return ret, nil
|
|
}
|
|
|
|
func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) {
|
|
snapshots, _, err := self.GetSnapshots("", "", "", []string{}, 0, 0)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ret := make([]cloudprovider.ICloudSnapshot, len(snapshots))
|
|
for i := 0; i < len(snapshots); i += 1 {
|
|
ret[i] = &snapshots[i]
|
|
}
|
|
return ret, nil
|
|
}
|
|
|
|
func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) {
|
|
izones, err := self.GetIZones()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, zone := range izones {
|
|
if zone.GetGlobalId() == id {
|
|
return zone, nil
|
|
}
|
|
}
|
|
|
|
return nil, ErrorNotFound()
|
|
}
|
|
|
|
func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) {
|
|
ivpcs, err := self.GetIVpcs()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, vpc := range ivpcs {
|
|
if vpc.GetGlobalId() == id {
|
|
return vpc, nil
|
|
}
|
|
}
|
|
|
|
return nil, ErrorNotFound()
|
|
}
|
|
|
|
func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) {
|
|
izones, err := self.GetIZones()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for i := 0; i < len(izones); i += 1 {
|
|
ihost, err := izones[i].GetIHostById(id)
|
|
if err == nil {
|
|
return ihost, nil
|
|
} else if err != cloudprovider.ErrNotFound {
|
|
return nil, err
|
|
}
|
|
}
|
|
return nil, ErrorNotFound()
|
|
}
|
|
|
|
func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
|
|
izones, err := self.GetIZones()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for i := 0; i < len(izones); i += 1 {
|
|
istore, err := izones[i].GetIStorageById(id)
|
|
if err == nil {
|
|
return istore, nil
|
|
} else if err != cloudprovider.ErrNotFound {
|
|
return nil, err
|
|
}
|
|
}
|
|
return nil, ErrorNotFound()
|
|
}
|
|
|
|
func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) {
|
|
iHosts := make([]cloudprovider.ICloudHost, 0)
|
|
|
|
izones, err := self.GetIZones()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for i := 0; i < len(izones); i += 1 {
|
|
iZoneHost, err := izones[i].GetIHosts()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
iHosts = append(iHosts, iZoneHost...)
|
|
}
|
|
return iHosts, nil
|
|
}
|
|
|
|
func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
|
|
iStores := make([]cloudprovider.ICloudStorage, 0)
|
|
|
|
izones, err := self.GetIZones()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for i := 0; i < len(izones); i += 1 {
|
|
iZoneStores, err := izones[i].GetIStorages()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
iStores = append(iStores, iZoneStores...)
|
|
}
|
|
return iStores, nil
|
|
}
|
|
|
|
func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) {
|
|
if self.storageCache == nil {
|
|
self.storageCache = &SStoragecache{region: self}
|
|
}
|
|
|
|
if self.storageCache.GetGlobalId() == id {
|
|
return self.storageCache, nil
|
|
}
|
|
return nil, ErrorNotFound()
|
|
|
|
}
|
|
|
|
func (self *SRegion) CreateIVpc(name string, desc string, cidr string) (cloudprovider.ICloudVpc, error) {
|
|
tagspec := TagSpec{ResourceType: "vpc"}
|
|
if len(name) > 0 {
|
|
tagspec.SetNameTag(name)
|
|
}
|
|
|
|
if len(desc) > 0 {
|
|
tagspec.SetDescTag(desc)
|
|
}
|
|
|
|
spec, err := tagspec.GetTagSpecifications()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// start create vpc
|
|
vpc, err := self.ec2Client.CreateVpc(&ec2.CreateVpcInput{CidrBlock: &cidr})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
tagsParams := &ec2.CreateTagsInput{Resources: []*string{vpc.Vpc.VpcId}, Tags: spec.Tags}
|
|
_, err = self.ec2Client.CreateTags(tagsParams)
|
|
if err != nil {
|
|
log.Debugf("CreateIVpc add tag failed %s", err.Error())
|
|
}
|
|
|
|
err = self.fetchInfrastructure()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return self.GetIVpcById(*vpc.Vpc.VpcId)
|
|
}
|
|
|
|
func (self *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) {
|
|
eips, total, err := self.GetEips(eipId, "", 0, 0)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if total == 0 {
|
|
return nil, ErrorNotFound()
|
|
}
|
|
if total > 1 {
|
|
return nil, cloudprovider.ErrDuplicateId
|
|
}
|
|
return &eips[0], nil
|
|
}
|
|
|
|
func (self *SRegion) GetProvider() string {
|
|
return CLOUD_PROVIDER_AWS
|
|
}
|
|
|
|
func (self *SRegion) GetCloudEnv() string {
|
|
return self.client.accessUrl
|
|
}
|
|
|
|
func (self *SRegion) CreateInstanceSimple(name string, imgId string, cpu int, memGB int, storageType string, dataDiskSizesGB []int, networkId string, publicKey string) (*SInstance, error) {
|
|
izones, err := self.GetIZones()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for i := 0; i < len(izones); i += 1 {
|
|
z := izones[i].(*SZone)
|
|
log.Debugf("Search in zone %s", z.LocalName)
|
|
net := z.getNetworkById(networkId)
|
|
if net != nil {
|
|
desc := &cloudprovider.SManagedVMCreateConfig{
|
|
Name: name,
|
|
ExternalImageId: imgId,
|
|
SysDisk: cloudprovider.SDiskInfo{SizeGB: 0, StorageType: storageType},
|
|
Cpu: cpu,
|
|
MemoryMB: memGB * 1024,
|
|
ExternalNetworkId: networkId,
|
|
DataDisks: []cloudprovider.SDiskInfo{},
|
|
PublicKey: publicKey,
|
|
}
|
|
for _, sizeGB := range dataDiskSizesGB {
|
|
desc.DataDisks = append(desc.DataDisks, cloudprovider.SDiskInfo{SizeGB: sizeGB, StorageType: storageType})
|
|
}
|
|
inst, err := z.getHost().CreateVM(desc)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return inst.(*SInstance), nil
|
|
}
|
|
}
|
|
return nil, fmt.Errorf("cannot find vswitch %s", networkId)
|
|
}
|
|
|
|
func (self *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) {
|
|
client, err := self.GetElbV2Client()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
params := &elbv2.DescribeLoadBalancersInput{}
|
|
ret, err := client.DescribeLoadBalancers(params)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result := make([]SElb, 0)
|
|
err = unmarshalAwsOutput(ret, "LoadBalancers", &result)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ielbs := make([]cloudprovider.ICloudLoadbalancer, len(result))
|
|
for i := range result {
|
|
result[i].region = self
|
|
ielbs[i] = &result[i]
|
|
}
|
|
|
|
return ielbs, nil
|
|
}
|
|
|
|
func (self *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) {
|
|
client, err := self.GetElbV2Client()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
params := &elbv2.DescribeLoadBalancersInput{}
|
|
params.SetLoadBalancerArns([]*string{&loadbalancerId})
|
|
ret, err := client.DescribeLoadBalancers(params)
|
|
if err != nil {
|
|
if strings.Contains(err.Error(), "LoadBalancerNotFound") {
|
|
return nil, cloudprovider.ErrNotFound
|
|
}
|
|
|
|
return nil, err
|
|
}
|
|
|
|
elbs := []SElb{}
|
|
err = unmarshalAwsOutput(ret, "LoadBalancers", &elbs)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(elbs) == 1 {
|
|
elbs[0].region = self
|
|
return &elbs[0], nil
|
|
}
|
|
|
|
return nil, ErrorNotFound()
|
|
}
|
|
|
|
func (self *SRegion) getElbAttributesById(loadbalancerId string) (map[string]string, error) {
|
|
client, err := self.GetElbV2Client()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
params := &elbv2.DescribeLoadBalancerAttributesInput{}
|
|
params.SetLoadBalancerArn(loadbalancerId)
|
|
output, err := client.DescribeLoadBalancerAttributes(params)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
attrs := []map[string]string{}
|
|
err = unmarshalAwsOutput(output, "Attributes", &attrs)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ret := map[string]string{}
|
|
for i := range attrs {
|
|
for k, v := range attrs[i] {
|
|
ret[k] = v
|
|
}
|
|
}
|
|
|
|
return ret, nil
|
|
}
|
|
|
|
func (self *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) {
|
|
return nil, cloudprovider.ErrNotSupported
|
|
}
|
|
|
|
func (self *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) {
|
|
certs, err := self.GetILoadBalancerCertificates()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for i := range certs {
|
|
if certs[i].GetId() == certId {
|
|
return certs[i], nil
|
|
}
|
|
}
|
|
|
|
return nil, ErrorNotFound()
|
|
}
|
|
|
|
func (self *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) {
|
|
client, err := self.getIamClient()
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "region.CreateILoadBalancerCertificate.getIamClient")
|
|
}
|
|
|
|
params := &iam.UploadServerCertificateInput{}
|
|
params.SetServerCertificateName(cert.Name)
|
|
params.SetPrivateKey(cert.PrivateKey)
|
|
params.SetCertificateBody(cert.Certificate)
|
|
ret, err := client.UploadServerCertificate(params)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "region.CreateILoadBalancerCertificate.UploadServerCertificate")
|
|
}
|
|
|
|
// wait upload cert success
|
|
err = cloudprovider.Wait(5*time.Second, 30*time.Second, func() (bool, error) {
|
|
_, err := self.GetILoadBalancerCertificateById(*ret.ServerCertificateMetadata.Arn)
|
|
if err == nil {
|
|
return true, nil
|
|
}
|
|
|
|
if err == cloudprovider.ErrNotFound {
|
|
return false, nil
|
|
} else {
|
|
return false, err
|
|
}
|
|
})
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "region.CreateILoadBalancerCertificate.Wait")
|
|
}
|
|
|
|
return self.GetILoadBalancerCertificateById(*ret.ServerCertificateMetadata.Arn)
|
|
}
|
|
|
|
func (self *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) {
|
|
return nil, cloudprovider.ErrNotSupported
|
|
}
|
|
|
|
func (self *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) {
|
|
client, err := self.getIamClient()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
params := &iam.ListServerCertificatesInput{}
|
|
ret, err := client.ListServerCertificates(params)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
certs := []SElbCertificate{}
|
|
err = unmarshalAwsOutput(ret, "ServerCertificateMetadataList", &certs)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
icerts := make([]cloudprovider.ICloudLoadbalancerCertificate, len(certs))
|
|
for i := range certs {
|
|
certs[i].region = self
|
|
icerts[i] = &certs[i]
|
|
}
|
|
|
|
return icerts, nil
|
|
}
|
|
|
|
func (self *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) {
|
|
client, err := self.GetElbV2Client()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
params := &elbv2.CreateLoadBalancerInput{}
|
|
params.SetName(loadbalancer.Name)
|
|
params.SetType(loadbalancer.LoadbalancerSpec)
|
|
params.SetIpAddressType("ipv4")
|
|
if loadbalancer.AddressType == api.LB_ADDR_TYPE_INTERNET {
|
|
params.SetScheme("internet-facing")
|
|
} else {
|
|
params.SetScheme("internal")
|
|
}
|
|
|
|
// params.SetSecurityGroups()
|
|
params.SetSubnets(ConvertedList(loadbalancer.NetworkIDs))
|
|
ret, err := client.CreateLoadBalancer(params)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
elbs := []SElb{}
|
|
err = unmarshalAwsOutput(ret, "LoadBalancers", &elbs)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(elbs) == 1 {
|
|
elbs[0].region = self
|
|
return &elbs[0], nil
|
|
}
|
|
|
|
return nil, fmt.Errorf("CreateILoadBalancer error %#v", elbs)
|
|
}
|
|
|
|
func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) {
|
|
iBuckets, err := region.client.getIBuckets()
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "getIBuckets")
|
|
}
|
|
ret := make([]cloudprovider.ICloudBucket, 0)
|
|
for i := range iBuckets {
|
|
if iBuckets[i].GetLocation() != region.GetId() {
|
|
continue
|
|
}
|
|
ret = append(ret, iBuckets[i])
|
|
}
|
|
return ret, nil
|
|
}
|
|
|
|
func (region *SRegion) CreateIBucket(name string, storageClassStr string, acl string) error {
|
|
s3cli, err := region.GetS3Client()
|
|
if err != nil {
|
|
return errors.Wrap(err, "GetS3Client")
|
|
}
|
|
input := &s3.CreateBucketInput{}
|
|
input.SetBucket(name)
|
|
input.CreateBucketConfiguration = &s3.CreateBucketConfiguration{}
|
|
input.CreateBucketConfiguration.SetLocationConstraint(region.GetId())
|
|
_, err = s3cli.CreateBucket(input)
|
|
if err != nil {
|
|
return errors.Wrap(err, "CreateBucket")
|
|
}
|
|
region.client.invalidateIBuckets()
|
|
// if *output.Location != region.GetId() {
|
|
// log.Warningf("Request location %s != got locaiton %s", region.GetId(), *output.Location)
|
|
// }
|
|
return nil
|
|
}
|
|
|
|
func (region *SRegion) DeleteIBucket(name string) error {
|
|
s3cli, err := region.GetS3Client()
|
|
if err != nil {
|
|
return errors.Wrap(err, "GetS3Client")
|
|
}
|
|
input := &s3.DeleteBucketInput{}
|
|
input.Bucket = &name
|
|
_, err = s3cli.DeleteBucket(input)
|
|
if err != nil {
|
|
if region.client.debug {
|
|
log.Debugf("%#v %s", err, err)
|
|
}
|
|
if strings.Index(err.Error(), "NoSuchBucket:") >= 0 {
|
|
return nil
|
|
}
|
|
return errors.Wrap(err, "DeleteBucket")
|
|
}
|
|
region.client.invalidateIBuckets()
|
|
return nil
|
|
}
|
|
|
|
func (region *SRegion) IBucketExist(name string) (bool, error) {
|
|
s3cli, err := region.GetS3Client()
|
|
if err != nil {
|
|
return false, errors.Wrap(err, "GetS3Client")
|
|
}
|
|
input := &s3.HeadBucketInput{}
|
|
input.Bucket = &name
|
|
_, err = s3cli.HeadBucket(input)
|
|
if err != nil {
|
|
if region.client.debug {
|
|
log.Debugf("%#v %s", err, err)
|
|
}
|
|
if strings.Index(err.Error(), "NotFound:") >= 0 {
|
|
return false, nil
|
|
}
|
|
return false, errors.Wrap(err, "IsBucketExist")
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) {
|
|
return cloudprovider.GetIBucketById(region, name)
|
|
}
|
|
|
|
func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) {
|
|
return region.GetIBucketById(name)
|
|
}
|
|
|
|
func (region *SRegion) getBaseEndpoint() string {
|
|
if len(region.RegionEndpoint) > 4 {
|
|
return region.RegionEndpoint[4:]
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (region *SRegion) getS3Endpoint() string {
|
|
base := region.getBaseEndpoint()
|
|
if len(base) > 0 {
|
|
return "s3." + base
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (region *SRegion) getEc2Endpoint() string {
|
|
return region.RegionEndpoint
|
|
}
|
|
|
|
func (self *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) {
|
|
return nil, cloudprovider.ErrNotSupported
|
|
}
|
|
|
|
func (self *SRegion) GetSkus(zoneId string) ([]cloudprovider.ICloudSku, error) {
|
|
return nil, cloudprovider.ErrNotImplemented
|
|
}
|
|
|
|
func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) {
|
|
backendgroups, err := self.GetElbBackendgroups("", nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ret := make([]cloudprovider.ICloudLoadbalancerBackendGroup, len(backendgroups))
|
|
for i := range backendgroups {
|
|
ret[i] = &backendgroups[i]
|
|
}
|
|
|
|
return ret, nil
|
|
}
|
|
|
|
func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) {
|
|
secgroups, total, err := self.GetSecurityGroups("", "", secgroupId, 0, 1)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if total == 0 {
|
|
return nil, cloudprovider.ErrNotFound
|
|
}
|
|
if total > 1 {
|
|
return nil, cloudprovider.ErrDuplicateId
|
|
}
|
|
return &secgroups[0], nil
|
|
}
|
|
|
|
func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) {
|
|
secgroups, total, err := self.GetSecurityGroups(opts.VpcId, opts.Name, "", 0, 1)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if total == 0 {
|
|
return nil, cloudprovider.ErrNotFound
|
|
}
|
|
if total > 1 {
|
|
return nil, cloudprovider.ErrDuplicateId
|
|
}
|
|
return &secgroups[0], nil
|
|
}
|
|
|
|
func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) {
|
|
groupId, err := self.CreateSecurityGroup(conf.VpcId, conf.Name, "", conf.Desc)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return self.GetISecurityGroupById(groupId)
|
|
}
|
|
|
|
func (region *SRegion) GetCapabilities() []string {
|
|
return region.client.GetCapabilities()
|
|
}
|