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

Provider VDC CRUD #580

Merged
merged 59 commits into from
Jul 12, 2023
Merged
Show file tree
Hide file tree
Changes from 54 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
301e8bf
WIP Add Provider VDC creation functions
dataclouder Jun 19, 2023
799d12f
Add data structure for Provider VDC creation
dataclouder Jun 19, 2023
c9e0b4e
Add vsphere tag to tests
dataclouder Jun 19, 2023
468a464
Convert simple queries to cumulativeQuery calls
dataclouder Jun 19, 2023
0e793ee
WIP Add test for Provider VDC creation
dataclouder Jun 19, 2023
5e7fd0a
Add resource pool retrieval functions
dataclouder Jun 19, 2023
5521542
Add vCenter retrieval functions
dataclouder Jun 19, 2023
095b805
Remove unneeded field
dataclouder Jun 19, 2023
5a4a56c
Change .Add to .Set in additionalHeader handling
dataclouder Jun 21, 2023
36f1a0f
Add provider network pool data structures
dataclouder Jun 21, 2023
3399f9d
Fix vsphere_* GetAll* functions
dataclouder Jun 21, 2023
90e357c
Add network pool retrieval methods
dataclouder Jun 21, 2023
d101e9c
Update provider VDC creation test
dataclouder Jun 21, 2023
67f0b00
Merge branch 'main' into provider-vdc
dataclouder Jun 21, 2023
9df2981
Update some types with JSON tags
dataclouder Jun 25, 2023
b3866cc
Add resource pools to TestConfig structure
dataclouder Jun 25, 2023
d2b8b0c
Improve return values for GetNetworkPoolByName
dataclouder Jun 25, 2023
3e1601a
Add method vcdClient.QueryNsxtManagerByHref
dataclouder Jun 25, 2023
1db7666
Add PVDC methods Delete, IsEnabled, Disable, Enable
dataclouder Jun 25, 2023
ad640e9
Improve provider VDC creation test
dataclouder Jun 25, 2023
283470f
Update Provider VDC type definitions
dataclouder Jun 28, 2023
a0235b1
Update network pool retrieval
dataclouder Jun 28, 2023
ea69564
Change resource pool retrieval
dataclouder Jun 28, 2023
f0bfddc
Fix naming for resource pools in configuration
dataclouder Jun 28, 2023
7581400
Fix version for OpenApiEndpointResourcePoolsBrowseAll
dataclouder Jun 28, 2023
d0d4fa8
Add Update method to provider VDC
dataclouder Jun 28, 2023
06bb024
Add vsphere_storage_profile methods
dataclouder Jul 2, 2023
543d987
Add method Client.ExecuteJsonRequest
dataclouder Jul 2, 2023
9385fb1
Add second storage profile to TestConfig
dataclouder Jul 2, 2023
71561f1
Remove unused function NewVcenter
dataclouder Jul 2, 2023
673d9fe
Update resource pool retrieval functions
dataclouder Jul 2, 2023
c2cfaa2
Add structure for storage profiles
dataclouder Jul 2, 2023
ce8a492
Add storage profile openapi endpoint
dataclouder Jul 2, 2023
e550b8a
Update data structures needed for provider VDC
dataclouder Jul 2, 2023
6ab169f
Add provider VDC update functions
dataclouder Jul 2, 2023
7981dff
Merge branch 'main' into provider-vdc
dataclouder Jul 2, 2023
1abee0f
Fix possible out of bound error in QueryNsxtManagerByHref
dataclouder Jul 3, 2023
d7ac0f9
Add system administrator checks for vspgere_* tests
dataclouder Jul 3, 2023
6c7c4f3
Remove Unused function
dataclouder Jul 3, 2023
fb81e49
Add changelog item
dataclouder Jul 3, 2023
e0095ac
Fix network pool retrieval
dataclouder Jul 3, 2023
dcaeadb
Fix incorrect SupportedHardwareVersions data type
dataclouder Jul 3, 2023
aea0b48
Make the test less chatty
dataclouder Jul 3, 2023
475cce7
Fix optimistic tests with network pools
dataclouder Jul 3, 2023
6a367f7
Fix incorrect SupportedHardwareVersion label
dataclouder Jul 3, 2023
fadba89
Add test comment
dataclouder Jul 4, 2023
2a9a516
Remove unnedeed comment
dataclouder Jul 4, 2023
5a624c3
Make ExecuteJsonRequest a private method
dataclouder Jul 4, 2023
94a816b
make the task progress check into a private method
dataclouder Jul 4, 2023
15da7a7
Add PvDC tests for all network pool handlings
dataclouder Jul 5, 2023
7d11f55
Fix wrong type in QueryProviderVdcStorageProfileByName
dataclouder Jul 6, 2023
12a5eb5
Ensure response body is closed after executeJsonRequest
dataclouder Jul 6, 2023
9b4f4d7
Fix unchecked error
dataclouder Jul 6, 2023
3d984cc
Address review comments
dataclouder Jul 7, 2023
debfae8
Add skip for non-admin user in Test_GetNetworkPools
dataclouder Jul 10, 2023
71b2737
Simplify executeJsonRequest
dataclouder Jul 10, 2023
f5057a0
Add safety check for params.ResourcePoolRefs
dataclouder Jul 10, 2023
5d77972
Simplify QueryNsxtManagerByName
dataclouder Jul 10, 2023
ed51536
Add error for duplicate IDs in ResourcePoolsFromIds
dataclouder Jul 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .changes/v2.21.0/580-bug-fixes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* Fixed [Issue #1066](https://github.com/vmware/terraform-provider-vcd/issues/1066) - Not possible to handle more than 128 storage profiles [GH-580]
13 changes: 13 additions & 0 deletions .changes/v2.21.0/580-features.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
* Added method `VCDClient.QueryNsxtManagerByHref` to retrieve a NSX-T manager by its ID/HREF [GH-580]
* Added method `VCDClient.CreateProviderVdc` to create a Provider VDC [GH-580]
* Added method `VCDClient.ResourcePoolsFromIds` to convert list of IDs to resource pools [GH-580]
* Added `ProviderVdcExtended` methods `AddResourcePools`, `AddStorageProfiles`, `Delete`, `DeleteResourcePools`,`DeleteStorageProfiles`,`Disable`,`Enable`,`GetResourcePools`,`IsEnabled`,`Rename`,`Update` to fully manage a provider VDC [GH-580]
* Added method `NetworkPool.GetOpenApiUrl` to generate the full URL of a network pool [GH-580]
* Added `ResourcePool` methods `GetAvailableHardwareVersions` and `GetDefaultHardwareVersion` to get hardware versions [GH-580]
* Added `VCDClient` method `GetAllResourcePools` to retrieve all resource pools regardless of vCenter affiliation [GH-580]
* Added `VCDClient` method `GetAllVcenters` to retrieve all vCenters [GH-580]
* Added `VCDClient` methods `GetNetworkPoolById`,`GetNetworkPoolByName`,`GetNetworkPoolSummaries` to retrieve network pools [GH-580]
* Added `VCDClient` methods `GetVcenterById`,`GetVcenterByName` to retrieve vCenters [GH-580]
* Added `VCenter` methods `GetAllResourcePools`,`VCenter.GetResourcePoolById`,`VCenter.GetResourcePoolByName` to retrieve resource pools [GH-580]
* Added `VCenter` methods `GetAllStorageProfiles`,`GetStorageProfileById`,`GetStorageProfileByName` to retrieve storage profiles [GH-580]
* Added method `VCenter.GetVimServerUrl` to retrieve the full URL of a vCenter within a VCD [GH-580]
4 changes: 2 additions & 2 deletions govcd/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,12 +238,12 @@ func (client *Client) newRequest(params map[string]string, notEncodedParams map[
req.Header.Add("Authorization", "bearer "+client.VCDToken)
}

// Merge in additional headers before logging if any where specified in additionalHeader
// Merge in additional headers before logging if anywhere specified in additionalHeader
// parameter
if len(additionalHeader) > 0 {
for headerName, headerValueSlice := range additionalHeader {
for _, singleHeaderValue := range headerValueSlice {
req.Header.Add(headerName, singleHeaderValue)
req.Header.Set(headerName, singleHeaderValue)
}
}
}
Expand Down
74 changes: 74 additions & 0 deletions govcd/api_json.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright 2023 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
*/

package govcd

import (
"bytes"
"encoding/json"
"fmt"
"github.com/vmware/go-vcloud-director/v2/types/v56"
"github.com/vmware/go-vcloud-director/v2/util"
"io"
"net/http"
"net/url"
"strings"
)

// executeJsonRequest is a wrapper around regular API call operations, similar to client.ExecuteRequest, but with JSON payback
// Returns a http.Response object, which, in case of success, has its body still unread
Didainius marked this conversation as resolved.
Show resolved Hide resolved
// Caller function has the responsibility for closing the response body
func (client Client) executeJsonRequest(href, httpMethod string, inputStructure any, errorMessage string) (*http.Response, error) {

text := bytes.Buffer{}
encoder := json.NewEncoder(&text)
encoder.SetEscapeHTML(false)
encoder.SetIndent(" ", " ")
err := encoder.Encode(inputStructure)
dataclouder marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return nil, err
}
requestHref, err := url.Parse(href)
if err != nil {
return nil, err
}

var resp *http.Response
body := strings.NewReader(text.String())
apiVersion := client.APIVersion
headAccept := http.Header{}
headAccept.Set("Accept", fmt.Sprintf("application/*+json;version=%s", apiVersion))
headAccept.Set("Content-Type", "application/*+json")
request := client.newRequest(nil, nil, httpMethod, *requestHref, body, apiVersion, headAccept)
resp, err = client.Http.Do(request)
if err != nil {
return nil, fmt.Errorf(errorMessage, err)
}

if resp.StatusCode < 200 || resp.StatusCode >= 300 {
body, _ := io.ReadAll(resp.Body)
util.ProcessResponseOutput(util.CallFuncName(), resp, string(body))
var jsonError types.OpenApiError
err = json.Unmarshal(body, &jsonError)
// By default, we return the whole response body as error message. This may also contain the stack trace
message := string(body)
// if the body contains a valid JSON representation of the error, we return a more agile message, using the
// exposed fields, and hiding the stack trace from view
if err == nil {
message = fmt.Sprintf("%s - %s", jsonError.MinorErrorCode, jsonError.Message)
}
util.ProcessResponseOutput(util.CallFuncName(), resp, string(body))
return resp, fmt.Errorf(errorMessage, message)
dataclouder marked this conversation as resolved.
Show resolved Hide resolved
}

return checkRespWithErrType(types.BodyTypeJSON, resp, err, &types.Error{})
Didainius marked this conversation as resolved.
Show resolved Hide resolved
}

// closeBody is a wrapper function that should be used with "defer" after calling executeJsonRequest
func closeBody(resp *http.Response) {
err := resp.Body.Close()
if err != nil {
util.Logger.Printf("error closing response body - Called by %s: %s\n", util.CallFuncName(), err)
}
}
30 changes: 29 additions & 1 deletion govcd/api_vcd_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//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 || rde || uiPlugin || 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 || rde || vsphere || uiPlugin || ALL

/*
* Copyright 2022 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
Expand Down Expand Up @@ -146,6 +146,7 @@ type TestConfig struct {
NsxtProviderVdc struct {
Name string `yaml:"name"`
StorageProfile string `yaml:"storage_profile"`
StorageProfile2 string `yaml:"storage_profile_2"`
NetworkPool string `yaml:"network_pool"`
PlacementPolicyVmGroup string `yaml:"placementPolicyVmGroup,omitempty"`
} `yaml:"nsxt_provider_vdc"`
Expand Down Expand Up @@ -198,6 +199,10 @@ type TestConfig struct {
NsxtAlbServiceEngineGroup string `yaml:"nsxtAlbServiceEngineGroup"`
} `yaml:"nsxt"`
} `yaml:"vcd"`
Vsphere struct {
ResourcePoolForVcd1 string `yaml:"resourcePoolForVcd1,omitempty"`
ResourcePoolForVcd2 string `yaml:"resourcePoolForVcd2,omitempty"`
} `yaml:"vsphere,omitempty"`
Logging struct {
Enabled bool `yaml:"enabled,omitempty"`
LogFileName string `yaml:"logFileName,omitempty"`
Expand Down Expand Up @@ -931,6 +936,29 @@ func (vcd *TestVCD) removeLeftoverEntities(entity CleanupEntity) {
}
vcd.infoCleanup(removedMsg, entity.EntityType, entity.Name, entity.CreatedBy)
return
case "provider_vdc":
pvdc, err := vcd.client.GetProviderVdcExtendedByName(entity.Name)
if err != nil {
vcd.infoCleanup(notFoundMsg, entity.EntityType, entity.Name)
return
}
err = pvdc.Disable()
if err != nil {
vcd.infoCleanup(notDeletedMsg, entity.EntityType, entity.Name, err)
return
}
task, err := pvdc.Delete()
if err != nil {
vcd.infoCleanup(notDeletedMsg, entity.EntityType, entity.Name, err)
return
}
err = task.WaitTaskCompletion()
if err != nil {
vcd.infoCleanup(notDeletedMsg, entity.EntityType, entity.Name, err)
return
}
vcd.infoCleanup(removedMsg, entity.EntityType, entity.Name, entity.CreatedBy)
return
case "catalogItem":
if entity.Parent == "" {
vcd.infoCleanup("removeLeftoverEntries: [ERROR] No Org provided for catalogItem '%s'\n", strings.Split(entity.Parent, "|")[0])
Expand Down
2 changes: 1 addition & 1 deletion govcd/common_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//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 || rde || uiPlugin || 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 || rde || uiPlugin || vsphere || ALL

/*
* Copyright 2021 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
Expand Down
104 changes: 104 additions & 0 deletions govcd/network_pool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* Copyright 2023 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
*/

package govcd

import (
"fmt"
"github.com/vmware/go-vcloud-director/v2/types/v56"
"net/url"
)

type NetworkPool struct {
NetworkPool *types.NetworkPool
vcdClient *VCDClient
}

// GetOpenApiUrl retrieves the full URL of a network pool
func (np NetworkPool) GetOpenApiUrl() (string, error) {
Didainius marked this conversation as resolved.
Show resolved Hide resolved
response, err := url.JoinPath(np.vcdClient.sessionHREF.String(), "admin", "extension", "networkPool", np.NetworkPool.Id)
if err != nil {
return "", err
}
return response, nil
}

// GetNetworkPoolSummaries retrieves the list of all available network pools
func (vcdClient *VCDClient) GetNetworkPoolSummaries(queryParameters url.Values) ([]*types.NetworkPool, error) {
client := vcdClient.Client
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointNetworkPoolSummaries
apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint)
if err != nil {
return nil, err
}

urlRef, err := client.OpenApiBuildEndpoint(endpoint)
if err != nil {
return nil, err
}
typeResponse := []*types.NetworkPool{{}}
err = client.OpenApiGetAllItems(apiVersion, urlRef, queryParameters, &typeResponse, nil)
if err != nil {
return nil, err
}

return typeResponse, nil
}

