Skip to content

Commit

Permalink
Add support for Provider VDCs read functions and upgrade OpenAPI Comp…
Browse files Browse the repository at this point in the history
…ute Policies version to v2.0.0 (#502)

* Add read functions for Provider VDCs and extended flavor of Provider VDCs
* Upgrade some Compute Policy retrieval functions from OpenAPI 1.0.0 to 2.0.0

Signed-off-by: abarreiro <abarreiro@vmware.com>
  • Loading branch information
adambarreiro authored Sep 1, 2022
1 parent cc66003 commit 6176f3e
Show file tree
Hide file tree
Showing 13 changed files with 497 additions and 8 deletions.
4 changes: 4 additions & 0 deletions .changes/v2.17.0/502-features.md
Original file line number Diff line number Diff line change
@@ -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`, `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]
2 changes: 2 additions & 0 deletions .changes/v2.17.0/502-improvements.md
Original file line number Diff line number Diff line change
@@ -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]
15 changes: 14 additions & 1 deletion govcd/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -776,7 +776,20 @@ 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)
}

// Retrieves the admin extension 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)
}

// TestConnection calls API to test a connection against a VCD, including SSL handshake and hostname verification.
Expand Down
4 changes: 2 additions & 2 deletions govcd/api_vcd_test.go
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
4 changes: 2 additions & 2 deletions govcd/common_test.go
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
80 changes: 80 additions & 0 deletions govcd/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
11 changes: 11 additions & 0 deletions govcd/metadata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 4 additions & 1 deletion govcd/openapi_endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ 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",
types.OpenApiPathVersion2_0_0 + types.OpenApiEndpointVdcComputePolicies: "35.0",
}

// elevateNsxtNatRuleApiVersion helps to elevate API version to consume newer NSX-T NAT Rule features
Expand Down Expand Up @@ -126,7 +129,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) {
Expand Down
178 changes: 178 additions & 0 deletions govcd/provider_vdc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package govcd

import (
"fmt"
"github.com/vmware/go-vcloud-director/v2/types/v56"
"net/http"
"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),
client: cli,
}
}

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
func (vcdClient *VCDClient) GetProviderVdcByHref(providerVdcHref string) (*ProviderVdc, error) {
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
}

// 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
func (vcdClient *VCDClient) GetProviderVdcById(providerVdcId string) (*ProviderVdc, error) {
providerVdcHref := vcdClient.Client.VCDHREF
providerVdcHref.Path += "/admin/providervdc/" + extractUuid(providerVdcId)

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) {
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.
func (providerVdc *ProviderVdc) Refresh() error {
if providerVdc.ProviderVdc.HREF == "" {
return fmt.Errorf("cannot refresh, receiver Provider VDC 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
}

// Refresh updates the contents of the extended Provider VDC associated to the receiver object.
func (providerVdcExtended *ProviderVdcExtended) Refresh() error {
if providerVdcExtended.VMWProviderVdc.HREF == "" {
return fmt.Errorf("cannot refresh, receiver extended Provider VDC is empty")
}

unmarshalledVdc := &types.VMWProviderVdc{}

_, err := providerVdcExtended.client.ExecuteRequest(providerVdcExtended.VMWProviderVdc.HREF, http.MethodGet,
"", "error refreshing extended Provider VDC: %s", nil, unmarshalledVdc)
if err != nil {
return err
}

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
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)
}
Loading

0 comments on commit 6176f3e

Please sign in to comment.