Skip to content

Commit 9322377

Browse files
committed
vcsim: add esxcli support
Signed-off-by: Doug MacEachern <[email protected]>
1 parent 8101bae commit 9322377

File tree

15 files changed

+5206
-43
lines changed

15 files changed

+5206
-43
lines changed

cli/host/esxcli/command.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2014-2023 VMware, Inc. All Rights Reserved.
2+
Copyright (c) 2024-2024 VMware, Inc. All Rights Reserved.
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -57,7 +57,7 @@ type CommandInfoMethod struct {
5757

5858
type CommandInfo struct {
5959
CommandInfoItem
60-
Method []*CommandInfoMethod `xml:"method" json:"method"`
60+
Method []CommandInfoMethod `xml:"method" json:"method"`
6161
}
6262

6363
func NewCommand(args []string) *Command {

cli/host/esxcli/esxcli.go

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2014-2023 VMware, Inc. All Rights Reserved.
2+
Copyright (c) 2024-2024 VMware, Inc. All Rights Reserved.
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -22,18 +22,24 @@ import (
2222
"flag"
2323
"fmt"
2424
"io"
25+
"os"
26+
"os/exec"
2527
"sort"
2628
"strings"
2729
"text/tabwriter"
2830

31+
"github.com/dougm/pretty"
32+
2933
"github.com/vmware/govmomi/cli"
3034
"github.com/vmware/govmomi/cli/flags"
35+
"github.com/vmware/govmomi/internal"
3136
)
3237

3338
type esxcli struct {
3439
*flags.HostSystemFlag
3540

3641
hints bool
42+
trace bool
3743
}
3844

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

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

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

83+
func fmtXML(s string) {
84+
cmd := exec.Command("xmlstarlet", "fo")
85+
cmd.Stdout = os.Stderr
86+
cmd.Stderr = os.Stderr
87+
cmd.Stdin = strings.NewReader(s)
88+
if err := cmd.Run(); err != nil {
89+
panic(err) // yes xmlstarlet is required (your eyes will thank you)
90+
}
91+
}
92+
93+
func (cmd *esxcli) Trace(req *internal.ExecuteSoapRequest, res *internal.ExecuteSoapResponse) {
94+
x := res.Returnval
95+
96+
if req.Moid == "ha-dynamic-type-manager-local-cli-cliinfo" {
97+
if x.Fault == nil {
98+
return // TODO: option to trace this
99+
}
100+
}
101+
102+
pretty.Fprintf(os.Stderr, "%# v\n", req)
103+
104+
if x.Fault == nil {
105+
fmtXML(res.Returnval.Response)
106+
} else {
107+
fmt.Fprintln(os.Stderr, "Message=", x.Fault.FaultMsg)
108+
if x.Fault.FaultDetail != "" {
109+
fmt.Fprint(os.Stderr, "Detail=")
110+
fmtXML(x.Fault.FaultDetail)
111+
}
112+
}
113+
}
114+
74115
func (cmd *esxcli) Run(ctx context.Context, f *flag.FlagSet) error {
75116
if f.NArg() == 0 {
76117
return flag.ErrHelp
@@ -90,6 +131,9 @@ func (cmd *esxcli) Run(ctx context.Context, f *flag.FlagSet) error {
90131
if err != nil {
91132
return err
92133
}
134+
if cmd.trace {
135+
e.Trace = cmd.Trace
136+
}
93137

94138
res, err := e.Run(f.Args())
95139
if err != nil {
@@ -117,6 +161,10 @@ type result struct {
117161
cmd *esxcli
118162
}
119163

164+
func (r *result) Dump() interface{} {
165+
return r.Response
166+
}
167+
120168
func (r *result) Write(w io.Writer) error {
121169
var formatType string
122170
if r.cmd.hints {

cli/host/esxcli/executor.go

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2014-2023 VMware, Inc. All Rights Reserved.
2+
Copyright (c) 2024-2024 VMware, Inc. All Rights Reserved.
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -49,6 +49,8 @@ type Executor struct {
4949
mme *internal.ReflectManagedMethodExecuter
5050
dtm *internal.InternalDynamicTypeManager
5151
info map[string]*CommandInfo
52+
53+
Trace func(*internal.ExecuteSoapRequest, *internal.ExecuteSoapResponse)
5254
}
5355

5456
func NewExecutor(c *vim25.Client, host *object.HostSystem) (*Executor, error) {
@@ -88,32 +90,42 @@ func NewExecutor(c *vim25.Client, host *object.HostSystem) (*Executor, error) {
8890
return e, nil
8991
}
9092

91-
func (e *Executor) CommandInfo(c *Command) (*CommandInfoMethod, error) {
92-
ns := c.Namespace()
93-
var info *CommandInfo
94-
var ok bool
95-
96-
if info, ok = e.info[ns]; !ok {
97-
req := internal.ExecuteSoapRequest{
98-
Moid: "ha-dynamic-type-manager-local-cli-cliinfo",
99-
Method: "vim.CLIInfo.FetchCLIInfo",
100-
Argument: []internal.ReflectManagedMethodExecuterSoapArgument{
101-
c.Argument("typeName", "vim.EsxCLI."+ns),
102-
},
103-
}
93+
func (e *Executor) CommandInfo(ns string) (*CommandInfo, error) {
94+
info, ok := e.info[ns]
95+
if ok {
96+
return info, nil
97+
}
10498

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

110-
e.info[ns] = info
107+
info = new(CommandInfo)
108+
if err := e.Execute(&req, info); err != nil {
109+
return nil, err
110+
}
111+
112+
e.info[ns] = info
113+
114+
return info, nil
115+
}
116+
117+
func (e *Executor) CommandInfoMethod(c *Command) (*CommandInfoMethod, error) {
118+
ns := c.Namespace()
119+
120+
info, err := e.CommandInfo(ns)
121+
if err != nil {
122+
return nil, err
111123
}
112124

113125
name := c.Name()
114126
for _, method := range info.Method {
115127
if method.Name == name {
116-
return method, nil
128+
return &method, nil
117129
}
118130
}
119131

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

126-
info, err := e.CommandInfo(c)
138+
info, err := e.CommandInfoMethod(c)
127139
if err != nil {
128140
return nil, nil, err
129141
}
@@ -152,6 +164,10 @@ func (e *Executor) Execute(req *internal.ExecuteSoapRequest, res interface{}) er
152164
return err
153165
}
154166

167+
if e.Trace != nil {
168+
e.Trace(req, x)
169+
}
170+
155171
if x.Returnval != nil {
156172
if x.Returnval.Fault != nil {
157173
return &Fault{

0 commit comments

Comments
 (0)