From ea64aca25cc43d63b6c45c12e6c1dc7d2a94bb82 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Thu, 25 Aug 2022 12:13:49 +0200 Subject: [PATCH 01/48] Init Signed-off-by: abarreiro --- govcd/openapi_endpoints.go | 2 ++ govcd/vdccomputepolicy.go | 2 +- types/v56/constants.go | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/govcd/openapi_endpoints.go b/govcd/openapi_endpoints.go index 531a5dce0..1cd186960 100644 --- a/govcd/openapi_endpoints.go +++ b/govcd/openapi_endpoints.go @@ -73,6 +73,8 @@ var endpointMinApiVersions = map[string]string{ types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointEdgeBgpNeighbor: "35.0", // VCD 10.2+ types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointEdgeBgpConfigPrefixLists: "35.0", // VCD 10.2+ types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointEdgeBgpConfig: "35.0", // VCD 10.2+ + + types.OpenApiPathVersion2_0_0 + types.OpenApiEndpointVdcAssignedComputePolicies: "35.0", } // elevateNsxtNatRuleApiVersion helps to elevate API version to consume newer NSX-T NAT Rule features diff --git a/govcd/vdccomputepolicy.go b/govcd/vdccomputepolicy.go index 56af70f92..85b0c045c 100644 --- a/govcd/vdccomputepolicy.go +++ b/govcd/vdccomputepolicy.go @@ -213,7 +213,7 @@ func (vdcComputePolicy *VdcComputePolicy) Delete() error { // GetAllAssignedVdcComputePolicies retrieves all VDC assigned compute policies using OpenAPI endpoint. Query parameters can be supplied to perform additional // filtering func (vdc *AdminVdc) GetAllAssignedVdcComputePolicies(queryParameters url.Values) ([]*VdcComputePolicy, error) { - endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcAssignedComputePolicies + endpoint := types.OpenApiPathVersion2_0_0 + types.OpenApiEndpointVdcAssignedComputePolicies minimumApiVersion, err := vdc.client.checkOpenApiEndpointCompatibility(endpoint) if err != nil { return nil, err diff --git a/types/v56/constants.go b/types/v56/constants.go index 476bc4e29..9fff0bf2c 100644 --- a/types/v56/constants.go +++ b/types/v56/constants.go @@ -340,6 +340,7 @@ const ( // future. const ( OpenApiPathVersion1_0_0 = "1.0.0/" + OpenApiPathVersion2_0_0 = "2.0.0/" OpenApiEndpointRoles = "roles/" OpenApiEndpointGlobalRoles = "globalRoles/" OpenApiEndpointRights = "rights/" From b4a34a2e20b5fe10e65b36cdf261d87c45de2643 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Thu, 25 Aug 2022 12:17:20 +0200 Subject: [PATCH 02/48] Remove OpenAPI endpoint Signed-off-by: abarreiro --- .changes/v2.17.0/502-improvements.md | 0 govcd/openapi_endpoints.go | 11 +++++------ 2 files changed, 5 insertions(+), 6 deletions(-) create mode 100644 .changes/v2.17.0/502-improvements.md diff --git a/.changes/v2.17.0/502-improvements.md b/.changes/v2.17.0/502-improvements.md new file mode 100644 index 000000000..e69de29bb diff --git a/govcd/openapi_endpoints.go b/govcd/openapi_endpoints.go index 1cd186960..6f40e9371 100644 --- a/govcd/openapi_endpoints.go +++ b/govcd/openapi_endpoints.go @@ -28,12 +28,11 @@ var endpointMinApiVersions = map[string]string{ types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointImportableTier0Routers: "32.0", // OpenApiEndpointExternalNetworks endpoint support was introduced with version 32.0 however it was still not stable // enough to be used. (i.e. it did not support update "PUT") - types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointExternalNetworks: "33.0", - types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcComputePolicies: "32.0", - types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcAssignedComputePolicies: "33.0", - types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointSessionCurrent: "34.0", - types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointEdgeClusters: "34.0", // VCD 10.1+ - types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointEdgeGateways: "34.0", + types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointExternalNetworks: "33.0", + types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcComputePolicies: "32.0", + types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointSessionCurrent: "34.0", + types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointEdgeClusters: "34.0", // VCD 10.1+ + types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointEdgeGateways: "34.0", // Static security groups and IP sets in VCD 10.2, Dynamic security groups in VCD 10.3+ types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointFirewallGroups: "34.0", From 3eb87b189a3e33bd8c0f75039d2a7248b637d3ee Mon Sep 17 00:00:00 2001 From: abarreiro Date: Thu, 25 Aug 2022 13:29:02 +0200 Subject: [PATCH 03/48] Add Provider VDC types Signed-off-by: abarreiro --- govcd/provider_vdc.go | 34 ++++++++++++++++++++ govcd/provider_vdc_test.go | 18 +++++++++++ types/v56/types.go | 65 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 govcd/provider_vdc.go create mode 100644 govcd/provider_vdc_test.go diff --git a/govcd/provider_vdc.go b/govcd/provider_vdc.go new file mode 100644 index 000000000..0145f61cd --- /dev/null +++ b/govcd/provider_vdc.go @@ -0,0 +1,34 @@ +package govcd + +import ( + "github.com/vmware/go-vcloud-director/v2/types/v56" + "net/http" +) + +type ProviderVdc struct { + ProviderVdc *types.ProviderVdc + client *Client +} + +func NewProviderVdc(cli *Client) *ProviderVdc { + return &ProviderVdc{ + ProviderVdc: new(types.ProviderVdc), + client: cli, + } +} + +// GetProviderVdcById finds a Provider VDC by URN. +// On success, returns a pointer to the ProviderVdc structure and a nil error +// On failure, returns a nil pointer and an error +func (vcdClient *VCDClient) GetProviderVdcById(providerVdcId string) (*ProviderVdc, error) { + providerVdcHref := vcdClient.Client.VCDHREF.Path + "/admin/providervdc/" + providerVdcId + providerVdc := NewProviderVdc(&vcdClient.Client) + + _, err := vcdClient.Client.ExecuteRequest(providerVdcHref, http.MethodGet, + "", "error retrieving Provider VDC: %s", nil, providerVdc.ProviderVdc) + if err != nil { + return nil, err + } + + return providerVdc, nil +} diff --git a/govcd/provider_vdc_test.go b/govcd/provider_vdc_test.go new file mode 100644 index 000000000..be049da29 --- /dev/null +++ b/govcd/provider_vdc_test.go @@ -0,0 +1,18 @@ +//go:build pvdc || functional || ALL + +/* + * Copyright 2018 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. + * Copyright 2016 Skyscape Cloud Services. All rights reserved. Licensed under the Apache v2 License. + */ + +package govcd + +import ( + . "gopkg.in/check.v1" +) + +func (vcd *TestVCD) Test_ProviderVdc(check *C) { + providerVdc, err := vcd.client.GetProviderVdcById("0f32bce0-62c0-481e-bb71-254b1fd40434") + check.Assert(err, IsNil) + check.Assert(providerVdc, NotNil) +} diff --git a/types/v56/types.go b/types/v56/types.go index ce6b132cc..ad6a1cbe7 100644 --- a/types/v56/types.go +++ b/types/v56/types.go @@ -463,6 +463,71 @@ type AdminVdc struct { UniversalNetworkPoolReference *Reference `xml:"UniversalNetworkPoolReference,omitempty"` // Reference to a universal network pool } +type ProviderVdc struct { + Xmlns string `xml:"xmlns,attr"` + HREF string `xml:"href,attr,omitempty"` + Type string `xml:"type,attr,omitempty"` + ID string `xml:"id,attr,omitempty"` + OperationKey string `xml:"operationKey,attr,omitempty"` + Name string `xml:"name,attr"` + Status int `xml:"status,attr,omitempty"` + + AvailableNetworks []*AvailableNetworks `xml:"AvailableNetworks,attr,omitempty"` + Capabilities []*Capabilities `xml:"Capabilities,attr,omitempty"` + ComputeCapacity *RootComputeCapacity `xml:"RootComputeCapacity,attr,omitempty"` + Description *string `xml:"Description,attr,omitempty"` + IsEnabled *bool `xml:"IsEnabled,attr,omitempty"` + Link *Link `xml:"Link,attr,omitempty"` + NetworkPoolReferences []*NetworkPoolReferences `xml:"NetworkPoolReferences,attr,omitempty"` + StorageProfiles []*ProviderStorageProfiles `xml:"StorageProfiles,attr,omitempty"` + Tasks *TasksInProgress `xml:"Tasks,attr,omitempty"` + Vdcs []*Vdc `xml:"Vdcs,attr,omitempty"` +} + +// RootComputeCapacity represents compute capacity with units. +// Type: RootComputeCapacityType +// Namespace: http://www.vmware.com/vcloud/v1.5 +// Description: Represents compute capacity with units. +// Since: 0.9 +type RootComputeCapacity struct { + Cpu *ProviderVdcCapacity `xml:"Cpu"` + IsElastic *bool `xml:"IsElastic,omitempty"` + IsHA *bool `xml:"IsHA,omitempty"` + Memory *ProviderVdcCapacity `xml:"Memory"` +} + +// NetworkPoolReferences is a container for references to network pools in this vDC. +// Type: NetworkPoolReferencesType +// Namespace: http://www.vmware.com/vcloud/v1.5 +// Description: Container for references to network pools in this vDC. +// Since: 0.9 +type NetworkPoolReferences struct { + NetworkPoolReference *Reference `xml:"NetworkPoolReference"` +} + +// ProviderVdcStorageProfiles is a container for references to storage profiles associated with a Provider vDC. +// Type: ProviderVdcStorageProfilesType +// Namespace: http://www.vmware.com/vcloud/v1.5 +// Description: Container for references to storage profiles associated with a Provider vDC. +// Since: 0.9 +type ProviderStorageProfiles struct { + ProviderVdcStorageProfile *Reference `xml:"ProviderVdcStorageProfile"` +} + +// ProviderVdcCapacity represents resource capacity in a Provider vDC. +// Type: ProviderVdcCapacityType +// Namespace: http://www.vmware.com/vcloud/v1.5 +// Description: Represents resource capacity in a Provider vDC. +// Since: 0.9 +type ProviderVdcCapacity struct { + Allocation *int64 `xml:"Allocation,omitempty"` + Overhead *int64 `xml:"Overhead,omitempty"` + Reserved *int64 `xml:"Reserved,omitempty"` + Total int64 `xml:"Total"` + Units string `xml:"Units"` + Used *int64 `xml:"Used,omitempty"` +} + // VdcStorageProfileConfiguration represents the parameters to assign a storage profile in creation of organization vDC. // Type: VdcStorageProfileParamsType // Namespace: http://www.vmware.com/vcloud/v1.5 From a20f2461b1b361a41dae850eca793be893066d61 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Thu, 25 Aug 2022 16:39:52 +0200 Subject: [PATCH 04/48] Finish provider functions Signed-off-by: abarreiro --- govcd/api.go | 6 ++- govcd/api_vcd_test.go | 4 +- govcd/metadata.go | 80 ++++++++++++++++++++++++++++++++++++++ govcd/metadata_test.go | 11 ++++++ govcd/provider_vdc.go | 57 +++++++++++++++++++++++++-- govcd/provider_vdc_test.go | 37 +++++++++++++----- types/v56/types.go | 31 ++++++++------- 7 files changed, 198 insertions(+), 28 deletions(-) diff --git a/govcd/api.go b/govcd/api.go index 747da7ef9..3912e0ea0 100644 --- a/govcd/api.go +++ b/govcd/api.go @@ -775,7 +775,11 @@ func (client *Client) RemoveProvidedCustomHeaders(values map[string]string) { // Retrieves the administrator URL of a given HREF func getAdminURL(href string) string { - return strings.ReplaceAll(href, "/api/", "/api/admin/") + adminApi := "/api/admin" + if strings.Contains(href, adminApi) { + return href + } + return strings.ReplaceAll(href, "/api/", adminApi) } // --------------------------------------------------------------------- diff --git a/govcd/api_vcd_test.go b/govcd/api_vcd_test.go index 944cb8784..7727c2a8d 100644 --- a/govcd/api_vcd_test.go +++ b/govcd/api_vcd_test.go @@ -1,5 +1,5 @@ -//go:build api || openapi || functional || catalog || vapp || gateway || network || org || query || extnetwork || task || vm || vdc || system || disk || lb || lbAppRule || lbAppProfile || lbServerPool || lbServiceMonitor || lbVirtualServer || user || search || nsxv || nsxt || auth || affinity || role || alb || certificate || vdcGroup || metadata || ALL -// +build api openapi functional catalog vapp gateway network org query extnetwork task vm vdc system disk lb lbAppRule lbAppProfile lbServerPool lbServiceMonitor lbVirtualServer user search nsxv nsxt auth affinity role alb certificate vdcGroup metadata ALL +//go:build api || openapi || functional || catalog || vapp || gateway || network || org || query || extnetwork || task || vm || vdc || system || disk || lb || lbAppRule || lbAppProfile || lbServerPool || lbServiceMonitor || lbVirtualServer || user || search || nsxv || nsxt || auth || affinity || role || alb || certificate || vdcGroup || metadata || providervdc || ALL +// +build api openapi functional catalog vapp gateway network org query extnetwork task vm vdc system disk lb lbAppRule lbAppProfile lbServerPool lbServiceMonitor lbVirtualServer user search nsxv nsxt auth affinity role alb certificate vdcGroup metadata providervdc ALL /* * Copyright 2022 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. diff --git a/govcd/metadata.go b/govcd/metadata.go index f0a155a91..813f7c1fc 100644 --- a/govcd/metadata.go +++ b/govcd/metadata.go @@ -223,6 +223,86 @@ func (vdc *Vdc) DeleteMetadataEntryAsync(key string) (Task, error) { return deleteMetadata(vdc.client, key, getAdminURL(vdc.Vdc.HREF)) } +// GetMetadata returns Provider VDC metadata. +// Note: Requires system administrator privileges. +func (providerVdc *ProviderVdc) GetMetadata() (*types.Metadata, error) { + return getMetadata(providerVdc.client, providerVdc.ProviderVdc.HREF) +} + +// AddMetadataEntry adds Provider VDC metadata typedValue and key/value pair provided as input +// and waits for the task to finish. +// Note: Requires system administrator privileges. +func (providerVdc *ProviderVdc) AddMetadataEntry(typedValue, key, value string) error { + task, err := providerVdc.AddMetadataEntryAsync(typedValue, key, value) + if err != nil { + return err + } + + err = task.WaitTaskCompletion() + if err != nil { + return err + } + + err = providerVdc.Refresh() + if err != nil { + return err + } + + return nil +} + +// AddMetadataEntryAsync adds Provider VDC metadata typedValue and key/value pair provided as input and returns the task. +// Note: Requires system administrator privileges. +func (providerVdc *ProviderVdc) AddMetadataEntryAsync(typedValue, key, value string) (Task, error) { + return addMetadata(providerVdc.client, typedValue, key, value, providerVdc.ProviderVdc.HREF) +} + +// MergeMetadataAsync merges Provider VDC metadata provided as a key-value map of type `typedValue` with the already present in VCD, +// then waits for the task to complete. +// Note: Requires system administrator privileges. +func (providerVdc *ProviderVdc) MergeMetadataAsync(typedValue string, metadata map[string]interface{}) (Task, error) { + return mergeAllMetadata(providerVdc.client, typedValue, metadata, providerVdc.ProviderVdc.HREF) +} + +// MergeMetadata merges Provider VDC metadata provided as a key-value map of type `typedValue` with the already present in VCD, +// then waits for the task to complete. +// Note: Requires system administrator privileges. +func (providerVdc *ProviderVdc) MergeMetadata(typedValue string, metadata map[string]interface{}) error { + task, err := providerVdc.MergeMetadataAsync(typedValue, metadata) + if err != nil { + return err + } + return task.WaitTaskCompletion() +} + +// DeleteMetadataEntry deletes Provider VDC metadata by key provided as input and waits for +// the task to finish. +// Note: Requires system administrator privileges. +func (providerVdc *ProviderVdc) DeleteMetadataEntry(key string) error { + task, err := providerVdc.DeleteMetadataEntryAsync(key) + if err != nil { + return err + } + + err = task.WaitTaskCompletion() + if err != nil { + return err + } + + err = providerVdc.Refresh() + if err != nil { + return err + } + + return nil +} + +// DeleteMetadataEntryAsync deletes Provider VDC metadata depending on key provided as input and returns the task. +// Note: Requires system administrator privileges. +func (providerVdc *ProviderVdc) DeleteMetadataEntryAsync(key string) (Task, error) { + return deleteMetadata(providerVdc.client, key, providerVdc.ProviderVdc.HREF) +} + // GetMetadata returns VApp metadata. func (vapp *VApp) GetMetadata() (*types.Metadata, error) { return getMetadata(vapp.client, vapp.VApp.HREF) diff --git a/govcd/metadata_test.go b/govcd/metadata_test.go index 976bb8dc6..36afcb936 100644 --- a/govcd/metadata_test.go +++ b/govcd/metadata_test.go @@ -474,6 +474,17 @@ func (vcd *TestVCD) Test_MetadataOnCatalogItemCRUD(check *C) { testMetadataCRUDActions(catalogItem, check, nil) } +func (vcd *TestVCD) Test_MetadataOnProviderVdcCRUD(check *C) { + fmt.Printf("Running: %s\n", check.TestName()) + providerVdc, err := vcd.client.GetProviderVdcByName(vcd.config.VCD.NsxtProviderVdc.Name) + if err != nil { + check.Skip(fmt.Sprintf("%s: Provider VDC %s not found. Test can't proceed", check.TestName(), vcd.config.VCD.NsxtProviderVdc.Name)) + return + } + + testMetadataCRUDActions(providerVdc, check, nil) +} + func (vcd *TestVCD) Test_MetadataOnOpenApiOrgVdcNetworkCRUD(check *C) { fmt.Printf("Running: %s\n", check.TestName()) net, err := vcd.vdc.GetOpenApiOrgVdcNetworkByName(vcd.config.VCD.Network.Net1) diff --git a/govcd/provider_vdc.go b/govcd/provider_vdc.go index 0145f61cd..a301286c5 100644 --- a/govcd/provider_vdc.go +++ b/govcd/provider_vdc.go @@ -1,8 +1,10 @@ package govcd import ( + "fmt" "github.com/vmware/go-vcloud-director/v2/types/v56" "net/http" + "net/url" ) type ProviderVdc struct { @@ -17,11 +19,10 @@ func NewProviderVdc(cli *Client) *ProviderVdc { } } -// GetProviderVdcById finds a Provider VDC by URN. +// GetProviderVdcByHref finds a Provider VDC by its HREF. // On success, returns a pointer to the ProviderVdc structure and a nil error // On failure, returns a nil pointer and an error -func (vcdClient *VCDClient) GetProviderVdcById(providerVdcId string) (*ProviderVdc, error) { - providerVdcHref := vcdClient.Client.VCDHREF.Path + "/admin/providervdc/" + providerVdcId +func (vcdClient *VCDClient) GetProviderVdcByHref(providerVdcHref string) (*ProviderVdc, error) { providerVdc := NewProviderVdc(&vcdClient.Client) _, err := vcdClient.Client.ExecuteRequest(providerVdcHref, http.MethodGet, @@ -32,3 +33,53 @@ func (vcdClient *VCDClient) GetProviderVdcById(providerVdcId string) (*ProviderV return providerVdc, nil } + +// GetProviderVdcById finds a Provider VDC by URN. +// On success, returns a pointer to the ProviderVdc structure and a nil error +// On failure, returns a nil pointer and an error +func (vcdClient *VCDClient) GetProviderVdcById(providerVdcId string) (*ProviderVdc, error) { + providerVdcHref := vcdClient.Client.VCDHREF + providerVdcHref.Path += "/admin/providervdc/" + extractUuid(providerVdcId) + + return vcdClient.GetProviderVdcByHref(providerVdcHref.String()) +} + +// GetProviderVdcByName finds a Provider VDC by name. +// On success, returns a pointer to the ProviderVdc structure and a nil error +// On failure, returns a nil pointer and an error +func (vcdClient *VCDClient) GetProviderVdcByName(providerVdcName string) (*ProviderVdc, error) { + foundProviderVdcs, err := vcdClient.QueryWithNotEncodedParams(nil, map[string]string{ + "type": "providerVdc", + "filter": fmt.Sprintf("name==%s", url.QueryEscape(providerVdcName)), + "filterEncoded": "true", + }) + if err != nil { + return nil, err + } + if len(foundProviderVdcs.Results.VMWProviderVdcRecord) == 0 { + return nil, ErrorEntityNotFound + } + if len(foundProviderVdcs.Results.VMWProviderVdcRecord) > 1 { + return nil, fmt.Errorf("more than one Provider VDC found with name '%s'", providerVdcName) + } + return vcdClient.GetProviderVdcByHref(foundProviderVdcs.Results.VMWProviderVdcRecord[0].HREF) +} + +// Refresh updates the contents of the Provider VDC associated to the receiver object. +func (providerVdc *ProviderVdc) Refresh() error { + if providerVdc.ProviderVdc.HREF == "" { + return fmt.Errorf("cannot refresh, receiver object is empty") + } + + unmarshalledVdc := &types.ProviderVdc{} + + _, err := providerVdc.client.ExecuteRequest(providerVdc.ProviderVdc.HREF, http.MethodGet, + "", "error refreshing Provider VDC: %s", nil, unmarshalledVdc) + if err != nil { + return err + } + + providerVdc.ProviderVdc = unmarshalledVdc + + return nil +} diff --git a/govcd/provider_vdc_test.go b/govcd/provider_vdc_test.go index be049da29..103cbe2a8 100644 --- a/govcd/provider_vdc_test.go +++ b/govcd/provider_vdc_test.go @@ -1,18 +1,37 @@ -//go:build pvdc || functional || ALL - -/* - * Copyright 2018 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. - * Copyright 2016 Skyscape Cloud Services. All rights reserved. Licensed under the Apache v2 License. - */ +//go:build providervdc || functional || ALL +// +build providervdc functional ALL package govcd import ( + "fmt" . "gopkg.in/check.v1" ) -func (vcd *TestVCD) Test_ProviderVdc(check *C) { - providerVdc, err := vcd.client.GetProviderVdcById("0f32bce0-62c0-481e-bb71-254b1fd40434") +func init() { + testingTags["providervdc"] = "provider_vdc_test.go" +} + +func (vcd *TestVCD) Test_GetProviderVdc(check *C) { + if vcd.skipAdminTests { + check.Skip(fmt.Sprintf(TestRequiresSysAdminPrivileges, check.TestName())) + } + + var providerVdcs []*ProviderVdc + providerVdc, err := vcd.client.GetProviderVdcByName(vcd.config.VCD.NsxtProviderVdc.Name) check.Assert(err, IsNil) - check.Assert(providerVdc, NotNil) + providerVdcs = append(providerVdcs, providerVdc) + providerVdc, err = vcd.client.GetProviderVdcById(providerVdc.ProviderVdc.ID) + check.Assert(err, IsNil) + providerVdcs = append(providerVdcs, providerVdc) + providerVdc, err = vcd.client.GetProviderVdcByHref(providerVdc.ProviderVdc.HREF) + check.Assert(err, IsNil) + providerVdcs = append(providerVdcs, providerVdc) + + // Common asserts + for _, providerVdc := range providerVdcs { + check.Assert(providerVdc.ProviderVdc.Name, Equals, vcd.config.VCD.NsxtProviderVdc.Name) + check.Assert(providerVdc.ProviderVdc.StorageProfiles.ProviderVdcStorageProfile[0].Name, Equals, vcd.config.VCD.NsxtProviderVdc.StorageProfile) + } + } diff --git a/types/v56/types.go b/types/v56/types.go index ad6a1cbe7..c7e1663bd 100644 --- a/types/v56/types.go +++ b/types/v56/types.go @@ -463,6 +463,11 @@ type AdminVdc struct { UniversalNetworkPoolReference *Reference `xml:"UniversalNetworkPoolReference,omitempty"` // Reference to a universal network pool } +// ProviderVdc represents a Provider VDC. +// Type: ProviderVdcType +// Namespace: http://www.vmware.com/vcloud/v1.5 +// Description: Represents a Provider VDC. +// Since: 0.9 type ProviderVdc struct { Xmlns string `xml:"xmlns,attr"` HREF string `xml:"href,attr,omitempty"` @@ -470,18 +475,18 @@ type ProviderVdc struct { ID string `xml:"id,attr,omitempty"` OperationKey string `xml:"operationKey,attr,omitempty"` Name string `xml:"name,attr"` - Status int `xml:"status,attr,omitempty"` + Status int `xml:"status,attr,omitempty"` // -1 (creation failed), 0 (not ready), 1 (ready), 2 (unknown), 3 (unrecognized) - AvailableNetworks []*AvailableNetworks `xml:"AvailableNetworks,attr,omitempty"` - Capabilities []*Capabilities `xml:"Capabilities,attr,omitempty"` - ComputeCapacity *RootComputeCapacity `xml:"RootComputeCapacity,attr,omitempty"` - Description *string `xml:"Description,attr,omitempty"` - IsEnabled *bool `xml:"IsEnabled,attr,omitempty"` - Link *Link `xml:"Link,attr,omitempty"` - NetworkPoolReferences []*NetworkPoolReferences `xml:"NetworkPoolReferences,attr,omitempty"` - StorageProfiles []*ProviderStorageProfiles `xml:"StorageProfiles,attr,omitempty"` - Tasks *TasksInProgress `xml:"Tasks,attr,omitempty"` - Vdcs []*Vdc `xml:"Vdcs,attr,omitempty"` + AvailableNetworks *AvailableNetworks `xml:"AvailableNetworks,omitempty"` // Read-only list of available networks. + Capabilities *Capabilities `xml:"Capabilities,omitempty"` // Read-only list of virtual hardware versions supported by this Provider vDC. + ComputeCapacity *RootComputeCapacity `xml:"RootComputeCapacity,omitempty"` // Read-only indicator of CPU and memory capacity. + Description string `xml:"Description,omitempty"` // Optional description. + IsEnabled *bool `xml:"IsEnabled,omitempty"` // True if this Provider vDC is enabled and can provide resources to organization vDCs. A Provider vDC is always enabled on creation. + Link *Link `xml:"Link,omitempty"` // A reference to an entity or operation associated with this object. + NetworkPoolReferences *NetworkPoolReferences `xml:"NetworkPoolReferences,omitempty"` // Container for references to vSphere storage profiles available to this Provider vDC. + StorageProfiles *ProviderStorageProfiles `xml:"StorageProfiles,omitempty"` // Read-only list of network pools used by this Provider vDC. + Tasks *TasksInProgress `xml:"Tasks,omitempty"` // A list of queued, running, or recently completed tasks associated with this entity. + Vdcs []*Vdc `xml:"Vdcs,omitempty"` // Read-only list of organization vDCs backed by this Provider vDC. } // RootComputeCapacity represents compute capacity with units. @@ -502,7 +507,7 @@ type RootComputeCapacity struct { // Description: Container for references to network pools in this vDC. // Since: 0.9 type NetworkPoolReferences struct { - NetworkPoolReference *Reference `xml:"NetworkPoolReference"` + NetworkPoolReference []*Reference `xml:"NetworkPoolReference"` } // ProviderVdcStorageProfiles is a container for references to storage profiles associated with a Provider vDC. @@ -511,7 +516,7 @@ type NetworkPoolReferences struct { // Description: Container for references to storage profiles associated with a Provider vDC. // Since: 0.9 type ProviderStorageProfiles struct { - ProviderVdcStorageProfile *Reference `xml:"ProviderVdcStorageProfile"` + ProviderVdcStorageProfile []*Reference `xml:"ProviderVdcStorageProfile"` } // ProviderVdcCapacity represents resource capacity in a Provider vDC. From 532b8f5a6a1e4e8174f5b8d5ccfc1aded1ba4a26 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Fri, 26 Aug 2022 11:36:55 +0200 Subject: [PATCH 05/48] Fixes Signed-off-by: abarreiro --- govcd/api.go | 2 +- govcd/openapi_endpoints.go | 2 +- govcd/vdccomputepolicy.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/govcd/api.go b/govcd/api.go index 3912e0ea0..5fff7d42e 100644 --- a/govcd/api.go +++ b/govcd/api.go @@ -775,7 +775,7 @@ func (client *Client) RemoveProvidedCustomHeaders(values map[string]string) { // Retrieves the administrator URL of a given HREF func getAdminURL(href string) string { - adminApi := "/api/admin" + adminApi := "/api/admin/" if strings.Contains(href, adminApi) { return href } diff --git a/govcd/openapi_endpoints.go b/govcd/openapi_endpoints.go index 6f40e9371..66898f3a5 100644 --- a/govcd/openapi_endpoints.go +++ b/govcd/openapi_endpoints.go @@ -29,7 +29,6 @@ var endpointMinApiVersions = map[string]string{ // OpenApiEndpointExternalNetworks endpoint support was introduced with version 32.0 however it was still not stable // enough to be used. (i.e. it did not support update "PUT") types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointExternalNetworks: "33.0", - types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcComputePolicies: "32.0", types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointSessionCurrent: "34.0", types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointEdgeClusters: "34.0", // VCD 10.1+ types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointEdgeGateways: "34.0", @@ -74,6 +73,7 @@ var endpointMinApiVersions = map[string]string{ types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointEdgeBgpConfig: "35.0", // VCD 10.2+ types.OpenApiPathVersion2_0_0 + types.OpenApiEndpointVdcAssignedComputePolicies: "35.0", + types.OpenApiPathVersion2_0_0 + types.OpenApiEndpointVdcComputePolicies: "35.0", } // elevateNsxtNatRuleApiVersion helps to elevate API version to consume newer NSX-T NAT Rule features diff --git a/govcd/vdccomputepolicy.go b/govcd/vdccomputepolicy.go index 85b0c045c..20c48f4a5 100644 --- a/govcd/vdccomputepolicy.go +++ b/govcd/vdccomputepolicy.go @@ -92,7 +92,7 @@ func (org *Org) GetAllVdcComputePolicies(queryParameters url.Values) ([]*VdcComp // getAllVdcComputePolicies retrieves all VDC compute policies using OpenAPI endpoint. Query parameters can be supplied to perform additional // filtering func getAllVdcComputePolicies(client *Client, queryParameters url.Values) ([]*VdcComputePolicy, error) { - endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcComputePolicies + endpoint := types.OpenApiPathVersion2_0_0 + types.OpenApiEndpointVdcComputePolicies minimumApiVersion, err := client.checkOpenApiEndpointCompatibility(endpoint) if err != nil { return nil, err From e9d2fb3ab4f5618c418bf956a809ca1c09dce3c8 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Fri, 26 Aug 2022 11:37:17 +0200 Subject: [PATCH 06/48] fmt Signed-off-by: abarreiro --- govcd/openapi_endpoints.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/govcd/openapi_endpoints.go b/govcd/openapi_endpoints.go index 66898f3a5..b13e8a74b 100644 --- a/govcd/openapi_endpoints.go +++ b/govcd/openapi_endpoints.go @@ -28,10 +28,10 @@ var endpointMinApiVersions = map[string]string{ types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointImportableTier0Routers: "32.0", // OpenApiEndpointExternalNetworks endpoint support was introduced with version 32.0 however it was still not stable // enough to be used. (i.e. it did not support update "PUT") - types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointExternalNetworks: "33.0", - types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointSessionCurrent: "34.0", - types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointEdgeClusters: "34.0", // VCD 10.1+ - types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointEdgeGateways: "34.0", + types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointExternalNetworks: "33.0", + types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointSessionCurrent: "34.0", + types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointEdgeClusters: "34.0", // VCD 10.1+ + types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointEdgeGateways: "34.0", // Static security groups and IP sets in VCD 10.2, Dynamic security groups in VCD 10.3+ types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointFirewallGroups: "34.0", @@ -73,7 +73,7 @@ var endpointMinApiVersions = map[string]string{ types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointEdgeBgpConfig: "35.0", // VCD 10.2+ types.OpenApiPathVersion2_0_0 + types.OpenApiEndpointVdcAssignedComputePolicies: "35.0", - types.OpenApiPathVersion2_0_0 + types.OpenApiEndpointVdcComputePolicies: "35.0", + types.OpenApiPathVersion2_0_0 + types.OpenApiEndpointVdcComputePolicies: "35.0", } // elevateNsxtNatRuleApiVersion helps to elevate API version to consume newer NSX-T NAT Rule features From d7cf45166e559b87e840b1df8c1aba7a5d64780b Mon Sep 17 00:00:00 2001 From: abarreiro Date: Fri, 26 Aug 2022 13:00:40 +0200 Subject: [PATCH 07/48] Fix Signed-off-by: abarreiro --- govcd/api.go | 9 ++++ govcd/provider_vdc.go | 107 +++++++++++++++++++++++++++++++------ govcd/provider_vdc_test.go | 43 +++++++++++++++ types/v56/types.go | 30 ++++++++++- 4 files changed, 173 insertions(+), 16 deletions(-) diff --git a/govcd/api.go b/govcd/api.go index 5fff7d42e..f664a7305 100644 --- a/govcd/api.go +++ b/govcd/api.go @@ -782,6 +782,15 @@ func getAdminURL(href string) string { return strings.ReplaceAll(href, "/api/", adminApi) } +// Retrieves the administrator URL of a given HREF +func getAdminExtensionURL(href string) string { + adminExtensionApi := "/api/admin/extension/" + if strings.Contains(href, adminExtensionApi) { + return href + } + return strings.ReplaceAll(getAdminURL(href), "/api/admin/", adminExtensionApi) +} + // --------------------------------------------------------------------- // The following functions are needed to avoid strict Coverity warnings // --------------------------------------------------------------------- diff --git a/govcd/provider_vdc.go b/govcd/provider_vdc.go index a301286c5..d9ef944c7 100644 --- a/govcd/provider_vdc.go +++ b/govcd/provider_vdc.go @@ -7,11 +7,18 @@ import ( "net/url" ) +// ProviderVdc is the basic Provider VDC structure, contains the minimum set of attributes. type ProviderVdc struct { ProviderVdc *types.ProviderVdc client *Client } +// ProviderVdcExtended is the extended Provider VDC structure, contains same attributes as ProviderVdc plus some more. +type ProviderVdcExtended struct { + VMWProviderVdc *types.VMWProviderVdc + client *Client +} + func NewProviderVdc(cli *Client) *ProviderVdc { return &ProviderVdc{ ProviderVdc: new(types.ProviderVdc), @@ -19,6 +26,13 @@ func NewProviderVdc(cli *Client) *ProviderVdc { } } +func NewProviderVdcExtended(cli *Client) *ProviderVdcExtended { + return &ProviderVdcExtended{ + VMWProviderVdc: new(types.VMWProviderVdc), + client: cli, + } +} + // GetProviderVdcByHref finds a Provider VDC by its HREF. // On success, returns a pointer to the ProviderVdc structure and a nil error // On failure, returns a nil pointer and an error @@ -34,6 +48,21 @@ func (vcdClient *VCDClient) GetProviderVdcByHref(providerVdcHref string) (*Provi return providerVdc, nil } +// GetProviderVdcExtendedByHref finds a Provider VDC with extended attributes by its HREF. +// On success, returns a pointer to the ProviderVdcExtended structure and a nil error +// On failure, returns a nil pointer and an error +func (vcdClient *VCDClient) GetProviderVdcExtendedByHref(providerVdcHref string) (*ProviderVdcExtended, error) { + providerVdc := NewProviderVdcExtended(&vcdClient.Client) + + _, err := vcdClient.Client.ExecuteRequest(getAdminExtensionURL(providerVdcHref), http.MethodGet, + "", "error retrieving extended Provider VDC: %s", nil, providerVdc.VMWProviderVdc) + if err != nil { + return nil, err + } + + return providerVdc, nil +} + // GetProviderVdcById finds a Provider VDC by URN. // On success, returns a pointer to the ProviderVdc structure and a nil error // On failure, returns a nil pointer and an error @@ -44,25 +73,30 @@ func (vcdClient *VCDClient) GetProviderVdcById(providerVdcId string) (*ProviderV return vcdClient.GetProviderVdcByHref(providerVdcHref.String()) } +// GetProviderVdcExtendedById finds a Provider VDC with extended attributes by URN. +// On success, returns a pointer to the ProviderVdcExtended structure and a nil error +// On failure, returns a nil pointer and an error +func (vcdClient *VCDClient) GetProviderVdcExtendedById(providerVdcId string) (*ProviderVdcExtended, error) { + providerVdcHref := vcdClient.Client.VCDHREF + providerVdcHref.Path += "/admin/extension/providervdc/" + extractUuid(providerVdcId) + + return vcdClient.GetProviderVdcExtendedByHref(providerVdcHref.String()) +} + // GetProviderVdcByName finds a Provider VDC by name. // On success, returns a pointer to the ProviderVdc structure and a nil error // On failure, returns a nil pointer and an error func (vcdClient *VCDClient) GetProviderVdcByName(providerVdcName string) (*ProviderVdc, error) { - foundProviderVdcs, err := vcdClient.QueryWithNotEncodedParams(nil, map[string]string{ - "type": "providerVdc", - "filter": fmt.Sprintf("name==%s", url.QueryEscape(providerVdcName)), - "filterEncoded": "true", - }) - if err != nil { - return nil, err - } - if len(foundProviderVdcs.Results.VMWProviderVdcRecord) == 0 { - return nil, ErrorEntityNotFound - } - if len(foundProviderVdcs.Results.VMWProviderVdcRecord) > 1 { - return nil, fmt.Errorf("more than one Provider VDC found with name '%s'", providerVdcName) - } - return vcdClient.GetProviderVdcByHref(foundProviderVdcs.Results.VMWProviderVdcRecord[0].HREF) + providerVdc, err := getProviderVdcByName(vcdClient, providerVdcName, false) + return providerVdc.(*ProviderVdc), err +} + +// GetProviderVdcExtendedByName finds a Provider VDC with extended attributes by name. +// On success, returns a pointer to the ProviderVdcExtended structure and a nil error +// On failure, returns a nil pointer and an error +func (vcdClient *VCDClient) GetProviderVdcExtendedByName(providerVdcName string) (*ProviderVdcExtended, error) { + providerVdcExtended, err := getProviderVdcByName(vcdClient, providerVdcName, true) + return providerVdcExtended.(*ProviderVdcExtended), err } // Refresh updates the contents of the Provider VDC associated to the receiver object. @@ -83,3 +117,46 @@ func (providerVdc *ProviderVdc) Refresh() error { return nil } + +// Refresh updates the contents of the extended Provider VDC associated to the receiver object. +func (providerVdc *ProviderVdcExtended) Refresh() error { + if providerVdc.VMWProviderVdc.HREF == "" { + return fmt.Errorf("cannot refresh, receiver object is empty") + } + + unmarshalledVdc := &types.VMWProviderVdc{} + + _, err := providerVdc.client.ExecuteRequest(providerVdc.VMWProviderVdc.HREF, http.MethodGet, + "", "error refreshing extended Provider VDC: %s", nil, unmarshalledVdc) + if err != nil { + return err + } + + providerVdc.VMWProviderVdc = unmarshalledVdc + + return nil +} + +// getProviderVdcByName finds a Provider VDC with extension (extended=true) or without extension (extended=false) by name +// On success, returns a pointer to the ProviderVdc (extended=false) or ProviderVdcExtended (extended=true) structure and a nil error +// On failure, returns a nil pointer and an error +func getProviderVdcByName(vcdClient *VCDClient, providerVdcName string, extended bool) (interface{}, error) { + foundProviderVdcs, err := vcdClient.QueryWithNotEncodedParams(nil, map[string]string{ + "type": "providerVdc", + "filter": fmt.Sprintf("name==%s", url.QueryEscape(providerVdcName)), + "filterEncoded": "true", + }) + if err != nil { + return nil, err + } + if len(foundProviderVdcs.Results.VMWProviderVdcRecord) == 0 { + return nil, ErrorEntityNotFound + } + if len(foundProviderVdcs.Results.VMWProviderVdcRecord) > 1 { + return nil, fmt.Errorf("more than one Provider VDC found with name '%s'", providerVdcName) + } + if extended { + return vcdClient.GetProviderVdcExtendedByHref(foundProviderVdcs.Results.VMWProviderVdcRecord[0].HREF) + } + return vcdClient.GetProviderVdcByHref(foundProviderVdcs.Results.VMWProviderVdcRecord[0].HREF) +} diff --git a/govcd/provider_vdc_test.go b/govcd/provider_vdc_test.go index 103cbe2a8..0d9d59961 100644 --- a/govcd/provider_vdc_test.go +++ b/govcd/provider_vdc_test.go @@ -6,6 +6,7 @@ package govcd import ( "fmt" . "gopkg.in/check.v1" + "strings" ) func init() { @@ -32,6 +33,48 @@ func (vcd *TestVCD) Test_GetProviderVdc(check *C) { for _, providerVdc := range providerVdcs { check.Assert(providerVdc.ProviderVdc.Name, Equals, vcd.config.VCD.NsxtProviderVdc.Name) check.Assert(providerVdc.ProviderVdc.StorageProfiles.ProviderVdcStorageProfile[0].Name, Equals, vcd.config.VCD.NsxtProviderVdc.StorageProfile) + check.Assert(*providerVdc.ProviderVdc.IsEnabled, Equals, true) + check.Assert(providerVdc.ProviderVdc.Status, Equals, 1) + check.Assert(len(providerVdc.ProviderVdc.NetworkPoolReferences.NetworkPoolReference), Equals, 1) + check.Assert(providerVdc.ProviderVdc.NetworkPoolReferences.NetworkPoolReference[0].Name, Equals, vcd.config.VCD.NsxtProviderVdc.NetworkPool) + check.Assert(providerVdc.ProviderVdc.Link, NotNil) + } +} + +func (vcd *TestVCD) Test_GetProviderVdcExtended(check *C) { + if vcd.skipAdminTests { + check.Skip(fmt.Sprintf(TestRequiresSysAdminPrivileges, check.TestName())) } + var providerVdcsExtended []*ProviderVdcExtended + providerVdcExtended, err := vcd.client.GetProviderVdcExtendedByName(vcd.config.VCD.NsxtProviderVdc.Name) + check.Assert(err, IsNil) + providerVdcsExtended = append(providerVdcsExtended, providerVdcExtended) + providerVdcExtended, err = vcd.client.GetProviderVdcExtendedById(providerVdcExtended.VMWProviderVdc.ID) + check.Assert(err, IsNil) + providerVdcsExtended = append(providerVdcsExtended, providerVdcExtended) + providerVdcExtended, err = vcd.client.GetProviderVdcExtendedByHref(providerVdcExtended.VMWProviderVdc.HREF) + check.Assert(err, IsNil) + providerVdcsExtended = append(providerVdcsExtended, providerVdcExtended) + + // Common asserts + for _, providerVdcExtended := range providerVdcsExtended { + // Basic PVDC asserts + check.Assert(providerVdcExtended.VMWProviderVdc.Name, Equals, vcd.config.VCD.NsxtProviderVdc.Name) + check.Assert(providerVdcExtended.VMWProviderVdc.StorageProfiles.ProviderVdcStorageProfile[0].Name, Equals, vcd.config.VCD.NsxtProviderVdc.StorageProfile) + check.Assert(*providerVdcExtended.VMWProviderVdc.IsEnabled, Equals, true) + check.Assert(providerVdcExtended.VMWProviderVdc.Status, Equals, 1) + check.Assert(len(providerVdcExtended.VMWProviderVdc.NetworkPoolReferences.NetworkPoolReference), Equals, 1) + check.Assert(providerVdcExtended.VMWProviderVdc.NetworkPoolReferences.NetworkPoolReference[0].Name, Equals, vcd.config.VCD.NsxtProviderVdc.NetworkPool) + check.Assert(providerVdcExtended.VMWProviderVdc.Link, NotNil) + // Extended PVDC asserts + check.Assert(providerVdcExtended.VMWProviderVdc.ComputeProviderScope, Equals, "vc1") + check.Assert(len(providerVdcExtended.VMWProviderVdc.DataStoreRefs.VimObjectRef), Equals, 4) + check.Assert(strings.HasPrefix(providerVdcExtended.VMWProviderVdc.HighestSupportedHardwareVersion, "vmx-"), Equals, true) + check.Assert(providerVdcExtended.VMWProviderVdc.HostReferences, NotNil) + check.Assert(providerVdcExtended.VMWProviderVdc.NsxTManagerReference, NotNil) + check.Assert(providerVdcExtended.VMWProviderVdc.NsxTManagerReference.Name, Equals, vcd.config.VCD.Nsxt.Manager) + check.Assert(providerVdcExtended.VMWProviderVdc.ResourcePoolRefs, NotNil) + check.Assert(providerVdcExtended.VMWProviderVdc.VimServer, NotNil) + } } diff --git a/types/v56/types.go b/types/v56/types.go index c7e1663bd..5172ffaf2 100644 --- a/types/v56/types.go +++ b/types/v56/types.go @@ -489,6 +489,34 @@ type ProviderVdc struct { Vdcs []*Vdc `xml:"Vdcs,omitempty"` // Read-only list of organization vDCs backed by this Provider vDC. } +// VMWProviderVdc represents an extension of ProviderVdc. +// Type: VMWProviderVdcType +// Namespace: http://www.vmware.com/vcloud/v1.5 +// Description: Represents an extension of ProviderVdc. +// Since: 1.0 +type VMWProviderVdc struct { + ProviderVdc + + AvailableUniversalNetworkPool *Reference `xml:"AvailableUniversalNetworkPool,omitempty"` // Selectable universal network reference. + ComputeProviderScope string `xml:"ComputeProviderScope,omitempty"` // The compute provider scope represents the compute fault domain for this provider VDC. This value is a tenant-facing tag that is shown to tenants when viewing fault domains of the child Organization VDCs (for ex. a VDC Group). + DataStoreRefs *VimObjectRefs `xml:"DataStoreRefs,omitempty"` // vSphere datastores backing this provider VDC. + HighestSupportedHardwareVersion string `xml:"HighestSupportedHardwareVersion,omitempty"` // The highest virtual hardware version supported by this Provider VDC. If empty or omitted on creation, the system sets it to the highest virtual hardware version supported by all hosts in the primary resource pool. You can modify it when you add more resource pools. + HostReferences *VMWHostReferences `xml:"HostReferences,omitempty"` // Shows all hosts which are connected to VC server. + NsxTManagerReference *Reference `xml:"NsxTManagerReference,omitempty"` // An optional reference to a registered NSX-T Manager to back networking operations for this provider VDC. + ResourcePoolRefs *VimObjectRefs `xml:"ResourcePoolRefs,omitempty"` // Resource pools backing this provider vDC. On create, you must specify a resource pool that is not used by (and is not the child of a resource pool used by) any other provider VDC. On modify, this element is required for schema validation, but its contents cannot be changed. + VimServer *Reference `xml:"VimServer,omitempty"` // The vCenter server that provides the resource pools and datastores. A valid reference is required on create. On modify, this element is required for schema validation, but its contents cannot be changed. +} + +// VMWHostReferences represents a list of available hosts. +// Type: VMWHostReferencesType +// Namespace: http://www.vmware.com/vcloud/v1.5 +// Description: Represents a list of available hosts. +// Since: 1.0 +type VMWHostReferences struct { + HostReference *Reference `xml:"HostReference,omitempty"` + Link *Link `xml:"Link,omitempty"` +} + // RootComputeCapacity represents compute capacity with units. // Type: RootComputeCapacityType // Namespace: http://www.vmware.com/vcloud/v1.5 @@ -510,7 +538,7 @@ type NetworkPoolReferences struct { NetworkPoolReference []*Reference `xml:"NetworkPoolReference"` } -// ProviderVdcStorageProfiles is a container for references to storage profiles associated with a Provider vDC. +// ProviderStorageProfiles is a container for references to storage profiles associated with a Provider vDC. // Type: ProviderVdcStorageProfilesType // Namespace: http://www.vmware.com/vcloud/v1.5 // Description: Container for references to storage profiles associated with a Provider vDC. From dbee8c5e47de26d2e895c90f4348df07f4ed31d3 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Fri, 26 Aug 2022 13:20:05 +0200 Subject: [PATCH 08/48] Complete pvdc Signed-off-by: abarreiro --- govcd/provider_vdc.go | 28 ++++++++++++++++++++++------ govcd/provider_vdc_test.go | 18 ++++++++++++++++++ 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/govcd/provider_vdc.go b/govcd/provider_vdc.go index d9ef944c7..27b823b5f 100644 --- a/govcd/provider_vdc.go +++ b/govcd/provider_vdc.go @@ -102,7 +102,7 @@ func (vcdClient *VCDClient) GetProviderVdcExtendedByName(providerVdcName string) // Refresh updates the contents of the Provider VDC associated to the receiver object. func (providerVdc *ProviderVdc) Refresh() error { if providerVdc.ProviderVdc.HREF == "" { - return fmt.Errorf("cannot refresh, receiver object is empty") + return fmt.Errorf("cannot refresh, receiver Provider VDC is empty") } unmarshalledVdc := &types.ProviderVdc{} @@ -119,24 +119,40 @@ func (providerVdc *ProviderVdc) Refresh() error { } // Refresh updates the contents of the extended Provider VDC associated to the receiver object. -func (providerVdc *ProviderVdcExtended) Refresh() error { - if providerVdc.VMWProviderVdc.HREF == "" { - return fmt.Errorf("cannot refresh, receiver object is empty") +func (providerVdcExtended *ProviderVdcExtended) Refresh() error { + if providerVdcExtended.VMWProviderVdc.HREF == "" { + return fmt.Errorf("cannot refresh, receiver extended Provider VDC is empty") } unmarshalledVdc := &types.VMWProviderVdc{} - _, err := providerVdc.client.ExecuteRequest(providerVdc.VMWProviderVdc.HREF, http.MethodGet, + _, err := providerVdcExtended.client.ExecuteRequest(providerVdcExtended.VMWProviderVdc.HREF, http.MethodGet, "", "error refreshing extended Provider VDC: %s", nil, unmarshalledVdc) if err != nil { return err } - providerVdc.VMWProviderVdc = unmarshalledVdc + providerVdcExtended.VMWProviderVdc = unmarshalledVdc return nil } +// ToProviderVdc converts the receiver ProviderVdcExtended into the subset ProviderVdc +func (providerVdcExtended *ProviderVdcExtended) ToProviderVdc() (*ProviderVdc, error) { + providerVdcHref := providerVdcExtended.client.VCDHREF + providerVdcHref.Path += "/admin/providervdc/" + extractUuid(providerVdcExtended.VMWProviderVdc.ID) + + providerVdc := NewProviderVdc(providerVdcExtended.client) + + _, err := providerVdcExtended.client.ExecuteRequest(providerVdcHref.String(), http.MethodGet, + "", "error retrieving Provider VDC: %s", nil, providerVdc.ProviderVdc) + if err != nil { + return nil, err + } + + return providerVdc, nil +} + // getProviderVdcByName finds a Provider VDC with extension (extended=true) or without extension (extended=false) by name // On success, returns a pointer to the ProviderVdc (extended=false) or ProviderVdcExtended (extended=true) structure and a nil error // On failure, returns a nil pointer and an error diff --git a/govcd/provider_vdc_test.go b/govcd/provider_vdc_test.go index 0d9d59961..c9a65bc36 100644 --- a/govcd/provider_vdc_test.go +++ b/govcd/provider_vdc_test.go @@ -78,3 +78,21 @@ func (vcd *TestVCD) Test_GetProviderVdcExtended(check *C) { check.Assert(providerVdcExtended.VMWProviderVdc.VimServer, NotNil) } } + +func (vcd *TestVCD) Test_GetProviderVdcConvertFromExtendedToNormal(check *C) { + if vcd.skipAdminTests { + check.Skip(fmt.Sprintf(TestRequiresSysAdminPrivileges, check.TestName())) + } + + providerVdcExtended, err := vcd.client.GetProviderVdcExtendedByName(vcd.config.VCD.NsxtProviderVdc.Name) + check.Assert(err, IsNil) + providerVdc, err := providerVdcExtended.ToProviderVdc() + check.Assert(err, IsNil) + check.Assert(providerVdc.ProviderVdc.Name, Equals, vcd.config.VCD.NsxtProviderVdc.Name) + check.Assert(providerVdc.ProviderVdc.StorageProfiles.ProviderVdcStorageProfile[0].Name, Equals, vcd.config.VCD.NsxtProviderVdc.StorageProfile) + check.Assert(*providerVdc.ProviderVdc.IsEnabled, Equals, true) + check.Assert(providerVdc.ProviderVdc.Status, Equals, 1) + check.Assert(len(providerVdc.ProviderVdc.NetworkPoolReferences.NetworkPoolReference), Equals, 1) + check.Assert(providerVdc.ProviderVdc.NetworkPoolReferences.NetworkPoolReference[0].Name, Equals, vcd.config.VCD.NsxtProviderVdc.NetworkPool) + check.Assert(providerVdc.ProviderVdc.Link, NotNil) +} From 1d315aa204b373c817a6cd57cda28a921bf4e549 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Fri, 26 Aug 2022 14:52:05 +0200 Subject: [PATCH 09/48] Fix bug with capacity Signed-off-by: abarreiro --- govcd/provider_vdc_test.go | 2 ++ types/v56/types.go | 18 +++++++++--------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/govcd/provider_vdc_test.go b/govcd/provider_vdc_test.go index c9a65bc36..2e953368b 100644 --- a/govcd/provider_vdc_test.go +++ b/govcd/provider_vdc_test.go @@ -34,6 +34,7 @@ func (vcd *TestVCD) Test_GetProviderVdc(check *C) { check.Assert(providerVdc.ProviderVdc.Name, Equals, vcd.config.VCD.NsxtProviderVdc.Name) check.Assert(providerVdc.ProviderVdc.StorageProfiles.ProviderVdcStorageProfile[0].Name, Equals, vcd.config.VCD.NsxtProviderVdc.StorageProfile) check.Assert(*providerVdc.ProviderVdc.IsEnabled, Equals, true) + check.Assert(providerVdc.ProviderVdc.ComputeCapacity, NotNil) check.Assert(providerVdc.ProviderVdc.Status, Equals, 1) check.Assert(len(providerVdc.ProviderVdc.NetworkPoolReferences.NetworkPoolReference), Equals, 1) check.Assert(providerVdc.ProviderVdc.NetworkPoolReferences.NetworkPoolReference[0].Name, Equals, vcd.config.VCD.NsxtProviderVdc.NetworkPool) @@ -63,6 +64,7 @@ func (vcd *TestVCD) Test_GetProviderVdcExtended(check *C) { check.Assert(providerVdcExtended.VMWProviderVdc.Name, Equals, vcd.config.VCD.NsxtProviderVdc.Name) check.Assert(providerVdcExtended.VMWProviderVdc.StorageProfiles.ProviderVdcStorageProfile[0].Name, Equals, vcd.config.VCD.NsxtProviderVdc.StorageProfile) check.Assert(*providerVdcExtended.VMWProviderVdc.IsEnabled, Equals, true) + check.Assert(providerVdcExtended.VMWProviderVdc.ComputeCapacity, NotNil) check.Assert(providerVdcExtended.VMWProviderVdc.Status, Equals, 1) check.Assert(len(providerVdcExtended.VMWProviderVdc.NetworkPoolReferences.NetworkPoolReference), Equals, 1) check.Assert(providerVdcExtended.VMWProviderVdc.NetworkPoolReferences.NetworkPoolReference[0].Name, Equals, vcd.config.VCD.NsxtProviderVdc.NetworkPool) diff --git a/types/v56/types.go b/types/v56/types.go index 5172ffaf2..d9e12d1a4 100644 --- a/types/v56/types.go +++ b/types/v56/types.go @@ -478,15 +478,15 @@ type ProviderVdc struct { Status int `xml:"status,attr,omitempty"` // -1 (creation failed), 0 (not ready), 1 (ready), 2 (unknown), 3 (unrecognized) AvailableNetworks *AvailableNetworks `xml:"AvailableNetworks,omitempty"` // Read-only list of available networks. - Capabilities *Capabilities `xml:"Capabilities,omitempty"` // Read-only list of virtual hardware versions supported by this Provider vDC. - ComputeCapacity *RootComputeCapacity `xml:"RootComputeCapacity,omitempty"` // Read-only indicator of CPU and memory capacity. + Capabilities *Capabilities `xml:"Capabilities,omitempty"` // Read-only list of virtual hardware versions supported by this Provider VDC. + ComputeCapacity *RootComputeCapacity `xml:"ComputeCapacity,omitempty"` // Read-only indicator of CPU and memory capacity. Description string `xml:"Description,omitempty"` // Optional description. - IsEnabled *bool `xml:"IsEnabled,omitempty"` // True if this Provider vDC is enabled and can provide resources to organization vDCs. A Provider vDC is always enabled on creation. + IsEnabled *bool `xml:"IsEnabled,omitempty"` // True if this Provider VDC is enabled and can provide resources to organization VDCs. A Provider VDC is always enabled on creation. Link *Link `xml:"Link,omitempty"` // A reference to an entity or operation associated with this object. - NetworkPoolReferences *NetworkPoolReferences `xml:"NetworkPoolReferences,omitempty"` // Container for references to vSphere storage profiles available to this Provider vDC. - StorageProfiles *ProviderStorageProfiles `xml:"StorageProfiles,omitempty"` // Read-only list of network pools used by this Provider vDC. + NetworkPoolReferences *NetworkPoolReferences `xml:"NetworkPoolReferences,omitempty"` // Read-only list of network pools used by this Provider VDC. + StorageProfiles *ProviderStorageProfiles `xml:"StorageProfiles,omitempty"` // Container for references to vSphere storage profiles available to this Provider VDC. Tasks *TasksInProgress `xml:"Tasks,omitempty"` // A list of queued, running, or recently completed tasks associated with this entity. - Vdcs []*Vdc `xml:"Vdcs,omitempty"` // Read-only list of organization vDCs backed by this Provider vDC. + Vdcs []*Vdc `xml:"Vdcs,omitempty"` // Read-only list of organization VDCs backed by this Provider VDC. } // VMWProviderVdc represents an extension of ProviderVdc. @@ -503,7 +503,7 @@ type VMWProviderVdc struct { HighestSupportedHardwareVersion string `xml:"HighestSupportedHardwareVersion,omitempty"` // The highest virtual hardware version supported by this Provider VDC. If empty or omitted on creation, the system sets it to the highest virtual hardware version supported by all hosts in the primary resource pool. You can modify it when you add more resource pools. HostReferences *VMWHostReferences `xml:"HostReferences,omitempty"` // Shows all hosts which are connected to VC server. NsxTManagerReference *Reference `xml:"NsxTManagerReference,omitempty"` // An optional reference to a registered NSX-T Manager to back networking operations for this provider VDC. - ResourcePoolRefs *VimObjectRefs `xml:"ResourcePoolRefs,omitempty"` // Resource pools backing this provider vDC. On create, you must specify a resource pool that is not used by (and is not the child of a resource pool used by) any other provider VDC. On modify, this element is required for schema validation, but its contents cannot be changed. + ResourcePoolRefs *VimObjectRefs `xml:"ResourcePoolRefs,omitempty"` // Resource pools backing this provider VDC. On create, you must specify a resource pool that is not used by (and is not the child of a resource pool used by) any other provider VDC. On modify, this element is required for schema validation, but its contents cannot be changed. VimServer *Reference `xml:"VimServer,omitempty"` // The vCenter server that provides the resource pools and datastores. A valid reference is required on create. On modify, this element is required for schema validation, but its contents cannot be changed. } @@ -513,8 +513,8 @@ type VMWProviderVdc struct { // Description: Represents a list of available hosts. // Since: 1.0 type VMWHostReferences struct { - HostReference *Reference `xml:"HostReference,omitempty"` - Link *Link `xml:"Link,omitempty"` + HostReference []*Reference `xml:"HostReference,omitempty"` + Link *Link `xml:"Link,omitempty"` } // RootComputeCapacity represents compute capacity with units. From f8e46fae709f4bb84267fa2e7dbe1865334ed1cf Mon Sep 17 00:00:00 2001 From: abarreiro Date: Mon, 29 Aug 2022 10:51:03 +0200 Subject: [PATCH 10/48] Revert openapi endpoint removal Signed-off-by: abarreiro --- govcd/openapi_endpoints.go | 12 +++++++----- types/v56/types.go | 12 ++++++------ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/govcd/openapi_endpoints.go b/govcd/openapi_endpoints.go index b13e8a74b..7a75f6283 100644 --- a/govcd/openapi_endpoints.go +++ b/govcd/openapi_endpoints.go @@ -28,10 +28,12 @@ var endpointMinApiVersions = map[string]string{ types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointImportableTier0Routers: "32.0", // OpenApiEndpointExternalNetworks endpoint support was introduced with version 32.0 however it was still not stable // enough to be used. (i.e. it did not support update "PUT") - types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointExternalNetworks: "33.0", - types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointSessionCurrent: "34.0", - types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointEdgeClusters: "34.0", // VCD 10.1+ - types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointEdgeGateways: "34.0", + types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointExternalNetworks: "33.0", + types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcComputePolicies: "32.0", + types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcAssignedComputePolicies: "33.0", + types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointSessionCurrent: "34.0", + types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointEdgeClusters: "34.0", // VCD 10.1+ + types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointEdgeGateways: "34.0", // Static security groups and IP sets in VCD 10.2, Dynamic security groups in VCD 10.3+ types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointFirewallGroups: "34.0", @@ -126,7 +128,7 @@ var endpointElevatedApiVersions = map[string][]string{ func (client *Client) checkOpenApiEndpointCompatibility(endpoint string) (string, error) { minimumApiVersion, ok := endpointMinApiVersions[endpoint] if !ok { - return "", fmt.Errorf("minimum API version for endopoint '%s' is not defined", endpoint) + return "", fmt.Errorf("minimum API version for endpoint '%s' is not defined", endpoint) } if client.APIVCDMaxVersionIs("< " + minimumApiVersion) { diff --git a/types/v56/types.go b/types/v56/types.go index d9e12d1a4..3f106915e 100644 --- a/types/v56/types.go +++ b/types/v56/types.go @@ -524,8 +524,8 @@ type VMWHostReferences struct { // Since: 0.9 type RootComputeCapacity struct { Cpu *ProviderVdcCapacity `xml:"Cpu"` - IsElastic *bool `xml:"IsElastic,omitempty"` - IsHA *bool `xml:"IsHA,omitempty"` + IsElastic bool `xml:"IsElastic,omitempty"` + IsHA bool `xml:"IsHA,omitempty"` Memory *ProviderVdcCapacity `xml:"Memory"` } @@ -553,12 +553,12 @@ type ProviderStorageProfiles struct { // Description: Represents resource capacity in a Provider vDC. // Since: 0.9 type ProviderVdcCapacity struct { - Allocation *int64 `xml:"Allocation,omitempty"` - Overhead *int64 `xml:"Overhead,omitempty"` - Reserved *int64 `xml:"Reserved,omitempty"` + Allocation int64 `xml:"Allocation,omitempty"` + Overhead int64 `xml:"Overhead,omitempty"` + Reserved int64 `xml:"Reserved,omitempty"` Total int64 `xml:"Total"` Units string `xml:"Units"` - Used *int64 `xml:"Used,omitempty"` + Used int64 `xml:"Used,omitempty"` } // VdcStorageProfileConfiguration represents the parameters to assign a storage profile in creation of organization vDC. From 3a8b73b4a548ade26acc4ac1faca8e7011ae3410 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Mon, 29 Aug 2022 11:06:04 +0200 Subject: [PATCH 11/48] Changelog Signed-off-by: abarreiro --- .changes/v2.17.0/502-features.md | 4 ++++ .changes/v2.17.0/502-improvements.md | 2 ++ govcd/api.go | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 .changes/v2.17.0/502-features.md diff --git a/.changes/v2.17.0/502-features.md b/.changes/v2.17.0/502-features.md new file mode 100644 index 000000000..893ce66c2 --- /dev/null +++ b/.changes/v2.17.0/502-features.md @@ -0,0 +1,4 @@ +* Added new methods `VCDClient.GetProviderVdcByHref`, `VCDClient.GetProviderVdcById`, `VCDClient.GetProviderVdcByName` and `ProviderVdc.Refresh` to retrieve Provider VDCs [GH-502] +* Added new methods `VCDClient.GetProviderVdcExtendedByHref`, `VCDClient.GetProviderVdcExtendedById` and `VCDClient.GetProviderVdcExtendedByName` to retrieve the extended flavor of Provider VDCs [GH-502] +* Added new methods `ProviderVdcExtended.ToProviderVdc`, to convert from an extended Provider VDC to a regular one [GH-502] +* Added new methods `ProviderVdc.GetMetadata`, `ProviderVdc.AddMetadataEntry`, `ProviderVdc.AddMetadataEntryAsync`, `ProviderVdc.MergeMetadataAsync`, `ProviderVdc.MergeMetadata`, `ProviderVdc.DeleteMetadataEntry` and `ProviderVdc.DeleteMetadataEntryAsync` to manage Provider VDCs metadata [GH-502] diff --git a/.changes/v2.17.0/502-improvements.md b/.changes/v2.17.0/502-improvements.md index e69de29bb..0b5236787 100644 --- a/.changes/v2.17.0/502-improvements.md +++ b/.changes/v2.17.0/502-improvements.md @@ -0,0 +1,2 @@ +* Updated VDC Compute Policies retrieval methods `AdminVdc.GetAllAssignedVdcComputePolicies` and `Org.GetAllVdcComputePolicies` + from OpenAPI v1.0.0 to v2.0.0, this version supports more filtering options like `isVgpuPolicy`[GH-502] diff --git a/govcd/api.go b/govcd/api.go index f664a7305..f11cac57c 100644 --- a/govcd/api.go +++ b/govcd/api.go @@ -782,7 +782,7 @@ func getAdminURL(href string) string { return strings.ReplaceAll(href, "/api/", adminApi) } -// Retrieves the administrator URL of a given HREF +// Retrieves the admin extension URL of a given HREF func getAdminExtensionURL(href string) string { adminExtensionApi := "/api/admin/extension/" if strings.Contains(href, adminExtensionApi) { From 537f89ec33b3aff4d52d6c440a352b6abd2a1484 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Mon, 29 Aug 2022 11:08:17 +0200 Subject: [PATCH 12/48] Changelog Signed-off-by: abarreiro --- .changes/v2.17.0/502-features.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changes/v2.17.0/502-features.md b/.changes/v2.17.0/502-features.md index 893ce66c2..40e0c9bde 100644 --- a/.changes/v2.17.0/502-features.md +++ b/.changes/v2.17.0/502-features.md @@ -1,4 +1,4 @@ * Added new methods `VCDClient.GetProviderVdcByHref`, `VCDClient.GetProviderVdcById`, `VCDClient.GetProviderVdcByName` and `ProviderVdc.Refresh` to retrieve Provider VDCs [GH-502] -* Added new methods `VCDClient.GetProviderVdcExtendedByHref`, `VCDClient.GetProviderVdcExtendedById` and `VCDClient.GetProviderVdcExtendedByName` to retrieve the extended flavor of Provider VDCs [GH-502] +* Added new methods `VCDClient.GetProviderVdcExtendedByHref`, `VCDClient.GetProviderVdcExtendedById`, `VCDClient.GetProviderVdcExtendedByName` and `ProviderVdcExtended.Refresh` to retrieve the extended flavor of Provider VDCs [GH-502] * Added new methods `ProviderVdcExtended.ToProviderVdc`, to convert from an extended Provider VDC to a regular one [GH-502] * Added new methods `ProviderVdc.GetMetadata`, `ProviderVdc.AddMetadataEntry`, `ProviderVdc.AddMetadataEntryAsync`, `ProviderVdc.MergeMetadataAsync`, `ProviderVdc.MergeMetadata`, `ProviderVdc.DeleteMetadataEntry` and `ProviderVdc.DeleteMetadataEntryAsync` to manage Provider VDCs metadata [GH-502] From 960437d3a4edf739cb5161a8e5d9b7d2dda18340 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Mon, 29 Aug 2022 11:20:36 +0200 Subject: [PATCH 13/48] Fix test tags Signed-off-by: abarreiro --- govcd/common_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/govcd/common_test.go b/govcd/common_test.go index c6fda76d6..51f7b0f23 100644 --- a/govcd/common_test.go +++ b/govcd/common_test.go @@ -1,5 +1,5 @@ -//go:build api || auth || functional || catalog || vapp || gateway || network || org || query || extnetwork || task || vm || vdc || system || disk || lb || lbAppRule || lbAppProfile || lbServerPool || lbServiceMonitor || lbVirtualServer || user || role || nsxv || nsxt || openapi || affinity || search || alb || certificate || vdcGroup || metadata || ALL -// +build api auth functional catalog vapp gateway network org query extnetwork task vm vdc system disk lb lbAppRule lbAppProfile lbServerPool lbServiceMonitor lbVirtualServer user role nsxv nsxt openapi affinity search alb certificate vdcGroup metadata ALL +//go:build api || auth || functional || catalog || vapp || gateway || network || org || query || extnetwork || task || vm || vdc || system || disk || lb || lbAppRule || lbAppProfile || lbServerPool || lbServiceMonitor || lbVirtualServer || user || role || nsxv || nsxt || openapi || affinity || search || alb || certificate || vdcGroup || metadata || providervdc || ALL +// +build api auth functional catalog vapp gateway network org query extnetwork task vm vdc system disk lb lbAppRule lbAppProfile lbServerPool lbServiceMonitor lbVirtualServer user role nsxv nsxt openapi affinity search alb certificate vdcGroup metadata providervdc ALL /* * Copyright 2021 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. From 1982f987a66321a0dc4774db280d83ebc19d64a8 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Mon, 29 Aug 2022 14:43:02 +0200 Subject: [PATCH 14/48] Make constructors private Signed-off-by: abarreiro --- govcd/provider_vdc.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/govcd/provider_vdc.go b/govcd/provider_vdc.go index 27b823b5f..e191dddba 100644 --- a/govcd/provider_vdc.go +++ b/govcd/provider_vdc.go @@ -19,14 +19,14 @@ type ProviderVdcExtended struct { client *Client } -func NewProviderVdc(cli *Client) *ProviderVdc { +func newProviderVdc(cli *Client) *ProviderVdc { return &ProviderVdc{ ProviderVdc: new(types.ProviderVdc), client: cli, } } -func NewProviderVdcExtended(cli *Client) *ProviderVdcExtended { +func newProviderVdcExtended(cli *Client) *ProviderVdcExtended { return &ProviderVdcExtended{ VMWProviderVdc: new(types.VMWProviderVdc), client: cli, @@ -37,7 +37,7 @@ func NewProviderVdcExtended(cli *Client) *ProviderVdcExtended { // On success, returns a pointer to the ProviderVdc structure and a nil error // On failure, returns a nil pointer and an error func (vcdClient *VCDClient) GetProviderVdcByHref(providerVdcHref string) (*ProviderVdc, error) { - providerVdc := NewProviderVdc(&vcdClient.Client) + providerVdc := newProviderVdc(&vcdClient.Client) _, err := vcdClient.Client.ExecuteRequest(providerVdcHref, http.MethodGet, "", "error retrieving Provider VDC: %s", nil, providerVdc.ProviderVdc) @@ -52,7 +52,7 @@ func (vcdClient *VCDClient) GetProviderVdcByHref(providerVdcHref string) (*Provi // On success, returns a pointer to the ProviderVdcExtended structure and a nil error // On failure, returns a nil pointer and an error func (vcdClient *VCDClient) GetProviderVdcExtendedByHref(providerVdcHref string) (*ProviderVdcExtended, error) { - providerVdc := NewProviderVdcExtended(&vcdClient.Client) + providerVdc := newProviderVdcExtended(&vcdClient.Client) _, err := vcdClient.Client.ExecuteRequest(getAdminExtensionURL(providerVdcHref), http.MethodGet, "", "error retrieving extended Provider VDC: %s", nil, providerVdc.VMWProviderVdc) @@ -142,7 +142,7 @@ func (providerVdcExtended *ProviderVdcExtended) ToProviderVdc() (*ProviderVdc, e providerVdcHref := providerVdcExtended.client.VCDHREF providerVdcHref.Path += "/admin/providervdc/" + extractUuid(providerVdcExtended.VMWProviderVdc.ID) - providerVdc := NewProviderVdc(providerVdcExtended.client) + providerVdc := newProviderVdc(providerVdcExtended.client) _, err := providerVdcExtended.client.ExecuteRequest(providerVdcHref.String(), http.MethodGet, "", "error retrieving Provider VDC: %s", nil, providerVdc.ProviderVdc) From e8dd6c87ce7ad2e65a90a13f89a51536c18c5d96 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Mon, 29 Aug 2022 14:53:11 +0200 Subject: [PATCH 15/48] Added omitempty to Total in ProviderVdcCapacity Signed-off-by: abarreiro --- types/v56/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/v56/types.go b/types/v56/types.go index 37dc44c96..7e5fdce6c 100644 --- a/types/v56/types.go +++ b/types/v56/types.go @@ -559,7 +559,7 @@ type ProviderVdcCapacity struct { Allocation int64 `xml:"Allocation,omitempty"` Overhead int64 `xml:"Overhead,omitempty"` Reserved int64 `xml:"Reserved,omitempty"` - Total int64 `xml:"Total"` + Total int64 `xml:"Total,omitempty"` Units string `xml:"Units"` Used int64 `xml:"Used,omitempty"` } From 364b2780f23353f0accda95389e39a2c134dc931 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Mon, 29 Aug 2022 15:25:55 +0200 Subject: [PATCH 16/48] Remove Vdcs from struct Signed-off-by: abarreiro --- types/v56/types.go | 1 - 1 file changed, 1 deletion(-) diff --git a/types/v56/types.go b/types/v56/types.go index 7e5fdce6c..e050c7867 100644 --- a/types/v56/types.go +++ b/types/v56/types.go @@ -489,7 +489,6 @@ type ProviderVdc struct { NetworkPoolReferences *NetworkPoolReferences `xml:"NetworkPoolReferences,omitempty"` // Read-only list of network pools used by this Provider VDC. StorageProfiles *ProviderStorageProfiles `xml:"StorageProfiles,omitempty"` // Container for references to vSphere storage profiles available to this Provider VDC. Tasks *TasksInProgress `xml:"Tasks,omitempty"` // A list of queued, running, or recently completed tasks associated with this entity. - Vdcs []*Vdc `xml:"Vdcs,omitempty"` // Read-only list of organization VDCs backed by this Provider VDC. } // VMWProviderVdc represents an extension of ProviderVdc. From 54d8de64a1d4b2b7b8c5be0036e564835bde4d4b Mon Sep 17 00:00:00 2001 From: abarreiro Date: Tue, 30 Aug 2022 16:11:42 +0200 Subject: [PATCH 17/48] Add VM Logical Groups support Signed-off-by: abarreiro --- govcd/api_vcd_test.go | 1 + govcd/openapi_endpoints.go | 1 + govcd/vm_groups.go | 129 +++++++++++++++++++++++++++++++++++++ govcd/vm_groups_test.go | 62 ++++++++++++++++++ types/v56/constants.go | 1 + types/v56/openapi.go | 27 ++++---- types/v56/types.go | 12 ++++ 7 files changed, 221 insertions(+), 12 deletions(-) create mode 100644 govcd/vm_groups.go create mode 100644 govcd/vm_groups_test.go diff --git a/govcd/api_vcd_test.go b/govcd/api_vcd_test.go index 703d634f6..2cb4c6f39 100644 --- a/govcd/api_vcd_test.go +++ b/govcd/api_vcd_test.go @@ -154,6 +154,7 @@ type TestConfig struct { SP1 string `yaml:"storageProfile1"` SP2 string `yaml:"storageProfile2,omitempty"` } `yaml:"storageProfile"` + PlacementPolicy string `yaml:"placementPolicy,omitempty"` ExternalIp string `yaml:"externalIp,omitempty"` ExternalNetmask string `yaml:"externalNetmask,omitempty"` InternalIp string `yaml:"internalIp,omitempty"` diff --git a/govcd/openapi_endpoints.go b/govcd/openapi_endpoints.go index 7c8745e8e..9e0d61292 100644 --- a/govcd/openapi_endpoints.go +++ b/govcd/openapi_endpoints.go @@ -53,6 +53,7 @@ var endpointMinApiVersions = map[string]string{ types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcGroupsDfwDefaultPolicies: "35.0", // VCD 10.2+ types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointSecurityTags: "36.0", // VCD 10.3+ types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointNsxtRouteAdvertisement: "34.0", // VCD 10.1+ + types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointLogicalVmGroups: "35.0", // VCD 10.2+ // NSX-T ALB (Advanced/AVI Load Balancer) support was introduced in 10.2 types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointAlbController: "35.0", // VCD 10.2+ diff --git a/govcd/vm_groups.go b/govcd/vm_groups.go new file mode 100644 index 000000000..53b6b97c1 --- /dev/null +++ b/govcd/vm_groups.go @@ -0,0 +1,129 @@ +package govcd + +import ( + "fmt" + "github.com/vmware/go-vcloud-director/v2/types/v56" + "net/url" +) + +// LogicalVmGroup is used to create VM Placement Policies. +type LogicalVmGroup struct { + LogicalVmGroup *types.LogicalVmGroup + client *Client +} + +// VmGroup is used to create VM Placement Policies. +type VmGroup struct { + VmGroup *types.QueryResultVmGroupsRecordType + client *Client +} + +// GetVmGroupByNamedVmGroupId finds a VM Group by its URN. +// On success, returns a pointer to the VmGroup structure and a nil error +// On failure, returns a nil pointer and an error +func (vcdClient *VCDClient) GetVmGroupByNamedVmGroupId(namedVmGroupId string) (*VmGroup, error) { + foundVmGroups, err := vcdClient.QueryWithNotEncodedParams(nil, map[string]string{ + "type": "vmGroups", + "filter": fmt.Sprintf("namedVmGroupId==%s", url.QueryEscape(extractUuid(namedVmGroupId))), + "filterEncoded": "true", + }) + if err != nil { + return nil, err + } + if len(foundVmGroups.Results.VmGroupsRecord) == 0 { + return nil, ErrorEntityNotFound + } + if len(foundVmGroups.Results.VmGroupsRecord) > 1 { + return nil, fmt.Errorf("more than one VM Group found with Named VM Group ID '%s'", namedVmGroupId) + } + vmGroup := &VmGroup{ + VmGroup: foundVmGroups.Results.VmGroupsRecord[0], + client: &vcdClient.Client, + } + return vmGroup, nil +} + +// GetLogicalVmGroupById finds a Logical VM Group by its URN. +// On success, returns a pointer to the LogicalVmGroup structure and a nil error +// On failure, returns a nil pointer and an error +func (vcdClient *VCDClient) GetLogicalVmGroupById(logicalVmGroupId string) (*LogicalVmGroup, error) { + endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointLogicalVmGroups + + apiVersion, err := vcdClient.Client.getOpenApiHighestElevatedVersion(endpoint) + if err != nil { + return nil, err + } + + if logicalVmGroupId == "" { + return nil, fmt.Errorf("empty Logical VM Group id") + } + + urlRef, err := vcdClient.Client.OpenApiBuildEndpoint(endpoint, logicalVmGroupId) + if err != nil { + return nil, err + } + + result := &LogicalVmGroup{ + LogicalVmGroup: &types.LogicalVmGroup{}, + client: &vcdClient.Client, + } + + err = vcdClient.Client.OpenApiGetItem(apiVersion, urlRef, nil, result.LogicalVmGroup, nil) + if err != nil { + return nil, fmt.Errorf("error getting Logical VM Group: %s", err) + } + + return result, nil +} + +// CreateLogicalVmGroup creates a new Logical VM Group in VCD +func (vcdClient *VCDClient) CreateLogicalVmGroup(logicalVmGroup types.LogicalVmGroup) (*LogicalVmGroup, error) { + endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointLogicalVmGroups + + apiVersion, err := vcdClient.Client.getOpenApiHighestElevatedVersion(endpoint) + if err != nil { + return nil, err + } + + urlRef, err := vcdClient.Client.OpenApiBuildEndpoint(endpoint) + if err != nil { + return nil, err + } + + result := &LogicalVmGroup{ + LogicalVmGroup: &types.LogicalVmGroup{}, + client: &vcdClient.Client, + } + + err = vcdClient.Client.OpenApiPostItem(apiVersion, urlRef, nil, logicalVmGroup, result.LogicalVmGroup, nil) + if err != nil { + return nil, fmt.Errorf("error creating the Logical VM Group: %s", err) + } + + return result, nil +} + +// Delete deletes the receiver Logical VM Group +func (logicalVmGroup *LogicalVmGroup) Delete() error { + if logicalVmGroup.LogicalVmGroup.ID == "" { + return fmt.Errorf("cannot delete Logical VM Group without id") + } + + endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointLogicalVmGroups + + apiVersion, err := logicalVmGroup.client.getOpenApiHighestElevatedVersion(endpoint) + if err != nil { + return err + } + + urlRef, err := logicalVmGroup.client.OpenApiBuildEndpoint(endpoint, logicalVmGroup.LogicalVmGroup.ID) + if err != nil { + return err + } + + err = logicalVmGroup.client.OpenApiDeleteItem(apiVersion, urlRef, nil, nil) + if err != nil { + return fmt.Errorf("error deleting the Logical VM Group: %s", err) + } + return nil +} diff --git a/govcd/vm_groups_test.go b/govcd/vm_groups_test.go new file mode 100644 index 000000000..e2e01b4a9 --- /dev/null +++ b/govcd/vm_groups_test.go @@ -0,0 +1,62 @@ +//go:build functional || openapi || ALL +// +build functional openapi ALL + +/* + * Copyright 2022 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. + */ + +package govcd + +import ( + "fmt" + "net/url" + + "github.com/vmware/go-vcloud-director/v2/types/v56" + . "gopkg.in/check.v1" +) + +// TODO: Add VM Placement Policy name in vcd.config.VCD.PlacementPolicy +// This test retrieves a VM Placement Policy to check the behaviour of VM Groups and Logical VM Groups. +// With the information of this VM Placement Policy we test the read logic, then we create a Logical VM Group and +// finally we delete it. +func (vcd *TestVCD) Test_VmGroupsCRUD(check *C) { + if vcd.skipAdminTests { + check.Skip(fmt.Sprintf(TestRequiresSysAdminPrivileges, check.TestName())) + } + + computePolicies, err := vcd.client.Client.GetAllVdcComputePolicies(url.Values{ + "filter": []string{fmt.Sprintf("name==%s;policyType==VdcVmPolicy", vcd.config.VCD.PlacementPolicy)}, + }) + check.Assert(err, IsNil) + check.Assert(len(computePolicies), Equals, 1) + computePolicy := computePolicies[0] + check.Assert(len(computePolicy.VdcComputePolicy.NamedVMGroups), Not(Equals), 0) + check.Assert(len(computePolicy.VdcComputePolicy.NamedVMGroups[0]), Not(Equals), 0) + + vmGroup, err := vcd.client.GetVmGroupByNamedVmGroupId(computePolicy.VdcComputePolicy.NamedVMGroups[0][0].ID) + check.Assert(err, IsNil) + check.Assert(vmGroup.VmGroup.NamedVmGroupId, Equals, extractUuid(computePolicy.VdcComputePolicy.NamedVMGroups[0][0].ID)) + check.Assert(vmGroup.VmGroup.Name, Equals, computePolicy.VdcComputePolicy.NamedVMGroups[0][0].Name) + + pVdc, err := vcd.client.GetProviderVdcByName(vcd.config.VCD.NsxtProviderVdc.Name) + check.Assert(err, IsNil) + + logicalVmGroup, err := vcd.client.CreateLogicalVmGroup(types.LogicalVmGroup{ + Name: check.TestName(), + NamedVmGroupReferences: types.OpenApiReferences{ + types.OpenApiReference{ + ID: computePolicy.VdcComputePolicy.NamedVMGroups[0][0].ID, + Name: vmGroup.VmGroup.Name}, + }, + PvdcID: pVdc.ProviderVdc.ID, + }) + check.Assert(err, IsNil) + AddToCleanupList(logicalVmGroup.LogicalVmGroup.ID, "logicalVmGroup", "", check.TestName()) + + retrievedLogicalVmGroup, err := vcd.client.GetLogicalVmGroupById(logicalVmGroup.LogicalVmGroup.ID) + check.Assert(err, IsNil) + check.Assert(retrievedLogicalVmGroup.LogicalVmGroup, DeepEquals, logicalVmGroup.LogicalVmGroup) + + err = logicalVmGroup.Delete() + check.Assert(err, IsNil) +} diff --git a/types/v56/constants.go b/types/v56/constants.go index 67031b7ac..ddc4699ef 100644 --- a/types/v56/constants.go +++ b/types/v56/constants.go @@ -374,6 +374,7 @@ const ( OpenApiEndpointVdcGroupsDfwPolicies = "vdcGroups/%s/dfwPolicies" OpenApiEndpointVdcGroupsDfwDefaultPolicies = "vdcGroups/%s/dfwPolicies/default" OpenApiEndpointVdcGroupsDfwRules = "vdcGroups/%s/dfwPolicies/%s/rules" + OpenApiEndpointLogicalVmGroups = "logicalVmGroups/" OpenApiEndpointNetworkContextProfiles = "networkContextProfiles" OpenApiEndpointSecurityTags = "securityTags" OpenApiEndpointNsxtRouteAdvertisement = "edgeGateways/%s/routing/advertisement" diff --git a/types/v56/openapi.go b/types/v56/openapi.go index bbd6c30c8..ac9c683dc 100644 --- a/types/v56/openapi.go +++ b/types/v56/openapi.go @@ -183,18 +183,12 @@ type VdcComputePolicy struct { Name string `json:"name,omitempty"` ID string `json:"id,omitempty"` } `json:"pvdcComputePolicy,omitempty"` - CompatibleVdcTypes []string `json:"compatibleVdcTypes,omitempty"` - IsSizingOnly bool `json:"isSizingOnly,omitempty"` - PvdcID string `json:"pvdcId,omitempty"` - NamedVMGroups [][]struct { - Name string `json:"name,omitempty"` - ID string `json:"id,omitempty"` - } `json:"namedVmGroups,omitempty"` - LogicalVMGroupReferences []struct { - Name string `json:"name,omitempty"` - ID string `json:"id,omitempty"` - } `json:"logicalVmGroupReferences,omitempty"` - IsAutoGenerated bool `json:"isAutoGenerated,omitempty"` + CompatibleVdcTypes []string `json:"compatibleVdcTypes,omitempty"` + IsSizingOnly bool `json:"isSizingOnly,omitempty"` + PvdcID string `json:"pvdcId,omitempty"` + NamedVMGroups []OpenApiReferences `json:"namedVmGroups,omitempty"` + LogicalVMGroupReferences []OpenApiReference `json:"logicalVmGroupReferences,omitempty"` + IsAutoGenerated bool `json:"isAutoGenerated,omitempty"` } // OpenApiReference is a generic reference type commonly used throughout OpenAPI endpoints @@ -404,3 +398,12 @@ type ProbeResult struct { CertificateChain string `json:"certificateChain,omitempty"` // The SSL certificate chain presented by the server if a secure connection was made. AdditionalCAIssuers []string `json:"additionalCAIssuers,omitempty"` // URLs supplied by Certificate Authorities to retrieve signing certificates, when those certificates are not included in the chain. } + +// LogicalVmGroup is used to create VM Placement Policies in VCD. +type LogicalVmGroup struct { + Name string `json:"name,omitempty"` // Display name + Description string `json:"description,omitempty"` + ID string `json:"id,omitempty"` // UUID for LogicalVmGroup. This is immutable + NamedVmGroupReferences OpenApiReferences `json:"namedVmGroupReferences,omitempty"` // List of named vm groups associated with LogicalVmGroup. + PvdcID string `json:"pvdcId,omitempty"` // URN for Provider VDC +} diff --git a/types/v56/types.go b/types/v56/types.go index e050c7867..093fba821 100644 --- a/types/v56/types.go +++ b/types/v56/types.go @@ -2312,6 +2312,18 @@ type QueryResultRecordsType struct { NsxtManagerRecord []*QueryResultNsxtManagerRecordType `xml:"NsxTManagerRecord"` // A record representing NSX-T manager OrgVdcRecord []*QueryResultOrgVdcRecordType `xml:"OrgVdcRecord"` // A record representing Org VDC OrgVdcAdminRecord []*QueryResultOrgVdcRecordType `xml:"AdminVdcRecord"` // A record representing Org VDC + VmGroupsRecord []*QueryResultVmGroupsRecordType `xml:"VmGroupsRecord"` +} + +// QueryResultVmGroupsRecordType represent a VM Groups record +type QueryResultVmGroupsRecordType struct { + HREF string `xml:"href,attr,omitempty"` + ID string `xml:"vmGroupId,attr,omitempty"` + Name string `xml:"vmGroupName,attr,omitempty"` + ClusterMoref string `xml:"clusterMoref,attr,omitempty"` + ClusterName string `xml:"clusterName,attr,omitempty"` + VcenterId string `xml:"vcId,attr,omitempty"` + NamedVmGroupId string `xml:"namedVmGroupId,attr,omitempty"` } // QueryResultOrgVdcRecordType represents an Org VDC record From 62fe36136419208b0199534be4366c60b0841d85 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Tue, 30 Aug 2022 16:15:11 +0200 Subject: [PATCH 18/48] Add changelog Signed-off-by: abarreiro --- .changes/v2.17.0/504-features.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .changes/v2.17.0/504-features.md diff --git a/.changes/v2.17.0/504-features.md b/.changes/v2.17.0/504-features.md new file mode 100644 index 000000000..6a95c5a58 --- /dev/null +++ b/.changes/v2.17.0/504-features.md @@ -0,0 +1,2 @@ +* Added a new method `VCDClient.GetVmGroupByNamedVmGroupId` to retrieve VM Groups by Named VM Group ID. This is useful to create VM Placement Policies [GH-504] +* Added new methods `VCDClient.GetLogicalVmGroupById`, `VCDClient.CreateLogicalVmGroup`, `LogicalVmGroup.Delete` to manage Logical VM Groups. These are useful to create VM Placement Policies [GH-504] From a0c2de031aff77272e54f3c8bed92f18797caa2d Mon Sep 17 00:00:00 2001 From: abarreiro Date: Wed, 31 Aug 2022 11:54:37 +0200 Subject: [PATCH 19/48] Fix tests Signed-off-by: abarreiro --- govcd/api_vcd_test.go | 2 +- govcd/vm_groups.go | 52 ++++++++++++++++++++++++++--------------- govcd/vm_groups_test.go | 28 +++++++++------------- 3 files changed, 45 insertions(+), 37 deletions(-) diff --git a/govcd/api_vcd_test.go b/govcd/api_vcd_test.go index 2cb4c6f39..985989154 100644 --- a/govcd/api_vcd_test.go +++ b/govcd/api_vcd_test.go @@ -154,7 +154,7 @@ type TestConfig struct { SP1 string `yaml:"storageProfile1"` SP2 string `yaml:"storageProfile2,omitempty"` } `yaml:"storageProfile"` - PlacementPolicy string `yaml:"placementPolicy,omitempty"` + PlacementPolicyVmGroup string `yaml:"placementPolicyVmGroup,omitempty"` ExternalIp string `yaml:"externalIp,omitempty"` ExternalNetmask string `yaml:"externalNetmask,omitempty"` InternalIp string `yaml:"internalIp,omitempty"` diff --git a/govcd/vm_groups.go b/govcd/vm_groups.go index 53b6b97c1..774e6db19 100644 --- a/govcd/vm_groups.go +++ b/govcd/vm_groups.go @@ -22,25 +22,14 @@ type VmGroup struct { // On success, returns a pointer to the VmGroup structure and a nil error // On failure, returns a nil pointer and an error func (vcdClient *VCDClient) GetVmGroupByNamedVmGroupId(namedVmGroupId string) (*VmGroup, error) { - foundVmGroups, err := vcdClient.QueryWithNotEncodedParams(nil, map[string]string{ - "type": "vmGroups", - "filter": fmt.Sprintf("namedVmGroupId==%s", url.QueryEscape(extractUuid(namedVmGroupId))), - "filterEncoded": "true", - }) - if err != nil { - return nil, err - } - if len(foundVmGroups.Results.VmGroupsRecord) == 0 { - return nil, ErrorEntityNotFound - } - if len(foundVmGroups.Results.VmGroupsRecord) > 1 { - return nil, fmt.Errorf("more than one VM Group found with Named VM Group ID '%s'", namedVmGroupId) - } - vmGroup := &VmGroup{ - VmGroup: foundVmGroups.Results.VmGroupsRecord[0], - client: &vcdClient.Client, - } - return vmGroup, nil + return getVmGroupByFilterField(vcdClient, "namedVmGroupId", extractUuid(namedVmGroupId)) +} + +// GetVmGroupByName finds a VM Group by its name. +// On success, returns a pointer to the VmGroup structure and a nil error +// On failure, returns a nil pointer and an error +func (vcdClient *VCDClient) GetVmGroupByName(vmGroupName string) (*VmGroup, error) { + return getVmGroupByFilterField(vcdClient, "vmGroupName", vmGroupName) } // GetLogicalVmGroupById finds a Logical VM Group by its URN. @@ -127,3 +116,28 @@ func (logicalVmGroup *LogicalVmGroup) Delete() error { } return nil } + +// getVmGroupByFilterField finds a VM Group by specifying a filter=(filterKey==filterValue). +// On success, returns a pointer to the VmGroup structure and a nil error +// On failure, returns a nil pointer and an error +func getVmGroupByFilterField(vcdClient *VCDClient, filterKey, filterValue string) (*VmGroup, error) { + foundVmGroups, err := vcdClient.QueryWithNotEncodedParams(nil, map[string]string{ + "type": "vmGroups", + "filter": fmt.Sprintf("%s==%s", url.QueryEscape(filterKey), url.QueryEscape(filterValue)), + "filterEncoded": "true", + }) + if err != nil { + return nil, err + } + if len(foundVmGroups.Results.VmGroupsRecord) == 0 { + return nil, ErrorEntityNotFound + } + if len(foundVmGroups.Results.VmGroupsRecord) > 1 { + return nil, fmt.Errorf("more than one VM Group found with Named VM Group %s '%s'", filterKey, filterValue) + } + vmGroup := &VmGroup{ + VmGroup: foundVmGroups.Results.VmGroupsRecord[0], + client: &vcdClient.Client, + } + return vmGroup, nil +} diff --git a/govcd/vm_groups_test.go b/govcd/vm_groups_test.go index e2e01b4a9..f31eaa01a 100644 --- a/govcd/vm_groups_test.go +++ b/govcd/vm_groups_test.go @@ -9,35 +9,29 @@ package govcd import ( "fmt" - "net/url" - "github.com/vmware/go-vcloud-director/v2/types/v56" . "gopkg.in/check.v1" ) -// TODO: Add VM Placement Policy name in vcd.config.VCD.PlacementPolicy -// This test retrieves a VM Placement Policy to check the behaviour of VM Groups and Logical VM Groups. -// With the information of this VM Placement Policy we test the read logic, then we create a Logical VM Group and -// finally we delete it. +// This test checks the correct behaviour of the read, create and delete operations for VM Groups and Logical VM Groups. func (vcd *TestVCD) Test_VmGroupsCRUD(check *C) { if vcd.skipAdminTests { check.Skip(fmt.Sprintf(TestRequiresSysAdminPrivileges, check.TestName())) } - computePolicies, err := vcd.client.Client.GetAllVdcComputePolicies(url.Values{ - "filter": []string{fmt.Sprintf("name==%s;policyType==VdcVmPolicy", vcd.config.VCD.PlacementPolicy)}, - }) + if vcd.config.VCD.PlacementPolicyVmGroup == "" { + check.Skip(fmt.Sprintf("%s test requires vcd.placementPolicyVmGroup configuration", check.TestName())) + } + + vmGroup, err := vcd.client.GetVmGroupByName(vcd.config.VCD.PlacementPolicyVmGroup) check.Assert(err, IsNil) - check.Assert(len(computePolicies), Equals, 1) - computePolicy := computePolicies[0] - check.Assert(len(computePolicy.VdcComputePolicy.NamedVMGroups), Not(Equals), 0) - check.Assert(len(computePolicy.VdcComputePolicy.NamedVMGroups[0]), Not(Equals), 0) + check.Assert(vmGroup.VmGroup.Name, Equals, vcd.config.VCD.PlacementPolicyVmGroup) - vmGroup, err := vcd.client.GetVmGroupByNamedVmGroupId(computePolicy.VdcComputePolicy.NamedVMGroups[0][0].ID) + vmGroup2, err := vcd.client.GetVmGroupByNamedVmGroupId(vmGroup.VmGroup.NamedVmGroupId) check.Assert(err, IsNil) - check.Assert(vmGroup.VmGroup.NamedVmGroupId, Equals, extractUuid(computePolicy.VdcComputePolicy.NamedVMGroups[0][0].ID)) - check.Assert(vmGroup.VmGroup.Name, Equals, computePolicy.VdcComputePolicy.NamedVMGroups[0][0].Name) + check.Assert(vmGroup, DeepEquals, vmGroup2) + // We need the Provider VDC to create a Logical VM Group pVdc, err := vcd.client.GetProviderVdcByName(vcd.config.VCD.NsxtProviderVdc.Name) check.Assert(err, IsNil) @@ -45,7 +39,7 @@ func (vcd *TestVCD) Test_VmGroupsCRUD(check *C) { Name: check.TestName(), NamedVmGroupReferences: types.OpenApiReferences{ types.OpenApiReference{ - ID: computePolicy.VdcComputePolicy.NamedVMGroups[0][0].ID, + ID: fmt.Sprintf("urn:vcloud:namedVmGroup:%s", vmGroup.VmGroup.NamedVmGroupId), Name: vmGroup.VmGroup.Name}, }, PvdcID: pVdc.ProviderVdc.ID, From 5dea3894568b56627890427332ea824b0515a4d0 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Thu, 1 Sep 2022 09:59:45 +0200 Subject: [PATCH 20/48] Update changelog Signed-off-by: abarreiro --- .changes/v2.17.0/504-features.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.changes/v2.17.0/504-features.md b/.changes/v2.17.0/504-features.md index 6a95c5a58..e3b943ac1 100644 --- a/.changes/v2.17.0/504-features.md +++ b/.changes/v2.17.0/504-features.md @@ -1,2 +1,2 @@ -* Added a new method `VCDClient.GetVmGroupByNamedVmGroupId` to retrieve VM Groups by Named VM Group ID. This is useful to create VM Placement Policies [GH-504] -* Added new methods `VCDClient.GetLogicalVmGroupById`, `VCDClient.CreateLogicalVmGroup`, `LogicalVmGroup.Delete` to manage Logical VM Groups. These are useful to create VM Placement Policies [GH-504] +* Added new methods `VCDClient.GetVmGroupByNamedVmGroupId` and `VCDClient.GetVmGroupByName` to retrieve VM Groups. These are useful to create VM Placement Policies [GH-504] +* Added new methods `VCDClient.GetLogicalVmGroupById`, `VCDClient.CreateLogicalVmGroup` and `LogicalVmGroup.Delete` to manage Logical VM Groups. These are useful to create VM Placement Policies [GH-504] From 8874400dbf2c70040a35445925a7d3836bab15c8 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Thu, 1 Sep 2022 12:41:40 +0200 Subject: [PATCH 21/48] Fix bug in Provider VDC funcs Signed-off-by: abarreiro --- govcd/provider_vdc.go | 6 ++++++ govcd/provider_vdc_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/govcd/provider_vdc.go b/govcd/provider_vdc.go index e191dddba..7f6256143 100644 --- a/govcd/provider_vdc.go +++ b/govcd/provider_vdc.go @@ -88,6 +88,9 @@ func (vcdClient *VCDClient) GetProviderVdcExtendedById(providerVdcId string) (*P // On failure, returns a nil pointer and an error func (vcdClient *VCDClient) GetProviderVdcByName(providerVdcName string) (*ProviderVdc, error) { providerVdc, err := getProviderVdcByName(vcdClient, providerVdcName, false) + if err != nil { + return nil, err + } return providerVdc.(*ProviderVdc), err } @@ -96,6 +99,9 @@ func (vcdClient *VCDClient) GetProviderVdcByName(providerVdcName string) (*Provi // On failure, returns a nil pointer and an error func (vcdClient *VCDClient) GetProviderVdcExtendedByName(providerVdcName string) (*ProviderVdcExtended, error) { providerVdcExtended, err := getProviderVdcByName(vcdClient, providerVdcName, true) + if err != nil { + return nil, err + } return providerVdcExtended.(*ProviderVdcExtended), err } diff --git a/govcd/provider_vdc_test.go b/govcd/provider_vdc_test.go index 2e953368b..9add5e633 100644 --- a/govcd/provider_vdc_test.go +++ b/govcd/provider_vdc_test.go @@ -81,6 +81,31 @@ func (vcd *TestVCD) Test_GetProviderVdcExtended(check *C) { } } +func (vcd *TestVCD) Test_GetNonExistentProviderVdc(check *C) { + if vcd.skipAdminTests { + check.Skip(fmt.Sprintf(TestRequiresSysAdminPrivileges, check.TestName())) + } + + providerVdcExtended, err := vcd.client.GetProviderVdcExtendedByName("non-existent-pvdc") + check.Assert(providerVdcExtended, IsNil) + check.Assert(err, NotNil) + providerVdcExtended, err = vcd.client.GetProviderVdcExtendedById("non-existent-pvdc") + check.Assert(providerVdcExtended, IsNil) + check.Assert(err, NotNil) + providerVdcExtended, err = vcd.client.GetProviderVdcExtendedByHref("non-existent-pvdc") + check.Assert(providerVdcExtended, IsNil) + check.Assert(err, NotNil) + providerVdc, err := vcd.client.GetProviderVdcByName("non-existent-pvdc") + check.Assert(providerVdc, IsNil) + check.Assert(err, NotNil) + providerVdc, err = vcd.client.GetProviderVdcById("non-existent-pvdc") + check.Assert(providerVdc, IsNil) + check.Assert(err, NotNil) + providerVdc, err = vcd.client.GetProviderVdcByHref("non-existent-pvdc") + check.Assert(providerVdc, IsNil) + check.Assert(err, NotNil) +} + func (vcd *TestVCD) Test_GetProviderVdcConvertFromExtendedToNormal(check *C) { if vcd.skipAdminTests { check.Skip(fmt.Sprintf(TestRequiresSysAdminPrivileges, check.TestName())) From 6fbb497d6c0ea031a923c89cdef22ed609664d19 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Thu, 1 Sep 2022 16:01:14 +0200 Subject: [PATCH 22/48] Refactor VM group implementation Signed-off-by: abarreiro --- govcd/vm_groups.go | 39 +++++++++++++++++++++++++++++---------- govcd/vm_groups_test.go | 15 +++++++-------- types/v56/types.go | 19 ++++++++++++++++++- 3 files changed, 54 insertions(+), 19 deletions(-) diff --git a/govcd/vm_groups.go b/govcd/vm_groups.go index 774e6db19..a91958078 100644 --- a/govcd/vm_groups.go +++ b/govcd/vm_groups.go @@ -18,18 +18,33 @@ type VmGroup struct { client *Client } -// GetVmGroupByNamedVmGroupId finds a VM Group by its URN. +// GetVmGroupById finds a VM Group by its ID. // On success, returns a pointer to the VmGroup structure and a nil error // On failure, returns a nil pointer and an error -func (vcdClient *VCDClient) GetVmGroupByNamedVmGroupId(namedVmGroupId string) (*VmGroup, error) { - return getVmGroupByFilterField(vcdClient, "namedVmGroupId", extractUuid(namedVmGroupId)) +func (vcdClient *VCDClient) GetVmGroupById(id string) (*VmGroup, error) { + return getVmGroupWithFilter(vcdClient, map[string]string{"vmGroupId": extractUuid(id)}) } -// GetVmGroupByName finds a VM Group by its name. +// GetVmGroupByNameAndProviderVdcUrn finds a VM Group by its name and associated Provider VDC URN. // On success, returns a pointer to the VmGroup structure and a nil error // On failure, returns a nil pointer and an error -func (vcdClient *VCDClient) GetVmGroupByName(vmGroupName string) (*VmGroup, error) { - return getVmGroupByFilterField(vcdClient, "vmGroupName", vmGroupName) +func (vcdClient *VCDClient) GetVmGroupByNameAndProviderVdcUrn(name, pvdcUrn string) (*VmGroup, error) { + foundResourcePools, err := vcdClient.QueryWithNotEncodedParams(nil, map[string]string{ + "type": "resourcePool", + "filter": fmt.Sprintf("providerVdc==%s", pvdcUrn), + "filterEncoded": "true", + }) + if err != nil { + return nil, fmt.Errorf("could not get the VM Group, failed fetching associated Resource pool: %s", err) + } + if len(foundResourcePools.Results.ResourcePoolRecord) == 0 { + return nil, ErrorEntityNotFound + } + if len(foundResourcePools.Results.ResourcePoolRecord) > 1 { + return nil, fmt.Errorf("more than one Resource Pool found for the pVDC: %s", pvdcUrn) + } + resourcePool := foundResourcePools.Results.ResourcePoolRecord[0] + return getVmGroupWithFilter(vcdClient, map[string]string{"vmGroupName": name, "clusterMoref": resourcePool.ClusterMoref, "vcId": extractUuid(resourcePool.VcenterHREF)}) } // GetLogicalVmGroupById finds a Logical VM Group by its URN. @@ -117,13 +132,17 @@ func (logicalVmGroup *LogicalVmGroup) Delete() error { return nil } -// getVmGroupByFilterField finds a VM Group by specifying a filter=(filterKey==filterValue). +// getVmGroupWithFilter finds a VM Group by specifying a filter=(filterKey==filterValue). // On success, returns a pointer to the VmGroup structure and a nil error // On failure, returns a nil pointer and an error -func getVmGroupByFilterField(vcdClient *VCDClient, filterKey, filterValue string) (*VmGroup, error) { +func getVmGroupWithFilter(vcdClient *VCDClient, filter map[string]string) (*VmGroup, error) { + filterEncoded := "" + for k, v := range filter { + filterEncoded += fmt.Sprintf("%s==%s;", url.QueryEscape(k), url.QueryEscape(v)) + } foundVmGroups, err := vcdClient.QueryWithNotEncodedParams(nil, map[string]string{ "type": "vmGroups", - "filter": fmt.Sprintf("%s==%s", url.QueryEscape(filterKey), url.QueryEscape(filterValue)), + "filter": filterEncoded[:len(filterEncoded)-1], // Removes the trailing ';' "filterEncoded": "true", }) if err != nil { @@ -133,7 +152,7 @@ func getVmGroupByFilterField(vcdClient *VCDClient, filterKey, filterValue string return nil, ErrorEntityNotFound } if len(foundVmGroups.Results.VmGroupsRecord) > 1 { - return nil, fmt.Errorf("more than one VM Group found with Named VM Group %s '%s'", filterKey, filterValue) + return nil, fmt.Errorf("more than one VM Group found with the filter: %v", filter) } vmGroup := &VmGroup{ VmGroup: foundVmGroups.Results.VmGroupsRecord[0], diff --git a/govcd/vm_groups_test.go b/govcd/vm_groups_test.go index f31eaa01a..4983c657d 100644 --- a/govcd/vm_groups_test.go +++ b/govcd/vm_groups_test.go @@ -22,18 +22,17 @@ func (vcd *TestVCD) Test_VmGroupsCRUD(check *C) { if vcd.config.VCD.PlacementPolicyVmGroup == "" { check.Skip(fmt.Sprintf("%s test requires vcd.placementPolicyVmGroup configuration", check.TestName())) } + if vcd.config.VCD.NsxtProviderVdc.Name == "" { + check.Skip(fmt.Sprintf("%s test requires vcd.nsxtProviderVdc configuration", check.TestName())) + } - vmGroup, err := vcd.client.GetVmGroupByName(vcd.config.VCD.PlacementPolicyVmGroup) - check.Assert(err, IsNil) - check.Assert(vmGroup.VmGroup.Name, Equals, vcd.config.VCD.PlacementPolicyVmGroup) - - vmGroup2, err := vcd.client.GetVmGroupByNamedVmGroupId(vmGroup.VmGroup.NamedVmGroupId) + // We need the Provider VDC URN + pVdc, err := vcd.client.GetProviderVdcByName(vcd.config.VCD.NsxtProviderVdc.Name) check.Assert(err, IsNil) - check.Assert(vmGroup, DeepEquals, vmGroup2) - // We need the Provider VDC to create a Logical VM Group - pVdc, err := vcd.client.GetProviderVdcByName(vcd.config.VCD.NsxtProviderVdc.Name) + vmGroup, err := vcd.client.GetVmGroupByNameAndProviderVdcUrn(vcd.config.VCD.PlacementPolicyVmGroup, pVdc.ProviderVdc.ID) check.Assert(err, IsNil) + check.Assert(vmGroup.VmGroup.Name, Equals, vcd.config.VCD.PlacementPolicyVmGroup) logicalVmGroup, err := vcd.client.CreateLogicalVmGroup(types.LogicalVmGroup{ Name: check.TestName(), diff --git a/types/v56/types.go b/types/v56/types.go index 33474201f..91c5fed37 100644 --- a/types/v56/types.go +++ b/types/v56/types.go @@ -2312,7 +2312,8 @@ type QueryResultRecordsType struct { NsxtManagerRecord []*QueryResultNsxtManagerRecordType `xml:"NsxTManagerRecord"` // A record representing NSX-T manager OrgVdcRecord []*QueryResultOrgVdcRecordType `xml:"OrgVdcRecord"` // A record representing Org VDC OrgVdcAdminRecord []*QueryResultOrgVdcRecordType `xml:"AdminVdcRecord"` // A record representing Org VDC - VmGroupsRecord []*QueryResultVmGroupsRecordType `xml:"VmGroupsRecord"` + ResourcePoolRecord []*QueryResultResourcePoolRecordType `xml:"ResourcePoolRecord"` // A record representing a Resource Pool + VmGroupsRecord []*QueryResultVmGroupsRecordType `xml:"VmGroupsRecord"` // A record representing a VM Group } // QueryResultVmGroupsRecordType represent a VM Groups record @@ -2326,6 +2327,22 @@ type QueryResultVmGroupsRecordType struct { NamedVmGroupId string `xml:"namedVmGroupId,attr,omitempty"` } +// QueryResultResourcePoolRecordType represent a Resource Pool record +type QueryResultResourcePoolRecordType struct { + HREF string `xml:"href,attr,omitempty"` + Name string `xml:"name,attr,omitempty"` + Moref string `xml:"moref,attr,omitempty"` + IsDeleted bool `xml:"isDeleted,attr,omitempty"` + VcenterHREF string `xml:"vc,attr,omitempty"` + VcenterName string `xml:"vcName,attr,omitempty"` + ProviderVdcHREF string `xml:"providerVdc,attr,omitempty"` + ProviderName string `xml:"providerName,attr,omitempty"` + IsEnabled bool `xml:"isEnabled,attr,omitempty"` + IsPrimary bool `xml:"isPrimary,attr,omitempty"` + ClusterMoref string `xml:"clusterMoref,attr,omitempty"` + IsKubernetesEnabled bool `xml:"isKubernetesEnabled,attr,omitempty"` +} + // QueryResultOrgVdcRecordType represents an Org VDC record type QueryResultOrgVdcRecordType struct { HREF string `xml:"href,attr,omitempty"` From 48172eecd2680b4c9d65d3cfac79cde3fc3d0848 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Thu, 1 Sep 2022 16:18:44 +0200 Subject: [PATCH 23/48] # Signed-off-by: abarreiro --- govcd/vm_groups_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/govcd/vm_groups_test.go b/govcd/vm_groups_test.go index 4983c657d..874065202 100644 --- a/govcd/vm_groups_test.go +++ b/govcd/vm_groups_test.go @@ -34,6 +34,10 @@ func (vcd *TestVCD) Test_VmGroupsCRUD(check *C) { check.Assert(err, IsNil) check.Assert(vmGroup.VmGroup.Name, Equals, vcd.config.VCD.PlacementPolicyVmGroup) + vmGroup2, err := vcd.client.GetVmGroupById(vmGroup.VmGroup.ID) + check.Assert(err, IsNil) + check.Assert(vmGroup2, DeepEquals, vmGroup) + logicalVmGroup, err := vcd.client.CreateLogicalVmGroup(types.LogicalVmGroup{ Name: check.TestName(), NamedVmGroupReferences: types.OpenApiReferences{ From 7759318d865008013c68c012c7da04226207f82c Mon Sep 17 00:00:00 2001 From: abarreiro Date: Thu, 1 Sep 2022 16:36:34 +0200 Subject: [PATCH 24/48] # Signed-off-by: abarreiro --- govcd/vm_groups.go | 47 +++++++++++++++++++++++++++++------------ govcd/vm_groups_test.go | 4 ++++ 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/govcd/vm_groups.go b/govcd/vm_groups.go index a91958078..49d908203 100644 --- a/govcd/vm_groups.go +++ b/govcd/vm_groups.go @@ -25,28 +25,30 @@ func (vcdClient *VCDClient) GetVmGroupById(id string) (*VmGroup, error) { return getVmGroupWithFilter(vcdClient, map[string]string{"vmGroupId": extractUuid(id)}) } +// GetVmGroupByNamedVmGroupIdAndProviderVdcUrn finds a VM Group by its Named VM Group ID and Provider VDC URN. +// On success, returns a pointer to the VmGroup structure and a nil error +// On failure, returns a nil pointer and an error +func (vcdClient *VCDClient) GetVmGroupByNamedVmGroupIdAndProviderVdcUrn(namedVmGroupId, pvdcUrn string) (*VmGroup, error) { + resourcePool, err := getResourcePool(vcdClient, pvdcUrn) + if err != nil { + return nil, fmt.Errorf("could not get VM Group: %s", err) + } + return getVmGroupWithFilter(vcdClient, map[string]string{"namedVmGroupId": namedVmGroupId, "clusterMoref": resourcePool.ClusterMoref, "vcId": extractUuid(resourcePool.VcenterHREF)}) +} + // GetVmGroupByNameAndProviderVdcUrn finds a VM Group by its name and associated Provider VDC URN. // On success, returns a pointer to the VmGroup structure and a nil error // On failure, returns a nil pointer and an error func (vcdClient *VCDClient) GetVmGroupByNameAndProviderVdcUrn(name, pvdcUrn string) (*VmGroup, error) { - foundResourcePools, err := vcdClient.QueryWithNotEncodedParams(nil, map[string]string{ - "type": "resourcePool", - "filter": fmt.Sprintf("providerVdc==%s", pvdcUrn), - "filterEncoded": "true", - }) + resourcePool, err := getResourcePool(vcdClient, pvdcUrn) if err != nil { - return nil, fmt.Errorf("could not get the VM Group, failed fetching associated Resource pool: %s", err) - } - if len(foundResourcePools.Results.ResourcePoolRecord) == 0 { - return nil, ErrorEntityNotFound - } - if len(foundResourcePools.Results.ResourcePoolRecord) > 1 { - return nil, fmt.Errorf("more than one Resource Pool found for the pVDC: %s", pvdcUrn) + return nil, fmt.Errorf("could not get VM Group: %s", err) } - resourcePool := foundResourcePools.Results.ResourcePoolRecord[0] return getVmGroupWithFilter(vcdClient, map[string]string{"vmGroupName": name, "clusterMoref": resourcePool.ClusterMoref, "vcId": extractUuid(resourcePool.VcenterHREF)}) } + + // GetLogicalVmGroupById finds a Logical VM Group by its URN. // On success, returns a pointer to the LogicalVmGroup structure and a nil error // On failure, returns a nil pointer and an error @@ -160,3 +162,22 @@ func getVmGroupWithFilter(vcdClient *VCDClient, filter map[string]string) (*VmGr } return vmGroup, nil } + +// getResourcePool returns the Resource Pool that can unequivocally identify a VM Group +func getResourcePool(vcdClient *VCDClient, pvdcUrn string) (*types.QueryResultResourcePoolRecordType, error) { + foundResourcePools, err := vcdClient.QueryWithNotEncodedParams(nil, map[string]string{ + "type": "resourcePool", + "filter": fmt.Sprintf("providerVdc==%s", pvdcUrn), + "filterEncoded": "true", + }) + if err != nil { + return nil, fmt.Errorf("could not get the Resource pool: %s", err) + } + if len(foundResourcePools.Results.ResourcePoolRecord) == 0 { + return nil, ErrorEntityNotFound + } + if len(foundResourcePools.Results.ResourcePoolRecord) > 1 { + return nil, fmt.Errorf("more than one Resource Pool found for the pVDC: %s", pvdcUrn) + } + return foundResourcePools.Results.ResourcePoolRecord[0], nil +} diff --git a/govcd/vm_groups_test.go b/govcd/vm_groups_test.go index 874065202..85903f232 100644 --- a/govcd/vm_groups_test.go +++ b/govcd/vm_groups_test.go @@ -38,6 +38,10 @@ func (vcd *TestVCD) Test_VmGroupsCRUD(check *C) { check.Assert(err, IsNil) check.Assert(vmGroup2, DeepEquals, vmGroup) + vmGroup3, err := vcd.client.GetVmGroupByNamedVmGroupIdAndProviderVdcUrn(vmGroup2.VmGroup.NamedVmGroupId, pVdc.ProviderVdc.ID) + check.Assert(err, IsNil) + check.Assert(vmGroup3, DeepEquals, vmGroup2) + logicalVmGroup, err := vcd.client.CreateLogicalVmGroup(types.LogicalVmGroup{ Name: check.TestName(), NamedVmGroupReferences: types.OpenApiReferences{ From 77a849fd3ed17914a060a7191e57e6e5558bcb2c Mon Sep 17 00:00:00 2001 From: abarreiro Date: Thu, 1 Sep 2022 16:44:12 +0200 Subject: [PATCH 25/48] # Signed-off-by: abarreiro --- govcd/vm_groups.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/govcd/vm_groups.go b/govcd/vm_groups.go index 49d908203..0485eb285 100644 --- a/govcd/vm_groups.go +++ b/govcd/vm_groups.go @@ -33,7 +33,7 @@ func (vcdClient *VCDClient) GetVmGroupByNamedVmGroupIdAndProviderVdcUrn(namedVmG if err != nil { return nil, fmt.Errorf("could not get VM Group: %s", err) } - return getVmGroupWithFilter(vcdClient, map[string]string{"namedVmGroupId": namedVmGroupId, "clusterMoref": resourcePool.ClusterMoref, "vcId": extractUuid(resourcePool.VcenterHREF)}) + return getVmGroupWithFilter(vcdClient, map[string]string{"namedVmGroupId": extractUuid(namedVmGroupId), "clusterMoref": resourcePool.ClusterMoref, "vcId": extractUuid(resourcePool.VcenterHREF)}) } // GetVmGroupByNameAndProviderVdcUrn finds a VM Group by its name and associated Provider VDC URN. From e4dce2ca4a6381b491b5fa254d6e6434b0cfdc44 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Thu, 1 Sep 2022 16:44:33 +0200 Subject: [PATCH 26/48] # Signed-off-by: abarreiro --- govcd/vm_groups.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/govcd/vm_groups.go b/govcd/vm_groups.go index 0485eb285..65f70a387 100644 --- a/govcd/vm_groups.go +++ b/govcd/vm_groups.go @@ -47,8 +47,6 @@ func (vcdClient *VCDClient) GetVmGroupByNameAndProviderVdcUrn(name, pvdcUrn stri return getVmGroupWithFilter(vcdClient, map[string]string{"vmGroupName": name, "clusterMoref": resourcePool.ClusterMoref, "vcId": extractUuid(resourcePool.VcenterHREF)}) } - - // GetLogicalVmGroupById finds a Logical VM Group by its URN. // On success, returns a pointer to the LogicalVmGroup structure and a nil error // On failure, returns a nil pointer and an error From f87ac43a8aaf892f982910e66415bbee2dd10fc1 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Thu, 1 Sep 2022 16:45:26 +0200 Subject: [PATCH 27/48] # Signed-off-by: abarreiro --- .changes/v2.17.0/504-features.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changes/v2.17.0/504-features.md b/.changes/v2.17.0/504-features.md index e3b943ac1..635181d9b 100644 --- a/.changes/v2.17.0/504-features.md +++ b/.changes/v2.17.0/504-features.md @@ -1,2 +1,2 @@ -* Added new methods `VCDClient.GetVmGroupByNamedVmGroupId` and `VCDClient.GetVmGroupByName` to retrieve VM Groups. These are useful to create VM Placement Policies [GH-504] +* Added new methods `VCDClient.GetVmGroupById` and `VCDClient.GetVmGroupByNamedVmGroupIdAndProviderVdcUrn` and `VCDClient.GetVmGroupByNameAndProviderVdcUrn` to retrieve VM Groups. These are useful to create VM Placement Policies [GH-504] * Added new methods `VCDClient.GetLogicalVmGroupById`, `VCDClient.CreateLogicalVmGroup` and `LogicalVmGroup.Delete` to manage Logical VM Groups. These are useful to create VM Placement Policies [GH-504] From 8dd3ad0e542415d354f991825e7a7d77227d5734 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Fri, 2 Sep 2022 10:43:46 +0200 Subject: [PATCH 28/48] Address typo Signed-off-by: abarreiro --- types/v56/openapi.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/v56/openapi.go b/types/v56/openapi.go index ac9c683dc..8c6b95f04 100644 --- a/types/v56/openapi.go +++ b/types/v56/openapi.go @@ -404,6 +404,6 @@ type LogicalVmGroup struct { Name string `json:"name,omitempty"` // Display name Description string `json:"description,omitempty"` ID string `json:"id,omitempty"` // UUID for LogicalVmGroup. This is immutable - NamedVmGroupReferences OpenApiReferences `json:"namedVmGroupReferences,omitempty"` // List of named vm groups associated with LogicalVmGroup. + NamedVmGroupReferences OpenApiReferences `json:"namedVmGroupReferences,omitempty"` // List of named VM Groups associated with LogicalVmGroup. PvdcID string `json:"pvdcId,omitempty"` // URN for Provider VDC } From ce2c9c50419dced1f849b6461e3c9c9524af2fc2 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Fri, 2 Sep 2022 10:44:24 +0200 Subject: [PATCH 29/48] Address typo Signed-off-by: abarreiro --- .changes/v2.17.0/504-features.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changes/v2.17.0/504-features.md b/.changes/v2.17.0/504-features.md index 635181d9b..8dcfa53ba 100644 --- a/.changes/v2.17.0/504-features.md +++ b/.changes/v2.17.0/504-features.md @@ -1,2 +1,2 @@ -* Added new methods `VCDClient.GetVmGroupById` and `VCDClient.GetVmGroupByNamedVmGroupIdAndProviderVdcUrn` and `VCDClient.GetVmGroupByNameAndProviderVdcUrn` to retrieve VM Groups. These are useful to create VM Placement Policies [GH-504] +* Added new methods `VCDClient.GetVmGroupById`, `VCDClient.GetVmGroupByNamedVmGroupIdAndProviderVdcUrn` and `VCDClient.GetVmGroupByNameAndProviderVdcUrn` to retrieve VM Groups. These are useful to create VM Placement Policies [GH-504] * Added new methods `VCDClient.GetLogicalVmGroupById`, `VCDClient.CreateLogicalVmGroup` and `LogicalVmGroup.Delete` to manage Logical VM Groups. These are useful to create VM Placement Policies [GH-504] From 964bcbb25f4a1f925e2ee024383dd631d4423a8f Mon Sep 17 00:00:00 2001 From: abarreiro Date: Fri, 2 Sep 2022 15:55:26 +0200 Subject: [PATCH 30/48] Upgrade ComputePolicies endpoints to v2.0.0 Signed-off-by: abarreiro --- govcd/openapi_endpoints.go | 2 +- govcd/vdccomputepolicy.go | 58 ++---- govcd/vdccomputepolicy_v2.go | 241 +++++++++++++++++++++++ govcd/vdccomputepolicy_v2_test.go | 315 ++++++++++++++++++++++++++++++ types/v56/openapi.go | 39 +++- 5 files changed, 603 insertions(+), 52 deletions(-) create mode 100644 govcd/vdccomputepolicy_v2.go create mode 100644 govcd/vdccomputepolicy_v2_test.go diff --git a/govcd/openapi_endpoints.go b/govcd/openapi_endpoints.go index 9e0d61292..d0d357cd8 100644 --- a/govcd/openapi_endpoints.go +++ b/govcd/openapi_endpoints.go @@ -30,7 +30,7 @@ var endpointMinApiVersions = map[string]string{ // OpenApiEndpointExternalNetworks endpoint support was introduced with version 32.0 however it was still not stable // enough to be used. (i.e. it did not support update "PUT") types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointExternalNetworks: "33.0", - types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcComputePolicies: "32.0", + types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcComputePolicies: "32.0", // Deprecated in favor of v2.0.0 types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcAssignedComputePolicies: "33.0", types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointSessionCurrent: "34.0", types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointEdgeClusters: "34.0", // VCD 10.1+ diff --git a/govcd/vdccomputepolicy.go b/govcd/vdccomputepolicy.go index 20c48f4a5..623035b8b 100644 --- a/govcd/vdccomputepolicy.go +++ b/govcd/vdccomputepolicy.go @@ -6,14 +6,13 @@ package govcd import ( "fmt" - "net/http" "net/url" "github.com/vmware/go-vcloud-director/v2/types/v56" - "github.com/vmware/go-vcloud-director/v2/util" ) -// In UI called VM sizing policy. In API VDC compute policy +// VdcComputePolicy defines a VDC Compute Policy, which can be a VM Sizing Policy, a VM Placement Policy or a vGPU Policy. +// Deprecated: Use VdcComputePolicyV2 instead type VdcComputePolicy struct { VdcComputePolicy *types.VdcComputePolicy Href string @@ -21,23 +20,25 @@ type VdcComputePolicy struct { } // GetVdcComputePolicyById retrieves VDC compute policy by given ID +// Deprecated: Use VCDClient.GetVdcComputePolicyV2ById instead func (client *Client) GetVdcComputePolicyById(id string) (*VdcComputePolicy, error) { return getVdcComputePolicyById(client, id) } // GetVdcComputePolicyById retrieves VDC compute policy by given ID -// Deprecated: use client.GetVdcComputePolicyById +// Deprecated: use VCDClient.GetVdcComputePolicyV2ById func (org *AdminOrg) GetVdcComputePolicyById(id string) (*VdcComputePolicy, error) { return getVdcComputePolicyById(org.client, id) } // GetVdcComputePolicyById retrieves VDC compute policy by given ID -// Deprecated: use client.GetVdcComputePolicyById +// Deprecated: use VCDClient.GetVdcComputePolicyV2ById func (org *Org) GetVdcComputePolicyById(id string) (*VdcComputePolicy, error) { return getVdcComputePolicyById(org.client, id) } // getVdcComputePolicyById retrieves VDC compute policy by given ID +// Deprecated: Use getVdcComputePolicyV2ById instead func getVdcComputePolicyById(client *Client, id string) (*VdcComputePolicy, error) { endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcComputePolicies minimumApiVersion, err := client.checkOpenApiEndpointCompatibility(endpoint) @@ -71,28 +72,30 @@ func getVdcComputePolicyById(client *Client, id string) (*VdcComputePolicy, erro // GetAllVdcComputePolicies retrieves all VDC compute policies using OpenAPI endpoint. Query parameters can be supplied to perform additional // filtering +// Deprecated: use VCDClient.GetAllVdcComputePoliciesV2 func (client *Client) GetAllVdcComputePolicies(queryParameters url.Values) ([]*VdcComputePolicy, error) { return getAllVdcComputePolicies(client, queryParameters) } // GetAllVdcComputePolicies retrieves all VDC compute policies using OpenAPI endpoint. Query parameters can be supplied to perform additional // filtering -// Deprecated: use client.GetAllVdcComputePolicies +// Deprecated: use VCDClient.GetAllVdcComputePoliciesV2 func (org *AdminOrg) GetAllVdcComputePolicies(queryParameters url.Values) ([]*VdcComputePolicy, error) { return getAllVdcComputePolicies(org.client, queryParameters) } // GetAllVdcComputePolicies retrieves all VDC compute policies using OpenAPI endpoint. Query parameters can be supplied to perform additional // filtering -// Deprecated: use client.GetAllVdcComputePolicies +// Deprecated: use VCDClient.GetAllVdcComputePoliciesV2 func (org *Org) GetAllVdcComputePolicies(queryParameters url.Values) ([]*VdcComputePolicy, error) { return getAllVdcComputePolicies(org.client, queryParameters) } // getAllVdcComputePolicies retrieves all VDC compute policies using OpenAPI endpoint. Query parameters can be supplied to perform additional // filtering +// Deprecated: use getAllVdcComputePoliciesV2 func getAllVdcComputePolicies(client *Client, queryParameters url.Values) ([]*VdcComputePolicy, error) { - endpoint := types.OpenApiPathVersion2_0_0 + types.OpenApiEndpointVdcComputePolicies + endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcComputePolicies minimumApiVersion, err := client.checkOpenApiEndpointCompatibility(endpoint) if err != nil { return nil, err @@ -123,12 +126,13 @@ func getAllVdcComputePolicies(client *Client, queryParameters url.Values) ([]*Vd } // CreateVdcComputePolicy creates a new VDC Compute Policy using OpenAPI endpoint -// Deprecated: use client.CreateVdcComputePolicy +// Deprecated: use VCDClient.CreateVdcComputePolicyV2 func (org *AdminOrg) CreateVdcComputePolicy(newVdcComputePolicy *types.VdcComputePolicy) (*VdcComputePolicy, error) { return org.client.CreateVdcComputePolicy(newVdcComputePolicy) } // CreateVdcComputePolicy creates a new VDC Compute Policy using OpenAPI endpoint +// Deprecated: use VCDClient.CreateVdcComputePolicyV2 func (client *Client) CreateVdcComputePolicy(newVdcComputePolicy *types.VdcComputePolicy) (*VdcComputePolicy, error) { endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcComputePolicies minimumApiVersion, err := client.checkOpenApiEndpointCompatibility(endpoint) @@ -155,6 +159,7 @@ func (client *Client) CreateVdcComputePolicy(newVdcComputePolicy *types.VdcCompu } // Update existing VDC compute policy +// Deprecated: use VdcComputePolicyV2.Update func (vdcComputePolicy *VdcComputePolicy) Update() (*VdcComputePolicy, error) { endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcComputePolicies minimumApiVersion, err := vdcComputePolicy.client.checkOpenApiEndpointCompatibility(endpoint) @@ -185,6 +190,7 @@ func (vdcComputePolicy *VdcComputePolicy) Update() (*VdcComputePolicy, error) { } // Delete deletes VDC compute policy +// Deprecated: use VdcComputePolicyV2.Delete func (vdcComputePolicy *VdcComputePolicy) Delete() error { endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcComputePolicies minimumApiVersion, err := vdcComputePolicy.client.checkOpenApiEndpointCompatibility(endpoint) @@ -212,8 +218,9 @@ func (vdcComputePolicy *VdcComputePolicy) Delete() error { // GetAllAssignedVdcComputePolicies retrieves all VDC assigned compute policies using OpenAPI endpoint. Query parameters can be supplied to perform additional // filtering +// Deprecated: use AdminVdc.GetAllAssignedVdcComputePoliciesV2 func (vdc *AdminVdc) GetAllAssignedVdcComputePolicies(queryParameters url.Values) ([]*VdcComputePolicy, error) { - endpoint := types.OpenApiPathVersion2_0_0 + types.OpenApiEndpointVdcAssignedComputePolicies + endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcAssignedComputePolicies minimumApiVersion, err := vdc.client.checkOpenApiEndpointCompatibility(endpoint) if err != nil { return nil, err @@ -242,34 +249,3 @@ func (vdc *AdminVdc) GetAllAssignedVdcComputePolicies(queryParameters url.Values return wrappedVdcComputePolicies, nil } - -// SetAssignedComputePolicies assign(set) compute policies. -func (vdc *AdminVdc) SetAssignedComputePolicies(computePolicyReferences types.VdcComputePolicyReferences) (*types.VdcComputePolicyReferences, error) { - util.Logger.Printf("[TRACE] Set Compute Policies started") - - if !vdc.client.IsSysAdmin { - return nil, fmt.Errorf("functionality requires System Administrator privileges") - } - - adminVdcPolicyHREF, err := url.ParseRequestURI(vdc.AdminVdc.HREF) - if err != nil { - return nil, fmt.Errorf("error parsing VDC URL: %s", err) - } - - vdcId, err := GetUuidFromHref(vdc.AdminVdc.HREF, true) - if err != nil { - return nil, fmt.Errorf("unable to get vdc ID from HREF: %s", err) - } - adminVdcPolicyHREF.Path = "/api/admin/vdc/" + vdcId + "/computePolicies" - - returnedVdcComputePolicies := &types.VdcComputePolicyReferences{} - computePolicyReferences.Xmlns = types.XMLNamespaceVCloud - - _, err = vdc.client.ExecuteRequest(adminVdcPolicyHREF.String(), http.MethodPut, - types.MimeVdcComputePolicyReferences, "error setting compute policies for VDC: %s", computePolicyReferences, returnedVdcComputePolicies) - if err != nil { - return nil, err - } - - return returnedVdcComputePolicies, nil -} diff --git a/govcd/vdccomputepolicy_v2.go b/govcd/vdccomputepolicy_v2.go new file mode 100644 index 000000000..a5c137a7d --- /dev/null +++ b/govcd/vdccomputepolicy_v2.go @@ -0,0 +1,241 @@ +package govcd + +/* + * Copyright 2022 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. + */ + +import ( + "fmt" + "net/http" + "net/url" + + "github.com/vmware/go-vcloud-director/v2/types/v56" + "github.com/vmware/go-vcloud-director/v2/util" +) + +// VdcComputePolicyV2 defines a VDC Compute Policy, which can be a VM Sizing Policy, a VM Placement Policy or a vGPU Policy. +type VdcComputePolicyV2 struct { + VdcComputePolicyV2 *types.VdcComputePolicyV2 + client *Client +} + +// GetVdcComputePolicyV2ById retrieves VDC Compute Policy (version 2) by given ID +func (client *VCDClient) GetVdcComputePolicyV2ById(id string) (*VdcComputePolicyV2, error) { + return getVdcComputePolicyV2ById(client, id) +} + +// getVdcComputePolicyV2ById retrieves VDC Compute Policy (version 2) by given ID +func getVdcComputePolicyV2ById(client *VCDClient, id string) (*VdcComputePolicyV2, error) { + endpoint := types.OpenApiPathVersion2_0_0 + types.OpenApiEndpointVdcComputePolicies + minimumApiVersion, err := client.Client.checkOpenApiEndpointCompatibility(endpoint) + if err != nil { + return nil, err + } + + if id == "" { + return nil, fmt.Errorf("empty VDC id") + } + + urlRef, err := client.Client.OpenApiBuildEndpoint(endpoint, id) + + if err != nil { + return nil, err + } + + vdcComputePolicy := &VdcComputePolicyV2{ + VdcComputePolicyV2: &types.VdcComputePolicyV2{}, + client: &client.Client, + } + + err = client.Client.OpenApiGetItem(minimumApiVersion, urlRef, nil, vdcComputePolicy.VdcComputePolicyV2, nil) + if err != nil { + return nil, err + } + + return vdcComputePolicy, nil +} + +// GetAllVdcComputePoliciesV2 retrieves all VDC Compute Policies (version 2) using OpenAPI endpoint. Query parameters can be supplied to perform additional +// filtering +func (client *VCDClient) GetAllVdcComputePoliciesV2(queryParameters url.Values) ([]*VdcComputePolicyV2, error) { + return getAllVdcComputePoliciesV2(client, queryParameters) +} + +// getAllVdcComputePolicies retrieves all VDC Compute Policies (version 2) using OpenAPI endpoint. Query parameters can be supplied to perform additional +// filtering +func getAllVdcComputePoliciesV2(client *VCDClient, queryParameters url.Values) ([]*VdcComputePolicyV2, error) { + endpoint := types.OpenApiPathVersion2_0_0 + types.OpenApiEndpointVdcComputePolicies + minimumApiVersion, err := client.Client.checkOpenApiEndpointCompatibility(endpoint) + if err != nil { + return nil, err + } + + urlRef, err := client.Client.OpenApiBuildEndpoint(endpoint) + if err != nil { + return nil, err + } + + responses := []*types.VdcComputePolicyV2{{}} + + err = client.Client.OpenApiGetAllItems(minimumApiVersion, urlRef, queryParameters, &responses, nil) + if err != nil { + return nil, err + } + + var wrappedVdcComputePolicies []*VdcComputePolicyV2 + for _, response := range responses { + wrappedVdcComputePolicy := &VdcComputePolicyV2{ + client: &client.Client, + VdcComputePolicyV2: response, + } + wrappedVdcComputePolicies = append(wrappedVdcComputePolicies, wrappedVdcComputePolicy) + } + + return wrappedVdcComputePolicies, nil +} + +// CreateVdcComputePolicyV2 creates a new VDC Compute Policy (version 2) using OpenAPI endpoint +func (client *VCDClient) CreateVdcComputePolicyV2(newVdcComputePolicy *types.VdcComputePolicyV2) (*VdcComputePolicyV2, error) { + endpoint := types.OpenApiPathVersion2_0_0 + types.OpenApiEndpointVdcComputePolicies + minimumApiVersion, err := client.Client.checkOpenApiEndpointCompatibility(endpoint) + if err != nil { + return nil, err + } + + urlRef, err := client.Client.OpenApiBuildEndpoint(endpoint) + if err != nil { + return nil, err + } + + returnVdcComputePolicy := &VdcComputePolicyV2{ + VdcComputePolicyV2: &types.VdcComputePolicyV2{}, + client: &client.Client, + } + + err = client.Client.OpenApiPostItem(minimumApiVersion, urlRef, nil, newVdcComputePolicy, returnVdcComputePolicy.VdcComputePolicyV2, nil) + if err != nil { + return nil, fmt.Errorf("error creating VDC Compute Policy: %s", err) + } + + return returnVdcComputePolicy, nil +} + +// Update existing VDC Compute Policy (version 2) +func (vdcComputePolicy *VdcComputePolicyV2) Update() (*VdcComputePolicyV2, error) { + endpoint := types.OpenApiPathVersion2_0_0 + types.OpenApiEndpointVdcComputePolicies + minimumApiVersion, err := vdcComputePolicy.client.checkOpenApiEndpointCompatibility(endpoint) + if err != nil { + return nil, err + } + + if vdcComputePolicy.VdcComputePolicyV2.ID == "" { + return nil, fmt.Errorf("cannot update VDC Compute Policy without ID") + } + + urlRef, err := vdcComputePolicy.client.OpenApiBuildEndpoint(endpoint, vdcComputePolicy.VdcComputePolicyV2.ID) + if err != nil { + return nil, err + } + + returnVdcComputePolicy := &VdcComputePolicyV2{ + VdcComputePolicyV2: &types.VdcComputePolicyV2{}, + client: vdcComputePolicy.client, + } + + err = vdcComputePolicy.client.OpenApiPutItem(minimumApiVersion, urlRef, nil, vdcComputePolicy.VdcComputePolicyV2, returnVdcComputePolicy.VdcComputePolicyV2, nil) + if err != nil { + return nil, fmt.Errorf("error updating VDC Compute Policy: %s", err) + } + + return returnVdcComputePolicy, nil +} + +// Delete deletes VDC Compute Policy (version 2) +func (vdcComputePolicy *VdcComputePolicyV2) Delete() error { + endpoint := types.OpenApiPathVersion2_0_0 + types.OpenApiEndpointVdcComputePolicies + minimumApiVersion, err := vdcComputePolicy.client.checkOpenApiEndpointCompatibility(endpoint) + if err != nil { + return err + } + + if vdcComputePolicy.VdcComputePolicyV2.ID == "" { + return fmt.Errorf("cannot delete VDC Compute Policy without id") + } + + urlRef, err := vdcComputePolicy.client.OpenApiBuildEndpoint(endpoint, vdcComputePolicy.VdcComputePolicyV2.ID) + if err != nil { + return err + } + + err = vdcComputePolicy.client.OpenApiDeleteItem(minimumApiVersion, urlRef, nil, nil) + + if err != nil { + return fmt.Errorf("error deleting VDC Compute Policy: %s", err) + } + + return nil +} + +// GetAllAssignedVdcComputePoliciesV2 retrieves all VDC assigned Compute Policies (version 2) using OpenAPI endpoint. Query parameters can be supplied to perform additional +// filtering +func (vdc *AdminVdc) GetAllAssignedVdcComputePoliciesV2(queryParameters url.Values) ([]*VdcComputePolicyV2, error) { + endpoint := types.OpenApiPathVersion2_0_0 + types.OpenApiEndpointVdcAssignedComputePolicies + minimumApiVersion, err := vdc.client.checkOpenApiEndpointCompatibility(endpoint) + if err != nil { + return nil, err + } + + urlRef, err := vdc.client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, vdc.AdminVdc.ID)) + if err != nil { + return nil, err + } + + responses := []*types.VdcComputePolicyV2{{}} + + err = vdc.client.OpenApiGetAllItems(minimumApiVersion, urlRef, queryParameters, &responses, nil) + if err != nil { + return nil, err + } + + var wrappedVdcComputePolicies []*VdcComputePolicyV2 + for _, response := range responses { + wrappedVdcComputePolicy := &VdcComputePolicyV2{ + client: vdc.client, + VdcComputePolicyV2: response, + } + wrappedVdcComputePolicies = append(wrappedVdcComputePolicies, wrappedVdcComputePolicy) + } + + return wrappedVdcComputePolicies, nil +} + +// SetAssignedComputePolicies assign(set) Compute Policies to the receiver VDC. +func (vdc *AdminVdc) SetAssignedComputePolicies(computePolicyReferences types.VdcComputePolicyReferences) (*types.VdcComputePolicyReferences, error) { + util.Logger.Printf("[TRACE] Set Compute Policies started") + + if !vdc.client.IsSysAdmin { + return nil, fmt.Errorf("functionality requires System Administrator privileges") + } + + adminVdcPolicyHREF, err := url.ParseRequestURI(vdc.AdminVdc.HREF) + if err != nil { + return nil, fmt.Errorf("error parsing VDC URL: %s", err) + } + + vdcId, err := GetUuidFromHref(vdc.AdminVdc.HREF, true) + if err != nil { + return nil, fmt.Errorf("unable to get vdc ID from HREF: %s", err) + } + adminVdcPolicyHREF.Path = "/api/admin/vdc/" + vdcId + "/computePolicies" + + returnedVdcComputePolicies := &types.VdcComputePolicyReferences{} + computePolicyReferences.Xmlns = types.XMLNamespaceVCloud + + _, err = vdc.client.ExecuteRequest(adminVdcPolicyHREF.String(), http.MethodPut, + types.MimeVdcComputePolicyReferences, "error setting Compute Policies for VDC: %s", computePolicyReferences, returnedVdcComputePolicies) + if err != nil { + return nil, err + } + + return returnedVdcComputePolicies, nil +} diff --git a/govcd/vdccomputepolicy_v2_test.go b/govcd/vdccomputepolicy_v2_test.go new file mode 100644 index 000000000..2958c7cdd --- /dev/null +++ b/govcd/vdccomputepolicy_v2_test.go @@ -0,0 +1,315 @@ +//go:build vdc || functional || openapi || ALL +// +build vdc functional openapi ALL + +/* + * Copyright 2022 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. + */ + +package govcd + +import ( + "fmt" + "net/url" + "strings" + + "github.com/vmware/go-vcloud-director/v2/types/v56" + . "gopkg.in/check.v1" +) + +func (vcd *TestVCD) Test_VdcComputePoliciesV2(check *C) { + if vcd.skipAdminTests { + check.Skip(fmt.Sprintf(TestRequiresSysAdminPrivileges, check.TestName())) + } + + // Step 1 - Create a new VDC Compute Policy + newComputePolicy := &VdcComputePolicyV2{ + client: &vcd.client.Client, + VdcComputePolicyV2: &types.VdcComputePolicyV2{ + VdcComputePolicy: types.VdcComputePolicy{ + Name: check.TestName() + "_empty", + Description: "Empty policy created by test", + }, + PolicyType: "VdcVmPolicy", + }, + } + + createdPolicy, err := vcd.client.CreateVdcComputePolicyV2(newComputePolicy.VdcComputePolicyV2) + check.Assert(err, IsNil) + + AddToCleanupList(createdPolicy.VdcComputePolicyV2.ID, "vdcComputePolicy", "", check.TestName()) + + check.Assert(createdPolicy.VdcComputePolicyV2.Name, Equals, newComputePolicy.VdcComputePolicyV2.Name) + check.Assert(createdPolicy.VdcComputePolicyV2.Description, Equals, newComputePolicy.VdcComputePolicyV2.Description) + + newComputePolicy2 := &VdcComputePolicyV2{ + client: &vcd.client.Client, + VdcComputePolicyV2: &types.VdcComputePolicyV2{ + VdcComputePolicy: types.VdcComputePolicy{ + Name: check.TestName(), + Description: "Not Empty policy created by test", + CPUSpeed: takeIntAddress(100), + CPUCount: takeIntAddress(2), + CoresPerSocket: takeIntAddress(1), + CPUReservationGuarantee: takeFloatAddress(0.26), + CPULimit: takeIntAddress(200), + CPUShares: takeIntAddress(5), + Memory: takeIntAddress(1600), + MemoryReservationGuarantee: takeFloatAddress(0.5), + MemoryLimit: takeIntAddress(1200), + MemoryShares: takeIntAddress(500), + }, + PolicyType: "VdcVmPolicy", + }, + } + + createdPolicy2, err := vcd.client.CreateVdcComputePolicyV2(newComputePolicy2.VdcComputePolicyV2) + check.Assert(err, IsNil) + + AddToCleanupList(createdPolicy2.VdcComputePolicyV2.ID, "vdcComputePolicy", "", check.TestName()) + + check.Assert(createdPolicy2.VdcComputePolicyV2.Name, Equals, newComputePolicy2.VdcComputePolicyV2.Name) + check.Assert(*createdPolicy2.VdcComputePolicyV2.CPUSpeed, Equals, 100) + check.Assert(*createdPolicy2.VdcComputePolicyV2.CPUCount, Equals, 2) + check.Assert(*createdPolicy2.VdcComputePolicyV2.CoresPerSocket, Equals, 1) + check.Assert(*createdPolicy2.VdcComputePolicyV2.CPUReservationGuarantee, Equals, 0.26) + check.Assert(*createdPolicy2.VdcComputePolicyV2.CPULimit, Equals, 200) + check.Assert(*createdPolicy2.VdcComputePolicyV2.CPUShares, Equals, 5) + check.Assert(*createdPolicy2.VdcComputePolicyV2.Memory, Equals, 1600) + check.Assert(*createdPolicy2.VdcComputePolicyV2.MemoryReservationGuarantee, Equals, 0.5) + check.Assert(*createdPolicy2.VdcComputePolicyV2.MemoryLimit, Equals, 1200) + check.Assert(*createdPolicy2.VdcComputePolicyV2.MemoryShares, Equals, 500) + + // Step 2 - update + createdPolicy2.VdcComputePolicyV2.Description = "Updated description" + updatedPolicy, err := createdPolicy2.Update() + check.Assert(err, IsNil) + check.Assert(updatedPolicy.VdcComputePolicyV2, DeepEquals, createdPolicy2.VdcComputePolicyV2) + + // Step 3 - Get all VDC compute policies + allExistingPolicies, err := vcd.client.GetAllVdcComputePoliciesV2(nil) + check.Assert(err, IsNil) + check.Assert(allExistingPolicies, NotNil) + + // Step 4 - Get all VDC compute policies using query filters + for _, onePolicy := range allExistingPolicies { + + // Step 3.1 - retrieve using FIQL filter + queryParams := url.Values{} + queryParams.Add("filter", "id=="+onePolicy.VdcComputePolicyV2.ID) + + expectOnePolicyResultById, err := vcd.client.GetAllVdcComputePoliciesV2(queryParams) + check.Assert(err, IsNil) + check.Assert(len(expectOnePolicyResultById) == 1, Equals, true) + + // Step 2.2 - retrieve + exactItem, err := vcd.client.GetVdcComputePolicyV2ById(onePolicy.VdcComputePolicyV2.ID) + check.Assert(err, IsNil) + + check.Assert(err, IsNil) + check.Assert(exactItem, NotNil) + + // Step 2.3 - compare struct retrieved by using filter and the one retrieved by exact ID + check.Assert(onePolicy, DeepEquals, expectOnePolicyResultById[0]) + + } + + // Step 5 - delete + err = createdPolicy.Delete() + check.Assert(err, IsNil) + // Step 5 - try to read deleted VDC computed policy should end up with error 'ErrorEntityNotFound' + deletedPolicy, err := vcd.client.GetVdcComputePolicyV2ById(createdPolicy.VdcComputePolicyV2.ID) + check.Assert(ContainsNotFound(err), Equals, true) + check.Assert(deletedPolicy, IsNil) + + err = createdPolicy2.Delete() + check.Assert(err, IsNil) + deletedPolicy2, err := vcd.client.GetVdcComputePolicyV2ById(createdPolicy2.VdcComputePolicyV2.ID) + check.Assert(ContainsNotFound(err), Equals, true) + check.Assert(deletedPolicy2, IsNil) +} + +func (vcd *TestVCD) Test_SetAssignedComputePoliciesV2(check *C) { + if vcd.skipAdminTests { + check.Skip(fmt.Sprintf(TestRequiresSysAdminPrivileges, check.TestName())) + } + + org, err := vcd.client.GetAdminOrgByName(vcd.org.Org.Name) + check.Assert(err, IsNil) + check.Assert(org, NotNil) + + adminVdc, err := org.GetAdminVDCByName(vcd.vdc.Vdc.Name, false) + if adminVdc == nil || err != nil { + vcd.infoCleanup(notFoundMsg, "vdc", vcd.vdc.Vdc.Name) + } + + // Step 1 - Create a new VDC compute policies + newComputePolicy := &VdcComputePolicyV2{ + client: &vcd.client.Client, + VdcComputePolicyV2: &types.VdcComputePolicyV2{ + VdcComputePolicy: types.VdcComputePolicy{ + Name: check.TestName() + "1", + Description: "Policy created by Test_SetAssignedComputePolicies", + CoresPerSocket: takeIntAddress(1), + CPUReservationGuarantee: takeFloatAddress(0.26), + CPULimit: takeIntAddress(200), + }, + PolicyType: "VdcVmPolicy", + }, + } + createdPolicy, err := vcd.client.CreateVdcComputePolicyV2(newComputePolicy.VdcComputePolicyV2) + check.Assert(err, IsNil) + AddToCleanupList(createdPolicy.VdcComputePolicyV2.ID, "vdcComputePolicy", "", check.TestName()) + + newComputePolicy2 := &VdcComputePolicyV2{ + client: &vcd.client.Client, + VdcComputePolicyV2: &types.VdcComputePolicyV2{ + VdcComputePolicy: types.VdcComputePolicy{ + Name: check.TestName() + "2", + Description: "Policy created by Test_SetAssignedComputePolicies", + CoresPerSocket: takeIntAddress(2), + CPUReservationGuarantee: takeFloatAddress(0.52), + CPULimit: takeIntAddress(400), + }, + PolicyType: "VdcVmPolicy", + }, + } + createdPolicy2, err := vcd.client.CreateVdcComputePolicyV2(newComputePolicy2.VdcComputePolicyV2) + check.Assert(err, IsNil) + AddToCleanupList(createdPolicy2.VdcComputePolicyV2.ID, "vdcComputePolicy", "", check.TestName()) + + // Get default compute policy + allAssignedComputePolicies, err := adminVdc.GetAllAssignedVdcComputePoliciesV2(nil) + check.Assert(err, IsNil) + var defaultPolicyId string + for _, assignedPolicy := range allAssignedComputePolicies { + if assignedPolicy.VdcComputePolicyV2.ID == vcd.vdc.Vdc.DefaultComputePolicy.ID { + defaultPolicyId = assignedPolicy.VdcComputePolicyV2.ID + } + } + + vdcComputePolicyHref, err := org.client.OpenApiBuildEndpoint(types.OpenApiPathVersion2_0_0, types.OpenApiEndpointVdcComputePolicies) + check.Assert(err, IsNil) + + // Assign compute policies to VDC + policyReferences := types.VdcComputePolicyReferences{VdcComputePolicyReference: []*types.Reference{ + {HREF: vdcComputePolicyHref.String() + createdPolicy.VdcComputePolicyV2.ID}, + {HREF: vdcComputePolicyHref.String() + createdPolicy2.VdcComputePolicyV2.ID}, + {HREF: vdcComputePolicyHref.String() + defaultPolicyId}}} + + assignedVdcComputePolicies, err := adminVdc.SetAssignedComputePolicies(policyReferences) + check.Assert(err, IsNil) + check.Assert(strings.SplitAfter(policyReferences.VdcComputePolicyReference[0].HREF, "vdcComputePolicy:")[1], Equals, + strings.SplitAfter(assignedVdcComputePolicies.VdcComputePolicyReference[0].HREF, "vdcComputePolicy:")[1]) + check.Assert(strings.SplitAfter(policyReferences.VdcComputePolicyReference[1].HREF, "vdcComputePolicy:")[1], Equals, + strings.SplitAfter(assignedVdcComputePolicies.VdcComputePolicyReference[1].HREF, "vdcComputePolicy:")[1]) + + // cleanup assigned compute policies + policyReferences = types.VdcComputePolicyReferences{VdcComputePolicyReference: []*types.Reference{ + {HREF: vdcComputePolicyHref.String() + defaultPolicyId}}} + + _, err = adminVdc.SetAssignedComputePolicies(policyReferences) + check.Assert(err, IsNil) + + err = createdPolicy.Delete() + check.Assert(err, IsNil) + err = createdPolicy2.Delete() + check.Assert(err, IsNil) +} + +// Test_VdcVmPlacementPoliciesV2 is similar to Test_VdcComputePoliciesV2 but focused on VM Placement Policies +func (vcd *TestVCD) Test_VdcVmPlacementPoliciesV2(check *C) { + if vcd.skipAdminTests { + check.Skip(fmt.Sprintf(TestRequiresSysAdminPrivileges, check.TestName())) + } + + // We need the Provider VDC URN + pVdc, err := vcd.client.GetProviderVdcByName(vcd.config.VCD.NsxtProviderVdc.Name) + check.Assert(err, IsNil) + + // We also need the VM Group to create a VM Placement Policy + vmGroup, err := vcd.client.GetVmGroupByNameAndProviderVdcUrn(vcd.config.VCD.PlacementPolicyVmGroup, pVdc.ProviderVdc.ID) + check.Assert(err, IsNil) + check.Assert(vmGroup.VmGroup.Name, Equals, vcd.config.VCD.PlacementPolicyVmGroup) + + // We'll also use a Logical VM Group to create the VM Placement Policy + logicalVmGroup, err := vcd.client.CreateLogicalVmGroup(types.LogicalVmGroup{ + Name: check.TestName(), + NamedVmGroupReferences: types.OpenApiReferences{ + types.OpenApiReference{ + ID: fmt.Sprintf("urn:vcloud:namedVmGroup:%s", vmGroup.VmGroup.NamedVmGroupId), + Name: vmGroup.VmGroup.Name}, + }, + PvdcID: pVdc.ProviderVdc.ID, + }) + check.Assert(err, IsNil) + AddToCleanupList(logicalVmGroup.LogicalVmGroup.ID, "logicalVmGroup", "", check.TestName()) + + // Step 1 - Create a new VDC Compute Policy + newComputePolicy := &VdcComputePolicyV2{ + client: &vcd.client.Client, + VdcComputePolicyV2: &types.VdcComputePolicyV2{ + VdcComputePolicy: types.VdcComputePolicy{ + Name: check.TestName() + "_empty", + Description: "VM Placement Policy created by "+check.TestName(), + }, + PolicyType: "VdcVmPolicy", + PvdcNamedVmGroupsMap: []types.PvdcNamedVmGroupsMap{ + { + NamedVmGroups: []types.OpenApiReferences{ + { + types.OpenApiReference{ + Name: vmGroup.VmGroup.Name, + ID: fmt.Sprintf("urn:vcloud:namedVmGroup:%s", vmGroup.VmGroup.NamedVmGroupId), + }, + }, + }, + Pvdc: types.OpenApiReference{ + Name: pVdc.ProviderVdc.Name, + ID: pVdc.ProviderVdc.ID, + }, + }, + }, + PvdcLogicalVmGroupsMap: []types.PvdcLogicalVmGroupsMap{ + { + LogicalVmGroups: types.OpenApiReferences{ + types.OpenApiReference{ + Name: logicalVmGroup.LogicalVmGroup.Name, + ID: logicalVmGroup.LogicalVmGroup.ID, + }, + }, + Pvdc: types.OpenApiReference{ + Name: pVdc.ProviderVdc.Name, + ID: pVdc.ProviderVdc.ID, + }, + }, + }, + }, + } + + createdPolicy, err := vcd.client.CreateVdcComputePolicyV2(newComputePolicy.VdcComputePolicyV2) + check.Assert(err, IsNil) + + AddToCleanupList(createdPolicy.VdcComputePolicyV2.ID, "vdcComputePolicy", "", check.TestName()) + + check.Assert(createdPolicy.VdcComputePolicyV2.Name, Equals, newComputePolicy.VdcComputePolicyV2.Name) + check.Assert(createdPolicy.VdcComputePolicyV2.Description, Equals, newComputePolicy.VdcComputePolicyV2.Description) + check.Assert(createdPolicy.VdcComputePolicyV2.PvdcLogicalVmGroupsMap, DeepEquals, newComputePolicy.VdcComputePolicyV2.PvdcLogicalVmGroupsMap) + check.Assert(createdPolicy.VdcComputePolicyV2.PvdcNamedVmGroupsMap, DeepEquals, newComputePolicy.VdcComputePolicyV2.PvdcNamedVmGroupsMap) + + // Update the VM Placement Policy + createdPolicy.VdcComputePolicyV2.Description = "Updated description" + updatedPolicy, err := createdPolicy.Update() + check.Assert(err, IsNil) + check.Assert(updatedPolicy.VdcComputePolicyV2, DeepEquals, createdPolicy.VdcComputePolicyV2) + + // Delete the VM Placement Policy and check it doesn't exist anymore + err = createdPolicy.Delete() + check.Assert(err, IsNil) + deletedPolicy, err := vcd.client.GetVdcComputePolicyV2ById(createdPolicy.VdcComputePolicyV2.ID) + check.Assert(ContainsNotFound(err), Equals, true) + check.Assert(deletedPolicy, IsNil) + + // Clean up + err = logicalVmGroup.Delete() + check.Assert(err, IsNil) +} diff --git a/types/v56/openapi.go b/types/v56/openapi.go index 8c6b95f04..84aa76323 100644 --- a/types/v56/openapi.go +++ b/types/v56/openapi.go @@ -155,7 +155,8 @@ type NetworkProvider struct { ID string `json:"id"` } -// VdcComputePolicy is represented as VM sizing policy in UI +// VdcComputePolicy contains VDC specific configuration for workloads. (version 1.0.0) +// Use VdcComputePolicyV2 instead (version 2.0.0) type VdcComputePolicy struct { ID string `json:"id,omitempty"` Description string `json:"description,omitempty"` @@ -175,22 +176,40 @@ type VdcComputePolicy struct { AdditionalProp2 string `json:"additionalProp2,omitempty"` AdditionalProp3 string `json:"additionalProp3,omitempty"` } `json:"extraConfigs,omitempty"` - PvdcComputePolicyRef *struct { - Name string `json:"name,omitempty"` - ID string `json:"id,omitempty"` - } `json:"pvdcComputePolicyRef,omitempty"` - PvdcComputePolicy *struct { - Name string `json:"name,omitempty"` - ID string `json:"id,omitempty"` - } `json:"pvdcComputePolicy,omitempty"` + PvdcComputePolicyRef *OpenApiReference `json:"pvdcComputePolicyRef,omitempty"` + PvdcComputePolicy *OpenApiReference `json:"pvdcComputePolicy,omitempty"` CompatibleVdcTypes []string `json:"compatibleVdcTypes,omitempty"` IsSizingOnly bool `json:"isSizingOnly,omitempty"` PvdcID string `json:"pvdcId,omitempty"` NamedVMGroups []OpenApiReferences `json:"namedVmGroups,omitempty"` - LogicalVMGroupReferences []OpenApiReference `json:"logicalVmGroupReferences,omitempty"` + LogicalVMGroupReferences OpenApiReferences `json:"logicalVmGroupReferences,omitempty"` IsAutoGenerated bool `json:"isAutoGenerated,omitempty"` } +// VdcComputePolicyV2 contains VDC specific configuration for workloads (version 2.0.0) +// https://developer.vmware.com/apis/vmware-cloud-director/latest/data-structures/VdcComputePolicy2/ +type VdcComputePolicyV2 struct { + VdcComputePolicy + PolicyType string `json:"policyType"` // Required. Can be "VdcVmPolicy" or "VdcKubernetesPolicy" + IsVgpuPolicy bool `json:"isVgpuPolicy,omitempty"` + PvdcNamedVmGroupsMap []PvdcNamedVmGroupsMap `json:"pvdcNamedVmGroupsMap,omitempty"` + PvdcLogicalVmGroupsMap []PvdcLogicalVmGroupsMap `json:"pvdcLogicalVmGroupsMap,omitempty"` +} + +// PvdcNamedVmGroupsMap is a combination of a reference to a Provider VDC and a list of references to Named VM Groups. +// This is used for VM Placement Policies (see VdcComputePolicyV2) +type PvdcNamedVmGroupsMap struct { + NamedVmGroups []OpenApiReferences `json:"namedVmGroups,omitempty"` + Pvdc OpenApiReference `json:"pvdc,omitempty"` +} + +// PvdcLogicalVmGroupsMap is a combination of a reference to a Provider VDC and a list of references to Logical VM Groups. +// This is used for VM Placement Policies (see VdcComputePolicyV2) +type PvdcLogicalVmGroupsMap struct { + LogicalVmGroups OpenApiReferences `json:"logicalVmGroups,omitempty"` + Pvdc OpenApiReference `json:"pvdc,omitempty"` +} + // OpenApiReference is a generic reference type commonly used throughout OpenAPI endpoints type OpenApiReference struct { Name string `json:"name,omitempty"` From eb2865ae6a08328ee71e89867c07896ea8ba78e6 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Fri, 2 Sep 2022 16:02:43 +0200 Subject: [PATCH 31/48] Changelog Signed-off-by: abarreiro --- .changes/v2.17.0/502-improvements.md | 6 ++++-- .changes/v2.17.0/504-deprecations.md | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .changes/v2.17.0/504-deprecations.md diff --git a/.changes/v2.17.0/502-improvements.md b/.changes/v2.17.0/502-improvements.md index 0b5236787..2e80be25c 100644 --- a/.changes/v2.17.0/502-improvements.md +++ b/.changes/v2.17.0/502-improvements.md @@ -1,2 +1,4 @@ -* Updated VDC Compute Policies retrieval methods `AdminVdc.GetAllAssignedVdcComputePolicies` and `Org.GetAllVdcComputePolicies` - from OpenAPI v1.0.0 to v2.0.0, this version supports more filtering options like `isVgpuPolicy`[GH-502] +* Created new VDC Compute Policies CRUD methods using OpenAPI v2.0.0: + `VCDClient.GetVdcComputePolicyV2ById`, `VCDClient.GetAllVdcComputePoliciesV2`, `VCDClient.CreateVdcComputePolicyV2`, + `VdcComputePolicyV2.Update`, `VdcComputePolicyV2.Delete` and `AdminVdc.GetAllAssignedVdcComputePoliciesV2`. + This version supports more filtering options like `isVgpuPolicy` [GH-502], [GH-504] diff --git a/.changes/v2.17.0/504-deprecations.md b/.changes/v2.17.0/504-deprecations.md new file mode 100644 index 000000000..0e16d3034 --- /dev/null +++ b/.changes/v2.17.0/504-deprecations.md @@ -0,0 +1,3 @@ +* Deprecated OpenAPI v1.0.0 VDC Compute Policies CRUD methods in favor of v2.0.0 ones: + `Client.GetVdcComputePolicyById`, `Client.GetAllVdcComputePolicies`, `Client.CreateVdcComputePolicy` + `VdcComputePolicy.Update`, `VdcComputePolicy.Delete` and `AdminVdc.GetAllAssignedVdcComputePolicies` [GH-504] From f920ab99cd8272c4bd843ec32a1a43319e4ad2ce Mon Sep 17 00:00:00 2001 From: abarreiro Date: Fri, 2 Sep 2022 16:05:29 +0200 Subject: [PATCH 32/48] Changelog Signed-off-by: abarreiro --- govcd/vdccomputepolicy_v2_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/govcd/vdccomputepolicy_v2_test.go b/govcd/vdccomputepolicy_v2_test.go index 2958c7cdd..885908935 100644 --- a/govcd/vdccomputepolicy_v2_test.go +++ b/govcd/vdccomputepolicy_v2_test.go @@ -244,7 +244,7 @@ func (vcd *TestVCD) Test_VdcVmPlacementPoliciesV2(check *C) { check.Assert(err, IsNil) AddToCleanupList(logicalVmGroup.LogicalVmGroup.ID, "logicalVmGroup", "", check.TestName()) - // Step 1 - Create a new VDC Compute Policy + // Create a new VDC Compute Policy (VM Placement Policy) newComputePolicy := &VdcComputePolicyV2{ client: &vcd.client.Client, VdcComputePolicyV2: &types.VdcComputePolicyV2{ From ac02aaf8fdd6c7fbf6a01fe04cbc8dde8e631e6a Mon Sep 17 00:00:00 2001 From: abarreiro Date: Mon, 5 Sep 2022 16:39:38 +0200 Subject: [PATCH 33/48] fmt Signed-off-by: abarreiro --- govcd/vdccomputepolicy_v2_test.go | 4 ++-- types/v56/openapi.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/govcd/vdccomputepolicy_v2_test.go b/govcd/vdccomputepolicy_v2_test.go index 885908935..593d16659 100644 --- a/govcd/vdccomputepolicy_v2_test.go +++ b/govcd/vdccomputepolicy_v2_test.go @@ -250,7 +250,7 @@ func (vcd *TestVCD) Test_VdcVmPlacementPoliciesV2(check *C) { VdcComputePolicyV2: &types.VdcComputePolicyV2{ VdcComputePolicy: types.VdcComputePolicy{ Name: check.TestName() + "_empty", - Description: "VM Placement Policy created by "+check.TestName(), + Description: "VM Placement Policy created by " + check.TestName(), }, PolicyType: "VdcVmPolicy", PvdcNamedVmGroupsMap: []types.PvdcNamedVmGroupsMap{ @@ -274,7 +274,7 @@ func (vcd *TestVCD) Test_VdcVmPlacementPoliciesV2(check *C) { LogicalVmGroups: types.OpenApiReferences{ types.OpenApiReference{ Name: logicalVmGroup.LogicalVmGroup.Name, - ID: logicalVmGroup.LogicalVmGroup.ID, + ID: logicalVmGroup.LogicalVmGroup.ID, }, }, Pvdc: types.OpenApiReference{ diff --git a/types/v56/openapi.go b/types/v56/openapi.go index 84aa76323..e5ff048d6 100644 --- a/types/v56/openapi.go +++ b/types/v56/openapi.go @@ -207,7 +207,7 @@ type PvdcNamedVmGroupsMap struct { // This is used for VM Placement Policies (see VdcComputePolicyV2) type PvdcLogicalVmGroupsMap struct { LogicalVmGroups OpenApiReferences `json:"logicalVmGroups,omitempty"` - Pvdc OpenApiReference `json:"pvdc,omitempty"` + Pvdc OpenApiReference `json:"pvdc,omitempty"` } // OpenApiReference is a generic reference type commonly used throughout OpenAPI endpoints From 2a32cbbd8d60ea3f653c9a3d267c5d5e2637ee4e Mon Sep 17 00:00:00 2001 From: abarreiro Date: Tue, 6 Sep 2022 09:47:58 +0200 Subject: [PATCH 34/48] Address comments Signed-off-by: abarreiro --- govcd/vdccomputepolicy_v2_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/govcd/vdccomputepolicy_v2_test.go b/govcd/vdccomputepolicy_v2_test.go index 593d16659..811db7a0c 100644 --- a/govcd/vdccomputepolicy_v2_test.go +++ b/govcd/vdccomputepolicy_v2_test.go @@ -79,7 +79,7 @@ func (vcd *TestVCD) Test_VdcComputePoliciesV2(check *C) { check.Assert(*createdPolicy2.VdcComputePolicyV2.MemoryLimit, Equals, 1200) check.Assert(*createdPolicy2.VdcComputePolicyV2.MemoryShares, Equals, 500) - // Step 2 - update + // Step 2 - Update createdPolicy2.VdcComputePolicyV2.Description = "Updated description" updatedPolicy, err := createdPolicy2.Update() check.Assert(err, IsNil) @@ -93,7 +93,7 @@ func (vcd *TestVCD) Test_VdcComputePoliciesV2(check *C) { // Step 4 - Get all VDC compute policies using query filters for _, onePolicy := range allExistingPolicies { - // Step 3.1 - retrieve using FIQL filter + // Step 3.1 - Retrieve using FIQL filter queryParams := url.Values{} queryParams.Add("filter", "id=="+onePolicy.VdcComputePolicyV2.ID) @@ -101,22 +101,22 @@ func (vcd *TestVCD) Test_VdcComputePoliciesV2(check *C) { check.Assert(err, IsNil) check.Assert(len(expectOnePolicyResultById) == 1, Equals, true) - // Step 2.2 - retrieve + // Step 2.2 - Retrieve exactItem, err := vcd.client.GetVdcComputePolicyV2ById(onePolicy.VdcComputePolicyV2.ID) check.Assert(err, IsNil) check.Assert(err, IsNil) check.Assert(exactItem, NotNil) - // Step 2.3 - compare struct retrieved by using filter and the one retrieved by exact ID + // Step 2.3 - Compare struct retrieved by using filter and the one retrieved by exact ID check.Assert(onePolicy, DeepEquals, expectOnePolicyResultById[0]) } - // Step 5 - delete + // Step 5 - Delete err = createdPolicy.Delete() check.Assert(err, IsNil) - // Step 5 - try to read deleted VDC computed policy should end up with error 'ErrorEntityNotFound' + // Step 5 - Try to read deleted VDC computed policy should end up with error 'ErrorEntityNotFound' deletedPolicy, err := vcd.client.GetVdcComputePolicyV2ById(createdPolicy.VdcComputePolicyV2.ID) check.Assert(ContainsNotFound(err), Equals, true) check.Assert(deletedPolicy, IsNil) @@ -142,7 +142,7 @@ func (vcd *TestVCD) Test_SetAssignedComputePoliciesV2(check *C) { vcd.infoCleanup(notFoundMsg, "vdc", vcd.vdc.Vdc.Name) } - // Step 1 - Create a new VDC compute policies + // Create a new VDC compute policies newComputePolicy := &VdcComputePolicyV2{ client: &vcd.client.Client, VdcComputePolicyV2: &types.VdcComputePolicyV2{ @@ -203,7 +203,7 @@ func (vcd *TestVCD) Test_SetAssignedComputePoliciesV2(check *C) { check.Assert(strings.SplitAfter(policyReferences.VdcComputePolicyReference[1].HREF, "vdcComputePolicy:")[1], Equals, strings.SplitAfter(assignedVdcComputePolicies.VdcComputePolicyReference[1].HREF, "vdcComputePolicy:")[1]) - // cleanup assigned compute policies + // Cleanup assigned compute policies policyReferences = types.VdcComputePolicyReferences{VdcComputePolicyReference: []*types.Reference{ {HREF: vdcComputePolicyHref.String() + defaultPolicyId}}} From 0ecfb3d95d617dfdd4fc5e6a8ba497d43cd188e7 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Tue, 6 Sep 2022 10:15:07 +0200 Subject: [PATCH 35/48] Changed to pointer and non-omitempty field Signed-off-by: abarreiro --- .changes/v2.17.0/504-bug-fixes.md | 1 + govcd/sample_govcd_test_config.yaml | 3 +++ govcd/vapp_test.go | 2 +- govcd/vdccomputepolicy_test.go | 12 ++++++------ govcd/vdccomputepolicy_v2_test.go | 18 +++++++++--------- govcd/vm_test.go | 4 ++-- types/v56/openapi.go | 2 +- 7 files changed, 23 insertions(+), 19 deletions(-) create mode 100644 .changes/v2.17.0/504-bug-fixes.md diff --git a/.changes/v2.17.0/504-bug-fixes.md b/.changes/v2.17.0/504-bug-fixes.md new file mode 100644 index 000000000..777821e58 --- /dev/null +++ b/.changes/v2.17.0/504-bug-fixes.md @@ -0,0 +1 @@ +* Changed `VdcComputePolicy.Description` to a non-omitempty pointer, to be able to send null values to VCD to set empty descriptions. [GH-504] diff --git a/govcd/sample_govcd_test_config.yaml b/govcd/sample_govcd_test_config.yaml index 1232e5d20..1405f3ea7 100644 --- a/govcd/sample_govcd_test_config.yaml +++ b/govcd/sample_govcd_test_config.yaml @@ -104,6 +104,9 @@ vcd: storageProfile1: Development # Second storage profile. If omitted, some tests will be skipped. storageProfile2: "*" + # A VM Group that needs to exist in the backing vSphere. This VM Group can be used + # to create VM Placement Policies. + placementPolicyVmGroup: testVmGroup # An edge gateway # (see https://pubs.vmware.com/vca/topic/com.vmware.vcloud.api.doc_56/GUID-18B0FB8B-385C-4B6D-982C-4B24D271C646.html) edgeGateway: myedgegw diff --git a/govcd/vapp_test.go b/govcd/vapp_test.go index 818c56ba9..ebd8a8b4d 100644 --- a/govcd/vapp_test.go +++ b/govcd/vapp_test.go @@ -1507,7 +1507,7 @@ func (vcd *TestVCD) Test_AddNewVMWithComputeCapacity(check *C) { client: vcd.org.client, VdcComputePolicy: &types.VdcComputePolicy{ Name: check.TestName() + "_empty", - Description: "Empty policy created by test", + Description: takeStringPointer("Empty policy created by test"), }, } diff --git a/govcd/vdccomputepolicy_test.go b/govcd/vdccomputepolicy_test.go index 0af02b738..d11dc3af8 100644 --- a/govcd/vdccomputepolicy_test.go +++ b/govcd/vdccomputepolicy_test.go @@ -27,7 +27,7 @@ func (vcd *TestVCD) Test_VdcComputePolicies(check *C) { client: client, VdcComputePolicy: &types.VdcComputePolicy{ Name: check.TestName() + "_empty", - Description: "Empty policy created by test", + Description: takeStringPointer("Empty policy created by test"), }, } @@ -37,13 +37,13 @@ func (vcd *TestVCD) Test_VdcComputePolicies(check *C) { AddToCleanupList(createdPolicy.VdcComputePolicy.ID, "vdcComputePolicy", "", check.TestName()) check.Assert(createdPolicy.VdcComputePolicy.Name, Equals, newComputePolicy.VdcComputePolicy.Name) - check.Assert(createdPolicy.VdcComputePolicy.Description, Equals, newComputePolicy.VdcComputePolicy.Description) + check.Assert(*createdPolicy.VdcComputePolicy.Description, Equals, *newComputePolicy.VdcComputePolicy.Description) newComputePolicy2 := &VdcComputePolicy{ client: client, VdcComputePolicy: &types.VdcComputePolicy{ Name: check.TestName(), - Description: "Not Empty policy created by test", + Description: takeStringPointer("Not Empty policy created by test"), CPUSpeed: takeIntAddress(100), CPUCount: takeIntAddress(2), CoresPerSocket: takeIntAddress(1), @@ -75,7 +75,7 @@ func (vcd *TestVCD) Test_VdcComputePolicies(check *C) { check.Assert(*createdPolicy2.VdcComputePolicy.MemoryShares, Equals, 500) // Step 2 - update - createdPolicy2.VdcComputePolicy.Description = "Updated description" + createdPolicy2.VdcComputePolicy.Description = takeStringPointer("Updated description") updatedPolicy, err := createdPolicy2.Update() check.Assert(err, IsNil) check.Assert(updatedPolicy.VdcComputePolicy, DeepEquals, createdPolicy2.VdcComputePolicy) @@ -143,7 +143,7 @@ func (vcd *TestVCD) Test_SetAssignedComputePolicies(check *C) { client: org.client, VdcComputePolicy: &types.VdcComputePolicy{ Name: check.TestName() + "1", - Description: "Policy created by Test_SetAssignedComputePolicies", + Description: takeStringPointer("Policy created by Test_SetAssignedComputePolicies"), CoresPerSocket: takeIntAddress(1), CPUReservationGuarantee: takeFloatAddress(0.26), CPULimit: takeIntAddress(200), @@ -157,7 +157,7 @@ func (vcd *TestVCD) Test_SetAssignedComputePolicies(check *C) { client: org.client, VdcComputePolicy: &types.VdcComputePolicy{ Name: check.TestName() + "2", - Description: "Policy created by Test_SetAssignedComputePolicies", + Description: takeStringPointer("Policy created by Test_SetAssignedComputePolicies"), CoresPerSocket: takeIntAddress(2), CPUReservationGuarantee: takeFloatAddress(0.52), CPULimit: takeIntAddress(400), diff --git a/govcd/vdccomputepolicy_v2_test.go b/govcd/vdccomputepolicy_v2_test.go index 811db7a0c..8bf7d49f1 100644 --- a/govcd/vdccomputepolicy_v2_test.go +++ b/govcd/vdccomputepolicy_v2_test.go @@ -27,7 +27,7 @@ func (vcd *TestVCD) Test_VdcComputePoliciesV2(check *C) { VdcComputePolicyV2: &types.VdcComputePolicyV2{ VdcComputePolicy: types.VdcComputePolicy{ Name: check.TestName() + "_empty", - Description: "Empty policy created by test", + Description: takeStringPointer("Empty policy created by test"), }, PolicyType: "VdcVmPolicy", }, @@ -39,14 +39,14 @@ func (vcd *TestVCD) Test_VdcComputePoliciesV2(check *C) { AddToCleanupList(createdPolicy.VdcComputePolicyV2.ID, "vdcComputePolicy", "", check.TestName()) check.Assert(createdPolicy.VdcComputePolicyV2.Name, Equals, newComputePolicy.VdcComputePolicyV2.Name) - check.Assert(createdPolicy.VdcComputePolicyV2.Description, Equals, newComputePolicy.VdcComputePolicyV2.Description) + check.Assert(*createdPolicy.VdcComputePolicyV2.Description, Equals, *newComputePolicy.VdcComputePolicyV2.Description) newComputePolicy2 := &VdcComputePolicyV2{ client: &vcd.client.Client, VdcComputePolicyV2: &types.VdcComputePolicyV2{ VdcComputePolicy: types.VdcComputePolicy{ Name: check.TestName(), - Description: "Not Empty policy created by test", + Description: takeStringPointer("Not Empty policy created by test"), CPUSpeed: takeIntAddress(100), CPUCount: takeIntAddress(2), CoresPerSocket: takeIntAddress(1), @@ -80,7 +80,7 @@ func (vcd *TestVCD) Test_VdcComputePoliciesV2(check *C) { check.Assert(*createdPolicy2.VdcComputePolicyV2.MemoryShares, Equals, 500) // Step 2 - Update - createdPolicy2.VdcComputePolicyV2.Description = "Updated description" + createdPolicy2.VdcComputePolicyV2.Description = takeStringPointer("Updated description") updatedPolicy, err := createdPolicy2.Update() check.Assert(err, IsNil) check.Assert(updatedPolicy.VdcComputePolicyV2, DeepEquals, createdPolicy2.VdcComputePolicyV2) @@ -148,7 +148,7 @@ func (vcd *TestVCD) Test_SetAssignedComputePoliciesV2(check *C) { VdcComputePolicyV2: &types.VdcComputePolicyV2{ VdcComputePolicy: types.VdcComputePolicy{ Name: check.TestName() + "1", - Description: "Policy created by Test_SetAssignedComputePolicies", + Description: takeStringPointer("Policy created by Test_SetAssignedComputePolicies"), CoresPerSocket: takeIntAddress(1), CPUReservationGuarantee: takeFloatAddress(0.26), CPULimit: takeIntAddress(200), @@ -165,7 +165,7 @@ func (vcd *TestVCD) Test_SetAssignedComputePoliciesV2(check *C) { VdcComputePolicyV2: &types.VdcComputePolicyV2{ VdcComputePolicy: types.VdcComputePolicy{ Name: check.TestName() + "2", - Description: "Policy created by Test_SetAssignedComputePolicies", + Description: takeStringPointer("Policy created by Test_SetAssignedComputePolicies"), CoresPerSocket: takeIntAddress(2), CPUReservationGuarantee: takeFloatAddress(0.52), CPULimit: takeIntAddress(400), @@ -250,7 +250,7 @@ func (vcd *TestVCD) Test_VdcVmPlacementPoliciesV2(check *C) { VdcComputePolicyV2: &types.VdcComputePolicyV2{ VdcComputePolicy: types.VdcComputePolicy{ Name: check.TestName() + "_empty", - Description: "VM Placement Policy created by " + check.TestName(), + Description: takeStringPointer("VM Placement Policy created by " + check.TestName()), }, PolicyType: "VdcVmPolicy", PvdcNamedVmGroupsMap: []types.PvdcNamedVmGroupsMap{ @@ -292,12 +292,12 @@ func (vcd *TestVCD) Test_VdcVmPlacementPoliciesV2(check *C) { AddToCleanupList(createdPolicy.VdcComputePolicyV2.ID, "vdcComputePolicy", "", check.TestName()) check.Assert(createdPolicy.VdcComputePolicyV2.Name, Equals, newComputePolicy.VdcComputePolicyV2.Name) - check.Assert(createdPolicy.VdcComputePolicyV2.Description, Equals, newComputePolicy.VdcComputePolicyV2.Description) + check.Assert(*createdPolicy.VdcComputePolicyV2.Description, Equals, *newComputePolicy.VdcComputePolicyV2.Description) check.Assert(createdPolicy.VdcComputePolicyV2.PvdcLogicalVmGroupsMap, DeepEquals, newComputePolicy.VdcComputePolicyV2.PvdcLogicalVmGroupsMap) check.Assert(createdPolicy.VdcComputePolicyV2.PvdcNamedVmGroupsMap, DeepEquals, newComputePolicy.VdcComputePolicyV2.PvdcNamedVmGroupsMap) // Update the VM Placement Policy - createdPolicy.VdcComputePolicyV2.Description = "Updated description" + createdPolicy.VdcComputePolicyV2.Description = takeStringPointer("Updated description") updatedPolicy, err := createdPolicy.Update() check.Assert(err, IsNil) check.Assert(updatedPolicy.VdcComputePolicyV2, DeepEquals, createdPolicy.VdcComputePolicyV2) diff --git a/govcd/vm_test.go b/govcd/vm_test.go index c55efb194..2efeeeaa4 100644 --- a/govcd/vm_test.go +++ b/govcd/vm_test.go @@ -1537,7 +1537,7 @@ func (vcd *TestVCD) Test_AddNewEmptyVMWithVmComputePolicyAndUpdate(check *C) { client: vcd.org.client, VdcComputePolicy: &types.VdcComputePolicy{ Name: check.TestName() + "_empty", - Description: "Empty policy created by test", + Description: takeStringPointer("Empty policy created by test"), }, } @@ -1545,7 +1545,7 @@ func (vcd *TestVCD) Test_AddNewEmptyVMWithVmComputePolicyAndUpdate(check *C) { client: vcd.org.client, VdcComputePolicy: &types.VdcComputePolicy{ Name: check.TestName() + "_memory", - Description: "Empty policy created by test 2", + Description: takeStringPointer("Empty policy created by test 2"), Memory: takeIntAddress(2048), }, } diff --git a/types/v56/openapi.go b/types/v56/openapi.go index e5ff048d6..e2a456c40 100644 --- a/types/v56/openapi.go +++ b/types/v56/openapi.go @@ -159,7 +159,7 @@ type NetworkProvider struct { // Use VdcComputePolicyV2 instead (version 2.0.0) type VdcComputePolicy struct { ID string `json:"id,omitempty"` - Description string `json:"description,omitempty"` + Description *string `json:"description"` // It's a not-omitempty pointer to be able to send "null" values for empty descriptions. Name string `json:"name"` CPUSpeed *int `json:"cpuSpeed,omitempty"` Memory *int `json:"memory,omitempty"` From 1914a6d9ed298ebf013d0afa9bed2c8b3a419bad Mon Sep 17 00:00:00 2001 From: abarreiro Date: Tue, 6 Sep 2022 10:16:01 +0200 Subject: [PATCH 36/48] Config sample Signed-off-by: abarreiro --- govcd/sample_govcd_test_config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/govcd/sample_govcd_test_config.yaml b/govcd/sample_govcd_test_config.yaml index 1405f3ea7..56ce5fba3 100644 --- a/govcd/sample_govcd_test_config.yaml +++ b/govcd/sample_govcd_test_config.yaml @@ -107,6 +107,7 @@ vcd: # A VM Group that needs to exist in the backing vSphere. This VM Group can be used # to create VM Placement Policies. placementPolicyVmGroup: testVmGroup + # # An edge gateway # (see https://pubs.vmware.com/vca/topic/com.vmware.vcloud.api.doc_56/GUID-18B0FB8B-385C-4B6D-982C-4B24D271C646.html) edgeGateway: myedgegw From d78862c266f1a7b775d2d475c9decaf16521b3ca Mon Sep 17 00:00:00 2001 From: abarreiro Date: Tue, 6 Sep 2022 12:16:10 +0200 Subject: [PATCH 37/48] Fix resourcepool parameter Signed-off-by: abarreiro --- govcd/vm_groups.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/govcd/vm_groups.go b/govcd/vm_groups.go index 65f70a387..b7ffab4ed 100644 --- a/govcd/vm_groups.go +++ b/govcd/vm_groups.go @@ -165,7 +165,7 @@ func getVmGroupWithFilter(vcdClient *VCDClient, filter map[string]string) (*VmGr func getResourcePool(vcdClient *VCDClient, pvdcUrn string) (*types.QueryResultResourcePoolRecordType, error) { foundResourcePools, err := vcdClient.QueryWithNotEncodedParams(nil, map[string]string{ "type": "resourcePool", - "filter": fmt.Sprintf("providerVdc==%s", pvdcUrn), + "filter": fmt.Sprintf("providerVdc==%s", url.QueryEscape(pvdcUrn)), "filterEncoded": "true", }) if err != nil { From 7edd9b1bc6f7c764fbd158f05aa31518cc23eb2f Mon Sep 17 00:00:00 2001 From: abarreiro Date: Tue, 6 Sep 2022 12:21:38 +0200 Subject: [PATCH 38/48] Address suggestion Signed-off-by: abarreiro --- govcd/vdccomputepolicy_v2.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/govcd/vdccomputepolicy_v2.go b/govcd/vdccomputepolicy_v2.go index a5c137a7d..138bda32a 100644 --- a/govcd/vdccomputepolicy_v2.go +++ b/govcd/vdccomputepolicy_v2.go @@ -61,7 +61,7 @@ func (client *VCDClient) GetAllVdcComputePoliciesV2(queryParameters url.Values) return getAllVdcComputePoliciesV2(client, queryParameters) } -// getAllVdcComputePolicies retrieves all VDC Compute Policies (version 2) using OpenAPI endpoint. Query parameters can be supplied to perform additional +// getAllVdcComputePolicies retrieves all VDC Compute Policies (version 2) using OpenAPI endpoint. Query parameters can be supplied to perform additional // filtering func getAllVdcComputePoliciesV2(client *VCDClient, queryParameters url.Values) ([]*VdcComputePolicyV2, error) { endpoint := types.OpenApiPathVersion2_0_0 + types.OpenApiEndpointVdcComputePolicies From 75323f0364667b3a3596295a0cac5a66f7db3958 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Tue, 6 Sep 2022 12:22:24 +0200 Subject: [PATCH 39/48] Address suggestion Signed-off-by: abarreiro --- govcd/vdccomputepolicy_v2.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/govcd/vdccomputepolicy_v2.go b/govcd/vdccomputepolicy_v2.go index 138bda32a..b7685b7d0 100644 --- a/govcd/vdccomputepolicy_v2.go +++ b/govcd/vdccomputepolicy_v2.go @@ -19,12 +19,12 @@ type VdcComputePolicyV2 struct { client *Client } -// GetVdcComputePolicyV2ById retrieves VDC Compute Policy (version 2) by given ID +// GetVdcComputePolicyV2ById retrieves VDC Compute Policy (V2) by given ID func (client *VCDClient) GetVdcComputePolicyV2ById(id string) (*VdcComputePolicyV2, error) { return getVdcComputePolicyV2ById(client, id) } -// getVdcComputePolicyV2ById retrieves VDC Compute Policy (version 2) by given ID +// getVdcComputePolicyV2ById retrieves VDC Compute Policy (V2) by given ID func getVdcComputePolicyV2ById(client *VCDClient, id string) (*VdcComputePolicyV2, error) { endpoint := types.OpenApiPathVersion2_0_0 + types.OpenApiEndpointVdcComputePolicies minimumApiVersion, err := client.Client.checkOpenApiEndpointCompatibility(endpoint) @@ -55,13 +55,13 @@ func getVdcComputePolicyV2ById(client *VCDClient, id string) (*VdcComputePolicyV return vdcComputePolicy, nil } -// GetAllVdcComputePoliciesV2 retrieves all VDC Compute Policies (version 2) using OpenAPI endpoint. Query parameters can be supplied to perform additional +// GetAllVdcComputePoliciesV2 retrieves all VDC Compute Policies (V2) using OpenAPI endpoint. Query parameters can be supplied to perform additional // filtering func (client *VCDClient) GetAllVdcComputePoliciesV2(queryParameters url.Values) ([]*VdcComputePolicyV2, error) { return getAllVdcComputePoliciesV2(client, queryParameters) } -// getAllVdcComputePolicies retrieves all VDC Compute Policies (version 2) using OpenAPI endpoint. Query parameters can be supplied to perform additional +// getAllVdcComputePolicies retrieves all VDC Compute Policies (V2) using OpenAPI endpoint. Query parameters can be supplied to perform additional // filtering func getAllVdcComputePoliciesV2(client *VCDClient, queryParameters url.Values) ([]*VdcComputePolicyV2, error) { endpoint := types.OpenApiPathVersion2_0_0 + types.OpenApiEndpointVdcComputePolicies @@ -94,7 +94,7 @@ func getAllVdcComputePoliciesV2(client *VCDClient, queryParameters url.Values) ( return wrappedVdcComputePolicies, nil } -// CreateVdcComputePolicyV2 creates a new VDC Compute Policy (version 2) using OpenAPI endpoint +// CreateVdcComputePolicyV2 creates a new VDC Compute Policy (V2) using OpenAPI endpoint func (client *VCDClient) CreateVdcComputePolicyV2(newVdcComputePolicy *types.VdcComputePolicyV2) (*VdcComputePolicyV2, error) { endpoint := types.OpenApiPathVersion2_0_0 + types.OpenApiEndpointVdcComputePolicies minimumApiVersion, err := client.Client.checkOpenApiEndpointCompatibility(endpoint) @@ -120,7 +120,7 @@ func (client *VCDClient) CreateVdcComputePolicyV2(newVdcComputePolicy *types.Vdc return returnVdcComputePolicy, nil } -// Update existing VDC Compute Policy (version 2) +// Update existing VDC Compute Policy (V2) func (vdcComputePolicy *VdcComputePolicyV2) Update() (*VdcComputePolicyV2, error) { endpoint := types.OpenApiPathVersion2_0_0 + types.OpenApiEndpointVdcComputePolicies minimumApiVersion, err := vdcComputePolicy.client.checkOpenApiEndpointCompatibility(endpoint) @@ -150,7 +150,7 @@ func (vdcComputePolicy *VdcComputePolicyV2) Update() (*VdcComputePolicyV2, error return returnVdcComputePolicy, nil } -// Delete deletes VDC Compute Policy (version 2) +// Delete deletes VDC Compute Policy (V2) func (vdcComputePolicy *VdcComputePolicyV2) Delete() error { endpoint := types.OpenApiPathVersion2_0_0 + types.OpenApiEndpointVdcComputePolicies minimumApiVersion, err := vdcComputePolicy.client.checkOpenApiEndpointCompatibility(endpoint) @@ -176,7 +176,7 @@ func (vdcComputePolicy *VdcComputePolicyV2) Delete() error { return nil } -// GetAllAssignedVdcComputePoliciesV2 retrieves all VDC assigned Compute Policies (version 2) using OpenAPI endpoint. Query parameters can be supplied to perform additional +// GetAllAssignedVdcComputePoliciesV2 retrieves all VDC assigned Compute Policies (V2) using OpenAPI endpoint. Query parameters can be supplied to perform additional // filtering func (vdc *AdminVdc) GetAllAssignedVdcComputePoliciesV2(queryParameters url.Values) ([]*VdcComputePolicyV2, error) { endpoint := types.OpenApiPathVersion2_0_0 + types.OpenApiEndpointVdcAssignedComputePolicies From 20ad03790c56d7a7e64f6d782b776b032146fe3b Mon Sep 17 00:00:00 2001 From: abarreiro Date: Tue, 6 Sep 2022 12:24:04 +0200 Subject: [PATCH 40/48] fmt Signed-off-by: abarreiro --- types/v56/openapi.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/v56/openapi.go b/types/v56/openapi.go index e2a456c40..2311c6dc4 100644 --- a/types/v56/openapi.go +++ b/types/v56/openapi.go @@ -159,7 +159,7 @@ type NetworkProvider struct { // Use VdcComputePolicyV2 instead (version 2.0.0) type VdcComputePolicy struct { ID string `json:"id,omitempty"` - Description *string `json:"description"` // It's a not-omitempty pointer to be able to send "null" values for empty descriptions. + Description *string `json:"description"` // It's a not-omitempty pointer to be able to send "null" values for empty descriptions. Name string `json:"name"` CPUSpeed *int `json:"cpuSpeed,omitempty"` Memory *int `json:"memory,omitempty"` From f8e808fc4ec61e3cee2674ca010b9550f2e56ecb Mon Sep 17 00:00:00 2001 From: abarreiro Date: Thu, 8 Sep 2022 09:58:41 +0200 Subject: [PATCH 41/48] Amend placementPolicyVmGroup config Signed-off-by: abarreiro --- govcd/sample_govcd_test_config.yaml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/govcd/sample_govcd_test_config.yaml b/govcd/sample_govcd_test_config.yaml index 56ce5fba3..1cedc5f4a 100644 --- a/govcd/sample_govcd_test_config.yaml +++ b/govcd/sample_govcd_test_config.yaml @@ -73,6 +73,9 @@ vcd: edgeGateway: nsxt-gw-name # Existing NSX-T segment to test NSX-T Imported Org Vdc network nsxtImportSegment: vcd-org-vdc-imported-network-backing + # A VM Group that needs to exist in the backing vSphere. This VM Group can be used + # to create VM Placement Policies. + placementPolicyVmGroup: testVmGroup # An Org catalog, possibly containing at least one item catalog: name: mycat @@ -104,10 +107,6 @@ vcd: storageProfile1: Development # Second storage profile. If omitted, some tests will be skipped. storageProfile2: "*" - # A VM Group that needs to exist in the backing vSphere. This VM Group can be used - # to create VM Placement Policies. - placementPolicyVmGroup: testVmGroup - # # An edge gateway # (see https://pubs.vmware.com/vca/topic/com.vmware.vcloud.api.doc_56/GUID-18B0FB8B-385C-4B6D-982C-4B24D271C646.html) edgeGateway: myedgegw From f580cae8a4e2b1438803728a844f250e95c49bfe Mon Sep 17 00:00:00 2001 From: abarreiro Date: Thu, 8 Sep 2022 10:00:11 +0200 Subject: [PATCH 42/48] Amend placementPolicyVmGroup config Signed-off-by: abarreiro --- govcd/sample_govcd_test_config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/govcd/sample_govcd_test_config.yaml b/govcd/sample_govcd_test_config.yaml index 1cedc5f4a..1baa9bb12 100644 --- a/govcd/sample_govcd_test_config.yaml +++ b/govcd/sample_govcd_test_config.yaml @@ -58,6 +58,9 @@ vcd: name: nsxTPvdc1 storage_profile: "*" network_pool: "NSX-T Overlay 1" + # A VM Group that needs to exist in the backing vSphere. This VM Group can be used + # to create VM Placement Policies. + placementPolicyVmGroup: testVmGroup nsxt: # NSX-T manager name to be used as defined in VCD manager: nsxManager1 @@ -73,9 +76,6 @@ vcd: edgeGateway: nsxt-gw-name # Existing NSX-T segment to test NSX-T Imported Org Vdc network nsxtImportSegment: vcd-org-vdc-imported-network-backing - # A VM Group that needs to exist in the backing vSphere. This VM Group can be used - # to create VM Placement Policies. - placementPolicyVmGroup: testVmGroup # An Org catalog, possibly containing at least one item catalog: name: mycat From 8409888eb34a6c8ee7e72b17de8dcab08275c087 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Thu, 8 Sep 2022 10:03:32 +0200 Subject: [PATCH 43/48] Amend placementPolicyVmGroup config Signed-off-by: abarreiro --- govcd/api_vcd_test.go | 8 ++++---- govcd/vdccomputepolicy_v2_test.go | 4 ++-- govcd/vm_groups_test.go | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/govcd/api_vcd_test.go b/govcd/api_vcd_test.go index 985989154..5be5b6d73 100644 --- a/govcd/api_vcd_test.go +++ b/govcd/api_vcd_test.go @@ -134,9 +134,10 @@ type TestConfig struct { NetworkPool string `yaml:"network_pool"` } `yaml:"provider_vdc"` NsxtProviderVdc struct { - Name string `yaml:"name"` - StorageProfile string `yaml:"storage_profile"` - NetworkPool string `yaml:"network_pool"` + Name string `yaml:"name"` + StorageProfile string `yaml:"storage_profile"` + NetworkPool string `yaml:"network_pool"` + PlacementPolicyVmGroup string `yaml:"placementPolicyVmGroup,omitempty"` } `yaml:"nsxt_provider_vdc"` Catalog struct { Name string `yaml:"name,omitempty"` @@ -154,7 +155,6 @@ type TestConfig struct { SP1 string `yaml:"storageProfile1"` SP2 string `yaml:"storageProfile2,omitempty"` } `yaml:"storageProfile"` - PlacementPolicyVmGroup string `yaml:"placementPolicyVmGroup,omitempty"` ExternalIp string `yaml:"externalIp,omitempty"` ExternalNetmask string `yaml:"externalNetmask,omitempty"` InternalIp string `yaml:"internalIp,omitempty"` diff --git a/govcd/vdccomputepolicy_v2_test.go b/govcd/vdccomputepolicy_v2_test.go index 8bf7d49f1..740f5c776 100644 --- a/govcd/vdccomputepolicy_v2_test.go +++ b/govcd/vdccomputepolicy_v2_test.go @@ -227,9 +227,9 @@ func (vcd *TestVCD) Test_VdcVmPlacementPoliciesV2(check *C) { check.Assert(err, IsNil) // We also need the VM Group to create a VM Placement Policy - vmGroup, err := vcd.client.GetVmGroupByNameAndProviderVdcUrn(vcd.config.VCD.PlacementPolicyVmGroup, pVdc.ProviderVdc.ID) + vmGroup, err := vcd.client.GetVmGroupByNameAndProviderVdcUrn(vcd.config.VCD.NsxtProviderVdc.PlacementPolicyVmGroup, pVdc.ProviderVdc.ID) check.Assert(err, IsNil) - check.Assert(vmGroup.VmGroup.Name, Equals, vcd.config.VCD.PlacementPolicyVmGroup) + check.Assert(vmGroup.VmGroup.Name, Equals, vcd.config.VCD.NsxtProviderVdc.PlacementPolicyVmGroup) // We'll also use a Logical VM Group to create the VM Placement Policy logicalVmGroup, err := vcd.client.CreateLogicalVmGroup(types.LogicalVmGroup{ diff --git a/govcd/vm_groups_test.go b/govcd/vm_groups_test.go index 85903f232..429fabef1 100644 --- a/govcd/vm_groups_test.go +++ b/govcd/vm_groups_test.go @@ -19,20 +19,20 @@ func (vcd *TestVCD) Test_VmGroupsCRUD(check *C) { check.Skip(fmt.Sprintf(TestRequiresSysAdminPrivileges, check.TestName())) } - if vcd.config.VCD.PlacementPolicyVmGroup == "" { - check.Skip(fmt.Sprintf("%s test requires vcd.placementPolicyVmGroup configuration", check.TestName())) + if vcd.config.VCD.NsxtProviderVdc.PlacementPolicyVmGroup == "" { + check.Skip(fmt.Sprintf("%s test requires vcd.nsxt_provider_vdc.placementPolicyVmGroup configuration", check.TestName())) } if vcd.config.VCD.NsxtProviderVdc.Name == "" { - check.Skip(fmt.Sprintf("%s test requires vcd.nsxtProviderVdc configuration", check.TestName())) + check.Skip(fmt.Sprintf("%s test requires vcd.nsxt_provider_vdc configuration", check.TestName())) } // We need the Provider VDC URN pVdc, err := vcd.client.GetProviderVdcByName(vcd.config.VCD.NsxtProviderVdc.Name) check.Assert(err, IsNil) - vmGroup, err := vcd.client.GetVmGroupByNameAndProviderVdcUrn(vcd.config.VCD.PlacementPolicyVmGroup, pVdc.ProviderVdc.ID) + vmGroup, err := vcd.client.GetVmGroupByNameAndProviderVdcUrn(vcd.config.VCD.NsxtProviderVdc.PlacementPolicyVmGroup, pVdc.ProviderVdc.ID) check.Assert(err, IsNil) - check.Assert(vmGroup.VmGroup.Name, Equals, vcd.config.VCD.PlacementPolicyVmGroup) + check.Assert(vmGroup.VmGroup.Name, Equals, vcd.config.VCD.NsxtProviderVdc.PlacementPolicyVmGroup) vmGroup2, err := vcd.client.GetVmGroupById(vmGroup.VmGroup.ID) check.Assert(err, IsNil) From 316e37e3abe91027c467dc0aead365bb7ce0d5c0 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Mon, 12 Sep 2022 09:35:10 +0200 Subject: [PATCH 44/48] Fix cleanup error Signed-off-by: abarreiro --- govcd/api_vcd_test.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/govcd/api_vcd_test.go b/govcd/api_vcd_test.go index 5be5b6d73..f485fafe2 100644 --- a/govcd/api_vcd_test.go +++ b/govcd/api_vcd_test.go @@ -1532,7 +1532,7 @@ func (vcd *TestVCD) removeLeftoverEntities(entity CleanupEntity) { return case "vdcComputePolicy": - policy, err := vcd.client.Client.GetVdcComputePolicyById(entity.Name) + policy, err := vcd.client.GetVdcComputePolicyV2ById(entity.Name) if policy == nil || err != nil { vcd.infoCleanup(notFoundMsg, "vdcComputePolicy", entity.Name) return @@ -1545,6 +1545,20 @@ func (vcd *TestVCD) removeLeftoverEntities(entity CleanupEntity) { } return + case "logicalVmGroup": + logicalVmGroup, err := vcd.client.GetLogicalVmGroupById(entity.Name) + if logicalVmGroup == nil || err != nil { + vcd.infoCleanup(notFoundMsg, "logicalVmGroup", entity.Name) + return + } + err = logicalVmGroup.Delete() + if err == nil { + vcd.infoCleanup(removedMsg, entity.EntityType, entity.Name, entity.CreatedBy) + } else { + vcd.infoCleanup(notDeletedMsg, entity.EntityType, entity.Name, err) + } + return + default: // If we reach this point, we are trying to clean up an entity that // we aren't prepared for yet. From ea7ecb2233601887c2599de2878d2f03d239be41 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Mon, 12 Sep 2022 10:04:10 +0200 Subject: [PATCH 45/48] Fix problems with tests Signed-off-by: abarreiro --- govcd/provider_vdc_test.go | 45 +++++++++++++++++++++++++++---- govcd/vdccomputepolicy_v2_test.go | 4 +++ 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/govcd/provider_vdc_test.go b/govcd/provider_vdc_test.go index 9add5e633..4125c3dd4 100644 --- a/govcd/provider_vdc_test.go +++ b/govcd/provider_vdc_test.go @@ -32,12 +32,26 @@ func (vcd *TestVCD) Test_GetProviderVdc(check *C) { // Common asserts for _, providerVdc := range providerVdcs { check.Assert(providerVdc.ProviderVdc.Name, Equals, vcd.config.VCD.NsxtProviderVdc.Name) - check.Assert(providerVdc.ProviderVdc.StorageProfiles.ProviderVdcStorageProfile[0].Name, Equals, vcd.config.VCD.NsxtProviderVdc.StorageProfile) + foundStorageProfile := false + for _, storageProfile := range providerVdc.ProviderVdc.StorageProfiles.ProviderVdcStorageProfile { + if storageProfile.Name == vcd.config.VCD.NsxtProviderVdc.StorageProfile { + foundStorageProfile = true + break + } + } + check.Assert(foundStorageProfile, Equals, true) check.Assert(*providerVdc.ProviderVdc.IsEnabled, Equals, true) check.Assert(providerVdc.ProviderVdc.ComputeCapacity, NotNil) check.Assert(providerVdc.ProviderVdc.Status, Equals, 1) check.Assert(len(providerVdc.ProviderVdc.NetworkPoolReferences.NetworkPoolReference), Equals, 1) - check.Assert(providerVdc.ProviderVdc.NetworkPoolReferences.NetworkPoolReference[0].Name, Equals, vcd.config.VCD.NsxtProviderVdc.NetworkPool) + foundNetworkPool := false + for _, networkPool := range providerVdc.ProviderVdc.NetworkPoolReferences.NetworkPoolReference { + if networkPool.Name == vcd.config.VCD.NsxtProviderVdc.NetworkPool { + foundNetworkPool = true + break + } + } + check.Assert(foundNetworkPool, Equals, true) check.Assert(providerVdc.ProviderVdc.Link, NotNil) } } @@ -62,12 +76,26 @@ func (vcd *TestVCD) Test_GetProviderVdcExtended(check *C) { for _, providerVdcExtended := range providerVdcsExtended { // Basic PVDC asserts check.Assert(providerVdcExtended.VMWProviderVdc.Name, Equals, vcd.config.VCD.NsxtProviderVdc.Name) - check.Assert(providerVdcExtended.VMWProviderVdc.StorageProfiles.ProviderVdcStorageProfile[0].Name, Equals, vcd.config.VCD.NsxtProviderVdc.StorageProfile) + foundStorageProfile := false + for _, storageProfile := range providerVdcExtended.VMWProviderVdc.StorageProfiles.ProviderVdcStorageProfile { + if storageProfile.Name == vcd.config.VCD.NsxtProviderVdc.StorageProfile { + foundStorageProfile = true + break + } + } + check.Assert(foundStorageProfile, Equals, true) check.Assert(*providerVdcExtended.VMWProviderVdc.IsEnabled, Equals, true) check.Assert(providerVdcExtended.VMWProviderVdc.ComputeCapacity, NotNil) check.Assert(providerVdcExtended.VMWProviderVdc.Status, Equals, 1) check.Assert(len(providerVdcExtended.VMWProviderVdc.NetworkPoolReferences.NetworkPoolReference), Equals, 1) - check.Assert(providerVdcExtended.VMWProviderVdc.NetworkPoolReferences.NetworkPoolReference[0].Name, Equals, vcd.config.VCD.NsxtProviderVdc.NetworkPool) + foundNetworkPool := false + for _, networkPool := range providerVdcExtended.VMWProviderVdc.NetworkPoolReferences.NetworkPoolReference { + if networkPool.Name == vcd.config.VCD.NsxtProviderVdc.NetworkPool { + foundNetworkPool = true + break + } + } + check.Assert(foundNetworkPool, Equals, true) check.Assert(providerVdcExtended.VMWProviderVdc.Link, NotNil) // Extended PVDC asserts check.Assert(providerVdcExtended.VMWProviderVdc.ComputeProviderScope, Equals, "vc1") @@ -116,7 +144,14 @@ func (vcd *TestVCD) Test_GetProviderVdcConvertFromExtendedToNormal(check *C) { providerVdc, err := providerVdcExtended.ToProviderVdc() check.Assert(err, IsNil) check.Assert(providerVdc.ProviderVdc.Name, Equals, vcd.config.VCD.NsxtProviderVdc.Name) - check.Assert(providerVdc.ProviderVdc.StorageProfiles.ProviderVdcStorageProfile[0].Name, Equals, vcd.config.VCD.NsxtProviderVdc.StorageProfile) + foundStorageProfile := false + for _, storageProfile := range providerVdc.ProviderVdc.StorageProfiles.ProviderVdcStorageProfile { + if storageProfile.Name == vcd.config.VCD.NsxtProviderVdc.StorageProfile { + foundStorageProfile = true + break + } + } + check.Assert(foundStorageProfile, Equals, true) check.Assert(*providerVdc.ProviderVdc.IsEnabled, Equals, true) check.Assert(providerVdc.ProviderVdc.Status, Equals, 1) check.Assert(len(providerVdc.ProviderVdc.NetworkPoolReferences.NetworkPoolReference), Equals, 1) diff --git a/govcd/vdccomputepolicy_v2_test.go b/govcd/vdccomputepolicy_v2_test.go index 740f5c776..eec89854f 100644 --- a/govcd/vdccomputepolicy_v2_test.go +++ b/govcd/vdccomputepolicy_v2_test.go @@ -222,6 +222,10 @@ func (vcd *TestVCD) Test_VdcVmPlacementPoliciesV2(check *C) { check.Skip(fmt.Sprintf(TestRequiresSysAdminPrivileges, check.TestName())) } + if vcd.config.VCD.NsxtProviderVdc.PlacementPolicyVmGroup == "" { + check.Skip("The configuration entry vcd.nsxt_provider_vdc.placementPolicyVmGroup is needed") + } + // We need the Provider VDC URN pVdc, err := vcd.client.GetProviderVdcByName(vcd.config.VCD.NsxtProviderVdc.Name) check.Assert(err, IsNil) From 8122bc8883f9aa0cdb0ea0535ab02680083ff769 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Mon, 12 Sep 2022 10:22:23 +0200 Subject: [PATCH 46/48] Add constant Signed-off-by: abarreiro --- govcd/vdccomputepolicy_v2_test.go | 4 ++-- govcd/vm_groups.go | 4 ++++ govcd/vm_groups_test.go | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/govcd/vdccomputepolicy_v2_test.go b/govcd/vdccomputepolicy_v2_test.go index eec89854f..88d5472b4 100644 --- a/govcd/vdccomputepolicy_v2_test.go +++ b/govcd/vdccomputepolicy_v2_test.go @@ -240,7 +240,7 @@ func (vcd *TestVCD) Test_VdcVmPlacementPoliciesV2(check *C) { Name: check.TestName(), NamedVmGroupReferences: types.OpenApiReferences{ types.OpenApiReference{ - ID: fmt.Sprintf("urn:vcloud:namedVmGroup:%s", vmGroup.VmGroup.NamedVmGroupId), + ID: fmt.Sprintf("%s:%s", vmGroupUrnPrefix, vmGroup.VmGroup.NamedVmGroupId), Name: vmGroup.VmGroup.Name}, }, PvdcID: pVdc.ProviderVdc.ID, @@ -263,7 +263,7 @@ func (vcd *TestVCD) Test_VdcVmPlacementPoliciesV2(check *C) { { types.OpenApiReference{ Name: vmGroup.VmGroup.Name, - ID: fmt.Sprintf("urn:vcloud:namedVmGroup:%s", vmGroup.VmGroup.NamedVmGroupId), + ID: fmt.Sprintf("%s:%s", vmGroupUrnPrefix, vmGroup.VmGroup.NamedVmGroupId), }, }, }, diff --git a/govcd/vm_groups.go b/govcd/vm_groups.go index b7ffab4ed..76bdf6dac 100644 --- a/govcd/vm_groups.go +++ b/govcd/vm_groups.go @@ -18,6 +18,10 @@ type VmGroup struct { client *Client } +// This constant is useful when managing Logical VM Groups by referencing VM Groups, as these are +// XML based and don't deal with IDs with full URNs, while Logical VM Groups are OpenAPI based and they do. +const vmGroupUrnPrefix = "urn:vcloud:namedVmGroup" + // GetVmGroupById finds a VM Group by its ID. // On success, returns a pointer to the VmGroup structure and a nil error // On failure, returns a nil pointer and an error diff --git a/govcd/vm_groups_test.go b/govcd/vm_groups_test.go index 429fabef1..34fd33bc0 100644 --- a/govcd/vm_groups_test.go +++ b/govcd/vm_groups_test.go @@ -46,7 +46,7 @@ func (vcd *TestVCD) Test_VmGroupsCRUD(check *C) { Name: check.TestName(), NamedVmGroupReferences: types.OpenApiReferences{ types.OpenApiReference{ - ID: fmt.Sprintf("urn:vcloud:namedVmGroup:%s", vmGroup.VmGroup.NamedVmGroupId), + ID: fmt.Sprintf("%s:%s", vmGroupUrnPrefix, vmGroup.VmGroup.NamedVmGroupId), Name: vmGroup.VmGroup.Name}, }, PvdcID: pVdc.ProviderVdc.ID, From 6e27d54b9693bbae4393d1f8b3d1e061a1a16195 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Mon, 12 Sep 2022 10:30:04 +0200 Subject: [PATCH 47/48] Remove confusing comment Signed-off-by: abarreiro --- govcd/openapi_endpoints.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/govcd/openapi_endpoints.go b/govcd/openapi_endpoints.go index d0d357cd8..9e0d61292 100644 --- a/govcd/openapi_endpoints.go +++ b/govcd/openapi_endpoints.go @@ -30,7 +30,7 @@ var endpointMinApiVersions = map[string]string{ // OpenApiEndpointExternalNetworks endpoint support was introduced with version 32.0 however it was still not stable // enough to be used. (i.e. it did not support update "PUT") types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointExternalNetworks: "33.0", - types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcComputePolicies: "32.0", // Deprecated in favor of v2.0.0 + types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcComputePolicies: "32.0", types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcAssignedComputePolicies: "33.0", types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointSessionCurrent: "34.0", types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointEdgeClusters: "34.0", // VCD 10.1+ From 68117f5c275aa60c27b188613b4baa85e7666cd9 Mon Sep 17 00:00:00 2001 From: abarreiro Date: Thu, 22 Sep 2022 11:07:14 +0200 Subject: [PATCH 48/48] Add Deprecated note to VdcComputePolicy Signed-off-by: abarreiro --- types/v56/openapi.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/v56/openapi.go b/types/v56/openapi.go index 2311c6dc4..2ac05c705 100644 --- a/types/v56/openapi.go +++ b/types/v56/openapi.go @@ -156,7 +156,7 @@ type NetworkProvider struct { } // VdcComputePolicy contains VDC specific configuration for workloads. (version 1.0.0) -// Use VdcComputePolicyV2 instead (version 2.0.0) +// Deprecated: Use VdcComputePolicyV2 instead (version 2.0.0) type VdcComputePolicy struct { ID string `json:"id,omitempty"` Description *string `json:"description"` // It's a not-omitempty pointer to be able to send "null" values for empty descriptions.