yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/ctyun/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 ctyun 16 17 import ( 18 "fmt" 19 "strconv" 20 "strings" 21 "time" 22 23 "yunion.io/x/jsonutils" 24 "yunion.io/x/log" 25 "yunion.io/x/pkg/errors" 26 27 billing_api "yunion.io/x/cloudmux/pkg/apis/billing" 28 api "yunion.io/x/cloudmux/pkg/apis/compute" 29 "yunion.io/x/cloudmux/pkg/cloudprovider" 30 "yunion.io/x/cloudmux/pkg/multicloud" 31 ) 32 33 type SEip struct { 34 region *SRegion 35 multicloud.SEipBase 36 CtyunTags 37 38 IPVersion int64 `json:"ip_version"` 39 BandwidthShareType string `json:"bandwidth_share_type"` 40 Type string `json:"type"` 41 PrivateIPAddress string `json:"private_ip_address"` 42 EnterpriseProjectID string `json:"enterprise_project_id"` 43 Status string `json:"status"` 44 PublicIPAddress string `json:"public_ip_address"` 45 ID string `json:"id"` 46 TenantID string `json:"tenant_id"` 47 Profile Profile `json:"profile"` 48 BandwidthName string `json:"bandwidth_name"` 49 BandwidthID string `json:"bandwidth_id"` 50 PortID string `json:"port_id"` 51 BandwidthSize int `json:"bandwidth_size"` 52 CreateTime int64 `json:"create_time"` 53 MasterOrderID string `json:"masterOrderId"` 54 WorkOrderResourceID string `json:"workOrderResourceId"` 55 ExpireTime int64 `json:"expireTime"` 56 IsFreeze int64 `json:"isFreeze"` 57 } 58 59 func (self *SEip) GetBillingType() string { 60 if len(self.MasterOrderID) > 0 { 61 return billing_api.BILLING_TYPE_PREPAID 62 } else { 63 return billing_api.BILLING_TYPE_POSTPAID 64 } 65 } 66 67 func (self *SEip) GetCreatedAt() time.Time { 68 return time.Unix(self.CreateTime/1000, 0) 69 } 70 71 func (self *SEip) GetExpiredAt() time.Time { 72 if self.ExpireTime == 0 { 73 return time.Time{} 74 } 75 76 return time.Unix(self.ExpireTime/1000, 0) 77 } 78 79 func (self *SEip) GetId() string { 80 return self.ID 81 } 82 83 func (self *SEip) GetName() string { 84 return self.BandwidthName 85 } 86 87 func (self *SEip) GetGlobalId() string { 88 return self.GetId() 89 } 90 91 func (self *SEip) GetStatus() string { 92 switch self.Status { 93 case "ACTIVE", "DOWN": 94 return api.EIP_STATUS_READY 95 case "ERROR": 96 return api.EIP_STATUS_ALLOCATE_FAIL 97 default: 98 return api.EIP_STATUS_UNKNOWN 99 } 100 } 101 102 func (self *SEip) Refresh() error { 103 if self.IsEmulated() { 104 return nil 105 } 106 new, err := self.region.GetEip(self.ID) 107 if err != nil { 108 return err 109 } 110 return jsonutils.Update(self, new) 111 } 112 113 func (self *SEip) IsEmulated() bool { 114 return false 115 } 116 117 func (self *SEip) GetProjectId() string { 118 return "" 119 } 120 121 func (self *SEip) GetIpAddr() string { 122 return self.PublicIPAddress 123 } 124 125 func (self *SEip) GetMode() string { 126 return api.EIP_MODE_STANDALONE_EIP 127 } 128 129 func (self *SEip) GetINetworkId() string { 130 return "" 131 } 132 133 func (self *SEip) GetAssociationType() string { 134 orders, err := self.region.GetOrder(self.WorkOrderResourceID) 135 if err != nil { 136 // bugfix: 由于没有接口可以返向查询出关联的device,这里默认关联的是server? 137 if len(self.PortID) > 0 || len(self.PrivateIPAddress) > 0 { 138 return api.EIP_ASSOCIATE_TYPE_SERVER 139 } 140 141 log.Errorf("SEip.GetAssociationType %s", err) 142 return "" 143 } 144 145 for i := range orders { 146 order := orders[i] 147 if strings.Contains(order.ResourceType, "LOADBALANCER") { 148 return api.EIP_ASSOCIATE_TYPE_LOADBALANCER 149 } else { 150 return api.EIP_ASSOCIATE_TYPE_SERVER 151 } 152 } 153 154 return "" 155 } 156 157 // eip查询接口未返回 绑定的实例ID/网卡port id。导致不能正常找出关联的主机 158 func (self *SEip) GetAssociationExternalId() string { 159 vms, err := self.region.GetVMs() 160 if err != nil { 161 log.Errorf("SEip.GetAssociationExternalId.GetVMs %s", err) 162 return "" 163 } 164 165 for i := range vms { 166 vm := vms[i] 167 nics, err := self.region.GetNics(vm.GetId()) 168 if err != nil { 169 log.Errorf("SEip.GetAssociationExternalId.GetNics %s", err) 170 return "" 171 } 172 173 for _, nic := range nics { 174 if nic.PortID == self.PortID { 175 return vm.GetGlobalId() 176 } 177 } 178 } 179 180 return "" 181 } 182 183 // http://ctyun-api-url/apiproxy/v3/queryNetworkDetail 184 func (self *SEip) GetBandwidth() int { 185 return self.BandwidthSize 186 } 187 188 func (self *SEip) GetInternetChargeType() string { 189 // todo: fix me 190 return "" 191 } 192 193 func (self *SEip) Delete() error { 194 return self.region.DeleteEip(self.GetId()) 195 } 196 197 func (self *SEip) Associate(conf *cloudprovider.AssociateConfig) error { 198 nics, err := self.region.GetNics(conf.InstanceId) 199 if err != nil { 200 return errors.Wrap(err, "Eip.Associate.GetNics") 201 } 202 203 if len(nics) == 0 { 204 return errors.Wrap(fmt.Errorf("no network card found"), "Eip.Associate.GetINics") 205 } 206 207 return self.region.AssociateEip(self.GetId(), nics[0].PortID) 208 } 209 210 func (self *SEip) Dissociate() error { 211 err := self.region.DissociateEip(self.GetId()) 212 if err != nil { 213 return err 214 } 215 216 err = cloudprovider.WaitStatusWithDelay(self, api.EIP_STATUS_READY, 5*time.Second, 10*time.Second, 180*time.Second) 217 return errors.Wrap(err, "SEip.Dissociate") 218 } 219 220 func (self *SEip) ChangeBandwidth(bw int) error { 221 return self.region.ChangeBandwidthEip(self.GetName(), self.GetId(), strconv.Itoa(bw)) 222 } 223 224 type Profile struct { 225 OrderID string `json:"order_id"` 226 RegionID string `json:"region_id"` 227 UserID string `json:"user_id"` 228 ProductID string `json:"product_id"` 229 } 230 231 func (self *SRegion) GetEips() ([]SEip, error) { 232 params := map[string]string{ 233 "regionId": self.GetId(), 234 } 235 236 eips := make([]SEip, 0) 237 resp, err := self.client.DoGet("/apiproxy/v3/ondemand/queryIps", params) 238 if err != nil { 239 return nil, errors.Wrap(err, "SRegion.GetEips.DoGet") 240 } 241 242 err = resp.Unmarshal(&eips, "returnObj", "publicips") 243 if err != nil { 244 return nil, errors.Wrap(err, "SRegion.GetEips.Unmarshal") 245 } 246 247 for i := range eips { 248 eips[i].region = self 249 } 250 251 return eips, nil 252 } 253 254 func (self *SRegion) GetEip(eipId string) (*SEip, error) { 255 params := map[string]string{ 256 "regionId": self.GetId(), 257 "publicIpId": eipId, 258 } 259 260 eips := make([]SEip, 0) 261 resp, err := self.client.DoGet("/apiproxy/v3/ondemand/queryIps", params) 262 if err != nil { 263 return nil, errors.Wrap(err, "SRegion.GetEip.DoGet") 264 } 265 266 err = resp.Unmarshal(&eips, "returnObj", "publicips") 267 if err != nil { 268 return nil, errors.Wrap(err, "SRegion.GetEip.Unmarshal") 269 } 270 271 if len(eips) == 0 { 272 return nil, errors.Wrap(cloudprovider.ErrNotFound, "SRegion.GetEip") 273 } else if len(eips) == 1 { 274 eips[0].region = self 275 return &eips[0], nil 276 } else { 277 return nil, errors.Wrap(cloudprovider.ErrDuplicateId, "SRegion.GetEip") 278 } 279 } 280 281 func (self *SRegion) CreateEip(zoneId, name, size, shareType, chargeType string) (*SEip, error) { 282 eipParams := jsonutils.NewDict() 283 eipParams.Set("regionId", jsonutils.NewString(self.GetId())) 284 eipParams.Set("zoneId", jsonutils.NewString(zoneId)) 285 eipParams.Set("name", jsonutils.NewString(name)) 286 eipParams.Set("type", jsonutils.NewString("5_telcom")) 287 eipParams.Set("size", jsonutils.NewString(size)) 288 eipParams.Set("shareType", jsonutils.NewString(shareType)) 289 eipParams.Set("chargeMode", jsonutils.NewString(chargeType)) 290 291 params := map[string]jsonutils.JSONObject{ 292 "createIpInfo": eipParams, 293 } 294 295 resp, err := self.client.DoPost("/apiproxy/v3/ondemand/createIp", params) 296 if err != nil { 297 return nil, errors.Wrap(err, "SRegion.CreateEip.DoPost") 298 } 299 300 eipId, err := resp.GetString("returnObj", "id") 301 if err != nil { 302 return nil, errors.Wrap(err, "SRegion.CreateEip.GetEipId") 303 } 304 305 return self.GetEip(eipId) 306 } 307 308 func (self *SRegion) DeleteEip(publicIpId string) error { 309 params := map[string]jsonutils.JSONObject{ 310 "regionId": jsonutils.NewString(self.GetId()), 311 "publicIpId": jsonutils.NewString(publicIpId), 312 } 313 314 resp, err := self.client.DoPost("/apiproxy/v3/ondemand/deleteIp", params) 315 if err != nil { 316 return errors.Wrap(err, "SRegion.DeleteEip.DoPost") 317 } 318 319 var ok bool 320 err = resp.Unmarshal(&ok, "returnObj") 321 if !ok { 322 msg, _ := resp.GetString("message") 323 return errors.Wrap(fmt.Errorf(msg), "SRegion.DeleteEip.JobFailed") 324 } 325 326 return nil 327 } 328 329 // 这里networkCardId 实际指的是port id 330 func (self *SRegion) AssociateEip(publicIpId, networkCardId string) error { 331 params := map[string]jsonutils.JSONObject{ 332 "regionId": jsonutils.NewString(self.GetId()), 333 "publicIpId": jsonutils.NewString(publicIpId), 334 "networkCardId": jsonutils.NewString(networkCardId), 335 } 336 337 _, err := self.client.DoPost("/apiproxy/v3/ondemand/bindIp", params) 338 if err != nil { 339 return errors.Wrap(err, "SRegion.AssociateEip.DoPost") 340 } 341 342 return nil 343 } 344 345 func (self *SRegion) DissociateEip(publicIpId string) error { 346 params := map[string]jsonutils.JSONObject{ 347 "regionId": jsonutils.NewString(self.GetId()), 348 "publicIpId": jsonutils.NewString(publicIpId), 349 } 350 351 _, err := self.client.DoPost("/apiproxy/v3/ondemand/unbindIp", params) 352 if err != nil { 353 return errors.Wrap(err, "SRegion.DissociateEip.DoPost") 354 } 355 356 return nil 357 } 358 359 type SBandwidth struct { 360 PublicipInfo []PublicipInfo `json:"publicip_info"` 361 EnterpriseProjectID string `json:"enterprise_project_id"` 362 Name string `json:"name"` 363 ID string `json:"id"` 364 ShareType string `json:"share_type"` 365 Size int64 `json:"size"` 366 TenantID string `json:"tenant_id"` 367 ChargeMode string `json:"charge_mode"` 368 BandwidthType string `json:"bandwidth_type"` 369 } 370 371 type PublicipInfo struct { 372 PublicipType string `json:"publicip_type"` 373 PublicipAddress string `json:"publicip_address"` 374 IPVersion int64 `json:"ip_version"` 375 PublicipID string `json:"publicip_id"` 376 } 377 378 func (self *SRegion) ChangeBandwidthEip(name, publicIpId, sizeMb string) error { 379 params := map[string]jsonutils.JSONObject{ 380 "regionId": jsonutils.NewString(self.GetId()), 381 "publicIpId": jsonutils.NewString(publicIpId), 382 "name": jsonutils.NewString(name), 383 "size": jsonutils.NewString(sizeMb), 384 } 385 386 resp, err := self.client.DoPost("/apiproxy/v3/ondemand/upgradeNetwork", params) 387 if err != nil { 388 return errors.Wrap(err, "SRegion.ChangeBandwidthEip.DoPost") 389 } 390 391 bandwidth := SBandwidth{} 392 err = resp.Unmarshal(&bandwidth, "returnObj") 393 if err != nil { 394 return errors.Wrap(err, "SRegion.ChangeBandwidthEip.Unmarshal") 395 } 396 397 return nil 398 }