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  }