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 }