Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for VDC Network Profile configuration #512

Merged
merged 14 commits into from
Nov 15, 2022
1 change: 0 additions & 1 deletion .changes/v2.17.0/505-improvements.md
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
* Simplify `Test_LDAP` by using a pre-configured LDAP server [GH-505]

4 changes: 4 additions & 0 deletions .changes/v2.17.0/512-improvements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
* Added VCDClient.GetAllNsxtEdgeClusters for lookup of NSX-T Edge Clusters in wider scopes -
Provider VDC, VDC Group or VDC [GH-512]
* Switch VDC.GetAllNsxtEdgeClusters to use 'orgVdcId' filter instead of '_context' (now deprecated)
[GH-512]
1 change: 1 addition & 0 deletions govcd/api_vcd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ type TestConfig struct {
NsxtImportSegment string `yaml:"nsxtImportSegment"`
VdcGroup string `yaml:"vdcGroup"`
VdcGroupEdgeGateway string `yaml:"vdcGroupEdgeGateway"`
NsxtEdgeCluster string `yaml:"nsxtEdgeCluster"`

NsxtAlbControllerUrl string `yaml:"nsxtAlbControllerUrl"`
NsxtAlbControllerUser string `yaml:"nsxtAlbControllerUser"`
Expand Down
47 changes: 33 additions & 14 deletions govcd/nsxt_edge_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ func filterNsxtEdgeClusters(name string, allNnsxtEdgeCluster []*NsxtEdgeCluster)
}

return filteredNsxtEdgeClusters

}

// GetAllNsxtEdgeClusters retrieves all available Edge Clusters for a particular VDC
Expand All @@ -77,28 +76,48 @@ func (vdc *Vdc) GetAllNsxtEdgeClusters(queryParameters url.Values) ([]*NsxtEdgeC
return nil, fmt.Errorf("VDC must have ID populated to retrieve NSX-T edge clusters")
}

// Get all NSX-T Edge clusters that are accessible to an organization VDC. The 'orgVdcId'filter
// key must be set with the ID of the VDC for which we want to get available Edge Clusters for.
//
// orgVdcId==urn:vcloud:vdc:09722307-aee0-4623-af95-7f8e577c9ebc

// Create a copy of queryParameters so that original queryParameters are not mutated (because a map is always a
// reference)
queryParams := queryParameterFilterAnd("orgVdcId=="+vdc.Vdc.ID, queryParameters)

return getAllNsxtEdgeClusters(vdc.client, queryParams)
}

// GetAllNsxtEdgeClusters retrieves all NSX-T Edge Clusters in the system
//
// A filter is mandatory as otherwise request will fail
// orgVdcId - | The filter orgVdcId must be set equal to the id of the NSX-T backed Org vDC for
// which we want to get the edge clusters. Example:
// (orgVdcId==urn:vcloud:vdc:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
// vdcGroupId - | The filter vdcGroupId must be set equal to the id of the NSX-T VDC Group for which
// we want to get the edge clusters. Example:
// (vdcGroupId==urn:vcloud:vdcGroup:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
// pvdcId - | The filter pvdcId must be set equal to the id of the NSX-T backed Provider VDC for
// which we want to get the edge clusters. pvdcId filter is supported from version 35.2 Example:
// (pvdcId==urn:vcloud:providervdc:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
func (vcdClient *VCDClient) GetAllNsxtEdgeClusters(queryParameters url.Values) ([]*NsxtEdgeCluster, error) {
return getAllNsxtEdgeClusters(&vcdClient.Client, queryParameters)
}

func getAllNsxtEdgeClusters(client *Client, queryParams url.Values) ([]*NsxtEdgeCluster, error) {
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointEdgeClusters
minimumApiVersion, err := vdc.client.checkOpenApiEndpointCompatibility(endpoint)
apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint)
if err != nil {
return nil, err
}

urlRef, err := vdc.client.OpenApiBuildEndpoint(endpoint)
urlRef, err := client.OpenApiBuildEndpoint(endpoint)
if err != nil {
return nil, err
}

// Get all NSX-T Edge clusters that are accessible to an organization VDC. The “_context” filter key must be set with
// the ID of the VDC for which we want to get available Edge Clusters for.
//
// _context==urn:vcloud:vdc:09722307-aee0-4623-af95-7f8e577c9ebc

// Create a copy of queryParameters so that original queryParameters are not mutated (because a map is always a
// reference)
queryParams := queryParameterFilterAnd("_context=="+vdc.Vdc.ID, queryParameters)

