vmware / govmomi

Go library for the VMware vSphere API
Apache License 2.0
2.3k stars 910 forks source link

[BUG] esxcli executor doesn't return value for single item responses #3573

Open flamingdumpster opened 2 days ago

flamingdumpster commented 2 days ago

Describe the bug When using an esxcli executor to run commands that have a single variable response, such as:

["system", "uuid", "get"] ["system", "stats", "uptime", "get"] ["system", "time", "get"]

the response (response.Values) comes back as an empty slice (response.String is also empty.) However, using the same code to run commands that have multiple items in the response, such as:

["storage", "core", "device", "list"] ["storage", "nmp", "satp", "rule", "list"] ["storage", "nmp", "psp", "roundrobin", "deviceconfig", "get", "-d"]

the data is returned correctly as a map of slices. Note: response.String is also empty for multi-item responses.

To Reproduce Steps to reproduce the behavior:

` executor, eErr := esxcli.NewExecutor(hrr.client, host)

if eErr != nil {
    return eErr
}
resp, rErr := executor.Run(command)

` Evaluate

resp

Expected behavior For single item responses a list of a single item is expected to be returned, not and empty slice. The value of response.String is presumably also expected to not be empty in either case, however the intent here is unknown.

Affected version github.com/vmware/govmomi v0.38.0

Screenshots/Debug Output time="2024-10-03T22:16:34Z" level=debug msg="Command: [system uuid get], Host response: []" Additional context It appears commands ending with (using) "get" have the issue, while commands ending with (using) "list" do not. The command ending in "get", "-d" is an outlier for the issue being strictly associated with "get" - suggests single items are not handled properly, but maybe something else.

github-actions[bot] commented 2 days ago

Howdy 🖐   flamingdumpster ! Thank you for your interest in this project. We value your feedback and will respond soon.

If you want to contribute to this project, please make yourself familiar with the CONTRIBUTION guidelines.

dougm commented 1 day ago

Is it working as expected with govc?

% govc host.esxcli -host $host system uuid get
66ec889c-ba99-5402-6b21-0a000cfc0909

Adding the -trace flag, you should see:

<reflect:response>&lt;obj ... xsi:type="xsd:string"&gt;66ec889c-ba99-5402-6b21-0a000cfc0909&lt;/obj&gt;</reflect:response>

Whereas list types are xsi:type="ArrayOfDataObject".

Do you have a main.go program you can share to reproduce?

flamingdumpster commented 1 day ago

We are not using govc - we use govmomi within a vmware remote plugin we are developing. I don't have a main.go I can share at the moment as this code is part of a much larger application.

I can take a look at that govc code and see if there is something I am missing...

dougm commented 1 day ago

Understood, govc is just a quick way to see if this is a soap/protocol issue or code issue. Standalone example below if you want to try that.

% export GOVMOMI_URL=$GOVC_URL GOVMOMI_INSECURE=true

% go run .
HostSystem:host-27=66ec889c-a54b-fba4-e93f-0a000ccc0a2d
HostSystem:host-24=66ec889c-debf-45d2-0373-0a000ccca0e8
HostSystem:host-21=66ec889c-ba99-5402-6b21-0a000cfc0909
HostSystem:host-30=66ec889a-0370-7953-3296-0a000c4b598d
package main

import (
    "context"
    "fmt"

    "github.com/vmware/govmomi/examples"
    "github.com/vmware/govmomi/govc/host/esxcli"
    "github.com/vmware/govmomi/object"
    "github.com/vmware/govmomi/property"
    "github.com/vmware/govmomi/view"
    "github.com/vmware/govmomi/vim25"
)

func main() {
    examples.Run(func(ctx context.Context, c *vim25.Client) error {
        m := view.NewManager(c)
        kind := []string{"HostSystem"}

        v, err := m.CreateContainerView(ctx, c.ServiceContent.RootFolder, kind, true)
        if err != nil {
            return err
        }

        hosts, err := v.Find(ctx, kind, property.Match{})
        if err != nil {
            return err
        }

        for _, ref := range hosts {
            host := object.NewHostSystem(c, ref)

            e, err := esxcli.NewExecutor(c, host)
            if err != nil {
                return err
            }

            res, err := e.Run([]string{"system", "uuid", "get"})
            if err != nil {
                return err
            }

            fmt.Printf("%s=%s\n", host.Reference(), res.String)
        }

        return nil
    })
}