github.com/vmware/govmomi@v0.51.0/cli/esx/executor.go (about) 1 // © Broadcom. All Rights Reserved. 2 // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 3 // SPDX-License-Identifier: Apache-2.0 4 5 package esx 6 7 import ( 8 "context" 9 "fmt" 10 11 "github.com/vmware/govmomi/internal" 12 "github.com/vmware/govmomi/vim25" 13 "github.com/vmware/govmomi/vim25/mo" 14 "github.com/vmware/govmomi/vim25/types" 15 "github.com/vmware/govmomi/vim25/xml" 16 ) 17 18 type Fault struct { 19 Message string `json:"message"` 20 Detail string `json:"detail"` 21 } 22 23 func (f Fault) Error() string { 24 return f.Message 25 } 26 27 func (f Fault) MessageDetail() string { 28 if f.Detail != "" { 29 return fmt.Sprintf("%s %s", f.Message, f.Detail) 30 } 31 32 return f.Message 33 } 34 35 type Executor struct { 36 c *vim25.Client 37 host mo.Reference 38 mme *internal.ReflectManagedMethodExecuter 39 dtm *internal.InternalDynamicTypeManager 40 info map[string]*CommandInfo 41 42 Trace func(*internal.ExecuteSoapRequest, *internal.ExecuteSoapResponse) 43 } 44 45 func NewExecutor(ctx context.Context, c *vim25.Client, host mo.Reference) (*Executor, error) { 46 e := &Executor{ 47 c: c, 48 host: host, 49 info: make(map[string]*CommandInfo), 50 } 51 52 { 53 req := internal.RetrieveManagedMethodExecuterRequest{ 54 This: host.Reference(), 55 } 56 57 res, err := internal.RetrieveManagedMethodExecuter(ctx, c, &req) 58 if err != nil { 59 return nil, err 60 } 61 62 e.mme = res.Returnval 63 } 64 65 { 66 req := internal.RetrieveDynamicTypeManagerRequest{ 67 This: host.Reference(), 68 } 69 70 res, err := internal.RetrieveDynamicTypeManager(ctx, c, &req) 71 if err != nil { 72 return nil, err 73 } 74 75 e.dtm = res.Returnval 76 } 77 78 return e, nil 79 } 80 81 func (e *Executor) Client() *vim25.Client { 82 return e.c 83 } 84 85 func (e *Executor) DynamicTypeManager() types.ManagedObjectReference { 86 return e.dtm.ManagedObjectReference 87 } 88 89 func (e *Executor) CommandInfo(ctx context.Context, ns string) (*CommandInfo, error) { 90 info, ok := e.info[ns] 91 if ok { 92 return info, nil 93 } 94 95 req := internal.ExecuteSoapRequest{ 96 Moid: "ha-dynamic-type-manager-local-cli-cliinfo", 97 Method: "vim.CLIInfo.FetchCLIInfo", 98 Argument: []internal.ReflectManagedMethodExecuterSoapArgument{ 99 NewCommand(nil).Argument("typeName", "vim.EsxCLI."+ns), 100 }, 101 } 102 103 info = new(CommandInfo) 104 if err := e.Execute(ctx, &req, info); err != nil { 105 return nil, err 106 } 107 108 e.info[ns] = info 109 110 return info, nil 111 } 112 113 func (e *Executor) CommandInfoMethod(ctx context.Context, c *Command) (*CommandInfoMethod, error) { 114 ns := c.Namespace() 115 116 info, err := e.CommandInfo(ctx, ns) 117 if err != nil { 118 return nil, err 119 } 120 121 name := c.Name() 122 for _, method := range info.Method { 123 if method.Name == name { 124 return &method, nil 125 } 126 } 127 128 return nil, fmt.Errorf("method '%s' not found in name space '%s'", name, c.Namespace()) 129 } 130 131 func (e *Executor) NewRequest(ctx context.Context, args []string) (*internal.ExecuteSoapRequest, *CommandInfoMethod, error) { 132 c := NewCommand(args) 133 134 info, err := e.CommandInfoMethod(ctx, c) 135 if err != nil { 136 return nil, nil, err 137 } 138 139 sargs, err := c.Parse(info.Param) 140 if err != nil { 141 return nil, nil, err 142 } 143 144 sreq := internal.ExecuteSoapRequest{ 145 Moid: c.Moid(), 146 Method: c.Method(), 147 Argument: sargs, 148 } 149 150 return &sreq, info, nil 151 } 152 153 func (e *Executor) Execute(ctx context.Context, req *internal.ExecuteSoapRequest, res any) error { 154 req.This = e.mme.ManagedObjectReference 155 req.Version = "urn:vim25/5.0" 156 157 x, err := internal.ExecuteSoap(ctx, e.c, req) 158 if err != nil { 159 return err 160 } 161 162 if e.Trace != nil { 163 e.Trace(req, x) 164 } 165 166 if x.Returnval != nil { 167 if x.Returnval.Fault != nil { 168 return &Fault{ 169 x.Returnval.Fault.FaultMsg, 170 x.Returnval.Fault.FaultDetail, 171 } 172 } 173 174 if err := xml.Unmarshal([]byte(x.Returnval.Response), res); err != nil { 175 return err 176 } 177 } 178 179 return nil 180 } 181 182 func (e *Executor) Run(ctx context.Context, args []string) (*Response, error) { 183 req, info, err := e.NewRequest(ctx, args) 184 if err != nil { 185 return nil, err 186 } 187 188 res := &Response{ 189 Info: info, 190 } 191 192 if err := e.Execute(ctx, req, res); err != nil { 193 return nil, err 194 } 195 196 return res, nil 197 }