typeResponses := []*types.NsxtEdgeCluster{{}}
err = vdc.client.OpenApiGetAllItems(minimumApiVersion, urlRef, queryParams, &typeResponses, nil)
err = client.OpenApiGetAllItems(apiVersion, urlRef, queryParams, &typeResponses, nil)
if err != nil {
return nil, err
}
Expand All @@ -107,7 +126,7 @@ func (vdc *Vdc) GetAllNsxtEdgeClusters(queryParameters url.Values) ([]*NsxtEdgeC
for sliceIndex := range typeResponses {
returnObjects[sliceIndex] = &NsxtEdgeCluster{
NsxtEdgeCluster: typeResponses[sliceIndex],
client: vdc.client,
client: client,
}
}

Expand Down
24 changes: 14 additions & 10 deletions govcd/nsxt_edge_cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package govcd

import (
"fmt"
"net/url"

. "gopkg.in/check.v1"
)
Expand All @@ -23,10 +24,17 @@ func (vcd *TestVCD) Test_GetAllNsxtEdgeClusters(check *C) {
nsxtVdc, err := vcd.org.GetVDCByNameOrId(vcd.config.VCD.Nsxt.Vdc, true)
check.Assert(err, IsNil)

tier0Router, err := nsxtVdc.GetAllNsxtEdgeClusters(nil)
edgeClusters, err := nsxtVdc.GetAllNsxtEdgeClusters(nil)
check.Assert(err, IsNil)
check.Assert(tier0Router, NotNil)
check.Assert(len(tier0Router) > 0, Equals, true)
check.Assert(edgeClusters, NotNil)
check.Assert(len(edgeClusters) > 0, Equals, true)

queryParams := url.Values{}
queryParams.Add("filter", fmt.Sprintf("orgVdcId==%s", nsxtVdc.Vdc.ID))
allEdgeClusters, err := vcd.client.GetAllNsxtEdgeClusters(queryParams)
check.Assert(err, IsNil)
check.Assert(allEdgeClusters, NotNil)
check.Assert(len(allEdgeClusters) > 0, Equals, true)
}

func (vcd *TestVCD) Test_GetNsxtEdgeClusterByName(check *C) {
Expand All @@ -39,13 +47,9 @@ func (vcd *TestVCD) Test_GetNsxtEdgeClusterByName(check *C) {
nsxtVdc, err := vcd.org.GetVDCByNameOrId(vcd.config.VCD.Nsxt.Vdc, true)
check.Assert(err, IsNil)

allEdgeClusters, err := nsxtVdc.GetAllNsxtEdgeClusters(nil)
edgeCluster, err := nsxtVdc.GetNsxtEdgeClusterByName(vcd.config.VCD.Nsxt.NsxtEdgeCluster)
check.Assert(err, IsNil)
check.Assert(allEdgeClusters, NotNil)

edgeCluster, err := nsxtVdc.GetNsxtEdgeClusterByName(allEdgeClusters[0].NsxtEdgeCluster.Name)
check.Assert(err, IsNil)
check.Assert(allEdgeClusters, NotNil)
check.Assert(edgeCluster, DeepEquals, allEdgeClusters[0])
check.Assert(edgeCluster, NotNil)
check.Assert(edgeCluster.NsxtEdgeCluster.Name, Equals, vcd.config.VCD.Nsxt.NsxtEdgeCluster)

}
5 changes: 5 additions & 0 deletions govcd/openapi_endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ var endpointMinApiVersions = map[string]string{

types.OpenApiPathVersion2_0_0 + types.OpenApiEndpointVdcAssignedComputePolicies: "35.0",
types.OpenApiPathVersion2_0_0 + types.OpenApiEndpointVdcComputePolicies: "35.0",
types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcNetworkProfile: "36.0", // VCD 10.3+
}

// elevateNsxtNatRuleApiVersion helps to elevate API version to consume newer NSX-T NAT Rule features
Expand Down Expand Up @@ -121,6 +122,10 @@ var endpointElevatedApiVersions = map[string][]string{
//"35.0", // Basic minimum required version
"37.0", // Deprecates LicenseType in favor of SupportedFeatureSet
},
types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcNetworkProfile: {
//"36.0", // Introduced support
"36.2", // 2 additional fields vappNetworkSegmentProfileTemplateRef and vdcNetworkSegmentProfileTemplateRef added
},
}

// checkOpenApiEndpointCompatibility checks if VCD version (to which the client is connected) is sufficient to work with
Expand Down
2 changes: 2 additions & 0 deletions govcd/sample_govcd_test_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ vcd:
edgeGateway: nsxt-gw-name
# Existing NSX-T segment to test NSX-T Imported Org Vdc network
nsxtImportSegment: vcd-org-vdc-imported-network-backing
# Existing NSX-T Edge Cluster name
nsxtEdgeCluster: existing-nsxt-edge-cluster
# An Org catalog, possibly containing at least one item
catalog:
name: mycat
Expand Down
146 changes: 146 additions & 0 deletions govcd/vdc_network_profile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/*
* Copyright 2022 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
*/

package govcd

import (
"fmt"

"github.com/vmware/go-vcloud-director/v2/types/v56"
)

// VDC Network profiles have 1:1 mapping with VDC - each VDC has an option to configure VDC Network
// Profiles. types.VdcNetworkProfile holds more information about possible configurations

// GetVdcNetworkProfile retrieves VDC Network Profile configuration
// vdc.Vdc.ID must be set and valid present
func (vdc *Vdc) GetVdcNetworkProfile() (*types.VdcNetworkProfile, error) {
if vdc == nil || vdc.Vdc == nil || vdc.Vdc.ID == "" {
return nil, fmt.Errorf("cannot lookup VDC Network Profile configuration without VDC ID")
}

return getVdcNetworkProfile(vdc.client, vdc.Vdc.ID)
}

// GetVdcNetworkProfile retrieves VDC Network Profile configuration
// vdc.Vdc.ID must be set and valid present
func (adminVdc *AdminVdc) GetVdcNetworkProfile() (*types.VdcNetworkProfile, error) {
if adminVdc == nil || adminVdc.AdminVdc == nil || adminVdc.AdminVdc.ID == "" {
return nil, fmt.Errorf("cannot lookup VDC Network Profile configuration without VDC ID")
}

return getVdcNetworkProfile(adminVdc.client, adminVdc.AdminVdc.ID)
}

// UpdateVdcNetworkProfile updates the VDC Network Profile configuration
//
// Note. Whenever updating VDC Network Profile it is required to send all fields (not only the
// changed ones) as VCD will remove other configuration. Best practice is to fetch current
// configuration of VDC Network Profile using GetVdcNetworkProfile, alter it with new values and
// submit it to UpdateVdcNetworkProfile.
func (vdc *Vdc) UpdateVdcNetworkProfile(vdcNetworkProfileConfig *types.VdcNetworkProfile) (*types.VdcNetworkProfile, error) {
if vdc == nil || vdc.Vdc == nil || vdc.Vdc.ID == "" {
return nil, fmt.Errorf("cannot update VDC Network Profile configuration without ID")
}

return updateVdcNetworkProfile(vdc.client, vdc.Vdc.ID, vdcNetworkProfileConfig)
}

// UpdateVdcNetworkProfile updates the VDC Network Profile configuration
func (adminVdc *AdminVdc) UpdateVdcNetworkProfile(vdcNetworkProfileConfig *types.VdcNetworkProfile) (*types.VdcNetworkProfile, error) {
if adminVdc == nil || adminVdc.AdminVdc == nil || adminVdc.AdminVdc.ID == "" {
return nil, fmt.Errorf("cannot update VDC Network Profile configuration without ID")
}

return updateVdcNetworkProfile(adminVdc.client, adminVdc.AdminVdc.ID, vdcNetworkProfileConfig)
}

// DeleteVdcNetworkProfile deletes VDC Network Profile Configuration
func (vdc *Vdc) DeleteVdcNetworkProfile() error {
if vdc == nil || vdc.Vdc == nil || vdc.Vdc.ID == "" {
return fmt.Errorf("cannot lookup VDC Network Profile without VDC ID")
}

return deleteVdcNetworkProfile(vdc.client, vdc.Vdc.ID)
}

// DeleteVdcNetworkProfile deletes VDC Network Profile Configuration
func (adminVdc *AdminVdc) DeleteVdcNetworkProfile() error {
if adminVdc == nil || adminVdc.AdminVdc == nil || adminVdc.AdminVdc.ID == "" {
return fmt.Errorf("cannot lookup VDC Network Profile without VDC ID")
}

return deleteVdcNetworkProfile(adminVdc.client, adminVdc.AdminVdc.ID)
}

func getVdcNetworkProfile(client *Client, vdcId string) (*types.VdcNetworkProfile, error) {
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcNetworkProfile
apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint)
if err != nil {
return nil, err
}

if vdcId == "" {
return nil, fmt.Errorf("cannot lookup VDC Network Profile configuration without VDC ID")
}

urlRef, err := client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, vdcId))
if err != nil {
return nil, err
}

