Skip to content

Commit

Permalink
Finder: support automatic Folder recursion (vmware#663)
Browse files Browse the repository at this point in the history
Prior to this change, the Finder behaved like the 'ls' command and
as such required a Folder name or wildcard in the path argument to
find resources within folders.  The original "list" mode of the Finder
is maintained, but will now switch to "find" mode if the path argument
does not contain a "/".  See find/doc.go for details.

The public Finder method signatures remain the same, with the exception of
ManagedObjectListChildren which now takes an optional (variadic) list of
types.

No new public methods or types have been added.

The 'list.Recurser' type is no longer exported and has moved to an unexported
type within the find package.  This part of the change assumes that 'list.Recurser'
was not used directly outside of the govmomi repo.

The tests depend on the Go based vCenter simulator, which currently lives
in the vmware/vic repo, but will be moving to the govmomi repo at some point.

Fixes vmware#190
Fixes vmware#519
Fixes vmware#540

Closes vmware#507
Closes vmware#593
  • Loading branch information
dougm authored Feb 13, 2017
1 parent 0a28e59 commit 9bda6c3
Show file tree
Hide file tree
Showing 12 changed files with 427 additions and 178 deletions.
34 changes: 34 additions & 0 deletions find/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
Copyright (c) 2014-2017 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 implements inventory listing and searching.
The Finder is an alternative to the object.SearchIndex FindByInventoryPath() and FindChild() methods.
SearchIndex.FindByInventoryPath requires an absolute path, whereas the Finder also supports relative paths
and patterns via filepath.Match.
SearchIndex.FindChild requires a parent to find the child, whereas the Finder also supports an ancestor via
recursive object traversal.
The various Finder methods accept a "path" argument, which can absolute or relative to the Folder for the object type.
The Finder supports two modes, "list" and "find". The "list" mode behaves like the "ls" command, only searching within
the immediate path. The "find" mode behaves like the "find" command, with the search starting at the immediate path but
also recursing into sub Folders relative to the Datacenter. The default mode is "list" if the given path contains a "/",
otherwise "find" mode is used.
See also: https://github.com/vmware/govmomi/blob/master/govc/README.md#usage
*/
package find
128 changes: 98 additions & 30 deletions find/finder.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved.
Copyright (c) 2014-2017 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.
Expand All @@ -20,6 +20,7 @@ import (
"context"
"errors"
"path"
"strings"

"github.com/vmware/govmomi/list"
"github.com/vmware/govmomi/object"
Expand All @@ -30,17 +31,16 @@ import (
)

type Finder struct {
client *vim25.Client
recurser list.Recurser

client *vim25.Client
r recurser
dc *object.Datacenter
folders *object.DatacenterFolders
}

func NewFinder(client *vim25.Client, all bool) *Finder {
f := &Finder{
client: client,
recurser: list.Recurser{
r: recurser{
Collector: property.DefaultCollector(client),
All: all,
},
Expand All @@ -55,9 +55,9 @@ func (f *Finder) SetDatacenter(dc *object.Datacenter) *Finder {
return f
}

type findRelativeFunc func(ctx context.Context) (object.Reference, error)
func (f *Finder) find(ctx context.Context, arg string, s *spec) ([]list.Element, error) {
isPath := strings.Contains(arg, "/")

func (f *Finder) find(ctx context.Context, fn findRelativeFunc, tl bool, arg string) ([]list.Element, error) {
root := list.Element{
Path: "/",
Object: object.NewRootFolder(f.client),
Expand All @@ -70,7 +70,7 @@ func (f *Finder) find(ctx context.Context, fn findRelativeFunc, tl bool, arg str
case "..": // Not supported; many edge case, little value
return nil, errors.New("cannot traverse up a tree")
case ".": // Relative to whatever
pivot, err := fn(ctx)
pivot, err := s.Relative(ctx)
if err != nil {
return nil, err
}
Expand All @@ -93,13 +93,13 @@ func (f *Finder) find(ctx context.Context, fn findRelativeFunc, tl bool, arg str
}
}

f.recurser.TraverseLeafs = tl
es, err := f.recurser.Recurse(ctx, root, parts)
if err != nil {
return nil, err
if s.listMode(isPath) {
return f.r.List(ctx, s, root, parts)
}

return es, nil
s.Parents = append(s.Parents, s.Nested...)

return f.r.Find(ctx, s, root, parts)
}

func (f *Finder) datacenter() (*object.Datacenter, error) {
Expand Down Expand Up @@ -208,7 +208,7 @@ 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) ([]list.Element, error) {
func (f *Finder) managedObjectList(ctx context.Context, path string, tl bool, include []string) ([]list.Element, error) {
fn := f.rootFolder

if f.dc != nil {
Expand All @@ -219,7 +219,23 @@ func (f *Finder) managedObjectList(ctx context.Context, path string, tl bool) ([
path = "."
}

return f.find(ctx, fn, tl, path)
s := &spec{
Relative: fn,
Parents: []string{"ComputeResource", "ClusterComputeResource", "HostSystem", "VirtualApp", "StoragePod"},
Include: include,
}

if tl {
if path == "/**" {
// TODO: support switching to find mode for any path, not just relative to f.rootFolder or f.dcReference
path = "*"
} else {
s.Contents = true
s.ListMode = types.NewBool(true)
}
}

return f.find(ctx, path, s)
}

// Element returns an Element for the given ManagedObjectReference
Expand All @@ -229,7 +245,11 @@ func (f *Finder) Element(ctx context.Context, ref types.ManagedObjectReference)
return ref, nil
}

e, err := f.find(ctx, rl, false, ".")
s := &spec{
Relative: rl,
}

e, err := f.find(ctx, "./", s)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -270,16 +290,21 @@ func (f *Finder) ObjectReference(ctx context.Context, ref types.ManagedObjectRef
return r, nil
}

func (f *Finder) ManagedObjectList(ctx context.Context, path string) ([]list.Element, error) {
return f.managedObjectList(ctx, path, false)
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) ([]list.Element, error) {
return f.managedObjectList(ctx, path, true)
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) {
es, err := f.find(ctx, f.rootFolder, false, path)
s := &spec{
Relative: f.rootFolder,
Include: []string{"Datacenter"},
}

es, err := f.find(ctx, path, s)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -336,7 +361,12 @@ func (f *Finder) DatacenterOrDefault(ctx context.Context, path string) (*object.
}

func (f *Finder) DatastoreList(ctx context.Context, path string) ([]*object.Datastore, error) {
es, err := f.find(ctx, f.datastoreFolder, false, path)
s := &spec{
Relative: f.datastoreFolder,
Parents: []string{"StoragePod"},
}

es, err := f.find(ctx, path, s)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -404,7 +434,11 @@ func (f *Finder) DatastoreOrDefault(ctx context.Context, path string) (*object.D
}

func (f *Finder) DatastoreClusterList(ctx context.Context, path string) ([]*object.StoragePod, error) {
es, err := f.find(ctx, f.datastoreFolder, false, path)
s := &spec{
Relative: f.datastoreFolder,
}

es, err := f.find(ctx, path, s)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -461,7 +495,11 @@ func (f *Finder) DatastoreClusterOrDefault(ctx context.Context, path string) (*o
}

func (f *Finder) ComputeResourceList(ctx context.Context, path string) ([]*object.ComputeResource, error) {
es, err := f.find(ctx, f.hostFolder, false, path)
s := &spec{
Relative: f.hostFolder,
}

es, err := f.find(ctx, path, s)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -523,7 +561,11 @@ func (f *Finder) ComputeResourceOrDefault(ctx context.Context, path string) (*ob
}

func (f *Finder) ClusterComputeResourceList(ctx context.Context, path string) ([]*object.ClusterComputeResource, error) {
es, err := f.find(ctx, f.hostFolder, false, path)
s := &spec{
Relative: f.hostFolder,
}

es, err := f.find(ctx, path, s)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -564,7 +606,13 @@ func (f *Finder) ClusterComputeResource(ctx context.Context, path string) (*obje
}

func (f *Finder) HostSystemList(ctx context.Context, path string) ([]*object.HostSystem, error) {
es, err := f.find(ctx, f.hostFolder, false, path)
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
}
Expand Down Expand Up @@ -635,7 +683,11 @@ func (f *Finder) HostSystemOrDefault(ctx context.Context, path string) (*object.
}

func (f *Finder) NetworkList(ctx context.Context, path string) ([]object.NetworkReference, error) {
es, err := f.find(ctx, f.networkFolder, false, path)
s := &spec{
Relative: f.networkFolder,
}

es, err := f.find(ctx, path, s)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -701,7 +753,14 @@ func (f *Finder) NetworkOrDefault(ctx context.Context, path string) (object.Netw
}

func (f *Finder) ResourcePoolList(ctx context.Context, path string) ([]*object.ResourcePool, error) {
es, err := f.find(ctx, f.hostFolder, true, path)
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
}
Expand Down Expand Up @@ -804,7 +863,12 @@ func (f *Finder) FolderOrDefault(ctx context.Context, path string) (*object.Fold
}

func (f *Finder) VirtualMachineList(ctx context.Context, path string) ([]*object.VirtualMachine, error) {
es, err := f.find(ctx, f.vmFolder, false, path)
s := &spec{
Relative: f.vmFolder,
Parents: []string{"VirtualApp"},
}

es, err := f.find(ctx, path, s)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -840,7 +904,11 @@ func (f *Finder) VirtualMachine(ctx context.Context, path string) (*object.Virtu
}

func (f *Finder) VirtualAppList(ctx context.Context, path string) ([]*object.VirtualApp, error) {
es, err := f.find(ctx, f.vmFolder, false, path)
s := &spec{
Relative: f.vmFolder,
}

es, err := f.find(ctx, path, s)
if err != nil {
return nil, err
}
Expand Down
Loading

0 comments on commit 9bda6c3

Please sign in to comment.