Skip to content

Commit

Permalink
Self review and tests
Browse files Browse the repository at this point in the history
Signed-off-by: Dainius Serplis <dserplis@vmware.com>
  • Loading branch information
Didainius committed Jun 23, 2023
1 parent b2b9bba commit fd37cb6
Show file tree
Hide file tree
Showing 12 changed files with 236 additions and 101 deletions.
13 changes: 13 additions & 0 deletions .changes/v2.21.0/579-features.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
* Added IP Space Uplink CRUD support via `IpSpaceUplink` and `types.IpSpaceUplink` and
`VCDClient.CreateIpSpaceUplink`, `VCDClient.GetAllIpSpaceUplinks`,
`VCDClient.GetIpSpaceUplinkById`, `VCDClient.GetIpSpaceUplinkByName`, `IpSpaceUplink.Update`,
`IpSpaceUplink.Delete` [GH-579]
* Added IP Space Allocation CRUD suport via `IpSpaceIpAllocation`, `types.IpSpaceIpAllocation`,
`types.IpSpaceIpAllocationRequest`, `types.IpSpaceIpAllocationRequestResult`. Methods
`IpSpace.AllocateIp`, `Org.IpSpaceAllocateIp`, `Org.GetIpSpaceAllocationByTypeAndValue`,
`IpSpace.GetAllIpSpaceAllocations`, `Org.GetIpSpaceAllocationById`, `IpSpaceIpAllocation.Update`,
`IpSpaceIpAllocation.Delete` [GH-579]
* Added IP Space Org allocation to support Custom Quotas via `IpSpaceOrgAssignment`,
`types.IpSpaceOrgAssignment`, `IpSpace.GetAllOrgAssignments`, `IpSpace.GetOrgAssignmentById`,
`IpSpace.GetOrgAssignmentByOrgName`, `IpSpace.GetOrgAssignmentByOrgId`,
`IpSpaceOrgAssignment.Update` [GH-579]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
* External Network V2 now supports IP Spaces on VCD 10.4.1+ with new fields `UsingIpSpace` and
`DedicatedOrg` [GH-XXX]
`DedicatedOrg` [GH-579]
4 changes: 0 additions & 4 deletions .changes/v2.21.0/XXX-features.md

This file was deleted.

13 changes: 0 additions & 13 deletions govcd/external_network_v2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,16 +231,3 @@ func getVcenterHref(vcdClient *VCDClient, name string) (string, error) {
}
return virtualCenters[0].HREF, nil
}

// func (vcd *TestVCD) Test_CreateExternalNetworkV2NsxtIpSpaces(check *C) {
// // Create External Network backed by IP Spaces

// if vcd.client.Client.APIVCDMaxVersionIs("< 37.1") {
// check.Skip("IP Spaces are supported in VCD 10.4.1+")
// }

// // endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointExternalNetworks
// // skipOpenApiEndpointTest(vcd, check, endpoint)
// // skipNoNsxtConfiguration(vcd, check)

// }
103 changes: 59 additions & 44 deletions govcd/ip_space_allocation.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"github.com/vmware/go-vcloud-director/v2/types/v56"
)

// IpSpaceIpAllocation
// IpSpaceIpAllocation handle IP Space IP allocation requests
type IpSpaceIpAllocation struct {
IpSpaceIpAllocation *types.IpSpaceIpAllocation
IpSpaceId string
Expand All @@ -22,51 +22,23 @@ type IpSpaceIpAllocation struct {
parent organization
}

// AllocateIp performs IP Allocation request for a specific Org and returns the result
func (ipSpace *IpSpace) AllocateIp(orgId, orgName string, ipAllocationConfig *types.IpSpaceIpAllocationRequest) ([]types.IpSpaceIpAllocationRequestResult, error) {
return allocateIpSpaceIp(&ipSpace.vcdClient.Client, orgId, orgName, ipSpace.IpSpace.ID, ipAllocationConfig)
}

// IpSpaceAllocateIp performs IP allocation request for a specific IP Space
func (org *Org) IpSpaceAllocateIp(ipSpaceId string, ipAllocationConfig *types.IpSpaceIpAllocationRequest) ([]types.IpSpaceIpAllocationRequestResult, error) {
return allocateIpSpaceIp(org.client, org.Org.ID, org.Org.Name, ipSpaceId, ipAllocationConfig)
}

func (org *Org) GetAllIpSpaceAllocations(ipSpaceId string, queryParameters url.Values) ([]*IpSpaceIpAllocation, error) {
client := org.client
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaceUplinksAllocations
apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint)
if err != nil {
return nil, err
}

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

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

// Wrap all typeResponses into DefinedEntityType types with client
results := make([]*IpSpaceIpAllocation, len(typeResponses))
for sliceIndex := range typeResponses {
results[sliceIndex] = &IpSpaceIpAllocation{
IpSpaceIpAllocation: typeResponses[sliceIndex],
client: client,
parent: org,
IpSpaceId: ipSpaceId,
}
}

return results, nil
}

