Repository: vmware/govmomi
Pull request #2277 (2021-02-10 00:09:34)

ovf: add Config and ExtraConfig to VirtualHardwareSection
ovf.Unmarshal() didn't have much test coverage other than the govc import.ova bats tests.
Update ovf/ovf_test.go to validate these fields are properly unmarshaled.


Patch:
diff --git a/ovf/envelope.go b/ovf/envelope.go
index fa4690d8..274adb9d 100644
--- a/ovf/envelope.go
+++ b/ovf/envelope.go
@@ -148,6 +148,12 @@ type EulaSection struct {
 	License string `xml:"License"`
 }
 
+type Config struct {
+	Required *bool  `xml:"required,attr"`
+	Key      string `xml:"key,attr"`
+	Value    string `xml:"value,attr"`
+}
+
 type VirtualHardwareSection struct {
 	Section
 
@@ -157,6 +163,8 @@ type VirtualHardwareSection struct {
 	System      *VirtualSystemSettingData       `xml:"System"`
 	Item        []ResourceAllocationSettingData `xml:"Item"`
 	StorageItem []StorageAllocationSettingData  `xml:"StorageItem"`
+	Config      []Config                        `xml:"Config"`
+	ExtraConfig []Config                        `xml:"ExtraConfig"`
 }
 
 type VirtualSystemSettingData struct {
diff --git a/ovf/fixtures/ttylinux.ovf b/ovf/fixtures/ttylinux.ovf
new file mode 100644
index 00000000..2b7bec5b
--- /dev/null
+++ b/ovf/fixtures/ttylinux.ovf
@@ -0,0 +1,100 @@
+<!-- fork of ../govc/test/images/ttylinux-pc_i486-16.1.ovf (see govc/test/README.md) -->
+<Envelope vmw:buildId="build-2060496"
+          xmlns="http://schemas.dmtf.org/ovf/envelope/1"
+          xmlns:cim="http://schemas.dmtf.org/wbem/wscim/1/common"
+          xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1"
+          xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData"
+          xmlns:vmw="http://www.vmware.com/schema/ovf"
+          xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData"
+          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <References>
+    <File ovf:href="ttylinux-pc_i486-16.1-disk1.vmdk" ovf:id="file1" ovf:size="10595840"/>
+  </References>
+  <DiskSection>
+    <Info>Virtual disk information</Info>
+    <Disk ovf:capacity="30" ovf:capacityAllocationUnits="byte * 2^20" ovf:diskId="vmdisk1" ovf:fileRef="file1"
+          ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" ovf:populatedSize="18743296"/>
+  </DiskSection>
+  <NetworkSection>
+    <Info>The list of logical networks</Info>
+    <Network ovf:name="nat">
+      <Description>The nat network</Description>
+    </Network>
+  </NetworkSection>
+  <VirtualSystem ovf:id="vm">
+    <Info>A virtual machine</Info>
+    <Name>ttylinux-pc_i486-16.1</Name>
+    <OperatingSystemSection ovf:id="36" vmw:osType="otherLinuxGuest">
+      <Info>The kind of installed guest operating system</Info>
+    </OperatingSystemSection>
+    <VirtualHardwareSection>
+      <Info>Virtual hardware requirements</Info>
+      <System>
+        <vssd:ElementName>Virtual Hardware Family</vssd:ElementName>
+        <vssd:InstanceID>0</vssd:InstanceID>
+        <vssd:VirtualSystemIdentifier>ttylinux-pc_i486-16.1</vssd:VirtualSystemIdentifier>
+        <vssd:VirtualSystemType>vmx-09</vssd:VirtualSystemType>
+      </System>
+      <Item>
+        <rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits>
+        <rasd:Description>Number of Virtual CPUs</rasd:Description>
+        <rasd:ElementName>1 virtual CPU(s)</rasd:ElementName>
+        <rasd:InstanceID>1</rasd:InstanceID>
+        <rasd:ResourceType>3</rasd:ResourceType>
+        <rasd:VirtualQuantity>1</rasd:VirtualQuantity>
+      </Item>
+      <Item>
+        <rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits>
+        <rasd:Description>Memory Size</rasd:Description>
+        <rasd:ElementName>32MB of memory</rasd:ElementName>
+        <rasd:InstanceID>2</rasd:InstanceID>
+        <rasd:ResourceType>4</rasd:ResourceType>
+        <rasd:VirtualQuantity>32</rasd:VirtualQuantity>
+      </Item>
+      <Item>
+        <rasd:Address>0</rasd:Address>
+        <rasd:Description>IDE Controller</rasd:Description>
+        <rasd:ElementName>ideController0</rasd:ElementName>
+        <rasd:InstanceID>3</rasd:InstanceID>
+        <rasd:ResourceType>5</rasd:ResourceType>
+      </Item>
+      <Item>
+        <rasd:AddressOnParent>0</rasd:AddressOnParent>
+        <rasd:ElementName>disk0</rasd:ElementName>
+        <rasd:HostResource>ovf:/disk/vmdisk1</rasd:HostResource>
+        <rasd:InstanceID>4</rasd:InstanceID>
+        <rasd:Parent>3</rasd:Parent>
+        <rasd:ResourceType>17</rasd:ResourceType>
+      </Item>
+      <Item>
+        <rasd:AddressOnParent>1</rasd:AddressOnParent>
+        <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
+        <rasd:Connection>nat</rasd:Connection>
+        <rasd:Description>E1000 ethernet adapter on &quot;nat&quot;</rasd:Description>
+        <rasd:ElementName>ethernet0</rasd:ElementName>
+        <rasd:InstanceID>5</rasd:InstanceID>
+        <rasd:ResourceSubType>E1000</rasd:ResourceSubType>
+        <rasd:ResourceType>10</rasd:ResourceType>
+        <vmw:Config ovf:required="false" vmw:key="wakeOnLanEnabled" vmw:value="false"/>
+      </Item>
+      <Item ovf:required="false">
+        <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
+        <rasd:ElementName>video</rasd:ElementName>
+        <rasd:InstanceID>6</rasd:InstanceID>
+        <rasd:ResourceType>24</rasd:ResourceType>
+      </Item>
+      <Item ovf:required="false">
+        <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
+        <rasd:ElementName>vmci</rasd:ElementName>
+        <rasd:InstanceID>7</rasd:InstanceID>
+        <rasd:ResourceSubType>vmware.vmci</rasd:ResourceSubType>
+        <rasd:ResourceType>1</rasd:ResourceType>
+      </Item>
+      <vmw:Config ovf:required="false" vmw:key="powerOpInfo.powerOffType" vmw:value="soft"/>
+      <vmw:Config ovf:required="false" vmw:key="powerOpInfo.resetType" vmw:value="soft"/>
+      <vmw:Config ovf:required="false" vmw:key="powerOpInfo.suspendType" vmw:value="soft"/>
+      <vmw:ExtraConfig ovf:required="false" vmw:key="tools.syncTimeWithHost" vmw:value="true"/>
+      <vmw:ExtraConfig ovf:required="false" vmw:key="tools.toolsUpgradePolicy" vmw:value="upgradeAtPowerCycle"/>
+    </VirtualHardwareSection>
+  </VirtualSystem>
+</Envelope>


Test patch:
diff --git a/ovf/ovf_test.go b/ovf/ovf_test.go
index 3511ff6d..f75e2fad 100644
--- a/ovf/ovf_test.go
+++ b/ovf/ovf_test.go
@@ -24,22 +24,11 @@ import (
 	"text/tabwriter"
 )
 
-func testFile(t *testing.T) *os.File {
-	fn := os.Getenv("OVF_TEST_FILE")
-	if fn == "" {
-		t.Skip("OVF_TEST_FILE not specified")
-	}
-
+func testEnvelope(t *testing.T, fn string) *Envelope {
 	f, err := os.Open(fn)
 	if err != nil {
 		t.Fatalf("error opening %s %s", fn, err)
 	}
-
-	return f
-}
-
-func testEnvelope(t *testing.T) *Envelope {
-	f := testFile(t)
 	defer f.Close()
 
 	e, err := Unmarshal(f)
@@ -55,11 +44,34 @@ func testEnvelope(t *testing.T) *Envelope {
 }
 
 func TestUnmarshal(t *testing.T) {
-	testEnvelope(t)
+	e := testEnvelope(t, "fixtures/ttylinux.ovf")
+
+	hw := e.VirtualSystem.VirtualHardware[0]
+	if n := len(hw.Config); n != 3 {
+		t.Errorf("Config=%d", n)
+	}
+	if n := len(hw.ExtraConfig); n != 2 {
+		t.Errorf("ExtraConfig=%d", n)
+	}
+	for i, c := range append(hw.Config, hw.ExtraConfig...) {
+		if *c.Required {
+			t.Errorf("%d: Required=%t", i, *c.Required)
+		}
+		if c.Key == "" {
+			t.Errorf("%d: key=''", i)
+		}
+		if c.Value == "" {
+			t.Errorf("%d: value=''", i)
+		}
+	}
 }
 
 func TestDeploymentOptions(t *testing.T) {
-	e := testEnvelope(t)
+	fn := os.Getenv("OVF_TEST_FILE")
+	if fn == "" {
+		t.Skip("OVF_TEST_FILE not specified")
+	}
+	e := testEnvelope(t, fn)
 
 	if e.DeploymentOption == nil {
 		t.Fatal("DeploymentOptionSection empty")