Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add tm Org and VDC support #710

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .changes/v3.0.0/710-features.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
* Added `TmOrg` and `types.TmOrg` to structure for OpenAPI management of Organizations with methods
`VCDClient.CreateTmOrg`, `VCDClient.GetAllTmOrgs`, `VCDClient.GetTmOrgByName`,
`VCDClient.GetTmOrgById`, `TmOrg.Update`, `TmOrg.Delete`, `.TmOrg.Disable` [GH-710]
* Added `TmVdc` and `types.TmVdc` to structure for OpenAPI management of Organizations VDCs with
methods `VCDClient.CreateTmVdc`, `VCDClient.GetAllTmVdcs`, `VCDClient.GetTmVdcByName`,
`VCDClient.GetTmVdcById`, `TmVdc.Update`, `TmVdc.Delete`, `.TmVdc.Disable` [GH-710]
* Added types `Region` and `types.Region` for managing regions with methods
`VCDClient.CreateRegion`, `VCDClient.GetAllRegions`, `VCDClient.GetRegionByName`,
`VCDClient.GetRegionById`, `Region.Update`, `Region.Delete` [GH-710]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit hesitant to merge this PR until we can write tests for create/update/delete.

* Added types `Supervisor` and `types.Supervisor` for reading Supervisors
`VCDClient.GetAllSupervisors`, `VCDClient.GetSupervisorById`, `VCDClient.GetSupervisorByName`
[GH-710]
* Added types `SupervisorZone` and `types.SupervisorZone` for reading Supervisors
`VCDClient.GetAllSupervisorZones`, `VCDClient.GetSupervisorZoneById`,
`VCDClient.GetSupervisorZoneByName` [GH-710]
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ testlb:
testnsxv:
cd govcd && go test -tags "nsxv" -timeout $(timeout) -check.vv

testtm:
cd govcd && go test -tags "tm" -timeout 0 -check.vv

# vet runs the Go source code static analysis tool `vet` to find
# any common errors.
vet:
Expand Down
72 changes: 50 additions & 22 deletions govcd/api_vcd_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build api || openapi || functional || catalog || vapp || gateway || network || org || query || extnetwork || task || vm || vdc || system || disk || lb || lbAppRule || lbAppProfile || lbServerPool || lbServiceMonitor || lbVirtualServer || user || search || nsxv || nsxt || auth || affinity || role || alb || certificate || vdcGroup || metadata || providervdc || rde || vsphere || uiPlugin || cse || slz || 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 || cse || slz || tm || ALL

