Skip to content

Commit

Permalink
Merge pull request #3609 from dougm/find-by-id
Browse files Browse the repository at this point in the history
api: support MOID conversion in Finder methods
  • Loading branch information
dougm authored Nov 5, 2024
2 parents 73b10a0 + a9d5985 commit 63f11e9
Show file tree
Hide file tree
Showing 12 changed files with 228 additions and 31 deletions.
7 changes: 5 additions & 2 deletions find/doc.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/*
Copyright (c) 2014-2017 VMware, Inc. All Rights Reserved.
Copyright (c) 2017-2022 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
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,
Expand All @@ -32,6 +32,9 @@ otherwise "find" mode is used.
The exception is to use a "..." wildcard with a path to find all objects recursively underneath any root object.
For example: VirtualMachineList("/DC1/...")
Finder methods can also convert a managed object reference (aka MOID) to an object instance.
For example: VirtualMachine("VirtualMachine:vm-123") or VirtualMachine("vm-123")
See also: https://github.com/vmware/govmomi/blob/main/govc/README.md#usage
*/
package find
23 changes: 16 additions & 7 deletions find/finder.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/*
Copyright (c) 2014-2023 VMware, Inc. All Rights Reserved.
Copyright (c) 2014-2024 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
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,
Expand All @@ -22,6 +22,7 @@ import (
"path"
"strings"

"github.com/vmware/govmomi/fault"
"github.com/vmware/govmomi/internal"
"github.com/vmware/govmomi/list"
"github.com/vmware/govmomi/object"
Expand Down Expand Up @@ -116,6 +117,19 @@ func (f *Finder) findRoot(ctx context.Context, root *list.Element, parts []strin
func (f *Finder) find(ctx context.Context, arg string, s *spec) ([]list.Element, error) {
isPath := strings.Contains(arg, "/")

if !isPath {
if ref := object.ReferenceFromString(arg); ref != nil {
p, err := InventoryPath(ctx, f.client, *ref)
if err == nil {
if t, ok := mo.Value(*ref); ok {
return []list.Element{{Object: t, Path: p}}, nil
}
} else if !fault.Is(err, &types.ManagedObjectNotFound{}) {
return nil, err
} // else fall through to name based lookup
}
}

root := list.Element{
Object: object.NewRootFolder(f.client),
Path: "/",
Expand Down Expand Up @@ -821,11 +835,6 @@ func (f *Finder) Network(ctx context.Context, path string) (object.NetworkRefere
}

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)
Expand Down
47 changes: 46 additions & 1 deletion find/finder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ 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
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,
Expand Down Expand Up @@ -105,3 +105,48 @@ func TestFindNetwork(t *testing.T) {
}
}, model)
}

func TestFindByID(t *testing.T) {
simulator.Test(func(ctx context.Context, c *vim25.Client) {
find := find.NewFinder(c)

vms, err := find.VirtualMachineList(ctx, "*")
if err != nil {
t.Fatal(err)
}

for _, vm := range vms {
ref := vm.Reference()
byRef, err := find.VirtualMachine(ctx, ref.String())
if err != nil {
t.Fatal(err)
}
if byRef.InventoryPath != vm.InventoryPath {
t.Errorf("InventoryPath=%q", byRef.InventoryPath)
}
if byRef.Reference() != ref {
t.Error(byRef.Reference())
}
_, err = find.VirtualMachine(ctx, ref.String()+"invalid")
if err == nil {
t.Error("expected error")
}

byID, err := find.VirtualMachine(ctx, ref.Value)
if err != nil {
t.Error(err)
}
if byID.InventoryPath != vm.InventoryPath {
t.Errorf("InventoryPath=%q", byID.InventoryPath)
}
if byID.Reference() != ref {
t.Error(byID.Reference())
}
_, err = find.VirtualMachine(ctx, ref.Value+"invalid")
if err == nil {
t.Error("expected error")
}

}
})
}
3 changes: 3 additions & 0 deletions govc/USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2600,6 +2600,7 @@ The '-type' flag value can be a managed entity type or one of the following alia
Examples:
govc find
govc find -l / # include object type in output
govc find -l -I / # include MOID in output
govc find /dc1 -type c
govc find vm -name my-vm-*
govc find . -type n
Expand All @@ -2611,6 +2612,7 @@ Examples:
govc find . -type h -hardware.cpuInfo.numCpuCores 16
Options:
-I=false Print the managed object ID
-i=false Print the managed object reference
-l=false Long listing format
-maxdepth=-1 Max depth
Expand Down Expand Up @@ -4388,6 +4390,7 @@ Examples:
govc ls -t Datastore host/ClusterA/* | grep -v local | xargs -n1 basename | sort | uniq
Options:
-I=false Print the managed object ID
-L=false Follow managed object references
-i=false Print the managed object reference
-l=false Long listing format
Expand Down
18 changes: 6 additions & 12 deletions govc/flags/datacenter.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/*
Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved.
Copyright (c) 2014-2024 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
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,
Expand Down Expand Up @@ -197,16 +197,6 @@ func (flag *DatacenterFlag) ManagedObjects(ctx context.Context, args []string) (
}

for _, arg := range args {
if ref := object.ReferenceFromString(arg); ref != nil {
// e.g. output from object.collect
refs = append(refs, *ref)
continue
}

if !strings.Contains(arg, "/") {
return nil, fmt.Errorf("%q must be qualified with a path", arg)
}

elements, err := finder.ManagedObjectList(ctx, arg)
if err != nil {
return nil, err
Expand All @@ -216,6 +206,10 @@ func (flag *DatacenterFlag) ManagedObjects(ctx context.Context, args []string) (
return nil, fmt.Errorf("object '%s' not found", arg)
}

if len(elements) > 1 && !strings.Contains(arg, "/") {
return nil, fmt.Errorf("%q must be qualified with a path", arg)
}

for _, e := range elements {
refs = append(refs, e.Object.Reference())
}
Expand Down
15 changes: 11 additions & 4 deletions govc/ls/command.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/*
Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved.
Copyright (c) 2014-2024 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
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,
Expand Down Expand Up @@ -36,6 +36,7 @@ type ls struct {
Long bool
Type string
ToRef bool
ToID bool
DeRef bool
}

Expand All @@ -49,6 +50,7 @@ func (cmd *ls) Register(ctx context.Context, f *flag.FlagSet) {

f.BoolVar(&cmd.Long, "l", false, "Long listing format")
f.BoolVar(&cmd.ToRef, "i", false, "Print the managed object reference")
f.BoolVar(&cmd.ToID, "I", false, "Print the managed object ID")
f.BoolVar(&cmd.DeRef, "L", false, "Follow managed object references")
f.StringVar(&cmd.Type, "t", "", "Object type")
}
Expand Down Expand Up @@ -145,8 +147,13 @@ func (l listResult) Write(w io.Writer) error {
var err error

for _, e := range l.Elements {
if l.ToRef {
fmt.Fprint(w, e.Object.Reference().String())
if l.ToRef || l.ToID {
ref := e.Object.Reference()
id := ref.String()
if l.ToID {
id = ref.Value
}
fmt.Fprint(w, id)
if l.Long {
fmt.Fprintf(w, " %s", e.Path)
}
Expand Down
18 changes: 16 additions & 2 deletions govc/object/find.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type find struct {
*flags.DatacenterFlag

ref bool
id bool
long bool
parent bool
kind kinds
Expand Down Expand Up @@ -128,6 +129,7 @@ func (cmd *find) Register(ctx context.Context, f *flag.FlagSet) {
f.StringVar(&cmd.name, "name", "*", "Resource name")
f.IntVar(&cmd.maxdepth, "maxdepth", -1, "Max depth")
f.BoolVar(&cmd.ref, "i", false, "Print the managed object reference")
f.BoolVar(&cmd.id, "I", false, "Print the managed object ID")
f.BoolVar(&cmd.long, "l", false, "Long listing format")
f.BoolVar(&cmd.parent, "p", false, "Find parent objects")
}
Expand All @@ -153,6 +155,7 @@ The '-type' flag value can be a managed entity type or one of the following alia
Examples:
govc find
govc find -l / # include object type in output
govc find -l -I / # include MOID in output
govc find /dc1 -type c
govc find vm -name my-vm-*
govc find . -type n
Expand Down Expand Up @@ -214,6 +217,13 @@ func (cmd *find) writeResult(paths []string) error {
return cmd.WriteResult(findResult(paths))
}

func (cmd *find) mo(o types.ManagedObjectReference) string {
if cmd.id {
return o.Value
}
return o.String()
}

func (cmd *find) Run(ctx context.Context, f *flag.FlagSet) error {
client, err := cmd.Client()
if err != nil {
Expand All @@ -225,6 +235,10 @@ func (cmd *find) Run(ctx context.Context, f *flag.FlagSet) error {
return err
}

if cmd.id {
cmd.ref = true
}

root := client.ServiceContent.RootFolder
rootPath := "/"

Expand Down Expand Up @@ -316,15 +330,15 @@ func (cmd *find) Run(ctx context.Context, f *flag.FlagSet) error {

printPath := func(o types.ManagedObjectReference, p string) {
if cmd.ref && !cmd.long {
paths = append(paths, o.String())
paths = append(paths, cmd.mo(o))
return
}

path := strings.Replace(p, rootPath, arg, 1)
if cmd.long {
id := strings.TrimPrefix(o.Type, "Vmware")
if cmd.ref {
id = o.String()
id = cmd.mo(o)
}

path = id + "\t" + path
Expand Down
36 changes: 36 additions & 0 deletions govc/test/object.bats
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,42 @@ EOF
assert_success 2
}

@test "collect by id" {
vcsim_env -standalone-host 0 -pod 1 -app 1

run govc find -i /
assert_success

for ref in "${lines[@]}" ; do
run govc collect "$ref" name
assert_success
done

run govc find -I /
assert_success

for id in "${lines[@]}" ; do
run govc collect "$id" name
assert_success
done

run govc find -I -type m /
assert_success

for id in "${lines[@]}" ; do
run govc vm.info "$id"
assert_success
done

run govc find -I -type h /
assert_success

for id in "${lines[@]}" ; do
run govc host.info "$id"
assert_success
done
}

@test "object.find" {
vcsim_env -ds 2

Expand Down
Loading

0 comments on commit 63f11e9

Please sign in to comment.