Skip to content

Commit 42bf813

Browse files
committedDec 5, 2024
api: Update OVF parser to conform to spec
This patch updates the OVF parser to conform to the DMTF spec for OVF content. This includes: * support for VirtualSystemCollection * a single OperatingSystem section in VirtualSystem * removing the roll-up sections at the root of the Envelope that belong only under a VirtualSystem or VirtualSystemCollection BREAKING: Users of the `ovf` package will need to update their sources to conform to the changes from this patch. It should be a fairly simple change. Signed-off-by: akutz <akutz@vmware.com>
1 parent 46c15fb commit 42bf813

File tree

5 files changed

+234
-21
lines changed

5 files changed

+234
-21
lines changed
 

‎ovf/envelope.go

+30-16
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2015-2023 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.
@@ -20,32 +20,46 @@ import (
2020
"fmt"
2121
)
2222

23+
// Envelope is defined according to
24+
// https://www.dmtf.org/sites/default/files/standards/documents/DSP0243_2.1.1.pdf.
25+
//
26+
// Section 9 describes the parent/child relationships.
27+
//
28+
// A VirtualSystem may have zero or more VirtualHardware sections.
2329
type Envelope struct {
2430
References []File `xml:"References>File"`
2531

2632
// Package level meta-data
27-
Annotation *AnnotationSection `xml:"AnnotationSection"`
28-
Product *ProductSection `xml:"ProductSection"`
29-
Network *NetworkSection `xml:"NetworkSection"`
30-
Disk *DiskSection `xml:"DiskSection"`
31-
OperatingSystem *OperatingSystemSection `xml:"OperatingSystemSection"`
32-
Eula *EulaSection `xml:"EulaSection"`
33-
VirtualHardware *VirtualHardwareSection `xml:"VirtualHardwareSection"`
34-
ResourceAllocation *ResourceAllocationSection `xml:"ResourceAllocationSection"`
35-
DeploymentOption *DeploymentOptionSection `xml:"DeploymentOptionSection"`
33+
Disk *DiskSection `xml:"DiskSection,omitempty"`
34+
Network *NetworkSection `xml:"NetworkSection,omitempty"`
35+
DeploymentOption *DeploymentOptionSection `xml:"DeploymentOptionSection,omitempty"`
3636

3737
// Content: A VirtualSystem or a VirtualSystemCollection
38-
VirtualSystem *VirtualSystem `xml:"VirtualSystem"`
38+
VirtualSystem *VirtualSystem `xml:"VirtualSystem,omitempty"`
39+
VirtualSystemCollection *VirtualSystemCollection `xml:"VirtualSystemCollection,omitempty"`
3940
}
4041

4142
type VirtualSystem struct {
4243
Content
4344

44-
Annotation []AnnotationSection `xml:"AnnotationSection"`
45-
Product []ProductSection `xml:"ProductSection"`
46-
OperatingSystem []OperatingSystemSection `xml:"OperatingSystemSection"`
47-
Eula []EulaSection `xml:"EulaSection"`
48-
VirtualHardware []VirtualHardwareSection `xml:"VirtualHardwareSection"`
45+
Annotation *AnnotationSection `xml:"AnnotationSection,omitempty"`
46+
Product []ProductSection `xml:"ProductSection,omitempty"`
47+
Eula []EulaSection `xml:"EulaSection,omitempty"`
48+
OperatingSystem *OperatingSystemSection `xml:"OperatingSystemSection,omitempty"`
49+
VirtualHardware []VirtualHardwareSection `xml:"VirtualHardwareSection,omitempty"`
50+
}
51+
52+
type VirtualSystemCollection struct {
53+
Content
54+
55+
// Collection level meta-data
56+
ResourceAllocation *ResourceAllocationSection `xml:"ResourceAllocationSection,omitempty"`
57+
Annotation *AnnotationSection `xml:"AnnotationSection,omitempty"`
58+
Product []ProductSection `xml:"ProductSection,omitempty"`
59+
Eula []EulaSection `xml:"EulaSection,omitempty"`
60+
61+
// Content: One or more VirtualSystems
62+
VirtualSystem []VirtualSystem `xml:"VirtualSystem,omitempty"`
4963
}
5064

