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

New functions for getting and updating Org vDC #206

Merged
merged 12 commits into from
Jul 1, 2019
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Added edge gateway create/delete functions [#130](https://github.com/vmware/go-vcloud-director/issues/130).
* Added load balancer service monitor [#196](https://github.com/vmware/go-vcloud-director/pull/196)
* Added load balancer server pool [#205](https://github.com/vmware/go-vcloud-director/pull/205)
* Added functions for refreshing, getting and update Org VDC [#206](https://github.com/vmware/go-vcloud-director/pull/206)

## 2.2.0 (May 15, 2019)

Expand Down
1 change: 1 addition & 0 deletions govcd/api_vcd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const (
TestUploadOvf = "TestUploadOvf"
TestDeleteCatalogItem = "TestDeleteCatalogItem"
TestCreateOrgVdc = "TestCreateOrgVdc"
TestRefreshOrgVdc = "TestRefreshOrgVdc"
TestCreateOrgVdcNetworkEGW = "TestCreateOrgVdcNetworkEGW"
TestCreateOrgVdcNetworkIso = "TestCreateOrgVdcNetworkIso"
TestCreateOrgVdcNetworkDirect = "TestCreateOrgVdcNetworkDirect"
Expand Down
78 changes: 78 additions & 0 deletions govcd/org.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,84 @@ func (org *Org) GetVdcByName(vdcname string) (Vdc, error) {
return Vdc{}, nil
}

// Given an adminVdc with a valid HREF, the function refresh the adminVdc
// and updates the adminVdc data. Returns an error on failure
// Users should use refresh whenever they suspect
// a stale VDC due to the creation/update/deletion of a resource
// within the the VDC itself.
func (adminVdc *AdminVdc) Refresh() error {
dataclouder marked this conversation as resolved.
Show resolved Hide resolved
if *adminVdc == (AdminVdc{}) || adminVdc.AdminVdc.HREF == "" {
return fmt.Errorf("cannot refresh, Object is empty or HREF is empty")
}

// Empty struct before a new unmarshal, otherwise we end up with duplicate
// elements in slices.
unmarshalledAdminVdc := &types.AdminVdc{}

_, err := adminVdc.client.ExecuteRequest(adminVdc.AdminVdc.HREF, http.MethodGet,
"", "error refreshing VDC: %s", nil, unmarshalledAdminVdc)
if err != nil {
return err
}
adminVdc.AdminVdc = unmarshalledAdminVdc

return nil
}

// GetAdminVdcByName function uses a valid VDC name and returns a admin VDC object.
// If no VDC is found, then it returns an empty VDC and no error.
// Otherwise it returns an empty VDC and an error.
func (adminOrg *AdminOrg) GetAdminVdcByName(vdcname string) (AdminVdc, error) {
for _, vdcs := range adminOrg.AdminOrg.Vdcs.Vdcs {
if vdcs.Name == vdcname {

adminVdc := NewAdminVdc(adminOrg.client)

_, err := adminOrg.client.ExecuteRequest(vdcs.HREF, http.MethodGet,
"", "error getting vdc: %s", nil, adminVdc.AdminVdc)

return *adminVdc, err
}
}
return AdminVdc{}, nil
}

// UpdateAsync updates VDC from current VDC struct contents.
// Any differences that may be legally applied will be updated.
// Returns an error if the call to vCD fails.
// API Documentation: https://vdc-repo.vmware.com/vmwb-repository/dcr-public/7a028e78-bd37-4a6a-8298-9c26c7eeb9aa/09142237-dd46-4dee-8326-e07212fb63a8/doc/doc/operations/PUT-Vdc.html
func (adminVdc *AdminVdc) UpdateAsync() (Task, error) {

adminVdc.AdminVdc.Xmlns = types.XMLNamespaceVCloud

// Return the task
return adminVdc.client.ExecuteTaskRequest(adminVdc.AdminVdc.HREF, http.MethodPut,
types.MimeAdminVDC, "error updating VDC: %s", adminVdc.AdminVdc)
}

// Update function updates an Admin VDC from current VDC struct contents.
// Any differences that may be legally applied will be updated.
// Returns an empty AdminVdc struct and error if the call to vCD fails.
// API Documentation: https://vdc-repo.vmware.com/vmwb-repository/dcr-public/7a028e78-bd37-4a6a-8298-9c26c7eeb9aa/09142237-dd46-4dee-8326-e07212fb63a8/doc/doc/operations/PUT-Vdc.html
func (adminVdc *AdminVdc) Update() (AdminVdc, error) {
task, err := adminVdc.UpdateAsync()
if err != nil {
return AdminVdc{}, err
}

err = task.WaitTaskCompletion()
if err != nil {
return AdminVdc{}, err
}

err = adminVdc.Refresh()
if err != nil {
return AdminVdc{}, err
}

return *adminVdc, nil
}

// AdminOrg gives an admin representation of an org.
// Administrators can delete and update orgs with an admin org object.
// AdminOrg includes all members of the Org element, and adds several
Expand Down
211 changes: 211 additions & 0 deletions govcd/org_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package govcd

import (
"fmt"
"math"
"time"

"github.com/vmware/go-vcloud-director/v2/types/v56"
Expand Down Expand Up @@ -420,3 +421,213 @@ func (vcd *TestVCD) Test_GetAdminCatalog(check *C) {
check.Assert(cat.AdminCatalog.Description, Equals, vcd.config.VCD.Catalog.Description)
}
}

// Tests Refresh for VDC by updating it and then asserting if the
// variable is updated.
func (vcd *TestVCD) Test_RefreshVdc(check *C) {

adminOrg, err, vdcConfiguration := setupVDc(vcd, check)

// Refresh so the new VDC shows up in the org's list
err = adminOrg.Refresh()
check.Assert(err, IsNil)

adminVdc, err := adminOrg.GetAdminVdcByName(vdcConfiguration.Name)

check.Assert(err, IsNil)
check.Assert(adminVdc, Not(Equals), Vdc{})
check.Assert(adminVdc.AdminVdc.Name, Equals, vdcConfiguration.Name)
check.Assert(adminVdc.AdminVdc.IsEnabled, Equals, vdcConfiguration.IsEnabled)
check.Assert(adminVdc.AdminVdc.AllocationModel, Equals, vdcConfiguration.AllocationModel)

adminVdc.AdminVdc.Name = TestRefreshOrgVdc
_, err = adminVdc.Update()
check.Assert(err, IsNil)
AddToCleanupList(TestRefreshOrgVdc, "vdc", vcd.org.Org.Name, check.TestName())

// Test Refresh on vdc
err = adminVdc.Refresh()
check.Assert(err, IsNil)
check.Assert(adminVdc.AdminVdc.Name, Equals, TestRefreshOrgVdc)
}

func setupVDc(vcd *TestVCD, check *C) (AdminOrg, error, *types.VdcConfiguration) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
func setupVDc(vcd *TestVCD, check *C) (AdminOrg, error, *types.VdcConfiguration) {
func setupVDc(vcd *TestVCD, check *C) (AdminOrg, *types.VdcConfiguration, error) {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

if vcd.skipAdminTests {
check.Skip(fmt.Sprintf(TestRequiresSysAdminPrivileges, check.TestName()))
}
if vcd.config.VCD.ProviderVdc.Name == "" {
check.Skip("No Provider VDC name given for VDC tests")
}
if vcd.config.VCD.ProviderVdc.StorageProfile == "" {
check.Skip("No Storage Profile given for VDC tests")
}
if vcd.config.VCD.ProviderVdc.NetworkPool == "" {
check.Skip("No Network Pool given for VDC tests")
}
adminOrg, err := GetAdminOrgByName(vcd.client, vcd.org.Org.Name)
check.Assert(err, IsNil)
check.Assert(adminOrg, Not(Equals), AdminOrg{})
results, err := vcd.client.QueryWithNotEncodedParams(nil, map[string]string{
"type": "providerVdc",
"filter": fmt.Sprintf("(name==%s)", vcd.config.VCD.ProviderVdc.Name),
})
check.Assert(err, IsNil)
if len(results.Results.VMWProviderVdcRecord) == 0 {
check.Skip(fmt.Sprintf("No Provider VDC found with name '%s'", vcd.config.VCD.ProviderVdc.Name))
}
providerVdcHref := results.Results.VMWProviderVdcRecord[0].HREF
results, err = vcd.client.QueryWithNotEncodedParams(nil, map[string]string{
"type": "providerVdcStorageProfile",
"filter": fmt.Sprintf("(name==%s)", vcd.config.VCD.ProviderVdc.StorageProfile),
})
check.Assert(err, IsNil)
if len(results.Results.ProviderVdcStorageProfileRecord) == 0 {
check.Skip(fmt.Sprintf("No storage profile found with name '%s'", vcd.config.VCD.ProviderVdc.StorageProfile))
}
providerVdcStorageProfileHref := results.Results.ProviderVdcStorageProfileRecord[0].HREF
results, err = vcd.client.QueryWithNotEncodedParams(nil, map[string]string{
"type": "networkPool",
"filter": fmt.Sprintf("(name==%s)", vcd.config.VCD.ProviderVdc.NetworkPool),
})
check.Assert(err, IsNil)
if len(results.Results.NetworkPoolRecord) == 0 {
check.Skip(fmt.Sprintf("No network pool found with name '%s'", vcd.config.VCD.ProviderVdc.NetworkPool))
}
networkPoolHref := results.Results.NetworkPoolRecord[0].HREF
vdcConfiguration := &types.VdcConfiguration{
Name: TestCreateOrgVdc + "ForRefresh",
Xmlns: types.XMLNamespaceVCloud,
AllocationModel: "AllocationPool",
ComputeCapacity: []*types.ComputeCapacity{
&types.ComputeCapacity{
CPU: &types.CapacityWithUsage{
Units: "MHz",
Allocated: 1024,
Limit: 1024,
},
Memory: &types.CapacityWithUsage{
Allocated: 1024,
Limit: 1024,
Units: "MB",
},
},
},
VdcStorageProfile: []*types.VdcStorageProfile{&types.VdcStorageProfile{
Enabled: true,
Units: "MB",
Limit: 1024,
Default: true,
ProviderVdcStorageProfile: &types.Reference{
HREF: providerVdcStorageProfileHref,
},
},
},
NetworkPoolReference: &types.Reference{
HREF: networkPoolHref,
},
ProviderVdcReference: &types.Reference{
HREF: providerVdcHref,
},
IsEnabled: true,
IsThinProvision: true,
UsesFastProvisioning: true,
}
vdc, err := adminOrg.GetVdcByName(vdcConfiguration.Name)
check.Assert(err, IsNil)
if vdc != (Vdc{}) {
err = vdc.DeleteWait(true, true)
check.Assert(err, IsNil)
}
err = adminOrg.CreateVdcWait(vdcConfiguration)
check.Assert(err, IsNil)
AddToCleanupList(vdcConfiguration.Name, "vdc", vcd.org.Org.Name, check.TestName())
return adminOrg, err, vdcConfiguration
}

// Tests VDC by updating it and then asserting if the
// variable is updated.
func (vcd *TestVCD) Test_UpdateVdc(check *C) {
adminOrg, err, vdcConfiguration := setupVDc(vcd, check)

// Refresh so the new VDC shows up in the org's list
err = adminOrg.Refresh()
check.Assert(err, IsNil)

adminVdc, err := adminOrg.GetAdminVdcByName(vdcConfiguration.Name)

check.Assert(err, IsNil)
check.Assert(adminVdc, Not(Equals), Vdc{})
check.Assert(adminVdc.AdminVdc.Name, Equals, vdcConfiguration.Name)
check.Assert(adminVdc.AdminVdc.IsEnabled, Equals, vdcConfiguration.IsEnabled)
check.Assert(adminVdc.AdminVdc.AllocationModel, Equals, vdcConfiguration.AllocationModel)

updateDescription := "updateDescription"
computeCapacity := []*types.ComputeCapacity{
&types.ComputeCapacity{
CPU: &types.CapacityWithUsage{
Units: "MHz",
Allocated: 2024,
Limit: 2024,
},
Memory: &types.CapacityWithUsage{
Allocated: 2024,
Limit: 2024,
Units: "MB",
},
},
}
quota := 111
vCpu := int64(1000)
guaranteed := float64(0.6)
adminVdc.AdminVdc.Description = updateDescription
adminVdc.AdminVdc.ComputeCapacity = computeCapacity
adminVdc.AdminVdc.IsEnabled = false
adminVdc.AdminVdc.IsThinProvision = false
adminVdc.AdminVdc.NetworkQuota = quota
adminVdc.AdminVdc.VMQuota = quota
adminVdc.AdminVdc.OverCommitAllowed = false
adminVdc.AdminVdc.VCpuInMhz = vCpu
adminVdc.AdminVdc.UsesFastProvisioning = false
adminVdc.AdminVdc.ResourceGuaranteedCpu = &guaranteed
adminVdc.AdminVdc.ResourceGuaranteedMemory = &guaranteed

updatedVdc, err := adminVdc.Update()
check.Assert(err, IsNil)
check.Assert(updatedVdc, Not(IsNil))
check.Assert(updatedVdc.AdminVdc.Description, Equals, updateDescription)
check.Assert(updatedVdc.AdminVdc.ComputeCapacity[0].CPU.Allocated, Equals, computeCapacity[0].CPU.Allocated)
check.Assert(updatedVdc.AdminVdc.IsEnabled, Equals, false)
check.Assert(updatedVdc.AdminVdc.IsThinProvision, Equals, false)
check.Assert(updatedVdc.AdminVdc.NetworkQuota, Equals, quota)
check.Assert(updatedVdc.AdminVdc.VMQuota, Equals, quota)
check.Assert(updatedVdc.AdminVdc.OverCommitAllowed, Equals, false)
check.Assert(updatedVdc.AdminVdc.VCpuInMhz, Equals, vCpu)
check.Assert(updatedVdc.AdminVdc.UsesFastProvisioning, Equals, false)
check.Assert(math.Abs(*updatedVdc.AdminVdc.ResourceGuaranteedCpu-guaranteed) < 0.001, Equals, true)
check.Assert(math.Abs(*updatedVdc.AdminVdc.ResourceGuaranteedMemory-guaranteed) < 0.001, Equals, true)
}

// Tests org function GetAdminVdcByName with the vdc specified
// in the config file. Then tests with a vdc that doesn't exist.
// Fails if the config file name doesn't match with the found VDC, or
// if the invalid VDC is found by the function. Also tests an VDC
// that doesn't exist. Asserts an error if the function finds it or
// if the error is not nil.
func (vcd *TestVCD) Test_GetAdminVdcByName(check *C) {
if vcd.skipAdminTests {
check.Skip(fmt.Sprintf(TestRequiresSysAdminPrivileges, check.TestName()))
}

adminOrg, err := GetAdminOrgByName(vcd.client, vcd.org.Org.Name)
check.Assert(err, IsNil)
check.Assert(adminOrg, Not(Equals), AdminOrg{})

adminVdc, err := adminOrg.GetAdminVdcByName(vcd.config.VCD.Vdc)
check.Assert(adminVdc, Not(Equals), AdminVdc{})
check.Assert(err, IsNil)
check.Assert(adminVdc.AdminVdc.Name, Equals, vcd.config.VCD.Vdc)
// Try a vdc that doesn't exist
adminVdc, err = adminOrg.GetAdminVdcByName(INVALID_NAME)
check.Assert(adminVdc, Equals, AdminVdc{})
check.Assert(err, IsNil)
}
15 changes: 15 additions & 0 deletions govcd/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"strings"

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

// Simple structure to pass Edge Gateway creation parameters.
Expand Down Expand Up @@ -500,3 +501,17 @@ func QueryProviderVdcByName(vcdCli *VCDClient, name string) ([]*types.QueryResul

return results.Results.VMWProviderVdcRecord, nil
}

// GetNetworkPoolByHREF functions fetches an network pool using VDC client and network pool href
func GetNetworkPoolByHREF(client *VCDClient, href string) (*types.VMWNetworkPool, error) {
util.Logger.Printf("[TRACE] Get network pool by HREF: %s\n", href)

networkPool := &types.VMWNetworkPool{}

_, err := client.Client.ExecuteRequest(href, http.MethodGet,
"", "error fetching network ppol: %s", nil, networkPool)

// Return the disk
return networkPool, err

}
22 changes: 22 additions & 0 deletions govcd/system_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,28 @@ func (vcd *TestVCD) Test_FindBadlyNamedStorageProfile(check *C) {
check.Assert(err.Error(), Matches, reNotFound)
}

// Test getting network pool by href and vdc client
func (vcd *TestVCD) Test_GetNetworkPoolByHREF(check *C) {
if vcd.config.VCD.ProviderVdc.NetworkPool == "" {
check.Skip("Skipping test because network pool is not configured")
}

fmt.Printf("Running: %s\n", check.TestName())

adminOrg, err := GetAdminOrgByName(vcd.client, vcd.config.VCD.Org)
check.Assert(adminOrg, Not(Equals), AdminOrg{})
check.Assert(err, IsNil)

adminVdc, err := adminOrg.GetAdminVdcByName(vcd.config.VCD.Vdc)
check.Assert(adminVdc, Not(Equals), AdminVdc{})
check.Assert(err, IsNil)

// Get network pool by href
foundNetworkPool, err := GetNetworkPoolByHREF(vcd.client, adminVdc.AdminVdc.NetworkPoolReference.HREF)
check.Assert(err, IsNil)
check.Assert(foundNetworkPool, Not(Equals), types.VMWNetworkPool{})
}

// longer than the 128 characters so nothing can be named this
var INVALID_NAME = `*******************************************INVALID
****************************************************
Expand Down
2 changes: 2 additions & 0 deletions types/v56/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ const (
MimeCatalogItem = "application/vnd.vmware.vcloud.catalogItem+xml"
// MimeVDC mime for a VDC
MimeVDC = "application/vnd.vmware.vcloud.vdc+xml"
// MimeVDC mime for a admin VDC
MimeAdminVDC = "application/vnd.vmware.admin.vdc+xml"
// MimeVAppTemplate mime for a vapp template
MimeVAppTemplate = "application/vnd.vmware.vcloud.vAppTemplate+xml"
// MimeVApp mime for a vApp
Expand Down
Loading