mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-19 02:37:24 +08:00
feat(region): aws nat gateway read
This commit is contained in:
@@ -104,3 +104,10 @@ type ElasticipAssociateInput struct {
|
||||
// default: server
|
||||
InstanceType string `json:"instance_type"`
|
||||
}
|
||||
|
||||
type ElasticDissociateInput struct {
|
||||
// 注意: 若关联到aws NAT网关后,目前没办法解除关联关系
|
||||
// 是否解绑后自动删除弹性公网IP
|
||||
// default: false
|
||||
AutoDelete bool `json:"auto_delete"`
|
||||
}
|
||||
|
||||
@@ -1087,7 +1087,7 @@ func (self *SElasticip) StartEipAssociateTask(ctx context.Context, userCred mccl
|
||||
return task.ScheduleRun(nil)
|
||||
}
|
||||
|
||||
func (self *SElasticip) PerformDissociate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
func (self *SElasticip) PerformDissociate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ElasticDissociateInput) (jsonutils.JSONObject, error) {
|
||||
if len(self.AssociateId) == 0 {
|
||||
return nil, nil // success
|
||||
}
|
||||
@@ -1111,9 +1111,7 @@ func (self *SElasticip) PerformDissociate(ctx context.Context, userCred mcclient
|
||||
return nil, httperrors.NewUnsupportOperationError("fixed public eip cannot be dissociated")
|
||||
}
|
||||
|
||||
autoDelete := jsonutils.QueryBoolean(data, "auto_delete", false)
|
||||
|
||||
err = self.StartEipDissociateTask(ctx, userCred, autoDelete, "")
|
||||
err = self.StartEipDissociateTask(ctx, userCred, input.AutoDelete, "")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -10,11 +10,12 @@ package apis
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
math "math"
|
||||
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
||||
@@ -23,14 +23,10 @@ import (
|
||||
sdk "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/corehandlers"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
|
||||
"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/cloudwatch"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/aws/aws-sdk-go/service/elasticache"
|
||||
@@ -186,19 +182,6 @@ func (client *SAwsClient) GetAccountId() string {
|
||||
return client.ownerId
|
||||
}
|
||||
|
||||
/*
|
||||
func (self *SAwsClient) UpdateAccount(accessKey, secret string) error {
|
||||
if self.accessKey != accessKey || self.accessSecret != secret {
|
||||
self.accessKey = accessKey
|
||||
self.accessSecret = secret
|
||||
self.iregions = nil
|
||||
return self.fetchRegions()
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
var (
|
||||
// cache for describeRegions
|
||||
describeRegionResult map[string]*ec2.DescribeRegionsOutput = map[string]*ec2.DescribeRegionsOutput{}
|
||||
@@ -328,26 +311,6 @@ func (client *SAwsClient) fetchOwnerId() error {
|
||||
return errors.Wrap(err, "GetCallerIdentity")
|
||||
}
|
||||
client.ownerId = ident.Account
|
||||
|
||||
/* s, err := client.getDefaultSession()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "getDefaultSession")
|
||||
}
|
||||
s3cli := s3.New(s)
|
||||
output, err := s3cli.ListBuckets(&s3.ListBucketsInput{})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "ListBuckets")
|
||||
}
|
||||
|
||||
if output.Owner != nil {
|
||||
if output.Owner.ID != nil {
|
||||
client.ownerId = *output.Owner.ID
|
||||
}
|
||||
if output.Owner.DisplayName != nil {
|
||||
client.ownerName = *output.Owner.DisplayName
|
||||
}
|
||||
} */
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -527,40 +490,6 @@ func (self *SAwsClient) GetAccessEnv() string {
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SAwsClient) request(regionId, serviceName, serviceId, apiVersion string, apiName string, params map[string]string, retval interface{}, assumeRole bool) error {
|
||||
if len(regionId) == 0 {
|
||||
regionId = self.getDefaultRegionId()
|
||||
}
|
||||
session, err := self.getAwsSession(regionId, assumeRole)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c := session.ClientConfig(serviceName)
|
||||
metadata := metadata.ClientInfo{
|
||||
ServiceName: serviceName,
|
||||
ServiceID: serviceId,
|
||||
SigningName: c.SigningName,
|
||||
SigningRegion: c.SigningRegion,
|
||||
Endpoint: c.Endpoint,
|
||||
APIVersion: apiVersion,
|
||||
}
|
||||
|
||||
if self.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)
|
||||
client.Handlers.Validate.Remove(corehandlers.ValidateEndpointHandler)
|
||||
return jsonRequest(client, apiName, params, retval, true)
|
||||
|
||||
}
|
||||
|
||||
func (self *SAwsClient) iamRequest(apiName string, params map[string]string, retval interface{}) error {
|
||||
return self.request("", IAM_SERVICE_NAME, IAM_SERVICE_ID, "2010-05-08", apiName, params, retval, true)
|
||||
}
|
||||
@@ -569,30 +498,6 @@ func (self *SAwsClient) stsRequest(apiName string, params map[string]string, ret
|
||||
return self.request("", STS_SERVICE_NAME, STS_SERVICE_ID, "2011-06-15", apiName, params, retval, false)
|
||||
}
|
||||
|
||||
func jsonRequest(cli *client.Client, apiName string, params map[string]string, retval interface{}, debug bool) error {
|
||||
op := &request.Operation{
|
||||
Name: apiName,
|
||||
HTTPMethod: "POST",
|
||||
HTTPPath: "/",
|
||||
Paginator: &request.Paginator{
|
||||
InputTokens: []string{"NextToken"},
|
||||
OutputTokens: []string{"NextToken"},
|
||||
LimitToken: "MaxResults",
|
||||
TruncationToken: "",
|
||||
},
|
||||
}
|
||||
|
||||
req := cli.NewRequest(op, params, retval)
|
||||
err := req.Send()
|
||||
if err != nil {
|
||||
if e, ok := err.(awserr.RequestFailure); ok && e.StatusCode() == 404 {
|
||||
return cloudprovider.ErrNotFound
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SAwsClient) GetCapabilities() []string {
|
||||
caps := []string{
|
||||
// cloudprovider.CLOUD_CAPABILITY_PROJECT,
|
||||
|
||||
@@ -0,0 +1,233 @@
|
||||
// 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"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"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/corehandlers"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
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/private/protocol/xml/xmlutil"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
)
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
var UnmarshalErrorHandler = request.NamedHandler{Name: "awssdk.ec2query.UnmarshalError", Fn: UnmarshalError}
|
||||
|
||||
func UnmarshalError(r *request.Request) {
|
||||
defer r.HTTPResponse.Body.Close()
|
||||
|
||||
respErr := &struct {
|
||||
XMLName xml.Name `xml:"Response"`
|
||||
Code string `xml:"Errors>Error>Code"`
|
||||
Message string `xml:"Errors>Error>Message"`
|
||||
RequestID string `xml:"RequestID"`
|
||||
}{}
|
||||
|
||||
err := xmlutil.UnmarshalXMLError(&respErr, r.HTTPResponse.Body)
|
||||
if err != nil {
|
||||
r.Error = awserr.NewRequestFailure(
|
||||
awserr.New(request.ErrCodeSerialization,
|
||||
"failed to unmarshal error message", err),
|
||||
r.HTTPResponse.StatusCode,
|
||||
r.RequestID,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if strings.Contains(respErr.Code, "NotFound") {
|
||||
r.Error = errors.Wrapf(cloudprovider.ErrNotFound, jsonutils.Marshal(respErr).String())
|
||||
return
|
||||
}
|
||||
|
||||
r.Error = awserr.NewRequestFailure(
|
||||
awserr.New(respErr.Code, respErr.Message, nil),
|
||||
r.HTTPResponse.StatusCode,
|
||||
respErr.RequestID,
|
||||
)
|
||||
}
|
||||
|
||||
func (self *SAwsClient) request(regionId, serviceName, serviceId, apiVersion string, apiName string, params map[string]string, retval interface{}, assumeRole bool) error {
|
||||
if len(regionId) == 0 {
|
||||
regionId = self.getDefaultRegionId()
|
||||
}
|
||||
session, err := self.getAwsSession(regionId, assumeRole)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c := session.ClientConfig(serviceName)
|
||||
metadata := metadata.ClientInfo{
|
||||
ServiceName: serviceName,
|
||||
ServiceID: serviceId,
|
||||
SigningName: c.SigningName,
|
||||
SigningRegion: c.SigningRegion,
|
||||
Endpoint: c.Endpoint,
|
||||
APIVersion: apiVersion,
|
||||
}
|
||||
|
||||
if self.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(UnmarshalErrorHandler)
|
||||
client.Handlers.Validate.Remove(corehandlers.ValidateEndpointHandler)
|
||||
return jsonRequest(client, apiName, params, retval, true)
|
||||
}
|
||||
|
||||
func jsonRequest(cli *client.Client, apiName string, params map[string]string, retval interface{}, debug bool) error {
|
||||
op := &request.Operation{
|
||||
Name: apiName,
|
||||
HTTPMethod: "POST",
|
||||
HTTPPath: "/",
|
||||
Paginator: &request.Paginator{
|
||||
InputTokens: []string{"NextToken"},
|
||||
OutputTokens: []string{"NextToken"},
|
||||
LimitToken: "MaxResults",
|
||||
TruncationToken: "",
|
||||
},
|
||||
}
|
||||
|
||||
req := cli.NewRequest(op, params, retval)
|
||||
err := req.Send()
|
||||
if err != nil {
|
||||
if e, ok := err.(awserr.RequestFailure); ok && e.StatusCode() == 404 {
|
||||
return cloudprovider.ErrNotFound
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+131
-195
@@ -18,10 +18,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis/billing"
|
||||
@@ -40,17 +37,19 @@ type SEipAddress struct {
|
||||
multicloud.SEipBase
|
||||
multicloud.AwsTags
|
||||
|
||||
AllocationId string
|
||||
Bandwidth int
|
||||
Status string
|
||||
InstanceId string
|
||||
AssociationId string
|
||||
Domain string
|
||||
NetworkInterfaceId string
|
||||
NetworkInterfaceOwnerId string
|
||||
PrivateIpAddress string
|
||||
IpAddress string
|
||||
Name string
|
||||
AllocationId string `xml:"allocationId"`
|
||||
AssociationId string `xml:"associationId"`
|
||||
CarrierIp string `xml:"carrierIp"`
|
||||
CustomerOwnedIp string `xml:"customerOwnedIp"`
|
||||
CustomerOwnedIpv4Pool string `xml:"customerOwnedIpv4Pool"`
|
||||
Domain string `xml:"domain"`
|
||||
InstanceId string `xml:"instanceId"`
|
||||
NetworkBorderGroup string `xml:"networkBorderGroup"`
|
||||
NetworkInterfaceId string `xml:"networkInterfaceId"`
|
||||
NetworkInterfaceOwnerId string `xml:"networkInterfaceOwnerId"`
|
||||
PrivateIpAddress string `xml:"privateIpAddress"`
|
||||
PublicIp string `xml:"publicIp"`
|
||||
PublicIpv4Pool string `xml:"publicIpv4Pool"`
|
||||
}
|
||||
|
||||
func (self *SEipAddress) GetId() string {
|
||||
@@ -58,11 +57,11 @@ func (self *SEipAddress) GetId() string {
|
||||
}
|
||||
|
||||
func (self *SEipAddress) GetName() string {
|
||||
if len(self.Name) == 0 {
|
||||
return self.IpAddress
|
||||
name := self.AwsTags.GetName()
|
||||
if len(name) > 0 {
|
||||
return name
|
||||
}
|
||||
|
||||
return self.Name
|
||||
return self.AllocationId
|
||||
}
|
||||
|
||||
func (self *SEipAddress) GetGlobalId() string {
|
||||
@@ -70,13 +69,7 @@ func (self *SEipAddress) GetGlobalId() string {
|
||||
}
|
||||
|
||||
func (self *SEipAddress) GetStatus() string {
|
||||
switch self.Status {
|
||||
// todo: EIP_STATUS_INUSE 对应READY?
|
||||
case EIP_STATUS_AVAILABLE, EIP_STATUS_INUSE:
|
||||
return api.EIP_STATUS_READY
|
||||
default:
|
||||
return api.EIP_STATUS_UNKNOWN
|
||||
}
|
||||
return api.EIP_STATUS_READY
|
||||
}
|
||||
|
||||
func (self *SEipAddress) Refresh() error {
|
||||
@@ -94,33 +87,67 @@ func (self *SEipAddress) IsEmulated() bool {
|
||||
if self.AllocationId == self.InstanceId {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SEipAddress) GetIpAddr() string {
|
||||
return self.IpAddress
|
||||
return self.PublicIp
|
||||
}
|
||||
|
||||
func (self *SEipAddress) GetMode() string {
|
||||
if self.InstanceId == self.AllocationId {
|
||||
return api.EIP_MODE_INSTANCE_PUBLICIP
|
||||
} else {
|
||||
return api.EIP_MODE_STANDALONE_EIP
|
||||
}
|
||||
return api.EIP_MODE_STANDALONE_EIP
|
||||
}
|
||||
|
||||
func (self *SEipAddress) GetAssociationType() string {
|
||||
// todo : ?
|
||||
if len(self.InstanceId) > 0 {
|
||||
return api.EIP_ASSOCIATE_TYPE_SERVER
|
||||
}
|
||||
if len(self.NetworkInterfaceId) > 0 {
|
||||
net, err := self.region.GetNetworkInterface(self.NetworkInterfaceId)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
switch net.InterfaceType {
|
||||
case "nat_gateway":
|
||||
return api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY
|
||||
}
|
||||
}
|
||||
return api.EIP_ASSOCIATE_TYPE_SERVER
|
||||
}
|
||||
|
||||
func (self *SEipAddress) GetAssociationExternalId() string {
|
||||
if len(self.InstanceId) > 0 {
|
||||
return self.InstanceId
|
||||
}
|
||||
if len(self.NetworkInterfaceId) > 0 {
|
||||
net, err := self.region.GetNetworkInterface(self.NetworkInterfaceId)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
switch net.InterfaceType {
|
||||
case "nat_gateway":
|
||||
nats, err := self.region.GetNatGateways(nil, net.VpcId, net.SubnetId)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
for i := range nats {
|
||||
for _, addr := range nats[i].NatGatewayAddresses {
|
||||
if addr.PublicIp == self.PublicIp {
|
||||
return nats[i].GetGlobalId()
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
}
|
||||
return self.InstanceId
|
||||
}
|
||||
|
||||
func (self *SEipAddress) GetBandwidth() int {
|
||||
return self.Bandwidth
|
||||
return 0
|
||||
}
|
||||
|
||||
func (self *SEipAddress) GetINetworkId() string {
|
||||
@@ -128,7 +155,6 @@ func (self *SEipAddress) GetINetworkId() string {
|
||||
}
|
||||
|
||||
func (self *SEipAddress) GetInternetChargeType() string {
|
||||
// todo : implement me
|
||||
return api.EIP_CHARGE_TYPE_BY_TRAFFIC
|
||||
}
|
||||
|
||||
@@ -137,207 +163,117 @@ func (self *SEipAddress) Delete() error {
|
||||
}
|
||||
|
||||
func (self *SEipAddress) Associate(conf *cloudprovider.AssociateConfig) error {
|
||||
err := self.region.AssociateEip(self.AllocationId, conf.InstanceId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = cloudprovider.WaitStatusWithDelay(self, api.EIP_STATUS_READY, 5*time.Second, 10*time.Second, 180*time.Second)
|
||||
return err
|
||||
return self.region.AssociateEip(self.AllocationId, conf.InstanceId)
|
||||
}
|
||||
|
||||
func (self *SEipAddress) Dissociate() error {
|
||||
err := self.region.DissociateEip(self.AllocationId, self.InstanceId)
|
||||
if err != nil {
|
||||
return err
|
||||
if len(self.InstanceId) > 0 {
|
||||
return self.region.DissociateEip(self.InstanceId)
|
||||
}
|
||||
err = cloudprovider.WaitStatus(self, api.EIP_STATUS_READY, 10*time.Second, 180*time.Second)
|
||||
return err
|
||||
return self.region.DissociateEip(self.AssociationId)
|
||||
}
|
||||
|
||||
func (self *SEipAddress) ChangeBandwidth(bw int) error {
|
||||
return self.region.UpdateEipBandwidth(self.AllocationId, bw)
|
||||
}
|
||||
|
||||
func (self *SRegion) GetEips(eipId string, eipAddress string, offset int, limit int) ([]SEipAddress, int, error) {
|
||||
params := ec2.DescribeAddressesInput{}
|
||||
if len(eipId) > 0 {
|
||||
params.SetAllocationIds([]*string{&eipId})
|
||||
func (self *SRegion) GetEips(id, ip, associateId string) ([]SEipAddress, error) {
|
||||
params := map[string]string{}
|
||||
if len(id) > 0 {
|
||||
params["AllocationId.1"] = id
|
||||
}
|
||||
|
||||
if len(eipAddress) > 0 {
|
||||
params.SetPublicIps([]*string{&eipAddress})
|
||||
if len(ip) > 0 {
|
||||
params["PublicIp.1"] = ip
|
||||
}
|
||||
|
||||
ec2Client, err := self.getEc2Client()
|
||||
idx := 1
|
||||
if len(associateId) > 0 {
|
||||
params[fmt.Sprintf("Filter.%d.Name", idx)] = "association-id"
|
||||
params[fmt.Sprintf("Filter.%d.Value.1", idx)] = associateId
|
||||
idx++
|
||||
}
|
||||
result := struct {
|
||||
AddressesSet []SEipAddress `xml:"addressesSet>item"`
|
||||
}{}
|
||||
err := self.ec2Request("DescribeAddresses", params, &result)
|
||||
if err != nil {
|
||||
return nil, 0, errors.Wrap(err, "getEc2Client")
|
||||
return nil, errors.Wrapf(err, "DescribeAddresses")
|
||||
}
|
||||
res, err := ec2Client.DescribeAddresses(¶ms)
|
||||
err = parseNotFoundError(err)
|
||||
if err != nil {
|
||||
log.Errorf("DescribeEipAddresses fail %s", err)
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
eips := make([]SEipAddress, 0)
|
||||
for _, ip := range res.Addresses {
|
||||
if err := FillZero(ip); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
tagspec := TagSpec{ResourceType: "eip"}
|
||||
tagspec.LoadingEc2Tags(ip.Tags)
|
||||
|
||||
var status string
|
||||
if len(*ip.AssociationId) > 0 {
|
||||
status = EIP_STATUS_INUSE
|
||||
} else {
|
||||
status = EIP_STATUS_AVAILABLE
|
||||
}
|
||||
|
||||
eip := SEipAddress{
|
||||
region: self,
|
||||
AllocationId: *ip.AllocationId,
|
||||
Status: status,
|
||||
InstanceId: *ip.InstanceId,
|
||||
AssociationId: *ip.AssociationId,
|
||||
Domain: *ip.Domain,
|
||||
NetworkInterfaceId: *ip.NetworkInterfaceId,
|
||||
NetworkInterfaceOwnerId: *ip.NetworkInterfaceOwnerId,
|
||||
PrivateIpAddress: *ip.PrivateIpAddress,
|
||||
IpAddress: *ip.PublicIp,
|
||||
Name: tagspec.GetNameTag(),
|
||||
}
|
||||
jsonutils.Update(&eip.AwsTags.TagSet, ip.Tags)
|
||||
eips = append(eips, eip)
|
||||
}
|
||||
return eips, len(eips), nil
|
||||
return result.AddressesSet, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) GetEip(eipId string) (*SEipAddress, error) {
|
||||
// 这里必须强制要求eipId大于零。避免用户账号正好只有一个eip的情况,返回错误的eip。
|
||||
if len(eipId) == 0 {
|
||||
return nil, fmt.Errorf("GetEip eipId should not be emtpy.")
|
||||
}
|
||||
|
||||
eips, total, err := self.GetEips(eipId, "", 0, 0)
|
||||
func (self *SRegion) GetEip(id string) (*SEipAddress, error) {
|
||||
eips, err := self.GetEips(id, "", "")
|
||||
if err != nil {
|
||||
log.Errorf("GetEips %s: %s", eipId, err)
|
||||
return nil, errors.Wrap(err, "GetEips")
|
||||
return nil, errors.Wrapf(err, "GetEips")
|
||||
}
|
||||
if total != 1 {
|
||||
return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetEips")
|
||||
for i := range eips {
|
||||
if eips[i].GetGlobalId() == id {
|
||||
eips[i].region = self
|
||||
return &eips[i], nil
|
||||
}
|
||||
}
|
||||
return &eips[0], nil
|
||||
return nil, errors.Wrapf(cloudprovider.ErrNotFound, id)
|
||||
}
|
||||
|
||||
func (self *SRegion) GetEipByIpAddress(eipAddress string) (*SEipAddress, error) {
|
||||
eips, total, err := self.GetEips("", eipAddress, 0, 0)
|
||||
eips, err := self.GetEips("", eipAddress, "")
|
||||
if err != nil {
|
||||
log.Errorf("GetEips %s: %s", eipAddress, err)
|
||||
return nil, errors.Wrap(err, "GetEips")
|
||||
return nil, errors.Wrapf(err, "GetEips")
|
||||
}
|
||||
|
||||
if total != 1 {
|
||||
return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetEips")
|
||||
}
|
||||
return &eips[0], nil
|
||||
}
|
||||
|
||||
func (self *SRegion) AllocateEIP(domainType string) (*SEipAddress, error) {
|
||||
params := &ec2.AllocateAddressInput{}
|
||||
params.SetDomain(domainType)
|
||||
|
||||
ec2Client, err := self.getEc2Client()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getEc2Client")
|
||||
}
|
||||
eip, err := ec2Client.AllocateAddress(params)
|
||||
if err != nil {
|
||||
log.Errorf("AllocateEipAddress fail %s", err)
|
||||
return nil, errors.Wrap(err, "AllocateAddress")
|
||||
}
|
||||
|
||||
err = self.fetchInfrastructure()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetchInfrastructure")
|
||||
}
|
||||
return self.GetEip(*eip.AllocationId)
|
||||
}
|
||||
|
||||
func (self *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) {
|
||||
ec2Client, err := self.getEc2Client()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getEc2Client")
|
||||
}
|
||||
// todo: aws 不支持指定bwMbps, chargeType ?
|
||||
log.Debugf("CreateEip: aws not support specific params name/bwMbps/chargeType.")
|
||||
ieip, err := self.AllocateEIP("vpc")
|
||||
if err == nil && len(eip.Name) > 0 {
|
||||
eipId := ieip.GetId()
|
||||
k := "Name"
|
||||
nameTag := &ec2.Tag{Key: &k, Value: &eip.Name}
|
||||
params := &ec2.CreateTagsInput{}
|
||||
params.SetResources([]*string{&eipId})
|
||||
params.SetTags([]*ec2.Tag{nameTag})
|
||||
|
||||
// name 创建成功与否不影响eip的正常使用
|
||||
if _, e := ec2Client.CreateTags(params); e != nil {
|
||||
log.Infof("CreateEIP create name tag failed: %s", e)
|
||||
for i := range eips {
|
||||
if eips[i].GetIpAddr() == eipAddress {
|
||||
eips[i].region = self
|
||||
return &eips[i], nil
|
||||
}
|
||||
}
|
||||
return nil, errors.Wrapf(cloudprovider.ErrNotFound, eipAddress)
|
||||
}
|
||||
|
||||
return ieip, err
|
||||
func (self *SRegion) AllocateEIP(opts *cloudprovider.SEip) (*SEipAddress, error) {
|
||||
params := map[string]string{
|
||||
"Domain": "vpc",
|
||||
}
|
||||
if len(opts.Name) > 0 {
|
||||
params["TagSpecification.1.ResourceType"] = "elastic-ip"
|
||||
params["TagSpecification.1.Tag.1.Key"] = "Name"
|
||||
params["TagSpecification.1.Tag.1.Value"] = opts.Name
|
||||
}
|
||||
ret := SEipAddress{region: self}
|
||||
err := self.ec2Request("AllocateAddress", params, &ret)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "AllocateAddress")
|
||||
}
|
||||
return &ret, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) CreateEIP(opts *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) {
|
||||
eip, err := self.AllocateEIP(opts)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "AllocateEIP")
|
||||
}
|
||||
return eip, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) DeallocateEIP(eipId string) error {
|
||||
ec2Client, err := self.getEc2Client()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "getEc2Client")
|
||||
params := map[string]string{
|
||||
"AllocationId": eipId,
|
||||
}
|
||||
params := &ec2.ReleaseAddressInput{}
|
||||
params.SetAllocationId(eipId)
|
||||
_, err = ec2Client.ReleaseAddress(params)
|
||||
return errors.Wrap(err, "ReleaseAddress")
|
||||
return self.ec2Request("ReleaseAddress", params, nil)
|
||||
}
|
||||
|
||||
func (self *SRegion) AssociateEip(eipId string, instanceId string) error {
|
||||
params := &ec2.AssociateAddressInput{}
|
||||
params.SetAllocationId(eipId)
|
||||
params.SetInstanceId(instanceId)
|
||||
ec2Client, err := self.getEc2Client()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "getEc2Client")
|
||||
params := map[string]string{
|
||||
"AllocationId": eipId,
|
||||
"InstanceId": instanceId,
|
||||
}
|
||||
_, err = ec2Client.AssociateAddress(params)
|
||||
return errors.Wrap(err, "AssociateAddress")
|
||||
return self.ec2Request("AssociateAddress", params, nil)
|
||||
}
|
||||
|
||||
func (self *SRegion) DissociateEip(eipId string, instanceId string) error {
|
||||
eip, err := self.GetEip(eipId)
|
||||
if err != nil {
|
||||
return err
|
||||
func (self *SRegion) DissociateEip(insId string) error {
|
||||
params := map[string]string{
|
||||
"AssociationId": insId,
|
||||
}
|
||||
|
||||
if len(eip.AssociationId) == 0 {
|
||||
// 已经是解绑状态
|
||||
return nil
|
||||
}
|
||||
|
||||
if eip.InstanceId != instanceId {
|
||||
return fmt.Errorf("eip %s associate with another instance %s", eipId, eip.InstanceId)
|
||||
}
|
||||
|
||||
params := &ec2.DisassociateAddressInput{}
|
||||
params.SetAssociationId(eip.AssociationId)
|
||||
|
||||
ec2Client, err := self.getEc2Client()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "getEc2Client")
|
||||
}
|
||||
|
||||
_, err = ec2Client.DisassociateAddress(params)
|
||||
return errors.Wrap(err, "DisassociateAddress")
|
||||
return self.ec2Request("DisassociateAddress", params, nil)
|
||||
}
|
||||
|
||||
func (self *SRegion) UpdateEipBandwidth(eipId string, bw int) error {
|
||||
|
||||
@@ -90,7 +90,7 @@ type SInstance struct {
|
||||
VlanId string // subnet ID ?
|
||||
VpcAttributes SVpcAttributes
|
||||
SecurityGroupIds SSecurityGroupIds
|
||||
NetworkInterfaces SNetworkInterfaces
|
||||
NetworkInterfaces []SNetworkInterface
|
||||
EipAddress SEipAddress
|
||||
Disks []string
|
||||
DeviceNames []string
|
||||
@@ -262,7 +262,7 @@ func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
|
||||
|
||||
func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) {
|
||||
var (
|
||||
networkInterfaces = self.NetworkInterfaces.NetworkInterface
|
||||
networkInterfaces = self.NetworkInterfaces
|
||||
nics = make([]cloudprovider.ICloudNic, 0)
|
||||
)
|
||||
for _, networkInterface := range networkInterfaces {
|
||||
@@ -278,20 +278,18 @@ func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) {
|
||||
}
|
||||
|
||||
func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) {
|
||||
if len(self.EipAddress.IpAddress) > 0 {
|
||||
return self.host.zone.region.GetEipByIpAddress(self.EipAddress.IpAddress)
|
||||
} else if len(self.PublicIpAddress.IpAddress) > 0 {
|
||||
eip := SEipAddress{}
|
||||
if len(self.EipAddress.PublicIp) > 0 {
|
||||
return self.host.zone.region.GetEipByIpAddress(self.EipAddress.PublicIp)
|
||||
}
|
||||
if len(self.PublicIpAddress.IpAddress) > 0 {
|
||||
eip := SEipAddress{region: self.host.zone.region}
|
||||
eip.region = self.host.zone.region
|
||||
eip.IpAddress = self.PublicIpAddress.IpAddress[0]
|
||||
eip.PublicIp = self.PublicIpAddress.IpAddress[0]
|
||||
eip.InstanceId = self.InstanceId
|
||||
eip.AllocationId = self.InstanceId // fixed. AllocationId等于InstanceId即表示为 仿真EIP。
|
||||
eip.Bandwidth = 10000
|
||||
eip.Status = EIP_STATUS_INUSE
|
||||
return &eip, nil
|
||||
} else {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (self *SInstance) GetVcpuCount() int {
|
||||
@@ -618,7 +616,7 @@ func (self *SRegion) GetInstances(zoneId string, ids []string, offset int, limit
|
||||
}
|
||||
}
|
||||
|
||||
var networkInterfaces SNetworkInterfaces
|
||||
networkInterfaces := []SNetworkInterface{}
|
||||
eipAddress := SEipAddress{}
|
||||
for _, n := range instance.NetworkInterfaces {
|
||||
i := SNetworkInterface{
|
||||
@@ -626,12 +624,12 @@ func (self *SRegion) GetInstances(zoneId string, ids []string, offset int, limit
|
||||
NetworkInterfaceId: *n.NetworkInterfaceId,
|
||||
PrivateIpAddress: *n.PrivateIpAddress,
|
||||
}
|
||||
networkInterfaces.NetworkInterface = append(networkInterfaces.NetworkInterface, i)
|
||||
networkInterfaces = append(networkInterfaces, i)
|
||||
|
||||
// todo: 可能有多个EIP的情况。目前只支持一个EIP
|
||||
if n.Association != nil && StrVal(n.Association.IpOwnerId) != "amazon" {
|
||||
if eipAddress.IpAddress == "" && len(StrVal(n.Association.PublicIp)) > 0 {
|
||||
eipAddress.IpAddress = *n.Association.PublicIp
|
||||
if eipAddress.PublicIp == "" && len(StrVal(n.Association.PublicIp)) > 0 {
|
||||
eipAddress.PublicIp = *n.Association.PublicIp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
// 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 (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"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"
|
||||
)
|
||||
|
||||
type NatGatewayAddress struct {
|
||||
AllocationId string `xml:"allocationId"`
|
||||
NetworkInterfaceId string `xml:"networkInterfaceId"`
|
||||
PrivateIp string `xml:"privateIp"`
|
||||
PublicIp string `xml:"publicIp"`
|
||||
}
|
||||
|
||||
type ProvisionedBandwidth struct {
|
||||
ProvisionTime time.Time `xml:"provisionTime"`
|
||||
Provisioned string `xml:"provisioned"`
|
||||
RequestTime time.Time `xml:"requestTime"`
|
||||
Requested string `xml:"requested"`
|
||||
Status string `xml:"status"`
|
||||
}
|
||||
|
||||
type SNatGateway struct {
|
||||
multicloud.SNatGatewayBase
|
||||
multicloud.AwsTags
|
||||
|
||||
region *SRegion
|
||||
|
||||
ConnectivityType string `xml:"connectivityType"`
|
||||
CreateTime time.Time `xml:"createTime"`
|
||||
DeleteTime time.Time `xml:"deleteTime"`
|
||||
FailureCode string `xml:"failureCode"`
|
||||
FailureMessage string `xml:"failureMessage"`
|
||||
NatGatewayAddresses []NatGatewayAddress `xml:"natGatewayAddressSet>item"`
|
||||
NatGatewayId string `xml:"natGatewayId"`
|
||||
ProvisionedBandwidth ProvisionedBandwidth `xml:"provisionedBandwidth"`
|
||||
// pending | failed | available | deleting | deleted
|
||||
State string `xml:"state"`
|
||||
SubnetId string `xml:"subnetId"`
|
||||
VpcId string `xml:"vpcId"`
|
||||
}
|
||||
|
||||
func (self *SNatGateway) GetName() string {
|
||||
name := self.AwsTags.GetName()
|
||||
if len(name) > 0 {
|
||||
return name
|
||||
}
|
||||
return self.NatGatewayId
|
||||
}
|
||||
|
||||
func (self *SNatGateway) GetId() string {
|
||||
return self.NatGatewayId
|
||||
}
|
||||
|
||||
func (self *SNatGateway) GetGlobalId() string {
|
||||
return self.NatGatewayId
|
||||
}
|
||||
|
||||
func (self *SNatGateway) GetStatus() string {
|
||||
switch self.State {
|
||||
case "pending":
|
||||
return api.NAT_STATUS_ALLOCATE
|
||||
case "failed":
|
||||
return api.NAT_STATUS_CREATE_FAILED
|
||||
case "available":
|
||||
return api.NAT_STAUTS_AVAILABLE
|
||||
case "deleting", "deleted":
|
||||
return api.NAT_STATUS_DELETING
|
||||
default:
|
||||
return api.NAT_STATUS_UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SNatGateway) GetNatSpec() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SNatGateway) Refresh() error {
|
||||
nat, err := self.region.GetNatGateway(self.NatGatewayId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return jsonutils.Update(self, nat)
|
||||
}
|
||||
|
||||
func (self *SNatGateway) GetIEips() ([]cloudprovider.ICloudEIP, error) {
|
||||
eips, err := self.region.GetEips("", "", self.NatGatewayId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetEIPs")
|
||||
}
|
||||
ret := []cloudprovider.ICloudEIP{}
|
||||
for i := range eips {
|
||||
eips[i].region = self.region
|
||||
ret = append(ret, &eips[i])
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *SNatGateway) GetINatDTable() ([]cloudprovider.ICloudNatDEntry, error) {
|
||||
return []cloudprovider.ICloudNatDEntry{}, nil
|
||||
}
|
||||
|
||||
func (self *SNatGateway) GetINatSTable() ([]cloudprovider.ICloudNatSEntry, error) {
|
||||
return []cloudprovider.ICloudNatSEntry{}, nil
|
||||
}
|
||||
|
||||
func (self *SNatGateway) GetINatDEntryByID(id string) (cloudprovider.ICloudNatDEntry, error) {
|
||||
return nil, errors.Wrapf(cloudprovider.ErrNotFound, id)
|
||||
}
|
||||
|
||||
func (self *SNatGateway) GetINatSEntryByID(id string) (cloudprovider.ICloudNatSEntry, error) {
|
||||
return nil, errors.Wrapf(cloudprovider.ErrNotFound, id)
|
||||
}
|
||||
|
||||
func (self *SNatGateway) CreateINatDEntry(rule cloudprovider.SNatDRule) (cloudprovider.ICloudNatDEntry, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (self *SNatGateway) CreateINatSEntry(rule cloudprovider.SNatSRule) (cloudprovider.ICloudNatSEntry, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (self *SNatGateway) GetINetworkId() string {
|
||||
return self.SubnetId
|
||||
}
|
||||
|
||||
func (self *SNatGateway) GetBandwidthMb() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (self *SNatGateway) GetIpAddr() string {
|
||||
ipAddrs := []string{}
|
||||
for _, addr := range self.NatGatewayAddresses {
|
||||
if len(addr.PrivateIp) > 0 {
|
||||
ipAddrs = append(ipAddrs, addr.PrivateIp)
|
||||
}
|
||||
}
|
||||
return strings.Join(ipAddrs, ",")
|
||||
}
|
||||
|
||||
func (self *SNatGateway) Delete() error {
|
||||
return self.region.DeleteNatgateway(self.NatGatewayId)
|
||||
}
|
||||
|
||||
func (self *SRegion) DeleteNatgateway(id string) error {
|
||||
params := map[string]string{
|
||||
"NatGatewayId": id,
|
||||
}
|
||||
return self.ec2Request("DeleteNatGateway", params, nil)
|
||||
}
|
||||
|
||||
func (self *SRegion) GetNatGateways(ids []string, vpcId, subnetId string) ([]SNatGateway, error) {
|
||||
params := map[string]string{}
|
||||
for i, id := range ids {
|
||||
params[fmt.Sprintf("NatGatewayId.%d", i+1)] = id
|
||||
}
|
||||
idx := 1
|
||||
if len(vpcId) > 0 {
|
||||
params[fmt.Sprintf("Filter.%d.Name", idx)] = "vpc-id"
|
||||
params[fmt.Sprintf("Filter.%d.Value.1", idx)] = vpcId
|
||||
idx++
|
||||
}
|
||||
if len(subnetId) > 0 {
|
||||
params[fmt.Sprintf("Filter.%d.Name", idx)] = "subnet-id"
|
||||
params[fmt.Sprintf("Filter.%d.Value.1", idx)] = subnetId
|
||||
idx++
|
||||
}
|
||||
params[fmt.Sprintf("Filter.%d.Name", idx)] = "state"
|
||||
for i, state := range []string{
|
||||
"pending",
|
||||
"failed",
|
||||
"available",
|
||||
"deleting",
|
||||
} {
|
||||
params[fmt.Sprintf("Filter.%d.Value.%d", idx, i+1)] = state
|
||||
}
|
||||
idx++
|
||||
ret := []SNatGateway{}
|
||||
for {
|
||||
result := struct {
|
||||
Nats []SNatGateway `xml:"natGatewaySet>item"`
|
||||
NextToken string `xml:"nextToken"`
|
||||
}{}
|
||||
err := self.ec2Request("DescribeNatGateways", params, &result)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "DescribeNatGateways")
|
||||
}
|
||||
ret = append(ret, result.Nats...)
|
||||
if len(result.NextToken) == 0 || len(result.Nats) == 0 {
|
||||
break
|
||||
}
|
||||
params["NextToken"] = result.NextToken
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) GetNatGateway(id string) (*SNatGateway, error) {
|
||||
nats, err := self.GetNatGateways([]string{id}, "", "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetNatGateways")
|
||||
}
|
||||
for i := range nats {
|
||||
if nats[i].GetGlobalId() == id {
|
||||
nats[i].region = self
|
||||
return &nats[i], nil
|
||||
}
|
||||
}
|
||||
return nil, errors.Wrapf(cloudprovider.ErrNotFound, id)
|
||||
}
|
||||
|
||||
func (self *SVpc) GetINatGateways() ([]cloudprovider.ICloudNatGateway, error) {
|
||||
nats, err := self.region.GetNatGateways(nil, self.VpcId, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetINatGateways")
|
||||
}
|
||||
ret := []cloudprovider.ICloudNatGateway{}
|
||||
for i := range nats {
|
||||
nats[i].region = self.region
|
||||
ret = append(ret, &nats[i])
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
@@ -18,6 +18,8 @@ import (
|
||||
"time"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
)
|
||||
|
||||
type SGroupSet struct {
|
||||
@@ -60,16 +62,39 @@ type SNetworkInterface struct {
|
||||
InterfaceType string `xml:"interfaceType"`
|
||||
}
|
||||
|
||||
type SNetworkInterfaces struct {
|
||||
NetworkInterface []SNetworkInterface `xml:"networkInterfaceSet>item"`
|
||||
func (self *SRegion) GetNetworkInterface(id string) (*SNetworkInterface, error) {
|
||||
nets, err := self.GetNetworkInterfaces(id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetNetworkInterface")
|
||||
}
|
||||
for i := range nets {
|
||||
if nets[i].NetworkInterfaceId == id {
|
||||
return &nets[i], nil
|
||||
}
|
||||
}
|
||||
return nil, errors.Wrapf(cloudprovider.ErrNotFound, id)
|
||||
}
|
||||
|
||||
func (region *SRegion) GetNetworkInterfaces() ([]SNetworkInterface, error) {
|
||||
func (self *SRegion) GetNetworkInterfaces(id string) ([]SNetworkInterface, error) {
|
||||
params := map[string]string{}
|
||||
interfaces := SNetworkInterfaces{}
|
||||
err := region.ec2Request("DescribeNetworkInterfaces", params, &interfaces)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "DescribeNetworkInterfaces")
|
||||
if len(id) > 0 {
|
||||
params["NetworkInterfaceId.1"] = id
|
||||
}
|
||||
return interfaces.NetworkInterface, nil
|
||||
ret := []SNetworkInterface{}
|
||||
for {
|
||||
result := struct {
|
||||
NetworkInterfaceSet []SNetworkInterface `xml:"networkInterfaceSet>item"`
|
||||
NextToken string `xml:"nextToken"`
|
||||
}{}
|
||||
err := self.ec2Request("DescribeNetworkInterfaces", params, &result)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "DescribeNetworkInterfaces")
|
||||
}
|
||||
ret = append(ret, result.NetworkInterfaceSet...)
|
||||
if len(result.NextToken) == 0 || len(result.NetworkInterfaceSet) == 0 {
|
||||
break
|
||||
}
|
||||
params["NextToken"] = result.NextToken
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
@@ -15,19 +15,13 @@
|
||||
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"
|
||||
@@ -235,108 +229,6 @@ func (self *SRegion) getResourceGroupTagClient() (*resourcegroupstaggingapi.Reso
|
||||
return self.resourceGroupTagClient, 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 {
|
||||
return self.client.request(self.RegionId, RDS_SERVICE_NAME, RDS_SERVICE_ID, "2014-10-31", apiName, params, retval, true)
|
||||
}
|
||||
@@ -553,19 +445,14 @@ func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) {
|
||||
}
|
||||
|
||||
func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) {
|
||||
_, err := self.getEc2Client()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getEc2Client")
|
||||
}
|
||||
|
||||
eips, total, err := self.GetEips("", "", 0, 0)
|
||||
eips, err := self.GetEips("", "", "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetEips")
|
||||
}
|
||||
|
||||
ret := make([]cloudprovider.ICloudEIP, total)
|
||||
for i := 0; i < len(eips); i += 1 {
|
||||
ret[i] = &eips[i]
|
||||
ret := []cloudprovider.ICloudEIP{}
|
||||
for i := range eips {
|
||||
eips[i].region = self
|
||||
ret = append(ret, &eips[i])
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
@@ -732,19 +619,12 @@ func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprov
|
||||
return self.GetIVpcById(*vpc.Vpc.VpcId)
|
||||
}
|
||||
|
||||
func (self *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) {
|
||||
eips, total, err := self.GetEips(eipId, "", 0, 0)
|
||||
func (self *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) {
|
||||
eip, err := self.GetEip(id)
|
||||
if err != nil {
|
||||
log.Errorf("GetEips %s: %s", eipId, err)
|
||||
return nil, errors.Wrap(err, "GetEips")
|
||||
return nil, errors.Wrap(err, "GetEip")
|
||||
}
|
||||
if total == 0 {
|
||||
return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetIEipById")
|
||||
}
|
||||
if total > 1 {
|
||||
return nil, cloudprovider.ErrDuplicateId
|
||||
}
|
||||
return &eips[0], nil
|
||||
return eip, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) GetProvider() string {
|
||||
|
||||
@@ -15,28 +15,32 @@
|
||||
package shell
|
||||
|
||||
import (
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud/aws"
|
||||
"yunion.io/x/onecloud/pkg/util/shellutils"
|
||||
)
|
||||
|
||||
func init() {
|
||||
type EipListOptions struct {
|
||||
Offset int `help:"List offset"`
|
||||
Limit int `help:"List limit"`
|
||||
Id string
|
||||
Addr string
|
||||
AssociateId string
|
||||
}
|
||||
shellutils.R(&EipListOptions{}, "eip-list", "List eips", func(cli *aws.SRegion, args *EipListOptions) error {
|
||||
eips, total, e := cli.GetEips("", "", args.Offset, args.Limit)
|
||||
if e != nil {
|
||||
return e
|
||||
eips, err := cli.GetEips(args.Id, args.Addr, args.AssociateId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printList(eips, total, args.Offset, args.Limit, []string{})
|
||||
printList(eips, 0, 0, 0, []string{})
|
||||
return nil
|
||||
})
|
||||
|
||||
type EipAllocateOptions struct {
|
||||
Name string
|
||||
}
|
||||
shellutils.R(&EipAllocateOptions{}, "eip-create", "Allocate an EIP", func(cli *aws.SRegion, args *EipAllocateOptions) error {
|
||||
eip, err := cli.AllocateEIP("vpc")
|
||||
opts := cloudprovider.SEip{Name: args.Name}
|
||||
eip, err := cli.AllocateEIP(&opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -60,8 +64,13 @@ func init() {
|
||||
err := cli.AssociateEip(args.ID, args.INSTANCE)
|
||||
return err
|
||||
})
|
||||
shellutils.R(&EipAssociateOptions{}, "eip-dissociate", "Dissociate an EIP", func(cli *aws.SRegion, args *EipAssociateOptions) error {
|
||||
err := cli.DissociateEip(args.ID, args.INSTANCE)
|
||||
|
||||
type EipDissociateOptions struct {
|
||||
INSTANCE string `help:"Instance ID"`
|
||||
}
|
||||
|
||||
shellutils.R(&EipDissociateOptions{}, "eip-dissociate", "Dissociate an EIP", func(cli *aws.SRegion, args *EipDissociateOptions) error {
|
||||
err := cli.DissociateEip(args.INSTANCE)
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
// 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 shell
|
||||
|
||||
import (
|
||||
"yunion.io/x/onecloud/pkg/multicloud/aws"
|
||||
"yunion.io/x/onecloud/pkg/util/shellutils"
|
||||
)
|
||||
|
||||
func init() {
|
||||
type NatListOptions struct {
|
||||
Ids []string
|
||||
VpcId string
|
||||
SubnetId string
|
||||
}
|
||||
shellutils.R(&NatListOptions{}, "natgateway-list", "List natgateway", func(cli *aws.SRegion, args *NatListOptions) error {
|
||||
nats, err := cli.GetNatGateways(args.Ids, args.VpcId, args.SubnetId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printList(nats, 0, 0, 0, nil)
|
||||
return nil
|
||||
})
|
||||
|
||||
type NatIdOptions struct {
|
||||
ID string
|
||||
}
|
||||
|
||||
shellutils.R(&NatIdOptions{}, "natgateway-delete", "Delete natgateway", func(cli *aws.SRegion, args *NatIdOptions) error {
|
||||
return cli.DeleteNatgateway(args.ID)
|
||||
})
|
||||
|
||||
}
|
||||
@@ -21,9 +21,10 @@ import (
|
||||
|
||||
func init() {
|
||||
type NetworkInterfaceListOptions struct {
|
||||
Id string
|
||||
}
|
||||
shellutils.R(&NetworkInterfaceListOptions{}, "network-interface-list", "List network interfaces", func(cli *aws.SRegion, args *NetworkInterfaceListOptions) error {
|
||||
interfaces, err := cli.GetNetworkInterfaces()
|
||||
interfaces, err := cli.GetNetworkInterfaces(args.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -598,7 +598,7 @@ func (self *SRegion) assignSecurityGroups(secgroupIds []*string, instanceId stri
|
||||
return errors.Wrap(err, "getEc2Client")
|
||||
}
|
||||
|
||||
for _, eth := range instance.NetworkInterfaces.NetworkInterface {
|
||||
for _, eth := range instance.NetworkInterfaces {
|
||||
params := &ec2.ModifyNetworkInterfaceAttributeInput{}
|
||||
params.SetNetworkInterfaceId(eth.NetworkInterfaceId)
|
||||
params.SetGroups(secgroupIds)
|
||||
|
||||
@@ -221,8 +221,22 @@ func (self *AzureTags) SetTags(tags map[string]string, replace bool) error {
|
||||
return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags")
|
||||
}
|
||||
|
||||
type SAwsTag struct {
|
||||
Key string `xml:"key"`
|
||||
Value string `xml:"value"`
|
||||
}
|
||||
|
||||
type AwsTags struct {
|
||||
TagSet []STag
|
||||
TagSet []SAwsTag `xml:"tagSet>item"`
|
||||
}
|
||||
|
||||
func (self AwsTags) GetName() string {
|
||||
for _, tag := range self.TagSet {
|
||||
if strings.ToLower(tag.Key) == "name" {
|
||||
return tag.Value
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *AwsTags) GetTags() (map[string]string, error) {
|
||||
|
||||
Reference in New Issue
Block a user