/*
* Copyright 2022 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
Expand Down Expand Up @@ -97,6 +97,7 @@ const (

const (
TestRequiresSysAdminPrivileges = "Test %s requires system administrator privileges"
TestRequiresTm = "Test %s requires TM"
)

type Tenant struct {
Expand Down Expand Up @@ -140,7 +141,12 @@ type TestConfig struct {
HttpTimeout int64 `yaml:"httpTimeout,omitempty"`
}
Tenants []Tenant `yaml:"tenants,omitempty"`
VCD struct {
Tm struct {
Org string `yaml:"org"`
Region string `yaml:"region"`
Vdc string `yaml:"vdc"`
} `yaml:"tm"`
VCD struct {
Org string `yaml:"org"`
Vdc string `yaml:"vdc"`
ProviderVdc struct {
Expand Down Expand Up @@ -648,7 +654,13 @@ func (vcd *TestVCD) SetUpSuite(check *C) {
if err == nil {
versionInfo = fmt.Sprintf("version %s built at %s", version, versionTime)
}
fmt.Printf("Running on VCD %s (%s)\nas user %s@%s (using %s)\n", vcd.config.Provider.Url, versionInfo,
env := "VCD"
isTm := vcd.client.Client.IsTm()
if isTm {
env = "TM"
}

fmt.Printf("Running on %s %s (%s)\nas user %s@%s (using %s)\n", env, vcd.config.Provider.Url, versionInfo,
vcd.config.Provider.User, vcd.config.Provider.SysOrg, authenticationMode)
if !vcd.client.Client.IsSysAdmin {
vcd.skipAdminTests = true
Expand All @@ -661,29 +673,33 @@ func (vcd *TestVCD) SetUpSuite(check *C) {
persistentCleanupIp = vcd.config.Provider.Url
persistentCleanupIp = reHttp.ReplaceAllString(persistentCleanupIp, "")
persistentCleanupIp = reApi.ReplaceAllString(persistentCleanupIp, "")
// set org
vcd.org, err = vcd.client.GetOrgByName(config.VCD.Org)
if err != nil {
fmt.Printf("error retrieving org %s: %s\n", config.VCD.Org, err)
os.Exit(1)
}
// set vdc
vcd.vdc, err = vcd.org.GetVDCByName(config.VCD.Vdc, false)
if err != nil || vcd.vdc == nil {
panic(err)
}

// configure NSX-T VDC for convenience if it is specified in configuration
if config.VCD.Nsxt.Vdc != "" {
vcd.nsxtVdc, err = vcd.org.GetVDCByName(config.VCD.Nsxt.Vdc, false)
if !isTm {
// set org
vcd.org, err = vcd.client.GetOrgByName(config.VCD.Org)
if err != nil {
panic(fmt.Errorf("error geting NSX-T VDC '%s': %s", config.VCD.Nsxt.Vdc, err))
fmt.Printf("error retrieving org %s: %s\n", config.VCD.Org, err)
os.Exit(1)
}
// set vdc
vcd.vdc, err = vcd.org.GetVDCByName(config.VCD.Vdc, false)
if err != nil || vcd.vdc == nil {
panic(err)
}

// configure NSX-T VDC for convenience if it is specified in configuration
if config.VCD.Nsxt.Vdc != "" {
vcd.nsxtVdc, err = vcd.org.GetVDCByName(config.VCD.Nsxt.Vdc, false)
if err != nil {
panic(fmt.Errorf("error geting NSX-T VDC '%s': %s", config.VCD.Nsxt.Vdc, err))
}
}
}

// If neither the vApp or VM tags are set, we also skip the
// creation of the default vApp
if !isTagSet("vapp") && !isTagSet("vm") {
// vApp creation is skipped for one out of two reasons:
// * neither the vApp or VM tags are set
// * env is TM
if (!isTagSet("vapp") && !isTagSet("vm")) || isTm {
// vcd.skipVappTests = true
skipVappCreation = true
}
Expand Down Expand Up @@ -1810,7 +1826,7 @@ func (vcd *TestVCD) TestClient_getloginurl(check *C) {
check.Fatalf("err: %s", err)
}

if client.sessionHREF.Path != "/cloudapi/1.0.0/sessions" {
if !strings.HasSuffix(client.sessionHREF.Path, "/cloudapi/1.0.0/sessions") {
check.Fatalf("Getting LoginUrl failed, url: %s", client.sessionHREF.Path)
}
}
Expand Down Expand Up @@ -2063,6 +2079,18 @@ func skipNoNsxtAlbConfiguration(vcd *TestVCD, check *C) {
}
}

func skipNonTm(vcd *TestVCD, check *C) {
if !vcd.client.Client.IsTm() {
check.Skip(fmt.Sprintf(TestRequiresTm, check.TestName()))
}
}

func sysadminOnly(vcd *TestVCD, check *C) {
if vcd.skipAdminTests {
check.Skip(fmt.Sprintf(TestRequiresSysAdminPrivileges, check.TestName()))
}
}

// skipOpenApiEndpointTest is a helper to skip tests for particular unsupported OpenAPI endpoints
func skipOpenApiEndpointTest(vcd *TestVCD, check *C, endpoint string) {
minimumRequiredApiVersion := endpointMinApiVersions[endpoint]
Expand Down
4 changes: 4 additions & 0 deletions govcd/api_vcd_versions.go
Original file line number Diff line number Diff line change
Expand Up @@ -371,3 +371,7 @@ func (client *Client) VersionEqualOrGreater(compareTo string, howManyDigits int)

return fullVersion.Version.GreaterThanOrEqual(compareToVersion), nil
}

func (client *Client) IsTm() bool {
return client.APIVCDMaxVersionIs(">= 40") // TODO - make it more precise
}
2 changes: 1 addition & 1 deletion govcd/common_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build api || auth || functional || catalog || vapp || gateway || network || org || query || extnetwork || task || vm || vdc || system || disk || lb || lbAppRule || lbAppProfile || lbServerPool || lbServiceMonitor || lbVirtualServer || user || role || nsxv || nsxt || openapi || affinity || search || alb || certificate || vdcGroup || metadata || providervdc || rde || uiPlugin || vsphere || cse || slz || 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 || cse || slz || tm || ALL

/*
* Copyright 2021 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
Expand Down
9 changes: 9 additions & 0 deletions govcd/openapi_endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,12 @@ var endpointMinApiVersions = map[string]string{

// NSX-T Tier 0 router interfaces that can be used for IP Space uplink assignment
types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointNsxtTier0RouterInterfaces: "38.0",

// VCF
types.OpenApiPathVcf + types.OpenApiEndpointRegions: "40.0",
types.OpenApiPathVcf + types.OpenApiEndpointSupervisors: "40.0",
types.OpenApiPathVcf + types.OpenApiEndpointSupervisorZones: "40.0",
types.OpenApiPathVcf + types.OpenApiEndpointTmVdcs: "40.0",
}

// endpointElevatedApiVersions endpoint elevated API versions
Expand Down Expand Up @@ -240,6 +246,9 @@ var endpointElevatedApiVersions = map[string][]string{
//"37.1", // Introduced support
"38.0", // Adds 'Interfaces' structure for associating particular Tier-0 router interfaces
},
types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointOrgs: {
"40.0", // TM Orgs
},
}

// checkOpenApiEndpointCompatibility checks if VCD version (to which the client is connected) is sufficient to work with
Expand Down
107 changes: 107 additions & 0 deletions govcd/tm_org.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package govcd

/*
* Copyright 2024 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
*/

