yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/aws/eip.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 aws
    16  
    17  import (
    18  	"fmt"
    19  	"time"
    20  
    21  	"yunion.io/x/jsonutils"
    22  	"yunion.io/x/pkg/errors"
    23  
    24  	"yunion.io/x/cloudmux/pkg/apis/billing"
    25  	api "yunion.io/x/cloudmux/pkg/apis/compute"
    26  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    27  	"yunion.io/x/cloudmux/pkg/multicloud"
    28  )
    29  
    30  const (
    31  	EIP_STATUS_INUSE     = "InUse"
    32  	EIP_STATUS_AVAILABLE = "Available"
    33  )
    34  
    35  type SEipAddress struct {
    36  	region *SRegion
    37  	multicloud.SEipBase
    38  	AwsTags
    39  
    40  	AllocationId            string `xml:"allocationId"`
    41  	AssociationId           string `xml:"associationId"`
    42  	CarrierIp               string `xml:"carrierIp"`
    43  	CustomerOwnedIp         string `xml:"customerOwnedIp"`
    44  	CustomerOwnedIpv4Pool   string `xml:"customerOwnedIpv4Pool"`
    45  	Domain                  string `xml:"domain"`
    46  	InstanceId              string `xml:"instanceId"`
    47  	NetworkBorderGroup      string `xml:"networkBorderGroup"`
    48  	NetworkInterfaceId      string `xml:"networkInterfaceId"`
    49  	NetworkInterfaceOwnerId string `xml:"networkInterfaceOwnerId"`
    50  	PrivateIpAddress        string `xml:"privateIpAddress"`
    51  	PublicIp                string `xml:"publicIp"`
    52  	PublicIpv4Pool          string `xml:"publicIpv4Pool"`
    53  }
    54  
    55  func (self *SEipAddress) GetId() string {
    56  	return self.AllocationId
    57  }
    58  
    59  func (self *SEipAddress) GetName() string {
    60  	name := self.AwsTags.GetName()
    61  	if len(name) > 0 {
    62  		return name
    63  	}
    64  	return self.AllocationId
    65  }
    66  
    67  func (self *SEipAddress) GetGlobalId() string {
    68  	return self.AllocationId
    69  }
    70  
    71  func (self *SEipAddress) GetStatus() string {
    72  	return api.EIP_STATUS_READY
    73  }
    74  
    75  func (self *SEipAddress) Refresh() error {
    76  	if self.IsEmulated() {
    77  		return nil
    78  	}
    79  	new, err := self.region.GetEip(self.AllocationId)
    80  	if err != nil {
    81  		return err
    82  	}
    83  	return jsonutils.Update(self, new)
    84  }
    85  
    86  func (self *SEipAddress) IsEmulated() bool {
    87  	if self.AllocationId == self.InstanceId {
    88  		return true
    89  	}
    90  	return false
    91  }
    92  
    93  func (self *SEipAddress) GetIpAddr() string {
    94  	return self.PublicIp
    95  }
    96  
    97  func (self *SEipAddress) GetMode() string {
    98  	if self.InstanceId == self.AllocationId {
    99  		return api.EIP_MODE_INSTANCE_PUBLICIP
   100  	}
   101  	return api.EIP_MODE_STANDALONE_EIP
   102  }
   103  
   104  func (self *SEipAddress) GetAssociationType() string {
   105  	if len(self.InstanceId) > 0 {
   106  		return api.EIP_ASSOCIATE_TYPE_SERVER
   107  	}
   108  	if len(self.NetworkInterfaceId) > 0 {
   109  		net, err := self.region.GetNetworkInterface(self.NetworkInterfaceId)
   110  		if err != nil {
   111  			return ""
   112  		}
   113  		switch net.InterfaceType {
   114  		case "nat_gateway":
   115  			return api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY
   116  		default:
   117  			return net.InterfaceType
   118  		}
   119  	}
   120  	return ""
   121  }
   122  
   123  func (self *SEipAddress) GetAssociationExternalId() string {
   124  	if len(self.InstanceId) > 0 {
   125  		return self.InstanceId
   126  	}
   127  	if len(self.NetworkInterfaceId) > 0 {
   128  		net, err := self.region.GetNetworkInterface(self.NetworkInterfaceId)
   129  		if err != nil {
   130  			return ""
   131  		}
   132  		switch net.InterfaceType {
   133  		case "nat_gateway":
   134  			nats, err := self.region.GetNatGateways(nil, net.VpcId, net.SubnetId)
   135  			if err != nil {
   136  				return ""
   137  			}
   138  			for i := range nats {
   139  				for _, addr := range nats[i].NatGatewayAddresses {
   140  					if addr.PublicIp == self.PublicIp {
   141  						return nats[i].GetGlobalId()
   142  					}
   143  				}
   144  			}
   145  			return ""
   146  		}
   147  	}
   148  	return self.InstanceId
   149  }
   150  
   151  func (self *SEipAddress) GetBandwidth() int {
   152  	return 0
   153  }
   154  
   155  func (self *SEipAddress) GetINetworkId() string {
   156  	return ""
   157  }
   158  
   159  func (self *SEipAddress) GetInternetChargeType() string {
   160  	return api.EIP_CHARGE_TYPE_BY_TRAFFIC
   161  }
   162  
   163  func (self *SEipAddress) Delete() error {
   164  	return self.region.DeallocateEIP(self.AllocationId)
   165  }
   166  
   167  func (self *SEipAddress) Associate(conf *cloudprovider.AssociateConfig) error {
   168  	return self.region.AssociateEip(self.AllocationId, conf.InstanceId)
   169  }
   170  
   171  func (self *SEipAddress) Dissociate() error {
   172  	return self.region.DissociateEip(self.AssociationId)
   173  }
   174  
   175  func (self *SEipAddress) ChangeBandwidth(bw int) error {
   176  	return self.region.UpdateEipBandwidth(self.AllocationId, bw)
   177  }
   178  
   179  func (self *SRegion) GetEips(id, ip, associateId string) ([]SEipAddress, error) {
   180  	params := map[string]string{}
   181  	if len(id) > 0 {
   182  		params["AllocationId.1"] = id
   183  	}
   184  	if len(ip) > 0 {
   185  		params["PublicIp.1"] = ip
   186  	}
   187  	idx := 1
   188  	if len(associateId) > 0 {
   189  		params[fmt.Sprintf("Filter.%d.Name", idx)] = "association-id"
   190  		params[fmt.Sprintf("Filter.%d.Value.1", idx)] = associateId
   191  		idx++
   192  	}
   193  	result := struct {
   194  		AddressesSet []SEipAddress `xml:"addressesSet>item"`
   195  	}{}
   196  	err := self.ec2Request("DescribeAddresses", params, &result)
   197  	if err != nil {
   198  		return nil, errors.Wrapf(err, "DescribeAddresses")
   199  	}
   200  	return result.AddressesSet, nil
   201  }
   202  
   203  func (self *SRegion) GetEip(id string) (*SEipAddress, error) {
   204  	eips, err := self.GetEips(id, "", "")
   205  	if err != nil {
   206  		return nil, errors.Wrapf(err, "GetEips")
   207  	}
   208  	for i := range eips {
   209  		if eips[i].GetGlobalId() == id {
   210  			eips[i].region = self
   211  			return &eips[i], nil
   212  		}
   213  	}
   214  	return nil, errors.Wrapf(cloudprovider.ErrNotFound, id)
   215  }
   216  
   217  func (self *SRegion) GetEipByIpAddress(eipAddress string) (*SEipAddress, error) {
   218  	eips, err := self.GetEips("", eipAddress, "")
   219  	if err != nil {
   220  		return nil, errors.Wrapf(err, "GetEips")
   221  	}
   222  	for i := range eips {
   223  		if eips[i].GetIpAddr() == eipAddress {
   224  			eips[i].region = self
   225  			return &eips[i], nil
   226  		}
   227  	}
   228  	return nil, errors.Wrapf(cloudprovider.ErrNotFound, eipAddress)
   229  }
   230  
   231  func (self *SRegion) AllocateEIP(opts *cloudprovider.SEip) (*SEipAddress, error) {
   232  	params := map[string]string{
   233  		"Domain": "vpc",
   234  	}
   235  	if len(opts.Name) > 0 {
   236  		params["TagSpecification.1.ResourceType"] = "elastic-ip"
   237  		params["TagSpecification.1.Tag.1.Key"] = "Name"
   238  		params["TagSpecification.1.Tag.1.Value"] = opts.Name
   239  	}
   240  	ret := SEipAddress{region: self}
   241  	err := self.ec2Request("AllocateAddress", params, &ret)
   242  	if err != nil {
   243  		return nil, errors.Wrapf(err, "AllocateAddress")
   244  	}
   245  	return &ret, nil
   246  }
   247  
   248  func (self *SRegion) CreateEIP(opts *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) {
   249  	eip, err := self.AllocateEIP(opts)
   250  	if err != nil {
   251  		return nil, errors.Wrapf(err, "AllocateEIP")
   252  	}
   253  	return eip, nil
   254  }
   255  
   256  func (self *SRegion) DeallocateEIP(eipId string) error {
   257  	params := map[string]string{
   258  		"AllocationId": eipId,
   259  	}
   260  	return self.ec2Request("ReleaseAddress", params, nil)
   261  }
   262  
   263  func (self *SRegion) AssociateEip(eipId string, instanceId string) error {
   264  	params := map[string]string{
   265  		"AllocationId": eipId,
   266  		"InstanceId":   instanceId,
   267  	}
   268  	return self.ec2Request("AssociateAddress", params, nil)
   269  }
   270  
   271  func (self *SRegion) DissociateEip(insId string) error {
   272  	params := map[string]string{
   273  		"AssociationId": insId,
   274  	}
   275  	return self.ec2Request("DisassociateAddress", params, nil)
   276  }
   277  
   278  func (self *SRegion) UpdateEipBandwidth(eipId string, bw int) error {
   279  	return cloudprovider.ErrNotSupported
   280  }
   281  
   282  func (self *SEipAddress) GetBillingType() string {
   283  	return billing.BILLING_TYPE_POSTPAID
   284  }
   285  
   286  func (self *SEipAddress) GetCreatedAt() time.Time {
   287  	return time.Time{}
   288  }
   289  
   290  func (self *SEipAddress) GetExpiredAt() time.Time {
   291  	return time.Time{}
   292  }
   293  
   294  func (self *SEipAddress) GetProjectId() string {
   295  	return ""
   296  }