From 66728a21cb4a0ed7acee713cc46a0482a15f91ef Mon Sep 17 00:00:00 2001 From: Vaidotas Bauzys Date: Mon, 23 Mar 2020 14:04:49 +0200 Subject: [PATCH 1/9] First implementation Signed-off-by: Vaidotas Bauzys --- govcd/api.go | 5 ++ govcd/edgegateway_unit_test.go | 5 -- govcd/vm.go | 30 ++++++++ govcd/vm_test.go | 135 +++++++++++++++++++++++++++++++++ types/v56/types.go | 17 ----- types/v56/vm_types.go | 38 ++++++++++ 6 files changed, 208 insertions(+), 22 deletions(-) create mode 100644 types/v56/vm_types.go diff --git a/govcd/api.go b/govcd/api.go index b509ae5d5..9eac7430f 100644 --- a/govcd/api.go +++ b/govcd/api.go @@ -564,3 +564,8 @@ func combinedTaskErrorMessage(task *types.Task, err error) string { func takeBoolPointer(value bool) *bool { return &value } + +// takeIntAddress is a helper which can gives address of `int` +func takeIntAddress(x int) *int { + return &x +} diff --git a/govcd/edgegateway_unit_test.go b/govcd/edgegateway_unit_test.go index 1d2e49cdc..303c93390 100644 --- a/govcd/edgegateway_unit_test.go +++ b/govcd/edgegateway_unit_test.go @@ -423,8 +423,3 @@ func Test_getNetworkNameTypeFromVnicIndex(t *testing.T) { }) } } - -// takeIntAddress is a helper which can gives address of `int` -func takeIntAddress(x int) *int { - return &x -} diff --git a/govcd/vm.go b/govcd/vm.go index 106d65eac..9dec8dbcc 100644 --- a/govcd/vm.go +++ b/govcd/vm.go @@ -1355,3 +1355,33 @@ func (vm *VM) UpdateInternalDisksAsync(disksSettingToUpdate *types.VmSpecSection }, vm.client.GetSpecificApiVersionOnCondition(">= 32.0", "32.0")) } + +func (vapp *VApp) AddEmptyVm(reComposeVAppParams *types.RecomposeVAppParamsForEmptyVm) (*VM, error) { + // TODO add validation + task, err := vapp.AddEmptyVmAsync(reComposeVAppParams) + if err != nil { + return nil, err + } + + err = task.WaitTaskCompletion() + if err != nil { + return nil, err + } + + newVm, err := vapp.GetVMByName(reComposeVAppParams.CreateItem.Name, true) + if err != nil { + return nil, err + } + + return newVm, nil + +} + +func (vapp *VApp) AddEmptyVmAsync(reComposeVAppParams *types.RecomposeVAppParamsForEmptyVm) (Task, error) { + apiEndpoint, _ := url.ParseRequestURI(vapp.VApp.HREF) + apiEndpoint.Path += "/action/recomposeVApp" + + // Return the task + return vapp.client.ExecuteTaskRequest(apiEndpoint.String(), http.MethodPost, + types.MimeRecomposeVappParams, "error instantiating a new VM: %s", reComposeVAppParams) +} diff --git a/govcd/vm_test.go b/govcd/vm_test.go index b94ec0707..60c51ec34 100644 --- a/govcd/vm_test.go +++ b/govcd/vm_test.go @@ -1296,3 +1296,138 @@ func deleteVapp(vcd *TestVCD, name string) error { } return nil } + +func (vcd *TestVCD) Test_AddNewEmptyVMMultiNIC(check *C) { + + config := vcd.config + if config.VCD.Network.Net1 == "" { + check.Skip("Skipping test because no network was given") + } + + // Find VApp + if vcd.vapp.VApp == nil { + check.Skip("skipping test because no vApp is found") + } + + vapp, err := createVappForTest(vcd, "Test_AddNewEmptyVMMultiNIC") + check.Assert(err, IsNil) + check.Assert(vapp, NotNil) + + desiredNetConfig := &types.NetworkConnectionSection{} + desiredNetConfig.PrimaryNetworkConnectionIndex = 0 + desiredNetConfig.NetworkConnection = append(desiredNetConfig.NetworkConnection, + &types.NetworkConnection{ + IsConnected: true, + IPAddressAllocationMode: types.IPAllocationModePool, + Network: config.VCD.Network.Net1, + NetworkConnectionIndex: 0, + }, + &types.NetworkConnection{ + IsConnected: true, + IPAddressAllocationMode: types.IPAllocationModeNone, + Network: types.NoneNetwork, + NetworkConnectionIndex: 1, + }) + + // Test with two different networks if we have them + if config.VCD.Network.Net2 != "" { + // Attach second vdc network to vApp + vdcNetwork2, err := vcd.vdc.GetOrgVdcNetworkByName(vcd.config.VCD.Network.Net2, false) + check.Assert(err, IsNil) + _, err = vapp.AddOrgNetwork(&VappNetworkSettings{}, vdcNetwork2.OrgVDCNetwork, false) + check.Assert(err, IsNil) + + desiredNetConfig.NetworkConnection = append(desiredNetConfig.NetworkConnection, + &types.NetworkConnection{ + IsConnected: true, + IPAddressAllocationMode: types.IPAllocationModePool, + Network: config.VCD.Network.Net2, + NetworkConnectionIndex: 2, + }, + ) + } else { + fmt.Println("Skipping adding another vdc network as network2 was not specified") + } + + cat, err := vcd.org.GetCatalogByName(vcd.config.VCD.Catalog.Name, true) + check.Assert(err, IsNil) + check.Assert(cat, NotNil) + + //media, err := cat.GetMediaByName("photon-custom-hw11-2.0-304b817.ova", false) + media, err := cat.GetMediaByName("vaido2", false) + check.Assert(err, IsNil) + check.Assert(media, NotNil) + + var task Task + var sp types.Reference + var customSP = false + + if vcd.config.VCD.StorageProfile.SP1 != "" { + sp, _ = vcd.vdc.FindStorageProfileReference(vcd.config.VCD.StorageProfile.SP1) + } + + newDisk := types.DiskSettings{ + AdapterType: "5", + SizeMb: int64(16384), + BusNumber: 0, + UnitNumber: 0, + ThinProvisioned: takeBoolPointer(true), + OverrideVmDefault: true} + + requestDetails := &types.RecomposeVAppParamsForEmptyVm{ + XmlnsVcloud: types.XMLNamespaceVCloud, + XmlnsOvf: types.XMLNamespaceOVF, + CreateItem: &types.CreateItem{ + Name: "Test_AddNewEmptyVMMultiNIC", + NetworkConnectionSection: desiredNetConfig, + Description: "created by Test_AddNewEmptyVMMultiNIC", + GuestCustomizationSection: nil, + VmSpecSection: &types.VmSpecSection{ + Modified: takeBoolPointer(true), + Info: "Virtual Machine specification", + OsType: "debian10Guest", + NumCpus: takeIntAddress(2), + NumCoresPerSocket: takeIntAddress(1), + CpuResourceMhz: &types.CpuResourceMhz{Configured: 1}, + MemoryResourceMb: &types.MemoryResourceMb{Configured: 1024}, + MediaSection: nil, + DiskSection: &types.DiskSection{DiskSettings: []*types.DiskSettings{&newDisk}}, + HardwareVersion: &types.HardwareVersion{Value: "vmx-13"}, // need support older version vCD + VmToolsVersion: "", + VirtualCpuType: "VM32", + TimeSyncWithHost: nil, + }, + BootImage: &types.Media{HREF: media.Media.HREF, Name: media.Media.Name, ID: media.Media.ID}, + }, + AllEULAsAccepted: true, + } + + createdVm, err := vapp.AddEmptyVm(requestDetails) + check.Assert(err, IsNil) + check.Assert(createdVm, NotNil) + + // Ensure network config was valid + actualNetConfig, err := createdVm.GetNetworkConnectionSection() + check.Assert(err, IsNil) + + if customSP { + check.Assert(createdVm.VM.StorageProfile.HREF, Equals, sp.HREF) + } + + verifyNetworkConnectionSection(check, actualNetConfig, desiredNetConfig) + + // Cleanup + err = vapp.RemoveVM(*createdVm) + check.Assert(err, IsNil) + + // Ensure network is detached from vApp to avoid conflicts in other tests + task, err = vapp.RemoveAllNetworks() + check.Assert(err, IsNil) + err = task.WaitTaskCompletion() + check.Assert(err, IsNil) + task, err = vapp.Delete() + check.Assert(err, IsNil) + err = task.WaitTaskCompletion() + check.Assert(err, IsNil) + check.Assert(task.Task.Status, Equals, "success") +} diff --git a/types/v56/types.go b/types/v56/types.go index 6b8c28e3c..1065a6f29 100644 --- a/types/v56/types.go +++ b/types/v56/types.go @@ -1392,23 +1392,6 @@ type VMDiskChange struct { VmSpecSection *VmSpecSection `xml:"VmSpecSection,omitempty"` // Container for the specification of this virtual machine. This is an alternative to using ovf:VirtualHardwareSection + ovf:OperatingSystemSection } -// VmSpecSection from VM struct -type VmSpecSection struct { - Modified *bool `xml:"Modified,attr,omitempty"` - Info string `xml:"ovf:Info"` - OsType string `xml:"OsType,omitempty"` // The type of the OS. This parameter may be omitted when using the VmSpec to update the contents of an existing VM. - NumCpus *int `xml:"NumCpus,omitempty"` // Number of CPUs. This parameter may be omitted when using the VmSpec to update the contents of an existing VM. - NumCoresPerSocket *int `xml:"NumCoresPerSocket,omitempty"` // Number of cores among which to distribute CPUs in this virtual machine. This parameter may be omitted when using the VmSpec to update the contents of an existing VM. - CpuResourceMhz *CpuResourceMhz `xml:"CpuResourceMhz,omitempty"` // CPU compute resources. This parameter may be omitted when using the VmSpec to update the contents of an existing VM. - MemoryResourceMb *MemoryResourceMb `xml:"MemoryResourceMb"` // Memory compute resources. This parameter may be omitted when using the VmSpec to update the contents of an existing VM. - MediaSection *MediaSection `xml:"MediaSection,omitempty"` // The media devices of this VM. - DiskSection *DiskSection `xml:"DiskSection,omitempty"` // virtual disks of this VM. - HardwareVersion *HardwareVersion `xml:"HardwareVersion"` // vSphere name of Virtual Hardware Version of this VM. Example: vmx-13 - This parameter may be omitted when using the VmSpec to update the contents of an existing VM. - VmToolsVersion string `xml:"VmToolsVersion,omitempty"` // VMware tools version of this VM. - VirtualCpuType string `xml:"VirtualCpuType,omitempty"` // The capabilities settings for this VM. This parameter may be omitted when using the VmSpec to update the contents of an existing VM. - TimeSyncWithHost *bool `xml:"TimeSyncWithHost,omitempty"` // Synchronize the VM's time with the host. -} - // DiskSection from VM/VmSpecSection struct type DiskSection struct { DiskSettings []*DiskSettings `xml:"DiskSettings"` diff --git a/types/v56/vm_types.go b/types/v56/vm_types.go new file mode 100644 index 000000000..6d7264020 --- /dev/null +++ b/types/v56/vm_types.go @@ -0,0 +1,38 @@ +package types + +import "encoding/xml" + +// VmSpecSection from VM struct +type VmSpecSection struct { + Modified *bool `xml:"Modified,attr,omitempty"` + Info string `xml:"ovf:Info"` + OsType string `xml:"OsType,omitempty"` // The type of the OS. This parameter may be omitted when using the VmSpec to update the contents of an existing VM. + NumCpus *int `xml:"NumCpus,omitempty"` // Number of CPUs. This parameter may be omitted when using the VmSpec to update the contents of an existing VM. + NumCoresPerSocket *int `xml:"NumCoresPerSocket,omitempty"` // Number of cores among which to distribute CPUs in this virtual machine. This parameter may be omitted when using the VmSpec to update the contents of an existing VM. + CpuResourceMhz *CpuResourceMhz `xml:"CpuResourceMhz,omitempty"` // CPU compute resources. This parameter may be omitted when using the VmSpec to update the contents of an existing VM. + MemoryResourceMb *MemoryResourceMb `xml:"MemoryResourceMb"` // Memory compute resources. This parameter may be omitted when using the VmSpec to update the contents of an existing VM. + MediaSection *MediaSection `xml:"MediaSection,omitempty"` // The media devices of this VM. + DiskSection *DiskSection `xml:"DiskSection,omitempty"` // virtual disks of this VM. + HardwareVersion *HardwareVersion `xml:"HardwareVersion"` // vSphere name of Virtual Hardware Version of this VM. Example: vmx-13 - This parameter may be omitted when using the VmSpec to update the contents of an existing VM. + VmToolsVersion string `xml:"VmToolsVersion,omitempty"` // VMware tools version of this VM. + VirtualCpuType string `xml:"VirtualCpuType,omitempty"` // The capabilities settings for this VM. This parameter may be omitted when using the VmSpec to update the contents of an existing VM. + TimeSyncWithHost *bool `xml:"TimeSyncWithHost,omitempty"` // Synchronize the VM's time with the host. +} + +type RecomposeVAppParamsForEmptyVm struct { + XMLName xml.Name `xml:"RecomposeVAppParams"` + XmlnsVcloud string `xml:"xmlns,attr"` + XmlnsOvf string `xml:"xmlns:ovf,attr"` + CreateItem *CreateItem `xml:"CreateItem,omitempty"` + AllEULAsAccepted bool `xml:"AllEULAsAccepted,omitempty"` +} + +type CreateItem struct { + //XMLName xml.Name `xml:"CreateItem"` + Name string `xml:"name,attr,omitempty"` + Description string `xml:"Description,omitempty"` + GuestCustomizationSection *GuestCustomizationSection `xml:"GuestCustomizationSection,omitempty"` + NetworkConnectionSection *NetworkConnectionSection `xml:"NetworkConnectionSection,omitempty"` + VmSpecSection *VmSpecSection `xml:"VmSpecSection,omitempty"` + BootImage *Media `xml:"Media,omitempty"` // boot image as vApp template. Href, Id and name needed. +} From 254770e0c98497361b759bb8f96f64a799c49e7f Mon Sep 17 00:00:00 2001 From: Vaidotas Bauzys Date: Thu, 26 Mar 2020 13:15:28 +0200 Subject: [PATCH 2/9] Added filterEncoded to queries Signed-off-by: Vaidotas Bauzys --- CHANGELOG.md | 3 +++ govcd/adminorg.go | 5 +++-- govcd/disk.go | 4 ++-- govcd/media.go | 8 +++++--- govcd/orgvdcnetwork.go | 10 ++++++---- govcd/system.go | 25 +++++++++++++++---------- govcd/vdc.go | 3 ++- 7 files changed, 36 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e58c9c60e..0f2b5e83a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ * Added methods `OrgVdcNetwork.Update`, `OrgVdcNetwork.UpdateAsync`, and `OrgVdcNetwork.Rename` [#292](https://github.com/vmware/go-vcloud-director/pull/292) * Added methods `EdgeGateway.Update` and `EdgeGateway.UpdateAsync` [#292](https://github.com/vmware/go-vcloud-director/pull/292) +BUGS FIXED: +* Fix issue in Queries with vCD 10 version, which do not return network pool or provider VDC[#xxx](https://github.com/vmware/go-vcloud-director/pull/xxx) + ## 2.6.0 (March 13, 2010) * Moved `VCDClient.supportedVersions` to `VCDClient.Client.supportedVersions` [#274](https://github.com/vmware/go-vcloud-director/pull/274) diff --git a/govcd/adminorg.go b/govcd/adminorg.go index 1f0e0d824..470bbca81 100644 --- a/govcd/adminorg.go +++ b/govcd/adminorg.go @@ -322,8 +322,9 @@ func isCatalogFromSameOrg(adminOrg *AdminOrg, catalogName string) (bool, error) func (adminOrg *AdminOrg) FindAdminCatalogRecords(name string) ([]*types.AdminCatalogRecord, error) { util.Logger.Printf("[DEBUG] FindAdminCatalogRecords with name: %s and org name: %s", name, adminOrg.AdminOrg.Name) results, err := adminOrg.client.QueryWithNotEncodedParams(nil, map[string]string{ - "type": "adminCatalog", - "filter": fmt.Sprintf("name==%s;orgName==%s", url.QueryEscape(name), url.QueryEscape(adminOrg.AdminOrg.Name)), + "type": "adminCatalog", + "filter": fmt.Sprintf("name==%s;orgName==%s", url.QueryEscape(name), url.QueryEscape(adminOrg.AdminOrg.Name)), + "filterEncoded": "true", }) if err != nil { return nil, err diff --git a/govcd/disk.go b/govcd/disk.go index 1e46cd2aa..67a3411c4 100644 --- a/govcd/disk.go +++ b/govcd/disk.go @@ -329,7 +329,7 @@ func (vdc *Vdc) QueryDisk(diskName string) (DiskRecord, error) { typeMedia = "adminDisk" } - results, err := vdc.QueryWithNotEncodedParams(nil, map[string]string{"type": typeMedia, "filter": "name==" + url.QueryEscape(diskName)}) + results, err := vdc.QueryWithNotEncodedParams(nil, map[string]string{"type": typeMedia, "filter": "name==" + url.QueryEscape(diskName), "filterEncoded": "true"}) if err != nil { return DiskRecord{}, fmt.Errorf("error querying disk %s", err) } @@ -362,7 +362,7 @@ func (vdc *Vdc) QueryDisks(diskName string) (*[]*types.DiskRecordType, error) { typeMedia = "adminDisk" } - results, err := vdc.QueryWithNotEncodedParams(nil, map[string]string{"type": typeMedia, "filter": "name==" + url.QueryEscape(diskName)}) + results, err := vdc.QueryWithNotEncodedParams(nil, map[string]string{"type": typeMedia, "filter": "name==" + url.QueryEscape(diskName), "filterEncoded": "true"}) if err != nil { return nil, fmt.Errorf("error querying disks %s", err) } diff --git a/govcd/media.go b/govcd/media.go index 22f90e4fa..87526b550 100644 --- a/govcd/media.go +++ b/govcd/media.go @@ -306,7 +306,7 @@ func queryMediaWithFilter(vdc *Vdc, filter string) ([]*types.MediaRecordType, er typeMedia = "adminMedia" } - results, err := vdc.QueryWithNotEncodedParams(nil, map[string]string{"type": typeMedia, "filter": filter}) + results, err := vdc.QueryWithNotEncodedParams(nil, map[string]string{"type": typeMedia, "filter": filter, "filterEncoded": "true"}) if err != nil { return nil, fmt.Errorf("error querying medias %s", err) } @@ -487,7 +487,8 @@ func (catalog *Catalog) GetMediaById(mediaId string) (*Media, error) { } results, err := catalog.client.QueryWithNotEncodedParams(nil, map[string]string{"type": typeMedia, - "filter": fmt.Sprintf("catalogName==%s", url.QueryEscape(catalog.Catalog.Name))}) + "filter": fmt.Sprintf("catalogName==%s", url.QueryEscape(catalog.Catalog.Name)), + "filterEncoded": "true"}) if err != nil { return nil, fmt.Errorf("error querying medias %s", err) } @@ -572,7 +573,8 @@ func (catalog *Catalog) QueryMedia(mediaName string) (*MediaRecord, error) { results, err := catalog.client.QueryWithNotEncodedParams(nil, map[string]string{"type": typeMedia, "filter": fmt.Sprintf("name==%s;catalogName==%s", url.QueryEscape(mediaName), - url.QueryEscape(catalog.Catalog.Name))}) + url.QueryEscape(catalog.Catalog.Name)), + "filterEncoded": "true"}) if err != nil { return nil, fmt.Errorf("error querying medias %s", err) } diff --git a/govcd/orgvdcnetwork.go b/govcd/orgvdcnetwork.go index e6346fa9d..e20e7f42b 100644 --- a/govcd/orgvdcnetwork.go +++ b/govcd/orgvdcnetwork.go @@ -200,8 +200,9 @@ func (vdc *Vdc) CreateOrgVDCNetwork(networkConfig *types.OrgVDCNetwork) (Task, e func (vdc *Vdc) GetNetworkList() ([]*types.QueryResultOrgVdcNetworkRecordType, error) { // Find the list of networks with the wanted name result, err := vdc.client.QueryWithNotEncodedParams(nil, map[string]string{ - "type": "orgVdcNetwork", - "filter": fmt.Sprintf("vdc==%s", url.QueryEscape(vdc.Vdc.ID)), + "type": "orgVdcNetwork", + "filter": fmt.Sprintf("vdc==%s", url.QueryEscape(vdc.Vdc.ID)), + "filterEncoded": "true", }) if err != nil { return nil, fmt.Errorf("[findEdgeGatewayConnection] error returning the list of networks for VDC: %s", err) @@ -215,8 +216,9 @@ func (vdc *Vdc) FindEdgeGatewayNameByNetwork(networkName string) (string, error) // Find the list of networks with the wanted name result, err := vdc.client.QueryWithNotEncodedParams(nil, map[string]string{ - "type": "orgVdcNetwork", - "filter": fmt.Sprintf("name==%s;vdc==%s", url.QueryEscape(networkName), url.QueryEscape(vdc.Vdc.ID)), + "type": "orgVdcNetwork", + "filter": fmt.Sprintf("name==%s;vdc==%s", url.QueryEscape(networkName), url.QueryEscape(vdc.Vdc.ID)), + "filterEncoded": "true", }) if err != nil { return "", fmt.Errorf("[findEdgeGatewayConnection] error returning the list of networks for VDC: %s", err) diff --git a/govcd/system.go b/govcd/system.go index 96405b6d6..a272c0325 100644 --- a/govcd/system.go +++ b/govcd/system.go @@ -414,8 +414,9 @@ func QueryDistributedPortGroup(vcdCli *VCDClient, name string) ([]*types.PortGro // Find a list of Port groups matching the filter parameter. func QueryPortGroups(vcdCli *VCDClient, filter string) ([]*types.PortGroupRecordType, error) { results, err := vcdCli.QueryWithNotEncodedParams(nil, map[string]string{ - "type": "portgroup", - "filter": filter, + "type": "portgroup", + "filter": filter, + "filterEncoded": "true", }) if err != nil { return nil, err @@ -695,8 +696,9 @@ func GetStorageProfileByHref(vcdClient *VCDClient, url string) (*types.VdcStorag // QueryProviderVdcStorageProfileByName finds a provider VDC storage profile by name func QueryProviderVdcStorageProfileByName(vcdCli *VCDClient, name string) ([]*types.QueryResultProviderVdcStorageProfileRecordType, error) { results, err := vcdCli.QueryWithNotEncodedParams(nil, map[string]string{ - "type": "providerVdcStorageProfile", - "filter": fmt.Sprintf("name==%s", url.QueryEscape(name)), + "type": "providerVdcStorageProfile", + "filter": fmt.Sprintf("name==%s", url.QueryEscape(name)), + "filterEncoded": "true", }) if err != nil { return nil, err @@ -708,8 +710,9 @@ func QueryProviderVdcStorageProfileByName(vcdCli *VCDClient, name string) ([]*ty // QueryNetworkPoolByName finds a network pool by name func QueryNetworkPoolByName(vcdCli *VCDClient, name string) ([]*types.QueryResultNetworkPoolRecordType, error) { results, err := vcdCli.QueryWithNotEncodedParams(nil, map[string]string{ - "type": "networkPool", - "filter": fmt.Sprintf("name==%s", url.QueryEscape(name)), + "type": "networkPool", + "filter": fmt.Sprintf("name==%s", url.QueryEscape(name)), + "filterEncoded": "true", }) if err != nil { return nil, err @@ -721,8 +724,9 @@ func QueryNetworkPoolByName(vcdCli *VCDClient, name string) ([]*types.QueryResul // QueryProviderVdcByName finds a provider VDC by name func QueryProviderVdcByName(vcdCli *VCDClient, name string) ([]*types.QueryResultVMWProviderVdcRecordType, error) { results, err := vcdCli.QueryWithNotEncodedParams(nil, map[string]string{ - "type": "providerVdc", - "filter": fmt.Sprintf("name==%s", url.QueryEscape(name)), + "type": "providerVdc", + "filter": fmt.Sprintf("name==%s", url.QueryEscape(name)), + "filterEncoded": "true", }) if err != nil { return nil, err @@ -784,8 +788,9 @@ func GetNetworkPoolByHREF(client *VCDClient, href string) (*types.VMWNetworkPool // QueryOrgVdcNetworkByName finds a org VDC network by name which has edge gateway as reference func QueryOrgVdcNetworkByName(vcdCli *VCDClient, name string) ([]*types.QueryResultOrgVdcNetworkRecordType, error) { results, err := vcdCli.QueryWithNotEncodedParams(nil, map[string]string{ - "type": "orgVdcNetwork", - "filter": fmt.Sprintf("name==%s", url.QueryEscape(name)), + "type": "orgVdcNetwork", + "filter": fmt.Sprintf("name==%s", url.QueryEscape(name)), + "filterEncoded": "true", }) if err != nil { return nil, err diff --git a/govcd/vdc.go b/govcd/vdc.go index 93f4b1d9d..75324ed1e 100644 --- a/govcd/vdc.go +++ b/govcd/vdc.go @@ -663,7 +663,8 @@ func (vdc *Vdc) QueryVM(vappName, vmName string) (VMRecord, error) { } results, err := vdc.QueryWithNotEncodedParams(nil, map[string]string{"type": typeMedia, - "filter": "name==" + url.QueryEscape(vmName) + ";containerName==" + url.QueryEscape(vappName)}) + "filter": "name==" + url.QueryEscape(vmName) + ";containerName==" + url.QueryEscape(vappName), + "filterEncoded": "true"}) if err != nil { return VMRecord{}, fmt.Errorf("error querying vm %s", err) } From 6226fbbe937ad9bc5e9ccebb699d00bd20672505 Mon Sep 17 00:00:00 2001 From: Vaidotas Bauzys Date: Thu, 26 Mar 2020 13:16:42 +0200 Subject: [PATCH 3/9] Update change log Signed-off-by: Vaidotas Bauzys --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f2b5e83a..c415654e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ * Added methods `EdgeGateway.Update` and `EdgeGateway.UpdateAsync` [#292](https://github.com/vmware/go-vcloud-director/pull/292) BUGS FIXED: -* Fix issue in Queries with vCD 10 version, which do not return network pool or provider VDC[#xxx](https://github.com/vmware/go-vcloud-director/pull/xxx) +* Fix issue in Queries with vCD 10 version, which do not return network pool or provider VDC[#293](https://github.com/vmware/go-vcloud-director/pull/293) ## 2.6.0 (March 13, 2010) From 533f3be65162ec348f4f75144dbbf658161ab694 Mon Sep 17 00:00:00 2001 From: Vaidotas Bauzys Date: Thu, 26 Mar 2020 13:40:41 +0200 Subject: [PATCH 4/9] Cleanup stuff from another branch Signed-off-by: Vaidotas Bauzys --- govcd/vm.go | 30 ---------- govcd/vm_test.go | 135 ------------------------------------------ types/v56/vm_types.go | 38 ------------ 3 files changed, 203 deletions(-) delete mode 100644 types/v56/vm_types.go diff --git a/govcd/vm.go b/govcd/vm.go index 9dec8dbcc..106d65eac 100644 --- a/govcd/vm.go +++ b/govcd/vm.go @@ -1355,33 +1355,3 @@ func (vm *VM) UpdateInternalDisksAsync(disksSettingToUpdate *types.VmSpecSection }, vm.client.GetSpecificApiVersionOnCondition(">= 32.0", "32.0")) } - -func (vapp *VApp) AddEmptyVm(reComposeVAppParams *types.RecomposeVAppParamsForEmptyVm) (*VM, error) { - // TODO add validation - task, err := vapp.AddEmptyVmAsync(reComposeVAppParams) - if err != nil { - return nil, err - } - - err = task.WaitTaskCompletion() - if err != nil { - return nil, err - } - - newVm, err := vapp.GetVMByName(reComposeVAppParams.CreateItem.Name, true) - if err != nil { - return nil, err - } - - return newVm, nil - -} - -func (vapp *VApp) AddEmptyVmAsync(reComposeVAppParams *types.RecomposeVAppParamsForEmptyVm) (Task, error) { - apiEndpoint, _ := url.ParseRequestURI(vapp.VApp.HREF) - apiEndpoint.Path += "/action/recomposeVApp" - - // Return the task - return vapp.client.ExecuteTaskRequest(apiEndpoint.String(), http.MethodPost, - types.MimeRecomposeVappParams, "error instantiating a new VM: %s", reComposeVAppParams) -} diff --git a/govcd/vm_test.go b/govcd/vm_test.go index 60c51ec34..b94ec0707 100644 --- a/govcd/vm_test.go +++ b/govcd/vm_test.go @@ -1296,138 +1296,3 @@ func deleteVapp(vcd *TestVCD, name string) error { } return nil } - -func (vcd *TestVCD) Test_AddNewEmptyVMMultiNIC(check *C) { - - config := vcd.config - if config.VCD.Network.Net1 == "" { - check.Skip("Skipping test because no network was given") - } - - // Find VApp - if vcd.vapp.VApp == nil { - check.Skip("skipping test because no vApp is found") - } - - vapp, err := createVappForTest(vcd, "Test_AddNewEmptyVMMultiNIC") - check.Assert(err, IsNil) - check.Assert(vapp, NotNil) - - desiredNetConfig := &types.NetworkConnectionSection{} - desiredNetConfig.PrimaryNetworkConnectionIndex = 0 - desiredNetConfig.NetworkConnection = append(desiredNetConfig.NetworkConnection, - &types.NetworkConnection{ - IsConnected: true, - IPAddressAllocationMode: types.IPAllocationModePool, - Network: config.VCD.Network.Net1, - NetworkConnectionIndex: 0, - }, - &types.NetworkConnection{ - IsConnected: true, - IPAddressAllocationMode: types.IPAllocationModeNone, - Network: types.NoneNetwork, - NetworkConnectionIndex: 1, - }) - - // Test with two different networks if we have them - if config.VCD.Network.Net2 != "" { - // Attach second vdc network to vApp - vdcNetwork2, err := vcd.vdc.GetOrgVdcNetworkByName(vcd.config.VCD.Network.Net2, false) - check.Assert(err, IsNil) - _, err = vapp.AddOrgNetwork(&VappNetworkSettings{}, vdcNetwork2.OrgVDCNetwork, false) - check.Assert(err, IsNil) - - desiredNetConfig.NetworkConnection = append(desiredNetConfig.NetworkConnection, - &types.NetworkConnection{ - IsConnected: true, - IPAddressAllocationMode: types.IPAllocationModePool, - Network: config.VCD.Network.Net2, - NetworkConnectionIndex: 2, - }, - ) - } else { - fmt.Println("Skipping adding another vdc network as network2 was not specified") - } - - cat, err := vcd.org.GetCatalogByName(vcd.config.VCD.Catalog.Name, true) - check.Assert(err, IsNil) - check.Assert(cat, NotNil) - - //media, err := cat.GetMediaByName("photon-custom-hw11-2.0-304b817.ova", false) - media, err := cat.GetMediaByName("vaido2", false) - check.Assert(err, IsNil) - check.Assert(media, NotNil) - - var task Task - var sp types.Reference - var customSP = false - - if vcd.config.VCD.StorageProfile.SP1 != "" { - sp, _ = vcd.vdc.FindStorageProfileReference(vcd.config.VCD.StorageProfile.SP1) - } - - newDisk := types.DiskSettings{ - AdapterType: "5", - SizeMb: int64(16384), - BusNumber: 0, - UnitNumber: 0, - ThinProvisioned: takeBoolPointer(true), - OverrideVmDefault: true} - - requestDetails := &types.RecomposeVAppParamsForEmptyVm{ - XmlnsVcloud: types.XMLNamespaceVCloud, - XmlnsOvf: types.XMLNamespaceOVF, - CreateItem: &types.CreateItem{ - Name: "Test_AddNewEmptyVMMultiNIC", - NetworkConnectionSection: desiredNetConfig, - Description: "created by Test_AddNewEmptyVMMultiNIC", - GuestCustomizationSection: nil, - VmSpecSection: &types.VmSpecSection{ - Modified: takeBoolPointer(true), - Info: "Virtual Machine specification", - OsType: "debian10Guest", - NumCpus: takeIntAddress(2), - NumCoresPerSocket: takeIntAddress(1), - CpuResourceMhz: &types.CpuResourceMhz{Configured: 1}, - MemoryResourceMb: &types.MemoryResourceMb{Configured: 1024}, - MediaSection: nil, - DiskSection: &types.DiskSection{DiskSettings: []*types.DiskSettings{&newDisk}}, - HardwareVersion: &types.HardwareVersion{Value: "vmx-13"}, // need support older version vCD - VmToolsVersion: "", - VirtualCpuType: "VM32", - TimeSyncWithHost: nil, - }, - BootImage: &types.Media{HREF: media.Media.HREF, Name: media.Media.Name, ID: media.Media.ID}, - }, - AllEULAsAccepted: true, - } - - createdVm, err := vapp.AddEmptyVm(requestDetails) - check.Assert(err, IsNil) - check.Assert(createdVm, NotNil) - - // Ensure network config was valid - actualNetConfig, err := createdVm.GetNetworkConnectionSection() - check.Assert(err, IsNil) - - if customSP { - check.Assert(createdVm.VM.StorageProfile.HREF, Equals, sp.HREF) - } - - verifyNetworkConnectionSection(check, actualNetConfig, desiredNetConfig) - - // Cleanup - err = vapp.RemoveVM(*createdVm) - check.Assert(err, IsNil) - - // Ensure network is detached from vApp to avoid conflicts in other tests - task, err = vapp.RemoveAllNetworks() - check.Assert(err, IsNil) - err = task.WaitTaskCompletion() - check.Assert(err, IsNil) - task, err = vapp.Delete() - check.Assert(err, IsNil) - err = task.WaitTaskCompletion() - check.Assert(err, IsNil) - check.Assert(task.Task.Status, Equals, "success") -} diff --git a/types/v56/vm_types.go b/types/v56/vm_types.go deleted file mode 100644 index 6d7264020..000000000 --- a/types/v56/vm_types.go +++ /dev/null @@ -1,38 +0,0 @@ -package types - -import "encoding/xml" - -// VmSpecSection from VM struct -type VmSpecSection struct { - Modified *bool `xml:"Modified,attr,omitempty"` - Info string `xml:"ovf:Info"` - OsType string `xml:"OsType,omitempty"` // The type of the OS. This parameter may be omitted when using the VmSpec to update the contents of an existing VM. - NumCpus *int `xml:"NumCpus,omitempty"` // Number of CPUs. This parameter may be omitted when using the VmSpec to update the contents of an existing VM. - NumCoresPerSocket *int `xml:"NumCoresPerSocket,omitempty"` // Number of cores among which to distribute CPUs in this virtual machine. This parameter may be omitted when using the VmSpec to update the contents of an existing VM. - CpuResourceMhz *CpuResourceMhz `xml:"CpuResourceMhz,omitempty"` // CPU compute resources. This parameter may be omitted when using the VmSpec to update the contents of an existing VM. - MemoryResourceMb *MemoryResourceMb `xml:"MemoryResourceMb"` // Memory compute resources. This parameter may be omitted when using the VmSpec to update the contents of an existing VM. - MediaSection *MediaSection `xml:"MediaSection,omitempty"` // The media devices of this VM. - DiskSection *DiskSection `xml:"DiskSection,omitempty"` // virtual disks of this VM. - HardwareVersion *HardwareVersion `xml:"HardwareVersion"` // vSphere name of Virtual Hardware Version of this VM. Example: vmx-13 - This parameter may be omitted when using the VmSpec to update the contents of an existing VM. - VmToolsVersion string `xml:"VmToolsVersion,omitempty"` // VMware tools version of this VM. - VirtualCpuType string `xml:"VirtualCpuType,omitempty"` // The capabilities settings for this VM. This parameter may be omitted when using the VmSpec to update the contents of an existing VM. - TimeSyncWithHost *bool `xml:"TimeSyncWithHost,omitempty"` // Synchronize the VM's time with the host. -} - -type RecomposeVAppParamsForEmptyVm struct { - XMLName xml.Name `xml:"RecomposeVAppParams"` - XmlnsVcloud string `xml:"xmlns,attr"` - XmlnsOvf string `xml:"xmlns:ovf,attr"` - CreateItem *CreateItem `xml:"CreateItem,omitempty"` - AllEULAsAccepted bool `xml:"AllEULAsAccepted,omitempty"` -} - -type CreateItem struct { - //XMLName xml.Name `xml:"CreateItem"` - Name string `xml:"name,attr,omitempty"` - Description string `xml:"Description,omitempty"` - GuestCustomizationSection *GuestCustomizationSection `xml:"GuestCustomizationSection,omitempty"` - NetworkConnectionSection *NetworkConnectionSection `xml:"NetworkConnectionSection,omitempty"` - VmSpecSection *VmSpecSection `xml:"VmSpecSection,omitempty"` - BootImage *Media `xml:"Media,omitempty"` // boot image as vApp template. Href, Id and name needed. -} From 3d5abec3cbf2535779dd94713c99d8b608ea7c3d Mon Sep 17 00:00:00 2001 From: Vaidotas Bauzys Date: Thu, 26 Mar 2020 13:42:35 +0200 Subject: [PATCH 5/9] Cleanup stuff from another branch Signed-off-by: Vaidotas Bauzys --- govcd/edgegateway_unit_test.go | 5 +++++ types/v56/types.go | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/govcd/edgegateway_unit_test.go b/govcd/edgegateway_unit_test.go index 303c93390..1d2e49cdc 100644 --- a/govcd/edgegateway_unit_test.go +++ b/govcd/edgegateway_unit_test.go @@ -423,3 +423,8 @@ func Test_getNetworkNameTypeFromVnicIndex(t *testing.T) { }) } } + +// takeIntAddress is a helper which can gives address of `int` +func takeIntAddress(x int) *int { + return &x +} diff --git a/types/v56/types.go b/types/v56/types.go index 5a815a724..e727c606c 100644 --- a/types/v56/types.go +++ b/types/v56/types.go @@ -1392,6 +1392,23 @@ type VMDiskChange struct { VmSpecSection *VmSpecSection `xml:"VmSpecSection,omitempty"` // Container for the specification of this virtual machine. This is an alternative to using ovf:VirtualHardwareSection + ovf:OperatingSystemSection } +// VmSpecSection from VM struct +type VmSpecSection struct { + Modified *bool `xml:"Modified,attr,omitempty"` + Info string `xml:"ovf:Info"` + OsType string `xml:"OsType,omitempty"` // The type of the OS. This parameter may be omitted when using the VmSpec to update the contents of an existing VM. + NumCpus *int `xml:"NumCpus,omitempty"` // Number of CPUs. This parameter may be omitted when using the VmSpec to update the contents of an existing VM. + NumCoresPerSocket *int `xml:"NumCoresPerSocket,omitempty"` // Number of cores among which to distribute CPUs in this virtual machine. This parameter may be omitted when using the VmSpec to update the contents of an existing VM. + CpuResourceMhz *CpuResourceMhz `xml:"CpuResourceMhz,omitempty"` // CPU compute resources. This parameter may be omitted when using the VmSpec to update the contents of an existing VM. + MemoryResourceMb *MemoryResourceMb `xml:"MemoryResourceMb"` // Memory compute resources. This parameter may be omitted when using the VmSpec to update the contents of an existing VM. + MediaSection *MediaSection `xml:"MediaSection,omitempty"` // The media devices of this VM. + DiskSection *DiskSection `xml:"DiskSection,omitempty"` // virtual disks of this VM. + HardwareVersion *HardwareVersion `xml:"HardwareVersion"` // vSphere name of Virtual Hardware Version of this VM. Example: vmx-13 - This parameter may be omitted when using the VmSpec to update the contents of an existing VM. + VmToolsVersion string `xml:"VmToolsVersion,omitempty"` // VMware tools version of this VM. + VirtualCpuType string `xml:"VirtualCpuType,omitempty"` // The capabilities settings for this VM. This parameter may be omitted when using the VmSpec to update the contents of an existing VM. + TimeSyncWithHost *bool `xml:"TimeSyncWithHost,omitempty"` // Synchronize the VM's time with the host. +} + // DiskSection from VM/VmSpecSection struct type DiskSection struct { DiskSettings []*DiskSettings `xml:"DiskSettings"` From 46a3dfc9f0f33a0b63a952cb3bf342399a44a770 Mon Sep 17 00:00:00 2001 From: Vaidotas Bauzys Date: Thu, 26 Mar 2020 13:43:14 +0200 Subject: [PATCH 6/9] Cleanup stuff from another branch Signed-off-by: Vaidotas Bauzys --- govcd/api.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/govcd/api.go b/govcd/api.go index 9eac7430f..b509ae5d5 100644 --- a/govcd/api.go +++ b/govcd/api.go @@ -564,8 +564,3 @@ func combinedTaskErrorMessage(task *types.Task, err error) string { func takeBoolPointer(value bool) *bool { return &value } - -// takeIntAddress is a helper which can gives address of `int` -func takeIntAddress(x int) *int { - return &x -} From 3a6c8379c130de0529d79472052380b5bbb81979 Mon Sep 17 00:00:00 2001 From: Vaidotas Bauzys Date: Fri, 27 Mar 2020 09:30:04 +0200 Subject: [PATCH 7/9] Added VDC function handling mappings for version 10.1 Signed-off-by: Vaidotas Bauzys --- govcd/adminvdc.go | 2 ++ govcd/api_vcd_versions.go | 3 +++ 2 files changed, 5 insertions(+) diff --git a/govcd/adminvdc.go b/govcd/adminvdc.go index 2869eafd8..d7d9fb3a3 100644 --- a/govcd/adminvdc.go +++ b/govcd/adminvdc.go @@ -52,6 +52,7 @@ var vdcVersionedFuncsV97 = vdcVersionedFuncs{ UpdateVdcAsync: updateVdcAsyncV97, } +// TODO: add a wrapper function to use newest available method when version is higher than currently handled // VDC function mapping by vDC version var vdcVersionedFuncsByVcdVersion = map[string]vdcVersionedFuncs{ "vdc9.0": vdcVersionedFuncsV90, @@ -59,6 +60,7 @@ var vdcVersionedFuncsByVcdVersion = map[string]vdcVersionedFuncs{ "vdc9.5": vdcVersionedFuncsV90, "vdc9.7": vdcVersionedFuncsV97, "vdc10.0": vdcVersionedFuncsV97, + "vdc10.1": vdcVersionedFuncsV97, } // GetAdminVdcByName function uses a valid VDC name and returns a admin VDC object. diff --git a/govcd/api_vcd_versions.go b/govcd/api_vcd_versions.go index e51f755bc..5ff6e15bc 100644 --- a/govcd/api_vcd_versions.go +++ b/govcd/api_vcd_versions.go @@ -33,6 +33,8 @@ var apiVersionToVcdVersion = map[string]string{ "31.0": "9.5", "32.0": "9.7", "33.0": "10.0", + "34.0": "10.1", + "35.0": "10.1", } // vcdVersionToApiVersion gets the max supported API version from vCD version @@ -42,6 +44,7 @@ var vcdVersionToApiVersion = map[string]string{ "9.5": "31.0", "9.7": "32.0", "10.0": "33.0", + "10.1": "34.0", } // to make vcdVersionToApiVersion used From 26828955c0204e1c0c996666c7fd7b6f2d96b4b0 Mon Sep 17 00:00:00 2001 From: Vaidotas Bauzys Date: Mon, 30 Mar 2020 13:27:08 +0300 Subject: [PATCH 8/9] Add change for provider VDC query, increases version to get result, as backed NSX-T is returned only from API 31 version. Signed-off-by: Vaidotas Bauzys --- govcd/query.go | 17 +++++++++++++++-- govcd/system.go | 4 ++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/govcd/query.go b/govcd/query.go index 564c2b8b9..7dbaee1c0 100644 --- a/govcd/query.go +++ b/govcd/query.go @@ -42,11 +42,16 @@ func (vdc *Vdc) Query(params map[string]string) (Results, error) { // QueryWithNotEncodedParams uses Query API to search for requested data func (client *Client) QueryWithNotEncodedParams(params map[string]string, notEncodedParams map[string]string) (Results, error) { + return client.QueryWithNotEncodedParamsWithApiVersion(params, notEncodedParams, client.APIVersion) +} + +// QueryWithNotEncodedParams uses Query API to search for requested data +func (client *Client) QueryWithNotEncodedParamsWithApiVersion(params map[string]string, notEncodedParams map[string]string, apiVersion string) (Results, error) { queryUlr := client.VCDHREF queryUlr.Path += "/query" - req := client.NewRequestWitNotEncodedParams(params, notEncodedParams, http.MethodGet, queryUlr, nil) - req.Header.Add("Accept", "vnd.vmware.vcloud.org+xml;version="+client.APIVersion) + req := client.NewRequestWitNotEncodedParamsWithApiVersion(params, notEncodedParams, http.MethodGet, queryUlr, nil, apiVersion) + req.Header.Add("Accept", "vnd.vmware.vcloud.org+xml;version="+apiVersion) return getResult(client, req) } @@ -59,6 +64,14 @@ func (vdc *Vdc) QueryWithNotEncodedParams(params map[string]string, notEncodedPa return vdc.client.QueryWithNotEncodedParams(params, notEncodedParams) } +func (vcdCli *VCDClient) QueryWithNotEncodedParamsWithApiVersion(params map[string]string, notEncodedParams map[string]string, apiVersion string) (Results, error) { + return vcdCli.Client.QueryWithNotEncodedParamsWithApiVersion(params, notEncodedParams, apiVersion) +} + +func (vdc *Vdc) QueryWithNotEncodedParamsWithApiVersion(params map[string]string, notEncodedParams map[string]string, apiVersion string) (Results, error) { + return vdc.client.QueryWithNotEncodedParamsWithApiVersion(params, notEncodedParams, apiVersion) +} + func getResult(client *Client, request *http.Request) (Results, error) { resp, err := checkResp(client.Http.Do(request)) if err != nil { diff --git a/govcd/system.go b/govcd/system.go index a272c0325..bdb4a4113 100644 --- a/govcd/system.go +++ b/govcd/system.go @@ -723,11 +723,11 @@ func QueryNetworkPoolByName(vcdCli *VCDClient, name string) ([]*types.QueryResul // QueryProviderVdcByName finds a provider VDC by name func QueryProviderVdcByName(vcdCli *VCDClient, name string) ([]*types.QueryResultVMWProviderVdcRecordType, error) { - results, err := vcdCli.QueryWithNotEncodedParams(nil, map[string]string{ + results, err := vcdCli.QueryWithNotEncodedParamsWithApiVersion(nil, map[string]string{ "type": "providerVdc", "filter": fmt.Sprintf("name==%s", url.QueryEscape(name)), "filterEncoded": "true", - }) + }, vcdCli.Client.GetSpecificApiVersionOnCondition(">= 31.0", "31.0")) if err != nil { return nil, err } From a10e855642984eac6e3f786fd4e59bd4fefb245c Mon Sep 17 00:00:00 2001 From: Vaidotas Bauzys Date: Wed, 1 Apr 2020 08:43:56 +0300 Subject: [PATCH 9/9] Cleanup Signed-off-by: Vaidotas Bauzys --- govcd/api_vcd_versions.go | 1 - 1 file changed, 1 deletion(-) diff --git a/govcd/api_vcd_versions.go b/govcd/api_vcd_versions.go index 5ff6e15bc..94d8251d6 100644 --- a/govcd/api_vcd_versions.go +++ b/govcd/api_vcd_versions.go @@ -34,7 +34,6 @@ var apiVersionToVcdVersion = map[string]string{ "32.0": "9.7", "33.0": "10.0", "34.0": "10.1", - "35.0": "10.1", } // vcdVersionToApiVersion gets the max supported API version from vCD version