// GetNetworkPoolById retrieves Network Pool with a given ID
func (vcdClient *VCDClient) GetNetworkPoolById(id string) (*NetworkPool, error) {
if id == "" {
return nil, fmt.Errorf("network pool lookup requires ID")
}

client := vcdClient.Client
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointNetworkPools
apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint)
if err != nil {
return nil, err
}

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

response := &NetworkPool{
vcdClient: vcdClient,
NetworkPool: &types.NetworkPool{},
}

err = client.OpenApiGetItem(apiVersion, urlRef, nil, response.NetworkPool, nil)
if err != nil {
return nil, err
}

return response, nil
}

// GetNetworkPoolByName retrieves a network pool with a given name
// Note. It will return an error if multiple network pools exist with the same name
func (vcdClient *VCDClient) GetNetworkPoolByName(name string) (*NetworkPool, error) {
if name == "" {
return nil, fmt.Errorf("network pool lookup requires name")
}

queryParameters := url.Values{}
queryParameters.Add("filter", "name=="+name)

filteredNetworkPools, err := vcdClient.GetNetworkPoolSummaries(queryParameters)
if err != nil {
return nil, fmt.Errorf("error getting network pools: %s", err)
}

if len(filteredNetworkPools) == 0 {
return nil, fmt.Errorf("no network pool found with name '%s' - %s", name, ErrorEntityNotFound)
}

if len(filteredNetworkPools) > 1 {
return nil, fmt.Errorf("more than one network pool found with name '%s'", name)
}
Didainius marked this conversation as resolved.
Show resolved Hide resolved

return vcdClient.GetNetworkPoolById(filteredNetworkPools[0].Id)
}
47 changes: 47 additions & 0 deletions govcd/network_pool_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//go:build providervdc || functional || ALL

