Skip to content

Commit 495a820

Browse files
committedDec 6, 2024·
api: OVF to ConfigSpec
This patch provides a utility function for transforming an OVF envelop into a ConfigSpec. Signed-off-by: akutz <akutz@vmware.com>
1 parent e9f9eb0 commit 495a820

File tree

6 files changed

+2116
-11
lines changed

6 files changed

+2116
-11
lines changed
 

‎object/virtual_device_list.go

+11-6
Original file line numberDiff line numberDiff line change
@@ -573,15 +573,20 @@ func (l VirtualDeviceList) CreateDisk(c types.BaseVirtualController, ds types.Ma
573573
name += ".vmdk"
574574
}
575575

576+
bi := types.VirtualDeviceFileBackingInfo{
577+
FileName: name,
578+
}
579+
580+
if ds.Value != "" {
581+
bi.Datastore = &ds
582+
}
583+
576584
device := &types.VirtualDisk{
577585
VirtualDevice: types.VirtualDevice{
578586
Backing: &types.VirtualDiskFlatVer2BackingInfo{
579-
DiskMode: string(types.VirtualDiskModePersistent),
580-
ThinProvisioned: types.NewBool(true),
581-
VirtualDeviceFileBackingInfo: types.VirtualDeviceFileBackingInfo{
582-
FileName: name,
583-
Datastore: &ds,
584-
},
587+
DiskMode: string(types.VirtualDiskModePersistent),
588+
ThinProvisioned: types.NewBool(true),
589+
VirtualDeviceFileBackingInfo: bi,
585590
},
586591
},
587592
}

‎ovf/configspec.go

+983
Large diffs are not rendered by default.

‎ovf/configspec_test.go

