github.com/vmware/govmomi@v0.43.0/govc/host/esxcli/executor.go (about) 1 /* 2 Copyright (c) 2014-2023 VMware, Inc. All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package esxcli 18 19 import ( 20 "context" 21 "fmt" 22 23 "github.com/vmware/govmomi/internal" 24 "github.com/vmware/govmomi/object" 25 "github.com/vmware/govmomi/vim25" 26 "github.com/vmware/govmomi/vim25/xml" 27 ) 28 29 type Fault struct { 30 Message string `json:"message"` 31 Detail string `json:"detail"` 32 } 33 34 func (f Fault) Error() string { 35 return f.Message 36 } 37 38 func (f Fault) messageDetail() string { 39 if f.Detail != "" { 40 return fmt.Sprintf("%s %s", f.Message, f.Detail) 41 } 42 43 return f.Message 44 } 45 46 type Executor struct { 47 c *vim25.Client 48 host *object.HostSystem 49 mme *internal.ReflectManagedMethodExecuter 50 dtm *internal.InternalDynamicTypeManager 51 info map[string]*CommandInfo 52 } 53 54 func NewExecutor(c *vim25.Client, host *object.HostSystem) (*Executor, error) { 55 ctx := context.TODO() 56 e := &Executor{ 57 c: c, 58 host: host, 59 info: make(map[string]*CommandInfo), 60 } 61 62 { 63 req := internal.RetrieveManagedMethodExecuterRequest{ 64 This: host.Reference(), 65 } 66 67 res, err := internal.RetrieveManagedMethodExecuter(ctx, c, &req) 68 if err != nil { 69 return nil, err 70 } 71 72 e.mme = res.Returnval 73 } 74 75 { 76 req := internal.RetrieveDynamicTypeManagerRequest{ 77 This: host.Reference(), 78 } 79 80 res, err := internal.RetrieveDynamicTypeManager(ctx, c, &req) 81 if err != nil { 82 return nil, err 83 } 84 85 e.dtm = res.Returnval 86 } 87 88 return e, nil 89 } 90 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 } 104 105 info = new(CommandInfo) 106 if err := e.Execute(&req, info); err != nil { 107 return nil, err 108 } 109 110 e.info[ns] = info 111 } 112 113 name := c.Name() 114 for _, method := range info.Method { 115 if method.Name == name { 116 return method, nil 117 } 118 } 119 120 return nil, fmt.Errorf("method '%s' not found in name space '%s'", name, c.Namespace()) 121 } 122 123 func (e *Executor) NewRequest(args []string) (*internal.ExecuteSoapRequest, *CommandInfoMethod, error) { 124 c := NewCommand(args) 125 126 info, err := e.CommandInfo(c) 127 if err != nil { 128 return nil, nil, err 129 } 130 131 sargs, err := c.Parse(info.Param) 132 if err != nil { 133 return nil, nil, err 134 } 135 136 sreq := internal.ExecuteSoapRequest{ 137 Moid: c.Moid(), 138 Method: c.Method(), 139 Argument: sargs, 140 } 141 142 return &sreq, info, nil 143 } 144 145 func (e *Executor) Execute(req *internal.ExecuteSoapRequest, res interface{}) error { 146 ctx := context.TODO() 147 req.This = e.mme.ManagedObjectReference 148 req.Version = "urn:vim25/5.0" 149 150 x, err := internal.ExecuteSoap(ctx, e.c, req) 151 if err != nil { 152 return err 153 } 154 155 if x.Returnval != nil { 156 if x.Returnval.Fault != nil { 157 return &Fault{ 158 x.Returnval.Fault.FaultMsg, 159 x.Returnval.Fault.FaultDetail, 160 } 161 } 162 163 if err := xml.Unmarshal([]byte(x.Returnval.Response), res); err != nil { 164 return err 165 } 166 } 167 168 return nil 169 } 170 171 func (e *Executor) Run(args []string) (*Response, error) { 172 req, info, err := e.NewRequest(args) 173 if err != nil { 174 return nil, err 175 } 176 177 res := &Response{ 178 Info: info, 179 } 180 181 if err := e.Execute(req, res); err != nil { 182 return nil, err 183 } 184 185 return res, nil 186 }