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 }