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  }