import (
"fmt"
"net/url"

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

const labelOrganization = "Organization"

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

// wrap is a hidden helper that facilitates the usage of a generic CRUD function
//
//lint:ignore U1000 this method is used in generic functions, but annoys staticcheck
func (g TmOrg) wrap(inner *types.TmOrg) *TmOrg {
g.TmOrg = inner
return &g
}

func (vcdClient *VCDClient) CreateTmOrg(config *types.TmOrg) (*TmOrg, error) {
if !vcdClient.Client.IsTm() {
return nil, fmt.Errorf("err")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noticed this error message, looks incomplete?

}
c := crudConfig{
entityLabel: labelOrganization,
endpoint: types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointOrgs,
}
outerType := TmOrg{vcdClient: vcdClient}
return createOuterEntity(&vcdClient.Client, outerType, c, config)
}

func (vcdClient *VCDClient) GetAllTmOrgs(queryParameters url.Values) ([]*TmOrg, error) {
c := crudConfig{
entityLabel: labelOrganization,
endpoint: types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointOrgs,
queryParameters: queryParameters,
}

outerType := TmOrg{vcdClient: vcdClient}
return getAllOuterEntities(&vcdClient.Client, outerType, c)
}

func (vcdClient *VCDClient) GetTmOrgByName(name string) (*TmOrg, error) {
if name == "" {
return nil, fmt.Errorf("%s lookup requires name", labelOrganization)
}

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

filteredEntities, err := vcdClient.GetAllTmOrgs(queryParams)
if err != nil {
return nil, err
}

singleEntity, err := oneOrError("name", name, filteredEntities)
if err != nil {
return nil, err
}

return vcdClient.GetTmOrgById(singleEntity.TmOrg.ID)
}

func (vcdClient *VCDClient) GetTmOrgById(id string) (*TmOrg, error) {
c := crudConfig{
entityLabel: labelOrganization,
endpoint: types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointOrgs,
endpointParams: []string{id},
}

outerType := TmOrg{vcdClient: vcdClient}
return getOuterEntity(&vcdClient.Client, outerType, c)
}

func (o *TmOrg) Update(TmOrgConfig *types.TmOrg) (*TmOrg, error) {
c := crudConfig{
entityLabel: labelOrganization,
endpoint: types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointOrgs,
endpointParams: []string{o.TmOrg.ID},
}
outerType := TmOrg{vcdClient: o.vcdClient}
return updateOuterEntity(&o.vcdClient.Client, outerType, c, TmOrgConfig)
}

func (o *TmOrg) Delete() error {
c := crudConfig{
entityLabel: labelOrganization,
endpoint: types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointOrgs,
endpointParams: []string{o.TmOrg.ID},
}
return deleteEntityById(&o.vcdClient.Client, c)
}

func (o *TmOrg) Disable() error {
o.TmOrg.IsEnabled = false
_, err := o.Update(o.TmOrg)
return err
}
61 changes: 61 additions & 0 deletions govcd/tm_org_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//go:build tm || functional || ALL

/*
* Copyright 2024 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
*/

package govcd

import (
. "gopkg.in/check.v1"

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

func (vcd *TestVCD) Test_TmOrg(check *C) {
skipNonTm(vcd, check)
sysadminOnly(vcd, check)

cfg := &types.TmOrg{
Name: check.TestName(),
DisplayName: check.TestName(),
CanManageOrgs: true,
}

tmOrg, err := vcd.client.CreateTmOrg(cfg)
check.Assert(err, IsNil)
check.Assert(tmOrg, NotNil)

// Add to cleanup list
PrependToCleanupListOpenApi(tmOrg.TmOrg.ID, check.TestName(), types.OpenApiPathVersion1_0_0+types.OpenApiEndpointOrgs+tmOrg.TmOrg.ID)

// Get By Name
byName, err := vcd.client.GetTmOrgByName(cfg.Name)
check.Assert(err, IsNil)
check.Assert(byName, NotNil)

// Get By ID
byId, err := vcd.client.GetTmOrgById(tmOrg.TmOrg.ID)
check.Assert(err, IsNil)
check.Assert(byId, NotNil)

// Get All
allTmOrgs, err := vcd.client.GetAllTmOrgs(nil)
check.Assert(err, IsNil)
check.Assert(allTmOrgs, NotNil)
check.Assert(len(allTmOrgs) > 0, Equals, true)

// Update
tmOrg.TmOrg.IsEnabled = false
updated, err := tmOrg.Update(tmOrg.TmOrg)
check.Assert(err, IsNil)
check.Assert(updated, NotNil)

// Delete
err = tmOrg.Delete()
check.Assert(err, IsNil)

notFoundByName, err := vcd.client.GetTmOrgByName(cfg.Name)
check.Assert(ContainsNotFound(err), Equals, true)
check.Assert(notFoundByName, IsNil)
}
Loading
Loading