multicloud: aliyun: instancenic: secondary address management

This commit is contained in:
Yousong Zhou
2020-11-26 21:18:58 +08:00
parent fe6714b287
commit 33fdcda955
3 changed files with 189 additions and 0 deletions
+8
View File
@@ -337,6 +337,11 @@ type ICloudNic interface {
GetDriver() string
GetINetwork() ICloudNetwork
// GetSubAddress returns non-primary/secondary/alias ipv4 addresses of
// the network interface
//
// Implement it when any AssignXx ops methods are implemented
GetSubAddress() ([]string, error)
AssignNAddress(count int) ([]string, error)
AssignAddress(ipAddrs []string) error
// UnassignAddress should not return error if the network interface is
@@ -355,6 +360,9 @@ func (d DummyICloudNic) GetMAC() string { panic(errors.ErrNotImpleme
func (d DummyICloudNic) InClassicNetwork() bool { panic(errors.ErrNotImplemented) }
func (d DummyICloudNic) GetDriver() string { panic(errors.ErrNotImplemented) }
func (d DummyICloudNic) GetINetwork() ICloudNetwork { panic(errors.ErrNotImplemented) }
func (d DummyICloudNic) GetSubAddress() ([]string, error) {
return nil, nil
}
func (d DummyICloudNic) AssignNAddress(count int) ([]string, error) {
return nil, errors.ErrNotImplemented
}
+169
View File
@@ -15,6 +15,13 @@
package aliyun
import (
"fmt"
"time"
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
@@ -31,6 +38,13 @@ func (self *SInstanceNic) GetId() string {
return self.id
}
func (self *SInstanceNic) mustGetId() string {
if self.id == "" {
panic("empty network interface id")
}
return self.id
}
func (self *SInstanceNic) GetIP() string {
return self.ipAddr
}
@@ -62,3 +76,158 @@ func (self *SInstanceNic) GetINetwork() cloudprovider.ICloudNetwork {
}
return nil
}
func (self *SInstanceNic) GetSubAddress() ([]string, error) {
selfId := self.mustGetId()
region := self.instance.host.zone.region
params := map[string]string{
"RegionId": region.GetId(),
"NetworkInterfaceId.1": selfId,
}
body, err := region.ecsRequest("DescribeNetworkInterfaces", params)
if err != nil {
return nil, err
}
type DescribeNetworkInterfacesResponse struct {
TotalCount int `json:"TotalCount"`
RequestID string `json:"RequestId"`
PageSize int `json:"PageSize"`
NextToken string `json:"NextToken"`
PageNumber int `json:"PageNumber"`
NetworkInterfaceSets struct {
NetworkInterfaceSet []struct {
Status string `json:"Status"`
PrivateIPAddress string `json:"PrivateIpAddress"`
ZoneID string `json:"ZoneId"`
ResourceGroupID string `json:"ResourceGroupId"`
InstanceID string `json:"InstanceId"`
VSwitchID string `json:"VSwitchId"`
NetworkInterfaceID string `json:"NetworkInterfaceId"`
MacAddress string `json:"MacAddress"`
SecurityGroupIds struct {
SecurityGroupID []string `json:"SecurityGroupId"`
} `json:"SecurityGroupIds"`
Type string `json:"Type"`
Ipv6Sets struct {
Ipv6Set []struct {
Ipv6Address string `json:"Ipv6Address"`
} `json:"Ipv6Set"`
} `json:"Ipv6Sets"`
VpcID string `json:"VpcId"`
OwnerID string `json:"OwnerId"`
AssociatedPublicIP struct {
} `json:"AssociatedPublicIp"`
CreationTime time.Time `json:"CreationTime"`
Tags struct {
Tag []struct {
TagKey string `json:"TagKey"`
TagValue string `json:"TagValue"`
} `json:"Tag"`
} `json:"Tags"`
PrivateIPSets struct {
PrivateIPSet []struct {
PrivateIPAddress string `json:"PrivateIpAddress"`
AssociatedPublicIP struct {
} `json:"AssociatedPublicIp"`
Primary bool `json:"Primary"`
} `json:"PrivateIpSet"`
} `json:"PrivateIpSets"`
} `json:"NetworkInterfaceSet"`
} `json:"NetworkInterfaceSets"`
}
var resp DescribeNetworkInterfacesResponse
if err := body.Unmarshal(&resp); err != nil {
return nil, errors.Wrapf(err, "unmarshal DescribeNetworkInterfacesResponse: %s", body)
}
if got := len(resp.NetworkInterfaceSets.NetworkInterfaceSet); got != 1 {
return nil, errors.Errorf("got %d element(s) in interface set, expect 1", got)
}
var (
ipAddrs []string
networkInterface = resp.NetworkInterfaceSets.NetworkInterfaceSet[0]
)
if got := networkInterface.NetworkInterfaceID; got != selfId {
return nil, errors.Errorf("got interface data for %s, expect %s", got, selfId)
}
for _, privateIP := range networkInterface.PrivateIPSets.PrivateIPSet {
if !privateIP.Primary {
ipAddrs = append(ipAddrs, privateIP.PrivateIPAddress)
}
}
return ipAddrs, nil
}
func (self *SInstanceNic) ipAddrsParams(ipAddrs []string) map[string]string {
region := self.instance.host.zone.region
params := map[string]string{
"RegionId": region.GetId(),
"NetworkInterfaceId": self.mustGetId(),
}
for i, ipAddr := range ipAddrs {
k := fmt.Sprintf("PrivateIpAddress.%d", i+1)
params[k] = ipAddr
}
return params
}
func (self *SInstanceNic) AssignAddress(ipAddrs []string) error {
var (
selfId = self.mustGetId()
instance = self.instance
zone = instance.host.zone
region = zone.region
)
ecsClient, err := region.getEcsClient()
if err != nil {
return err
}
request := ecs.CreateAssignPrivateIpAddressesRequest()
request.Scheme = "https"
request.NetworkInterfaceId = selfId
request.PrivateIpAddress = &ipAddrs
resp, err := ecsClient.AssignPrivateIpAddresses(request)
if err != nil {
return errors.Wrapf(err, "AssignPrivateIpAddresses")
}
allocated := resp.AssignedPrivateIpAddressesSet.PrivateIpSet.PrivateIpAddress
if len(allocated) != len(ipAddrs) {
return errors.Errorf("AssignAddress want %d addresses, got %d", len(ipAddrs), len(allocated))
}
for i := 0; i < len(ipAddrs); i++ {
ip0 := ipAddrs[i]
ip1 := allocated[i]
if ip0 != ip1 {
return errors.Errorf("AssignAddress address %d does not match: want %s, got %s", i, ip0, ip1)
}
}
return nil
}
func (self *SInstanceNic) UnassignAddress(ipAddrs []string) error {
var (
selfId = self.mustGetId()
instance = self.instance
zone = instance.host.zone
region = zone.region
)
ecsClient, err := region.getEcsClient()
if err != nil {
return err
}
request := ecs.CreateUnassignPrivateIpAddressesRequest()
request.Scheme = "https"
request.NetworkInterfaceId = selfId
request.PrivateIpAddress = &ipAddrs
resp, err := ecsClient.UnassignPrivateIpAddresses(request)
if err != nil {
if resp.GetHttpStatus() == 404 {
return nil
}
return err
}
return nil
}
+12
View File
@@ -20,6 +20,7 @@ import (
"time"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk"
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"yunion.io/x/jsonutils"
@@ -83,6 +84,17 @@ func (self *SRegion) getSdkClient() (*sdk.Client, error) {
return self.sdkClient, nil
}
func (self *SRegion) getEcsClient() (*ecs.Client, error) {
sdkClient, err := self.getSdkClient()
if err != nil {
return nil, errors.Wrap(err, "getSdkClient")
}
ecsClient := &ecs.Client{
Client: *sdkClient,
}
return ecsClient, nil
}
func (self *SRegion) getOSSExternalDomain() string {
return getOSSExternalDomain(self.RegionId)
}