From 4eb5f8eb794371dd68674114050327b86dd27fe6 Mon Sep 17 00:00:00 2001 From: Olivier DRAGHI Date: Wed, 30 Nov 2022 00:43:28 +0100 Subject: [PATCH 01/12] Add VM.GetEnvironment() to retrieve OVF Environment Signed-off-by: Olivier DRAGHI --- govcd/vm.go | 15 ++++++++++++++ types/v56/vm_types.go | 46 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/govcd/vm.go b/govcd/vm.go index e9c525de1..ef3bde84c 100644 --- a/govcd/vm.go +++ b/govcd/vm.go @@ -832,6 +832,21 @@ func (vm *VM) GetProductSectionList() (*types.ProductSectionList, error) { return getProductSectionList(vm.client, vm.VM.HREF) } +// GetEnvironment returns the OVF Environment. It's only available for poweredOn VM +func (vm *VM) GetEnvironment() (*types.OVF_Environment, error) { + v := &types.Vm{} + + if vm.VM.HREF == "" { + return nil, fmt.Errorf("cannot refresh, invalid reference url") + } + + _, err := vm.client.ExecuteRequest(vm.VM.HREF, http.MethodGet, + types.MimeVM, "error retrieving ovf environment: %s", nil, v) + + // The request was successful + return v.Environment, err +} + // GetGuestCustomizationSection retrieves guest customization section for a VM. It allows to read VM guest customization properties. func (vm *VM) GetGuestCustomizationSection() (*types.GuestCustomizationSection, error) { if vm == nil || vm.VM.HREF == "" { diff --git a/types/v56/vm_types.go b/types/v56/vm_types.go index 16482be97..faa966020 100644 --- a/types/v56/vm_types.go +++ b/types/v56/vm_types.go @@ -51,8 +51,7 @@ type Vm struct { Snapshots *SnapshotSection `xml:"SnapshotSection,omitempty"` - // TODO: OVF Sections to be implemented - // Environment OVF_Environment `xml:"Environment,omitempty" + Environment *OVF_Environment `xml:"Environment,omitempty"` VmSpecSection *VmSpecSection `xml:"VmSpecSection,omitempty"` @@ -161,3 +160,46 @@ type SourcedVmTemplateParams struct { VmTemplateInstantiationParams *InstantiationParams `xml:"VmTemplateInstantiationParams,omitempty"` // Same as InstantiationParams used for VMs within a vApp StorageProfile *Reference `xml:"StorageProfile,omitempty"` // A reference to a storage profile to be used for the VM. The specified storage profile must exist in the organization vDC that contains the composed vApp. If not specified, the default storage profile for the vDC is used. } + +type OVF_Environment struct { + XMLName xml.Name `xml:"Environment"` + Ve string `xml:"ve,attr,omitempty"` + Id string `xml:"id,attr,omitempty"` + VCenterId string `xml:"vCenterId,attr,omitempty"` + PlatformSection *PlatformSection `xml:"PlatformSection,omitempty"` + PropertySection *PropertySection `xml:"PropertySection,omitempty"` + EthernetAdapterSection *EthernetAdapterSection `xml:"EthernetAdapterSection,omitempty"` +} + +type PlatformSection struct { + XMLName xml.Name `xml:"PlatformSection"` + Kind string `xml:"Kind,omitempty"` + Version string `xml:"Version,omitempty"` + Vendor string `xml:"Vendor,omitempty"` + Locale string `xml:"Locale,omitempty"` +} + +type PropertySection struct { + XMLName xml.Name `xml:"PropertySection"` + PropertyList PropertyList `xml:"Property,omitempty"` +} + +type PropertyList []*OVF_Property + +type OVF_Property struct { + Key string `xml:"key,attr"` + Value string `xml:"value,attr"` +} + +type EthernetAdapterSection struct { + XMLName xml.Name `xml:"EthernetAdapterSection"` + AdapterList AdapterList `xml:"Adapter,omitempty"` +} + +type AdapterList []*Adapter + +type Adapter struct { + Mac string `xml:"mac,attr"` + Network string `xml:"network,attr"` + UnitNumber string `xml:"unitNumber,attr"` +} From bd814a1ea51336fde678a53e079fffca5271d2eb Mon Sep 17 00:00:00 2001 From: Olivier DRAGHI Date: Thu, 1 Dec 2022 02:29:04 +0100 Subject: [PATCH 02/12] Add Test_GetOvfEnvironment Signed-off-by: Olivier DRAGHI --- govcd/vm_test.go | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/govcd/vm_test.go b/govcd/vm_test.go index e395f6811..a55e278d5 100644 --- a/govcd/vm_test.go +++ b/govcd/vm_test.go @@ -2281,3 +2281,55 @@ func createNsxtVAppAndVm(vcd *TestVCD, check *C) (*VApp, *VM) { return vapp, vm } + +func (vcd *TestVCD) Test_GetOvfEnvironment(check *C) { + if vcd.skipVappTests { + check.Skip("Skipping test because vapp was not successfully created at setup") + } + vapp := vcd.findFirstVapp() + existingVm, vmName := vcd.findFirstVm(vapp) + if vmName == "" { + check.Skip("skipping test because no VM is found") + } + vm, err := vcd.client.Client.GetVMByHref(existingVm.HREF) + check.Assert(err, IsNil) + + vmStatus, err := vm.GetStatus() + check.Assert(err, IsNil) + if vmStatus != "POWERED_ON" { + task, err := vm.PowerOn() + check.Assert(err, IsNil) + err = task.WaitTaskCompletion() + check.Assert(err, IsNil) + check.Assert(task.Task.Status, Equals, "success") + } + + // Read ovfenv when VM is started + ovfenv, err := vm.GetEnvironment() + check.Assert(err, IsNil) + check.Assert(strings.Contains(ovfenv.VCenterId, "vm-"), Equals, true) + check.Assert(ovfenv, NotNil) + check.Assert(ovfenv.PlatformSection, NotNil) + check.Assert(ovfenv.PlatformSection.Kind, Equals, "VMware ESXi") + check.Assert(ovfenv.PropertySection, NotNil) + for _, p := range ovfenv.PropertySection.PropertyList { + if p.Key == "vCloud_computerName" { + check.Assert(p.Value, Not(Equals), "") + } + } + check.Assert(ovfenv.EthernetAdapterSection, NotNil) + for _, p := range ovfenv.EthernetAdapterSection.AdapterList { + check.Assert(p.Mac, Not(Equals), "") + } + + // PowerOff + task, err := vm.PowerOff() + check.Assert(err, IsNil) + err = task.WaitTaskCompletion() + check.Assert(err, IsNil) + check.Assert(task.Task.Status, Equals, "success") + + ovfenv, err = vm.GetEnvironment() + check.Assert(err, IsNil) + check.Assert(ovfenv, IsNil) +} From d0850fbcf3a48e8eb05d2a4e8c4a6cff8b73f704 Mon Sep 17 00:00:00 2001 From: Olivier DRAGHI Date: Thu, 1 Dec 2022 21:49:04 +0100 Subject: [PATCH 03/12] Apply PR directive in VM.GetEnvironment() Signed-off-by: Olivier DRAGHI --- govcd/vm.go | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/govcd/vm.go b/govcd/vm.go index ef3bde84c..3a2d7d388 100644 --- a/govcd/vm.go +++ b/govcd/vm.go @@ -834,17 +834,16 @@ func (vm *VM) GetProductSectionList() (*types.ProductSectionList, error) { // GetEnvironment returns the OVF Environment. It's only available for poweredOn VM func (vm *VM) GetEnvironment() (*types.OVF_Environment, error) { - v := &types.Vm{} - - if vm.VM.HREF == "" { - return nil, fmt.Errorf("cannot refresh, invalid reference url") + vmStatus, err := vm.GetStatus() + if err != nil { + return nil, fmt.Errorf("unable to get ovf environment: %s", err) } - _, err := vm.client.ExecuteRequest(vm.VM.HREF, http.MethodGet, - types.MimeVM, "error retrieving ovf environment: %s", nil, v) + if vmStatus != "POWERED_ON" { + return nil, fmt.Errorf("ovf environment is only available when VM is poweredOn") + } - // The request was successful - return v.Environment, err + return vm.VM.Environment, nil } // GetGuestCustomizationSection retrieves guest customization section for a VM. It allows to read VM guest customization properties. From d3041711789a3050d04205809c7056d2996e0fca Mon Sep 17 00:00:00 2001 From: Olivier DRAGHI Date: Thu, 1 Dec 2022 22:52:30 +0100 Subject: [PATCH 04/12] Add OVF_Environment types descriptions Signed-off-by: Olivier DRAGHI --- types/v56/vm_types.go | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/types/v56/vm_types.go b/types/v56/vm_types.go index faa966020..8c8c56181 100644 --- a/types/v56/vm_types.go +++ b/types/v56/vm_types.go @@ -51,6 +51,7 @@ type Vm struct { Snapshots *SnapshotSection `xml:"SnapshotSection,omitempty"` + // The OVF environment defines how the guest software and the virtualization platform interact. Environment *OVF_Environment `xml:"Environment,omitempty"` VmSpecSection *VmSpecSection `xml:"VmSpecSection,omitempty"` @@ -161,24 +162,31 @@ type SourcedVmTemplateParams struct { StorageProfile *Reference `xml:"StorageProfile,omitempty"` // A reference to a storage profile to be used for the VM. The specified storage profile must exist in the organization vDC that contains the composed vApp. If not specified, the default storage profile for the vDC is used. } +// The OVF environment enables the guest software to access information about the virtualization platform, such as +// the user-specified values for the properties defined in the OVF descriptor. type OVF_Environment struct { XMLName xml.Name `xml:"Environment"` - Ve string `xml:"ve,attr,omitempty"` - Id string `xml:"id,attr,omitempty"` - VCenterId string `xml:"vCenterId,attr,omitempty"` - PlatformSection *PlatformSection `xml:"PlatformSection,omitempty"` - PropertySection *PropertySection `xml:"PropertySection,omitempty"` - EthernetAdapterSection *EthernetAdapterSection `xml:"EthernetAdapterSection,omitempty"` + Ve string `xml:"ve,attr,omitempty"` // Xml namespace + Id string `xml:"id,attr,omitempty"` // Identification of VM from OVF Descriptor. Describes this virtual system. + VCenterId string `xml:"vCenterId,attr,omitempty"` // VM moref in the vCenter + PlatformSection *PlatformSection `xml:"PlatformSection,omitempty"` // Describes the virtualization platform + PropertySection *PropertySection `xml:"PropertySection,omitempty"` // Property elements with key/value pairs + EthernetAdapterSection *EthernetAdapterSection `xml:"EthernetAdapterSection,omitempty"` // Contains adapters info and virtual networks attached } +// Provides information from the virtualization platform type PlatformSection struct { XMLName xml.Name `xml:"PlatformSection"` - Kind string `xml:"Kind,omitempty"` - Version string `xml:"Version,omitempty"` - Vendor string `xml:"Vendor,omitempty"` - Locale string `xml:"Locale,omitempty"` + Kind string `xml:"Kind,omitempty"` // Hypervisor kind is typically VMware ESXi + Version string `xml:"Version,omitempty"` // Hypervisor version + Vendor string `xml:"Vendor,omitempty"` // VMware, Inc. + Locale string `xml:"Locale,omitempty"` // Hypervisor locale } +// Contains a list of key/value pairs corresponding to properties defined in the OVF descriptor +// Operating system level configuration, such as host names, IP address, subnets, gateways, etc. +// Application-level configuration such as DNS name of active directory server, databases and +// other external services. type PropertySection struct { XMLName xml.Name `xml:"PropertySection"` PropertyList PropertyList `xml:"Property,omitempty"` @@ -191,6 +199,7 @@ type OVF_Property struct { Value string `xml:"value,attr"` } +// Contains adapters info and virtual networks attached type EthernetAdapterSection struct { XMLName xml.Name `xml:"EthernetAdapterSection"` AdapterList AdapterList `xml:"Adapter,omitempty"` From ee6aa499677fe7ad66fa88a1c12afe572d41205d Mon Sep 17 00:00:00 2001 From: Olivier DRAGHI Date: Thu, 1 Dec 2022 23:36:34 +0100 Subject: [PATCH 05/12] Apply PR directives for Test_GetOvfEnvironment Signed-off-by: Olivier DRAGHI --- govcd/vm_test.go | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/govcd/vm_test.go b/govcd/vm_test.go index a55e278d5..389a48667 100644 --- a/govcd/vm_test.go +++ b/govcd/vm_test.go @@ -2307,10 +2307,15 @@ func (vcd *TestVCD) Test_GetOvfEnvironment(check *C) { // Read ovfenv when VM is started ovfenv, err := vm.GetEnvironment() check.Assert(err, IsNil) + + // Provides information from the virtualization platform like VM moref check.Assert(strings.Contains(ovfenv.VCenterId, "vm-"), Equals, true) - check.Assert(ovfenv, NotNil) + + // Check virtualization platform Vendor check.Assert(ovfenv.PlatformSection, NotNil) - check.Assert(ovfenv.PlatformSection.Kind, Equals, "VMware ESXi") + check.Assert(ovfenv.PlatformSection.Vendor, Equals, "VMware, Inc.") + + // Check guest operating system level configuration for hostname check.Assert(ovfenv.PropertySection, NotNil) for _, p := range ovfenv.PropertySection.PropertyList { if p.Key == "vCloud_computerName" { @@ -2330,6 +2335,15 @@ func (vcd *TestVCD) Test_GetOvfEnvironment(check *C) { check.Assert(task.Task.Status, Equals, "success") ovfenv, err = vm.GetEnvironment() - check.Assert(err, IsNil) + check.Assert(strings.Contains(err.Error(), "ovf environment is only available when VM is poweredOn"), Equals, true) check.Assert(ovfenv, IsNil) + + // Leave things as they were + if vmStatus != "POWERED_OFF" { + task, err := vm.PowerOn() + check.Assert(err, IsNil) + err = task.WaitTaskCompletion() + check.Assert(err, IsNil) + check.Assert(task.Task.Status, Equals, "success") + } } From c142bb071befcef88caf8fd6bfaddcc0fec57afc Mon Sep 17 00:00:00 2001 From: Olivier DRAGHI Date: Thu, 23 Feb 2023 08:30:21 +0100 Subject: [PATCH 06/12] Add 528-features.md for the final changelog --- .changes/v2.20.0/528-features.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 .changes/v2.20.0/528-features.md diff --git a/.changes/v2.20.0/528-features.md b/.changes/v2.20.0/528-features.md new file mode 100644 index 000000000..588909410 --- /dev/null +++ b/.changes/v2.20.0/528-features.md @@ -0,0 +1 @@ +* Added method `VM.GetEnvironment` to retrieve OVF Environment [GH-528] \ No newline at end of file From d03c8a728df7e876af25a06a06d655a661069e37 Mon Sep 17 00:00:00 2001 From: Olivier DRAGHI Date: Thu, 23 Feb 2023 08:37:19 +0100 Subject: [PATCH 07/12] Update govcd/vm_test.go --- govcd/vm_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/govcd/vm_test.go b/govcd/vm_test.go index 389a48667..e6707e6f6 100644 --- a/govcd/vm_test.go +++ b/govcd/vm_test.go @@ -2307,6 +2307,7 @@ func (vcd *TestVCD) Test_GetOvfEnvironment(check *C) { // Read ovfenv when VM is started ovfenv, err := vm.GetEnvironment() check.Assert(err, IsNil) + check.Assert(ovfenv, NotNil) // Provides information from the virtualization platform like VM moref check.Assert(strings.Contains(ovfenv.VCenterId, "vm-"), Equals, true) From 9d904a93f41e6147fee4c4b36ad670c2925212e3 Mon Sep 17 00:00:00 2001 From: Olivier DRAGHI Date: Thu, 23 Feb 2023 08:44:02 +0100 Subject: [PATCH 08/12] Go fmt vm_types.go --- types/v56/vm_types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/v56/vm_types.go b/types/v56/vm_types.go index 8c8c56181..2005fb8ed 100644 --- a/types/v56/vm_types.go +++ b/types/v56/vm_types.go @@ -166,7 +166,7 @@ type SourcedVmTemplateParams struct { // the user-specified values for the properties defined in the OVF descriptor. type OVF_Environment struct { XMLName xml.Name `xml:"Environment"` - Ve string `xml:"ve,attr,omitempty"` // Xml namespace + Ve string `xml:"ve,attr,omitempty"` // Xml namespace Id string `xml:"id,attr,omitempty"` // Identification of VM from OVF Descriptor. Describes this virtual system. VCenterId string `xml:"vCenterId,attr,omitempty"` // VM moref in the vCenter PlatformSection *PlatformSection `xml:"PlatformSection,omitempty"` // Describes the virtualization platform From 9c894b760d3ff226e74d2c2ba14c30645b5cd2ff Mon Sep 17 00:00:00 2001 From: Olivier DRAGHI Date: Thu, 23 Feb 2023 10:07:26 +0100 Subject: [PATCH 09/12] Replace PropertyList by Properties and AdapterList by Adapters --- govcd/vm_test.go | 4 ++-- types/v56/vm_types.go | 12 ++++-------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/govcd/vm_test.go b/govcd/vm_test.go index e6707e6f6..070b94572 100644 --- a/govcd/vm_test.go +++ b/govcd/vm_test.go @@ -2318,13 +2318,13 @@ func (vcd *TestVCD) Test_GetOvfEnvironment(check *C) { // Check guest operating system level configuration for hostname check.Assert(ovfenv.PropertySection, NotNil) - for _, p := range ovfenv.PropertySection.PropertyList { + for _, p := range ovfenv.PropertySection.Properties { if p.Key == "vCloud_computerName" { check.Assert(p.Value, Not(Equals), "") } } check.Assert(ovfenv.EthernetAdapterSection, NotNil) - for _, p := range ovfenv.EthernetAdapterSection.AdapterList { + for _, p := range ovfenv.EthernetAdapterSection.Adapters { check.Assert(p.Mac, Not(Equals), "") } diff --git a/types/v56/vm_types.go b/types/v56/vm_types.go index 2005fb8ed..16fc34827 100644 --- a/types/v56/vm_types.go +++ b/types/v56/vm_types.go @@ -188,12 +188,10 @@ type PlatformSection struct { // Application-level configuration such as DNS name of active directory server, databases and // other external services. type PropertySection struct { - XMLName xml.Name `xml:"PropertySection"` - PropertyList PropertyList `xml:"Property,omitempty"` + XMLName xml.Name `xml:"PropertySection"` + Properties []*OVF_Property `xml:"Property,omitempty"` } -type PropertyList []*OVF_Property - type OVF_Property struct { Key string `xml:"key,attr"` Value string `xml:"value,attr"` @@ -201,12 +199,10 @@ type OVF_Property struct { // Contains adapters info and virtual networks attached type EthernetAdapterSection struct { - XMLName xml.Name `xml:"EthernetAdapterSection"` - AdapterList AdapterList `xml:"Adapter,omitempty"` + XMLName xml.Name `xml:"EthernetAdapterSection"` + Adapters []*Adapter `xml:"Adapter,omitempty"` } -type AdapterList []*Adapter - type Adapter struct { Mac string `xml:"mac,attr"` Network string `xml:"network,attr"` From f7ea32aef6759b8c2d62ff8762a4acc0389e03b9 Mon Sep 17 00:00:00 2001 From: Olivier DRAGHI Date: Wed, 1 Mar 2023 13:59:42 +0100 Subject: [PATCH 10/12] Tidying error messages --- govcd/vm.go | 4 ++-- govcd/vm_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/govcd/vm.go b/govcd/vm.go index 3a2d7d388..9481c9a6f 100644 --- a/govcd/vm.go +++ b/govcd/vm.go @@ -836,11 +836,11 @@ func (vm *VM) GetProductSectionList() (*types.ProductSectionList, error) { func (vm *VM) GetEnvironment() (*types.OVF_Environment, error) { vmStatus, err := vm.GetStatus() if err != nil { - return nil, fmt.Errorf("unable to get ovf environment: %s", err) + return nil, fmt.Errorf("unable to get OVF environment: %s", err) } if vmStatus != "POWERED_ON" { - return nil, fmt.Errorf("ovf environment is only available when VM is poweredOn") + return nil, fmt.Errorf("OVF environment is only available when VM is powered on") } return vm.VM.Environment, nil diff --git a/govcd/vm_test.go b/govcd/vm_test.go index 070b94572..8da8cc47f 100644 --- a/govcd/vm_test.go +++ b/govcd/vm_test.go @@ -2336,7 +2336,7 @@ func (vcd *TestVCD) Test_GetOvfEnvironment(check *C) { check.Assert(task.Task.Status, Equals, "success") ovfenv, err = vm.GetEnvironment() - check.Assert(strings.Contains(err.Error(), "ovf environment is only available when VM is poweredOn"), Equals, true) + check.Assert(strings.Contains(err.Error(), "OVF environment is only available when VM is powered on"), Equals, true) check.Assert(ovfenv, IsNil) // Leave things as they were From b1f5512116f70fd576d5433d8ff2574a1bcc6794 Mon Sep 17 00:00:00 2001 From: Olivier DRAGHI Date: Fri, 3 Mar 2023 22:46:59 +0100 Subject: [PATCH 11/12] Rename types to OvfProperty and OvfEnvironment --- govcd/vm.go | 2 +- types/v56/vm_types.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/govcd/vm.go b/govcd/vm.go index 9481c9a6f..6c7752cf7 100644 --- a/govcd/vm.go +++ b/govcd/vm.go @@ -833,7 +833,7 @@ func (vm *VM) GetProductSectionList() (*types.ProductSectionList, error) { } // GetEnvironment returns the OVF Environment. It's only available for poweredOn VM -func (vm *VM) GetEnvironment() (*types.OVF_Environment, error) { +func (vm *VM) GetEnvironment() (*types.OvfEnvironment, error) { vmStatus, err := vm.GetStatus() if err != nil { return nil, fmt.Errorf("unable to get OVF environment: %s", err) diff --git a/types/v56/vm_types.go b/types/v56/vm_types.go index 16fc34827..fe2696da4 100644 --- a/types/v56/vm_types.go +++ b/types/v56/vm_types.go @@ -52,7 +52,7 @@ type Vm struct { Snapshots *SnapshotSection `xml:"SnapshotSection,omitempty"` // The OVF environment defines how the guest software and the virtualization platform interact. - Environment *OVF_Environment `xml:"Environment,omitempty"` + Environment *OvfEnvironment `xml:"Environment,omitempty"` VmSpecSection *VmSpecSection `xml:"VmSpecSection,omitempty"` @@ -164,7 +164,7 @@ type SourcedVmTemplateParams struct { // The OVF environment enables the guest software to access information about the virtualization platform, such as // the user-specified values for the properties defined in the OVF descriptor. -type OVF_Environment struct { +type OvfEnvironment struct { XMLName xml.Name `xml:"Environment"` Ve string `xml:"ve,attr,omitempty"` // Xml namespace Id string `xml:"id,attr,omitempty"` // Identification of VM from OVF Descriptor. Describes this virtual system. @@ -189,10 +189,10 @@ type PlatformSection struct { // other external services. type PropertySection struct { XMLName xml.Name `xml:"PropertySection"` - Properties []*OVF_Property `xml:"Property,omitempty"` + Properties []*OvfProperty `xml:"Property,omitempty"` } -type OVF_Property struct { +type OvfProperty struct { Key string `xml:"key,attr"` Value string `xml:"value,attr"` } From 5167fb28d72c5973b2a2bb1da414c73b7e787817 Mon Sep 17 00:00:00 2001 From: Olivier DRAGHI Date: Wed, 8 Mar 2023 12:54:31 +0100 Subject: [PATCH 12/12] Make fmt vm_types.go Signed-off-by: Olivier DRAGHI --- types/v56/vm_types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/v56/vm_types.go b/types/v56/vm_types.go index fe2696da4..9c33047f8 100644 --- a/types/v56/vm_types.go +++ b/types/v56/vm_types.go @@ -188,7 +188,7 @@ type PlatformSection struct { // Application-level configuration such as DNS name of active directory server, databases and // other external services. type PropertySection struct { - XMLName xml.Name `xml:"PropertySection"` + XMLName xml.Name `xml:"PropertySection"` Properties []*OvfProperty `xml:"Property,omitempty"` }