+491
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,491 @@
1+
/*
2+
Copyright (c) 2015-2024 VMware, Inc. All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package ovf
18+
19+
import (
20+
"bytes"
21+
"testing"
22+
23+
"github.com/stretchr/testify/assert"
24+
25+
"github.com/vmware/govmomi/vim25/types"
26+
)
27+
28+
func TestEnvelopeToConfigSpec(t *testing.T) {
29+
e := testEnvelope(t, "fixtures/haproxy-vsphere.ovf")
30+
31+
cs, err := e.ToConfigSpec()
32+
33+
var w bytes.Buffer
34+
enc := types.NewJSONEncoder(&w)
35+
enc.SetIndent("", " ")
36+
assert.NoError(t, enc.Encode(cs))
37+
t.Logf("\n\nconfigSpec=%s\n\n", w.String())
38+
39+
assert.NoError(t, err)
40+
assert.NotEmpty(t, cs)
41+
42+
assert.Equal(t, "haproxy", cs.Name)
43+
assert.Equal(t, int32(2), cs.NumCPUs)
44+
assert.Equal(t, int32(2), cs.NumCoresPerSocket)
45+
assert.Equal(t, int64(4096), cs.MemoryMB)
46+
assert.Equal(t, "vmx-13", cs.Version)
47+
48+
if assert.Len(t, cs.DeviceChange, 21) {
49+
50+
var scsiController1Key int32
51+
if d, ok := cs.DeviceChange[0].GetVirtualDeviceConfigSpec().Device.(*types.VirtualLsiLogicController); assert.True(t, ok) {
52+
scsiController1Key = d.Key
53+
assert.Equal(t, int32(0), d.BusNumber)
54+
if assert.NotNil(t, d.SlotInfo) {
55+
si, ok := d.SlotInfo.(*types.VirtualDevicePciBusSlotInfo)
56+
assert.True(t, ok)
57+
assert.Equal(t, int32(128), si.PciSlotNumber)
58+
}
59+
}
60+
61+
if d, ok := cs.DeviceChange[1].GetVirtualDeviceConfigSpec().Device.(*types.VirtualDisk); assert.True(t, ok) {
62+
assert.Equal(t, scsiController1Key, d.ControllerKey)
63+
if assert.NotNil(t, d.UnitNumber) {
64+
assert.Equal(t, int32(0), *d.UnitNumber)
65+
}
66+
db, ok := d.Backing.(*types.VirtualDiskFlatVer2BackingInfo)
67+
assert.True(t, ok)
68+
assert.Equal(t, string(types.VirtualDiskModePersistent), db.DiskMode)
69+
if assert.NotNil(t, db.ThinProvisioned) {
70+
assert.True(t, *db.ThinProvisioned)
71+
}
72+
assert.Equal(t, int64(20*1024*1024*1024), d.CapacityInBytes)
73+
}
74+
75+
if bd, ok := cs.DeviceChange[2].GetVirtualDeviceConfigSpec().Device.(types.BaseVirtualEthernetCard); assert.True(t, ok) {
76+
d := bd.GetVirtualEthernetCard()
77+
if assert.NotNil(t, d.UnitNumber) {
78+
assert.Equal(t, int32(2), *d.UnitNumber)
79+
}
80+
if assert.NotNil(t, d.Connectable) {
81+
assert.True(t, d.Connectable.AllowGuestControl)
82+
}
83+
if assert.NotNil(t, d.WakeOnLanEnabled) {
84+
assert.False(t, *d.WakeOnLanEnabled)
85+
}
86+
if assert.NotNil(t, d.SlotInfo) {
87+
si, ok := d.SlotInfo.(*types.VirtualDevicePciBusSlotInfo)
88+
assert.True(t, ok)
89+
assert.Equal(t, int32(160), si.PciSlotNumber)
90+
}
91+
}
92+
93+
if bd, ok := cs.DeviceChange[3].GetVirtualDeviceConfigSpec().Device.(types.BaseVirtualEthernetCard); assert.True(t, ok) {
94+
d := bd.GetVirtualEthernetCard()
95+
if assert.NotNil(t, d.UnitNumber) {
96+
assert.Equal(t, int32(3), *d.UnitNumber)
97+
}
98+
if assert.NotNil(t, d.Connectable) {
99+
assert.True(t, d.Connectable.AllowGuestControl)
100+
}
101+
if assert.NotNil(t, d.WakeOnLanEnabled) {
102+
assert.False(t, *d.WakeOnLanEnabled)
103+
}
104+
if assert.NotNil(t, d.SlotInfo) {
105+
si, ok := d.SlotInfo.(*types.VirtualDevicePciBusSlotInfo)
106+
assert.True(t, ok)
107+
assert.Equal(t, int32(192), si.PciSlotNumber)
108+
}
109+
if assert.NotNil(t, d.UptCompatibilityEnabled) {
110+
assert.False(t, *d.UptCompatibilityEnabled)
111+
}
112+
}
113+
114+
if d, ok := cs.DeviceChange[4].GetVirtualDeviceConfigSpec().Device.(*types.VirtualMachineVideoCard); assert.True(t, ok) {
115+
if assert.NotNil(t, d.Enable3DSupport) {
116+
assert.False(t, *d.Enable3DSupport)
117+
}
118+
assert.Equal(t, int64(262144), d.GraphicsMemorySizeInKB)
119+
if assert.NotNil(t, d.UseAutoDetect) {
120+
assert.False(t, *d.UseAutoDetect)
121+
}
122+
assert.Equal(t, int64(4096), d.VideoRamSizeInKB)
123+
assert.Equal(t, int32(1), d.NumDisplays)
124+
assert.Equal(t, "automatic", d.Use3dRenderer)
125+
}
126+
127+
var ideControllerKey int32
128+
if d, ok := cs.DeviceChange[5].GetVirtualDeviceConfigSpec().Device.(*types.VirtualIDEController); assert.True(t, ok) {
129+
ideControllerKey = d.Key
130+
assert.Equal(t, int32(1), d.BusNumber)
131+
}
132+
133+
if d, ok := cs.DeviceChange[6].GetVirtualDeviceConfigSpec().Device.(*types.VirtualIDEController); assert.True(t, ok) {
134+
assert.Equal(t, int32(0), d.BusNumber)
135+
}
136+
137+
if d, ok := cs.DeviceChange[7].GetVirtualDeviceConfigSpec().Device.(*types.VirtualCdrom); assert.True(t, ok) {
138+
if assert.NotNil(t, d.UnitNumber) {
139+
assert.Equal(t, int32(0), *d.UnitNumber)
140+
}
141+
assert.Equal(t, ideControllerKey, d.ControllerKey)
142+
}
143+
144+
var sioControllerKey int32
145+
if d, ok := cs.DeviceChange[8].GetVirtualDeviceConfigSpec().Device.(*types.VirtualSIOController); assert.True(t, ok) {
146+
sioControllerKey = d.Key
147+
}
148+
149+
if d, ok := cs.DeviceChange[9].GetVirtualDeviceConfigSpec().Device.(*types.VirtualFloppy); assert.True(t, ok) {
150+
if assert.NotNil(t, d.UnitNumber) {
151+
assert.Equal(t, int32(0), *d.UnitNumber)
152+
}
153+
assert.Equal(t, sioControllerKey, d.ControllerKey)
154+
}
155+
156+
if d, ok := cs.DeviceChange[10].GetVirtualDeviceConfigSpec().Device.(*types.VirtualMachineVMCIDevice); assert.True(t, ok) {
157+
if assert.NotNil(t, d.AllowUnrestrictedCommunication) {
158+
assert.False(t, *d.AllowUnrestrictedCommunication)
159+
}
160+
}
161+
162+
var scsiController2Key int32
163+
if d, ok := cs.DeviceChange[11].GetVirtualDeviceConfigSpec().Device.(*types.ParaVirtualSCSIController); assert.True(t, ok) {
164+
scsiController2Key = d.Key
165+
assert.Equal(t, int32(1), d.BusNumber)
166+
assert.Nil(t, d.SlotInfo)
167+
}
168+
169+
if d, ok := cs.DeviceChange[12].GetVirtualDeviceConfigSpec().Device.(*types.VirtualDisk); assert.True(t, ok) {
170+
assert.Equal(t, scsiController2Key, d.ControllerKey)
171+
if assert.NotNil(t, d.UnitNumber) {
172+
assert.Equal(t, int32(0), *d.UnitNumber)
173+
}
174+
db, ok := d.Backing.(*types.VirtualDiskFlatVer2BackingInfo)
175+
assert.True(t, ok)
176+
assert.Equal(t, string(types.VirtualDiskModePersistent), db.DiskMode)
177+
if assert.NotNil(t, db.ThinProvisioned) {
178+
assert.True(t, *db.ThinProvisioned)
179+
}
180+
assert.Equal(t, int64(10*1024*1024*1024), d.CapacityInBytes)
181+
}
182+
183+
var sataController1Key int32
184+
if d, ok := cs.DeviceChange[13].GetVirtualDeviceConfigSpec().Device.(*types.VirtualAHCIController); assert.True(t, ok) {
185+
sataController1Key = d.Key
186+
assert.Equal(t, int32(0), d.BusNumber)
187+
assert.Nil(t, d.SlotInfo)
188+
}
189+
190+
if d, ok := cs.DeviceChange[14].GetVirtualDeviceConfigSpec().Device.(*types.VirtualDisk); assert.True(t, ok) {
191+
assert.Equal(t, sataController1Key, d.ControllerKey)
192+
if assert.NotNil(t, d.UnitNumber) {
193+
assert.Equal(t, int32(0), *d.UnitNumber)
194+
}
195+
db, ok := d.Backing.(*types.VirtualDiskFlatVer2BackingInfo)
196+
assert.True(t, ok)
197+
assert.Equal(t, string(types.VirtualDiskModePersistent), db.DiskMode)
198+
if assert.NotNil(t, db.ThinProvisioned) {
199+
assert.True(t, *db.ThinProvisioned)
200+
}
201+
assert.Equal(t, int64(10*1024*1024*1024), d.CapacityInBytes)
202+
}
203+
204+
var sataController2Key int32
205+
if d, ok := cs.DeviceChange[15].GetVirtualDeviceConfigSpec().Device.(*types.VirtualAHCIController); assert.True(t, ok) {
206+
sataController2Key = d.Key
207+
assert.Equal(t, int32(1), d.BusNumber)
208+
assert.Nil(t, d.SlotInfo)
209+
}
210+
211+
if d, ok := cs.DeviceChange[16].GetVirtualDeviceConfigSpec().Device.(*types.VirtualDisk); assert.True(t, ok) {
212+
assert.Equal(t, sataController2Key, d.ControllerKey)
213+
if assert.NotNil(t, d.UnitNumber) {
214+
assert.Equal(t, int32(0), *d.UnitNumber)
215+
}
216+
db, ok := d.Backing.(*types.VirtualDiskFlatVer2BackingInfo)
217+
assert.True(t, ok)
218+
assert.Equal(t, string(types.VirtualDiskModePersistent), db.DiskMode)
219+
if assert.NotNil(t, db.ThinProvisioned) {
220+
assert.True(t, *db.ThinProvisioned)
221+
}
222+
assert.Equal(t, int64(10*1024*1024*1024), d.CapacityInBytes)
223+
}
224+
225+
var nvmeController1Key int32
226+
if d, ok := cs.DeviceChange[17].GetVirtualDeviceConfigSpec().Device.(*types.VirtualNVMEController); assert.True(t, ok) {
227+
nvmeController1Key = d.Key
228+
assert.Equal(t, int32(0), d.BusNumber)
229+
assert.Nil(t, d.SlotInfo)
230+
}
231+
232+
if d, ok := cs.DeviceChange[18].GetVirtualDeviceConfigSpec().Device.(*types.VirtualDisk); assert.True(t, ok) {
233+
assert.Equal(t, nvmeController1Key, d.ControllerKey)
234+
if assert.NotNil(t, d.UnitNumber) {
235+
assert.Equal(t, int32(0), *d.UnitNumber)
236+
}
237+
db, ok := d.Backing.(*types.VirtualDiskFlatVer2BackingInfo)
238+
assert.True(t, ok)
239+
assert.Equal(t, string(types.VirtualDiskModePersistent), db.DiskMode)
240+
if assert.NotNil(t, db.ThinProvisioned) {
241+
assert.True(t, *db.ThinProvisioned)
242+
}
243+
assert.Equal(t, int64(10*1024*1024*1024), d.CapacityInBytes)
244+
}
245+
246+
if d, ok := cs.DeviceChange[19].GetVirtualDeviceConfigSpec().Device.(*types.VirtualUSBController); assert.True(t, ok) {
247+
if assert.NotNil(t, d.AutoConnectDevices) {
248+
assert.True(t, *d.AutoConnectDevices)
249+
}
250+
if assert.NotNil(t, d.EhciEnabled) {
251+
assert.False(t, *d.EhciEnabled)
252+
}
253+
}
254+
255+
if d, ok := cs.DeviceChange[20].GetVirtualDeviceConfigSpec().Device.(*types.VirtualUSBXHCIController); assert.True(t, ok) {
256+
if assert.NotNil(t, d.AutoConnectDevices) {
257+
assert.True(t, *d.AutoConnectDevices)
258+
}
259+
}
260+
}
261+
262+
assert.ElementsMatch(t, cs.ExtraConfig, []types.BaseOptionValue{
263+
&types.OptionValue{
264+
Key: "guest_rpc.auth.cloud-init.set",
265+
Value: "FALSE",
266+
},
267+
})
268+
269+
if assert.NotNil(t, cs.Flags) {
270+
if assert.NotNil(t, cs.Flags.VbsEnabled) {
271+
assert.False(t, *cs.Flags.VbsEnabled)
272+
}
273+
if assert.NotNil(t, cs.Flags.VvtdEnabled) {
274+
assert.False(t, *cs.Flags.VvtdEnabled)
275+
}
276+
}
277+
278+
assert.Equal(t, "bios", cs.Firmware)
279+
280+
if assert.NotNil(t, cs.BootOptions) {
281+
if assert.NotNil(t, cs.BootOptions.EfiSecureBootEnabled) {
282+
assert.False(t, *cs.BootOptions.EfiSecureBootEnabled)
283+
}
284+
}
285+
286+
if assert.NotNil(t, cs.CpuHotAddEnabled) {
287+
assert.False(t, *cs.CpuHotAddEnabled)
288+
}
289+
if assert.NotNil(t, cs.CpuHotRemoveEnabled) {
290+
assert.False(t, *cs.CpuHotRemoveEnabled)
291+
}
292+
if assert.NotNil(t, cs.MemoryHotAddEnabled) {
293+
assert.False(t, *cs.MemoryHotAddEnabled)
294+
}
295+
if assert.NotNil(t, cs.NestedHVEnabled) {
296+
assert.False(t, *cs.NestedHVEnabled)
297+
}
298+
if assert.NotNil(t, cs.VirtualICH7MPresent) {
299+
assert.False(t, *cs.VirtualICH7MPresent)
300+
}
301+
302+
assert.Equal(t, int32(1), cs.SimultaneousThreads)
303+
304+
if assert.NotNil(t, cs.VPMCEnabled) {
305+
assert.False(t, *cs.VPMCEnabled)
306+
}
307+
308+
if assert.NotNil(t, cs.CpuAllocation) {
309+
if assert.NotNil(t, cs.CpuAllocation.Shares) {
310+
assert.Equal(t, &types.SharesInfo{
311+
Shares: 2000,
312+
Level: types.SharesLevelNormal,
313+
}, cs.CpuAllocation.Shares)
314+
}
315+
}
316+
317+
if assert.NotNil(t, cs.PowerOpInfo) {
318+
assert.Equal(t, &types.VirtualMachineDefaultPowerOpInfo{
319+
PowerOffType: "soft",
320+
ResetType: "soft",
321+
SuspendType: "hard",
322+
StandbyAction: "checkpoint",
323+
}, cs.PowerOpInfo)
324+
}
325+
326+
if assert.NotNil(t, cs.Tools) {
327+
assert.Equal(t, &types.ToolsConfigInfo{
328+
SyncTimeWithHost: types.NewBool(false),
329+
SyncTimeWithHostAllowed: types.NewBool(true),
330+
AfterPowerOn: types.NewBool(true),
331+
AfterResume: types.NewBool(true),
332+
BeforeGuestShutdown: types.NewBool(true),
333+
BeforeGuestStandby: types.NewBool(true),
334+
ToolsUpgradePolicy: "manual",
335+
}, cs.Tools)
336+
}
337+
338+
if va, ok := cs.VAppConfig.(*types.VAppConfigSpec); assert.True(t, ok) {
339+
if assert.Len(t, va.Product, 4) {
340+
assert.ElementsMatch(t,
341+
[]types.VAppProductSpec{
342+
{
343+
ArrayUpdateSpec: types.ArrayUpdateSpec{
344+
Operation: types.ArrayUpdateOperationAdd,
345+
},
346+
Info: &types.VAppProductInfo{
347+
Key: 0,
348+
Name: "HAProxy for the Load Balancer API v0.2.0",
349+
Vendor: "VMware Inc.",
350+
Version: "v0.2.0",
351+
FullVersion: "v0.2.0",
352+
ProductUrl: "https://vmware.com",
353+
VendorUrl: "https://vmware.com",
354+
},
355+
},
356+
{
357+
ArrayUpdateSpec: types.ArrayUpdateSpec{
358+
Operation: types.ArrayUpdateOperationAdd,
359+
},
360+
Info: &types.VAppProductInfo{
361+
Key: 1,
362+
ClassId: "appliance",
363+
},
364+
},
365+
{
366+
ArrayUpdateSpec: types.ArrayUpdateSpec{
367+
Operation: types.ArrayUpdateOperationAdd,
368+
},
369+
Info: &types.VAppProductInfo{
370+
Key: 2,
371+
ClassId: "network",
372+
},
373+
},
374+
{
375+
ArrayUpdateSpec: types.ArrayUpdateSpec{
376+
Operation: types.ArrayUpdateOperationAdd,
377+
},
378+
Info: &types.VAppProductInfo{
379+
Key: 3,
380+
ClassId: "loadbalance",
381+
},
382+
},
383+
},
384+
va.Product,
385+
)
386+
}
387+
if assert.Len(t, va.Property, 6) {
388+
assert.ElementsMatch(t,
389+
[]types.VAppPropertySpec{
390+
391+
// default
392+
{
393+
ArrayUpdateSpec: types.ArrayUpdateSpec{
394+
Operation: types.ArrayUpdateOperationAdd,
395+
},
396+
Info: &types.VAppPropertyInfo{
397+
Key: 0,
398+
Category: "Load Balancer API",
399+
Id: "BUILD_TIMESTAMP",
400+
Type: "string",
401+
UserConfigurable: types.NewBool(false),
402+
DefaultValue: "1615488399",
403+
},
404+
},
405+
{
406+
ArrayUpdateSpec: types.ArrayUpdateSpec{
407+
Operation: types.ArrayUpdateOperationAdd,
408+
},
409+
Info: &types.VAppPropertyInfo{
410+
Key: 1,
411+
Category: "Load Balancer API",
412+
Id: "BUILD_DATE",
413+
Type: "string",
414+
UserConfigurable: types.NewBool(false),
415+
DefaultValue: "2021-03-11T18:46:39Z",
416+
},
417+
},
418+
419+
// appliance
420+
{
421+
ArrayUpdateSpec: types.ArrayUpdateSpec{
422+
Operation: types.ArrayUpdateOperationAdd,
423+
},
424+
Info: &types.VAppPropertyInfo{
425+
Key: 2,
426+
Category: "1. Appliance Configuration",
427+
ClassId: "appliance",
428+
Id: "root_pwd",
429+
Label: "1.1. Root Password",
430+
Type: "string",
431+
UserConfigurable: types.NewBool(true),
432+
Description: "The initial password of the root user. Subsequent changes of password should be performed in operating system. (6-128 characters)",
433+
},
434+
},
435+
436+
// network
437+
{
438+
ArrayUpdateSpec: types.ArrayUpdateSpec{
439+
Operation: types.ArrayUpdateOperationAdd,
440+
},
441+
Info: &types.VAppPropertyInfo{
442+
Key: 3,
443+
Category: "2. Network Config",
444+
ClassId: "network",
445+
Id: "hostname",
446+
Label: "2.1. Host Name",
447+
Type: "string",
448+
UserConfigurable: types.NewBool(true),
449+
DefaultValue: "haproxy.local",
450+
Description: "The host name. A fully-qualified domain name is also supported.",
451+
},
452+
},
453+
454+
// loadbalance
455+
{
456+
ArrayUpdateSpec: types.ArrayUpdateSpec{
457+
Operation: types.ArrayUpdateOperationAdd,
458+
},
459+
Info: &types.VAppPropertyInfo{
460+
Key: 4,
461+
Category: "3. Load Balancing",
462+
ClassId: "loadbalance",
463+
Id: "service_ip_range",
464+
Label: "3.1. Load Balancer IP Ranges, comma-separated in CIDR format (Eg 1.2.3.4/28,5.6.7.8/28)",
465+
Type: "string",
466+
UserConfigurable: types.NewBool(true),
467+
Description: "The IP ranges the load balancer will use for Kubernetes Services and Control Planes. The Appliance will currently respond to ALL the IPs in these ranges whether they're assigned or not. As such, these ranges must not overlap with the IPs assigned for the appliance or any other VMs on the network.",
468+
},
469+
},
470+
{
471+
ArrayUpdateSpec: types.ArrayUpdateSpec{
472+
Operation: types.ArrayUpdateOperationAdd,
473+
},
474+
Info: &types.VAppPropertyInfo{
475+
Key: 5,
476+
Category: "3. Load Balancing",
477+
ClassId: "loadbalance",
478+
Id: "dataplane_port",
479+
Label: "3.2. Dataplane API Management Port",
480+
Type: "int",
481+
UserConfigurable: types.NewBool(true),
482+
DefaultValue: "5556",
483+
Description: "Specifies the port on which the Dataplane API will be advertized on the Management Network.",
484+
},
485+
},
486+
},
487+
va.Property,
488+
)
489+
}
490+
}
491+
}

‎ovf/envelope.go

+11-3
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ type Property struct {
125125
UserConfigurable *bool `xml:"userConfigurable,attr"`
126126
Default *string `xml:"value,attr"`
127127
Password *bool `xml:"password,attr"`
128+
Configuration *string `xml:"configuration,attr"`
128129

129130
Label *string `xml:"Label"`
130131
Description *string `xml:"Description"`
@@ -207,9 +208,11 @@ type VirtualSystemSettingData struct {
207208
type ResourceAllocationSettingData struct {
208209
CIMResourceAllocationSettingData
209210

210-
Required *bool `xml:"required,attr"`
211-
Configuration *string `xml:"configuration,attr"`
212-
Bound *string `xml:"bound,attr"`
211+
Required *bool `xml:"required,attr"`
212+
Configuration *string `xml:"configuration,attr"`
213+
Bound *string `xml:"bound,attr"`
214+
Config []Config `xml:"Config"`
215+
CoresPerSocket *CoresPerSocket `xml:"CoresPerSocket"`
213216
}
214217

215218
type StorageAllocationSettingData struct {
@@ -239,3 +242,8 @@ type DeploymentOptionConfiguration struct {
239242
Label string `xml:"Label"`
240243
Description string `xml:"Description"`
241244
}
245+
246+
type CoresPerSocket struct {
247+
Required *bool `xml:"required,attr"`
248+
Value int32 `xml:",chardata"`
249+
}

‎ovf/fixtures/haproxy-vsphere.ovf

+594
Large diffs are not rendered by default.

‎ovf/ovf_test.go

+26-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
/*
2-
Copyright (c) 2015 VMware, Inc. All Rights Reserved.
2+
Copyright (c) 2015-2024 VMware, Inc. All Rights Reserved.
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
66
You may obtain a copy of the License at
77
8-
http://www.apache.org/licenses/LICENSE-2.0
8+
http://www.apache.org/licenses/LICENSE-2.0
99
1010
Unless required by applicable law or agreed to in writing, software
1111
distributed under the License is distributed on an "AS IS" BASIS,
@@ -107,3 +107,27 @@ func TestVirtualSystemCollection(t *testing.T) {
107107
assert.Equal(t, e.VirtualSystemCollection.VirtualSystem[0].ID, "storage server")
108108
assert.Equal(t, e.VirtualSystemCollection.VirtualSystem[1].ID, "web-server")
109109
}
110+
111+
func TestMultipleDeploymentConfigs(t *testing.T) {
112+
e := testEnvelope(t, "fixtures/haproxy-vsphere.ovf")
113+
114+
assert.NotNil(t, e.VirtualSystem)
115+
assert.Nil(t, e.VirtualSystemCollection)
116+
assert.NotNil(t, e.DeploymentOption)
117+
assert.Len(t, e.DeploymentOption.Configuration, 2)
118+
119+
assert.NotNil(t, e.DeploymentOption.Configuration[0].Default)
120+
assert.True(t, *e.DeploymentOption.Configuration[0].Default)
121+
assert.Equal(t, "default", e.DeploymentOption.Configuration[0].ID)
122+
123+
assert.Nil(t, e.DeploymentOption.Configuration[1].Default)
124+
assert.Equal(t, "frontend", e.DeploymentOption.Configuration[1].ID)
125+
126+
assert.Len(t, e.VirtualSystem.VirtualHardware, 1)
127+
assert.Len(t, e.VirtualSystem.VirtualHardware[0].Item, 23)
128+
assert.Len(t, e.VirtualSystem.VirtualHardware[0].Item[2].Config, 1)
129+
assert.NotNil(t, e.VirtualSystem.VirtualHardware[0].Item[2].Config[0].Required)
130+
assert.False(t, *e.VirtualSystem.VirtualHardware[0].Item[2].Config[0].Required)
131+
assert.Equal(t, "slotInfo.pciSlotNumber", e.VirtualSystem.VirtualHardware[0].Item[2].Config[0].Key)
132+
assert.Equal(t, "128", e.VirtualSystem.VirtualHardware[0].Item[2].Config[0].Value)
133+
}

0 commit comments

Comments
 (0)
Please sign in to comment.