github.com/vmware/govmomi@v0.51.0/vim25/mo/ancestors.go (about) 1 // © Broadcom. All Rights Reserved. 2 // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 3 // SPDX-License-Identifier: Apache-2.0 4 5 package mo 6 7 import ( 8 "context" 9 "fmt" 10 11 "github.com/vmware/govmomi/vim25/soap" 12 "github.com/vmware/govmomi/vim25/types" 13 ) 14 15 // Ancestors returns the entire ancestry tree of a specified managed object. 16 // The return value includes the root node and the specified object itself. 17 func Ancestors(ctx context.Context, rt soap.RoundTripper, pc, obj types.ManagedObjectReference) ([]ManagedEntity, error) { 18 ospec := types.ObjectSpec{ 19 Obj: obj, 20 SelectSet: []types.BaseSelectionSpec{ 21 &types.TraversalSpec{ 22 SelectionSpec: types.SelectionSpec{Name: "traverseParent"}, 23 Type: "ManagedEntity", 24 Path: "parent", 25 Skip: types.NewBool(false), 26 SelectSet: []types.BaseSelectionSpec{ 27 &types.SelectionSpec{Name: "traverseParent"}, 28 }, 29 }, 30 &types.TraversalSpec{ 31 SelectionSpec: types.SelectionSpec{}, 32 Type: "VirtualMachine", 33 Path: "parentVApp", 34 Skip: types.NewBool(false), 35 SelectSet: []types.BaseSelectionSpec{ 36 &types.SelectionSpec{Name: "traverseParent"}, 37 }, 38 }, 39 }, 40 Skip: types.NewBool(false), 41 } 42 43 pspec := []types.PropertySpec{ 44 { 45 Type: "ManagedEntity", 46 PathSet: []string{"name", "parent"}, 47 }, 48 { 49 Type: "VirtualMachine", 50 PathSet: []string{"parentVApp"}, 51 }, 52 } 53 54 req := types.RetrieveProperties{ 55 This: pc, 56 SpecSet: []types.PropertyFilterSpec{ 57 { 58 ObjectSet: []types.ObjectSpec{ospec}, 59 PropSet: pspec, 60 }, 61 }, 62 } 63 64 var ifaces []any 65 err := RetrievePropertiesForRequest(ctx, rt, req, &ifaces) 66 if err != nil { 67 return nil, err 68 } 69 70 var out []ManagedEntity 71 72 // Build ancestry tree by iteratively finding a new child. 73 for len(out) < len(ifaces) { 74 var find types.ManagedObjectReference 75 76 if len(out) > 0 { 77 find = out[len(out)-1].Self 78 } 79 80 // Find entity we're looking for given the last entity in the current tree. 81 for _, iface := range ifaces { 82 me := iface.(IsManagedEntity).GetManagedEntity() 83 84 if me.Name == "" { 85 // The types below have their own 'Name' field, so ManagedEntity.Name (me.Name) is empty. 86 // We only hit this case when the 'obj' param is one of these types. 87 // In most cases, 'obj' is a Folder so Name isn't collected in this call. 88 switch x := iface.(type) { 89 case Network: 90 me.Name = x.Name 91 case DistributedVirtualSwitch: 92 me.Name = x.Name 93 case DistributedVirtualPortgroup: 94 me.Name = x.Name 95 case OpaqueNetwork: 96 me.Name = x.Name 97 default: 98 // ManagedEntity always has a Name, if we hit this point we missed a case above. 99 panic(fmt.Sprintf("%#v Name is empty", me.Reference())) 100 } 101 } 102 103 if me.Parent == nil { 104 // Special case for VirtualMachine within VirtualApp, 105 // unlikely to hit this other than via Finder.Element() 106 switch x := iface.(type) { 107 case VirtualMachine: 108 me.Parent = x.ParentVApp 109 } 110 } 111 112 if me.Parent == nil { 113 out = append(out, me) 114 break 115 } 116 117 if *me.Parent == find { 118 out = append(out, me) 119 break 120 } 121 } 122 } 123 124 return out, nil 125 }