// GetIpSpaceAllocationByTypeAndValue retrieves IP Space allocation by its type and value
// allocationType can be 'FLOATING_IP' (types.IpSpaceIpAllocationTypeFloatingIp) or 'IP_PREFIX'
// (types.IpSpaceIpAllocationTypeIpPrefix)
func (org *Org) GetIpSpaceAllocationByTypeAndValue(ipSpaceId string, allocationType, value string, queryParameters url.Values) (*IpSpaceIpAllocation, error) {
///// TODO FILTER BY ORG
queryParams := queryParameterFilterAnd(fmt.Sprintf("value==%s;type==%s", value, allocationType), queryParameters)

results, err := org.GetAllIpSpaceAllocations(ipSpaceId, queryParams)
results, err := getAllIpSpaceAllocations(org.client, ipSpaceId, org, queryParams)
if err != nil {
return nil, fmt.Errorf("error retrieving IP allocations: %s", err)
}
Expand All @@ -79,10 +51,16 @@ func (org *Org) GetIpSpaceAllocationByTypeAndValue(ipSpaceId string, allocationT
return singleResult, nil
}

// ipAllocationType is mandatory. FLOATING_IP or IP_PREFIX
func (ipSpace *IpSpace) GetAllIpSpaceAllocations(ipAllocationType string, queryParameters url.Values) ([]*IpSpaceIpAllocation, error) {
// GetAllIpSpaceAllocations retrieves all IP Allocations for a particular IP Space
// allocationType can be 'FLOATING_IP' (types.IpSpaceIpAllocationTypeFloatingIp) or 'IP_PREFIX'
// (types.IpSpaceIpAllocationTypeIpPrefix)
func (ipSpace *IpSpace) GetAllIpSpaceAllocations(allocationType string, queryParameters url.Values) ([]*IpSpaceIpAllocation, error) {
if allocationType == "" {
return nil, fmt.Errorf("allocationType is mandatory and must be 'FLOATING_IP' or 'IP_PREFIX'")
}

client := ipSpace.vcdClient.Client
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaceUplinksAllocations
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaceIpAllocations
apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint)
if err != nil {
return nil, err
Expand All @@ -92,9 +70,8 @@ func (ipSpace *IpSpace) GetAllIpSpaceAllocations(ipAllocationType string, queryP
if err != nil {
return nil, err
}
// Type is mandatory parameter
queryParams := queryParameterFilterAnd(fmt.Sprintf("type==%s", ipAllocationType), queryParameters)

queryParams := queryParameterFilterAnd(fmt.Sprintf("type==%s", allocationType), queryParameters)
typeResponses := []*types.IpSpaceIpAllocation{{}}
err = client.OpenApiGetAllItems(apiVersion, urlRef, queryParams, &typeResponses, nil)
if err != nil {
Expand All @@ -119,9 +96,13 @@ func (ipSpace *IpSpace) GetAllIpSpaceAllocations(ipAllocationType string, queryP
return results, nil
}

// GetIpSpaceAllocationById retrieves IP Allocation in a given IP Space by IDs
func (org *Org) GetIpSpaceAllocationById(ipSpaceId, allocationId string) (*IpSpaceIpAllocation, error) {
if ipSpaceId == "" || allocationId == "" {
return nil, fmt.Errorf("ipSpaceId and allocationId cannot be empty")
}
client := org.client
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaceUplinksAllocations
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaceIpAllocations
apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint)
if err != nil {
return nil, err
Expand All @@ -148,9 +129,10 @@ func (org *Org) GetIpSpaceAllocationById(ipSpaceId, allocationId string) (*IpSpa

}

// Update updates IP Allocation with a given configuration
func (ipSpaceAllocation *IpSpaceIpAllocation) Update(ipSpaceAllocationConfig *types.IpSpaceIpAllocation) (*IpSpaceIpAllocation, error) {
client := ipSpaceAllocation.client
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaceUplinksAllocations
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaceIpAllocations
apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint)
if err != nil {
return nil, err
Expand Down Expand Up @@ -181,6 +163,7 @@ func (ipSpaceAllocation *IpSpaceIpAllocation) Update(ipSpaceAllocationConfig *ty
return returnIpSpaceAllocation, nil
}

// Delete removes IP Allocation
func (ipSpaceAllocation *IpSpaceIpAllocation) Delete() error {
if ipSpaceAllocation == nil || ipSpaceAllocation.IpSpaceIpAllocation == nil || ipSpaceAllocation.IpSpaceIpAllocation.ID == "" {
return fmt.Errorf("IP Space IP Allocation must have ID")
Expand All @@ -191,7 +174,7 @@ func (ipSpaceAllocation *IpSpaceIpAllocation) Delete() error {
}

client := ipSpaceAllocation.client
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaceUplinksAllocations
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaceIpAllocations
apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint)
if err != nil {
return err
Expand Down Expand Up @@ -262,3 +245,35 @@ func allocateIpSpaceIp(client *Client, orgId, orgName, ipSpaceId string, ipAlloc

return unmarshalStorage, nil
}

func getAllIpSpaceAllocations(client *Client, ipSpaceId string, org *Org, queryParameters url.Values) ([]*IpSpaceIpAllocation, error) {
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaceIpAllocations
apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint)
if err != nil {
return nil, err
}

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

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

// Wrap all typeResponses into DefinedEntityType types with client
results := make([]*IpSpaceIpAllocation, len(typeResponses))
for sliceIndex := range typeResponses {
results[sliceIndex] = &IpSpaceIpAllocation{
IpSpaceIpAllocation: typeResponses[sliceIndex],
client: client,
parent: org,
IpSpaceId: ipSpaceId,
}
}

return results, nil
}
52 changes: 47 additions & 5 deletions govcd/ip_space_allocation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,16 @@ func (vcd *TestVCD) Test_IpSpaceIpAllocation(check *C) {
check.Skip(fmt.Sprintf(TestRequiresSysAdminPrivileges, check.TestName()))
}
skipNoNsxtConfiguration(vcd, check)
skipOpenApiEndpointTest(vcd, check, types.OpenApiPathVersion1_0_0+types.OpenApiEndpointIpSpaces)
skipOpenApiEndpointTest(vcd, check, types.OpenApiPathVersion1_0_0+types.OpenApiEndpointIpSpaceIpAllocations)

ipSpace := createIpSpace(vcd, check)
extNet := createExternalNetwork(vcd, check)

// IP Space uplink (not directly referenced anywhere, but is required to make IP allocations)
_ = createIpSpaceUplink(vcd, check, extNet.ExternalNetwork.ID, ipSpace.IpSpace.ID)
ipSpaceUplink := createIpSpaceUplink(vcd, check, extNet.ExternalNetwork.ID, ipSpace.IpSpace.ID)

// Create NSX-T Edge Gateway
_ = createNsxtEdgeGateway(vcd, check, extNet.ExternalNetwork.ID)
edgeGw := createNsxtEdgeGateway(vcd, check, extNet.ExternalNetwork.ID)

// Floating IP Allocation request
floatingIpAllocationRequest := &types.IpSpaceIpAllocationRequest{
Expand All @@ -35,11 +35,24 @@ func (vcd *TestVCD) Test_IpSpaceIpAllocation(check *C) {

// Prefix allocation request
prefixAllocationRequest := &types.IpSpaceIpAllocationRequest{
Type: "FLOATING_IP",
Type: "IP_PREFIX",
Quantity: addrOf(1),
PrefixLength: addrOf(31),
}
performIpAllocationChecks(vcd, check, ipSpace.IpSpace.ID, prefixAllocationRequest)

// Cleanup
err := edgeGw.Delete()
check.Assert(err, IsNil)

err = ipSpaceUplink.Delete()
check.Assert(err, IsNil)

err = extNet.Delete()
check.Assert(err, IsNil)

err = ipSpace.Delete()
check.Assert(err, IsNil)
}

func performIpAllocationChecks(vcd *TestVCD, check *C, ipSpaceId string, ipSpaceAllocationRequest *types.IpSpaceIpAllocationRequest) {
Expand All @@ -48,7 +61,7 @@ func performIpAllocationChecks(vcd *TestVCD, check *C, ipSpaceId string, ipSpace
check.Assert(err, IsNil)
check.Assert(len(ipAllocationResult), Equals, 1)

openApiEndpoint := types.OpenApiPathVersion1_0_0 + fmt.Sprintf(types.OpenApiEndpointIpSpaceUplinksAllocations, ipSpaceId) + ipAllocationResult[0].ID
openApiEndpoint := types.OpenApiPathVersion1_0_0 + fmt.Sprintf(types.OpenApiEndpointIpSpaceIpAllocations, ipSpaceId) + ipAllocationResult[0].ID
PrependToCleanupListOpenApi("NSX-T IP Space IP Allocation", check.TestName(), openApiEndpoint)

// Get IP Allocation
Expand All @@ -57,6 +70,12 @@ func performIpAllocationChecks(vcd *TestVCD, check *C, ipSpaceId string, ipSpace
check.Assert(ipAllocation, NotNil)
check.Assert(ipAllocation.IpSpaceIpAllocation.UsageState, Equals, types.IpSpaceIpAllocationUnused)

// Get IP Allocation by ID
ipAllocationById, err := vcd.org.GetIpSpaceAllocationById(ipSpaceId, ipAllocation.IpSpaceIpAllocation.ID)
check.Assert(err, IsNil)
check.Assert(ipAllocationById, NotNil)
check.Assert(ipAllocationById.IpSpaceIpAllocation, DeepEquals, ipAllocation.IpSpaceIpAllocation)

// Set the IP for manual usage
ipAllocation.IpSpaceIpAllocation.UsageState = types.IpSpaceIpAllocationUsedManual
ipAllocation.IpSpaceIpAllocation.Description = "Manual usage description"
Expand All @@ -75,6 +94,29 @@ func performIpAllocationChecks(vcd *TestVCD, check *C, ipSpaceId string, ipSpace

err = updatedIpAllocationManual.Delete()
check.Assert(err, IsNil)

// Get IP Space by ID
ipSpace, err := vcd.client.GetIpSpaceById(ipSpaceId)
check.Assert(err, IsNil)

// Attempt to search for allocations when none exist
allAllocations, err := ipSpace.GetAllIpSpaceAllocations(ipSpaceAllocationRequest.Type, nil)
check.Assert(err, IsNil)
check.Assert(len(allAllocations), Equals, 0)

// allocate IP
allocationByIpSpaceResult, err := ipSpace.AllocateIp(vcd.org.Org.ID, vcd.org.Org.Name, ipSpaceAllocationRequest)
check.Assert(err, IsNil)
check.Assert(len(allocationByIpSpaceResult), Equals, 1)

// Remove
ipAllocationByIpSpaceResult, err := vcd.org.GetIpSpaceAllocationByTypeAndValue(ipSpaceId, ipSpaceAllocationRequest.Type, allocationByIpSpaceResult[0].Value, nil)
check.Assert(err, IsNil)
check.Assert(ipAllocation, NotNil)

err = ipAllocationByIpSpaceResult.Delete()
check.Assert(err, IsNil)

}

func createIpSpaceUplink(vcd *TestVCD, check *C, extNetId, ipSpaceId string) *IpSpaceUplink {
Expand Down
28 changes: 16 additions & 12 deletions govcd/ip_space_org_assignment.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,23 @@ import (
"github.com/vmware/go-vcloud-director/v2/types/v56"
)

// IpSpaceIpAllocation
// IpSpaceOrgAssignment handles Custom Quotas (name in UI) for a particular Org. They complement
// default quotas which are being set in IP Space itself.
// The behavior of IpSpaceOrgAssignment is specific - whenever an NSX-T Edge Gateway backed by
// Provider gateway using IP Spaces is being created - Org Assignment is created implicitly. One can
// look that assignment by IP Space and Org to update `types.IpSpaceOrgAssignment.CustomQuotas`
// field
type IpSpaceOrgAssignment struct {
IpSpaceOrgAssignment *types.IpSpaceOrgAssignment
IpSpaceId string

vcdClient *VCDClient
// // Org context must be sent with requests
// parent organization
}

// Create - is there any point to have assignment
// Read
// Update
// Delete

// GetOrgAssignments retrieves all IP Space
// GetAllOrgAssignments retrieves all IP Space Org assignments within an IP Space
//
// Note. Org assignments are implicitly created after NSX-T Edge Gateway backed by Provider gateway
// using IP Spaces is being created.
func (ipSpace *IpSpace) GetAllOrgAssignments(queryParameters url.Values) ([]*IpSpaceOrgAssignment, error) {
client := ipSpace.vcdClient.Client
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaceOrgAssignments
Expand All @@ -39,9 +40,9 @@ func (ipSpace *IpSpace) GetAllOrgAssignments(queryParameters url.Values) ([]*IpS
if err != nil {
return nil, err
}

queryParams := queryParameterFilterAnd(fmt.Sprintf("ipSpaceRef.id==%s", ipSpace.IpSpace.ID), queryParameters)
typeResponses := []*types.IpSpaceOrgAssignment{{}}
err = client.OpenApiGetAllItems(apiVersion, urlRef, queryParameters, &typeResponses, nil)
err = client.OpenApiGetAllItems(apiVersion, urlRef, queryParams, &typeResponses, nil)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -91,6 +92,7 @@ func (ipSpace *IpSpace) GetOrgAssignmentById(id string) (*IpSpaceOrgAssignment,
return response, nil
}

// GetOrgAssignmentById retrieves IP Space Org Assignment with a given Org Name
func (ipSpace *IpSpace) GetOrgAssignmentByOrgName(orgName string) (*IpSpaceOrgAssignment, error) {
if orgName == "" {
return nil, fmt.Errorf("name of Org is required")
Expand All @@ -109,9 +111,10 @@ func (ipSpace *IpSpace) GetOrgAssignmentByOrgName(orgName string) (*IpSpaceOrgAs
return singleResult, nil
}

// GetOrgAssignmentById retrieves IP Space Org Assignment with a given Org ID
func (ipSpace *IpSpace) GetOrgAssignmentByOrgId(orgId string) (*IpSpaceOrgAssignment, error) {
if orgId == "" {
return nil, fmt.Errorf("Organization ID is required")
return nil, fmt.Errorf("organization ID is required")
}
queryParams := queryParameterFilterAnd(fmt.Sprintf("orgRef.id==%s", orgId), nil)
results, err := ipSpace.GetAllOrgAssignments(queryParams)
Expand All @@ -127,6 +130,7 @@ func (ipSpace *IpSpace) GetOrgAssignmentByOrgId(orgId string) (*IpSpaceOrgAssign
return singleResult, nil
}

// Update updates Org Assignment
func (ipSpaceOrgAssignment *IpSpaceOrgAssignment) Update(ipSpaceOrgAssignmentConfig *types.IpSpaceOrgAssignment) (*IpSpaceOrgAssignment, error) {
client := ipSpaceOrgAssignment.vcdClient.Client
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaceOrgAssignments
Expand Down
Loading

0 comments on commit fd37cb6

Please sign in to comment.