yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/esxi/datacenter.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 esxi 16 17 import ( 18 "regexp" 19 "strings" 20 21 "github.com/vmware/govmomi/object" 22 "github.com/vmware/govmomi/property" 23 "github.com/vmware/govmomi/view" 24 "github.com/vmware/govmomi/vim25/mo" 25 "github.com/vmware/govmomi/vim25/types" 26 27 "yunion.io/x/pkg/errors" 28 "yunion.io/x/pkg/util/sets" 29 30 api "yunion.io/x/cloudmux/pkg/apis/compute" 31 "yunion.io/x/cloudmux/pkg/cloudprovider" 32 ) 33 34 var DATACENTER_PROPS = []string{"name", "parent", "datastore", "network"} 35 36 type SDatacenter struct { 37 SManagedObject 38 39 ihosts []cloudprovider.ICloudHost 40 istorages []cloudprovider.ICloudStorage 41 inetworks []IVMNetwork 42 iresoucePool []cloudprovider.ICloudProject 43 clusters []*SCluster 44 45 Name string 46 } 47 48 func newDatacenter(manager *SESXiClient, dc *mo.Datacenter) *SDatacenter { 49 obj := SDatacenter{SManagedObject: newManagedObject(manager, dc, nil)} 50 obj.datacenter = &obj 51 return &obj 52 } 53 54 func (dc *SDatacenter) isDefaultDc() bool { 55 if dc.object == &defaultDc { 56 return true 57 } 58 return false 59 } 60 61 func (dc *SDatacenter) getDatacenter() *mo.Datacenter { 62 return dc.object.(*mo.Datacenter) 63 } 64 65 func (dc *SDatacenter) getObjectDatacenter() *object.Datacenter { 66 if dc.isDefaultDc() { 67 return nil 68 } 69 return object.NewDatacenter(dc.manager.client.Client, dc.object.Reference()) 70 } 71 72 func (dc *SDatacenter) scanResourcePool() error { 73 if dc.iresoucePool == nil { 74 pools, err := dc.listResourcePools() 75 if err != nil { 76 return errors.Wrap(err, "listResourcePools") 77 } 78 dc.iresoucePool = []cloudprovider.ICloudProject{} 79 for i := 0; i < len(pools); i++ { 80 p := NewResourcePool(dc.manager, &pools[i], dc) 81 dc.iresoucePool = append(dc.iresoucePool, p) 82 } 83 } 84 return nil 85 } 86 87 func (dc *SDatacenter) scanHosts() error { 88 if dc.ihosts == nil { 89 var hosts []mo.HostSystem 90 if dc.isDefaultDc() { 91 err := dc.manager.scanAllMObjects(HOST_SYSTEM_PROPS, &hosts) 92 if err != nil { 93 return errors.Wrap(err, "dc.manager.scanAllMObjects") 94 } 95 } else { 96 err := dc.manager.scanMObjects(dc.object.Entity().Self, HOST_SYSTEM_PROPS, &hosts) 97 if err != nil { 98 return errors.Wrap(err, "dc.manager.scanMObjects") 99 } 100 } 101 dc.ihosts = make([]cloudprovider.ICloudHost, 0) 102 for i := 0; i < len(hosts); i += 1 { 103 h := NewHost(dc.manager, &hosts[i], dc) 104 if h != nil { 105 dc.ihosts = append(dc.ihosts, h) 106 } 107 } 108 } 109 return nil 110 } 111 112 func (dc *SDatacenter) GetResourcePools() ([]cloudprovider.ICloudProject, error) { 113 err := dc.scanResourcePool() 114 if err != nil { 115 return nil, errors.Wrap(err, "dc.scanResourcePool") 116 } 117 return dc.iresoucePool, nil 118 } 119 120 func (dc *SDatacenter) listResourcePools() ([]mo.ResourcePool, error) { 121 var pools, result []mo.ResourcePool 122 err := dc.manager.scanMObjects(dc.object.Entity().Self, RESOURCEPOOL_PROPS, &pools) 123 if err != nil { 124 return nil, errors.Wrap(err, "scanMObjects") 125 } 126 for i := range pools { 127 if pools[i].Parent.Type == "ClusterComputeResource" { 128 continue 129 } 130 result = append(result, pools[i]) 131 } 132 return result, nil 133 } 134 135 func (dc *SDatacenter) ListClusters() ([]*SCluster, error) { 136 return dc.listClusters() 137 } 138 139 func (dc *SDatacenter) GetCluster(cluster string) (*SCluster, error) { 140 clusters, err := dc.ListClusters() 141 if err != nil { 142 return nil, errors.Wrap(err, "ListClusters") 143 } 144 for i := range clusters { 145 if clusters[i].GetName() == cluster { 146 return clusters[i], nil 147 } 148 149 } 150 return nil, cloudprovider.ErrNotFound 151 } 152 153 func (dc *SDatacenter) listClusters() ([]*SCluster, error) { 154 if dc.clusters != nil { 155 return dc.clusters, nil 156 } 157 clusters := []mo.ClusterComputeResource{} 158 err := dc.manager.scanMObjects(dc.object.Entity().Self, RESOURCEPOOL_PROPS, &clusters) 159 if err != nil { 160 return nil, errors.Wrap(err, "scanMObjects") 161 } 162 ret := []*SCluster{} 163 for i := range clusters { 164 c := NewCluster(dc.manager, &clusters[i], dc) 165 ret = append(ret, c) 166 } 167 return ret, nil 168 } 169 170 func (dc *SDatacenter) GetIHosts() ([]cloudprovider.ICloudHost, error) { 171 err := dc.scanHosts() 172 if err != nil { 173 return nil, errors.Wrap(err, "dc.scanHosts") 174 } 175 return dc.ihosts, nil 176 } 177 178 func (dc *SDatacenter) scanDatastores() error { 179 if dc.istorages == nil { 180 var stores []mo.Datastore 181 if dc.isDefaultDc() { 182 err := dc.manager.scanAllMObjects(DATASTORE_PROPS, &stores) 183 if err != nil { 184 return errors.Wrap(err, "dc.manager.scanAllMObjects") 185 } 186 } else { 187 dsList := dc.getDatacenter().Datastore 188 if dsList != nil { 189 err := dc.manager.references2Objects(dsList, DATASTORE_PROPS, &stores) 190 if err != nil { 191 return errors.Wrap(err, "dc.manager.references2Objects") 192 } 193 } 194 } 195 dc.istorages = make([]cloudprovider.ICloudStorage, 0) 196 for i := 0; i < len(stores); i += 1 { 197 ds := NewDatastore(dc.manager, &stores[i], dc) 198 dsId := ds.GetGlobalId() 199 if len(dsId) > 0 { 200 dc.istorages = append(dc.istorages, ds) 201 } 202 } 203 } 204 return nil 205 } 206 207 func (dc *SDatacenter) GetIStorages() ([]cloudprovider.ICloudStorage, error) { 208 err := dc.scanDatastores() 209 if err != nil { 210 return nil, errors.Wrap(err, "dc.scanDatastores") 211 } 212 return dc.istorages, nil 213 } 214 215 func (dc *SDatacenter) GetIHostByMoId(idstr string) (cloudprovider.ICloudHost, error) { 216 ihosts, err := dc.GetIHosts() 217 if err != nil { 218 return nil, errors.Wrap(err, "dc.GetIHosts") 219 } 220 for i := 0; i < len(ihosts); i += 1 { 221 if ihosts[i].GetId() == idstr { 222 return ihosts[i], nil 223 } 224 } 225 return nil, cloudprovider.ErrNotFound 226 } 227 228 func (dc *SDatacenter) GetIStorageByMoId(idstr string) (cloudprovider.ICloudStorage, error) { 229 istorages, err := dc.GetIStorages() 230 if err != nil { 231 return nil, errors.Wrap(err, "dc.GetIStorages") 232 } 233 for i := 0; i < len(istorages); i += 1 { 234 if istorages[i].GetId() == idstr { 235 return istorages[i], nil 236 } 237 } 238 return nil, cloudprovider.ErrNotFound 239 } 240 241 func (dc *SDatacenter) getDcObj() *object.Datacenter { 242 if dc.isDefaultDc() { 243 return nil 244 } 245 return object.NewDatacenter(dc.manager.client.Client, dc.object.Reference()) 246 } 247 248 func (dc *SDatacenter) fetchMoVms(filter property.Filter, props []string) ([]mo.VirtualMachine, error) { 249 odc := dc.getObjectDatacenter() 250 root := odc.Reference() 251 var movms []mo.VirtualMachine 252 err := dc.manager.scanMObjectsWithFilter(root, props, &movms, filter) 253 if err != nil { 254 return nil, errors.Wrap(err, "scanMObjectsWithFilter") 255 } 256 return movms, nil 257 } 258 259 func (dc *SDatacenter) moVms2Vm(movms []mo.VirtualMachine, all *bool) ([]*SVirtualMachine, error) { 260 // avoid applying new memory and copying 261 vms := make([]*SVirtualMachine, 0, len(movms)) 262 for i := range movms { 263 if (all != nil && *all) || !strings.HasPrefix(movms[i].Name, api.ESXI_IMAGE_CACHE_TMP_PREFIX) { 264 vm := NewVirtualMachine(dc.manager, &movms[i], dc) 265 // must 266 if vm == nil { 267 continue 268 } 269 vms = append(vms, vm) 270 } 271 } 272 return vms, nil 273 } 274 275 func (dc *SDatacenter) fetchFakeTemplateVMs(movms []mo.VirtualMachine, regex string) ([]*SVirtualMachine, error) { 276 var ( 277 tNameRegex *regexp.Regexp 278 err error 279 ) 280 if len(regex) == 0 { 281 tNameRegex = tempalteNameRegex 282 } else { 283 tNameRegex, err = regexp.Compile(regex) 284 if err != nil { 285 return nil, errors.Wrap(err, "generate regexp") 286 } 287 } 288 objs := make([]types.ManagedObjectReference, 0) 289 for i := range movms { 290 name := movms[i].Name 291 if tNameRegex != nil && tNameRegex.MatchString(name) { 292 objs = append(objs, movms[i].Reference()) 293 } 294 } 295 if len(objs) == 0 { 296 return nil, nil 297 } 298 return dc.fetchVms(objs, false) 299 } 300 301 func (dc *SDatacenter) fetchVmsFromCache(vmRefs []types.ManagedObjectReference) ([]*SVirtualMachine, error) { 302 vmRefSet := sets.NewString() 303 for i := range vmRefs { 304 vmRefSet.Insert(vmRefs[i].String()) 305 } 306 ihosts, err := dc.GetIHosts() 307 if err != nil { 308 return nil, err 309 } 310 ret := make([]*SVirtualMachine, 0, len(vmRefs)) 311 for i := range ihosts { 312 ivms, err := ihosts[i].GetIVMs() 313 if err != nil { 314 return nil, err 315 } 316 for i := range ivms { 317 vm := ivms[i].(*SVirtualMachine) 318 s := vm.getVirtualMachine().Self.String() 319 if vmRefSet.Has(s) { 320 ret = append(ret, vm) 321 vmRefSet.Delete(s) 322 } 323 } 324 } 325 return ret, nil 326 } 327 328 func (dc *SDatacenter) fetchVms(vmRefs []types.ManagedObjectReference, all bool) ([]*SVirtualMachine, error) { 329 var movms []mo.VirtualMachine 330 if vmRefs != nil { 331 err := dc.manager.references2Objects(vmRefs, VIRTUAL_MACHINE_PROPS, &movms) 332 if err != nil { 333 return nil, errors.Wrap(err, "dc.manager.references2Objects") 334 } 335 } 336 return dc.moVms2Vm(movms, &all) 337 } 338 339 func (dc *SDatacenter) fetchHosts_(vmRefs []types.ManagedObjectReference, all bool) ([]*SHost, error) { 340 var movms []mo.HostSystem 341 if vmRefs != nil { 342 err := dc.manager.references2Objects(vmRefs, VIRTUAL_MACHINE_PROPS, &movms) 343 if err != nil { 344 return nil, errors.Wrap(err, "dc.manager.references2Objects") 345 } 346 } 347 348 // avoid applying new memory and copying 349 vms := make([]*SHost, 0, len(movms)) 350 for i := range movms { 351 if all || !strings.HasPrefix(movms[i].Entity().Name, api.ESXI_IMAGE_CACHE_TMP_PREFIX) { 352 vms = append(vms, NewHost(dc.manager, &movms[i], dc)) 353 } 354 } 355 return vms, nil 356 } 357 358 func (dc *SDatacenter) FetchVMs() ([]*SVirtualMachine, error) { 359 return dc.fetchVMsWithFilter(property.Filter{}) 360 } 361 362 func (dc *SDatacenter) FetchNoTemplateVMs() ([]*SVirtualMachine, error) { 363 filter := property.Filter{} 364 filter["config.template"] = false 365 return dc.fetchVMsWithFilter(filter) 366 } 367 368 func (dc *SDatacenter) FetchFakeTempateVMs(regex string) ([]*SVirtualMachine, error) { 369 filter := property.Filter{} 370 filter["summary.runtime.powerState"] = types.VirtualMachinePowerStatePoweredOff 371 movms, err := dc.fetchMoVms(filter, []string{"name"}) 372 if err != nil { 373 return nil, errors.Wrap(err, "unable to fetch mo.VirtualMachines") 374 } 375 return dc.fetchFakeTemplateVMs(movms, regex) 376 } 377 378 func (dc *SDatacenter) fetchVMsWithFilter(filter property.Filter) ([]*SVirtualMachine, error) { 379 movms, err := dc.fetchMoVms(filter, VIRTUAL_MACHINE_PROPS) 380 if err != nil { 381 return nil, errors.Wrap(err, "unable to fetch mo.VirtualMachines") 382 } 383 ret, err := dc.moVms2Vm(movms, nil) 384 if err != nil { 385 return nil, errors.Wrap(err, "unable to convert mo.VirtualMachine to VirtualMachine") 386 } 387 return ret, err 388 } 389 390 func (dc *SDatacenter) FetchNoTemplateVMEntityReferens() ([]types.ManagedObjectReference, error) { 391 filter := property.Filter{} 392 filter["config.template"] = false 393 odc := dc.getObjectDatacenter() 394 root := odc.Reference() 395 m := view.NewManager(dc.manager.client.Client) 396 v, err := m.CreateContainerView(dc.manager.context, root, []string{"VirtualMachine"}, true) 397 if err != nil { 398 return nil, err 399 } 400 defer func() { 401 _ = v.Destroy(dc.manager.context) 402 }() 403 objs, err := v.Find(dc.manager.context, []string{"VirtualMachine"}, filter) 404 if err != nil { 405 return nil, err 406 } 407 return objs, nil 408 } 409 410 func (dc *SDatacenter) FetchNoTemplateHostEntityReferens() ([]types.ManagedObjectReference, error) { 411 filter := property.Filter{} 412 odc := dc.getObjectDatacenter() 413 root := odc.Reference() 414 m := view.NewManager(dc.manager.client.Client) 415 v, err := m.CreateContainerView(dc.manager.context, root, []string{"HostSystem"}, true) 416 if err != nil { 417 return nil, err 418 } 419 defer func() { 420 _ = v.Destroy(dc.manager.context) 421 }() 422 objs, err := v.Find(dc.manager.context, []string{"HostSystem"}, filter) 423 if err != nil { 424 return nil, err 425 } 426 return objs, nil 427 } 428 429 func (dc *SDatacenter) fetchHosts(filter property.Filter) ([]*SHost, error) { 430 odc := dc.getObjectDatacenter() 431 root := odc.Reference() 432 m := view.NewManager(dc.manager.client.Client) 433 v, err := m.CreateContainerView(dc.manager.context, root, []string{"HostSystem"}, true) 434 if err != nil { 435 return nil, err 436 } 437 defer func() { 438 _ = v.Destroy(dc.manager.context) 439 }() 440 objs, err := v.Find(dc.manager.context, []string{"HostSystem"}, filter) 441 if err != nil { 442 return nil, err 443 } 444 hosts, err := dc.fetchHosts_(objs, false) 445 return hosts, err 446 } 447 448 func (dc *SDatacenter) FetchTemplateVMs() ([]*SVirtualMachine, error) { 449 filter := property.Filter{} 450 filter["config.template"] = true 451 return dc.fetchVMsWithFilter(filter) 452 } 453 454 func (dc *SDatacenter) FetchTemplateVMById(id string) (*SVirtualMachine, error) { 455 filter := property.Filter{} 456 filter["config.template"] = true 457 filter["summary.config.uuid"] = id 458 vms, err := dc.fetchVMsWithFilter(filter) 459 if err != nil { 460 return nil, err 461 } 462 if len(vms) == 0 { 463 return nil, errors.ErrNotFound 464 } 465 return vms[0], nil 466 } 467 468 func (dc *SDatacenter) FetchVMById(id string) (*SVirtualMachine, error) { 469 filter := property.Filter{} 470 filter["summary.config.uuid"] = id 471 vms, err := dc.fetchVMsWithFilter(filter) 472 if err != nil { 473 return nil, err 474 } 475 if len(vms) == 0 { 476 return nil, errors.ErrNotFound 477 } 478 return vms[0], nil 479 } 480 481 func (dc *SDatacenter) fetchDatastores(datastoreRefs []types.ManagedObjectReference) ([]cloudprovider.ICloudStorage, error) { 482 var dss []mo.Datastore 483 if datastoreRefs != nil { 484 err := dc.manager.references2Objects(datastoreRefs, DATASTORE_PROPS, &dss) 485 if err != nil { 486 return nil, errors.Wrap(err, "dc.manager.references2Objects") 487 } 488 } 489 490 retDatastores := make([]cloudprovider.ICloudStorage, 0, len(dss)) 491 for i := range dss { 492 retDatastores = append(retDatastores, NewDatastore(dc.manager, &dss[i], dc)) 493 } 494 return retDatastores, nil 495 } 496 497 func (dc *SDatacenter) scanNetworks() error { 498 if dc.inetworks == nil { 499 if dc.isDefaultDc() { 500 return dc.scanDefaultNetworks() 501 } else { 502 return dc.scanDcNetworks() 503 } 504 } 505 return nil 506 } 507 508 func (dc *SDatacenter) scanDefaultNetworks() error { 509 dc.inetworks = make([]IVMNetwork, 0) 510 err := dc.scanAllDvPortgroups() 511 if err != nil { 512 return errors.Wrap(err, "dc.scanAllDvPortgroups") 513 } 514 err = dc.scanAllNetworks() 515 if err != nil { 516 return errors.Wrap(err, "dc.scanAllNetworks") 517 } 518 return nil 519 } 520 521 func (dc *SDatacenter) scanAllDvPortgroups() error { 522 var dvports []mo.DistributedVirtualPortgroup 523 524 err := dc.manager.scanAllMObjects(DVPORTGROUP_PROPS, &dvports) 525 if err != nil { 526 return errors.Wrap(err, "dc.manager.scanAllMObjects mo.DistributedVirtualPortgroup") 527 } 528 for i := range dvports { 529 net := NewDistributedVirtualPortgroup(dc.manager, &dvports[i], dc) 530 dc.inetworks = append(dc.inetworks, net) 531 } 532 return nil 533 } 534 535 func (dc *SDatacenter) scanAllNetworks() error { 536 var nets []mo.Network 537 538 err := dc.manager.scanAllMObjects(NETWORK_PROPS, &nets) 539 if err != nil { 540 return errors.Wrap(err, "dc.manager.scanAllMObjects mo.Network") 541 } 542 for i := range nets { 543 net := NewNetwork(dc.manager, &nets[i], dc) 544 dc.inetworks = append(dc.inetworks, net) 545 } 546 return nil 547 } 548 549 func (dc *SDatacenter) scanDcNetworks() error { 550 dc.inetworks = make([]IVMNetwork, 0) 551 552 netMOBs := dc.getDatacenter().Network 553 for i := range netMOBs { 554 dvport := mo.DistributedVirtualPortgroup{} 555 err := dc.manager.reference2Object(netMOBs[i], DVPORTGROUP_PROPS, &dvport) 556 if err == nil { 557 net := NewDistributedVirtualPortgroup(dc.manager, &dvport, dc) 558 dc.inetworks = append(dc.inetworks, net) 559 } else { 560 net := mo.Network{} 561 err = dc.manager.reference2Object(netMOBs[i], NETWORK_PROPS, &net) 562 if err == nil { 563 vnet := NewNetwork(dc.manager, &net, dc) 564 dc.inetworks = append(dc.inetworks, vnet) 565 } else { 566 return errors.Wrap(err, "dc.manager.reference2Object") 567 } 568 } 569 } 570 return nil 571 } 572 573 func (dc *SDatacenter) GetNetworks() ([]IVMNetwork, error) { 574 err := dc.scanNetworks() 575 if err != nil { 576 return nil, errors.Wrap(err, "dc.scanNetworks") 577 } 578 return dc.inetworks, nil 579 } 580 581 func (dc *SDatacenter) GetTemplateVMs() ([]*SVirtualMachine, error) { 582 hosts, err := dc.GetIHosts() 583 if err != nil { 584 return nil, errors.Wrap(err, "SDatacenter.GetIHosts") 585 } 586 templateVms := make([]*SVirtualMachine, 5) 587 for _, ihost := range hosts { 588 host := ihost.(*SHost) 589 tvms, err := host.GetTemplateVMs() 590 if err != nil { 591 return nil, errors.Wrap(err, "host.GetTemplateVMs") 592 } 593 templateVms = append(templateVms, tvms...) 594 } 595 return templateVms, nil 596 }