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

Fix vapp description and add vapp.Rename #372

Merged
merged 8 commits into from
Apr 30, 2021
Merged
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

* Added method `vdc.QueryEdgeGateway` [#364](https://github.com/vmware/go-vcloud-director/pull/364)
* Deprecated `vdc.GetEdgeGatewayRecordsType` [#364](https://github.com/vmware/go-vcloud-director/pull/364)
* Added parameter `description` to method `vdc.ComposeRawVapp` [#372](https://github.com/vmware/go-vcloud-director/pull/372)
* Added methods `vapp.Rename`, `vapp.UpdateDescription`, `vapp.UpdateNameDescription` [#372](https://github.com/vmware/go-vcloud-director/pull/372)

## 2.11.0 (March 10, 2021)

Expand Down
2 changes: 1 addition & 1 deletion govcd/access_control_vapp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func (vcd *TestVCD) Test_VappAccessControl(check *C) {
}

// Create a new vApp
vapp, err := makeEmptyVapp(vdc, vappName)
vapp, err := makeEmptyVapp(vdc, vappName, "")
check.Assert(err, IsNil)
check.Assert(vapp, NotNil)
AddToCleanupList(vappName, "vapp", vcd.config.VCD.Org+"|"+vcd.config.VCD.Vdc, "Test_VappAccessControl")
Expand Down
2 changes: 1 addition & 1 deletion govcd/adminorg_ldap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ func createLdapServer(vcd *TestVCD, check *C, directNetworkName string) (string,
vappTemplate, err := catalogItem.GetVAppTemplate()
check.Assert(err, IsNil)
// Compose Raw vApp
err = vdc.ComposeRawVApp(vAppName)
err = vdc.ComposeRawVApp(vAppName, "")
check.Assert(err, IsNil)
vapp, err := vdc.GetVAppByName(vAppName, true)
check.Assert(err, IsNil)
Expand Down
8 changes: 4 additions & 4 deletions govcd/common_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// +build api functional catalog vapp gateway network org query extnetwork task vm vdc system disk lb lbAppRule lbAppProfile lbServerPool lbServiceMonitor lbVirtualServer user nsxv affinity ALL

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

package govcd
Expand Down Expand Up @@ -55,7 +55,7 @@ func (vcd *TestVCD) createAndGetResourcesForVmCreation(check *C, vmName string)
vappTemplate, err := catalogItem.GetVAppTemplate()
check.Assert(err, IsNil)
// Compose Raw vApp
err = vdc.ComposeRawVApp(vmName)
err = vdc.ComposeRawVApp(vmName, "")
check.Assert(err, IsNil)
vapp, err := vdc.GetVAppByName(vmName, true)
check.Assert(err, IsNil)
Expand Down Expand Up @@ -670,9 +670,9 @@ func deleteVapp(vcd *TestVCD, name string) error {
}

// makeEmptyVapp creates a given vApp without any VM
func makeEmptyVapp(vdc *Vdc, name string) (*VApp, error) {
func makeEmptyVapp(vdc *Vdc, name string, description string) (*VApp, error) {

err := vdc.ComposeRawVApp(name)
err := vdc.ComposeRawVApp(name, description)
if err != nil {
return nil, err
}
Expand Down
67 changes: 66 additions & 1 deletion govcd/vapp.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
/*
* Copyright 2019 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
* Copyright 2021 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
*/

package govcd

import (
"encoding/xml"
"errors"
"fmt"
"net/http"
Expand Down Expand Up @@ -1375,3 +1376,67 @@ func (vapp *VApp) getOrgInfo() (orgInfoType, error) {
}
return getOrgInfo(vapp.client, vdc.Vdc.Link, vapp.VApp.ID, vapp.VApp.Name, "vApp")
}

// UpdateNameDescription can change the name and the description of a vApp
// If name is empty, it is left unchanged.
func (vapp *VApp) UpdateNameDescription(newName, newDescription string) error {
if vapp == nil || vapp.VApp.HREF == "" {
return fmt.Errorf("vApp or href cannot be empty")
}

// Skip update if we are using the original values
if (newName == vapp.VApp.Name || newName == "") && (newDescription == vapp.VApp.Description) {
return nil
}

opType := types.MimeRecomposeVappParams

href := ""
for _, link := range vapp.VApp.Link {
if link.Type == opType && link.Rel == "recompose" {
href = link.HREF
break
}
}

if href == "" {
return fmt.Errorf("no appropriate link for update found for vApp %s", vapp.VApp.Name)
}

if newName == "" {
newName = vapp.VApp.Name
}

recomposeParams := &types.SmallRecomposeVappParams{
XMLName: xml.Name{},
Ovf: types.XMLNamespaceOVF,
Xsi: types.XMLNamespaceXSI,
Xmlns: types.XMLNamespaceVCloud,
Name: newName,
Description: newDescription,
Deploy: vapp.VApp.Deployed,
}

task, err := vapp.client.ExecuteTaskRequest(href, http.MethodPost,
opType, "error updating vapp: %s", recomposeParams)

if err != nil {
return fmt.Errorf("unable to update vApp: %s", err)
}

err = task.WaitTaskCompletion()
if err != nil {
return fmt.Errorf("task for updating vApp failed: %s", err)
}
return vapp.Refresh()
}

// UpdateDescription changes the description of a vApp
func (vapp *VApp) UpdateDescription(newDescription string) error {
return vapp.UpdateNameDescription("", newDescription)
}

// Rename changes the name of a vApp
func (vapp *VApp) Rename(newName string) error {
return vapp.UpdateNameDescription(newName, vapp.VApp.Description)
}
99 changes: 98 additions & 1 deletion govcd/vapp_test.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
// +build vapp functional ALL

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

package govcd

import (
"fmt"
"regexp"
"time"

. "gopkg.in/check.v1"

Expand Down Expand Up @@ -1557,3 +1558,99 @@ func (vcd *TestVCD) Test_AddNewVMWithComputeCapacity(check *C) {
_, err = adminVdc.SetAssignedComputePolicies(types.VdcComputePolicyReferences{VdcComputePolicyReference: beforeTestPolicyReferences})
check.Assert(err, IsNil)
}

func (vcd *TestVCD) testUpdateVapp(op string, check *C, vapp *VApp, name, description string, vms []string) {

var err error
switch op {
case "update_desc", "remove_desc":
printVerbose("[%s] testing vapp.UpdateDescription(\"%s\")\n", op, description)
err = vapp.UpdateDescription(description)
check.Assert(err, IsNil)
case "update_both":
printVerbose("[%s] testing vapp.UpdateNameDescription(\"%s\", \"%s\")\n", op, name, description)
err = vapp.UpdateNameDescription(name, description)
check.Assert(err, IsNil)
case "rename":
printVerbose("[%s] testing vapp.Rename(\"%s\")\n", op, name)
err = vapp.Rename(name)
check.Assert(err, IsNil)
default:
check.Assert("unhandled operation", Equals, "true")
}

if name == "" {
name = vapp.VApp.Name
}

// Get a fresh copy of the vApp
vapp, err = vcd.vdc.GetVAppByName(name, true)
check.Assert(err, IsNil)

check.Assert(vapp.VApp.Name, Equals, name)
check.Assert(vapp.VApp.Description, Equals, description)
// check that the VMs still exist after vApp update
for _, vm := range vms {
printVerbose("checking VM %s\n", vm)
_, err = vapp.GetVMByName(vm, true)
check.Assert(err, IsNil)
}
}

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

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

vappName := check.TestName()
vappDescription := vappName + " description"
newVappName := vappName + "_new"

newVappDescription := vappName + " desc"
// Compose VApp
vapp, err := makeEmptyVapp(vcd.vdc, vappName, vappDescription)
check.Assert(err, IsNil)
AddToCleanupList(vappName, "vapp", "", "Test_RenameVapp")

check.Assert(vapp.VApp.Name, Equals, vappName)
check.Assert(vapp.VApp.Description, Equals, vappDescription)

// Need a slight delay for the vApp to get the links that are needed for renaming
time.Sleep(time.Second)

// change description
vcd.testUpdateVapp("update_desc", check, vapp, "", newVappDescription, nil)

// remove description
vcd.testUpdateVapp("remove_desc", check, vapp, vappName, "", nil)

// restore original
vcd.testUpdateVapp("update_both", check, vapp, vappName, vappDescription, nil)

// change name
vcd.testUpdateVapp("rename", check, vapp, newVappName, vappDescription, nil)
AddToCleanupList(newVappName, "vapp", "", "Test_RenameVapp")
// restore original
vcd.testUpdateVapp("update_both", check, vapp, vappName, vappDescription, nil)

// Add two VMs
_, err = makeEmptyVm(vapp, "vm1")
check.Assert(err, IsNil)
_, err = makeEmptyVm(vapp, "vm2")
check.Assert(err, IsNil)

vms := []string{"vm1", "vm2"}
// change description after adding VMs
vcd.testUpdateVapp("update_desc", check, vapp, "", newVappDescription, vms)
vcd.testUpdateVapp("remove_desc", check, vapp, vappName, "", nil)
// restore original
vcd.testUpdateVapp("update_both", check, vapp, vappName, vappDescription, vms)

// change name after adding VMs
vcd.testUpdateVapp("rename", check, vapp, newVappName, vappDescription, vms)
// restore original
vcd.testUpdateVapp("update_both", check, vapp, vappName, vappDescription, vms)

// Remove vApp
err = deleteVapp(vcd, vappName)
check.Assert(err, IsNil)
}
15 changes: 8 additions & 7 deletions govcd/vdc.go
Original file line number Diff line number Diff line change
Expand Up @@ -464,14 +464,15 @@ func (vdc *Vdc) GetEdgeGatewayByNameOrId(identifier string, refresh bool) (*Edge
return entity.(*EdgeGateway), err
}

func (vdc *Vdc) ComposeRawVApp(name string) error {
func (vdc *Vdc) ComposeRawVApp(name string, description string) error {
vcomp := &types.ComposeVAppParams{
Ovf: types.XMLNamespaceOVF,
Xsi: types.XMLNamespaceXSI,
Xmlns: types.XMLNamespaceVCloud,
Deploy: false,
Name: name,
PowerOn: false,
Ovf: types.XMLNamespaceOVF,
Xsi: types.XMLNamespaceXSI,
Xmlns: types.XMLNamespaceVCloud,
Deploy: false,
Name: name,
PowerOn: false,
Description: description,
}

vdcHref, err := url.ParseRequestURI(vdc.Vdc.HREF)
Expand Down
33 changes: 32 additions & 1 deletion govcd/vdc_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
// +build vdc functional ALL

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

package govcd

import (
"fmt"
"time"

. "gopkg.in/check.v1"

Expand Down Expand Up @@ -217,6 +218,36 @@ func (vcd *TestVCD) Test_ComposeVApp(check *C) {

}

func (vcd *TestVCD) Test_ComposeRawVApp(check *C) {
fmt.Printf("Running: %s\n", check.TestName())

vappName := check.TestName()
vappDescription := vappName + " desc"
// Compose VApp
err := vcd.vdc.ComposeRawVApp(vappName, vappDescription)
check.Assert(err, IsNil)

// Need a slight delay for the vApp to get the links that are needed for renaming
time.Sleep(time.Second)
// Get VApp
vapp, err := vcd.vdc.GetVAppByName(vappName, true)
check.Assert(err, IsNil)
AddToCleanupList(vappName, "vapp", "", "Test_ComposeRawVApp")
check.Assert(vapp.VApp.Name, Equals, vappName)
check.Assert(vapp.VApp.Description, Equals, vappDescription)
newVappName := vappName + "_new"
newVappDescription := vappDescription + " description"

err = vapp.UpdateNameDescription(newVappName, newVappDescription)
check.Assert(err, IsNil)
AddToCleanupList(newVappName, "vapp", "", "Test_ComposeRawVApp")
check.Assert(vapp.VApp.Name, Equals, newVappName)
check.Assert(vapp.VApp.Description, Equals, newVappDescription)

err = deleteVapp(vcd, newVappName)
check.Assert(err, IsNil)
}

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

if vcd.skipVappTests {
Expand Down
2 changes: 1 addition & 1 deletion govcd/vm_affinity_rule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ func makeVappGroup(label string, vdc *Vdc, groupDefinition map[string][]string)
if testVerbose {
fmt.Printf("Creating vApp %s\n", vappName)
}
vapp, err := makeEmptyVapp(vdc, vappName)
vapp, err := makeEmptyVapp(vdc, vappName, "")
if err != nil {
return nil, err
}
Expand Down
12 changes: 12 additions & 0 deletions types/v56/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -1186,6 +1186,18 @@ type ReComposeVAppParams struct {
DeleteItem *DeleteItem `xml:"DeleteItem,omitempty"`
}

// SmallRecomposeVappParams is used to update name and description of a vApp
// Using the full definition (ReComposeVAppParams), the description can be changed but not removed
type SmallRecomposeVappParams struct {
XMLName xml.Name `xml:"RecomposeVAppParams"`
Ovf string `xml:"xmlns:ovf,attr"`
Xsi string `xml:"xmlns:xsi,attr"`
Xmlns string `xml:"xmlns,attr"`
Name string `xml:"name,attr"`
Deploy bool `xml:"deploy,attr"`
Description string `xml:"Description"`
}

type DeleteItem struct {
HREF string `xml:"href,attr,omitempty"`
}
Expand Down