diff --git a/.changes/v2.21.0/580-bug-fixes.md b/.changes/v2.21.0/580-bug-fixes.md new file mode 100644 index 000000000..2f8827629 --- /dev/null +++ b/.changes/v2.21.0/580-bug-fixes.md @@ -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] diff --git a/.changes/v2.21.0/580-features.md b/.changes/v2.21.0/580-features.md new file mode 100644 index 000000000..eaccd06c7 --- /dev/null +++ b/.changes/v2.21.0/580-features.md @@ -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] diff --git a/govcd/api.go b/govcd/api.go index 246ab9199..ada89f19f 100644 --- a/govcd/api.go +++ b/govcd/api.go @@ -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) } } } diff --git a/govcd/api_json.go b/govcd/api_json.go new file mode 100644 index 000000000..e8b3023a4 --- /dev/null +++ b/govcd/api_json.go @@ -0,0 +1,69 @@ +/* + * Copyright 2023 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. + */ + +package govcd + +import ( + "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 +// 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, err := json.MarshalIndent(inputStructure, " ", " ") + if err != nil { + return nil, err + } + requestHref, err := url.Parse(href) + if err != nil { + return nil, err + } + + var resp *http.Response + body := strings.NewReader(string(text)) + 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) + } + + return checkRespWithErrType(types.BodyTypeJSON, resp, err, &types.Error{}) +} + +// 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) + } +} diff --git a/govcd/api_vcd_test.go b/govcd/api_vcd_test.go index ee778aa67..80cf2e1fc 100644 --- a/govcd/api_vcd_test.go +++ b/govcd/api_vcd_test.go @@ -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. @@ -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"` @@ -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"` @@ -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]) diff --git a/govcd/common_test.go b/govcd/common_test.go index b7d8a611c..c343a2c33 100644 --- a/govcd/common_test.go +++ b/govcd/common_test.go @@ -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. diff --git a/govcd/network_pool.go b/govcd/network_pool.go new file mode 100644 index 000000000..cb5922db3 --- /dev/null +++ b/govcd/network_pool.go @@ -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) { + 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) + } + + return vcdClient.GetNetworkPoolById(filteredNetworkPools[0].Id) +} diff --git a/govcd/network_pool_test.go b/govcd/network_pool_test.go new file mode 100644 index 000000000..f32aa086a --- /dev/null +++ b/govcd/network_pool_test.go @@ -0,0 +1,50 @@ +//go:build providervdc || functional || ALL + +package govcd + +import ( + "fmt" + "github.com/kr/pretty" + . "gopkg.in/check.v1" +) + +func (vcd *TestVCD) Test_GetNetworkPools(check *C) { + + if vcd.skipAdminTests { + check.Skip("this test requires system administrator privileges") + } + 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) + } + +} diff --git a/govcd/openapi_endpoints.go b/govcd/openapi_endpoints.go index e95cc1658..c6f314817 100644 --- a/govcd/openapi_endpoints.go +++ b/govcd/openapi_endpoints.go @@ -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+ diff --git a/govcd/provider_vdc.go b/govcd/provider_vdc.go index 7f6256143..2e572dbe0 100644 --- a/govcd/provider_vdc.go +++ b/govcd/provider_vdc.go @@ -3,8 +3,11 @@ package govcd import ( "fmt" "github.com/vmware/go-vcloud-director/v2/types/v56" + "github.com/vmware/go-vcloud-director/v2/util" + "io" "net/http" "net/url" + "time" ) // ProviderVdc is the basic Provider VDC structure, contains the minimum set of attributes. @@ -182,3 +185,409 @@ func getProviderVdcByName(vcdClient *VCDClient, providerVdcName string, extended } return vcdClient.GetProviderVdcByHref(foundProviderVdcs.Results.VMWProviderVdcRecord[0].HREF) } + +// CreateProviderVdc creates a new provider VDC using the passed parameters +func (vcdClient *VCDClient) CreateProviderVdc(params *types.ProviderVdcCreation) (*ProviderVdcExtended, error) { + if !vcdClient.Client.IsSysAdmin { + return nil, fmt.Errorf("functionality requires System Administrator privileges") + } + if params.Name == "" { + return nil, fmt.Errorf("a non-empty name is needed to create a provider VDC") + } + if params.ResourcePoolRefs == nil || len(params.ResourcePoolRefs.VimObjectRef) == 0 { + return nil, fmt.Errorf("resource pool is needed to create a provider VDC") + } + if len(params.StorageProfile) == 0 { + return nil, fmt.Errorf("storage profile is needed to create a provider VDC") + } + if params.VimServer == nil { + return nil, fmt.Errorf("vim server is needed to create a provider VDC") + } + pvdcCreateHREF := vcdClient.Client.VCDHREF + pvdcCreateHREF.Path += "/admin/extension/providervdcsparams" + + resp, err := vcdClient.Client.executeJsonRequest(pvdcCreateHREF.String(), http.MethodPost, params, "error creating provider VDC: %s") + if err != nil { + return nil, err + } + + body, _ := io.ReadAll(resp.Body) + util.ProcessResponseOutput(util.CallFuncName(), resp, string(body)) + + defer closeBody(resp) + + pvdc, err := vcdClient.GetProviderVdcExtendedByName(params.Name) + if err != nil { + return nil, err + } + + // At this stage, the provider VDC is created, but the task may be still working. + // Thus, we retrieve the associated tasks, and wait for their completion. + if pvdc.VMWProviderVdc.Tasks == nil { + err = pvdc.Refresh() + if err != nil { + return pvdc, fmt.Errorf("error refreshing provider VDC %s: %s", params.Name, err) + } + if pvdc.VMWProviderVdc.Tasks == nil { + return pvdc, fmt.Errorf("provider VDC %s was created, but no completion task was found: %s", params.Name, err) + } + } + for _, taskInProgress := range pvdc.VMWProviderVdc.Tasks.Task { + task := Task{ + Task: taskInProgress, + client: pvdc.client, + } + err = task.WaitTaskCompletion() + if err != nil { + return pvdc, fmt.Errorf("provider VDC %s was created, but it is not ready: %s", params.Name, err) + } + } + + err = pvdc.Refresh() + return pvdc, err +} + +// Disable changes the Provider VDC state from enabled to disabled +func (pvdc *ProviderVdcExtended) Disable() error { + util.Logger.Printf("[TRACE] ProviderVdc.Disable") + + href, err := url.JoinPath(pvdc.VMWProviderVdc.HREF, "action", "disable") + + if err != nil { + return err + } + + err = pvdc.client.ExecuteRequestWithoutResponse(href, http.MethodPost, "", "error disabling provider VDC: %s", nil) + if err != nil { + return err + } + err = pvdc.Refresh() + if err != nil { + return err + } + if pvdc.IsEnabled() { + return fmt.Errorf("provider VDC was disabled, but its status is still shown as 'enabled'") + } + return nil +} + +// IsEnabled shows whether the Provider VDC is enabled +func (pvdc *ProviderVdcExtended) IsEnabled() bool { + if pvdc.VMWProviderVdc.IsEnabled == nil { + return false + } + return *pvdc.VMWProviderVdc.IsEnabled +} + +// Enable changes the Provider VDC state from disabled to enabled +func (pvdc *ProviderVdcExtended) Enable() error { + util.Logger.Printf("[TRACE] ProviderVdc.Enable") + + href, err := url.JoinPath(pvdc.VMWProviderVdc.HREF, "action", "enable") + + if err != nil { + return err + } + + err = pvdc.client.ExecuteRequestWithoutResponse(href, http.MethodPost, "", + "error enabling provider VDC: %s", nil) + if err != nil { + return err + } + err = pvdc.Refresh() + if err != nil { + return err + } + if !pvdc.IsEnabled() { + return fmt.Errorf("provider VDC was enabled, but its status is still shown as 'disabled'") + } + return nil +} + +// Delete removes a Provider VDC +// The provider VDC must be disabled for deletion to succeed +// Deletion will also fail if the Provider VDC is backing other resources, such as organization VDCs +func (pvdc *ProviderVdcExtended) Delete() (Task, error) { + util.Logger.Printf("[TRACE] ProviderVdc.Delete") + + if pvdc.IsEnabled() { + return Task{}, fmt.Errorf("provider VDC %s is enabled - can't delete", pvdc.VMWProviderVdc.Name) + } + // Return the task + return pvdc.client.ExecuteTaskRequest(pvdc.VMWProviderVdc.HREF, http.MethodDelete, + "", "error deleting provider VDC: %s", nil) +} + +// Update can change some of the provider VDC internals +// In practical terms, only name and description are guaranteed to be changed through this method. +// The other admitted changes need to go through separate API calls +func (pvdc *ProviderVdcExtended) Update() error { + + resp, err := pvdc.client.executeJsonRequest(pvdc.VMWProviderVdc.HREF, http.MethodPut, pvdc.VMWProviderVdc, + "error updating provider VDC: %s") + + if err != nil { + return err + } + defer closeBody(resp) + + return pvdc.checkProgress("updating") +} + +// Rename changes name and/or description from a provider VDC +func (pvdc *ProviderVdcExtended) Rename(name, description string) error { + if name == "" { + return fmt.Errorf("provider VDC name cannot be empty") + } + pvdc.VMWProviderVdc.Name = name + pvdc.VMWProviderVdc.Description = description + return pvdc.Update() +} + +// AddResourcePools adds resource pools to the Provider VDC +func (pvdc *ProviderVdcExtended) AddResourcePools(resourcePools []*ResourcePool) error { + util.Logger.Printf("[TRACE] ProviderVdc.AddResourcePools") + + href, err := url.JoinPath(pvdc.VMWProviderVdc.HREF, "action", "updateResourcePools") + if err != nil { + return err + } + + var items []*types.VimObjectRef + + for _, rp := range resourcePools { + vcenterUrl, err := rp.vcenter.GetVimServerUrl() + if err != nil { + return err + } + item := types.VimObjectRef{ + MoRef: rp.ResourcePool.Moref, + VimObjectType: "RESOURCE_POOL", + VimServerRef: &types.Reference{ + HREF: vcenterUrl, + ID: extractUuid(rp.vcenter.VSphereVCenter.VcId), + Name: rp.vcenter.VSphereVCenter.Name, + Type: "application/vnd.vmware.admin.vmwvirtualcenter+xml", + }, + } + items = append(items, &item) + } + + input := types.AddResourcePool{VimObjectRef: items} + + resp, err := pvdc.client.executeJsonRequest(href, http.MethodPost, input, "error updating provider VDC resource pools: %s") + if err != nil { + return err + } + task := NewTask(pvdc.client) + err = decodeBody(types.BodyTypeJSON, resp, task.Task) + if err != nil { + return err + } + + defer closeBody(resp) + err = task.WaitTaskCompletion() + if err != nil { + return err + } + return pvdc.Refresh() +} + +// DeleteResourcePools removes resource pools from the Provider VDC +func (pvdc *ProviderVdcExtended) DeleteResourcePools(resourcePools []*ResourcePool) error { + util.Logger.Printf("[TRACE] ProviderVdc.DeleteResourcePools") + + href, err := url.JoinPath(pvdc.VMWProviderVdc.HREF, "action", "updateResourcePools") + if err != nil { + return err + } + + usedResourcePools, err := pvdc.GetResourcePools() + if err != nil { + return fmt.Errorf("error retrieving used resource pools: %s", err) + } + + var items []*types.Reference + + for _, rp := range resourcePools { + + var foundUsed *types.QueryResultResourcePoolRecordType + for _, urp := range usedResourcePools { + if rp.ResourcePool.Moref == urp.Moref { + foundUsed = urp + break + } + } + if foundUsed == nil { + return fmt.Errorf("resource pool %s not found in provider VDC %s", rp.ResourcePool.Name, pvdc.VMWProviderVdc.Name) + } + if foundUsed.IsPrimary { + return fmt.Errorf("resource pool %s (%s) caannot be removed, because it is the primary one for provider VDC %s", + rp.ResourcePool.Name, rp.ResourcePool.Moref, pvdc.VMWProviderVdc.Name) + } + if foundUsed.IsEnabled { + err = disableResourcePool(pvdc.client, foundUsed.HREF) + if err != nil { + return fmt.Errorf("error disabling resource pool %s: %s", foundUsed.Name, err) + } + } + + item := types.Reference{ + HREF: foundUsed.HREF, + ID: extractUuid(foundUsed.HREF), + Name: foundUsed.Name, + Type: "application/vnd.vmware.admin.vmwProviderVdcResourcePool+xml", + } + items = append(items, &item) + } + + input := types.DeleteResourcePool{ResourcePoolRefs: items} + + resp, err := pvdc.client.executeJsonRequest(href, http.MethodPost, input, "error removing resource pools from provider VDC: %s") + if err != nil { + return err + } + defer closeBody(resp) + task := NewTask(pvdc.client) + err = decodeBody(types.BodyTypeJSON, resp, task.Task) + if err != nil { + return err + } + err = task.WaitTaskCompletion() + if err != nil { + return err + } + return pvdc.Refresh() +} + +// GetResourcePools returns the Resource Pools belonging to this provider VDC +func (pvdc *ProviderVdcExtended) GetResourcePools() ([]*types.QueryResultResourcePoolRecordType, error) { + resourcePools, err := pvdc.client.cumulativeQuery(types.QtResourcePool, map[string]string{ + "type": types.QtResourcePool, + "filter": fmt.Sprintf("providerVdc==%s", url.QueryEscape(extractUuid(pvdc.VMWProviderVdc.HREF))), + "filterEncoded": "true", + }, nil) + if err != nil { + return nil, fmt.Errorf("could not get the Resource pool: %s", err) + } + return resourcePools.Results.ResourcePoolRecord, nil +} + +// disableResourcePool disables a resource pool while it is assigned to a provider VDC +// Calling this function is a prerequisite to removing a resource pool from a provider VDC +func disableResourcePool(client *Client, resourcePoolHref string) error { + href, err := url.JoinPath(resourcePoolHref, "action", "disable") + if err != nil { + return err + } + return client.ExecuteRequestWithoutResponse(href, http.MethodPost, "", "error disabling resource pool: %s", nil) +} + +// AddStorageProfiles adds the given storage profiles in this provider VDC +func (pvdc *ProviderVdcExtended) AddStorageProfiles(storageProfileNames []string) error { + href, err := url.JoinPath(pvdc.VMWProviderVdc.HREF, "storageProfiles") + if err != nil { + return err + } + + addStorageProfiles := &types.AddStorageProfiles{AddStorageProfile: storageProfileNames} + + resp, err := pvdc.client.executeJsonRequest(href, http.MethodPost, addStorageProfiles, + "error adding storage profiles to provider VDC: %s") + if err != nil { + return err + } + + defer closeBody(resp) + + return pvdc.checkProgress("adding storage profiles") +} + +func (pvdc *ProviderVdcExtended) checkProgress(label string) error { + // Let's keep this timeout as a precaution against an infinite wait + timeout := 2 * time.Minute + start := time.Now() + err := pvdc.Refresh() + if err != nil { + return err + } + + var elapsed time.Duration + for ResourceInProgress(pvdc.VMWProviderVdc.Tasks) { + err = pvdc.Refresh() + if err != nil { + return fmt.Errorf("error %s: %s", label, err) + } + time.Sleep(200 * time.Millisecond) + elapsed = time.Since(start) + if elapsed > timeout { + return fmt.Errorf("error %s within %s", label, timeout) + } + } + util.Logger.Printf("[ProviderVdcExtended.checkProgress] called by %s - running %s - elapsed: %s\n", + util.CallFuncName(), label, elapsed) + return nil +} + +// disableStorageProfile disables a storage profile while it is assigned to a provider VDC +// Calling this function is a prerequisite to removing a storage profile from a provider VDC +func disableStorageProfile(client *Client, storageProfileHref string) error { + disablePayload := &types.EnableStorageProfile{Enabled: false} + resp, err := client.executeJsonRequest(storageProfileHref, http.MethodPut, disablePayload, + "error disabling storage profile in provider VDC: %s") + + defer closeBody(resp) + return err +} + +// DeleteStorageProfiles removes storage profiles from the Provider VDC +func (pvdc *ProviderVdcExtended) DeleteStorageProfiles(storageProfiles []string) error { + util.Logger.Printf("[TRACE] ProviderVdc.DeleteStorageProfiles") + + href, err := url.JoinPath(pvdc.VMWProviderVdc.HREF, "storageProfiles") + if err != nil { + return err + } + + usedStorageProfileRefs := pvdc.VMWProviderVdc.StorageProfiles.ProviderVdcStorageProfile + + var toBeDeleted []*types.Reference + + for _, sp := range storageProfiles { + var foundUsed bool + for _, usp := range usedStorageProfileRefs { + if sp == usp.Name { + foundUsed = true + toBeDeleted = append(toBeDeleted, &types.Reference{HREF: usp.HREF}) + break + } + } + if !foundUsed { + return fmt.Errorf("storage profile %s not found in provider VDC %s", sp, pvdc.VMWProviderVdc.Name) + } + } + + for _, sp := range toBeDeleted { + err = disableStorageProfile(pvdc.client, sp.HREF) + if err != nil { + return fmt.Errorf("error disabling storage profile %s from provider VDC %s: %s", sp.Name, pvdc.VMWProviderVdc.Name, err) + } + } + input := &types.RemoveStorageProfile{RemoveStorageProfile: toBeDeleted} + + resp, err := pvdc.client.executeJsonRequest(href, http.MethodPost, input, "error removing storage profiles from provider VDC: %s") + if err != nil { + return err + } + defer closeBody(resp) + task := NewTask(pvdc.client) + err = decodeBody(types.BodyTypeJSON, resp, task.Task) + if err != nil { + return err + } + err = task.WaitTaskCompletion() + if err != nil { + return err + } + return pvdc.Refresh() +} diff --git a/govcd/provider_vdc_test.go b/govcd/provider_vdc_test.go index c22d5cb89..fbd167383 100644 --- a/govcd/provider_vdc_test.go +++ b/govcd/provider_vdc_test.go @@ -4,6 +4,7 @@ package govcd import ( "fmt" + "github.com/vmware/go-vcloud-director/v2/types/v56" . "gopkg.in/check.v1" "strings" ) @@ -42,7 +43,10 @@ func (vcd *TestVCD) Test_GetProviderVdc(check *C) { 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) + // This test may fail when the VCD has more than one network pool depending on the same NSX-T manager + //check.Assert(len(providerVdc.ProviderVdc.NetworkPoolReferences.NetworkPoolReference), Equals, 1) + check.Assert(len(providerVdc.ProviderVdc.NetworkPoolReferences.NetworkPoolReference) > 0, Equals, true) + foundNetworkPool := false for _, networkPool := range providerVdc.ProviderVdc.NetworkPoolReferences.NetworkPoolReference { if networkPool.Name == vcd.config.VCD.NsxtProviderVdc.NetworkPool { @@ -86,7 +90,9 @@ func (vcd *TestVCD) Test_GetProviderVdcExtended(check *C) { 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) + // This test may fail when the NSX-T manager has more than one network pool + //check.Assert(len(providerVdcExtended.VMWProviderVdc.NetworkPoolReferences.NetworkPoolReference), Equals, 1) + check.Assert(len(providerVdcExtended.VMWProviderVdc.NetworkPoolReferences.NetworkPoolReference) > 0, Equals, true) foundNetworkPool := false for _, networkPool := range providerVdcExtended.VMWProviderVdc.NetworkPoolReferences.NetworkPoolReference { if networkPool.Name == vcd.config.VCD.NsxtProviderVdc.NetworkPool { @@ -153,7 +159,266 @@ func (vcd *TestVCD) Test_GetProviderVdcConvertFromExtendedToNormal(check *C) { 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) - check.Assert(providerVdc.ProviderVdc.NetworkPoolReferences.NetworkPoolReference[0].Name, Equals, vcd.config.VCD.NsxtProviderVdc.NetworkPool) + // This test may fail when the NSX-T manager has more than one network pool + //check.Assert(len(providerVdc.ProviderVdc.NetworkPoolReferences.NetworkPoolReference), Equals, 1) + check.Assert(len(providerVdc.ProviderVdc.NetworkPoolReferences.NetworkPoolReference) > 0, Equals, true) + foundNetworkPool := false + + for _, np := range providerVdc.ProviderVdc.NetworkPoolReferences.NetworkPoolReference { + if np.Name == vcd.config.VCD.NsxtProviderVdc.NetworkPool { + foundNetworkPool = true + } + } + check.Assert(foundNetworkPool, Equals, true) check.Assert(providerVdc.ProviderVdc.Link, NotNil) } + +type providerVdcCreationElements struct { + label string + name string + description string + resourcePoolName string + params *types.ProviderVdcCreation + vcenter *VCenter + config TestConfig +} + +func (vcd *TestVCD) Test_ProviderVdcCRUD(check *C) { + // Note: you need to have at least one free resource pool to test provider VDC creation, + // and at least two of them to test update. They should be indicated in + // vcd.config.Vsphere.ResourcePoolForVcd1 and vcd.config.Vsphere.ResourcePoolForVcd2 + + if vcd.skipAdminTests { + check.Skip(fmt.Sprintf(TestRequiresSysAdminPrivileges, check.TestName())) + } + if vcd.config.Vsphere.ResourcePoolForVcd1 == "" { + check.Skip("no resource pool defined for this VCD") + } + providerVdcName := check.TestName() + providerVdcDescription := check.TestName() + storageProfileList, err := vcd.client.Client.QueryAllProviderVdcStorageProfiles() + check.Assert(err, IsNil) + check.Assert(len(storageProfileList) > 0, Equals, true) + var storageProfile types.QueryResultProviderVdcStorageProfileRecordType + for _, sp := range storageProfileList { + if sp.Name == vcd.config.VCD.NsxtProviderVdc.StorageProfile { + storageProfile = *sp + } + } + check.Assert(storageProfile.HREF, Not(Equals), "") + + vcenter, err := vcd.client.GetVCenterByName(vcd.config.VCD.VimServer) + check.Assert(err, IsNil) + check.Assert(vcenter, NotNil) + + resourcePool, err := vcenter.GetResourcePoolByName(vcd.config.Vsphere.ResourcePoolForVcd1) + check.Assert(err, IsNil) + check.Assert(resourcePool, NotNil) + + nsxtManagers, err := vcd.client.QueryNsxtManagerByName(vcd.config.VCD.Nsxt.Manager) + check.Assert(err, IsNil) + check.Assert(len(nsxtManagers), Equals, 1) + + hwVersion, err := resourcePool.GetDefaultHardwareVersion() + check.Assert(err, IsNil) + + vcenterUrl, err := vcenter.GetVimServerUrl() + check.Assert(err, IsNil) + + networkPool, err := vcd.client.GetNetworkPoolByName(vcd.config.VCD.NsxtProviderVdc.NetworkPool) + check.Assert(err, IsNil) + networkPoolHref, err := networkPool.GetOpenApiUrl() + check.Assert(err, IsNil) + + providerVdcCreation := types.ProviderVdcCreation{ + Name: providerVdcName, + Description: providerVdcDescription, + HighestSupportedHardwareVersion: hwVersion, + IsEnabled: true, + VimServer: []*types.Reference{ + { + HREF: vcenterUrl, + ID: extractUuid(vcenter.VSphereVCenter.VcId), + Name: vcenter.VSphereVCenter.Name, + }, + }, + ResourcePoolRefs: &types.VimObjectRefs{ + VimObjectRef: []*types.VimObjectRef{ + { + VimServerRef: &types.Reference{ + HREF: vcenterUrl, + ID: extractUuid(vcenter.VSphereVCenter.VcId), + Name: vcenter.VSphereVCenter.Name, + }, + MoRef: resourcePool.ResourcePool.Moref, + VimObjectType: "RESOURCE_POOL", + }, + }, + }, + StorageProfile: []string{storageProfile.Name}, + NsxTManagerReference: &types.Reference{ + HREF: nsxtManagers[0].HREF, + ID: extractUuid(nsxtManagers[0].HREF), + Name: nsxtManagers[0].Name, + }, + NetworkPool: &types.Reference{ + HREF: networkPoolHref, + Name: networkPool.NetworkPool.Name, + ID: extractUuid(networkPool.NetworkPool.Id), + Type: networkPool.NetworkPool.PoolType, + }, + AutoCreateNetworkPool: false, + } + providerVdcNoNetworkPoolCreation := types.ProviderVdcCreation{ + Name: providerVdcName, + Description: providerVdcDescription, + HighestSupportedHardwareVersion: hwVersion, + IsEnabled: true, + VimServer: []*types.Reference{ + { + HREF: vcenterUrl, + ID: extractUuid(vcenter.VSphereVCenter.VcId), + Name: vcenter.VSphereVCenter.Name, + }, + }, + ResourcePoolRefs: &types.VimObjectRefs{ + VimObjectRef: []*types.VimObjectRef{ + { + VimServerRef: &types.Reference{ + HREF: vcenterUrl, + ID: extractUuid(vcenter.VSphereVCenter.VcId), + Name: vcenter.VSphereVCenter.Name, + }, + MoRef: resourcePool.ResourcePool.Moref, + VimObjectType: "RESOURCE_POOL", + }, + }, + }, + StorageProfile: []string{storageProfile.Name}, + AutoCreateNetworkPool: false, + } + testProviderVdcCreation(vcd.client, check, providerVdcCreationElements{ + label: "ProviderVDC with network pool", + name: providerVdcName, + description: providerVdcDescription, + resourcePoolName: resourcePool.ResourcePool.Name, + params: &providerVdcCreation, + vcenter: vcenter, + config: vcd.config, + }) + testProviderVdcCreation(vcd.client, check, providerVdcCreationElements{ + label: "ProviderVDC without network pool", + name: providerVdcName, + description: providerVdcDescription, + resourcePoolName: resourcePool.ResourcePool.Name, + params: &providerVdcNoNetworkPoolCreation, + vcenter: vcenter, + config: vcd.config, + }) + providerVdcNoNetworkPoolCreation.AutoCreateNetworkPool = true + testProviderVdcCreation(vcd.client, check, providerVdcCreationElements{ + label: "ProviderVDC with automatic network pool", + name: providerVdcName, + description: providerVdcDescription, + resourcePoolName: resourcePool.ResourcePool.Name, + params: &providerVdcNoNetworkPoolCreation, + vcenter: vcenter, + config: vcd.config, + }) +} + +func testProviderVdcCreation(client *VCDClient, check *C, creationElements providerVdcCreationElements) { + + fmt.Printf("*** %s\n", creationElements.label) + providerVdcName := creationElements.name + providerVdcDescription := creationElements.description + storageProfileName := creationElements.params.StorageProfile[0] + resourcePoolName := creationElements.resourcePoolName + + printVerbose(" creating provider VDC '%s' using resource pool '%s' and storage profile '%s'\n", + providerVdcName, resourcePoolName, storageProfileName) + providerVdcJson, err := client.CreateProviderVdc(creationElements.params) + check.Assert(err, IsNil) + check.Assert(providerVdcJson, NotNil) + check.Assert(providerVdcJson.VMWProviderVdc.Name, Equals, providerVdcName) + + AddToCleanupList(providerVdcName, "provider_vdc", "", check.TestName()) + retrievedPvdc, err := client.GetProviderVdcExtendedByName(providerVdcName) + check.Assert(err, IsNil) + + err = retrievedPvdc.Disable() + check.Assert(err, IsNil) + check.Assert(retrievedPvdc.VMWProviderVdc.IsEnabled, NotNil) + check.Assert(*retrievedPvdc.VMWProviderVdc.IsEnabled, Equals, false) + + err = retrievedPvdc.Enable() + check.Assert(err, IsNil) + check.Assert(retrievedPvdc.VMWProviderVdc.IsEnabled, NotNil) + check.Assert(*retrievedPvdc.VMWProviderVdc.IsEnabled, Equals, true) + + newProviderVdcName := "TestNewName" + newProviderVdcDescription := "Test New provider VDC description" + printVerbose(" renaming provider VDC to '%s'\n", newProviderVdcName) + err = retrievedPvdc.Rename(newProviderVdcName, newProviderVdcDescription) + check.Assert(err, IsNil) + check.Assert(retrievedPvdc.VMWProviderVdc.Name, Equals, newProviderVdcName) + check.Assert(retrievedPvdc.VMWProviderVdc.Description, Equals, newProviderVdcDescription) + + printVerbose(" renaming back provider VDC to '%s'\n", providerVdcName) + err = retrievedPvdc.Rename(providerVdcName, providerVdcDescription) + check.Assert(err, IsNil) + check.Assert(retrievedPvdc.VMWProviderVdc.Name, Equals, providerVdcName) + check.Assert(retrievedPvdc.VMWProviderVdc.Description, Equals, providerVdcDescription) + + secondResourcePoolName := creationElements.config.Vsphere.ResourcePoolForVcd2 + if secondResourcePoolName != "" { + printVerbose(" adding resource pool '%s' to provider VDC\n", secondResourcePoolName) + secondResourcePool, err := creationElements.vcenter.GetResourcePoolByName(secondResourcePoolName) + check.Assert(err, IsNil) + check.Assert(secondResourcePool, NotNil) + err = retrievedPvdc.AddResourcePools([]*ResourcePool{secondResourcePool}) + check.Assert(err, IsNil) + err = retrievedPvdc.Refresh() + check.Assert(err, IsNil) + check.Assert(len(retrievedPvdc.VMWProviderVdc.ResourcePoolRefs.VimObjectRef), Equals, 2) + + printVerbose(" removing resource pool '%s' from provider VDC\n", secondResourcePoolName) + err = retrievedPvdc.DeleteResourcePools([]*ResourcePool{secondResourcePool}) + check.Assert(err, IsNil) + err = retrievedPvdc.Refresh() + check.Assert(err, IsNil) + check.Assert(len(retrievedPvdc.VMWProviderVdc.ResourcePoolRefs.VimObjectRef), Equals, 1) + } + + secondStorageProfile := creationElements.config.VCD.NsxtProviderVdc.StorageProfile2 + if secondStorageProfile != "" { + printVerbose(" adding storage profile '%s' to provider VDC\n", secondStorageProfile) + // Adds a storage profile + err = retrievedPvdc.AddStorageProfiles([]string{secondStorageProfile}) + check.Assert(err, IsNil) + check.Assert(len(retrievedPvdc.VMWProviderVdc.StorageProfiles.ProviderVdcStorageProfile), Equals, 2) + + printVerbose(" removing storage profile '%s' from provider VDC\n", secondStorageProfile) + // Remove a storage profile + err = retrievedPvdc.DeleteStorageProfiles([]string{secondStorageProfile}) + check.Assert(err, IsNil) + check.Assert(len(retrievedPvdc.VMWProviderVdc.StorageProfiles.ProviderVdcStorageProfile), Equals, 1) + } + + // Deleting while the Provider VDC is still enabled will fail + task, err := retrievedPvdc.Delete() + check.Assert(err, NotNil) + + // Properly deleting provider VDC: first disabling, then removing + printVerbose(" disabling provider VDC '%s'\n", providerVdcName) + err = retrievedPvdc.Disable() + check.Assert(err, IsNil) + check.Assert(retrievedPvdc.VMWProviderVdc.IsEnabled, NotNil) + check.Assert(*retrievedPvdc.VMWProviderVdc.IsEnabled, Equals, false) + + printVerbose(" removing provider VDC '%s'\n", providerVdcName) + task, err = retrievedPvdc.Delete() + check.Assert(err, IsNil) + err = task.WaitTaskCompletion() + check.Assert(err, IsNil) +} diff --git a/govcd/query_metadata.go b/govcd/query_metadata.go index 333f3d7b9..f031195e8 100644 --- a/govcd/query_metadata.go +++ b/govcd/query_metadata.go @@ -166,6 +166,15 @@ func addResults(queryType string, cumulativeResults, newResults Results) (Result case types.QtAdminTask: cumulativeResults.Results.AdminTaskRecord = append(cumulativeResults.Results.AdminTaskRecord, newResults.Results.AdminTaskRecord...) size = len(newResults.Results.AdminTaskRecord) + case types.QtNetworkPool: + cumulativeResults.Results.NetworkPoolRecord = append(cumulativeResults.Results.NetworkPoolRecord, newResults.Results.NetworkPoolRecord...) + size = len(newResults.Results.NetworkPoolRecord) + case types.QtProviderVdcStorageProfile: + cumulativeResults.Results.ProviderVdcStorageProfileRecord = append(cumulativeResults.Results.ProviderVdcStorageProfileRecord, newResults.Results.ProviderVdcStorageProfileRecord...) + size = len(newResults.Results.ProviderVdcStorageProfileRecord) + case types.QtResourcePool: + cumulativeResults.Results.ResourcePoolRecord = append(cumulativeResults.Results.ResourcePoolRecord, newResults.Results.ResourcePoolRecord...) + size = len(newResults.Results.ResourcePoolRecord) default: return Results{}, 0, fmt.Errorf("query type %s not supported", queryType) @@ -200,6 +209,9 @@ func (client *Client) cumulativeQueryWithHeaders(queryType string, params, notEn types.QtAdminOrgVdc, types.QtTask, types.QtAdminTask, + types.QtResourcePool, + types.QtNetworkPool, + types.QtProviderVdcStorageProfile, } // Make sure the query type is supported // We need to check early, as queries that would return less than 25 items (default page size) would succeed, diff --git a/govcd/sample_govcd_test_config.yaml b/govcd/sample_govcd_test_config.yaml index 7aa332f08..25d2c1dc0 100644 --- a/govcd/sample_govcd_test_config.yaml +++ b/govcd/sample_govcd_test_config.yaml @@ -73,6 +73,7 @@ vcd: nsxt_provider_vdc: name: nsxTPvdc1 storage_profile: "*" + storage_profile_2: "Development2" 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. @@ -174,6 +175,10 @@ vcd: # IP of a pre-configured LDAP server # using Docker image https://github.com/rroemhild/docker-test-openldap ldap_server: 10.10.10.99 +vsphere: + # resource pools needed to create new provider VDCs + resourcePoolForVcd1: resource-pool-for-vcd-01 + resourcePoolForVcd2: resource-pool-for-vcd-02 logging: # All items in this section are optional # Logging is disabled by default. diff --git a/govcd/system.go b/govcd/system.go index b320673b2..7a71e609b 100644 --- a/govcd/system.go +++ b/govcd/system.go @@ -753,21 +753,14 @@ func (client *Client) GetStorageProfileByHref(url string) (*types.VdcStorageProf // 3. [NOT FOUND] The name matches, is not unique, but no Provider HREF was given: the search will fail // 4. [NOT FOUND] The name does not match any of the storage profiles func (vcdClient *VCDClient) QueryProviderVdcStorageProfileByName(name, providerVDCHref string) (*types.QueryResultProviderVdcStorageProfileRecordType, error) { - results, err := vcdClient.QueryWithNotEncodedParams(nil, map[string]string{ - "type": "providerVdcStorageProfile", - "pageSize": "128", - }) + + results, err := vcdClient.Client.cumulativeQuery(types.QtProviderVdcStorageProfile, map[string]string{ + "type": types.QtProviderVdcStorageProfile, + }, nil) if err != nil { return nil, err } - // Note: pageSize of 128 (the maximum page size allowed) should be enough to get all storage profiles. - // In case this is not true, we trap the error, so that we become aware that this assumption is incorrect. - // TODO: convert this query into a cumulativeQuery - if results.Results.Total > 128.0 { - return nil, fmt.Errorf("[QueryWithNotEncodedParams] FATAL - more than 128 storage profiles found. Refactory needed") - } - var recs []*types.QueryResultProviderVdcStorageProfileRecordType for _, rec := range results.Results.ProviderVdcStorageProfileRecord { if rec.Name == name { @@ -812,8 +805,8 @@ func QueryProviderVdcStorageProfileByName(vcdCli *VCDClient, name string) ([]*ty // QueryNetworkPoolByName finds a network pool by name func QueryNetworkPoolByName(vcdCli *VCDClient, name string) ([]*types.QueryResultNetworkPoolRecordType, error) { - results, err := vcdCli.QueryWithNotEncodedParams(nil, map[string]string{ - "type": "networkPool", + results, err := vcdCli.Client.cumulativeQuery(types.QtNetworkPool, nil, map[string]string{ + "type": types.QtNetworkPool, "filter": fmt.Sprintf("name==%s", url.QueryEscape(name)), "filterEncoded": "true", }) @@ -852,9 +845,7 @@ func (vcdClient *VCDClient) QueryProviderVdcs() ([]*types.QueryResultVMWProvider // QueryNetworkPools gets the list of network pools func (vcdClient *VCDClient) QueryNetworkPools() ([]*types.QueryResultNetworkPoolRecordType, error) { - results, err := vcdClient.QueryWithNotEncodedParams(nil, map[string]string{ - "type": "networkPool", - }) + results, err := vcdClient.Client.cumulativeQuery(types.QtNetworkPool, nil, map[string]string{"type": types.QtNetworkPool}) if err != nil { return nil, err } @@ -870,9 +861,7 @@ func (vcdClient *VCDClient) QueryProviderVdcStorageProfiles() ([]*types.QueryRes // QueryAllProviderVdcStorageProfiles gets the list of provider VDC storage profiles from ALL provider VDCs func (client *Client) QueryAllProviderVdcStorageProfiles() ([]*types.QueryResultProviderVdcStorageProfileRecordType, error) { - results, err := client.QueryWithNotEncodedParams(nil, map[string]string{ - "type": "providerVdcStorageProfile", - }) + results, err := client.cumulativeQuery(types.QtProviderVdcStorageProfile, nil, map[string]string{"type": types.QtProviderVdcStorageProfile}) if err != nil { return nil, err } @@ -882,8 +871,8 @@ func (client *Client) QueryAllProviderVdcStorageProfiles() ([]*types.QueryResult // QueryProviderVdcStorageProfiles gets the list of provider VDC storage profiles for a given Provider VDC func (client *Client) QueryProviderVdcStorageProfiles(providerVdcHref string) ([]*types.QueryResultProviderVdcStorageProfileRecordType, error) { - results, err := client.QueryWithNotEncodedParams(nil, map[string]string{ - "type": "providerVdcStorageProfile", + results, err := client.cumulativeQuery(types.QtProviderVdcStorageProfile, nil, map[string]string{ + "type": types.QtProviderVdcStorageProfile, "filter": fmt.Sprintf("providerVdc==%s", providerVdcHref), }) if err != nil { @@ -951,6 +940,20 @@ func (vcdClient *VCDClient) QueryNsxtManagerByName(name string) ([]*types.QueryR return results.Results.NsxtManagerRecord, nil } +// QueryNsxtManagerByHref searches for NSX-T managers available in VCD +func (vcdClient *VCDClient) QueryNsxtManagerByHref(href string) ([]*types.QueryResultNsxtManagerRecordType, error) { + results, err := vcdClient.QueryWithNotEncodedParams(nil, map[string]string{ + "type": "nsxTManager", + "filter": fmt.Sprintf("href==%s", extractUuid(href)), + "filterEncoded": "true", + }) + if err != nil { + return nil, err + } + + return results.Results.NsxtManagerRecord, nil +} + // GetOrgByName finds an Organization by name // On success, returns a pointer to the Org structure and a nil error // On failure, returns a nil pointer and an error diff --git a/govcd/vsphere_resource_pool.go b/govcd/vsphere_resource_pool.go new file mode 100644 index 000000000..2f8d53c17 --- /dev/null +++ b/govcd/vsphere_resource_pool.go @@ -0,0 +1,211 @@ +/* + * 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" + "github.com/vmware/go-vcloud-director/v2/util" + "net/url" +) + +type ResourcePool struct { + ResourcePool *types.ResourcePool + vcenter *VCenter + client *VCDClient +} + +// GetAllResourcePools retrieves all resource pools for a given vCenter +func (vcenter VCenter) GetAllResourcePools(queryParams url.Values) ([]*ResourcePool, error) { + client := vcenter.client.Client + endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointResourcePoolsBrowseAll + minimumApiVersion, err := client.checkOpenApiEndpointCompatibility(endpoint) + if err != nil { + return nil, err + } + + urlRef, err := client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, vcenter.VSphereVCenter.VcId)) + if err != nil { + return nil, err + } + + retrieved := []*types.ResourcePool{{}} + + err = client.OpenApiGetAllItems(minimumApiVersion, urlRef, queryParams, &retrieved, nil) + if err != nil { + return nil, fmt.Errorf("error getting resource pool list: %s", err) + } + + if len(retrieved) == 0 { + return nil, nil + } + var returnList []*ResourcePool + + for _, r := range retrieved { + newRp := r + returnList = append(returnList, &ResourcePool{ + ResourcePool: newRp, + vcenter: &vcenter, + client: vcenter.client, + }) + } + return returnList, nil +} + +// GetAvailableHardwareVersions finds the hardware versions of a given resource pool +// In addition to proper resource pools, this method also works for any entity that is retrieved as a resource pool, +// such as provider VDCs and Org VDCs +func (rp ResourcePool) GetAvailableHardwareVersions() (*types.OpenApiSupportedHardwareVersions, error) { + + client := rp.client.Client + endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointResourcePoolHardware + minimumApiVersion, err := client.checkOpenApiEndpointCompatibility(endpoint) + if err != nil { + return nil, err + } + + urlRef, err := client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, rp.vcenter.VSphereVCenter.VcId, rp.ResourcePool.Moref)) + if err != nil { + return nil, err + } + + retrieved := types.OpenApiSupportedHardwareVersions{} + err = client.OpenApiGetItem(minimumApiVersion, urlRef, nil, &retrieved, nil) + if err != nil { + return nil, fmt.Errorf("error getting resource pool hardware versions: %s", err) + } + + return &retrieved, nil +} + +// GetDefaultHardwareVersion retrieves the default hardware version for a given resource pool. +// The default version is usually the highest available, but it's not guaranteed +func (rp ResourcePool) GetDefaultHardwareVersion() (string, error) { + + versions, err := rp.GetAvailableHardwareVersions() + if err != nil { + return "", err + } + + for _, v := range versions.SupportedVersions { + if v.IsDefault { + return v.Name, nil + } + } + return "", fmt.Errorf("no default hardware version found for resource pool %s", rp.ResourcePool.Name) +} + +// GetResourcePoolById retrieves a resource pool by its ID (Moref) +func (vcenter VCenter) GetResourcePoolById(id string) (*ResourcePool, error) { + resourcePools, err := vcenter.GetAllResourcePools(nil) + if err != nil { + return nil, err + } + for _, rp := range resourcePools { + if rp.ResourcePool.Moref == id { + return rp, nil + } + } + return nil, fmt.Errorf("no resource pool found with ID '%s' :%s", id, ErrorEntityNotFound) +} + +// GetResourcePoolByName retrieves a resource pool by name. +// It may fail if there are several resource pools with the same name +func (vcenter VCenter) GetResourcePoolByName(name string) (*ResourcePool, error) { + resourcePools, err := vcenter.GetAllResourcePools(nil) + if err != nil { + return nil, err + } + var found []*ResourcePool + for _, rp := range resourcePools { + if rp.ResourcePool.Name == name { + found = append(found, rp) + } + } + if len(found) == 0 { + return nil, fmt.Errorf("no resource pool found with name '%s' :%s", name, ErrorEntityNotFound) + } + if len(found) > 1 { + var idList []string + for _, f := range found { + idList = append(idList, f.ResourcePool.Moref) + } + return nil, fmt.Errorf("more than one resource pool was found with name %s - use resource pool ID instead - %v", name, idList) + } + return found[0], nil +} + +// GetAllResourcePools retrieves all available resource pool, across all vCenters +func (vcdClient *VCDClient) GetAllResourcePools(queryParams url.Values) ([]*ResourcePool, error) { + + vcenters, err := vcdClient.GetAllVCenters(queryParams) + if err != nil { + return nil, err + } + var result []*ResourcePool + for _, vc := range vcenters { + resourcePools, err := vc.GetAllResourcePools(queryParams) + if err != nil { + return nil, err + } + result = append(result, resourcePools...) + } + return result, nil +} + +// ResourcePoolsFromIds returns a slice of resource pools from a slice of resource pool IDs +func (vcdClient *VCDClient) ResourcePoolsFromIds(resourcePoolIds []string) ([]*ResourcePool, error) { + if len(resourcePoolIds) == 0 { + return nil, nil + } + + var result []*ResourcePool + + // 1. make sure there are no duplicates in the input IDs + uniqueIds := make(map[string]bool) + var duplicates []string + for _, id := range resourcePoolIds { + _, seen := uniqueIds[id] + if seen { + duplicates = append(duplicates, id) + } + uniqueIds[id] = true + } + + if len(duplicates) > 0 { + return nil, fmt.Errorf("duplicate IDs found in input: %v", duplicates) + } + + // 2. get all resource pools + resourcePools, err := vcdClient.GetAllResourcePools(nil) + if err != nil { + return nil, err + } + + util.Logger.Printf("wantedRecords: %v\n", resourcePoolIds) + // 3. build a map of resource pools, indexed by ID, for easy search + var foundRecords = make(map[string]*ResourcePool) + + for _, rpr := range resourcePools { + foundRecords[rpr.ResourcePool.Moref] = rpr + } + + // 4. loop through the requested IDs + for wanted := range uniqueIds { + // 4.1 if the wanted ID is not found, exit with an error + foundResourcePool, ok := foundRecords[wanted] + if !ok { + return nil, fmt.Errorf("resource pool ID '%s' not found in VCD", wanted) + } + result = append(result, foundResourcePool) + } + + // 5. Check that we got as many resource pools as the requested IDs + if len(result) != len(uniqueIds) { + return result, fmt.Errorf("%d IDs were requested, but only %d found", len(uniqueIds), len(result)) + } + + return result, nil +} diff --git a/govcd/vsphere_resource_pool_test.go b/govcd/vsphere_resource_pool_test.go new file mode 100644 index 000000000..87adb4dca --- /dev/null +++ b/govcd/vsphere_resource_pool_test.go @@ -0,0 +1,51 @@ +//go:build vsphere || functional || ALL + +package govcd + +import ( + "fmt" + "github.com/kr/pretty" + . "gopkg.in/check.v1" + "strings" +) + +func (vcd *TestVCD) Test_GetResourcePools(check *C) { + + if !vcd.client.Client.IsSysAdmin { + check.Skip("this test requires system administrator privileges") + } + vcenters, err := vcd.client.GetAllVCenters(nil) + check.Assert(err, IsNil) + + check.Assert(len(vcenters) > 0, Equals, true) + + vc := vcenters[0] + + allResourcePools, err := vc.GetAllResourcePools(nil) + check.Assert(err, IsNil) + + for i, rp := range allResourcePools { + rpByID, err := vc.GetResourcePoolById(rp.ResourcePool.Moref) + check.Assert(err, IsNil) + check.Assert(rpByID.ResourcePool.Moref, Equals, rp.ResourcePool.Moref) + check.Assert(rpByID.ResourcePool.Name, Equals, rp.ResourcePool.Name) + rpByName, err := vc.GetResourcePoolByName(rp.ResourcePool.Name) + if err != nil && strings.Contains(err.Error(), "more than one") { + if testVerbose { + fmt.Printf("%s\n", err) + } + continue + } + check.Assert(err, IsNil) + check.Assert(rpByName.ResourcePool.Moref, Equals, rp.ResourcePool.Moref) + check.Assert(rpByName.ResourcePool.Name, Equals, rp.ResourcePool.Name) + if testVerbose { + fmt.Printf("%2d %# v\n", i, pretty.Formatter(rp.ResourcePool)) + } + hw, err := rp.GetAvailableHardwareVersions() + check.Assert(err, IsNil) + if testVerbose { + fmt.Printf("%s %#v\n", rp.ResourcePool.Name, hw) + } + } +} diff --git a/govcd/vsphere_storage_profile.go b/govcd/vsphere_storage_profile.go new file mode 100644 index 000000000..b54172e08 --- /dev/null +++ b/govcd/vsphere_storage_profile.go @@ -0,0 +1,103 @@ +/* + * 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" +) + +/* +Note: These storage profile methods refer to storage profiles before they get assigned to a provider VDC. +This file, with related tests, was created before realizing that these calls do not retrieve the `*(Any)` +storage profile. +*/ + +// StorageProfile contains a storage profile in a given context (usually, a resource pool) +type StorageProfile struct { + StorageProfile *types.OpenApiStorageProfile + vcenter *VCenter + client *VCDClient +} + +// GetAllStorageProfiles retrieves all storage profiles existing in a given storage profile context +// Note: this function finds all *named* resource pools, but not the unnamed one [*(Any)] +func (vcenter VCenter) GetAllStorageProfiles(resourcePoolId string, queryParams url.Values) ([]*StorageProfile, error) { + client := vcenter.client.Client + endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointStorageProfiles + minimumApiVersion, err := client.checkOpenApiEndpointCompatibility(endpoint) + if err != nil { + return nil, err + } + + urlRef, err := client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, vcenter.VSphereVCenter.VcId)) + if err != nil { + return nil, err + } + + retrieved := []*types.OpenApiStorageProfile{{}} + + if queryParams == nil { + queryParams = url.Values{} + } + if resourcePoolId != "" { + queryParams.Set("filter", fmt.Sprintf("_context==%s", resourcePoolId)) + } + err = client.OpenApiGetAllItems(minimumApiVersion, urlRef, queryParams, &retrieved, nil) + if err != nil { + return nil, fmt.Errorf("error getting storage profile list: %s", err) + } + + if len(retrieved) == 0 { + return nil, nil + } + var returnList []*StorageProfile + + for _, sp := range retrieved { + newSp := sp + returnList = append(returnList, &StorageProfile{ + StorageProfile: newSp, + vcenter: &vcenter, + client: vcenter.client, + }) + } + return returnList, nil +} + +// GetStorageProfileById retrieves a storage profile in the context of a given resource pool +func (vcenter VCenter) GetStorageProfileById(resourcePoolId, id string) (*StorageProfile, error) { + storageProfiles, err := vcenter.GetAllStorageProfiles(resourcePoolId, nil) + if err != nil { + return nil, err + } + for _, sp := range storageProfiles { + if sp.StorageProfile.Moref == id { + return sp, nil + } + } + return nil, fmt.Errorf("no storage profile found with ID '%s': %s", id, err) +} + +// GetStorageProfileByName retrieves a storage profile in the context of a given resource pool +func (vcenter VCenter) GetStorageProfileByName(resourcePoolId, name string) (*StorageProfile, error) { + storageProfiles, err := vcenter.GetAllStorageProfiles(resourcePoolId, nil) + if err != nil { + return nil, err + } + var found []*StorageProfile + for _, sp := range storageProfiles { + if sp.StorageProfile.Name == name { + found = append(found, sp) + } + } + if len(found) == 0 { + return nil, fmt.Errorf("no storage profile found with name '%s': %s", name, ErrorEntityNotFound) + } + if len(found) > 1 { + return nil, fmt.Errorf("more than one storage profile found with name '%s'", name) + } + return found[0], nil +} diff --git a/govcd/vsphere_storage_profile_test.go b/govcd/vsphere_storage_profile_test.go new file mode 100644 index 000000000..3883d6929 --- /dev/null +++ b/govcd/vsphere_storage_profile_test.go @@ -0,0 +1,54 @@ +//go:build vsphere || functional || ALL + +/* + * Copyright 2023 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. + */ + +package govcd + +import ( + "fmt" + "github.com/kr/pretty" + . "gopkg.in/check.v1" + "strings" +) + +func (vcd *TestVCD) Test_GetStorageProfiles(check *C) { + if !vcd.client.Client.IsSysAdmin { + check.Skip("this test requires system administrator privileges") + } + vcenters, err := vcd.client.GetAllVCenters(nil) + check.Assert(err, IsNil) + + check.Assert(len(vcenters) > 0, Equals, true) + + vc := vcenters[0] + + if vcd.config.Vsphere.ResourcePoolForVcd1 == "" { + check.Skip("no resource pool found for this VCD") + } + + resourcePool, err := vc.GetResourcePoolByName(vcd.config.Vsphere.ResourcePoolForVcd1) + check.Assert(err, IsNil) + + allStorageProfiles, err := vc.GetAllStorageProfiles(resourcePool.ResourcePool.Moref, nil) + check.Assert(err, IsNil) + + for i, sp := range allStorageProfiles { + spById, err := vc.GetStorageProfileById(resourcePool.ResourcePool.Moref, sp.StorageProfile.Moref) + check.Assert(err, IsNil) + check.Assert(spById.StorageProfile.Moref, Equals, sp.StorageProfile.Moref) + check.Assert(spById.StorageProfile.Name, Equals, sp.StorageProfile.Name) + spByName, err := vc.GetStorageProfileByName(resourcePool.ResourcePool.Moref, sp.StorageProfile.Name) + if err != nil && strings.Contains(err.Error(), "more than one") { + fmt.Printf("%s\n", err) + continue + } + check.Assert(err, IsNil) + check.Assert(spByName.StorageProfile.Moref, Equals, sp.StorageProfile.Moref) + check.Assert(spByName.StorageProfile.Name, Equals, sp.StorageProfile.Name) + if testVerbose { + fmt.Printf("%2d %# v\n", i, pretty.Formatter(sp.StorageProfile)) + } + } +} diff --git a/govcd/vsphere_vcenter.go b/govcd/vsphere_vcenter.go new file mode 100644 index 000000000..37e664a40 --- /dev/null +++ b/govcd/vsphere_vcenter.go @@ -0,0 +1,93 @@ +/* + * 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 VCenter struct { + VSphereVCenter *types.VSphereVirtualCenter + client *VCDClient +} + +func (vcdClient *VCDClient) GetAllVCenters(queryParams url.Values) ([]*VCenter, error) { + client := vcdClient.Client + endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVirtualCenters + minimumApiVersion, err := client.checkOpenApiEndpointCompatibility(endpoint) + if err != nil { + return nil, err + } + + urlRef, err := client.OpenApiBuildEndpoint(endpoint) + if err != nil { + return nil, err + } + + var retrieved []*types.VSphereVirtualCenter + + err = client.OpenApiGetAllItems(minimumApiVersion, urlRef, queryParams, &retrieved, nil) + if err != nil { + return nil, fmt.Errorf("error getting vCenters list: %s", err) + } + + if len(retrieved) == 0 { + return nil, nil + } + var returnList []*VCenter + + for _, r := range retrieved { + returnList = append(returnList, &VCenter{ + VSphereVCenter: r, + client: vcdClient, + }) + } + return returnList, nil +} + +func (vcdClient *VCDClient) GetVCenterByName(name string) (*VCenter, error) { + vcenters, err := vcdClient.GetAllVCenters(nil) + if err != nil { + return nil, err + } + for _, vc := range vcenters { + if vc.VSphereVCenter.Name == name { + return vc, nil + } + } + return nil, fmt.Errorf("vcenter %s not found: %s", name, ErrorEntityNotFound) +} + +func (vcdClient *VCDClient) GetVCenterById(id string) (*VCenter, error) { + client := vcdClient.Client + endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVirtualCenters + minimumApiVersion, err := client.checkOpenApiEndpointCompatibility(endpoint) + if err != nil { + return nil, err + } + + urlRef, err := client.OpenApiBuildEndpoint(endpoint + "/" + id) + if err != nil { + return nil, err + } + + returnObject := &VCenter{ + VSphereVCenter: &types.VSphereVirtualCenter{}, + client: vcdClient, + } + + err = client.OpenApiGetItem(minimumApiVersion, urlRef, nil, returnObject.VSphereVCenter, nil) + if err != nil { + return nil, fmt.Errorf("error getting vCenter: %s", err) + } + + return returnObject, nil +} + +func (vcenter VCenter) GetVimServerUrl() (string, error) { + return url.JoinPath(vcenter.client.Client.VCDHREF.String(), "admin", "extension", "vimServer", extractUuid(vcenter.VSphereVCenter.VcId)) +} diff --git a/govcd/vsphere_vcenter_test.go b/govcd/vsphere_vcenter_test.go new file mode 100644 index 000000000..b0316623e --- /dev/null +++ b/govcd/vsphere_vcenter_test.go @@ -0,0 +1,28 @@ +//go:build vsphere || functional || ALL + +package govcd + +import ( + . "gopkg.in/check.v1" +) + +func (vcd *TestVCD) Test_GetVcenters(check *C) { + + if !vcd.client.Client.IsSysAdmin { + check.Skip("this test requires system administrator privileges") + } + vcenters, err := vcd.client.GetAllVCenters(nil) + check.Assert(err, IsNil) + + check.Assert(len(vcenters) > 0, Equals, true) + + for _, vc := range vcenters { + vcenterById, err := vcd.client.GetVCenterById(vc.VSphereVCenter.VcId) + check.Assert(err, IsNil) + check.Assert(vc.VSphereVCenter.VcId, Equals, vcenterById.VSphereVCenter.VcId) + vcenterByName, err := vcd.client.GetVCenterByName(vc.VSphereVCenter.Name) + check.Assert(err, IsNil) + check.Assert(vc.VSphereVCenter.VcId, Equals, vcenterByName.VSphereVCenter.VcId) + } + +} diff --git a/types/v56/constants.go b/types/v56/constants.go index 0631a282a..3be528555 100644 --- a/types/v56/constants.go +++ b/types/v56/constants.go @@ -141,6 +141,8 @@ const ( MimeSubscribeToExternalCatalog = "application/vnd.vmware.admin.externalCatalogSubscriptionParams+json" // Mime to identify a media item MimeMediaItem = "application/vnd.vmware.vcloud.media+xml" + // Mime to identify a provider VDC + MimeProviderVdc = "application/vnd.vmware.admin.vmwprovidervdc+xml" // Mime to identify SAML metadata MimeSamlMetadata = "application/samlmetadata+xml" // Mime to identify organization federation settings (SAML) XML and JSON @@ -271,6 +273,9 @@ const ( QtAdminOrgVdcStorageProfile = "adminOrgVdcStorageProfile" // StorageProfile of VDC as admin QtTask = "task" // Task QtAdminTask = "adminTask" // Task as admin + QtResourcePool = "resourcePool" // Resource Pool + QtNetworkPool = "networkPool" // Network Pool + QtProviderVdcStorageProfile = "providerVdcStorageProfile" // StorageProfile of Provider VDC ) // AdminQueryTypes returns the corresponding "admin" query type for each regular type @@ -405,6 +410,13 @@ const ( OpenApiEndpointRdeEntities = "entities/" OpenApiEndpointRdeEntitiesTypes = "entities/types/" OpenApiEndpointRdeEntitiesResolve = "entities/%s/resolve" + OpenApiEndpointVirtualCenters = "virtualCenters" + OpenApiEndpointResourcePools = "virtualCenters/%s/resourcePools/browse" // '%s' is vCenter ID + OpenApiEndpointResourcePoolsBrowseAll = "virtualCenters/%s/resourcePools/browseAll" // '%s' is vCenter ID + OpenApiEndpointResourcePoolHardware = "virtualCenters/%s/resourcePools/%s/hwv" // first '%s' is vCenter ID. Second one is Resource Pool MoRef + OpenApiEndpointNetworkPools = "networkPools/" + OpenApiEndpointNetworkPoolSummaries = "networkPools/networkPoolSummaries" + OpenApiEndpointStorageProfiles = "virtualCenters/%s/storageProfiles" // '%s' is vCenter ID OpenApiEndpointExtensionsUi = "extensions/ui/" OpenApiEndpointExtensionsUiPlugin = "extensions/ui/%s/plugin" OpenApiEndpointExtensionsUiTenants = "extensions/ui/%s/tenants" diff --git a/types/v56/openapi.go b/types/v56/openapi.go index af916fbb1..2d9b55448 100644 --- a/types/v56/openapi.go +++ b/types/v56/openapi.go @@ -466,6 +466,101 @@ type DefinedEntity struct { Org *OpenApiReference `json:"org,omitempty"` // The organization of the defined entity. } +type VSphereVirtualCenter struct { + VcId string `json:"vcId"` + Name string `json:"name"` + Description string `json:"description"` + Username string `json:"username"` + Password string `json:"password"` + Url string `json:"url"` + IsEnabled bool `json:"isEnabled"` + VsphereWebClientServerUrl string `json:"vsphereWebClientServerUrl"` + HasProxy bool `json:"hasProxy"` + RootFolder string `json:"rootFolder"` + VcNoneNetwork string `json:"vcNoneNetwork"` + TenantVisibleName string `json:"tenantVisibleName"` + IsConnected bool `json:"isConnected"` + Mode string `json:"mode"` + ListenerState string `json:"listenerState"` + ClusterHealthStatus string `json:"clusterHealthStatus"` + VcVersion string `json:"vcVersion"` + BuildNumber string `json:"buildNumber"` + Uuid string `json:"uuid"` + NsxVManager struct { + Username string `json:"username"` + Password string `json:"password"` + Url string `json:"url"` + SoftwareVersion string `json:"softwareVersion"` + } `json:"nsxVManager"` + ProxyConfigurationUrn string `json:"proxyConfigurationUrn"` +} + +type ResourcePoolSummary struct { + Associations []struct { + EntityId string `json:"entityId"` + AssociationId string `json:"associationId"` + } `json:"associations"` + Values []ResourcePool `json:"values"` +} + +// ResourcePool defines a vSphere Resource Pool +type ResourcePool struct { + Moref string `json:"moref"` + ClusterMoref string `json:"clusterMoref"` + Name string `json:"name"` + VcId string `json:"vcId"` + Eligible bool `json:"eligible"` + KubernetesEnabled bool `json:"kubernetesEnabled"` + VgpuEnabled bool `json:"vgpuEnabled"` +} + +// OpenApiSupportedHardwareVersions is the list of versions supported by a given resource +type OpenApiSupportedHardwareVersions struct { + Versions []string `json:"versions"` + SupportedVersions []struct { + IsDefault bool `json:"isDefault"` + Name string `json:"name"` + } `json:"supportedVersions"` +} + +// NetworkPool is the full data retrieved for a provider network pool +type NetworkPool struct { + Status string `json:"status"` + Id string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + PoolType string `json:"poolType"` + PromiscuousMode bool `json:"promiscuousMode"` + TotalBackingsCount int `json:"totalBackingsCount"` + UsedBackingsCount int `json:"usedBackingsCount"` + ManagingOwnerRef OpenApiReference `json:"managingOwnerRef"` + Backing NetworkPoolBacking `json:"backing"` +} + +// NetworkPoolBacking is the definition of the objects supporting the network pool +type NetworkPoolBacking struct { + VlanIdRanges VlanIdRanges `json:"vlanIdRanges"` + VdsRefs []OpenApiReference `json:"vdsRefs"` + PortGroupRefs []OpenApiReference `json:"portGroupRefs"` + TransportZoneRef OpenApiReference `json:"transportZoneRef"` + ProviderRef OpenApiReference `json:"providerRef"` +} + +type VlanIdRanges struct { + Values []VlanIdRange `json:"values"` +} + +type VlanIdRange struct { + StartId int `json:"startId"` + EndId int `json:"endId"` +} + +// OpenApiStorageProfile defines a storage profile before it is assigned to a provider VDC +type OpenApiStorageProfile struct { + Moref string `json:"moref"` + Name string `json:"name"` +} + // UIPluginMetadata gives meta information about a UI Plugin type UIPluginMetadata struct { ID string `json:"id,omitempty"` diff --git a/types/v56/types.go b/types/v56/types.go index d5efa6853..c8e37b59d 100644 --- a/types/v56/types.go +++ b/types/v56/types.go @@ -397,7 +397,7 @@ type OrgVDCNetwork struct { // Description: Contains a list of VMware virtual hardware versions supported in this vDC. // Since: 1.5 type SupportedHardwareVersions struct { - SupportedHardwareVersion []string `xml:"SupportedHardwareVersion,omitempty"` // A virtual hardware version supported in this vDC. + SupportedHardwareVersion []Reference `xml:"SupportedHardwareVersion,omitempty"` // A virtual hardware version supported in this vDC. } // Capabilities collection of supported hardware capabilities. @@ -406,7 +406,7 @@ type SupportedHardwareVersions struct { // Description: Collection of supported hardware capabilities. // Since: 1.5 type Capabilities struct { - SupportedHardwareVersions *SupportedHardwareVersions `xml:"SupportedHardwareVersions,omitempty"` // Read-only list of virtual hardware versions supported by this vDC. + SupportedHardwareVersions *SupportedHardwareVersions `xml:"SupportedHardwareVersions,omitempty" json:"supportedHardwareVersions,omitempty"` // Read-only list of virtual hardware versions supported by this vDC. } // Vdc represents the user view of an organization VDC. @@ -473,23 +473,22 @@ type AdminVdc struct { // Description: Represents a Provider VDC. // Since: 0.9 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"` // -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:"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. - Link *Link `xml:"Link,omitempty"` // A reference to an entity or operation associated with this object. - 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. + HREF string `xml:"href,attr,omitempty" json:"href,omitempty"` + Type string `xml:"type,attr,omitempty" json:"type,omitempty"` + ID string `xml:"id,attr,omitempty" json:"id,omitempty"` + OperationKey string `xml:"operationKey,attr,omitempty" json:"operationKey,omitempty"` + Name string `xml:"name,attr" json:"name"` + Status int `xml:"status,attr,omitempty" json:"status,omitempty"` // -1 (creation failed), 0 (not ready), 1 (ready), 2 (unknown), 3 (unrecognized) + + AvailableNetworks *AvailableNetworks `xml:"AvailableNetworks,omitempty" json:"availableNetworks,omitempty"` // Read-only list of available networks. + Capabilities *Capabilities `xml:"Capabilities,omitempty" json:"capabilities,omitempty"` // Read-only list of virtual hardware versions supported by this Provider VDC. + ComputeCapacity *RootComputeCapacity `xml:"ComputeCapacity,omitempty" json:"computeCapacity,omitempty"` // Read-only indicator of CPU and memory capacity. + Description string `xml:"Description,omitempty" json:"description,omitempty"` // Optional description. + IsEnabled *bool `xml:"IsEnabled,omitempty" json:"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 *LinkList `xml:"Link,omitempty" json:"link,omitempty"` // A reference to an entity or operation associated with this object. + NetworkPoolReferences *NetworkPoolReferences `xml:"NetworkPoolReferences,omitempty" json:"networkPoolReferences,omitempty"` // Read-only list of network pools used by this Provider VDC. + StorageProfiles *ProviderStorageProfiles `xml:"StorageProfiles,omitempty" json:"storageProfiles,omitempty"` // Container for references to vSphere storage profiles available to this Provider VDC. + Tasks *TasksInProgress `xml:"Tasks,omitempty" json:"tasks,omitempty"` // A list of queued, running, or recently completed tasks associated with this entity. } // VMWProviderVdc represents an extension of ProviderVdc. @@ -500,14 +499,14 @@ type ProviderVdc struct { 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. + AvailableUniversalNetworkPool *Reference `xml:"AvailableUniversalNetworkPool,omitempty" json:"availableUniversalNetworkPool,omitempty"` // Selectable universal network reference. + ComputeProviderScope string `xml:"ComputeProviderScope,omitempty" json:"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" json:"dataStoreRefs"` // vSphere datastores backing this provider VDC. + HighestSupportedHardwareVersion string `xml:"HighestSupportedHardwareVersion,omitempty" json:"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" json:"hostReferences,omitempty"` // Shows all hosts which are connected to VC server. + NsxTManagerReference *Reference `xml:"NsxTManagerReference,omitempty" json:"nsxTManagerReference,omitempty"` // An optional reference to a registered NSX-T Manager to back networking operations for this provider VDC. + ResourcePoolRefs *VimObjectRefs `xml:"ResourcePoolRefs,omitempty" json:"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" json:"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. @@ -516,8 +515,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" json:"hostReference,omitempty"` + Link *Link `xml:"Link,omitempty" json:"link,omitempty"` } // RootComputeCapacity represents compute capacity with units. @@ -526,10 +525,10 @@ type VMWHostReferences struct { // 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"` + Cpu *ProviderVdcCapacity `xml:"Cpu" json:"cpu"` + IsElastic bool `xml:"IsElastic,omitempty" json:"isElastic,omitempty"` + IsHA bool `xml:"IsHA,omitempty" json:"isHA,omitempty"` + Memory *ProviderVdcCapacity `xml:"Memory" json:"memory"` } // NetworkPoolReferences is a container for references to network pools in this vDC. @@ -538,7 +537,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" json:"networkPoolReference"` } // ProviderStorageProfiles is a container for references to storage profiles associated with a Provider vDC. @@ -547,7 +546,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" json:"providerVdcStorageProfile,omitempty"` } // ProviderVdcCapacity represents resource capacity in a Provider vDC. @@ -660,32 +659,32 @@ type VdcConfiguration struct { // Task represents an asynchronous operation in VMware Cloud Director. // Type: TaskType // Namespace: http://www.vmware.com/vcloud/v1.5 -// Description: Represents an asynchronous operation in VMware Cloud Director. +// Description: Represents an asynchronous operation in VMware Cloud Director.u // Since: 0.9 // Comments added from https://code.vmware.com/apis/912/vmware-cloud-director/doc/doc/types/TaskType.html type Task struct { - HREF string `xml:"href,attr,omitempty"` // The URI of the entity. - Type string `xml:"type,attr,omitempty"` // The MIME type of the entity. - ID string `xml:"id,attr,omitempty"` // The entity identifier, expressed in URN format. The value of this attribute uniquely identifies the entity, persists for the life of the entity, and is never reused. - OperationKey string `xml:"operationKey,attr,omitempty"` // Optional unique identifier to support idempotent semantics for create and delete operations. - Name string `xml:"name,attr"` // The name of the entity. - Status string `xml:"status,attr"` // The execution status of the task. One of queued, preRunning, running, success, error, aborted - Operation string `xml:"operation,attr,omitempty"` // A message describing the operation that is tracked by this task. - OperationName string `xml:"operationName,attr,omitempty"` // The short name of the operation that is tracked by this task. - ServiceNamespace string `xml:"serviceNamespace,attr,omitempty"` // Identifier of the service that created the task. It must not start with com.vmware.vcloud and the length must be between 1 and 128 symbols. - StartTime string `xml:"startTime,attr,omitempty"` // The date and time the system started executing the task. May not be present if the task has not been executed yet. - EndTime string `xml:"endTime,attr,omitempty"` // The date and time that processing of the task was completed. May not be present if the task is still being executed. - ExpiryTime string `xml:"expiryTime,attr,omitempty"` // The date and time at which the task resource will be destroyed and no longer available for retrieval. May not be present if the task has not been executed or is still being executed. - CancelRequested bool `xml:"cancelRequested,attr,omitempty"` // Whether user has requested this processing to be canceled. - Link *Link `xml:"Link,omitempty"` // A reference to an entity or operation associated with this object. - Description string `xml:"Description,omitempty"` // Optional description. - Tasks *TasksInProgress `xml:"Tasks,omitempty"` // A list of queued, running, or recently completed tasks associated with this entity. - Owner *Reference `xml:"Owner,omitempty"` // Reference to the owner of the task. This is typically the object that the task is creating or updating. - Error *Error `xml:"Error,omitempty"` // Represents error information from a failed task. - User *Reference `xml:"User,omitempty"` // The user who started the task. - Organization *Reference `xml:"Organization,omitempty"` // The organization to which the User belongs. - Progress int `xml:"Progress,omitempty"` // Read-only indicator of task progress as an approximate percentage between 0 and 100. Not available for all tasks. - Details string `xml:"Details,omitempty"` // Detailed message about the task. Also contained by the Owner entity when task status is preRunning. + HREF string `xml:"href,attr,omitempty" json:"HREF,omitempty"` // The URI of the entity. + Type string `xml:"type,attr,omitempty" json:"type,omitempty"` // The MIME type of the entity. + ID string `xml:"id,attr,omitempty" json:"ID,omitempty"` // The entity identifier, expressed in URN format. The value of this attribute uniquely identifies the entity, persists for the life of the entity, and is never reused. + OperationKey string `xml:"operationKey,attr,omitempty" json:"operationKey,omitempty"` // Optional unique identifier to support idempotent semantics for create and delete operations. + Name string `xml:"name,attr" json:"name,omitempty"` // The name of the entity. + Status string `xml:"status,attr" json:"status,omitempty"` // The execution status of the task. One of queued, preRunning, running, success, error, aborted + Operation string `xml:"operation,attr,omitempty" json:"operation,omitempty"` // A message describing the operation that is tracked by this task. + OperationName string `xml:"operationName,attr,omitempty" json:"operationName,omitempty"` // The short name of the operation that is tracked by this task. + ServiceNamespace string `xml:"serviceNamespace,attr,omitempty" json:"serviceNamespace,omitempty"` // Identifier of the service that created the task. It must not start with com.vmware.vcloud and the length must be between 1 and 128 symbols. + StartTime string `xml:"startTime,attr,omitempty" json:"startTime,omitempty"` // The date and time the system started executing the task. May not be present if the task has not been executed yet. + EndTime string `xml:"endTime,attr,omitempty" json:"endTime,omitempty"` // The date and time that processing of the task was completed. May not be present if the task is still being executed. + ExpiryTime string `xml:"expiryTime,attr,omitempty" json:"expiryTime,omitempty"` // The date and time at which the task resource will be destroyed and no longer available for retrieval. May not be present if the task has not been executed or is still being executed. + CancelRequested bool `xml:"cancelRequested,attr,omitempty" json:"cancelRequested,omitempty"` // Whether user has requested this processing to be canceled. + Link *LinkList `xml:"Link,omitempty" json:"link,omitempty"` // A reference to an entity or operation associated with this object. + Description string `xml:"Description,omitempty" json:"description,omitempty"` // Optional description. + Tasks *TasksInProgress `xml:"Tasks,omitempty" json:"tasks,omitempty"` // A list of queued, running, or recently completed tasks associated with this entity. + Owner *Reference `xml:"Owner,omitempty" json:"owner,omitempty"` // Reference to the owner of the task. This is typically the object that the task is creating or updating. + Error *Error `xml:"Error,omitempty" json:"error,omitempty"` // Represents error information from a failed task. + User *Reference `xml:"User,omitempty" json:"user,omitempty"` // The user who started the task. + Organization *Reference `xml:"Organization,omitempty" json:"organization,omitempty"` // The organization to which the User belongs. + Progress int `xml:"Progress,omitempty" json:"progress,omitempty"` // Read-only indicator of task progress as an approximate percentage between 0 and 100. Not available for all tasks. + Details string `xml:"Details,omitempty" json:"details,omitempty"` // Detailed message about the task. Also contained by the Owner entity when task status is preRunning. // // TODO: add the following fields @@ -723,10 +722,10 @@ type ComputeCapacity struct { // Description: A reference to a resource. Contains an href attribute and optional name and type attributes. // Since: 0.9 type Reference struct { - HREF string `xml:"href,attr,omitempty"` - ID string `xml:"id,attr,omitempty"` - Type string `xml:"type,attr,omitempty"` - Name string `xml:"name,attr,omitempty"` + HREF string `xml:"href,attr,omitempty" json:"href,omitempty"` + ID string `xml:"id,attr,omitempty" json:"id,omitempty"` + Type string `xml:"type,attr,omitempty" json:"type,omitempty"` + Name string `xml:"name,attr,omitempty" json:"name,omitempty"` } // ResourceReference represents a reference to a resource. Contains an href attribute, a resource status attribute, and optional name and type attributes. @@ -767,7 +766,7 @@ type ResourceEntities struct { // Description: Container for references to available organization vDC networks. // Since: 0.9 type AvailableNetworks struct { - Network []*Reference `xml:"Network,omitempty"` + Network []*Reference `xml:"Network,omitempty" json:"network,omitempty"` } // Link extends reference type by adding relation attribute. Defines a hyper-link with a relationship, hyper-link reference, and an optional MIME type. @@ -776,11 +775,11 @@ type AvailableNetworks struct { // Description: Extends reference type by adding relation attribute. Defines a hyper-link with a relationship, hyper-link reference, and an optional MIME type. // Since: 0.9 type Link struct { - HREF string `xml:"href,attr"` - ID string `xml:"id,attr,omitempty"` - Type string `xml:"type,attr,omitempty"` - Name string `xml:"name,attr,omitempty"` - Rel string `xml:"rel,attr"` + HREF string `xml:"href,attr" json:"href,omitempty"` + ID string `xml:"id,attr,omitempty" json:"id,omitempty"` + Type string `xml:"type,attr,omitempty" json:"type,omitempty"` + Name string `xml:"name,attr,omitempty" json:"name,omitempty"` + Rel string `xml:"rel,attr" json:"rel,omitempty"` } // OrgList represents a lists of Organizations @@ -1007,7 +1006,7 @@ type OrgLdapUserAttributes struct { // Description: Represents a list of organization vDCs. // Since: 0.9 type VDCList struct { - Vdcs []*Reference `xml:"Vdc,omitempty"` + Vdcs []*Reference `xml:"Vdc,omitempty" json:"vdcs,omitempty"` } // NetworksListType contains a list of references to Org Networks @@ -1168,11 +1167,11 @@ type Owner struct { // Description: The standard error message type used in the vCloud REST API. // Since: 0.9 type Error struct { - Message string `xml:"message,attr"` - MajorErrorCode int `xml:"majorErrorCode,attr"` - MinorErrorCode string `xml:"minorErrorCode,attr"` - VendorSpecificErrorCode string `xml:"vendorSpecificErrorCode,attr,omitempty"` - StackTrace string `xml:"stackTrace,attr,omitempty"` + Message string `xml:"message,attr" json:"message,omitempty"` + MajorErrorCode int `xml:"majorErrorCode,attr" json:"majorErrorCode,omitempty"` + MinorErrorCode string `xml:"minorErrorCode,attr" json:"minorErrorCode,omitempty"` + VendorSpecificErrorCode string `xml:"vendorSpecificErrorCode,attr,omitempty" json:"vendorSpecificErrorCode,omitempty"` + StackTrace string `xml:"stackTrace,attr,omitempty" json:"stackTrace,omitempty"` } func (err Error) Error() string { @@ -1519,7 +1518,7 @@ type VAppChildren struct { // Since: 0.9 type TasksInProgress struct { // Elements - Task []*Task `xml:"Task"` // A task. + Task []*Task `xml:"Task" json:"task"` // A task. } // VAppTemplateChildren is a container for virtual machines included in this vApp template. @@ -2743,9 +2742,9 @@ type ExternalNetworkReference struct { // Description: Represents the Managed Object Reference (MoRef) and the type of a vSphere object. // Since: 0.9 type VimObjectRef struct { - VimServerRef *Reference `xml:"VimServerRef"` - MoRef string `xml:"MoRef"` - VimObjectType string `xml:"VimObjectType"` + VimServerRef *Reference `xml:"VimServerRef" json:"vimServerRef"` + MoRef string `xml:"MoRef" json:"moRef"` + VimObjectType string `xml:"VimObjectType" json:"vimObjectType"` } // Type: VimObjectRefsType @@ -2754,7 +2753,7 @@ type VimObjectRef struct { // Description: List of VimObjectRef elements. // Since: 0.9 type VimObjectRefs struct { - VimObjectRef []*VimObjectRef `xml:"VimObjectRef"` + VimObjectRef []*VimObjectRef `xml:"VimObjectRef" json:"vimObjectRef"` } // Type: VMWExternalNetworkType @@ -3257,7 +3256,6 @@ type ApiTokenRefresh struct { UpdatedOn string `json:"updated_on,omitempty"` } -/**/ type QueryResultTaskRecordType struct { HREF string `xml:"href,attr,omitempty"` // Contains the URI to the resource. ID string `xml:"id,attr,omitempty"` // The resource identifier, expressed in URN format. The value of this attribute uniquely identifies the resource, persists for the life of the resource, and is never reused. Yes Yes @@ -3280,4 +3278,40 @@ type QueryResultTaskRecordType struct { Metadata *Metadata `xml:"Metadata,omitempty"` } -/**/ +// ProviderVdcCreation contains the data needed to create a provider VDC. +// Note that this is a subset of the full structure of a provider VDC. +type ProviderVdcCreation struct { + Name string `json:"name"` + Description string `json:"description"` + ResourcePoolRefs *VimObjectRefs `json:"resourcePoolRefs"` + HighestSupportedHardwareVersion string `json:"highestSupportedHardwareVersion"` + IsEnabled bool `json:"isEnabled"` + VimServer []*Reference `json:"vimServer"` + StorageProfile []string `json:"storageProfile"` + NsxTManagerReference *Reference `json:"nsxTManagerReference"` + NetworkPool *Reference `json:"networkPool"` + AutoCreateNetworkPool bool `json:"autoCreateNetworkPool"` +} + +// AddResourcePool is used to add one or more resource pools to a provider VDC +type AddResourcePool struct { + VimObjectRef []*VimObjectRef `xml:"AddItem" json:"addItem"` +} + +// DeleteResourcePool is used to remove one or more resource pools from a provider VDC +type DeleteResourcePool struct { + ResourcePoolRefs []*Reference `xml:"DeleteItem" json:"deleteItem"` +} + +// AddStorageProfiles is used to add storage profiles to an existing provider VDC +type AddStorageProfiles struct { + AddStorageProfile []string `json:"addStorageProfile"` +} + +type EnableStorageProfile struct { + Enabled bool `json:"enabled"` +} + +type RemoveStorageProfile struct { + RemoveStorageProfile []*Reference `json:"removeStorageProfile"` +}