github.com/vmware/govmomi@v0.51.0/simulator/esxcli.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 simulator
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"reflect"
    11  	"strconv"
    12  	"strings"
    13  	"time"
    14  
    15  	esxcli "github.com/vmware/govmomi/cli/esx"
    16  	"github.com/vmware/govmomi/internal"
    17  	"github.com/vmware/govmomi/simulator/esx"
    18  	"github.com/vmware/govmomi/vim25/mo"
    19  	"github.com/vmware/govmomi/vim25/soap"
    20  	"github.com/vmware/govmomi/vim25/types"
    21  	"github.com/vmware/govmomi/vim25/xml"
    22  )
    23  
    24  type DynamicTypeManager struct {
    25  	types.ManagedObjectReference
    26  }
    27  
    28  type ManagedMethodExecuter struct {
    29  	types.ManagedObjectReference
    30  
    31  	h *HostSystem
    32  }
    33  
    34  var esxcliNotFound = &types.LocalizedMethodFault{
    35  	Fault:            new(types.NotFound),
    36  	LocalizedMessage: "The object or item referred to could not be found.",
    37  }
    38  
    39  func esxcliFault(msg ...string) *types.LocalizedMethodFault {
    40  	return &types.LocalizedMethodFault{
    41  		Fault:            &internal.VimEsxCLICLIFault{ErrMsg: msg},
    42  		LocalizedMessage: "EsxCLI.CLIFault.summary",
    43  	}
    44  }
    45  
    46  func (h *HostSystem) RetrieveManagedMethodExecuter(ctx *Context, req *internal.RetrieveManagedMethodExecuterRequest) soap.HasFault {
    47  	if h.mme == nil {
    48  		h.mme = &ManagedMethodExecuter{
    49  			types.ManagedObjectReference{Type: "ManagedMethodExecuter", Value: h.Self.Value},
    50  			h,
    51  		}
    52  		ctx.Map.Put(h.mme)
    53  	}
    54  
    55  	return &internal.RetrieveManagedMethodExecuterBody{
    56  		Res: &internal.RetrieveManagedMethodExecuterResponse{
    57  			Returnval: &internal.ReflectManagedMethodExecuter{
    58  				ManagedObjectReference: h.mme.Reference(),
    59  			},
    60  		},
    61  	}
    62  }
    63  
    64  func (h *HostSystem) RetrieveDynamicTypeManager(ctx *Context, req *internal.RetrieveDynamicTypeManagerRequest) soap.HasFault {
    65  	if h.dtm == nil {
    66  		h.dtm = &DynamicTypeManager{
    67  			types.ManagedObjectReference{Type: "DynamicTypeManager", Value: h.Self.Value},
    68  		}
    69  		ctx.Map.Put(h.dtm)
    70  	}
    71  
    72  	return &internal.RetrieveDynamicTypeManagerBody{
    73  		Res: &internal.RetrieveDynamicTypeManagerResponse{
    74  			Returnval: &internal.InternalDynamicTypeManager{
    75  				ManagedObjectReference: h.dtm.Reference(),
    76  			},
    77  		},
    78  	}
    79  }
    80  
    81  func (*DynamicTypeManager) DynamicTypeMgrQueryTypeInfo(ctx *Context, req *internal.DynamicTypeMgrQueryTypeInfoRequest) soap.HasFault {
    82  	all := esx.TypeInfo
    83  
    84  	if spec, ok := req.FilterSpec.(*internal.DynamicTypeMgrTypeFilterSpec); ok {
    85  		all = internal.DynamicTypeMgrAllTypeInfo{}
    86  
    87  		for _, info := range esx.TypeInfo.DataTypeInfo {
    88  			if strings.Contains(info.Name, spec.TypeSubstr) {
    89  				all.DataTypeInfo = append(all.DataTypeInfo, info)
    90  			}
    91  		}
    92  
    93  		for _, info := range esx.TypeInfo.EnumTypeInfo {
    94  			if strings.Contains(info.Name, spec.TypeSubstr) {
    95  				all.EnumTypeInfo = append(all.EnumTypeInfo, info)
    96  			}
    97  		}
    98  
    99  		for _, info := range esx.TypeInfo.ManagedTypeInfo {
   100  			if strings.Contains(info.Name, spec.TypeSubstr) {
   101  				all.ManagedTypeInfo = append(all.ManagedTypeInfo, info)
   102  			}
   103  		}
   104  	}
   105  
   106  	body := &internal.DynamicTypeMgrQueryTypeInfoBody{
   107  		Res: &internal.DynamicTypeMgrQueryTypeInfoResponse{
   108  			Returnval: all,
   109  		},
   110  	}
   111  
   112  	return body
   113  }
   114  
   115  func (m *DynamicTypeManager) DynamicTypeMgrQueryMoInstances(ctx *Context, req *internal.DynamicTypeMgrQueryMoInstancesRequest) soap.HasFault {
   116  	body := &internal.DynamicTypeMgrQueryMoInstancesBody{
   117  		Res: &internal.DynamicTypeMgrQueryMoInstancesResponse{
   118  			Returnval: nil,
   119  		},
   120  	}
   121  
   122  	return body
   123  }
   124  
   125  func (m *ManagedMethodExecuter) VimCLIInfoFetchCLIInfo(_ *Context, args esxcli.Values) (*esxcli.CommandInfo, *types.LocalizedMethodFault) {
   126  	kind := args.Value("typeName")
   127  	kind = strings.TrimPrefix(kind, "vim.EsxCLI.")
   128  
   129  	for _, info := range esx.CommandInfo {
   130  		if info.CommandInfoItem.Name == kind {
   131  			return &info, nil
   132  		}
   133  	}
   134  
   135  	return nil, esxcliNotFound
   136  }
   137  
   138  // sample from: govc host.esxcli -dump software vib get
   139  var softwareVib = []esxcli.Values{
   140  	{
   141  		"AcceptanceLevel":         []string{"VMwareCertified"},
   142  		"CreationDate":            []string{"2023-03-22"},
   143  		"Depends":                 []string{"esx-version >= 5.0.0"},
   144  		"Description":             []string{"An embedded web UI for ESXi"},
   145  		"ID":                      []string{"VMware_bootbank_esx-ui_2.12.0-21482143"},
   146  		"InstallDate":             []string{"2023-03-28"},
   147  		"LiveInstallAllowed":      []string{"True"},
   148  		"LiveRemoveAllowed":       []string{"True"},
   149  		"MaintenanceModeRequired": []string{"False"},
   150  		"Name":                    []string{"esx-ui"},
   151  		"Overlay":                 []string{"False"},
   152  		"Payloads":                []string{"esx-ui"},
   153  		"Platforms":               []string{"host"},
   154  		"StatelessReady":          []string{"True"},
   155  		"Status":                  []string{""},
   156  		"Summary":                 []string{"VMware Host Client"},
   157  		"Type":                    []string{"bootbank"},
   158  		"Vendor":                  []string{"VMware"},
   159  		"Version":                 []string{"2.12.0-21482143"},
   160  	},
   161  	{
   162  		"AcceptanceLevel":         []string{"VMwareCertified"},
   163  		"CreationDate":            []string{"2023-03-25"},
   164  		"Depends":                 []string{"vmkapi_2_11_0_0", "vmkapi_incompat_2_11_0_0"},
   165  		"Description":             []string{"Intel DW GPIO controller driver"},
   166  		"ID":                      []string{"VMW_bootbank_intelgpio_0.1-1vmw.801.0.0.21495797"},
   167  		"InstallDate":             []string{"2023-03-28"},
   168  		"LiveInstallAllowed":      []string{"False"},
   169  		"LiveRemoveAllowed":       []string{"False"},
   170  		"MaintenanceModeRequired": []string{"True"},
   171  		"Name":                    []string{"intelgpio"},
   172  		"Overlay":                 []string{"False"},
   173  		"Payloads":                []string{"intelgpi"},
   174  		"Platforms":               []string{"host"},
   175  		"StatelessReady":          []string{"True"},
   176  		"Status":                  []string{""},
   177  		"Summary":                 []string{"VMware Esx VIB"},
   178  		"Tags":                    []string{"RestrictStickyFiles", "module", "driver", "sdkname:esx", "sdkversion:8.0.1-21495797"},
   179  		"Type":                    []string{"bootbank"},
   180  		"Vendor":                  []string{"VMW"},
   181  		"Version":                 []string{"0.1-1vmw.801.0.0.21495797"},
   182  	},
   183  }
   184  
   185  func (m *ManagedMethodExecuter) VimEsxCLISoftwareVibGet(_ *Context, args esxcli.Values) (*esxcli.Response, *types.LocalizedMethodFault) {
   186  	r := esxcli.Response{Kind: "VIBExt"}
   187  
   188  	name := args.Value("vibname")
   189  
   190  	if name != "" {
   191  		for _, vib := range softwareVib {
   192  			if vib.Value("Name") == name {
   193  				r.Values = append(r.Values, vib)
   194  				return &r, nil
   195  			}
   196  		}
   197  		return nil, esxcliFault("[NoMatchError]", "id="+name)
   198  	}
   199  
   200  	r.Values = softwareVib
   201  
   202  	return &r, nil
   203  }
   204  
   205  func (m *ManagedMethodExecuter) VimEsxCLISoftwareVibList(_ *Context, args esxcli.Values) (*esxcli.Response, *types.LocalizedMethodFault) {
   206  	r := esxcli.Response{Kind: "SummaryExt"}
   207  
   208  	r.Values = softwareVib // TODO: subset of VibGet fields
   209  
   210  	return &r, nil
   211  }
   212  
   213  func (m *ManagedMethodExecuter) VimEsxCLIHardwareClockGet(_ *Context, _ esxcli.Values) (*esxcli.Response, *types.LocalizedMethodFault) {
   214  	return &esxcli.Response{
   215  		Kind:   "string",
   216  		String: time.Now().UTC().Format(time.RFC3339),
   217  	}, nil
   218  }
   219  
   220  func (m *ManagedMethodExecuter) VimEsxCLINetworkFirewallGet(ctx *Context, args esxcli.Values) (*esxcli.Response, *types.LocalizedMethodFault) {
   221  	r := esxcli.Response{
   222  		Kind: "Firewall",
   223  		Values: []esxcli.Values{{
   224  			"DefaultAction": []string{"DROP"},
   225  			"Enabled":       []string{"false"},
   226  			"Loaded":        []string{"true"},
   227  		}},
   228  	}
   229  
   230  	return &r, nil
   231  }
   232  
   233  func (m *ManagedMethodExecuter) VimEsxCLINetworkVmList(ctx *Context, _ esxcli.Values) (*esxcli.Response, *types.LocalizedMethodFault) {
   234  	r := esxcli.Response{Kind: "VM"}
   235  
   236  	for _, ref := range m.h.Vm {
   237  		vm := ctx.Map.Get(ref).(*VirtualMachine)
   238  
   239  		var networks []string
   240  		for _, ref := range vm.Network {
   241  			name := entityName(ctx.Map.Get(ref).(mo.Entity))
   242  			networks = append(networks, name)
   243  		}
   244  
   245  		r.Values = append(r.Values, esxcli.Values{
   246  			"Name":     []string{vm.Name},
   247  			"Networks": networks,
   248  			"NumPorts": []string{strconv.Itoa(len(networks))},
   249  			"WorldID":  []string{strconv.Itoa(vm.worldID())},
   250  		})
   251  	}
   252  
   253  	return &r, nil
   254  }
   255  
   256  // sample from: govc host.esxcli -dump network ip connection list
   257  var networkIpConnectionList = []esxcli.Values{
   258  	{
   259  		"CCAlgo":         []string{"newreno"},
   260  		"ForeignAddress": []string{"0.0.0.0:0"},
   261  		"LocalAddress":   []string{"0.0.0.0:443"},
   262  		"Proto":          []string{"tcp"},
   263  		"RecvQ":          []string{"0"},
   264  		"SendQ":          []string{"0"},
   265  		"State":          []string{"LISTEN"},
   266  		"WorldID":        []string{"525276"},
   267  		"WorldName":      []string{"envoy"},
   268  	},
   269  	{
   270  		"CCAlgo":         []string{""},
   271  		"ForeignAddress": []string{"0.0.0.0:0"},
   272  		"LocalAddress":   []string{"127.0.0.1:123"},
   273  		"Proto":          []string{"udp"},
   274  		"RecvQ":          []string{"0"},
   275  		"SendQ":          []string{"0"},
   276  		"State":          []string{""},
   277  		"WorldID":        []string{"530726"},
   278  		"WorldName":      []string{"ntpd"},
   279  	},
   280  }
   281  
   282  func (m *ManagedMethodExecuter) VimEsxCLINetworkIpConnectionList(_ *Context, args esxcli.Values) (*esxcli.Response, *types.LocalizedMethodFault) {
   283  	r := esxcli.Response{Kind: "IpConnection"}
   284  
   285  	kind := args.Value("type")
   286  	if kind != "" && kind != "tcp" { // ip, tcp, udp, all
   287  		return nil, esxcliFault("Invalid data constraint for parameter 'type'.")
   288  	}
   289  
   290  	r.Values = networkIpConnectionList
   291  
   292  	return &r, nil
   293  }
   294  
   295  // sample from: govc host.esxcli -dump system settings advanced list
   296  var systemSettingsAdvancedList = []esxcli.Values{
   297  	{
   298  		"DefaultIntValue": []string{"2"},
   299  		"Description":     []string{"PShare salting allows for sharing isolation between multiple VM"},
   300  		"HostSpecific":    []string{"false"},
   301  		"Impact":          []string{"none"},
   302  		"IntValue":        []string{"2"},
   303  		"MaxValue":        []string{"2"},
   304  		"MinValue":        []string{"0"},
   305  		"Path":            []string{"/Mem/ShareForceSalting"},
   306  		"Type":            []string{"integer"},
   307  	},
   308  	{
   309  		"DefaultIntValue": []string{"0"},
   310  		"Description":     []string{"Enable guest arp inspection IOChain to get IP"},
   311  		"HostSpecific":    []string{"false"},
   312  		"Impact":          []string{"none"},
   313  		"IntValue":        []string{"1"},
   314  		"MaxValue":        []string{"1"},
   315  		"MinValue":        []string{"0"},
   316  		"Path":            []string{"/Net/GuestIPHack"},
   317  		"Type":            []string{"integer"},
   318  	},
   319  }
   320  
   321  func (m *ManagedMethodExecuter) VimEsxCLISystemSettingsAdvancedList(_ *Context, args esxcli.Values) (*esxcli.Response, *types.LocalizedMethodFault) {
   322  	r := esxcli.Response{Kind: "SettingsAdvancedOption"}
   323  
   324  	option := args.Value("option")
   325  	if option != "" {
   326  		for _, s := range systemSettingsAdvancedList {
   327  			if s.Value("Path") == option {
   328  				r.Values = append(r.Values, s)
   329  				return &r, nil
   330  			}
   331  		}
   332  		return nil, esxcliFault("Unable to find option")
   333  	}
   334  
   335  	r.Values = systemSettingsAdvancedList
   336  
   337  	return &r, nil
   338  }
   339  
   340  func (m *ManagedMethodExecuter) VimEsxCLIVmProcessList(ctx *Context, _ esxcli.Values) (*esxcli.Response, *types.LocalizedMethodFault) {
   341  	r := esxcli.Response{Kind: "VirtualMachine"}
   342  
   343  	for _, ref := range m.h.Vm {
   344  		vm := ctx.Map.Get(ref).(*VirtualMachine)
   345  
   346  		r.Values = append(r.Values, esxcli.Values{
   347  			"ConfigFile":  []string{vm.Config.Files.VmPathName},
   348  			"DisplayName": []string{vm.Name},
   349  			"ProcessID":   []string{"0"},
   350  			"UUID":        []string{vm.uid.String()},
   351  			"VMXCartelID": []string{strconv.Itoa(vm.worldID() + 1)},
   352  			"WorldID":     []string{strconv.Itoa(vm.worldID())},
   353  		})
   354  	}
   355  
   356  	return &r, nil
   357  }
   358  
   359  func (m *ManagedMethodExecuter) VimEsxCLIIscsiSoftwareGet(_ *Context, _ esxcli.Values) (*esxcli.Response, *types.LocalizedMethodFault) {
   360  	return &esxcli.Response{Kind: "boolean", String: "false"}, nil
   361  }
   362  
   363  var boot = time.Now()
   364  
   365  func (m *ManagedMethodExecuter) VimEsxCLISystemStatsUptimeGet(_ *Context, _ esxcli.Values) (*esxcli.Response, *types.LocalizedMethodFault) {
   366  	uptime := fmt.Sprintf("%d", time.Since(boot))
   367  	return &esxcli.Response{Kind: "long", String: uptime}, nil
   368  }
   369  
   370  func (_ *ManagedMethodExecuter) toXML(v any) string {
   371  	var out bytes.Buffer
   372  
   373  	err := xml.NewEncoder(&out).Encode(v)
   374  	if err != nil {
   375  		panic(err)
   376  	}
   377  
   378  	return out.String()
   379  }
   380  
   381  func (m *ManagedMethodExecuter) ExecuteSoap(ctx *Context, req *internal.ExecuteSoapRequest) soap.HasFault {
   382  	res := new(internal.ReflectManagedMethodExecuterSoapResult)
   383  
   384  	args := esxcli.Values{}
   385  	for _, arg := range req.Argument {
   386  		args[arg.Name] = arg.Value()
   387  	}
   388  
   389  	name := internal.EsxcliName(req.Method)
   390  	method := reflect.ValueOf(m).MethodByName(name)
   391  
   392  	var val types.AnyType
   393  	err := esxcliNotFound
   394  
   395  	if method.IsValid() {
   396  		ret := method.Call([]reflect.Value{reflect.ValueOf(ctx), reflect.ValueOf(args)})
   397  		val = ret[0].Interface()
   398  		err = ret[1].Interface().(*types.LocalizedMethodFault)
   399  	}
   400  
   401  	if err == nil {
   402  		if r, ok := val.(*esxcli.Response); ok {
   403  			if r.String == "" {
   404  				// DataObject xsi:type has method name prefix
   405  				r.Kind = strings.ReplaceAll(ucFirst(req.Method), ".", "") + r.Kind
   406  			}
   407  		}
   408  		res.Response = m.toXML(val)
   409  	} else {
   410  		res.Fault = &internal.ReflectManagedMethodExecuterSoapFault{
   411  			FaultMsg:    err.LocalizedMessage,
   412  			FaultDetail: m.toXML(err),
   413  		}
   414  	}
   415  
   416  	return &internal.ExecuteSoapBody{
   417  		Res: &internal.ExecuteSoapResponse{
   418  			Returnval: res,
   419  		},
   420  	}
   421  }