yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/aliyun/instancenic.go (about)

     1  // Copyright 2019 Yunion
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package aliyun
    16  
    17  import (
    18  	"fmt"
    19  	"time"
    20  
    21  	alierr "github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors"
    22  	"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
    23  
    24  	"yunion.io/x/pkg/errors"
    25  	"yunion.io/x/pkg/util/netutils"
    26  
    27  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    28  )
    29  
    30  type SInstanceNic struct {
    31  	instance *SInstance
    32  	id       string
    33  	ipAddr   string
    34  	macAddr  string
    35  
    36  	classic bool
    37  
    38  	cloudprovider.DummyICloudNic
    39  }
    40  
    41  func (self *SInstanceNic) GetId() string {
    42  	return self.id
    43  }
    44  
    45  func (self *SInstanceNic) mustGetId() string {
    46  	if self.id == "" {
    47  		panic("empty network interface id")
    48  	}
    49  	return self.id
    50  }
    51  
    52  func (self *SInstanceNic) GetIP() string {
    53  	return self.ipAddr
    54  }
    55  
    56  func (self *SInstanceNic) GetMAC() string {
    57  	if len(self.macAddr) > 0 {
    58  		return self.macAddr
    59  	}
    60  	ip, _ := netutils.NewIPV4Addr(self.GetIP())
    61  	return ip.ToMac("00:16:")
    62  }
    63  
    64  func (self *SInstanceNic) InClassicNetwork() bool {
    65  	return self.classic == true
    66  }
    67  
    68  func (self *SInstanceNic) GetDriver() string {
    69  	return "virtio"
    70  }
    71  
    72  func (self *SInstanceNic) GetINetworkId() string {
    73  	return self.instance.VpcAttributes.VSwitchId
    74  }
    75  
    76  func (self *SInstanceNic) GetSubAddress() ([]string, error) {
    77  	selfId := self.mustGetId()
    78  	region := self.instance.host.zone.region
    79  	params := map[string]string{
    80  		"RegionId":             region.GetId(),
    81  		"NetworkInterfaceId.1": selfId,
    82  	}
    83  	body, err := region.ecsRequest("DescribeNetworkInterfaces", params)
    84  	if err != nil {
    85  		return nil, err
    86  	}
    87  
    88  	type DescribeNetworkInterfacesResponse struct {
    89  		TotalCount           int    `json:"TotalCount"`
    90  		RequestID            string `json:"RequestId"`
    91  		PageSize             int    `json:"PageSize"`
    92  		NextToken            string `json:"NextToken"`
    93  		PageNumber           int    `json:"PageNumber"`
    94  		NetworkInterfaceSets struct {
    95  			NetworkInterfaceSet []struct {
    96  				Status             string `json:"Status"`
    97  				PrivateIPAddress   string `json:"PrivateIpAddress"`
    98  				ZoneID             string `json:"ZoneId"`
    99  				ResourceGroupID    string `json:"ResourceGroupId"`
   100  				InstanceID         string `json:"InstanceId"`
   101  				VSwitchID          string `json:"VSwitchId"`
   102  				NetworkInterfaceID string `json:"NetworkInterfaceId"`
   103  				MacAddress         string `json:"MacAddress"`
   104  				SecurityGroupIds   struct {
   105  					SecurityGroupID []string `json:"SecurityGroupId"`
   106  				} `json:"SecurityGroupIds"`
   107  				Type     string `json:"Type"`
   108  				Ipv6Sets struct {
   109  					Ipv6Set []struct {
   110  						Ipv6Address string `json:"Ipv6Address"`
   111  					} `json:"Ipv6Set"`
   112  				} `json:"Ipv6Sets"`
   113  				VpcID              string `json:"VpcId"`
   114  				OwnerID            string `json:"OwnerId"`
   115  				AssociatedPublicIP struct {
   116  				} `json:"AssociatedPublicIp"`
   117  				CreationTime time.Time `json:"CreationTime"`
   118  				Tags         struct {
   119  					Tag []struct {
   120  						TagKey   string `json:"TagKey"`
   121  						TagValue string `json:"TagValue"`
   122  					} `json:"Tag"`
   123  				} `json:"Tags"`
   124  				PrivateIPSets struct {
   125  					PrivateIPSet []struct {
   126  						PrivateIPAddress   string `json:"PrivateIpAddress"`
   127  						AssociatedPublicIP struct {
   128  						} `json:"AssociatedPublicIp"`
   129  						Primary bool `json:"Primary"`
   130  					} `json:"PrivateIpSet"`
   131  				} `json:"PrivateIpSets"`
   132  			} `json:"NetworkInterfaceSet"`
   133  		} `json:"NetworkInterfaceSets"`
   134  	}
   135  	var resp DescribeNetworkInterfacesResponse
   136  	if err := body.Unmarshal(&resp); err != nil {
   137  		return nil, errors.Wrapf(err, "unmarshal DescribeNetworkInterfacesResponse: %s", body)
   138  	}
   139  	if got := len(resp.NetworkInterfaceSets.NetworkInterfaceSet); got != 1 {
   140  		return nil, errors.Errorf("got %d element(s) in interface set, expect 1", got)
   141  	}
   142  	var (
   143  		ipAddrs          []string
   144  		networkInterface = resp.NetworkInterfaceSets.NetworkInterfaceSet[0]
   145  	)
   146  	if got := networkInterface.NetworkInterfaceID; got != selfId {
   147  		return nil, errors.Errorf("got interface data for %s, expect %s", got, selfId)
   148  	}
   149  	for _, privateIP := range networkInterface.PrivateIPSets.PrivateIPSet {
   150  		if !privateIP.Primary {
   151  			ipAddrs = append(ipAddrs, privateIP.PrivateIPAddress)
   152  		}
   153  	}
   154  	return ipAddrs, nil
   155  }
   156  
   157  func (self *SInstanceNic) ipAddrsParams(ipAddrs []string) map[string]string {
   158  	region := self.instance.host.zone.region
   159  	params := map[string]string{
   160  		"RegionId":           region.GetId(),
   161  		"NetworkInterfaceId": self.mustGetId(),
   162  	}
   163  	for i, ipAddr := range ipAddrs {
   164  		k := fmt.Sprintf("PrivateIpAddress.%d", i+1)
   165  		params[k] = ipAddr
   166  	}
   167  	return params
   168  }
   169  
   170  func (self *SInstanceNic) AssignAddress(ipAddrs []string) error {
   171  	var (
   172  		selfId   = self.mustGetId()
   173  		instance = self.instance
   174  		zone     = instance.host.zone
   175  		region   = zone.region
   176  	)
   177  	ecsClient, err := region.getEcsClient()
   178  	if err != nil {
   179  		return err
   180  	}
   181  	request := ecs.CreateAssignPrivateIpAddressesRequest()
   182  	request.Scheme = "https"
   183  
   184  	request.NetworkInterfaceId = selfId
   185  	request.PrivateIpAddress = &ipAddrs
   186  	resp, err := ecsClient.AssignPrivateIpAddresses(request)
   187  	if err != nil {
   188  		if aerr, ok := err.(*alierr.ServerError); ok {
   189  			if aerr.ErrorCode() == "InvalidOperation.Ipv4CountExceeded" {
   190  				return errors.Wrap(cloudprovider.ErrAddressCountExceed, aerr.Message())
   191  			}
   192  		}
   193  		return errors.Wrapf(err, "AssignPrivateIpAddresses")
   194  	}
   195  
   196  	allocated := resp.AssignedPrivateIpAddressesSet.PrivateIpSet.PrivateIpAddress
   197  	if len(allocated) != len(ipAddrs) {
   198  		return errors.Errorf("AssignAddress want %d addresses, got %d", len(ipAddrs), len(allocated))
   199  	}
   200  	for i := 0; i < len(ipAddrs); i++ {
   201  		ip0 := ipAddrs[i]
   202  		ip1 := allocated[i]
   203  		if ip0 != ip1 {
   204  			return errors.Errorf("AssignAddress address %d does not match: want %s, got %s", i, ip0, ip1)
   205  		}
   206  	}
   207  	return nil
   208  }
   209  
   210  func (self *SInstanceNic) UnassignAddress(ipAddrs []string) error {
   211  	var (
   212  		selfId   = self.mustGetId()
   213  		instance = self.instance
   214  		zone     = instance.host.zone
   215  		region   = zone.region
   216  	)
   217  	ecsClient, err := region.getEcsClient()
   218  	if err != nil {
   219  		return err
   220  	}
   221  	request := ecs.CreateUnassignPrivateIpAddressesRequest()
   222  	request.Scheme = "https"
   223  
   224  	request.NetworkInterfaceId = selfId
   225  	request.PrivateIpAddress = &ipAddrs
   226  	resp, err := ecsClient.UnassignPrivateIpAddresses(request)
   227  	if err != nil {
   228  		if resp.GetHttpStatus() == 404 {
   229  			return nil
   230  		}
   231  		return err
   232  	}
   233  	return nil
   234  }