package govcd

import (
"fmt"
"github.com/kr/pretty"
. "gopkg.in/check.v1"
)

func (vcd *TestVCD) Test_GetNetworkPools(check *C) {

knownNetworkPoolName := vcd.config.VCD.NsxtProviderVdc.NetworkPool
networkPools, err := vcd.client.GetNetworkPoolSummaries(nil)
check.Assert(err, IsNil)
check.Assert(len(networkPools) > 0, Equals, true)

checkNetworkPoolName := false
foundNetworkPool := false
if knownNetworkPoolName != "" {
checkNetworkPoolName = true
}

for i, nps := range networkPools {
if nps.Name == knownNetworkPoolName {
foundNetworkPool = true
}
networkPoolById, err := vcd.client.GetNetworkPoolById(nps.Id)
check.Assert(err, IsNil)
check.Assert(networkPoolById, NotNil)
check.Assert(networkPoolById.NetworkPool.Id, Equals, nps.Id)
check.Assert(networkPoolById.NetworkPool.Name, Equals, nps.Name)

networkPoolByName, err := vcd.client.GetNetworkPoolByName(nps.Name)
check.Assert(err, IsNil)
check.Assert(networkPoolByName, NotNil)
check.Assert(networkPoolByName.NetworkPool.Id, Equals, nps.Id)
check.Assert(networkPoolByName.NetworkPool.Name, Equals, nps.Name)
if testVerbose {
fmt.Printf("%d, %# v\n", i, pretty.Formatter(networkPoolByName.NetworkPool))
}
}
if checkNetworkPoolName {
check.Assert(foundNetworkPool, Equals, true)
}

}
7 changes: 7 additions & 0 deletions govcd/openapi_endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,13 @@ 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+
types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVirtualCenters: "36.0",
types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointResourcePools: "36.0",
types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointResourcePoolsBrowseAll: "36.2",
types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointResourcePoolHardware: "36.0",
types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointNetworkPools: "36.0",
types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointNetworkPoolSummaries: "36.0",
types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointStorageProfiles: "33.0",

// Extensions API endpoints. These are not versioned
types.OpenApiEndpointExtensionsUi: "35.0", // VCD 10.2+
Expand Down
Loading