5165
type File struct {
+189
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
Example 3 from https://www.dmtf.org/sites/default/files/standards/documents/DSP0243_2.1.1.pdf
4+
-->
5+
<Envelope
6+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
7+
xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/2"
8+
xmlns="http://schemas.dmtf.org/ovf/envelope/2"
9+
xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData"
10+
xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData"
11+
xmlns:epasd="http://schemas.dmtf.org/wbem/wscim/1/cim2608 schema/2/CIM_EthernetPortAllocationSettingData"
12+
xmlns:sasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_StorageAllocationSettingData">
13+
<!-- References to all external files -->
14+
<References>
15+
<File ovf:id="file1" ovf:href="vmdisk1.vmdk" ovf:size="2000000000" />
16+
</References>
17+
<!-- Describes meta-information for all virtual disks in the package -->
18+
<DiskSection>
19+
<Info>Describes the set of virtual disks</Info>
20+
<Disk ovf:diskId="vmdisk1" ovf:fileRef="file1" ovf:capacity="4294967296"
21+
ovf:format="http://www.examplecompany.com/interfaces/specifications/vmdk.html#sparse" />
22+
</DiskSection>
23+
<!-- Describes all networks used in the package -->
24+
<NetworkSection>
25+
<Info>List of logical networks used in the package</Info>
26+
<Network ovf:name="VS Network">
27+
<Description>The network that the VSs connect to</Description>
28+
<!-- Network port profile for storage traffic -->
29+
30+
<NetworkPortProfileURI>http://www.dmtf.org/networkportprofiles/networkportprofile1.xml</NetworkPortProfileURI>
31+
<!-- Network port profile for networking traffic -->
32+
33+
<NetworkPortProfileURI>http://www.dmtf.org/networkportprofiles/networkportprofile2.xml</NetworkPortProfileURI>
34+
</Network>
35+
</NetworkSection>
36+
<VirtualSystemCollection ovf:id="vsc1">
37+
<Info>Collection of 2 VSs</Info>
38+
<VirtualSystem ovf:id="storage server">
39+
<Info>Describes a virtual system</Info>
40+
<Name>Virtual Appliance One</Name>
41+
<ProductSection>
42+
<Info>Describes product information for the appliance</Info>
43+
<Product>The Great Appliance</Product>
44+
<Vendor>Some Great Corporation</Vendor>
45+
<Version>13.00</Version>
46+
<FullVersion>13.00-b5</FullVersion>
47+
<ProductUrl>http://www.somegreatcorporation.com/greatappliance</ProductUrl>
48+
<VendorUrl>http://www.somegreatcorporation.com/</VendorUrl>
49+
<Property ovf:key="adminemail" ovf:type="string">
50+
<Description>Email address of administrator</Description>
51+
</Property>
52+
<Property ovf:key="app_ip" ovf:type="string" ovf:defaultValue="192.168.0.10">
53+
<Description>The IP address of this appliance</Description>
54+
</Property>
55+
</ProductSection>
56+
<AnnotationSection ovf:required="false">
57+
<Info>A random annotation on this service. It can be ignored</Info>
58+
<Annotation>Contact customer support if you have any problems</Annotation>
59+
</AnnotationSection>
60+
<EulaSection>
61+
<Info>License information for the appliance</Info>
62+
<License>Insert your favorite license here</License>
63+
</EulaSection>
64+
<VirtualHardwareSection>
65+
<Info>Memory = 4 GB, CPU = 1 GHz, Disk = 100 GB, 1 Ethernet nic</Info>
66+
<Item>
67+
<rasd:AllocationUnits>Hertz*10^9</rasd:AllocationUnits>
68+
<rasd:Description>Virtual CPU</rasd:Description>
69+
<rasd:ElementName>1 GHz virtual CPU</rasd:ElementName>
70+
<rasd:InstanceID>1</rasd:InstanceID>
71+
<rasd:Reservation>1</rasd:Reservation>
72+
<rasd:ResourceType>3</rasd:ResourceType>
73+
<rasd:VirtualQuantity>1</rasd:VirtualQuantity>
74+
</Item>
75+
<Item>
76+
<rasd:AllocationUnits>byte*2^30</rasd:AllocationUnits>
77+
<rasd:Description>Memory</rasd:Description>
78+
<rasd:ElementName>1 GByte of memory</rasd:ElementName>
79+
<rasd:InstanceID>2</rasd:InstanceID>
80+
<rasd:ResourceType>4</rasd:ResourceType>
81+
<rasd:VirtualQuantity>1</rasd:VirtualQuantity>
82+
</Item>
83+
<EthernetPortItem>
84+
<epasd:Address>00-16-8B-DB-00-5E</epasd:Address>
85+
<epasd:Connection>VS Network</epasd:Connection>
86+
<epasd:Description>Virtual NIC</epasd:Description>
87+
88+
<epasd:ElementName>Ethernet Port</epasd:ElementName>
89+
90+
<epasd:InstanceID>3</epasd:InstanceID>
91+
92+
<epasd:NetworkPortProfileID>
93+
http://www.dmtf.org/networkportprofiles/networkportprofile1.xml</epasd:NetworkPortProfileID>
94+
<epasd:NetworkPortProfileIDType>2</epasd:NetworkPortProfileIDType>
95+
<epasd:ResourceType>10</epasd:ResourceType>
96+
<epasd:VirtualQuantityUnits>1</epasd:VirtualQuantityUnits>
97+
</EthernetPortItem>
98+
<StorageItem>
99+
<sasd:AllocationUnits>byte*2^30</sasd:AllocationUnits>
100+
<sasd:Description>Virtual Disk</sasd:Description>
101+
<sasd:ElementName>100 GByte Virtual Disk</sasd:ElementName>
102+
<sasd:InstanceID>4</sasd:InstanceID>
103+
<sasd:Reservation>100</sasd:Reservation>
104+
<sasd:ResourceType>31</sasd:ResourceType>
105+
<sasd:VirtualQuantity>1</sasd:VirtualQuantity>
106+
</StorageItem>
107+
</VirtualHardwareSection>
108+
<OperatingSystemSection ovf:id="58" ovf:required="false">
109+
<Info>Guest Operating System</Info>
110+
<Description>OS</Description>
111+
</OperatingSystemSection>
112+
</VirtualSystem>
113+
<VirtualSystem ovf:id="web-server">
114+
<Info>Describes a virtual system</Info>
115+
<Name>Virtual Appliance Two</Name>
116+
<ProductSection>
117+
<Info>Describes product information for the appliance</Info>
118+
<Product>The Great Appliance</Product>
119+
<Vendor>Some Great Corporation</Vendor>
120+
<Version>13.00</Version>
121+
<FullVersion>13.00-b5</FullVersion>
122+
<ProductUrl>http://www.somegreatcorporation.com/greatappliance</ProductUrl>
123+
<VendorUrl>http://www.somegreatcorporation.com/</VendorUrl>
124+
<Property ovf:key="adminemail" ovf:type="string">
125+
<Description>Email address of administrator</Description>
126+
</Property>
127+
<Property ovf:key="app_ip" ovf:type="string" ovf:defaultValue="192.168.0.10">
128+
<Description>The IP address of this appliance</Description>
129+
</Property>
130+
</ProductSection>
131+
<AnnotationSection ovf:required="false">
132+
<Info>A random annotation on this service. It can be ignored</Info>
133+
<Annotation>Contact customer support if you have any problems</Annotation>
134+
</AnnotationSection>
135+
<EulaSection>
136+
<Info>License information for the appliance</Info>
137+
<License>Insert your favorite license here</License>
138+
</EulaSection>
139+
<VirtualHardwareSection>
140+
<Info>Memory = 4 GB, CPU = 1 GHz, Disk = 100 GB, 1 Ethernet nic</Info>
141+
<Item>
142+
<rasd:AllocationUnits>Hertz*10^9</rasd:AllocationUnits>
143+
<rasd:Description>Virtual CPU</rasd:Description>
144+
<rasd:ElementName>1 GHz virtual CPU</rasd:ElementName>
145+
<rasd:InstanceID>1</rasd:InstanceID>
146+
<rasd:Reservation>1</rasd:Reservation>
147+
<rasd:ResourceType>3</rasd:ResourceType>
148+
<rasd:VirtualQuantity>1</rasd:VirtualQuantity>
149+
</Item>
150+
<Item>
151+
<rasd:AllocationUnits>byte*2^30</rasd:AllocationUnits>
152+
<rasd:Description>Memory</rasd:Description>
153+
<rasd:ElementName>1 GByte of memory</rasd:ElementName>
154+
<rasd:InstanceID>2</rasd:InstanceID>
155+
<rasd:ResourceType>4</rasd:ResourceType>
156+
<rasd:VirtualQuantity>1</rasd:VirtualQuantity>
157+
</Item>
158+
<EthernetPortItem>
159+
<epasd:Address>00-16-8B-DB-00-5F</epasd:Address>
160+
<epasd:Connection>VS Network</epasd:Connection>
161+
<epasd:Description>Virtual NIC</epasd:Description>
162+
163+
<epasd:ElementName>Ethernet Port</epasd:ElementName>
164+
<!-- Virtual NIC for networking traffic -->
165+
<epasd:InstanceID>3</epasd:InstanceID>
166+
167+
<epasd:NetworkPortProfileID>
168+
http://www.dmtf.org/networkportprofiles/networkportprofile2.xml</epasd:NetworkPortProfileID>
169+
<epasd:NetworkPortProfileIDType>2</epasd:NetworkPortProfileIDType>
170+
<epasd:ResourceType>10</epasd:ResourceType>
171+
<epasd:VirtualQuantityUnits>1</epasd:VirtualQuantityUnits>
172+
</EthernetPortItem>
173+
<StorageItem>
174+
<sasd:AllocationUnits>byte*2^30</sasd:AllocationUnits>
175+
<sasd:Description>Virtual Disk</sasd:Description>
176+
<sasd:ElementName>100 GByte Virtual Disk</sasd:ElementName>
177+
<sasd:InstanceID>4</sasd:InstanceID>
178+
<sasd:Reservation>100</sasd:Reservation>
179+
<sasd:ResourceType>31</sasd:ResourceType>
180+
<sasd:VirtualQuantity>1</sasd:VirtualQuantity>
181+
</StorageItem>
182+
</VirtualHardwareSection>
183+
<OperatingSystemSection ovf:id="58" ovf:required="false">
184+
<Info>Guest Operating System</Info>
185+
<Description>OS</Description>
186+
</OperatingSystemSection>
187+
</VirtualSystem>
188+
</VirtualSystemCollection>
189+
</Envelope>

‎ovf/importer/spec.go

+1-3
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,7 @@ func Spec(fpath string, a Archive, hidden, verbose bool) (*Options, error) {
114114
}
115115

116116
if e.VirtualSystem != nil && e.VirtualSystem.Annotation != nil {
117-
for _, a := range e.VirtualSystem.Annotation {
118-
o.Annotation += a.Annotation
119-
}
117+
o.Annotation = e.VirtualSystem.Annotation.Annotation
120118
}
121119

122120
if e.Network != nil {

‎ovf/ovf_test.go

+12
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import (
2222
"os"
2323
"testing"
2424
"text/tabwriter"
25+
26+
"github.com/stretchr/testify/assert"
2527
)
2628

2729
func testEnvelope(t *testing.T, fn string) *Envelope {
@@ -95,3 +97,13 @@ func TestDeploymentOptions(t *testing.T) {
9597
tw.Flush()
9698
t.Log(b.String())
9799
}
100+
101+
func TestVirtualSystemCollection(t *testing.T) {
102+
e := testEnvelope(t, "fixtures/virtualsystemcollection.ovf")
103+
104+
assert.Nil(t, e.VirtualSystem)
105+
assert.NotNil(t, e.VirtualSystemCollection)
106+
assert.Len(t, e.VirtualSystemCollection.VirtualSystem, 2)
107+
assert.Equal(t, e.VirtualSystemCollection.VirtualSystem[0].ID, "storage server")
108+
assert.Equal(t, e.VirtualSystemCollection.VirtualSystem[1].ID, "web-server")
109+
}

‎simulator/ovf_manager.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,8 @@ func (m *OvfManager) CreateImportSpec(ctx *Context, req *types.CreateImportSpec)
185185
}
186186
}
187187

188-
if os := env.VirtualSystem.OperatingSystem; len(os) != 0 {
189-
if id := os[0].OSType; id != nil {
188+
if os := env.VirtualSystem.OperatingSystem; os != nil {
189+
if id := os.OSType; id != nil {
190190
spec.ConfigSpec.GuestId = *id
191191
}
192192
}

0 commit comments

Comments
 (0)
Please sign in to comment.