returnObject := &types.VdcNetworkProfile{}
err = client.OpenApiGetItem(apiVersion, urlRef, nil, returnObject, nil)
if err != nil {
return nil, err
}

return returnObject, nil
}

func updateVdcNetworkProfile(client *Client, vdcId string, vdcNetworkProfileConfig *types.VdcNetworkProfile) (*types.VdcNetworkProfile, error) {
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcNetworkProfile
apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint)
if err != nil {
return nil, err
}

if vdcId == "" {
return nil, fmt.Errorf("cannot update VDC Network Profile configuration without ID")
}

urlRef, err := client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, vdcId))
if err != nil {
return nil, err
}

returnObject := &types.VdcNetworkProfile{}
err = client.OpenApiPutItem(apiVersion, urlRef, nil, vdcNetworkProfileConfig, returnObject, nil)
if err != nil {
return nil, fmt.Errorf("error updating VDC Network Profile configuration: %s", err)
}

return returnObject, nil
}

func deleteVdcNetworkProfile(client *Client, vdcId string) error {
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcNetworkProfile
apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint)
if err != nil {
return err
}

urlRef, err := client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, vdcId))
if err != nil {
return err
}

err = client.OpenApiDeleteItem(apiVersion, urlRef, nil, nil)

if err != nil {
return fmt.Errorf("error deleting VDC Network Profile configuration: %s", err)
}

