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 }