138 lines
3.5 KiB
Go
138 lines
3.5 KiB
Go
/*
|
|
Copyright (c) 2015 VMware, Inc. All Rights Reserved.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package mo
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/vmware/govmomi/vim25/soap"
|
|
"github.com/vmware/govmomi/vim25/types"
|
|
)
|
|
|
|
// Ancestors returns the entire ancestry tree of a specified managed object.
|
|
// The return value includes the root node and the specified object itself.
|
|
func Ancestors(ctx context.Context, rt soap.RoundTripper, pc, obj types.ManagedObjectReference) ([]ManagedEntity, error) {
|
|
ospec := types.ObjectSpec{
|
|
Obj: obj,
|
|
SelectSet: []types.BaseSelectionSpec{
|
|
&types.TraversalSpec{
|
|
SelectionSpec: types.SelectionSpec{Name: "traverseParent"},
|
|
Type: "ManagedEntity",
|
|
Path: "parent",
|
|
Skip: types.NewBool(false),
|
|
SelectSet: []types.BaseSelectionSpec{
|
|
&types.SelectionSpec{Name: "traverseParent"},
|
|
},
|
|
},
|
|
&types.TraversalSpec{
|
|
SelectionSpec: types.SelectionSpec{},
|
|
Type: "VirtualMachine",
|
|
Path: "parentVApp",
|
|
Skip: types.NewBool(false),
|
|
SelectSet: []types.BaseSelectionSpec{
|
|
&types.SelectionSpec{Name: "traverseParent"},
|
|
},
|
|
},
|
|
},
|
|
Skip: types.NewBool(false),
|
|
}
|
|
|
|
pspec := []types.PropertySpec{
|
|
{
|
|
Type: "ManagedEntity",
|
|
PathSet: []string{"name", "parent"},
|
|
},
|
|
{
|
|
Type: "VirtualMachine",
|
|
PathSet: []string{"parentVApp"},
|
|
},
|
|
}
|
|
|
|
req := types.RetrieveProperties{
|
|
This: pc,
|
|
SpecSet: []types.PropertyFilterSpec{
|
|
{
|
|
ObjectSet: []types.ObjectSpec{ospec},
|
|
PropSet: pspec,
|
|
},
|
|
},
|
|
}
|
|
|
|
var ifaces []interface{}
|
|
err := RetrievePropertiesForRequest(ctx, rt, req, &ifaces)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var out []ManagedEntity
|
|
|
|
// Build ancestry tree by iteratively finding a new child.
|
|
for len(out) < len(ifaces) {
|
|
var find types.ManagedObjectReference
|
|
|
|
if len(out) > 0 {
|
|
find = out[len(out)-1].Self
|
|
}
|
|
|
|
// Find entity we're looking for given the last entity in the current tree.
|
|
for _, iface := range ifaces {
|
|
me := iface.(IsManagedEntity).GetManagedEntity()
|
|
|
|
if me.Name == "" {
|
|
// The types below have their own 'Name' field, so ManagedEntity.Name (me.Name) is empty.
|
|
// We only hit this case when the 'obj' param is one of these types.
|
|
// In most cases, 'obj' is a Folder so Name isn't collected in this call.
|
|
switch x := iface.(type) {
|
|
case Network:
|
|
me.Name = x.Name
|
|
case DistributedVirtualSwitch:
|
|
me.Name = x.Name
|
|
case DistributedVirtualPortgroup:
|
|
me.Name = x.Name
|
|
case OpaqueNetwork:
|
|
me.Name = x.Name
|
|
default:
|
|
// ManagedEntity always has a Name, if we hit this point we missed a case above.
|
|
panic(fmt.Sprintf("%#v Name is empty", me.Reference()))
|
|
}
|
|
}
|
|
|
|
if me.Parent == nil {
|
|
// Special case for VirtualMachine within VirtualApp,
|
|
// unlikely to hit this other than via Finder.Element()
|
|
switch x := iface.(type) {
|
|
case VirtualMachine:
|
|
me.Parent = x.ParentVApp
|
|
}
|
|
}
|
|
|
|
if me.Parent == nil {
|
|
out = append(out, me)
|
|
break
|
|
}
|
|
|
|
if *me.Parent == find {
|
|
out = append(out, me)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
return out, nil
|
|
}
|