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  }