Skip to content

Commit

Permalink
Change PR to only Defined Interfaces contents
Browse files Browse the repository at this point in the history
Signed-off-by: abarreiro <[email protected]>
  • Loading branch information
abarreiro committed Jan 25, 2023
1 parent 94f1112 commit a9dd4c8
Show file tree
Hide file tree
Showing 8 changed files with 308 additions and 3 deletions.
3 changes: 3 additions & 0 deletions .changes/v2.19.0/527-features.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
* Added support for Defined Interfaces with client methods `VCDClient.CreateDefinedInterface`, `VCDClient.GetAllDefinedInterfaces`,
`VCDClient.GetDefinedInterface`, `VCDClient.GetDefinedInterfaceById` and methods to manipulate them `DefinedInterface.Update`,
`DefinedInterface.Delete` [GH-527]
4 changes: 2 additions & 2 deletions govcd/api_vcd_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//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 || ALL
// +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 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 || ALL
// +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 ALL

/*
* Copyright 2022 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
Expand Down
6 changes: 5 additions & 1 deletion govcd/catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,10 @@ func queryVappTemplateAndVerifyTask(client *Client, vappTemplateUrl *url.URL, ne
return nil, err
}

if vappTemplateParsed.Tasks == nil {
return vappTemplateParsed, fmt.Errorf("the vApp Template %s does not contain tasks, an error happened during upload", vappTemplateUrl)
}

for _, task := range vappTemplateParsed.Tasks.Task {
if task.Status == "error" && newItemName == task.Owner.Name {
util.Logger.Printf("[Error] %#v", task.Error)
Expand Down Expand Up @@ -787,7 +791,7 @@ func removeCatalogItemOnError(client *Client, vappTemplateLink *url.URL, itemNam
if err != nil {
util.Logger.Printf("[Error] Error deleting Catalog item %s: %s", vappTemplateLink, err)
}
if len(vAppTemplate.Tasks.Task) > 0 {
if vAppTemplate.Tasks != nil && len(vAppTemplate.Tasks.Task) > 0 {
util.Logger.Printf("[TRACE] Task found. Will try to cancel.\n")
break
}
Expand Down
211 changes: 211 additions & 0 deletions govcd/defined_interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
/*
* Copyright 2022 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"
)

// DefinedInterface is a type for handling Defined Interfaces in VCD that allow to define new RDEs (DefinedEntityType).
type DefinedInterface struct {
DefinedInterface *types.DefinedInterface
client *Client
}

// CreateDefinedInterface creates a Defined Interface.
// Only System administrator can create Defined Interfaces.
func (vcdClient *VCDClient) CreateDefinedInterface(definedInterface *types.DefinedInterface) (*DefinedInterface, error) {
client := vcdClient.Client
if !client.IsSysAdmin {
return nil, fmt.Errorf("creating Defined Interfaces requires System user")
}

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

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

result := &DefinedInterface{
DefinedInterface: &types.DefinedInterface{},
client: &vcdClient.Client,
}

err = client.OpenApiPostItem(apiVersion, urlRef, nil, definedInterface, result.DefinedInterface, nil)
if err != nil {
return nil, err
}

return result, nil
}

// GetAllDefinedInterfaces retrieves all Defined Interfaces. Query parameters can be supplied to perform additional filtering.
// Only System administrator can retrieve Defined Interfaces.
func (vcdClient *VCDClient) GetAllDefinedInterfaces(queryParameters url.Values) ([]*DefinedInterface, error) {
client := vcdClient.Client
if !client.IsSysAdmin {
return nil, fmt.Errorf("getting Defined Interfaces requires System user")
}

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

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

typeResponses := []*types.DefinedInterface{{}}
err = client.OpenApiGetAllItems(apiVersion, urlRef, queryParameters, &typeResponses, nil)
if err != nil {
return nil, err
}

// Wrap all typeResponses into DefinedEntityType types with client
returnRDEs := make([]*DefinedInterface, len(typeResponses))
for sliceIndex := range typeResponses {
returnRDEs[sliceIndex] = &DefinedInterface{
DefinedInterface: typeResponses[sliceIndex],
client: &vcdClient.Client,
}
}

return returnRDEs, nil
}

// GetDefinedInterface retrieves a single Defined Interface defined by its unique combination of vendor, namespace and version.
// Only System administrator can retrieve Defined Interfaces.
func (vcdClient *VCDClient) GetDefinedInterface(vendor, namespace, version string) (*DefinedInterface, error) {
client := vcdClient.Client
if !client.IsSysAdmin {
return nil, fmt.Errorf("getting Defined Interfaces requires System user")
}

queryParameters := url.Values{}
queryParameters.Add("filter", fmt.Sprintf("vendor==%s;nss==%s;version==%s", vendor, namespace, version))
interfaces, err := vcdClient.GetAllDefinedInterfaces(queryParameters)
if err != nil {
return nil, err
}

if len(interfaces) == 0 {
return nil, fmt.Errorf("%s could not find the Defined Interface with vendor %s, namespace %s and version %s", ErrorEntityNotFound, vendor, namespace, version)
}

if len(interfaces) > 1 {
return nil, fmt.Errorf("found more than 1 Defined Interface with vendor %s, namespace %s and version %s", vendor, namespace, version)
}

return interfaces[0], nil
}

// GetDefinedInterfaceById gets a Defined Interface identified by its unique URN.
// Only System administrator can retrieve Defined Interfaces.
func (vcdClient *VCDClient) GetDefinedInterfaceById(id string) (*DefinedInterface, error) {
client := vcdClient.Client
if !client.IsSysAdmin {
return nil, fmt.Errorf("getting Defined Interfaces requires System user")
}

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

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

result := &DefinedInterface{
DefinedInterface: &types.DefinedInterface{},
client: &vcdClient.Client,
}

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

return result, nil
}

// Update updates the receiver Defined Interface with the values given by the input.
// Only System administrator can update Defined Interfaces.
func (di *DefinedInterface) Update(definedInterface types.DefinedInterface) error {
client := di.client
if !client.IsSysAdmin {
return fmt.Errorf("updating Defined Interfaces requires System user")
}

if di.DefinedInterface.ID == "" {
return fmt.Errorf("ID of the receiver Defined Interface is empty")
}

if definedInterface.ID != "" && definedInterface.ID != di.DefinedInterface.ID {
return fmt.Errorf("ID of the receiver Defined Interface and the input ID don't match")
}

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

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

err = client.OpenApiPutItem(apiVersion, urlRef, nil, definedInterface, di.DefinedInterface, nil)
if err != nil {
return err
}

return nil
}

// Delete deletes the receiver Defined Interface.
// Only System administrator can delete Defined Interfaces.
func (di *DefinedInterface) Delete() error {
client := di.client
if !client.IsSysAdmin {
return fmt.Errorf("deleting Defined Interfaces requires System user")
}

if di.DefinedInterface.ID == "" {
return fmt.Errorf("ID of the receiver Defined Interface is empty")
}

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

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

err = client.OpenApiDeleteItem(apiVersion, urlRef, nil, nil)
if err != nil {
return err
}

di.DefinedInterface = &types.DefinedInterface{}
return nil
}
75 changes: 75 additions & 0 deletions govcd/defined_interface_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//go:build functional || openapi || rde || ALL
// +build functional openapi rde ALL

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

package govcd

import (
"fmt"
"github.com/vmware/go-vcloud-director/v2/types/v56"
. "gopkg.in/check.v1"
"strings"
)

// Test_DefinedInterface tests the CRUD behavior of Defined Interfaces. First, it checks how many exist already,
// as VCD contains some pre-defined ones. Then we create a new one, so the number of existing ones should be increased by 1.
// We try to get this new created interface with the available getter methods and then perform an update.
// As a final step, we delete it and check that the deletion is correct (the receiver object is empty and doesn't exist in VCD).
func (vcd *TestVCD) Test_DefinedInterface(check *C) {
if vcd.skipAdminTests {
check.Skip(fmt.Sprintf(TestRequiresSysAdminPrivileges, check.TestName()))
}
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointInterfaces
skipOpenApiEndpointTest(vcd, check, endpoint)

allDefinedInterfaces, err := vcd.client.GetAllDefinedInterfaces(nil)
check.Assert(err, IsNil)
alreadyPresentRDEs := len(allDefinedInterfaces)

dummyRde := &types.DefinedInterface{
Name: check.TestName() + "_name",
Namespace: check.TestName() + "_nss",
Version: "1.2.3",
Vendor: "vmware",
}
newDefinedInterface, err := vcd.client.CreateDefinedInterface(dummyRde)
check.Assert(err, IsNil)
check.Assert(newDefinedInterface, NotNil)
check.Assert(newDefinedInterface.DefinedInterface.Name, Equals, dummyRde.Name)
check.Assert(newDefinedInterface.DefinedInterface.Namespace, Equals, dummyRde.Namespace)
check.Assert(newDefinedInterface.DefinedInterface.Version, Equals, dummyRde.Version)
check.Assert(newDefinedInterface.DefinedInterface.Vendor, Equals, dummyRde.Vendor)
check.Assert(newDefinedInterface.DefinedInterface.IsReadOnly, Equals, dummyRde.IsReadOnly)

AddToCleanupListOpenApi(newDefinedInterface.DefinedInterface.ID, check.TestName(), types.OpenApiPathVersion1_0_0+types.OpenApiEndpointInterfaces+newDefinedInterface.DefinedInterface.ID)

allDefinedInterfaces, err = vcd.client.GetAllDefinedInterfaces(nil)
check.Assert(err, IsNil)
check.Assert(len(allDefinedInterfaces), Equals, alreadyPresentRDEs+1)

obtainedDefinedInterface, err := vcd.client.GetDefinedInterfaceById(newDefinedInterface.DefinedInterface.ID)
check.Assert(err, IsNil)
check.Assert(*obtainedDefinedInterface.DefinedInterface, DeepEquals, *newDefinedInterface.DefinedInterface)

obtainedDefinedInterface2, err := vcd.client.GetDefinedInterface(obtainedDefinedInterface.DefinedInterface.Vendor, obtainedDefinedInterface.DefinedInterface.Namespace, obtainedDefinedInterface.DefinedInterface.Version)
check.Assert(err, IsNil)
check.Assert(*obtainedDefinedInterface2.DefinedInterface, DeepEquals, *obtainedDefinedInterface.DefinedInterface)

err = newDefinedInterface.Update(types.DefinedInterface{
Name: dummyRde.Name + "2", // Only name can be updated
})
check.Assert(err, IsNil)
check.Assert(newDefinedInterface.DefinedInterface.Name, Equals, dummyRde.Name+"2")

deletedId := newDefinedInterface.DefinedInterface.ID
err = newDefinedInterface.Delete()
check.Assert(err, IsNil)
check.Assert(*newDefinedInterface.DefinedInterface, DeepEquals, types.DefinedInterface{})

_, err = vcd.client.GetDefinedInterfaceById(deletedId)
check.Assert(err, NotNil)
check.Assert(strings.Contains(err.Error(), ErrorEntityNotFound.Error()), Equals, true)
}
1 change: 1 addition & 0 deletions govcd/openapi_endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ var endpointMinApiVersions = map[string]string{
types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointSecurityTags: "36.0", // VCD 10.3+
types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointNsxtRouteAdvertisement: "34.0", // VCD 10.1+
types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointLogicalVmGroups: "35.0", // VCD 10.2+
types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointInterfaces: "35.0", // VCD 10.2+

// NSX-T ALB (Advanced/AVI Load Balancer) support was introduced in 10.2
types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointAlbController: "35.0", // VCD 10.2+
Expand Down
1 change: 1 addition & 0 deletions types/v56/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ const (
OpenApiEndpointEdgeBgpNeighbor = "edgeGateways/%s/routing/bgp/neighbors/" // '%s' is NSX-T Edge Gateway ID
OpenApiEndpointEdgeBgpConfigPrefixLists = "edgeGateways/%s/routing/bgp/prefixLists/" // '%s' is NSX-T Edge Gateway ID
OpenApiEndpointEdgeBgpConfig = "edgeGateways/%s/routing/bgp" // '%s' is NSX-T Edge Gateway ID
OpenApiEndpointInterfaces = "interfaces/"

// NSX-T ALB related endpoints

Expand Down
10 changes: 10 additions & 0 deletions types/v56/openapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -426,3 +426,13 @@ type LogicalVmGroup struct {
NamedVmGroupReferences OpenApiReferences `json:"namedVmGroupReferences,omitempty"` // List of named VM Groups associated with LogicalVmGroup.
PvdcID string `json:"pvdcId,omitempty"` // URN for Provider VDC
}

// DefinedInterface defines a interface for a defined entity. The combination of nss+version+vendor should be unique
type DefinedInterface struct {
ID string `json:"id,omitempty"` // The id of the defined interface type in URN format
Name string `json:"name,omitempty"` // The name of the defined interface
Namespace string `json:"nss,omitempty"` // A unique namespace associated with the interface
Version string `json:"version,omitempty"` // The interface's version. The version should follow semantic versioning rules
Vendor string `json:"vendor,omitempty"` // The vendor name
IsReadOnly bool `json:"readonly,omitempty"` // True if the entity type cannot be modified
}

0 comments on commit a9dd4c8

Please sign in to comment.