github.com/vmware/govmomi@v0.37.1/find/finder.go (about) 1 /* 2 Copyright (c) 2014-2023 VMware, Inc. All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package find 18 19 import ( 20 "context" 21 "errors" 22 "path" 23 "strings" 24 25 "github.com/vmware/govmomi/internal" 26 "github.com/vmware/govmomi/list" 27 "github.com/vmware/govmomi/object" 28 "github.com/vmware/govmomi/property" 29 "github.com/vmware/govmomi/view" 30 "github.com/vmware/govmomi/vim25" 31 "github.com/vmware/govmomi/vim25/mo" 32 "github.com/vmware/govmomi/vim25/types" 33 ) 34 35 type Finder struct { 36 client *vim25.Client 37 r recurser 38 dc *object.Datacenter 39 si *object.SearchIndex 40 folders *object.DatacenterFolders 41 } 42 43 func NewFinder(client *vim25.Client, all ...bool) *Finder { 44 props := false 45 if len(all) == 1 { 46 props = all[0] 47 } 48 49 f := &Finder{ 50 client: client, 51 si: object.NewSearchIndex(client), 52 r: recurser{ 53 Collector: property.DefaultCollector(client), 54 All: props, 55 }, 56 } 57 58 if len(all) == 0 { 59 // attempt to avoid SetDatacenter() requirement 60 f.dc, _ = f.DefaultDatacenter(context.Background()) 61 } 62 63 return f 64 } 65 66 func (f *Finder) SetDatacenter(dc *object.Datacenter) *Finder { 67 f.dc = dc 68 f.folders = nil 69 return f 70 } 71 72 // InventoryPath composes the given object's inventory path. 73 // There is no vSphere property or method that provides an inventory path directly. 74 // This method uses the ManagedEntity.Parent field to determine the ancestry tree of the object and 75 // the ManagedEntity.Name field for each ancestor to compose the path. 76 func InventoryPath(ctx context.Context, client *vim25.Client, obj types.ManagedObjectReference) (string, error) { 77 entities, err := mo.Ancestors(ctx, client, client.ServiceContent.PropertyCollector, obj) 78 if err != nil { 79 return "", err 80 } 81 return internal.InventoryPath(entities), nil 82 } 83 84 // findRoot makes it possible to use "find" mode with a different root path. 85 // Example: ResourcePoolList("/dc1/host/cluster1/...") 86 func (f *Finder) findRoot(ctx context.Context, root *list.Element, parts []string) bool { 87 if len(parts) == 0 { 88 return false 89 } 90 91 ix := len(parts) - 1 92 93 if parts[ix] != "..." { 94 return false 95 } 96 97 if ix == 0 { 98 return true // We already have the Object for root.Path 99 } 100 101 // Lookup the Object for the new root.Path 102 rootPath := path.Join(root.Path, path.Join(parts[:ix]...)) 103 104 ref, err := f.si.FindByInventoryPath(ctx, rootPath) 105 if err != nil || ref == nil { 106 // If we get an error or fail to match, fall through to find() with the original root and path 107 return false 108 } 109 110 root.Path = rootPath 111 root.Object = ref 112 113 return true 114 } 115 116 func (f *Finder) find(ctx context.Context, arg string, s *spec) ([]list.Element, error) { 117 isPath := strings.Contains(arg, "/") 118 119 root := list.Element{ 120 Object: object.NewRootFolder(f.client), 121 Path: "/", 122 } 123 124 parts := list.ToParts(arg) 125 126 if len(parts) > 0 { 127 switch parts[0] { 128 case "..": // Not supported; many edge case, little value 129 return nil, errors.New("cannot traverse up a tree") 130 case ".": // Relative to whatever 131 pivot, err := s.Relative(ctx) 132 if err != nil { 133 return nil, err 134 } 135 136 root.Path, err = InventoryPath(ctx, f.client, pivot.Reference()) 137 if err != nil { 138 return nil, err 139 } 140 root.Object = pivot 141 parts = parts[1:] 142 } 143 } 144 145 if s.listMode(isPath) { 146 if f.findRoot(ctx, &root, parts) { 147 parts = []string{"*"} 148 } else { 149 return f.r.List(ctx, s, root, parts) 150 } 151 } 152 153 s.Parents = append(s.Parents, s.Nested...) 154 155 return f.r.Find(ctx, s, root, parts) 156 } 157 158 func (f *Finder) datacenter() (*object.Datacenter, error) { 159 if f.dc == nil { 160 return nil, errors.New("please specify a datacenter") 161 } 162 163 return f.dc, nil 164 } 165 166 // datacenterPath returns the absolute path to the Datacenter containing the given ref 167 func (f *Finder) datacenterPath(ctx context.Context, ref types.ManagedObjectReference) (string, error) { 168 mes, err := mo.Ancestors(ctx, f.client, f.client.ServiceContent.PropertyCollector, ref) 169 if err != nil { 170 return "", err 171 } 172 173 // Chop leaves under the Datacenter 174 for i := len(mes) - 1; i > 0; i-- { 175 if mes[i].Self.Type == "Datacenter" { 176 break 177 } 178 mes = mes[:i] 179 } 180 181 var p string 182 183 for _, me := range mes { 184 // Skip root entity in building inventory path. 185 if me.Parent == nil { 186 continue 187 } 188 189 p = p + "/" + me.Name 190 } 191 192 return p, nil 193 } 194 195 func (f *Finder) dcFolders(ctx context.Context) (*object.DatacenterFolders, error) { 196 if f.folders != nil { 197 return f.folders, nil 198 } 199 200 dc, err := f.datacenter() 201 if err != nil { 202 return nil, err 203 } 204 205 folders, err := dc.Folders(ctx) 206 if err != nil { 207 return nil, err 208 } 209 210 f.folders = folders 211 212 return f.folders, nil 213 } 214 215 func (f *Finder) dcReference(_ context.Context) (object.Reference, error) { 216 dc, err := f.datacenter() 217 if err != nil { 218 return nil, err 219 } 220 221 return dc, nil 222 } 223 224 func (f *Finder) vmFolder(ctx context.Context) (object.Reference, error) { 225 folders, err := f.dcFolders(ctx) 226 if err != nil { 227 return nil, err 228 } 229 230 return folders.VmFolder, nil 231 } 232 233 func (f *Finder) hostFolder(ctx context.Context) (object.Reference, error) { 234 folders, err := f.dcFolders(ctx) 235 if err != nil { 236 return nil, err 237 } 238 239 return folders.HostFolder, nil 240 } 241 242 func (f *Finder) datastoreFolder(ctx context.Context) (object.Reference, error) { 243 folders, err := f.dcFolders(ctx) 244 if err != nil { 245 return nil, err 246 } 247 248 return folders.DatastoreFolder, nil 249 } 250 251 func (f *Finder) networkFolder(ctx context.Context) (object.Reference, error) { 252 folders, err := f.dcFolders(ctx) 253 if err != nil { 254 return nil, err 255 } 256 257 return folders.NetworkFolder, nil 258 } 259 260 func (f *Finder) rootFolder(_ context.Context) (object.Reference, error) { 261 return object.NewRootFolder(f.client), nil 262 } 263 264 func (f *Finder) managedObjectList(ctx context.Context, path string, tl bool, include []string) ([]list.Element, error) { 265 fn := f.rootFolder 266 267 if f.dc != nil { 268 fn = f.dcReference 269 } 270 271 if path == "" { 272 path = "." 273 } 274 275 s := &spec{ 276 Relative: fn, 277 Parents: []string{"ComputeResource", "ClusterComputeResource", "HostSystem", "VirtualApp", "StoragePod"}, 278 Include: include, 279 } 280 281 if tl { 282 s.Contents = true 283 s.ListMode = types.NewBool(true) 284 } 285 286 return f.find(ctx, path, s) 287 } 288 289 // Element is deprecated, use InventoryPath() instead. 290 func (f *Finder) Element(ctx context.Context, ref types.ManagedObjectReference) (*list.Element, error) { 291 rl := func(_ context.Context) (object.Reference, error) { 292 return ref, nil 293 } 294 295 s := &spec{ 296 Relative: rl, 297 } 298 299 e, err := f.find(ctx, "./", s) 300 if err != nil { 301 return nil, err 302 } 303 304 if len(e) == 0 { 305 return nil, &NotFoundError{ref.Type, ref.Value} 306 } 307 308 if len(e) > 1 { 309 panic("ManagedObjectReference must be unique") 310 } 311 312 return &e[0], nil 313 } 314 315 // ObjectReference converts the given ManagedObjectReference to a type from the object package via object.NewReference 316 // with the object.Common.InventoryPath field set. 317 func (f *Finder) ObjectReference(ctx context.Context, ref types.ManagedObjectReference) (object.Reference, error) { 318 path, err := InventoryPath(ctx, f.client, ref) 319 if err != nil { 320 return nil, err 321 } 322 323 r := object.NewReference(f.client, ref) 324 325 type common interface { 326 SetInventoryPath(string) 327 } 328 329 r.(common).SetInventoryPath(path) 330 331 if f.dc != nil { 332 if ds, ok := r.(*object.Datastore); ok { 333 ds.DatacenterPath = f.dc.InventoryPath 334 } 335 } 336 337 return r, nil 338 } 339 340 func (f *Finder) ManagedObjectList(ctx context.Context, path string, include ...string) ([]list.Element, error) { 341 return f.managedObjectList(ctx, path, false, include) 342 } 343 344 func (f *Finder) ManagedObjectListChildren(ctx context.Context, path string, include ...string) ([]list.Element, error) { 345 return f.managedObjectList(ctx, path, true, include) 346 } 347 348 func (f *Finder) DatacenterList(ctx context.Context, path string) ([]*object.Datacenter, error) { 349 s := &spec{ 350 Relative: f.rootFolder, 351 Include: []string{"Datacenter"}, 352 } 353 354 es, err := f.find(ctx, path, s) 355 if err != nil { 356 return nil, err 357 } 358 359 var dcs []*object.Datacenter 360 for _, e := range es { 361 ref := e.Object.Reference() 362 if ref.Type == "Datacenter" { 363 dc := object.NewDatacenter(f.client, ref) 364 dc.InventoryPath = e.Path 365 dcs = append(dcs, dc) 366 } 367 } 368 369 if len(dcs) == 0 { 370 return nil, &NotFoundError{"datacenter", path} 371 } 372 373 return dcs, nil 374 } 375 376 func (f *Finder) Datacenter(ctx context.Context, path string) (*object.Datacenter, error) { 377 dcs, err := f.DatacenterList(ctx, path) 378 if err != nil { 379 return nil, err 380 } 381 382 if len(dcs) > 1 { 383 return nil, &MultipleFoundError{"datacenter", path} 384 } 385 386 return dcs[0], nil 387 } 388 389 func (f *Finder) DefaultDatacenter(ctx context.Context) (*object.Datacenter, error) { 390 dc, err := f.Datacenter(ctx, "*") 391 if err != nil { 392 return nil, toDefaultError(err) 393 } 394 395 return dc, nil 396 } 397 398 func (f *Finder) DatacenterOrDefault(ctx context.Context, path string) (*object.Datacenter, error) { 399 if path != "" { 400 dc, err := f.Datacenter(ctx, path) 401 if err != nil { 402 return nil, err 403 } 404 return dc, nil 405 } 406 407 return f.DefaultDatacenter(ctx) 408 } 409 410 func (f *Finder) DatastoreList(ctx context.Context, path string) ([]*object.Datastore, error) { 411 s := &spec{ 412 Relative: f.datastoreFolder, 413 Parents: []string{"StoragePod"}, 414 } 415 416 es, err := f.find(ctx, path, s) 417 if err != nil { 418 return nil, err 419 } 420 421 var dss []*object.Datastore 422 for _, e := range es { 423 ref := e.Object.Reference() 424 if ref.Type == "Datastore" { 425 ds := object.NewDatastore(f.client, ref) 426 ds.InventoryPath = e.Path 427 428 if f.dc == nil { 429 // In this case SetDatacenter was not called and path is absolute 430 ds.DatacenterPath, err = f.datacenterPath(ctx, ref) 431 if err != nil { 432 return nil, err 433 } 434 } else { 435 ds.DatacenterPath = f.dc.InventoryPath 436 } 437 438 dss = append(dss, ds) 439 } 440 } 441 442 if len(dss) == 0 { 443 return nil, &NotFoundError{"datastore", path} 444 } 445 446 return dss, nil 447 } 448 449 func (f *Finder) Datastore(ctx context.Context, path string) (*object.Datastore, error) { 450 dss, err := f.DatastoreList(ctx, path) 451 if err != nil { 452 return nil, err 453 } 454 455 if len(dss) > 1 { 456 return nil, &MultipleFoundError{"datastore", path} 457 } 458 459 return dss[0], nil 460 } 461 462 func (f *Finder) DefaultDatastore(ctx context.Context) (*object.Datastore, error) { 463 ds, err := f.Datastore(ctx, "*") 464 if err != nil { 465 return nil, toDefaultError(err) 466 } 467 468 return ds, nil 469 } 470 471 func (f *Finder) DatastoreOrDefault(ctx context.Context, path string) (*object.Datastore, error) { 472 if path != "" { 473 ds, err := f.Datastore(ctx, path) 474 if err != nil { 475 return nil, err 476 } 477 return ds, nil 478 } 479 480 return f.DefaultDatastore(ctx) 481 } 482 483 func (f *Finder) DatastoreClusterList(ctx context.Context, path string) ([]*object.StoragePod, error) { 484 s := &spec{ 485 Relative: f.datastoreFolder, 486 } 487 488 es, err := f.find(ctx, path, s) 489 if err != nil { 490 return nil, err 491 } 492 493 var sps []*object.StoragePod 494 for _, e := range es { 495 ref := e.Object.Reference() 496 if ref.Type == "StoragePod" { 497 sp := object.NewStoragePod(f.client, ref) 498 sp.InventoryPath = e.Path 499 sps = append(sps, sp) 500 } 501 } 502 503 if len(sps) == 0 { 504 return nil, &NotFoundError{"datastore cluster", path} 505 } 506 507 return sps, nil 508 } 509 510 func (f *Finder) DatastoreCluster(ctx context.Context, path string) (*object.StoragePod, error) { 511 sps, err := f.DatastoreClusterList(ctx, path) 512 if err != nil { 513 return nil, err 514 } 515 516 if len(sps) > 1 { 517 return nil, &MultipleFoundError{"datastore cluster", path} 518 } 519 520 return sps[0], nil 521 } 522 523 func (f *Finder) DefaultDatastoreCluster(ctx context.Context) (*object.StoragePod, error) { 524 sp, err := f.DatastoreCluster(ctx, "*") 525 if err != nil { 526 return nil, toDefaultError(err) 527 } 528 529 return sp, nil 530 } 531 532 func (f *Finder) DatastoreClusterOrDefault(ctx context.Context, path string) (*object.StoragePod, error) { 533 if path != "" { 534 sp, err := f.DatastoreCluster(ctx, path) 535 if err != nil { 536 return nil, err 537 } 538 return sp, nil 539 } 540 541 return f.DefaultDatastoreCluster(ctx) 542 } 543 544 func (f *Finder) ComputeResourceList(ctx context.Context, path string) ([]*object.ComputeResource, error) { 545 s := &spec{ 546 Relative: f.hostFolder, 547 } 548 549 es, err := f.find(ctx, path, s) 550 if err != nil { 551 return nil, err 552 } 553 554 var crs []*object.ComputeResource 555 for _, e := range es { 556 var cr *object.ComputeResource 557 558 switch o := e.Object.(type) { 559 case mo.ComputeResource, mo.ClusterComputeResource: 560 cr = object.NewComputeResource(f.client, o.Reference()) 561 default: 562 continue 563 } 564 565 cr.InventoryPath = e.Path 566 crs = append(crs, cr) 567 } 568 569 if len(crs) == 0 { 570 return nil, &NotFoundError{"compute resource", path} 571 } 572 573 return crs, nil 574 } 575 576 func (f *Finder) ComputeResource(ctx context.Context, path string) (*object.ComputeResource, error) { 577 crs, err := f.ComputeResourceList(ctx, path) 578 if err != nil { 579 return nil, err 580 } 581 582 if len(crs) > 1 { 583 return nil, &MultipleFoundError{"compute resource", path} 584 } 585 586 return crs[0], nil 587 } 588 589 func (f *Finder) DefaultComputeResource(ctx context.Context) (*object.ComputeResource, error) { 590 cr, err := f.ComputeResource(ctx, "*") 591 if err != nil { 592 return nil, toDefaultError(err) 593 } 594 595 return cr, nil 596 } 597 598 func (f *Finder) ComputeResourceOrDefault(ctx context.Context, path string) (*object.ComputeResource, error) { 599 if path != "" { 600 cr, err := f.ComputeResource(ctx, path) 601 if err != nil { 602 return nil, err 603 } 604 return cr, nil 605 } 606 607 return f.DefaultComputeResource(ctx) 608 } 609 610 func (f *Finder) ClusterComputeResourceList(ctx context.Context, path string) ([]*object.ClusterComputeResource, error) { 611 s := &spec{ 612 Relative: f.hostFolder, 613 } 614 615 es, err := f.find(ctx, path, s) 616 if err != nil { 617 return nil, err 618 } 619 620 var ccrs []*object.ClusterComputeResource 621 for _, e := range es { 622 var ccr *object.ClusterComputeResource 623 624 switch o := e.Object.(type) { 625 case mo.ClusterComputeResource: 626 ccr = object.NewClusterComputeResource(f.client, o.Reference()) 627 default: 628 continue 629 } 630 631 ccr.InventoryPath = e.Path 632 ccrs = append(ccrs, ccr) 633 } 634 635 if len(ccrs) == 0 { 636 return nil, &NotFoundError{"cluster", path} 637 } 638 639 return ccrs, nil 640 } 641 642 func (f *Finder) DefaultClusterComputeResource(ctx context.Context) (*object.ClusterComputeResource, error) { 643 cr, err := f.ClusterComputeResource(ctx, "*") 644 if err != nil { 645 return nil, toDefaultError(err) 646 } 647 648 return cr, nil 649 } 650 651 func (f *Finder) ClusterComputeResource(ctx context.Context, path string) (*object.ClusterComputeResource, error) { 652 ccrs, err := f.ClusterComputeResourceList(ctx, path) 653 if err != nil { 654 return nil, err 655 } 656 657 if len(ccrs) > 1 { 658 return nil, &MultipleFoundError{"cluster", path} 659 } 660 661 return ccrs[0], nil 662 } 663 664 func (f *Finder) ClusterComputeResourceOrDefault(ctx context.Context, path string) (*object.ClusterComputeResource, error) { 665 if path != "" { 666 cr, err := f.ClusterComputeResource(ctx, path) 667 if err != nil { 668 return nil, err 669 } 670 return cr, nil 671 } 672 673 return f.DefaultClusterComputeResource(ctx) 674 } 675 676 func (f *Finder) HostSystemList(ctx context.Context, path string) ([]*object.HostSystem, error) { 677 s := &spec{ 678 Relative: f.hostFolder, 679 Parents: []string{"ComputeResource", "ClusterComputeResource"}, 680 Include: []string{"HostSystem"}, 681 } 682 683 es, err := f.find(ctx, path, s) 684 if err != nil { 685 return nil, err 686 } 687 688 var hss []*object.HostSystem 689 for _, e := range es { 690 var hs *object.HostSystem 691 692 switch o := e.Object.(type) { 693 case mo.HostSystem: 694 hs = object.NewHostSystem(f.client, o.Reference()) 695 696 hs.InventoryPath = e.Path 697 hss = append(hss, hs) 698 case mo.ComputeResource, mo.ClusterComputeResource: 699 cr := object.NewComputeResource(f.client, o.Reference()) 700 701 cr.InventoryPath = e.Path 702 703 hosts, err := cr.Hosts(ctx) 704 if err != nil { 705 return nil, err 706 } 707 708 hss = append(hss, hosts...) 709 } 710 } 711 712 if len(hss) == 0 { 713 return nil, &NotFoundError{"host", path} 714 } 715 716 return hss, nil 717 } 718 719 func (f *Finder) HostSystem(ctx context.Context, path string) (*object.HostSystem, error) { 720 hss, err := f.HostSystemList(ctx, path) 721 if err != nil { 722 return nil, err 723 } 724 725 if len(hss) > 1 { 726 return nil, &MultipleFoundError{"host", path} 727 } 728 729 return hss[0], nil 730 } 731 732 func (f *Finder) DefaultHostSystem(ctx context.Context) (*object.HostSystem, error) { 733 hs, err := f.HostSystem(ctx, "*") 734 if err != nil { 735 return nil, toDefaultError(err) 736 } 737 738 return hs, nil 739 } 740 741 func (f *Finder) HostSystemOrDefault(ctx context.Context, path string) (*object.HostSystem, error) { 742 if path != "" { 743 hs, err := f.HostSystem(ctx, path) 744 if err != nil { 745 return nil, err 746 } 747 return hs, nil 748 } 749 750 return f.DefaultHostSystem(ctx) 751 } 752 753 func (f *Finder) NetworkList(ctx context.Context, path string) ([]object.NetworkReference, error) { 754 s := &spec{ 755 Relative: f.networkFolder, 756 } 757 758 es, err := f.find(ctx, path, s) 759 if err != nil { 760 return nil, err 761 } 762 763 var ns []object.NetworkReference 764 for _, e := range es { 765 ref := e.Object.Reference() 766 switch ref.Type { 767 case "Network": 768 r := object.NewNetwork(f.client, ref) 769 r.InventoryPath = e.Path 770 ns = append(ns, r) 771 case "OpaqueNetwork": 772 r := object.NewOpaqueNetwork(f.client, ref) 773 r.InventoryPath = e.Path 774 ns = append(ns, r) 775 case "DistributedVirtualPortgroup": 776 r := object.NewDistributedVirtualPortgroup(f.client, ref) 777 r.InventoryPath = e.Path 778 ns = append(ns, r) 779 case "DistributedVirtualSwitch", "VmwareDistributedVirtualSwitch": 780 r := object.NewDistributedVirtualSwitch(f.client, ref) 781 r.InventoryPath = e.Path 782 ns = append(ns, r) 783 } 784 } 785 786 if len(ns) == 0 { 787 net, nerr := f.networkByID(ctx, path) 788 if nerr == nil { 789 return []object.NetworkReference{net}, nil 790 } 791 792 return nil, &NotFoundError{"network", path} 793 } 794 795 return ns, nil 796 } 797 798 // Network finds a NetworkReference using a Name, Inventory Path, ManagedObject ID, Logical Switch UUID or Segment ID. 799 // With standard vSphere networking, Portgroups cannot have the same name within the same network folder. 800 // With NSX, Portgroups can have the same name, even within the same Switch. In this case, using an inventory path 801 // results in a MultipleFoundError. A MOID, switch UUID or segment ID can be used instead, as both are unique. 802 // See also: https://kb.vmware.com/s/article/79872#Duplicate_names 803 // Examples: 804 // - Name: "dvpg-1" 805 // - Inventory Path: "vds-1/dvpg-1" 806 // - Cluster Path: "/dc-1/host/cluster-1/dvpg-1" 807 // - ManagedObject ID: "DistributedVirtualPortgroup:dvportgroup-53" 808 // - Logical Switch UUID: "da2a59b8-2450-4cb2-b5cc-79c4c1d2144c" 809 // - Segment ID: "/infra/segments/vnet_ce50e69b-1784-4a14-9206-ffd7f1f146f7" 810 func (f *Finder) Network(ctx context.Context, path string) (object.NetworkReference, error) { 811 networks, err := f.NetworkList(ctx, path) 812 if err != nil { 813 return nil, err 814 } 815 816 if len(networks) > 1 { 817 return nil, &MultipleFoundError{"network", path} 818 } 819 820 return networks[0], nil 821 } 822 823 func (f *Finder) networkByID(ctx context.Context, path string) (object.NetworkReference, error) { 824 if ref := object.ReferenceFromString(path); ref != nil { 825 // This is a MOID 826 return object.NewReference(f.client, *ref).(object.NetworkReference), nil 827 } 828 829 kind := []string{"DistributedVirtualPortgroup"} 830 831 m := view.NewManager(f.client) 832 v, err := m.CreateContainerView(ctx, f.client.ServiceContent.RootFolder, kind, true) 833 if err != nil { 834 return nil, err 835 } 836 defer v.Destroy(ctx) 837 838 filter := property.Match{ 839 "config.logicalSwitchUuid": path, 840 "config.segmentId": path, 841 } 842 843 refs, err := v.FindAny(ctx, kind, filter) 844 if err != nil { 845 return nil, err 846 } 847 848 if len(refs) == 0 { 849 return nil, &NotFoundError{"network", path} 850 } 851 if len(refs) > 1 { 852 return nil, &MultipleFoundError{"network", path} 853 } 854 855 return object.NewReference(f.client, refs[0]).(object.NetworkReference), nil 856 } 857 858 func (f *Finder) DefaultNetwork(ctx context.Context) (object.NetworkReference, error) { 859 network, err := f.Network(ctx, "*") 860 if err != nil { 861 return nil, toDefaultError(err) 862 } 863 864 return network, nil 865 } 866 867 func (f *Finder) NetworkOrDefault(ctx context.Context, path string) (object.NetworkReference, error) { 868 if path != "" { 869 network, err := f.Network(ctx, path) 870 if err != nil { 871 return nil, err 872 } 873 return network, nil 874 } 875 876 return f.DefaultNetwork(ctx) 877 } 878 879 func (f *Finder) ResourcePoolList(ctx context.Context, path string) ([]*object.ResourcePool, error) { 880 s := &spec{ 881 Relative: f.hostFolder, 882 Parents: []string{"ComputeResource", "ClusterComputeResource", "VirtualApp"}, 883 Nested: []string{"ResourcePool"}, 884 Contents: true, 885 } 886 887 es, err := f.find(ctx, path, s) 888 if err != nil { 889 return nil, err 890 } 891 892 var rps []*object.ResourcePool 893 for _, e := range es { 894 var rp *object.ResourcePool 895 896 switch o := e.Object.(type) { 897 case mo.ResourcePool: 898 rp = object.NewResourcePool(f.client, o.Reference()) 899 rp.InventoryPath = e.Path 900 rps = append(rps, rp) 901 } 902 } 903 904 if len(rps) == 0 { 905 return nil, &NotFoundError{"resource pool", path} 906 } 907 908 return rps, nil 909 } 910 911 func (f *Finder) ResourcePool(ctx context.Context, path string) (*object.ResourcePool, error) { 912 rps, err := f.ResourcePoolList(ctx, path) 913 if err != nil { 914 return nil, err 915 } 916 917 if len(rps) > 1 { 918 return nil, &MultipleFoundError{"resource pool", path} 919 } 920 921 return rps[0], nil 922 } 923 924 func (f *Finder) DefaultResourcePool(ctx context.Context) (*object.ResourcePool, error) { 925 rp, err := f.ResourcePool(ctx, "*/Resources") 926 if err != nil { 927 return nil, toDefaultError(err) 928 } 929 930 return rp, nil 931 } 932 933 func (f *Finder) ResourcePoolOrDefault(ctx context.Context, path string) (*object.ResourcePool, error) { 934 if path != "" { 935 rp, err := f.ResourcePool(ctx, path) 936 if err != nil { 937 return nil, err 938 } 939 return rp, nil 940 } 941 942 return f.DefaultResourcePool(ctx) 943 } 944 945 // ResourcePoolListAll combines ResourcePoolList and VirtualAppList 946 // VirtualAppList is only called if ResourcePoolList does not find any pools with the given path. 947 func (f *Finder) ResourcePoolListAll(ctx context.Context, path string) ([]*object.ResourcePool, error) { 948 pools, err := f.ResourcePoolList(ctx, path) 949 if err != nil { 950 if _, ok := err.(*NotFoundError); !ok { 951 return nil, err 952 } 953 954 vapps, _ := f.VirtualAppList(ctx, path) 955 956 if len(vapps) == 0 { 957 return nil, err 958 } 959 960 for _, vapp := range vapps { 961 pools = append(pools, vapp.ResourcePool) 962 } 963 } 964 965 return pools, nil 966 } 967 968 func (f *Finder) DefaultFolder(ctx context.Context) (*object.Folder, error) { 969 ref, err := f.vmFolder(ctx) 970 if err != nil { 971 return nil, toDefaultError(err) 972 } 973 folder := object.NewFolder(f.client, ref.Reference()) 974 975 // Set the InventoryPath of the newly created folder object 976 // The default foler becomes the datacenter's "vm" folder. 977 // The "vm" folder always exists for a datacenter. It cannot be 978 // removed or replaced 979 folder.SetInventoryPath(path.Join(f.dc.InventoryPath, "vm")) 980 981 return folder, nil 982 } 983 984 func (f *Finder) FolderOrDefault(ctx context.Context, path string) (*object.Folder, error) { 985 if path != "" { 986 folder, err := f.Folder(ctx, path) 987 if err != nil { 988 return nil, err 989 } 990 return folder, nil 991 } 992 return f.DefaultFolder(ctx) 993 } 994 995 func (f *Finder) VirtualMachineList(ctx context.Context, path string) ([]*object.VirtualMachine, error) { 996 s := &spec{ 997 Relative: f.vmFolder, 998 Parents: []string{"VirtualApp"}, 999 } 1000 1001 es, err := f.find(ctx, path, s) 1002 if err != nil { 1003 return nil, err 1004 } 1005 1006 var vms []*object.VirtualMachine 1007 for _, e := range es { 1008 switch o := e.Object.(type) { 1009 case mo.VirtualMachine: 1010 vm := object.NewVirtualMachine(f.client, o.Reference()) 1011 vm.InventoryPath = e.Path 1012 vms = append(vms, vm) 1013 } 1014 } 1015 1016 if len(vms) == 0 { 1017 return nil, &NotFoundError{"vm", path} 1018 } 1019 1020 return vms, nil 1021 } 1022 1023 func (f *Finder) VirtualMachine(ctx context.Context, path string) (*object.VirtualMachine, error) { 1024 vms, err := f.VirtualMachineList(ctx, path) 1025 if err != nil { 1026 return nil, err 1027 } 1028 1029 if len(vms) > 1 { 1030 return nil, &MultipleFoundError{"vm", path} 1031 } 1032 1033 return vms[0], nil 1034 } 1035 1036 func (f *Finder) VirtualAppList(ctx context.Context, path string) ([]*object.VirtualApp, error) { 1037 s := &spec{ 1038 Relative: f.vmFolder, 1039 } 1040 1041 es, err := f.find(ctx, path, s) 1042 if err != nil { 1043 return nil, err 1044 } 1045 1046 var apps []*object.VirtualApp 1047 for _, e := range es { 1048 switch o := e.Object.(type) { 1049 case mo.VirtualApp: 1050 app := object.NewVirtualApp(f.client, o.Reference()) 1051 app.InventoryPath = e.Path 1052 apps = append(apps, app) 1053 } 1054 } 1055 1056 if len(apps) == 0 { 1057 return nil, &NotFoundError{"app", path} 1058 } 1059 1060 return apps, nil 1061 } 1062 1063 func (f *Finder) VirtualApp(ctx context.Context, path string) (*object.VirtualApp, error) { 1064 apps, err := f.VirtualAppList(ctx, path) 1065 if err != nil { 1066 return nil, err 1067 } 1068 1069 if len(apps) > 1 { 1070 return nil, &MultipleFoundError{"app", path} 1071 } 1072 1073 return apps[0], nil 1074 } 1075 1076 func (f *Finder) FolderList(ctx context.Context, path string) ([]*object.Folder, error) { 1077 es, err := f.ManagedObjectList(ctx, path) 1078 if err != nil { 1079 return nil, err 1080 } 1081 1082 var folders []*object.Folder 1083 1084 for _, e := range es { 1085 switch o := e.Object.(type) { 1086 case mo.Folder, mo.StoragePod: 1087 folder := object.NewFolder(f.client, o.Reference()) 1088 folder.InventoryPath = e.Path 1089 folders = append(folders, folder) 1090 case *object.Folder: 1091 // RootFolder 1092 folders = append(folders, o) 1093 } 1094 } 1095 1096 if len(folders) == 0 { 1097 return nil, &NotFoundError{"folder", path} 1098 } 1099 1100 return folders, nil 1101 } 1102 1103 func (f *Finder) Folder(ctx context.Context, path string) (*object.Folder, error) { 1104 folders, err := f.FolderList(ctx, path) 1105 if err != nil { 1106 return nil, err 1107 } 1108 1109 if len(folders) > 1 { 1110 return nil, &MultipleFoundError{"folder", path} 1111 } 1112 1113 return folders[0], nil 1114 }