In addition, simplify the SPEC file to not have to update the minimum required osbuild version gazillion times, but just once. Update the minimum required osbuild version to v109, due to changes in grub2 stages required by the new osbuild/images version. Update osbild SHA in Schutzfile to v109. Signed-off-by: Tomáš Hozza <thozza@redhat.com>
1114 lines
25 KiB
Go
1114 lines
25 KiB
Go
/*
|
|
Copyright (c) 2014-2023 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 find
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"path"
|
|
"strings"
|
|
|
|
"github.com/vmware/govmomi/internal"
|
|
"github.com/vmware/govmomi/list"
|
|
"github.com/vmware/govmomi/object"
|
|
"github.com/vmware/govmomi/property"
|
|
"github.com/vmware/govmomi/view"
|
|
"github.com/vmware/govmomi/vim25"
|
|
"github.com/vmware/govmomi/vim25/mo"
|
|
"github.com/vmware/govmomi/vim25/types"
|
|
)
|
|
|
|
type Finder struct {
|
|
client *vim25.Client
|
|
r recurser
|
|
dc *object.Datacenter
|
|
si *object.SearchIndex
|
|
folders *object.DatacenterFolders
|
|
}
|
|
|
|
func NewFinder(client *vim25.Client, all ...bool) *Finder {
|
|
props := false
|
|
if len(all) == 1 {
|
|
props = all[0]
|
|
}
|
|
|
|
f := &Finder{
|
|
client: client,
|
|
si: object.NewSearchIndex(client),
|
|
r: recurser{
|
|
Collector: property.DefaultCollector(client),
|
|
All: props,
|
|
},
|
|
}
|
|
|
|
if len(all) == 0 {
|
|
// attempt to avoid SetDatacenter() requirement
|
|
f.dc, _ = f.DefaultDatacenter(context.Background())
|
|
}
|
|
|
|
return f
|
|
}
|
|
|
|
func (f *Finder) SetDatacenter(dc *object.Datacenter) *Finder {
|
|
f.dc = dc
|
|
f.folders = nil
|
|
return f
|
|
}
|
|
|
|
// InventoryPath composes the given object's inventory path.
|
|
// There is no vSphere property or method that provides an inventory path directly.
|
|
// This method uses the ManagedEntity.Parent field to determine the ancestry tree of the object and
|
|
// the ManagedEntity.Name field for each ancestor to compose the path.
|
|
func InventoryPath(ctx context.Context, client *vim25.Client, obj types.ManagedObjectReference) (string, error) {
|
|
entities, err := mo.Ancestors(ctx, client, client.ServiceContent.PropertyCollector, obj)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return internal.InventoryPath(entities), nil
|
|
}
|
|
|
|
// findRoot makes it possible to use "find" mode with a different root path.
|
|
// Example: ResourcePoolList("/dc1/host/cluster1/...")
|
|
func (f *Finder) findRoot(ctx context.Context, root *list.Element, parts []string) bool {
|
|
if len(parts) == 0 {
|
|
return false
|
|
}
|
|
|
|
ix := len(parts) - 1
|
|
|
|
if parts[ix] != "..." {
|
|
return false
|
|
}
|
|
|
|
if ix == 0 {
|
|
return true // We already have the Object for root.Path
|
|
}
|
|
|
|
// Lookup the Object for the new root.Path
|
|
rootPath := path.Join(root.Path, path.Join(parts[:ix]...))
|
|
|
|
ref, err := f.si.FindByInventoryPath(ctx, rootPath)
|
|
if err != nil || ref == nil {
|
|
// If we get an error or fail to match, fall through to find() with the original root and path
|
|
return false
|
|
}
|
|
|
|
root.Path = rootPath
|
|
root.Object = ref
|
|
|
|
return true
|
|
}
|
|
|
|
func (f *Finder) find(ctx context.Context, arg string, s *spec) ([]list.Element, error) {
|
|
isPath := strings.Contains(arg, "/")
|
|
|
|
root := list.Element{
|
|
Object: object.NewRootFolder(f.client),
|
|
Path: "/",
|
|
}
|
|
|
|
parts := list.ToParts(arg)
|
|
|
|
if len(parts) > 0 {
|
|
switch parts[0] {
|
|
case "..": // Not supported; many edge case, little value
|
|
return nil, errors.New("cannot traverse up a tree")
|
|
case ".": // Relative to whatever
|
|
pivot, err := s.Relative(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
root.Path, err = InventoryPath(ctx, f.client, pivot.Reference())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
root.Object = pivot
|
|
parts = parts[1:]
|
|
}
|
|
}
|
|
|
|
if s.listMode(isPath) {
|
|
if f.findRoot(ctx, &root, parts) {
|
|
parts = []string{"*"}
|
|
} else {
|
|
return f.r.List(ctx, s, root, parts)
|
|
}
|
|
}
|
|
|
|
s.Parents = append(s.Parents, s.Nested...)
|
|
|
|
return f.r.Find(ctx, s, root, parts)
|
|
}
|
|
|
|
func (f *Finder) datacenter() (*object.Datacenter, error) {
|
|
if f.dc == nil {
|
|
return nil, errors.New("please specify a datacenter")
|
|
}
|
|
|
|
return f.dc, nil
|
|
}
|
|
|
|
// datacenterPath returns the absolute path to the Datacenter containing the given ref
|
|
func (f *Finder) datacenterPath(ctx context.Context, ref types.ManagedObjectReference) (string, error) {
|
|
mes, err := mo.Ancestors(ctx, f.client, f.client.ServiceContent.PropertyCollector, ref)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Chop leaves under the Datacenter
|
|
for i := len(mes) - 1; i > 0; i-- {
|
|
if mes[i].Self.Type == "Datacenter" {
|
|
break
|
|
}
|
|
mes = mes[:i]
|
|
}
|
|
|
|
var p string
|
|
|
|
for _, me := range mes {
|
|
// Skip root entity in building inventory path.
|
|
if me.Parent == nil {
|
|
continue
|
|
}
|
|
|
|
p = p + "/" + me.Name
|
|
}
|
|
|
|
return p, nil
|
|
}
|
|
|
|
func (f *Finder) dcFolders(ctx context.Context) (*object.DatacenterFolders, error) {
|
|
if f.folders != nil {
|
|
return f.folders, nil
|
|
}
|
|
|
|
dc, err := f.datacenter()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
folders, err := dc.Folders(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
f.folders = folders
|
|
|
|
return f.folders, nil
|
|
}
|
|
|
|
func (f *Finder) dcReference(_ context.Context) (object.Reference, error) {
|
|
dc, err := f.datacenter()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return dc, nil
|
|
}
|
|
|
|
func (f *Finder) vmFolder(ctx context.Context) (object.Reference, error) {
|
|
folders, err := f.dcFolders(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return folders.VmFolder, nil
|
|
}
|
|
|
|
func (f *Finder) hostFolder(ctx context.Context) (object.Reference, error) {
|
|
folders, err := f.dcFolders(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return folders.HostFolder, nil
|
|
}
|
|
|
|
func (f *Finder) datastoreFolder(ctx context.Context) (object.Reference, error) {
|
|
folders, err := f.dcFolders(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return folders.DatastoreFolder, nil
|
|
}
|
|
|
|
func (f *Finder) networkFolder(ctx context.Context) (object.Reference, error) {
|
|
folders, err := f.dcFolders(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return folders.NetworkFolder, nil
|
|
}
|
|
|
|
func (f *Finder) rootFolder(_ context.Context) (object.Reference, error) {
|
|
return object.NewRootFolder(f.client), nil
|
|
}
|
|
|
|
func (f *Finder) managedObjectList(ctx context.Context, path string, tl bool, include []string) ([]list.Element, error) {
|
|
fn := f.rootFolder
|
|
|
|
if f.dc != nil {
|
|
fn = f.dcReference
|
|
}
|
|
|
|
if path == "" {
|
|
path = "."
|
|
}
|
|
|
|
s := &spec{
|
|
Relative: fn,
|
|
Parents: []string{"ComputeResource", "ClusterComputeResource", "HostSystem", "VirtualApp", "StoragePod"},
|
|
Include: include,
|
|
}
|
|
|
|
if tl {
|
|
s.Contents = true
|
|
s.ListMode = types.NewBool(true)
|
|
}
|
|
|
|
return f.find(ctx, path, s)
|
|
}
|
|
|
|
// Element is deprecated, use InventoryPath() instead.
|
|
func (f *Finder) Element(ctx context.Context, ref types.ManagedObjectReference) (*list.Element, error) {
|
|
rl := func(_ context.Context) (object.Reference, error) {
|
|
return ref, nil
|
|
}
|
|
|
|
s := &spec{
|
|
Relative: rl,
|
|
}
|
|
|
|
e, err := f.find(ctx, "./", s)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(e) == 0 {
|
|
return nil, &NotFoundError{ref.Type, ref.Value}
|
|
}
|
|
|
|
if len(e) > 1 {
|
|
panic("ManagedObjectReference must be unique")
|
|
}
|
|
|
|
return &e[0], nil
|
|
}
|
|
|
|
// ObjectReference converts the given ManagedObjectReference to a type from the object package via object.NewReference
|
|
// with the object.Common.InventoryPath field set.
|
|
func (f *Finder) ObjectReference(ctx context.Context, ref types.ManagedObjectReference) (object.Reference, error) {
|
|
path, err := InventoryPath(ctx, f.client, ref)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
r := object.NewReference(f.client, ref)
|
|
|
|
type common interface {
|
|
SetInventoryPath(string)
|
|
}
|
|
|
|
r.(common).SetInventoryPath(path)
|
|
|
|
if f.dc != nil {
|
|
if ds, ok := r.(*object.Datastore); ok {
|
|
ds.DatacenterPath = f.dc.InventoryPath
|
|
}
|
|
}
|
|
|
|
return r, nil
|
|
}
|
|
|
|
func (f *Finder) ManagedObjectList(ctx context.Context, path string, include ...string) ([]list.Element, error) {
|
|
return f.managedObjectList(ctx, path, false, include)
|
|
}
|
|
|
|
func (f *Finder) ManagedObjectListChildren(ctx context.Context, path string, include ...string) ([]list.Element, error) {
|
|
return f.managedObjectList(ctx, path, true, include)
|
|
}
|
|
|
|
func (f *Finder) DatacenterList(ctx context.Context, path string) ([]*object.Datacenter, error) {
|
|
s := &spec{
|
|
Relative: f.rootFolder,
|
|
Include: []string{"Datacenter"},
|
|
}
|
|
|
|
es, err := f.find(ctx, path, s)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var dcs []*object.Datacenter
|
|
for _, e := range es {
|
|
ref := e.Object.Reference()
|
|
if ref.Type == "Datacenter" {
|
|
dc := object.NewDatacenter(f.client, ref)
|
|
dc.InventoryPath = e.Path
|
|
dcs = append(dcs, dc)
|
|
}
|
|
}
|
|
|
|
if len(dcs) == 0 {
|
|
return nil, &NotFoundError{"datacenter", path}
|
|
}
|
|
|
|
return dcs, nil
|
|
}
|
|
|
|
func (f *Finder) Datacenter(ctx context.Context, path string) (*object.Datacenter, error) {
|
|
dcs, err := f.DatacenterList(ctx, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(dcs) > 1 {
|
|
return nil, &MultipleFoundError{"datacenter", path}
|
|
}
|
|
|
|
return dcs[0], nil
|
|
}
|
|
|
|
func (f *Finder) DefaultDatacenter(ctx context.Context) (*object.Datacenter, error) {
|
|
dc, err := f.Datacenter(ctx, "*")
|
|
if err != nil {
|
|
return nil, toDefaultError(err)
|
|
}
|
|
|
|
return dc, nil
|
|
}
|
|
|
|
func (f *Finder) DatacenterOrDefault(ctx context.Context, path string) (*object.Datacenter, error) {
|
|
if path != "" {
|
|
dc, err := f.Datacenter(ctx, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return dc, nil
|
|
}
|
|
|
|
return f.DefaultDatacenter(ctx)
|
|
}
|
|
|
|
func (f *Finder) DatastoreList(ctx context.Context, path string) ([]*object.Datastore, error) {
|
|
s := &spec{
|
|
Relative: f.datastoreFolder,
|
|
Parents: []string{"StoragePod"},
|
|
}
|
|
|
|
es, err := f.find(ctx, path, s)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var dss []*object.Datastore
|
|
for _, e := range es {
|
|
ref := e.Object.Reference()
|
|
if ref.Type == "Datastore" {
|
|
ds := object.NewDatastore(f.client, ref)
|
|
ds.InventoryPath = e.Path
|
|
|
|
if f.dc == nil {
|
|
// In this case SetDatacenter was not called and path is absolute
|
|
ds.DatacenterPath, err = f.datacenterPath(ctx, ref)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
} else {
|
|
ds.DatacenterPath = f.dc.InventoryPath
|
|
}
|
|
|
|
dss = append(dss, ds)
|
|
}
|
|
}
|
|
|
|
if len(dss) == 0 {
|
|
return nil, &NotFoundError{"datastore", path}
|
|
}
|
|
|
|
return dss, nil
|
|
}
|
|
|
|
func (f *Finder) Datastore(ctx context.Context, path string) (*object.Datastore, error) {
|
|
dss, err := f.DatastoreList(ctx, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(dss) > 1 {
|
|
return nil, &MultipleFoundError{"datastore", path}
|
|
}
|
|
|
|
return dss[0], nil
|
|
}
|
|
|
|
func (f *Finder) DefaultDatastore(ctx context.Context) (*object.Datastore, error) {
|
|
ds, err := f.Datastore(ctx, "*")
|
|
if err != nil {
|
|
return nil, toDefaultError(err)
|
|
}
|
|
|
|
return ds, nil
|
|
}
|
|
|
|
func (f *Finder) DatastoreOrDefault(ctx context.Context, path string) (*object.Datastore, error) {
|
|
if path != "" {
|
|
ds, err := f.Datastore(ctx, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return ds, nil
|
|
}
|
|
|
|
return f.DefaultDatastore(ctx)
|
|
}
|
|
|
|
func (f *Finder) DatastoreClusterList(ctx context.Context, path string) ([]*object.StoragePod, error) {
|
|
s := &spec{
|
|
Relative: f.datastoreFolder,
|
|
}
|
|
|
|
es, err := f.find(ctx, path, s)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var sps []*object.StoragePod
|
|
for _, e := range es {
|
|
ref := e.Object.Reference()
|
|
if ref.Type == "StoragePod" {
|
|
sp := object.NewStoragePod(f.client, ref)
|
|
sp.InventoryPath = e.Path
|
|
sps = append(sps, sp)
|
|
}
|
|
}
|
|
|
|
if len(sps) == 0 {
|
|
return nil, &NotFoundError{"datastore cluster", path}
|
|
}
|
|
|
|
return sps, nil
|
|
}
|
|
|
|
func (f *Finder) DatastoreCluster(ctx context.Context, path string) (*object.StoragePod, error) {
|
|
sps, err := f.DatastoreClusterList(ctx, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(sps) > 1 {
|
|
return nil, &MultipleFoundError{"datastore cluster", path}
|
|
}
|
|
|
|
return sps[0], nil
|
|
}
|
|
|
|
func (f *Finder) DefaultDatastoreCluster(ctx context.Context) (*object.StoragePod, error) {
|
|
sp, err := f.DatastoreCluster(ctx, "*")
|
|
if err != nil {
|
|
return nil, toDefaultError(err)
|
|
}
|
|
|
|
return sp, nil
|
|
}
|
|
|
|
func (f *Finder) DatastoreClusterOrDefault(ctx context.Context, path string) (*object.StoragePod, error) {
|
|
if path != "" {
|
|
sp, err := f.DatastoreCluster(ctx, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return sp, nil
|
|
}
|
|
|
|
return f.DefaultDatastoreCluster(ctx)
|
|
}
|
|
|
|
func (f *Finder) ComputeResourceList(ctx context.Context, path string) ([]*object.ComputeResource, error) {
|
|
s := &spec{
|
|
Relative: f.hostFolder,
|
|
}
|
|
|
|
es, err := f.find(ctx, path, s)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var crs []*object.ComputeResource
|
|
for _, e := range es {
|
|
var cr *object.ComputeResource
|
|
|
|
switch o := e.Object.(type) {
|
|
case mo.ComputeResource, mo.ClusterComputeResource:
|
|
cr = object.NewComputeResource(f.client, o.Reference())
|
|
default:
|
|
continue
|
|
}
|
|
|
|
cr.InventoryPath = e.Path
|
|
crs = append(crs, cr)
|
|
}
|
|
|
|
if len(crs) == 0 {
|
|
return nil, &NotFoundError{"compute resource", path}
|
|
}
|
|
|
|
return crs, nil
|
|
}
|
|
|
|
func (f *Finder) ComputeResource(ctx context.Context, path string) (*object.ComputeResource, error) {
|
|
crs, err := f.ComputeResourceList(ctx, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(crs) > 1 {
|
|
return nil, &MultipleFoundError{"compute resource", path}
|
|
}
|
|
|
|
return crs[0], nil
|
|
}
|
|
|
|
func (f *Finder) DefaultComputeResource(ctx context.Context) (*object.ComputeResource, error) {
|
|
cr, err := f.ComputeResource(ctx, "*")
|
|
if err != nil {
|
|
return nil, toDefaultError(err)
|
|
}
|
|
|
|
return cr, nil
|
|
}
|
|
|
|
func (f *Finder) ComputeResourceOrDefault(ctx context.Context, path string) (*object.ComputeResource, error) {
|
|
if path != "" {
|
|
cr, err := f.ComputeResource(ctx, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return cr, nil
|
|
}
|
|
|
|
return f.DefaultComputeResource(ctx)
|
|
}
|
|
|
|
func (f *Finder) ClusterComputeResourceList(ctx context.Context, path string) ([]*object.ClusterComputeResource, error) {
|
|
s := &spec{
|
|
Relative: f.hostFolder,
|
|
}
|
|
|
|
es, err := f.find(ctx, path, s)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var ccrs []*object.ClusterComputeResource
|
|
for _, e := range es {
|
|
var ccr *object.ClusterComputeResource
|
|
|
|
switch o := e.Object.(type) {
|
|
case mo.ClusterComputeResource:
|
|
ccr = object.NewClusterComputeResource(f.client, o.Reference())
|
|
default:
|
|
continue
|
|
}
|
|
|
|
ccr.InventoryPath = e.Path
|
|
ccrs = append(ccrs, ccr)
|
|
}
|
|
|
|
if len(ccrs) == 0 {
|
|
return nil, &NotFoundError{"cluster", path}
|
|
}
|
|
|
|
return ccrs, nil
|
|
}
|
|
|
|
func (f *Finder) DefaultClusterComputeResource(ctx context.Context) (*object.ClusterComputeResource, error) {
|
|
cr, err := f.ClusterComputeResource(ctx, "*")
|
|
if err != nil {
|
|
return nil, toDefaultError(err)
|
|
}
|
|
|
|
return cr, nil
|
|
}
|
|
|
|
func (f *Finder) ClusterComputeResource(ctx context.Context, path string) (*object.ClusterComputeResource, error) {
|
|
ccrs, err := f.ClusterComputeResourceList(ctx, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(ccrs) > 1 {
|
|
return nil, &MultipleFoundError{"cluster", path}
|
|
}
|
|
|
|
return ccrs[0], nil
|
|
}
|
|
|
|
func (f *Finder) ClusterComputeResourceOrDefault(ctx context.Context, path string) (*object.ClusterComputeResource, error) {
|
|
if path != "" {
|
|
cr, err := f.ClusterComputeResource(ctx, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return cr, nil
|
|
}
|
|
|
|
return f.DefaultClusterComputeResource(ctx)
|
|
}
|
|
|
|
func (f *Finder) HostSystemList(ctx context.Context, path string) ([]*object.HostSystem, error) {
|
|
s := &spec{
|
|
Relative: f.hostFolder,
|
|
Parents: []string{"ComputeResource", "ClusterComputeResource"},
|
|
Include: []string{"HostSystem"},
|
|
}
|
|
|
|
es, err := f.find(ctx, path, s)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var hss []*object.HostSystem
|
|
for _, e := range es {
|
|
var hs *object.HostSystem
|
|
|
|
switch o := e.Object.(type) {
|
|
case mo.HostSystem:
|
|
hs = object.NewHostSystem(f.client, o.Reference())
|
|
|
|
hs.InventoryPath = e.Path
|
|
hss = append(hss, hs)
|
|
case mo.ComputeResource, mo.ClusterComputeResource:
|
|
cr := object.NewComputeResource(f.client, o.Reference())
|
|
|
|
cr.InventoryPath = e.Path
|
|
|
|
hosts, err := cr.Hosts(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
hss = append(hss, hosts...)
|
|
}
|
|
}
|
|
|
|
if len(hss) == 0 {
|
|
return nil, &NotFoundError{"host", path}
|
|
}
|
|
|
|
return hss, nil
|
|
}
|
|
|
|
func (f *Finder) HostSystem(ctx context.Context, path string) (*object.HostSystem, error) {
|
|
hss, err := f.HostSystemList(ctx, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(hss) > 1 {
|
|
return nil, &MultipleFoundError{"host", path}
|
|
}
|
|
|
|
return hss[0], nil
|
|
}
|
|
|
|
func (f *Finder) DefaultHostSystem(ctx context.Context) (*object.HostSystem, error) {
|
|
hs, err := f.HostSystem(ctx, "*")
|
|
if err != nil {
|
|
return nil, toDefaultError(err)
|
|
}
|
|
|
|
return hs, nil
|
|
}
|
|
|
|
func (f *Finder) HostSystemOrDefault(ctx context.Context, path string) (*object.HostSystem, error) {
|
|
if path != "" {
|
|
hs, err := f.HostSystem(ctx, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return hs, nil
|
|
}
|
|
|
|
return f.DefaultHostSystem(ctx)
|
|
}
|
|
|
|
func (f *Finder) NetworkList(ctx context.Context, path string) ([]object.NetworkReference, error) {
|
|
s := &spec{
|
|
Relative: f.networkFolder,
|
|
}
|
|
|
|
es, err := f.find(ctx, path, s)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var ns []object.NetworkReference
|
|
for _, e := range es {
|
|
ref := e.Object.Reference()
|
|
switch ref.Type {
|
|
case "Network":
|
|
r := object.NewNetwork(f.client, ref)
|
|
r.InventoryPath = e.Path
|
|
ns = append(ns, r)
|
|
case "OpaqueNetwork":
|
|
r := object.NewOpaqueNetwork(f.client, ref)
|
|
r.InventoryPath = e.Path
|
|
ns = append(ns, r)
|
|
case "DistributedVirtualPortgroup":
|
|
r := object.NewDistributedVirtualPortgroup(f.client, ref)
|
|
r.InventoryPath = e.Path
|
|
ns = append(ns, r)
|
|
case "DistributedVirtualSwitch", "VmwareDistributedVirtualSwitch":
|
|
r := object.NewDistributedVirtualSwitch(f.client, ref)
|
|
r.InventoryPath = e.Path
|
|
ns = append(ns, r)
|
|
}
|
|
}
|
|
|
|
if len(ns) == 0 {
|
|
net, nerr := f.networkByID(ctx, path)
|
|
if nerr == nil {
|
|
return []object.NetworkReference{net}, nil
|
|
}
|
|
|
|
return nil, &NotFoundError{"network", path}
|
|
}
|
|
|
|
return ns, nil
|
|
}
|
|
|
|
// Network finds a NetworkReference using a Name, Inventory Path, ManagedObject ID, Logical Switch UUID or Segment ID.
|
|
// With standard vSphere networking, Portgroups cannot have the same name within the same network folder.
|
|
// With NSX, Portgroups can have the same name, even within the same Switch. In this case, using an inventory path
|
|
// results in a MultipleFoundError. A MOID, switch UUID or segment ID can be used instead, as both are unique.
|
|
// See also: https://kb.vmware.com/s/article/79872#Duplicate_names
|
|
// Examples:
|
|
// - Name: "dvpg-1"
|
|
// - Inventory Path: "vds-1/dvpg-1"
|
|
// - Cluster Path: "/dc-1/host/cluster-1/dvpg-1"
|
|
// - ManagedObject ID: "DistributedVirtualPortgroup:dvportgroup-53"
|
|
// - Logical Switch UUID: "da2a59b8-2450-4cb2-b5cc-79c4c1d2144c"
|
|
// - Segment ID: "/infra/segments/vnet_ce50e69b-1784-4a14-9206-ffd7f1f146f7"
|
|
func (f *Finder) Network(ctx context.Context, path string) (object.NetworkReference, error) {
|
|
networks, err := f.NetworkList(ctx, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(networks) > 1 {
|
|
return nil, &MultipleFoundError{"network", path}
|
|
}
|
|
|
|
return networks[0], nil
|
|
}
|
|
|
|
func (f *Finder) networkByID(ctx context.Context, path string) (object.NetworkReference, error) {
|
|
if ref := object.ReferenceFromString(path); ref != nil {
|
|
// This is a MOID
|
|
return object.NewReference(f.client, *ref).(object.NetworkReference), nil
|
|
}
|
|
|
|
kind := []string{"DistributedVirtualPortgroup"}
|
|
|
|
m := view.NewManager(f.client)
|
|
v, err := m.CreateContainerView(ctx, f.client.ServiceContent.RootFolder, kind, true)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer v.Destroy(ctx)
|
|
|
|
filter := property.Match{
|
|
"config.logicalSwitchUuid": path,
|
|
"config.segmentId": path,
|
|
}
|
|
|
|
refs, err := v.FindAny(ctx, kind, filter)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(refs) == 0 {
|
|
return nil, &NotFoundError{"network", path}
|
|
}
|
|
if len(refs) > 1 {
|
|
return nil, &MultipleFoundError{"network", path}
|
|
}
|
|
|
|
return object.NewReference(f.client, refs[0]).(object.NetworkReference), nil
|
|
}
|
|
|
|
func (f *Finder) DefaultNetwork(ctx context.Context) (object.NetworkReference, error) {
|
|
network, err := f.Network(ctx, "*")
|
|
if err != nil {
|
|
return nil, toDefaultError(err)
|
|
}
|
|
|
|
return network, nil
|
|
}
|
|
|
|
func (f *Finder) NetworkOrDefault(ctx context.Context, path string) (object.NetworkReference, error) {
|
|
if path != "" {
|
|
network, err := f.Network(ctx, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return network, nil
|
|
}
|
|
|
|
return f.DefaultNetwork(ctx)
|
|
}
|
|
|
|
func (f *Finder) ResourcePoolList(ctx context.Context, path string) ([]*object.ResourcePool, error) {
|
|
s := &spec{
|
|
Relative: f.hostFolder,
|
|
Parents: []string{"ComputeResource", "ClusterComputeResource", "VirtualApp"},
|
|
Nested: []string{"ResourcePool"},
|
|
Contents: true,
|
|
}
|
|
|
|
es, err := f.find(ctx, path, s)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var rps []*object.ResourcePool
|
|
for _, e := range es {
|
|
var rp *object.ResourcePool
|
|
|
|
switch o := e.Object.(type) {
|
|
case mo.ResourcePool:
|
|
rp = object.NewResourcePool(f.client, o.Reference())
|
|
rp.InventoryPath = e.Path
|
|
rps = append(rps, rp)
|
|
}
|
|
}
|
|
|
|
if len(rps) == 0 {
|
|
return nil, &NotFoundError{"resource pool", path}
|
|
}
|
|
|
|
return rps, nil
|
|
}
|
|
|
|
func (f *Finder) ResourcePool(ctx context.Context, path string) (*object.ResourcePool, error) {
|
|
rps, err := f.ResourcePoolList(ctx, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(rps) > 1 {
|
|
return nil, &MultipleFoundError{"resource pool", path}
|
|
}
|
|
|
|
return rps[0], nil
|
|
}
|
|
|
|
func (f *Finder) DefaultResourcePool(ctx context.Context) (*object.ResourcePool, error) {
|
|
rp, err := f.ResourcePool(ctx, "*/Resources")
|
|
if err != nil {
|
|
return nil, toDefaultError(err)
|
|
}
|
|
|
|
return rp, nil
|
|
}
|
|
|
|
func (f *Finder) ResourcePoolOrDefault(ctx context.Context, path string) (*object.ResourcePool, error) {
|
|
if path != "" {
|
|
rp, err := f.ResourcePool(ctx, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return rp, nil
|
|
}
|
|
|
|
return f.DefaultResourcePool(ctx)
|
|
}
|
|
|
|
// ResourcePoolListAll combines ResourcePoolList and VirtualAppList
|
|
// VirtualAppList is only called if ResourcePoolList does not find any pools with the given path.
|
|
func (f *Finder) ResourcePoolListAll(ctx context.Context, path string) ([]*object.ResourcePool, error) {
|
|
pools, err := f.ResourcePoolList(ctx, path)
|
|
if err != nil {
|
|
if _, ok := err.(*NotFoundError); !ok {
|
|
return nil, err
|
|
}
|
|
|
|
vapps, _ := f.VirtualAppList(ctx, path)
|
|
|
|
if len(vapps) == 0 {
|
|
return nil, err
|
|
}
|
|
|
|
for _, vapp := range vapps {
|
|
pools = append(pools, vapp.ResourcePool)
|
|
}
|
|
}
|
|
|
|
return pools, nil
|
|
}
|
|
|
|
func (f *Finder) DefaultFolder(ctx context.Context) (*object.Folder, error) {
|
|
ref, err := f.vmFolder(ctx)
|
|
if err != nil {
|
|
return nil, toDefaultError(err)
|
|
}
|
|
folder := object.NewFolder(f.client, ref.Reference())
|
|
|
|
// Set the InventoryPath of the newly created folder object
|
|
// The default foler becomes the datacenter's "vm" folder.
|
|
// The "vm" folder always exists for a datacenter. It cannot be
|
|
// removed or replaced
|
|
folder.SetInventoryPath(path.Join(f.dc.InventoryPath, "vm"))
|
|
|
|
return folder, nil
|
|
}
|
|
|
|
func (f *Finder) FolderOrDefault(ctx context.Context, path string) (*object.Folder, error) {
|
|
if path != "" {
|
|
folder, err := f.Folder(ctx, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return folder, nil
|
|
}
|
|
return f.DefaultFolder(ctx)
|
|
}
|
|
|
|
func (f *Finder) VirtualMachineList(ctx context.Context, path string) ([]*object.VirtualMachine, error) {
|
|
s := &spec{
|
|
Relative: f.vmFolder,
|
|
Parents: []string{"VirtualApp"},
|
|
}
|
|
|
|
es, err := f.find(ctx, path, s)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var vms []*object.VirtualMachine
|
|
for _, e := range es {
|
|
switch o := e.Object.(type) {
|
|
case mo.VirtualMachine:
|
|
vm := object.NewVirtualMachine(f.client, o.Reference())
|
|
vm.InventoryPath = e.Path
|
|
vms = append(vms, vm)
|
|
}
|
|
}
|
|
|
|
if len(vms) == 0 {
|
|
return nil, &NotFoundError{"vm", path}
|
|
}
|
|
|
|
return vms, nil
|
|
}
|
|
|
|
func (f *Finder) VirtualMachine(ctx context.Context, path string) (*object.VirtualMachine, error) {
|
|
vms, err := f.VirtualMachineList(ctx, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(vms) > 1 {
|
|
return nil, &MultipleFoundError{"vm", path}
|
|
}
|
|
|
|
return vms[0], nil
|
|
}
|
|
|
|
func (f *Finder) VirtualAppList(ctx context.Context, path string) ([]*object.VirtualApp, error) {
|
|
s := &spec{
|
|
Relative: f.vmFolder,
|
|
}
|
|
|
|
es, err := f.find(ctx, path, s)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var apps []*object.VirtualApp
|
|
for _, e := range es {
|
|
switch o := e.Object.(type) {
|
|
case mo.VirtualApp:
|
|
app := object.NewVirtualApp(f.client, o.Reference())
|
|
app.InventoryPath = e.Path
|
|
apps = append(apps, app)
|
|
}
|
|
}
|
|
|
|
if len(apps) == 0 {
|
|
return nil, &NotFoundError{"app", path}
|
|
}
|
|
|
|
return apps, nil
|
|
}
|
|
|
|
func (f *Finder) VirtualApp(ctx context.Context, path string) (*object.VirtualApp, error) {
|
|
apps, err := f.VirtualAppList(ctx, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(apps) > 1 {
|
|
return nil, &MultipleFoundError{"app", path}
|
|
}
|
|
|
|
return apps[0], nil
|
|
}
|
|
|
|
func (f *Finder) FolderList(ctx context.Context, path string) ([]*object.Folder, error) {
|
|
es, err := f.ManagedObjectList(ctx, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var folders []*object.Folder
|
|
|
|
for _, e := range es {
|
|
switch o := e.Object.(type) {
|
|
case mo.Folder, mo.StoragePod:
|
|
folder := object.NewFolder(f.client, o.Reference())
|
|
folder.InventoryPath = e.Path
|
|
folders = append(folders, folder)
|
|
case *object.Folder:
|
|
// RootFolder
|
|
folders = append(folders, o)
|
|
}
|
|
}
|
|
|
|
if len(folders) == 0 {
|
|
return nil, &NotFoundError{"folder", path}
|
|
}
|
|
|
|
return folders, nil
|
|
}
|
|
|
|
func (f *Finder) Folder(ctx context.Context, path string) (*object.Folder, error) {
|
|
folders, err := f.FolderList(ctx, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(folders) > 1 {
|
|
return nil, &MultipleFoundError{"folder", path}
|
|
}
|
|
|
|
return folders[0], nil
|
|
}
|