github.com/vmware/govmomi@v0.51.0/vim25/types/helpers.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 types
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/json"
    10  	"fmt"
    11  	"net/url"
    12  	"reflect"
    13  	"strings"
    14  	"time"
    15  )
    16  
    17  func EnumValuesAsStrings[T ~string](enumValues []T) []string {
    18  	stringValues := make([]string, len(enumValues))
    19  	for i := range enumValues {
    20  		stringValues[i] = string(enumValues[i])
    21  	}
    22  	return stringValues
    23  }
    24  
    25  func New[T any](t T) *T {
    26  	return &t
    27  }
    28  
    29  func NewBool(v bool) *bool {
    30  	return &v
    31  }
    32  
    33  func NewInt32(v int32) *int32 {
    34  	return &v
    35  }
    36  
    37  func NewInt64(v int64) *int64 {
    38  	return &v
    39  }
    40  
    41  func NewTime(v time.Time) *time.Time {
    42  	return &v
    43  }
    44  
    45  func NewReference(r ManagedObjectReference) *ManagedObjectReference {
    46  	return &r
    47  }
    48  
    49  func (r ManagedObjectReference) Reference() ManagedObjectReference {
    50  	return r
    51  }
    52  
    53  func (r ManagedObjectReference) String() string {
    54  	return strings.Join([]string{r.Type, r.Value}, ":")
    55  }
    56  
    57  func (r *ManagedObjectReference) FromString(o string) bool {
    58  	s := strings.SplitN(o, ":", 2)
    59  
    60  	if len(s) != 2 {
    61  		return false
    62  	}
    63  
    64  	r.Type = s[0]
    65  	r.Value = s[1]
    66  
    67  	return true
    68  }
    69  
    70  // Encode ManagedObjectReference for use with URL and File paths
    71  func (r ManagedObjectReference) Encode() string {
    72  	return strings.Join([]string{r.Type, url.QueryEscape(r.Value)}, "-")
    73  }
    74  
    75  func (c *PerfCounterInfo) Name() string {
    76  	return c.GroupInfo.GetElementDescription().Key + "." + c.NameInfo.GetElementDescription().Key + "." + string(c.RollupType)
    77  }
    78  
    79  func defaultResourceAllocationInfo() ResourceAllocationInfo {
    80  	return ResourceAllocationInfo{
    81  		Reservation:           NewInt64(0),
    82  		ExpandableReservation: NewBool(true),
    83  		Limit:                 NewInt64(-1),
    84  		Shares: &SharesInfo{
    85  			Level: SharesLevelNormal,
    86  		},
    87  	}
    88  }
    89  
    90  // DefaultResourceConfigSpec returns a ResourceConfigSpec populated with the same default field values as vCenter.
    91  // Note that the wsdl marks these fields as optional, but they are required to be set when creating a resource pool.
    92  // They are only optional when updating a resource pool.
    93  func DefaultResourceConfigSpec() ResourceConfigSpec {
    94  	return ResourceConfigSpec{
    95  		CpuAllocation:    defaultResourceAllocationInfo(),
    96  		MemoryAllocation: defaultResourceAllocationInfo(),
    97  	}
    98  }
    99  
   100  // ToConfigSpec returns a VirtualMachineConfigSpec based on the
   101  // VirtualMachineConfigInfo.
   102  func (ci VirtualMachineConfigInfo) ToConfigSpec() VirtualMachineConfigSpec {
   103  	cs := VirtualMachineConfigSpec{
   104  		ChangeVersion:                ci.ChangeVersion,
   105  		Name:                         ci.Name,
   106  		Version:                      ci.Version,
   107  		CreateDate:                   ci.CreateDate,
   108  		Uuid:                         ci.Uuid,
   109  		InstanceUuid:                 ci.InstanceUuid,
   110  		NpivNodeWorldWideName:        ci.NpivNodeWorldWideName,
   111  		NpivPortWorldWideName:        ci.NpivPortWorldWideName,
   112  		NpivWorldWideNameType:        ci.NpivWorldWideNameType,
   113  		NpivDesiredNodeWwns:          ci.NpivDesiredNodeWwns,
   114  		NpivDesiredPortWwns:          ci.NpivDesiredPortWwns,
   115  		NpivTemporaryDisabled:        ci.NpivTemporaryDisabled,
   116  		NpivOnNonRdmDisks:            ci.NpivOnNonRdmDisks,
   117  		LocationId:                   ci.LocationId,
   118  		GuestId:                      ci.GuestId,
   119  		AlternateGuestName:           ci.AlternateGuestName,
   120  		Annotation:                   ci.Annotation,
   121  		Files:                        &ci.Files,
   122  		Tools:                        ci.Tools,
   123  		Flags:                        &ci.Flags,
   124  		ConsolePreferences:           ci.ConsolePreferences,
   125  		PowerOpInfo:                  &ci.DefaultPowerOps,
   126  		RebootPowerOff:               ci.RebootPowerOff,
   127  		NumCPUs:                      ci.Hardware.NumCPU,
   128  		VcpuConfig:                   ci.VcpuConfig,
   129  		NumCoresPerSocket:            ci.Hardware.NumCoresPerSocket,
   130  		MemoryMB:                     int64(ci.Hardware.MemoryMB),
   131  		MemoryHotAddEnabled:          ci.MemoryHotAddEnabled,
   132  		CpuHotAddEnabled:             ci.CpuHotAddEnabled,
   133  		CpuHotRemoveEnabled:          ci.CpuHotRemoveEnabled,
   134  		VirtualICH7MPresent:          ci.Hardware.VirtualICH7MPresent,
   135  		VirtualSMCPresent:            ci.Hardware.VirtualSMCPresent,
   136  		DeviceChange:                 nil, // See below
   137  		CpuAllocation:                ci.CpuAllocation,
   138  		MemoryAllocation:             ci.MemoryAllocation,
   139  		LatencySensitivity:           ci.LatencySensitivity,
   140  		CpuAffinity:                  ci.CpuAffinity,
   141  		MemoryAffinity:               ci.MemoryAffinity,
   142  		NetworkShaper:                ci.NetworkShaper,
   143  		CpuFeatureMask:               nil, // See below
   144  		ExtraConfig:                  ci.ExtraConfig,
   145  		SwapPlacement:                ci.SwapPlacement,
   146  		BootOptions:                  ci.BootOptions,
   147  		FtInfo:                       ci.FtInfo,
   148  		RepConfig:                    ci.RepConfig,
   149  		VAssertsEnabled:              ci.VAssertsEnabled,
   150  		ChangeTrackingEnabled:        ci.ChangeTrackingEnabled,
   151  		Firmware:                     ci.Firmware,
   152  		MaxMksConnections:            ci.MaxMksConnections,
   153  		GuestAutoLockEnabled:         ci.GuestAutoLockEnabled,
   154  		ManagedBy:                    ci.ManagedBy,
   155  		MemoryReservationLockedToMax: ci.MemoryReservationLockedToMax,
   156  		NestedHVEnabled:              ci.NestedHVEnabled,
   157  		VPMCEnabled:                  ci.VPMCEnabled,
   158  		MessageBusTunnelEnabled:      ci.MessageBusTunnelEnabled,
   159  		MigrateEncryption:            ci.MigrateEncryption,
   160  		FtEncryptionMode:             ci.FtEncryptionMode,
   161  		SevEnabled:                   ci.SevEnabled,
   162  		MotherboardLayout:            ci.Hardware.MotherboardLayout,
   163  		ScheduledHardwareUpgradeInfo: ci.ScheduledHardwareUpgradeInfo,
   164  		SgxInfo:                      ci.SgxInfo,
   165  		GuestMonitoringModeInfo:      ci.GuestMonitoringModeInfo,
   166  		PmemFailoverEnabled:          ci.PmemFailoverEnabled,
   167  		VmxStatsCollectionEnabled:    ci.VmxStatsCollectionEnabled,
   168  		VmOpNotificationToAppEnabled: ci.VmOpNotificationToAppEnabled,
   169  		VmOpNotificationTimeout:      ci.VmOpNotificationTimeout,
   170  		DeviceSwap:                   ci.DeviceSwap,
   171  		SimultaneousThreads:          ci.Hardware.SimultaneousThreads,
   172  		Pmem:                         ci.Pmem,
   173  		DeviceGroups:                 ci.DeviceGroups,
   174  		FixedPassthruHotPlugEnabled:  ci.FixedPassthruHotPlugEnabled,
   175  		MetroFtEnabled:               ci.MetroFtEnabled,
   176  		MetroFtHostGroup:             ci.MetroFtHostGroup,
   177  	}
   178  
   179  	// Unassign the Files field if all of its fields are empty.
   180  	if ci.Files.FtMetadataDirectory == "" && ci.Files.LogDirectory == "" &&
   181  		ci.Files.SnapshotDirectory == "" && ci.Files.SuspendDirectory == "" &&
   182  		ci.Files.VmPathName == "" {
   183  		cs.Files = nil
   184  	}
   185  
   186  	// Unassign the Flags field if all of its fields are empty.
   187  	if ci.Flags.CbrcCacheEnabled == nil &&
   188  		ci.Flags.DisableAcceleration == nil &&
   189  		ci.Flags.DiskUuidEnabled == nil &&
   190  		ci.Flags.EnableLogging == nil &&
   191  		ci.Flags.FaultToleranceType == "" &&
   192  		ci.Flags.HtSharing == "" &&
   193  		ci.Flags.MonitorType == "" &&
   194  		ci.Flags.RecordReplayEnabled == nil &&
   195  		ci.Flags.RunWithDebugInfo == nil &&
   196  		ci.Flags.SnapshotDisabled == nil &&
   197  		ci.Flags.SnapshotLocked == nil &&
   198  		ci.Flags.SnapshotPowerOffBehavior == "" &&
   199  		ci.Flags.UseToe == nil &&
   200  		ci.Flags.VbsEnabled == nil &&
   201  		ci.Flags.VirtualExecUsage == "" &&
   202  		ci.Flags.VirtualMmuUsage == "" &&
   203  		ci.Flags.VvtdEnabled == nil {
   204  		cs.Flags = nil
   205  	}
   206  
   207  	// Unassign the PowerOps field if all of its fields are empty.
   208  	if ci.DefaultPowerOps.DefaultPowerOffType == "" &&
   209  		ci.DefaultPowerOps.DefaultResetType == "" &&
   210  		ci.DefaultPowerOps.DefaultSuspendType == "" &&
   211  		ci.DefaultPowerOps.PowerOffType == "" &&
   212  		ci.DefaultPowerOps.ResetType == "" &&
   213  		ci.DefaultPowerOps.StandbyAction == "" &&
   214  		ci.DefaultPowerOps.SuspendType == "" {
   215  		cs.PowerOpInfo = nil
   216  	}
   217  
   218  	if l := len(ci.CpuFeatureMask); l > 0 {
   219  		cs.CpuFeatureMask = make([]VirtualMachineCpuIdInfoSpec, l)
   220  		for i := 0; i < l; i++ {
   221  			cs.CpuFeatureMask[i] = VirtualMachineCpuIdInfoSpec{
   222  				ArrayUpdateSpec: ArrayUpdateSpec{
   223  					Operation: ArrayUpdateOperationAdd,
   224  				},
   225  				Info: &HostCpuIdInfo{
   226  					Level:  ci.CpuFeatureMask[i].Level,
   227  					Vendor: ci.CpuFeatureMask[i].Vendor,
   228  					Eax:    ci.CpuFeatureMask[i].Eax,
   229  					Ebx:    ci.CpuFeatureMask[i].Ebx,
   230  					Ecx:    ci.CpuFeatureMask[i].Ecx,
   231  					Edx:    ci.CpuFeatureMask[i].Edx,
   232  				},
   233  			}
   234  		}
   235  	}
   236  
   237  	if l := len(ci.Hardware.Device); l > 0 {
   238  		cs.DeviceChange = make([]BaseVirtualDeviceConfigSpec, l)
   239  		for i := 0; i < l; i++ {
   240  			cs.DeviceChange[i] = &VirtualDeviceConfigSpec{
   241  				Operation:     VirtualDeviceConfigSpecOperationAdd,
   242  				FileOperation: VirtualDeviceConfigSpecFileOperationCreate,
   243  				Device:        ci.Hardware.Device[i],
   244  				Profile:       nil,
   245  				Backing:       nil,
   246  				FilterSpec:    nil,
   247  			}
   248  		}
   249  	}
   250  
   251  	if ni := ci.NumaInfo; ni != nil {
   252  		cs.VirtualNuma = &VirtualMachineVirtualNuma{
   253  			CoresPerNumaNode:       ni.CoresPerNumaNode,
   254  			ExposeVnumaOnCpuHotadd: ni.VnumaOnCpuHotaddExposed,
   255  		}
   256  	}
   257  
   258  	if civa, ok := ci.VAppConfig.(*VmConfigInfo); ok {
   259  		var csva VmConfigSpec
   260  
   261  		csva.Eula = civa.Eula
   262  		csva.InstallBootRequired = &civa.InstallBootRequired
   263  		csva.InstallBootStopDelay = civa.InstallBootStopDelay
   264  
   265  		ipAssignment := civa.IpAssignment
   266  		csva.IpAssignment = &ipAssignment
   267  
   268  		csva.OvfEnvironmentTransport = civa.OvfEnvironmentTransport
   269  		for i := range civa.OvfSection {
   270  			s := civa.OvfSection[i]
   271  			csva.OvfSection = append(
   272  				csva.OvfSection,
   273  				VAppOvfSectionSpec{
   274  					ArrayUpdateSpec: ArrayUpdateSpec{
   275  						Operation: ArrayUpdateOperationAdd,
   276  					},
   277  					Info: &s,
   278  				},
   279  			)
   280  		}
   281  
   282  		for i := range civa.Product {
   283  			p := civa.Product[i]
   284  			csva.Product = append(
   285  				csva.Product,
   286  				VAppProductSpec{
   287  					ArrayUpdateSpec: ArrayUpdateSpec{
   288  						Operation: ArrayUpdateOperationAdd,
   289  					},
   290  					Info: &p,
   291  				},
   292  			)
   293  		}
   294  
   295  		for i := range civa.Property {
   296  			p := civa.Property[i]
   297  			csva.Property = append(
   298  				csva.Property,
   299  				VAppPropertySpec{
   300  					ArrayUpdateSpec: ArrayUpdateSpec{
   301  						Operation: ArrayUpdateOperationAdd,
   302  					},
   303  					Info: &p,
   304  				},
   305  			)
   306  		}
   307  
   308  		cs.VAppConfig = &csva
   309  	}
   310  
   311  	return cs
   312  }
   313  
   314  // ToString returns the string-ified version of the provided input value by
   315  // first attempting to encode the value to JSON using the vimtype JSON encoder,
   316  // and if that should fail, using the standard JSON encoder, and if that fails,
   317  // returning the value formatted with Sprintf("%v").
   318  //
   319  // Please note, this function is not intended to replace marshaling the data
   320  // to JSON using the normal workflows. This function is for when a string-ified
   321  // version of the data is needed for things like logging.
   322  func ToString(in AnyType) (s string) {
   323  	if in == nil {
   324  		return "null"
   325  	}
   326  
   327  	marshalWithSprintf := func() string {
   328  		return fmt.Sprintf("%v", in)
   329  	}
   330  
   331  	defer func() {
   332  		if err := recover(); err != nil {
   333  			s = marshalWithSprintf()
   334  		}
   335  	}()
   336  
   337  	rv := reflect.ValueOf(in)
   338  	switch rv.Kind() {
   339  
   340  	case reflect.Bool,
   341  		reflect.Complex64, reflect.Complex128,
   342  		reflect.Float32, reflect.Float64:
   343  
   344  		return fmt.Sprintf("%v", in)
   345  
   346  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
   347  		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
   348  		reflect.Uintptr:
   349  
   350  		return fmt.Sprintf("%d", in)
   351  
   352  	case reflect.String:
   353  		return in.(string)
   354  
   355  	case reflect.Interface, reflect.Pointer:
   356  		if rv.IsZero() {
   357  			return "null"
   358  		}
   359  		return ToString(rv.Elem().Interface())
   360  	}
   361  
   362  	marshalWithStdlibJSONEncoder := func() string {
   363  		data, err := json.Marshal(in)
   364  		if err != nil {
   365  			return marshalWithSprintf()
   366  		}
   367  		return string(data)
   368  	}
   369  
   370  	defer func() {
   371  		if err := recover(); err != nil {
   372  			s = marshalWithStdlibJSONEncoder()
   373  		}
   374  	}()
   375  
   376  	var w bytes.Buffer
   377  	enc := NewJSONEncoder(&w)
   378  	if err := enc.Encode(in); err != nil {
   379  		return marshalWithStdlibJSONEncoder()
   380  	}
   381  
   382  	// Do not include the newline character added by the vimtype JSON encoder.
   383  	return strings.TrimSuffix(w.String(), "\n")
   384  }
   385  
   386  func init() {
   387  	// Known 6.5 issue where this event type is sent even though it is internal.
   388  	// This workaround allows us to unmarshal and avoid NPEs.
   389  	t["HostSubSpecificationUpdateEvent"] = reflect.TypeOf((*HostEvent)(nil)).Elem()
   390  }