yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/ecloud/instance.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 ecloud 16 17 import ( 18 "context" 19 "fmt" 20 "time" 21 22 "yunion.io/x/pkg/errors" 23 "yunion.io/x/pkg/util/sets" 24 25 billing_api "yunion.io/x/cloudmux/pkg/apis/billing" 26 api "yunion.io/x/cloudmux/pkg/apis/compute" 27 "yunion.io/x/cloudmux/pkg/cloudprovider" 28 "yunion.io/x/cloudmux/pkg/multicloud" 29 "yunion.io/x/onecloud/pkg/util/billing" 30 ) 31 32 type SNovaRequest struct { 33 SApiRequest 34 } 35 36 func NewNovaRequest(ar *SApiRequest) *SNovaRequest { 37 return &SNovaRequest{ 38 SApiRequest: *ar, 39 } 40 } 41 42 func (nr *SNovaRequest) GetPort() string { 43 if nr.RegionId == "guangzhou-2" { 44 return "" 45 } 46 return nr.SApiRequest.GetPort() 47 } 48 49 type SInstance struct { 50 multicloud.SInstanceBase 51 EcloudTags 52 multicloud.SBillingBase 53 SZoneRegionBase 54 SCreateTime 55 56 nicComplete bool 57 host *SHost 58 image *SImage 59 60 sysDisk cloudprovider.ICloudDisk 61 dataDisks []cloudprovider.ICloudDisk 62 63 Id string 64 Name string 65 Vcpu int 66 Vmemory int 67 KeyName string 68 ImageRef string 69 ImageName string 70 ImageOsType string 71 FlavorRef string 72 SystemDiskSizeGB int `json:"vdisk"` 73 SystemDiskId string 74 ServerType string 75 ServerVmType string 76 EcStatus string 77 BootVolumeType string 78 Deleted int 79 Visible bool 80 Region string 81 PortDetail []SInstanceNic 82 } 83 84 func (i *SInstance) GetBillingType() string { 85 return billing_api.BILLING_TYPE_POSTPAID 86 } 87 88 func (i *SInstance) GetExpiredAt() time.Time { 89 return time.Time{} 90 } 91 92 func (i *SInstance) GetId() string { 93 return i.Id 94 } 95 96 func (i *SInstance) GetName() string { 97 return i.Name 98 } 99 100 func (i *SInstance) GetHostname() string { 101 return i.Name 102 } 103 104 func (i *SInstance) GetGlobalId() string { 105 return i.GetId() 106 } 107 108 func (i *SInstance) GetStatus() string { 109 switch i.EcStatus { 110 case "active": 111 return api.VM_RUNNING 112 case "suspended", "paused": 113 return api.VM_SUSPEND 114 case "build", "rebuild", "resize", "verify_resize", "revert_resize", "password": 115 return api.VM_STARTING 116 case "reboot", "hard_reboot": 117 return api.VM_STOPPING 118 case "stopped", "shutoff": 119 return api.VM_READY 120 case "migrating": 121 return api.VM_MIGRATING 122 case "backuping": 123 return api.VM_BACKUP_CREATING 124 default: 125 return api.VM_UNKNOWN 126 } 127 } 128 129 func (i *SInstance) Refresh() error { 130 // TODO 131 return nil 132 } 133 134 func (i *SInstance) IsEmulated() bool { 135 return false 136 } 137 138 func (self *SInstance) GetBootOrder() string { 139 return "dcn" 140 } 141 142 func (self *SInstance) GetVga() string { 143 return "std" 144 } 145 146 func (self *SInstance) GetVdi() string { 147 return "vnc" 148 } 149 150 func (i *SInstance) GetImage() (*SImage, error) { 151 if i.image != nil { 152 return i.image, nil 153 } 154 image, err := i.host.zone.region.GetImage(i.ImageRef) 155 if err != nil { 156 return nil, err 157 } 158 i.image = image 159 return i.image, nil 160 } 161 162 func (i *SInstance) GetOsType() cloudprovider.TOsType { 163 return cloudprovider.TOsType(i.ImageOsType) 164 } 165 166 func (i *SInstance) GetFullOsName() string { 167 image, err := i.GetImage() 168 if err != nil { 169 return "" 170 } 171 return image.GetFullOsName() 172 } 173 174 func (i *SInstance) GetBios() cloudprovider.TBiosType { 175 image, err := i.GetImage() 176 if err != nil { 177 return cloudprovider.BIOS 178 } 179 return image.GetBios() 180 } 181 182 func (i *SInstance) GetOsArch() string { 183 image, err := i.GetImage() 184 if err != nil { 185 return "" 186 } 187 return image.GetOsArch() 188 } 189 190 func (i *SInstance) GetOsDist() string { 191 image, err := i.GetImage() 192 if err != nil { 193 return "" 194 } 195 return image.GetOsDist() 196 } 197 198 func (i *SInstance) GetOsVersion() string { 199 image, err := i.GetImage() 200 if err != nil { 201 return "" 202 } 203 return image.GetOsVersion() 204 } 205 206 func (i *SInstance) GetOsLang() string { 207 image, err := i.GetImage() 208 if err != nil { 209 return "" 210 } 211 return image.GetOsLang() 212 } 213 214 func (i *SInstance) GetMachine() string { 215 return "pc" 216 } 217 218 func (i *SInstance) GetInstanceType() string { 219 return i.FlavorRef 220 } 221 222 func (in *SInstance) GetProjectId() string { 223 return "" 224 } 225 226 func (in *SInstance) GetIHost() cloudprovider.ICloudHost { 227 return in.host 228 } 229 230 func (in *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { 231 if in.sysDisk == nil { 232 in.fetchSysDisk() 233 } 234 if in.dataDisks == nil { 235 err := in.fetchDataDisks() 236 if err != nil { 237 return nil, err 238 } 239 } 240 return append([]cloudprovider.ICloudDisk{in.sysDisk}, in.dataDisks...), nil 241 } 242 243 func (in *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { 244 if !in.nicComplete { 245 err := in.makeNicComplete() 246 if err != nil { 247 return nil, errors.Wrap(err, "unable to make nics complete") 248 } 249 in.nicComplete = true 250 } 251 inics := make([]cloudprovider.ICloudNic, len(in.PortDetail)) 252 for i := range in.PortDetail { 253 in.PortDetail[i].instance = in 254 inics[i] = &in.PortDetail[i] 255 } 256 return inics, nil 257 } 258 259 func (in *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { 260 if !in.nicComplete { 261 err := in.makeNicComplete() 262 if err != nil { 263 return nil, errors.Wrap(err, "unable to make nics complete") 264 } 265 in.nicComplete = true 266 } 267 var eipId string 268 for i := range in.PortDetail { 269 if len(in.PortDetail[i].IpId) > 0 { 270 eipId = in.PortDetail[i].IpId 271 break 272 } 273 } 274 if len(eipId) == 0 { 275 return nil, nil 276 } 277 return in.host.zone.region.GetEipById(eipId) 278 } 279 280 func (in *SInstance) GetSecurityGroupIds() ([]string, error) { 281 if !in.nicComplete { 282 err := in.makeNicComplete() 283 if err != nil { 284 return nil, errors.Wrap(err, "unable to make nics complete") 285 } 286 in.nicComplete = true 287 } 288 ret := sets.NewString() 289 for i := range in.PortDetail { 290 for _, group := range in.PortDetail[i].SecurityGroups { 291 ret.Insert(group.Id) 292 } 293 } 294 return ret.UnsortedList(), nil 295 } 296 297 func (in *SInstance) GetVcpuCount() int { 298 return in.Vcpu 299 } 300 301 func (in *SInstance) GetVmemSizeMB() int { 302 return in.Vmemory 303 } 304 305 func (in *SInstance) AssignSecurityGroup(id string) error { 306 return cloudprovider.ErrNotImplemented 307 } 308 309 func (in *SInstance) SetSecurityGroups(ids []string) error { 310 return cloudprovider.ErrNotImplemented 311 } 312 313 func (in *SInstance) GetHypervisor() string { 314 return api.HYPERVISOR_ECLOUD 315 } 316 317 func (in *SInstance) StartVM(ctx context.Context) error { 318 return cloudprovider.ErrNotImplemented 319 } 320 321 func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { 322 return cloudprovider.ErrNotImplemented 323 } 324 325 func (self *SInstance) DeleteVM(ctx context.Context) error { 326 return cloudprovider.ErrNotImplemented 327 } 328 329 func (self *SInstance) UpdateVM(ctx context.Context, name string) error { 330 return cloudprovider.ErrNotSupported 331 } 332 333 func (self *SInstance) UpdateUserData(userData string) error { 334 return cloudprovider.ErrNotSupported 335 } 336 337 func (self *SInstance) RebuildRoot(ctx context.Context, config *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { 338 return "", cloudprovider.ErrNotImplemented 339 } 340 341 func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { 342 return cloudprovider.ErrNotImplemented 343 } 344 345 func (in *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { 346 return errors.ErrNotImplemented 347 } 348 349 func (in *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { 350 url, err := in.host.zone.region.GetInstanceVNCUrl(in.GetId()) 351 if err != nil { 352 return nil, err 353 } 354 ret := &cloudprovider.ServerVncOutput{ 355 Url: url, 356 Protocol: "ecloud", 357 InstanceId: in.GetId(), 358 Hypervisor: api.HYPERVISOR_ECLOUD, 359 } 360 return ret, nil 361 } 362 363 func (in *SInstance) AttachDisk(ctx context.Context, diskId string) error { 364 return cloudprovider.ErrNotImplemented 365 } 366 367 func (in *SInstance) DetachDisk(ctx context.Context, diskId string) error { 368 return cloudprovider.ErrNotImplemented 369 } 370 371 func (self *SInstance) Renew(bc billing.SBillingCycle) error { 372 return cloudprovider.ErrNotImplemented 373 } 374 375 func (self *SInstance) GetError() error { 376 return nil 377 } 378 379 func (in *SInstance) fetchSysDisk() { 380 storage, _ := in.host.zone.getStorageByType(api.STORAGE_ECLOUD_SYSTEM) 381 disk := SDisk{ 382 storage: storage, 383 ManualAttr: SDiskManualAttr{ 384 IsVirtual: true, 385 TempalteId: in.ImageRef, 386 ServerId: in.Id, 387 }, 388 SCreateTime: in.SCreateTime, 389 SZoneRegionBase: in.SZoneRegionBase, 390 ServerId: []string{in.Id}, 391 IsShare: false, 392 IsDelete: false, 393 SizeGB: in.SystemDiskSizeGB, 394 ID: in.SystemDiskId, 395 Name: fmt.Sprintf("%s-root", in.Name), 396 Status: "in-use", 397 Type: api.STORAGE_ECLOUD_SYSTEM, 398 } 399 in.sysDisk = &disk 400 return 401 } 402 403 func (in *SInstance) fetchDataDisks() error { 404 request := NewNovaRequest(NewApiRequest(in.host.zone.region.ID, "/api/v2/volume/volume/mount/list", 405 map[string]string{"serverId": in.Id}, nil)) 406 disks := make([]SDisk, 0, 5) 407 err := in.host.zone.region.client.doList(context.Background(), request, &disks) 408 if err != nil { 409 return err 410 } 411 idisks := make([]cloudprovider.ICloudDisk, len(disks)) 412 for i := range idisks { 413 storageType := disks[i].Type 414 storage, err := in.host.zone.getStorageByType(storageType) 415 if err != nil { 416 return errors.Wrapf(err, "unable to fetch storage with stoageType %s", storageType) 417 } 418 disks[i].storage = storage 419 idisks[i] = &disks[i] 420 } 421 in.dataDisks = idisks 422 return nil 423 } 424 425 func (in *SInstance) makeNicComplete() error { 426 routerIds := sets.NewString() 427 nics := make(map[string]*SInstanceNic, len(in.PortDetail)) 428 for i := range in.PortDetail { 429 nic := &in.PortDetail[i] 430 routerIds.Insert(nic.RouterId) 431 nics[nic.PortId] = nic 432 } 433 for _, routerId := range routerIds.UnsortedList() { 434 request := NewConsoleRequest(in.host.zone.region.ID, fmt.Sprintf("/api/vpc/%s/nic", routerId), 435 map[string]string{ 436 "resourceId": in.Id, 437 }, nil, 438 ) 439 completeNics := make([]SInstanceNic, 0, len(nics)/2) 440 err := in.host.zone.region.client.doList(context.Background(), request, &completeNics) 441 if err != nil { 442 return errors.Wrapf(err, "unable to get nics with instance %s in vpc %s", in.Id, routerId) 443 } 444 for i := range completeNics { 445 id := completeNics[i].Id 446 nic, ok := nics[id] 447 if !ok { 448 continue 449 } 450 nic.SInstanceNicDetail = completeNics[i].SInstanceNicDetail 451 } 452 } 453 return nil 454 } 455 456 func (r *SRegion) findHost(zoneRegion string) (*SHost, error) { 457 zone, err := r.FindZone(zoneRegion) 458 if err != nil { 459 return nil, err 460 } 461 return &SHost{ 462 zone: zone, 463 }, nil 464 } 465 466 func (r *SRegion) GetInstancesWithHost(zoneRegion string) ([]SInstance, error) { 467 instances, err := r.GetInstances(zoneRegion) 468 if err != nil { 469 return nil, err 470 } 471 for i := range instances { 472 host, _ := r.findHost(instances[i].Region) 473 instances[i].host = host 474 } 475 return instances, nil 476 } 477 478 func (r *SRegion) GetInstances(zoneRegion string) ([]SInstance, error) { 479 return r.getInstances(zoneRegion, "") 480 } 481 482 func (r *SRegion) getInstances(zoneRegion string, serverId string) ([]SInstance, error) { 483 query := map[string]string{ 484 "serverTypes": "VM", 485 "productTypes": "NORMAL,AUTOSCALING,VO,CDN,PAAS_MASTER,PAAS_SLAVE,VCPE,EMR,LOGAUDIT", 486 //"productTypes": "NORMAL", 487 "visible": "true", 488 } 489 if len(serverId) > 0 { 490 query["serverId"] = serverId 491 } 492 if len(zoneRegion) > 0 { 493 query["region"] = zoneRegion 494 } 495 request := NewNovaRequest(NewApiRequest(r.ID, "/api/v2/server/web/with/network", query, nil)) 496 var instances []SInstance 497 err := r.client.doList(context.Background(), request, &instances) 498 if err != nil { 499 return nil, err 500 } 501 return instances, nil 502 } 503 504 func (r *SRegion) GetInstanceById(id string) (*SInstance, error) { 505 instances, err := r.getInstances("", id) 506 if err != nil { 507 return nil, err 508 } 509 if len(instances) == 0 { 510 return nil, cloudprovider.ErrNotFound 511 } 512 instance := &instances[0] 513 host, err := r.findHost(instance.Region) 514 if err == nil { 515 instance.host = host 516 } 517 return instance, nil 518 } 519 520 func (r *SRegion) GetInstanceVNCUrl(instanceId string) (string, error) { 521 request := NewNovaRequest(NewApiRequest(r.ID, fmt.Sprintf("/api/server/%s/vnc", instanceId), nil, nil)) 522 var url string 523 err := r.client.doGet(context.Background(), request, &url) 524 if err != nil { 525 return "", err 526 } 527 return url, nil 528 }