return nil
}
52 changes: 52 additions & 0 deletions govcd/vdc_network_profile_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//go:build network || nsxt || functional || openapi || ALL
// +build network nsxt functional openapi ALL

package govcd

import (
"github.com/vmware/go-vcloud-director/v2/types/v56"
. "gopkg.in/check.v1"
)

func (vcd *TestVCD) Test_VdcNetworkProfile(check *C) {
skipNoNsxtConfiguration(vcd, check)

org, err := vcd.client.GetOrgByName(vcd.config.VCD.Org)
check.Assert(err, IsNil)
nsxtVdc, err := org.GetVDCByName(vcd.config.VCD.Nsxt.Vdc, false)
check.Assert(err, IsNil)

existingVdcNetworkProfile, err := nsxtVdc.GetVdcNetworkProfile()
check.Assert(err, IsNil)
check.Assert(existingVdcNetworkProfile, NotNil)

// Lookup Edge available Edge Cluster
edgeCluster, err := nsxtVdc.GetNsxtEdgeClusterByName(vcd.config.VCD.Nsxt.NsxtEdgeCluster)
check.Assert(err, IsNil)
check.Assert(edgeCluster, NotNil)

networkProfileConfig := &types.VdcNetworkProfile{
ServicesEdgeCluster: &types.VdcNetworkProfileServicesEdgeCluster{
BackingID: edgeCluster.NsxtEdgeCluster.ID,
},
}

newVdcNetworkProfile, err := nsxtVdc.UpdateVdcNetworkProfile(networkProfileConfig)
check.Assert(err, IsNil)
check.Assert(newVdcNetworkProfile, NotNil)
check.Assert(newVdcNetworkProfile.ServicesEdgeCluster.BackingID, Equals, edgeCluster.NsxtEdgeCluster.ID)

// Unset Edge Cluster (and other values) by sending empty structure
unsetNetworkProfileConfig := &types.VdcNetworkProfile{}
unsetVdcNetworkProfile, err := nsxtVdc.UpdateVdcNetworkProfile(unsetNetworkProfileConfig)
check.Assert(err, IsNil)
check.Assert(unsetVdcNetworkProfile, NotNil)

networkProfileAfterCleanup, err := nsxtVdc.GetVdcNetworkProfile()
check.Assert(err, IsNil)
check.Assert(networkProfileAfterCleanup.ServicesEdgeCluster, IsNil)
// Cleanup

err = nsxtVdc.DeleteVdcNetworkProfile()
check.Assert(err, IsNil)
}
1 change: 1 addition & 0 deletions types/v56/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ const (
OpenApiEndpointVdcComputePolicies = "vdcComputePolicies/"
OpenApiEndpointVdcAssignedComputePolicies = "vdcs/%s/computePolicies"
OpenApiEndpointVdcCapabilities = "vdcs/%s/capabilities"
OpenApiEndpointVdcNetworkProfile = "vdcs/%s/networkProfile"
OpenApiEndpointEdgeGateways = "edgeGateways/"
OpenApiEndpointNsxtFirewallRules = "edgeGateways/%s/firewall/rules"
OpenApiEndpointFirewallGroups = "firewallGroups/"
Expand Down
Loading