Skip to content

Commit

Permalink
vcsim: add esxcli support
Browse files Browse the repository at this point in the history
Signed-off-by: Doug MacEachern <dougm@broadcom.com>
  • Loading branch information
dougm committed Nov 23, 2024
1 parent 8101bae commit 9322377
Show file tree
Hide file tree
Showing 15 changed files with 5,206 additions and 43 deletions.
4 changes: 2 additions & 2 deletions cli/host/esxcli/command.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright (c) 2014-2023 VMware, Inc. All Rights Reserved.
Copyright (c) 2024-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.
Expand Down Expand Up @@ -57,7 +57,7 @@ type CommandInfoMethod struct {

type CommandInfo struct {
CommandInfoItem
Method []*CommandInfoMethod `xml:"method" json:"method"`
Method []CommandInfoMethod `xml:"method" json:"method"`
}

func NewCommand(args []string) *Command {
Expand Down
50 changes: 49 additions & 1 deletion cli/host/esxcli/esxcli.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright (c) 2014-2023 VMware, Inc. All Rights Reserved.
Copyright (c) 2024-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.
Expand All @@ -22,18 +22,24 @@ import (
"flag"
"fmt"
"io"
"os"
"os/exec"
"sort"
"strings"
"text/tabwriter"

"github.com/dougm/pretty"

"github.com/vmware/govmomi/cli"
"github.com/vmware/govmomi/cli/flags"
"github.com/vmware/govmomi/internal"
)

type esxcli struct {
*flags.HostSystemFlag

hints bool
trace bool
}

func init() {
Expand All @@ -49,6 +55,9 @@ func (cmd *esxcli) Register(ctx context.Context, f *flag.FlagSet) {
cmd.HostSystemFlag.Register(ctx, f)

f.BoolVar(&cmd.hints, "hints", true, "Use command info hints when formatting output")
if cli.ShowUnreleased() {
f.BoolVar(&cmd.trace, "T", false, "Write esxcli nested SOAP traffic to stderr")
}
}

func (cmd *esxcli) Description() string {
Expand All @@ -71,6 +80,38 @@ func (cmd *esxcli) Process(ctx context.Context) error {
return nil
}

func fmtXML(s string) {
cmd := exec.Command("xmlstarlet", "fo")
cmd.Stdout = os.Stderr
cmd.Stderr = os.Stderr
cmd.Stdin = strings.NewReader(s)
if err := cmd.Run(); err != nil {
panic(err) // yes xmlstarlet is required (your eyes will thank you)
}
}

func (cmd *esxcli) Trace(req *internal.ExecuteSoapRequest, res *internal.ExecuteSoapResponse) {
x := res.Returnval

if req.Moid == "ha-dynamic-type-manager-local-cli-cliinfo" {
if x.Fault == nil {
return // TODO: option to trace this
}
}

pretty.Fprintf(os.Stderr, "%# v\n", req)

if x.Fault == nil {
fmtXML(res.Returnval.Response)
} else {
fmt.Fprintln(os.Stderr, "Message=", x.Fault.FaultMsg)
if x.Fault.FaultDetail != "" {
fmt.Fprint(os.Stderr, "Detail=")
fmtXML(x.Fault.FaultDetail)
}
}
}

func (cmd *esxcli) Run(ctx context.Context, f *flag.FlagSet) error {
if f.NArg() == 0 {
return flag.ErrHelp
Expand All @@ -90,6 +131,9 @@ func (cmd *esxcli) Run(ctx context.Context, f *flag.FlagSet) error {
if err != nil {
return err
}
if cmd.trace {
e.Trace = cmd.Trace
}

res, err := e.Run(f.Args())
if err != nil {
Expand Down Expand Up @@ -117,6 +161,10 @@ type result struct {
cmd *esxcli
}

func (r *result) Dump() interface{} {
return r.Response
}

func (r *result) Write(w io.Writer) error {
var formatType string
if r.cmd.hints {
Expand Down
58 changes: 37 additions & 21 deletions cli/host/esxcli/executor.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright (c) 2014-2023 VMware, Inc. All Rights Reserved.
Copyright (c) 2024-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.
Expand Down Expand Up @@ -49,6 +49,8 @@ type Executor struct {
mme *internal.ReflectManagedMethodExecuter
dtm *internal.InternalDynamicTypeManager
info map[string]*CommandInfo

Trace func(*internal.ExecuteSoapRequest, *internal.ExecuteSoapResponse)
}

func NewExecutor(c *vim25.Client, host *object.HostSystem) (*Executor, error) {
Expand Down Expand Up @@ -88,32 +90,42 @@ func NewExecutor(c *vim25.Client, host *object.HostSystem) (*Executor, error) {
return e, nil
}

func (e *Executor) CommandInfo(c *Command) (*CommandInfoMethod, error) {
ns := c.Namespace()
var info *CommandInfo
var ok bool

if info, ok = e.info[ns]; !ok {
req := internal.ExecuteSoapRequest{
Moid: "ha-dynamic-type-manager-local-cli-cliinfo",
Method: "vim.CLIInfo.FetchCLIInfo",
Argument: []internal.ReflectManagedMethodExecuterSoapArgument{
c.Argument("typeName", "vim.EsxCLI."+ns),
},
}
func (e *Executor) CommandInfo(ns string) (*CommandInfo, error) {
info, ok := e.info[ns]
if ok {
return info, nil
}

info = new(CommandInfo)
if err := e.Execute(&req, info); err != nil {
return nil, err
}
req := internal.ExecuteSoapRequest{
Moid: "ha-dynamic-type-manager-local-cli-cliinfo",
Method: "vim.CLIInfo.FetchCLIInfo",
Argument: []internal.ReflectManagedMethodExecuterSoapArgument{
NewCommand(nil).Argument("typeName", "vim.EsxCLI."+ns),
},
}

e.info[ns] = info
info = new(CommandInfo)
if err := e.Execute(&req, info); err != nil {
return nil, err
}

e.info[ns] = info

return info, nil
}

func (e *Executor) CommandInfoMethod(c *Command) (*CommandInfoMethod, error) {
ns := c.Namespace()

info, err := e.CommandInfo(ns)
if err != nil {
return nil, err
}

name := c.Name()
for _, method := range info.Method {
if method.Name == name {
return method, nil
return &method, nil
}
}

Expand All @@ -123,7 +135,7 @@ func (e *Executor) CommandInfo(c *Command) (*CommandInfoMethod, error) {
func (e *Executor) NewRequest(args []string) (*internal.ExecuteSoapRequest, *CommandInfoMethod, error) {
c := NewCommand(args)

info, err := e.CommandInfo(c)
info, err := e.CommandInfoMethod(c)
if err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -152,6 +164,10 @@ func (e *Executor) Execute(req *internal.ExecuteSoapRequest, res interface{}) er
return err
}

if e.Trace != nil {
e.Trace(req, x)
}

if x.Returnval != nil {
if x.Returnval.Fault != nil {
return &Fault{
Expand Down
Loading

0 comments on commit 9322377

Please sign in to comment.