debian-forge-composer/vendor/github.com/vmware/govmomi/ovf/configspec.go
Achilleas Koutsou 3fd7092db5 go.mod: update osbuild/images to v0.156.0
tag v0.155.0
Tagger: imagebuilder-bot <imagebuilder-bots+imagebuilder-bot@redhat.com>

Changes with 0.155.0

----------------
  * Fedora 43: add shadow-utils when LockRoot is enabled, update cloud-init service name (osbuild/images#1618)
    * Author: Achilleas Koutsou, Reviewers: Gianluca Zuccarelli, Michael Vogt
  * Update osbuild dependency commit ID to latest (osbuild/images#1609)
    * Author: SchutzBot, Reviewers: Achilleas Koutsou, Simon de Vlieger, Tomáš Hozza
  * Update snapshots to 20250626 (osbuild/images#1623)
    * Author: SchutzBot, Reviewers: Achilleas Koutsou, Simon de Vlieger
  * distro/rhel9: xz compress azure-cvm image type [HMS-8587] (osbuild/images#1620)
    * Author: Achilleas Koutsou, Reviewers: Simon de Vlieger, Tomáš Hozza
  * distro/rhel: introduce new image type: Azure SAP Apps [HMS-8738] (osbuild/images#1612)
    * Author: Achilleas Koutsou, Reviewers: Simon de Vlieger, Tomáš Hozza
  * distro/rhel: move ansible-core to sap_extras_pkgset (osbuild/images#1624)
    * Author: Achilleas Koutsou, Reviewers: Brian C. Lane, Tomáš Hozza
  * github/create-tag: allow passing the version when run manually (osbuild/images#1621)
    * Author: Achilleas Koutsou, Reviewers: Lukáš Zapletal, Tomáš Hozza
  * rhel9: move image-config into pure YAML (HMS-8593) (osbuild/images#1616)
    * Author: Michael Vogt, Reviewers: Achilleas Koutsou, Simon de Vlieger
  * test: split manifest checksums into separate files (osbuild/images#1625)
    * Author: Achilleas Koutsou, Reviewers: Simon de Vlieger, Tomáš Hozza

— Somewhere on the Internet, 2025-06-30

---

tag v0.156.0
Tagger: imagebuilder-bot <imagebuilder-bots+imagebuilder-bot@redhat.com>

Changes with 0.156.0

----------------
  * Many: delete repositories for EOL distributions (HMS-7044) (osbuild/images#1607)
    * Author: Tomáš Hozza, Reviewers: Michael Vogt, Simon de Vlieger
  * RHSM/facts: add 'image-builder CLI' API type (osbuild/images#1640)
    * Author: Tomáš Hozza, Reviewers: Brian C. Lane, Simon de Vlieger
  * Update dependencies 2025-06-29 (osbuild/images#1628)
    * Author: SchutzBot, Reviewers: Simon de Vlieger, Tomáš Hozza
  * Update osbuild dependency commit ID to latest (osbuild/images#1627)
    * Author: SchutzBot, Reviewers: Simon de Vlieger, Tomáš Hozza
  * [RFC] image: drop `InstallWeakDeps` from image.DiskImage (osbuild/images#1642)
    * Author: Michael Vogt, Reviewers: Brian C. Lane, Simon de Vlieger, Tomáš Hozza
  * build(deps): bump the go-deps group across 1 directory with 3 updates (osbuild/images#1632)
    * Author: dependabot[bot], Reviewers: SchutzBot, Tomáš Hozza
  * distro/rhel10: xz compress azure-cvm image type (osbuild/images#1638)
    * Author: Achilleas Koutsou, Reviewers: Brian C. Lane, Simon de Vlieger
  * distro: cleanup/refactor distro/{defs,generic} (HMS-8744) (osbuild/images#1570)
    * Author: Michael Vogt, Reviewers: Simon de Vlieger, Tomáš Hozza
  * distro: remove some hardcoded values from generic/images.go (osbuild/images#1636)
    * Author: Michael Vogt, Reviewers: Simon de Vlieger, Tomáš Hozza
  * distro: small tweaks for the YAML based imagetypes (osbuild/images#1622)
    * Author: Michael Vogt, Reviewers: Brian C. Lane, Simon de Vlieger
  * fedora/wsl: packages and locale (osbuild/images#1635)
    * Author: Simon de Vlieger, Reviewers: Michael Vogt, Tomáš Hozza
  * image/many: make compression more generic (osbuild/images#1634)
    * Author: Simon de Vlieger, Reviewers: Brian C. Lane, Michael Vogt
  * manifest: handle content template name with spaces (osbuild/images#1641)
    * Author: Bryttanie, Reviewers: Brian C. Lane, Michael Vogt, Tomáš Hozza
  * many: implement gzip (osbuild/images#1633)
    * Author: Simon de Vlieger, Reviewers: Michael Vogt, Tomáš Hozza
  * rhel/azure: set GRUB_TERMINAL based on architecture [RHEL-91383] (osbuild/images#1626)
    * Author: Achilleas Koutsou, Reviewers: Simon de Vlieger, Tomáš Hozza

— Somewhere on the Internet, 2025-07-07

---
2025-07-14 13:13:20 +02:00

1069 lines
26 KiB
Go

// © Broadcom. All Rights Reserved.
// The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
// SPDX-License-Identifier: Apache-2.0
package ovf
import (
"errors"
"fmt"
"math"
"strconv"
"strings"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25/types"
)
const (
ResourceSubTypeSoundCardSB16 = "vmware.soundcard.sb16"
ResourceSubTypeSoundCardEnsoniq1371 = "vmware.soundcard.ensoniq1371"
ResourceSubTypeSoundCardHDAudio = "vmware.soundcard.hdaudio"
ResourceSubTypePCIController = "vmware.pcicontroller"
ResourceSubTypePS2Controller = "vmware.ps2controller"
ResourceSubTypeSIOController = "vmware.siocontroller"
ResourceSubTypeKeyboard = "vmware.keyboard"
ResourceSubTypePointingDevice = "vmware.pointingdevice"
ResourceSubTypeVMCI = "vmware.vmci"
ResourceSubTypeUSBEHCI = "vmware.usb.ehci" /* USB 2.0 */
ResourceSubTypeUSBXHCI = "vmware.usb.xhci" /* USB 3.0 */
ResourceSubTypeCdromISO = "vmware.cdrom.iso"
ResourceSubTypeCDROMRemotePassthrough = "vmware.cdrom.remotepassthrough"
ResourceSubTypeCDROMRemoteATAPI = "vmware.cdrom.remoteatapi"
ResourceSubTypeCDROMPassthrough = "vmware.cdrom.passthrough"
ResourceSubTypeCDROMATAPI = "vmware.cdrom.atapi"
ResourceSubTypeFloppyDevice = "vmware.floppy.device"
ResourceSubTypeFloppyImage = "vmware.floppy.image"
ResourceSubTypeFloppyRemoveDevice = "vmware.floppy.remotedevice"
ResourceSubTypeSCSIPassthrough = "vmware.scsi.passthrough"
ResourceSubTypeParallelPortDevice = "vmware.parallelport.device"
ResourceSubTypeParallelPortFile = "vmware.parallelport.file"
ResourceSubTypeSerialPortDevice = "vmware.serialport.device"
ResourceSubTypeSerialPortFile = "vmware.serialport.file"
ResourceSubTypeSerialPortPipe = "vmware.serialport.pipe"
ResourceSubTypeSerialPortURI = "vmware.serialport.uri"
ResourceSubTypeSerialPortThinPrint = "vmware.serialport.thinprint"
ResourceSubTypeSATAAHCI = "vmware.sata.ahci"
ResourceSubTypeSATAAHCIAlter = "ahci"
ResourceSubTypeNVMEController = "vmware.nvme.controller"
ResourceSubTypeNVDIMMController = "vmware.nvdimm.controller"
ResourceSubTypeNVDIMMDevice = "vmware.nvdimm.device"
ResourceSubTypePCIPassthrough = "vmware.pci.passthrough"
ResourceSubTypePCIPassthroughDVX = "vmware.pci.passthrough-dvx"
ResourceSubTypePCIPassthroughAH = "vmware.pci.passthrough-ah"
ResourceSubTypePCIPassthroughVMIOP = "vmware.pci.passthrough-vmiop"
ResourceSubTypePrecisionClock = "vmware.precisionclock"
ResourceSubTypeWatchdogTimer = "vmware.watchdogtimer"
ResourceSubTypeVTPM = "vmware.vtpm"
)
var errUnsupportedResourceSubtype = errors.New("unsupported resource subtype")
// ErrUnsupportedItem is returned by Envelope.ToConfigSpec when there is an
// invalid item configuration.
type ErrUnsupportedItem struct {
Name string
Index int
InstanceID string
ResourceType CIMResourceType
ResourceSubType string
LocalizedMessage string
}
func (e ErrUnsupportedItem) Error() string {
msg := fmt.Sprintf(
"unsupported item name=%q, index=%d, instanceID=%q",
e.Name, e.Index, e.InstanceID)
if e.ResourceType > 0 {
msg = fmt.Sprintf("%s, resourceType=%d", msg, e.ResourceType)
}
if e.ResourceSubType != "" {
msg = fmt.Sprintf("%s, resourceSubType=%s", msg, e.ResourceSubType)
}
if e.LocalizedMessage != "" {
msg = fmt.Sprintf("%s, msg=%q", msg, e.LocalizedMessage)
}
return msg
}
// AsErrUnsupportedItem returns any possible wrapped ErrUnsupportedItem error
// from the provided error.
func AsErrUnsupportedItem(in error) (ErrUnsupportedItem, bool) {
var out ErrUnsupportedItem
if errors.As(in, &out) {
return out, true
}
return ErrUnsupportedItem{}, false
}
func errUnsupportedItem(
index int,
item itemElement,
inner error,
args ...any) error {
err := ErrUnsupportedItem{
Name: item.ElementName,
InstanceID: item.InstanceID,
Index: index,
ResourceSubType: item.resourceSubType,
}
if item.ResourceType != nil {
err.ResourceType = *item.ResourceType
}
if len(args) == 1 {
err.LocalizedMessage = args[0].(string)
} else if len(args) > 1 {
err.LocalizedMessage = fmt.Sprintf(args[0].(string), args[1:]...)
}
if inner != nil {
return fmt.Errorf("%w, %w", err, inner)
}
return err
}
type itemElement struct {
ResourceAllocationSettingData
resourceSubType string
}
type configSpec = types.VirtualMachineConfigSpec
// ToConfigSpecOptions influence the behavior of the ToConfigSpecWithOptions
// function.
type ToConfigSpecOptions struct {
// Strict indicates that an error should be returned on Item elements in
// a VirtualHardware section that have an unknown ResourceType, i.e. a value
// that falls outside the range of the enum CIMResourceType.
Strict bool
}
// ToConfigSpec calls ToConfigSpecWithOptions with an empty ToConfigSpecOptions
// object.
func (e Envelope) ToConfigSpec() (types.VirtualMachineConfigSpec, error) {
return e.ToConfigSpecWithOptions(ToConfigSpecOptions{})
}
// ToConfigSpecWithOptions transforms the envelope into a ConfigSpec that may be
// used to create a new virtual machine.
// Please note, at this time:
// - Only a single VirtualSystem is supported. The VirtualSystemCollection
// section is ignored.
// - Only the first VirtualHardware section is supported.
// - Only the default deployment option configuration is considered. Elements
// part of a non-default configuration are ignored.
// - Disks must specify zero or one HostResource elements.
// - Many, many more constraints...
func (e Envelope) ToConfigSpecWithOptions(
opts ToConfigSpecOptions) (types.VirtualMachineConfigSpec, error) {
vs := e.VirtualSystem
if vs == nil {
return configSpec{}, errors.New("no VirtualSystem")
}
// Determine if there is a default configuration.
var defaultConfigName string
if do := e.DeploymentOption; do != nil {
for _, c := range do.Configuration {
if d := c.Default; d != nil && *d {
defaultConfigName = c.ID
break
}
}
}
dst := configSpec{
Files: &types.VirtualMachineFileInfo{},
Name: vs.ID,
}
// Set the guest ID.
if os := vs.OperatingSystem; os != nil && os.OSType != nil {
dst.GuestId = *os.OSType
}
// Parse the hardware.
if err := e.toHardware(&dst, defaultConfigName, vs, opts); err != nil {
return configSpec{}, err
}
// Parse the vApp config.
if err := e.toVAppConfig(&dst, defaultConfigName, vs); err != nil {
return configSpec{}, err
}
return dst, nil
}
func (e Envelope) toHardware(
dst *configSpec,
configName string,
vs *VirtualSystem,
opts ToConfigSpecOptions) error {
var hw VirtualHardwareSection
if len(vs.VirtualHardware) == 0 {
return errors.New("no VirtualHardware")
}
hw = vs.VirtualHardware[0]
// Set the hardware version.
if vmx := hw.System.VirtualSystemType; vmx != nil {
dst.Version = *vmx
}
// Parse the config
e.toConfig(dst, hw)
// Parse the extra config.
e.toExtraConfig(dst, hw)
var (
devices object.VirtualDeviceList
resources = map[string]types.BaseVirtualDevice{}
)
for index := range hw.Item {
item := itemElement{
ResourceAllocationSettingData: hw.Item[index],
}
if c := item.Configuration; c != nil {
if *c != configName {
// Skip items that do not belong to the provided config.
continue
}
}
if item.ResourceType == nil {
return errUnsupportedItem(index, item, nil, "nil ResourceType")
}
// Get the resource sub type, if any.
if rst := item.ResourceSubType; rst != nil {
item.resourceSubType = strings.ToLower(*rst)
}
var (
d types.BaseVirtualDevice
err error
)
switch *item.ResourceType {
case Other: // 1
d, err = e.toOther(item, devices, resources)
case ComputerSystem: // 2
// TODO(akutz)
case Processor: // 3
if item.VirtualQuantity == nil {
return errUnsupportedItem(
index, item, nil, "nil VirtualQuantity")
}
dst.NumCPUs = int32(*item.VirtualQuantity)
if cps := item.CoresPerSocket; cps != nil {
dst.NumCoresPerSocket = cps.Value
}
case Memory: // 4
if item.VirtualQuantity == nil {
return errUnsupportedItem(
index, item, nil, "nil VirtualQuantity")
}
dst.MemoryMB = int64(*item.VirtualQuantity)
case IdeController: // 5
d, err = e.toIDEController(item, devices, resources)
case ParallelScsiHba: // 6
d, err = e.toSCSIController(item, devices, resources)
case FcHba: // 7
// TODO(akutz)
case IScsiHba: // 8
// TODO(akutz)
case IbHba: // 9
// TODO(akutz)
case EthernetAdapter: // 10
d, err = e.toNetworkInterface(item, devices, resources)
case OtherNetwork: // 11
// TODO(akutz)
case IoSlot: // 12
// TODO(akutz)
case IoDevice: // 13
// TODO(akutz)
case FloppyDrive: // 14
if devices.PickController((*types.VirtualSIOController)(nil)) == nil {
c := &types.VirtualSIOController{}
c.Key = devices.NewKey()
devices = append(devices, c)
}
d, err = e.toFloppyDrive(item, devices, resources)
case CdDrive, DvdDrive: // 15, 16
d, err = e.toCDOrDVDDrive(item, devices, resources)
case DiskDrive: // 17
d, err = e.toVirtualDisk(item, devices, resources)
case TapeDrive: // 18
// TODO(akutz)
case StorageExtent: // 19
// TODO(akutz)
case OtherStorage: // 20
d, err = e.toOtherStorage(item, devices, resources)
case SerialPort: // 21
// TODO(akutz)
case ParallelPort: // 22
// TODO(akutz)
case UsbController: // 23
d, err = e.toUSB(item, devices, resources)
case Graphics: // 24
d, err = e.toVideoCard(item, devices, resources)
case Ieee1394: // 25
// TODO(akutz)
case PartitionableUnit: // 26
// TODO(akutz)
case BasePartitionable: // 27
// TODO(akutz)
case PowerSupply: // 28
// TODO(akutz)
case CoolingDevice: // 29
// TODO(akutz)
case EthernetSwitchPort: // 30
// TODO(akutz)
case LogicalDisk: // 31
// TODO(akutz)
case StorageVolume: // 32
// TODO(akutz)
case EthernetConnection: // 33
// TODO(akutz)
default:
if opts.Strict {
return errUnsupportedItem(
index, item, nil, "unsupported resource type")
}
}
if err != nil {
if err == errUnsupportedResourceSubtype {
if !opts.Strict {
continue
}
}
return errUnsupportedItem(index, item, err)
}
if d != nil {
setConnectable(d, item)
if err := e.setUnitNumber(item, d); err != nil {
return errUnsupportedItem(index, item, err)
}
if err := e.setPCISlotNumber(item, d); err != nil {
return errUnsupportedItem(index, item, err)
}
devices = append(devices, d)
}
}
// Add the devices to the ConfigSpec.
dst.DeviceChange, _ = devices.ConfigSpec(types.VirtualDeviceConfigSpecOperationAdd)
return nil
}
func (e Envelope) setUnitNumber(
item itemElement,
d types.BaseVirtualDevice) error {
if item.AddressOnParent == nil || *item.AddressOnParent == "" {
return nil
}
unitNumber, err := strconv.ParseInt(*item.AddressOnParent, 10, 32)
if err != nil {
return fmt.Errorf("invalid AddressOnParent=%q", *item.AddressOnParent)
}
d.GetVirtualDevice().UnitNumber = types.NewInt32(int32(unitNumber))
return nil
}
func (e Envelope) setBusNumber(
item itemElement,
d types.BaseVirtualDevice) error {
if item.Address == nil || *item.Address == "" {
return nil
}
c, ok := d.(types.BaseVirtualController)
if !ok {
return fmt.Errorf("expectedType=%s, actualType=%T",
"types.BaseVirtualController", d)
}
busNumber, err := strconv.ParseInt(*item.Address, 10, 32)
if err != nil {
return fmt.Errorf("invalid Address=%q", *item.Address)
}
c.GetVirtualController().BusNumber = int32(busNumber)
return nil
}
func (e Envelope) setPCISlotNumber(
item itemElement,
d types.BaseVirtualDevice) error {
var pciSlotNumber int32 = -1
for i := range item.Config {
c := item.Config[i]
if c.Key == "slotInfo.pciSlotNumber" {
if c.Value != "" {
v, err := strconv.ParseInt(c.Value, 10, 32)
if err != nil {
return fmt.Errorf("invalid pci slot number %s", c.Value)
}
pciSlotNumber = int32(v)
}
break
}
}
if pciSlotNumber >= 0 {
vd := d.GetVirtualDevice()
if vd.SlotInfo == nil {
vd.SlotInfo = &types.VirtualDevicePciBusSlotInfo{}
}
si, ok := vd.SlotInfo.(*types.VirtualDevicePciBusSlotInfo)
if !ok {
return fmt.Errorf("expectedType=%s, actualType=%T",
"*types.VirtualDevicePciBusSlotInfo", vd.SlotInfo)
}
si.PciSlotNumber = pciSlotNumber
}
return nil
}
func (e Envelope) ovfDisk(diskID string) *VirtualDiskDesc {
for _, disk := range e.Disk.Disks {
if strings.HasSuffix(diskID, disk.DiskID) {
return &disk
}
}
return nil
}
func (e Envelope) toVirtualDisk(
item itemElement,
devices object.VirtualDeviceList,
resources map[string]types.BaseVirtualDevice) (types.BaseVirtualDevice, error) {
if item.Parent == nil {
return nil, fmt.Errorf("missing Parent")
}
r, ok := resources[*item.Parent]
if !ok {
return nil, nil
}
c, ok := r.(types.BaseVirtualController)
if !ok {
return nil, fmt.Errorf("expectedType=%s, actualType=%T",
"types.BaseVirtualController", r)
}
d := devices.CreateDisk(c, types.ManagedObjectReference{}, "")
d.VirtualDevice.DeviceInfo = &types.Description{
Label: item.ElementName,
}
// Find the disk's capacity.
var capacityInBytes uint64
switch len(item.HostResource) {
case 0:
var allocUnitsSz string
if item.AllocationUnits != nil {
allocUnitsSz = *item.AllocationUnits
}
capacityInBytes = uint64(ParseCapacityAllocationUnits(allocUnitsSz))
if r := item.VirtualQuantity; r != nil {
capacityInBytes *= uint64(*r)
}
case 1:
diskID := item.HostResource[0]
dd := e.ovfDisk(diskID)
if dd == nil {
return nil, fmt.Errorf("missing diskID %q", diskID)
}
var allocUnitsSz string
if dd.CapacityAllocationUnits != nil {
allocUnitsSz = *dd.CapacityAllocationUnits
}
capacityInBytes = uint64(ParseCapacityAllocationUnits(allocUnitsSz))
if capSz := dd.Capacity; capSz != "" {
cap, err := strconv.ParseUint(dd.Capacity, 10, 64)
if err != nil {
return nil, fmt.Errorf("disk=%s has invalid capacity=%q",
diskID, capSz)
}
capacityInBytes *= cap
}
default:
return nil, fmt.Errorf("multiple HostResource elements")
}
if capacityInBytes > math.MaxInt64 {
return nil, fmt.Errorf(
"capacityInBytes=%d exceeds math.MaxInt64", capacityInBytes)
}
d.CapacityInBytes = int64(capacityInBytes)
return d, nil
}
func (e Envelope) toCDOrDVDDrive(
item itemElement,
devices object.VirtualDeviceList,
resources map[string]types.BaseVirtualDevice) (types.BaseVirtualDevice, error) {
if item.Parent == nil {
return nil, fmt.Errorf("missing Parent")
}
r, ok := resources[*item.Parent]
if !ok {
return nil, nil // Parent is unsupported
}
c, ok := r.(types.BaseVirtualController)
if !ok {
return nil, fmt.Errorf("expectedType=%s, actualType=%T",
"*types.VirtualIDEController", r)
}
d, err := devices.CreateCdrom(c)
if err != nil {
return nil, err
}
return d, nil
}
func (e Envelope) toSCSIController(
item itemElement,
devices object.VirtualDeviceList,
resources map[string]types.BaseVirtualDevice) (types.BaseVirtualDevice, error) {
d, err := devices.CreateSCSIController(item.resourceSubType)
if err != nil {
return nil, err
}
if err := e.setBusNumber(item, d); err != nil {
return nil, err
}
resources[item.InstanceID] = d
return d, nil
}
func (e Envelope) toIDEController(
item itemElement,
devices object.VirtualDeviceList,
resources map[string]types.BaseVirtualDevice) (types.BaseVirtualDevice, error) {
d, err := devices.CreateIDEController()
if err != nil {
return nil, err
}
if err := e.setBusNumber(item, d); err != nil {
return nil, err
}
resources[item.InstanceID] = d
return d, nil
}
func (e Envelope) toOtherStorage(
item itemElement,
devices object.VirtualDeviceList,
resources map[string]types.BaseVirtualDevice) (types.BaseVirtualDevice, error) {
switch item.resourceSubType {
case ResourceSubTypeSATAAHCI, ResourceSubTypeSATAAHCIAlter:
return e.toSATAController(item, devices, resources)
case ResourceSubTypeNVMEController:
return e.toNVMEController(item, devices, resources)
}
return nil, errUnsupportedResourceSubtype
}
func (e Envelope) toSATAController(
item itemElement,
devices object.VirtualDeviceList,
resources map[string]types.BaseVirtualDevice) (types.BaseVirtualDevice, error) {
d, err := devices.CreateSATAController()
if err != nil {
return nil, err
}
if err := e.setBusNumber(item, d); err != nil {
return nil, err
}
resources[item.InstanceID] = d
return d, nil
}
func (e Envelope) toNVMEController(
item itemElement,
devices object.VirtualDeviceList,
resources map[string]types.BaseVirtualDevice) (types.BaseVirtualDevice, error) {
d, err := devices.CreateNVMEController()
if err != nil {
return nil, err
}
if err := e.setBusNumber(item, d); err != nil {
return nil, err
}
resources[item.InstanceID] = d
return d, nil
}
func (e Envelope) toUSB(
item itemElement,
devices object.VirtualDeviceList,
resources map[string]types.BaseVirtualDevice) (types.BaseVirtualDevice, error) {
var d types.BaseVirtualDevice
vc := types.VirtualController{
VirtualDevice: types.VirtualDevice{
Key: devices.NewKey(),
},
}
switch item.resourceSubType {
case ResourceSubTypeUSBEHCI:
c := &types.VirtualUSBController{VirtualController: vc}
for i := range item.Config {
ic := item.Config[i]
switch ic.Key {
case "autoConnectDevices":
c.AutoConnectDevices = szToBoolPtr(ic.Value)
case "ehciEnabled":
c.EhciEnabled = szToBoolPtr(ic.Value)
}
}
d = c
case ResourceSubTypeUSBXHCI:
c := &types.VirtualUSBXHCIController{VirtualController: vc}
for i := range item.Config {
ic := item.Config[i]
switch ic.Key {
case "autoConnectDevices":
c.AutoConnectDevices = szToBoolPtr(ic.Value)
}
}
d = c
default:
return nil, errUnsupportedResourceSubtype
}
if err := e.setBusNumber(item, d); err != nil {
return nil, err
}
resources[item.InstanceID] = d
return d, nil
}
func (e Envelope) toNetworkInterface(
item itemElement,
devices object.VirtualDeviceList,
_ map[string]types.BaseVirtualDevice) (types.BaseVirtualDevice, error) {
d, err := devices.CreateEthernetCard(item.resourceSubType, nil)
if err != nil {
return nil, err
}
nic := d.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard()
for i := range item.Config {
c := item.Config[i]
switch c.Key {
case "wakeOnLanEnabled":
nic.WakeOnLanEnabled = szToBoolPtr(c.Value)
case "uptCompatibilityEnabled":
nic.UptCompatibilityEnabled = szToBoolPtr(c.Value)
}
}
return d, nil
}
func (e Envelope) toFloppyDrive(
item itemElement,
devices object.VirtualDeviceList,
resources map[string]types.BaseVirtualDevice) (types.BaseVirtualDevice, error) {
d, err := devices.CreateFloppy()
if err != nil {
return nil, err
}
resources[item.InstanceID] = d
return d, nil
}
func (e Envelope) toVideoCard(
item itemElement,
devices object.VirtualDeviceList,
_ map[string]types.BaseVirtualDevice) (types.BaseVirtualDevice, error) {
d := &types.VirtualMachineVideoCard{
VirtualDevice: types.VirtualDevice{
Key: devices.NewKey(),
},
}
for i := range item.Config {
c := item.Config[i]
switch c.Key {
case "enable3DSupport":
d.Enable3DSupport = szToBoolPtr(c.Value)
case "graphicsMemorySizeInKB":
v, err := strconv.ParseInt(c.Value, 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid %q=%s", c.Key, c.Value)
}
d.GraphicsMemorySizeInKB = v
case "useAutoDetect":
d.UseAutoDetect = szToBoolPtr(c.Value)
case "videoRamSizeInKB":
v, err := strconv.ParseInt(c.Value, 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid %q=%s", c.Key, c.Value)
}
d.VideoRamSizeInKB = v
case "numDisplays":
v, err := strconv.ParseInt(c.Value, 10, 32)
if err != nil {
return nil, fmt.Errorf("invalid %q=%s", c.Key, c.Value)
}
d.NumDisplays = int32(v)
case "use3dRenderer":
d.Use3dRenderer = c.Value
}
}
return d, nil
}
func (e Envelope) toOther(
item itemElement,
devices object.VirtualDeviceList,
resources map[string]types.BaseVirtualDevice) (types.BaseVirtualDevice, error) {
switch item.resourceSubType {
case ResourceSubTypeVMCI:
return e.toVMCI(item, devices, resources)
}
return nil, errUnsupportedResourceSubtype
}
func (e Envelope) toVMCI(
item itemElement,
devices object.VirtualDeviceList,
_ map[string]types.BaseVirtualDevice) (types.BaseVirtualDevice, error) {
d := &types.VirtualMachineVMCIDevice{
VirtualDevice: types.VirtualDevice{
Key: devices.NewKey(),
},
}
for i := range item.Config {
c := item.Config[i]
switch c.Key {
case "allowUnrestrictedCommunication":
d.AllowUnrestrictedCommunication = szToBoolPtr(c.Value)
}
}
return d, nil
}
func (e Envelope) toConfig(
dst *configSpec,
hw VirtualHardwareSection) {
for i := range hw.Config {
c := hw.Config[i]
switch c.Key {
case "cpuHotAddEnabled":
dst.CpuHotAddEnabled = szToBoolPtr(c.Value)
case "cpuHotRemoveEnabled":
dst.CpuHotRemoveEnabled = szToBoolPtr(c.Value)
case "bootOptions.efiSecureBootEnabled":
initBootOptions(dst)
dst.BootOptions.EfiSecureBootEnabled = szToBoolPtr(c.Value)
case "firmware":
dst.Firmware = c.Value
case "flags.vbsEnabled":
initFlags(dst)
dst.Flags.VbsEnabled = szToBoolPtr(c.Value)
case "flags.vvtdEnabled":
initFlags(dst)
dst.Flags.VvtdEnabled = szToBoolPtr(c.Value)
case "memoryHotAddEnabled":
dst.MemoryHotAddEnabled = szToBoolPtr(c.Value)
case "nestedHVEnabled":
dst.NestedHVEnabled = szToBoolPtr(c.Value)
case "virtualICH7MPresent":
dst.VirtualICH7MPresent = szToBoolPtr(c.Value)
case "virtualSMCPresent":
dst.VirtualSMCPresent = szToBoolPtr(c.Value)
case "cpuAllocation.shares.shares":
initCPUAllocationShares(dst)
dst.CpuAllocation.Shares.Shares = szToInt32(c.Value)
case "cpuAllocation.shares.level":
initCPUAllocationShares(dst)
dst.CpuAllocation.Shares.Level = types.SharesLevel(c.Value)
case "simultaneousThreads":
dst.SimultaneousThreads = szToInt32(c.Value)
case "tools.syncTimeWithHost":
initToolsConfig(dst)
dst.Tools.SyncTimeWithHost = szToBoolPtr(c.Value)
case "tools.syncTimeWithHostAllowed":
initToolsConfig(dst)
dst.Tools.SyncTimeWithHostAllowed = szToBoolPtr(c.Value)
case "tools.afterPowerOn":
initToolsConfig(dst)
dst.Tools.AfterPowerOn = szToBoolPtr(c.Value)
case "tools.afterResume":
initToolsConfig(dst)
dst.Tools.AfterResume = szToBoolPtr(c.Value)
case "tools.beforeGuestShutdown":
initToolsConfig(dst)
dst.Tools.BeforeGuestShutdown = szToBoolPtr(c.Value)
case "tools.beforeGuestStandby":
initToolsConfig(dst)
dst.Tools.BeforeGuestStandby = szToBoolPtr(c.Value)
case "tools.toolsUpgradePolicy":
initToolsConfig(dst)
dst.Tools.ToolsUpgradePolicy = c.Value
case "powerOpInfo.powerOffType":
initPowerOpInfo(dst)
dst.PowerOpInfo.PowerOffType = c.Value
case "powerOpInfo.resetType":
initPowerOpInfo(dst)
dst.PowerOpInfo.ResetType = c.Value
case "powerOpInfo.suspendType":
initPowerOpInfo(dst)
dst.PowerOpInfo.SuspendType = c.Value
case "powerOpInfo.standbyAction":
initPowerOpInfo(dst)
dst.PowerOpInfo.StandbyAction = c.Value
case "vPMCEnabled":
dst.VPMCEnabled = szToBoolPtr(c.Value)
}
}
}
func (e Envelope) toExtraConfig(
dst *configSpec,
hw VirtualHardwareSection) {
var newEC object.OptionValueList
for i := range hw.ExtraConfig {
newEC = append(newEC, &types.OptionValue{
Key: hw.ExtraConfig[i].Key,
Value: hw.ExtraConfig[i].Value,
})
}
dst.ExtraConfig = newEC.Join(dst.ExtraConfig...)
}
func initToolsConfig(dst *configSpec) {
if dst.Tools == nil {
dst.Tools = &types.ToolsConfigInfo{}
}
}
func initPowerOpInfo(dst *configSpec) {
if dst.PowerOpInfo == nil {
dst.PowerOpInfo = &types.VirtualMachineDefaultPowerOpInfo{}
}
}
func initCPUAllocation(dst *configSpec) {
if dst.CpuAllocation == nil {
dst.CpuAllocation = &types.ResourceAllocationInfo{}
}
}
func initCPUAllocationShares(dst *configSpec) {
initCPUAllocation(dst)
if dst.CpuAllocation.Shares == nil {
dst.CpuAllocation.Shares = &types.SharesInfo{}
}
}
func initFlags(dst *configSpec) {
if dst.Flags == nil {
dst.Flags = &types.VirtualMachineFlagInfo{}
}
}
func initBootOptions(dst *configSpec) {
if dst.BootOptions == nil {
dst.BootOptions = &types.VirtualMachineBootOptions{}
}
}
func setConnectable(dst types.BaseVirtualDevice, src itemElement) {
d := dst.GetVirtualDevice()
for i := range src.Config {
c := src.Config[i]
switch c.Key {
case "connectable.allowGuestControl":
if d.Connectable == nil {
d.Connectable = &types.VirtualDeviceConnectInfo{}
}
d.Connectable.AllowGuestControl = szToBool(c.Value)
}
}
}
func szToBoolPtr(s string) *bool {
if s == "" {
return nil
}
b, _ := strconv.ParseBool(s)
return &b
}
func szToBool(s string) bool {
b, _ := strconv.ParseBool(s)
return b
}
func szToInt32(s string) int32 {
v, _ := strconv.ParseInt(s, 10, 32)
return int32(v)
}
func deref[T any](pT *T) T {
var t T
if pT != nil {
t = *pT
}
return t
}
func (e Envelope) toVAppConfig(
dst *configSpec,
configName string,
vs *VirtualSystem) error {
if len(vs.Product) == 0 {
return nil
}
vapp := &types.VAppConfigSpec{}
index := 0
for i, product := range vs.Product {
vapp.Product = append(vapp.Product, types.VAppProductSpec{
ArrayUpdateSpec: types.ArrayUpdateSpec{
Operation: types.ArrayUpdateOperationAdd,
},
Info: &types.VAppProductInfo{
Key: int32(i),
ClassId: deref(product.Class),
InstanceId: deref(product.Instance),
Name: product.Product,
Vendor: product.Vendor,
Version: product.Version,
FullVersion: product.FullVersion,
ProductUrl: product.ProductURL,
VendorUrl: product.VendorURL,
AppUrl: product.AppURL,
},
})
for _, p := range product.Property {
if p.Configuration != nil && *p.Configuration != configName {
// Skip properties that are not part of the provided
// configuration.
continue
}
vapp.Property = append(vapp.Property, types.VAppPropertySpec{
ArrayUpdateSpec: types.ArrayUpdateSpec{
Operation: types.ArrayUpdateOperationAdd,
},
Info: &types.VAppPropertyInfo{
Key: int32(index),
ClassId: deref(product.Class),
InstanceId: deref(product.Instance),
Id: p.Key,
Category: product.Category,
Label: deref(p.Label),
Type: p.Type,
UserConfigurable: p.UserConfigurable,
DefaultValue: deref(p.Default),
Value: "",
Description: deref(p.Description),
},
})
index++
}
}
dst.VAppConfig = vapp
return nil
}