Skip to content

Commit 1bb3b54

Browse files
committed
Consumption of Generic functions
1 parent 4d5a06a commit 1bb3b54

12 files changed

+270
-797
lines changed

.changes/v2.23.0/644-notes.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* Add internal generic functions to handle CRUD operations for inner and outer entities [GH-644]

govcd/adminorg_ldap_test.go

-5
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ package govcd
88

99
import (
1010
"fmt"
11-
"time"
1211

1312
"github.com/vmware/go-vcloud-director/v2/types/v56"
1413
. "gopkg.in/check.v1"
@@ -62,10 +61,6 @@ func (vcd *TestVCD) Test_LDAP(check *C) {
6261
check.Assert(err, IsNil)
6362
}()
6463

65-
sleepTime := 10 * time.Second
66-
fmt.Printf("# Sleeping %s to prevent 'LDAP context not initialized' errors\n", sleepTime.String())
67-
time.Sleep(sleepTime)
68-
6964
// Run tests requiring LDAP from here.
7065
vcd.test_GroupCRUD(check)
7166
vcd.test_GroupFinderGetGenericEntity(check)

govcd/generic_functions.go

+5-6
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,17 @@ func oneOrError[E any](key, name string, entitySlice []*E) (*E, error) {
4040
return entitySlice[0], nil
4141
}
4242

43-
// genericLocalFilter performs filtering of a type E based on a field name `fieldName` and its
43+
// localFilter performs filtering of a type E based on a field name `fieldName` and its
4444
// expected string value `expectedFieldValue`. Common use case for GetAllX methods where API does
4545
// not support filtering and it must be done on client side.
4646
//
4747
// Note. The field name `fieldName` must be present in a given type E (letter casing is important)
48-
func genericLocalFilter[E any](entities []*E, fieldName, expectedFieldValue string, entityName string) ([]*E, error) {
48+
func localFilter[E any](entities []*E, fieldName, expectedFieldValue string, entityName string) ([]*E, error) {
4949
if len(entities) == 0 {
5050
return nil, fmt.Errorf("zero entities provided for filtering")
5151
}
5252

5353
filteredValues := make([]*E, 0)
54-
5554
for _, entity := range entities {
5655

5756
// Need to deference pointer because `reflect` package requires to work with types and not
@@ -82,15 +81,15 @@ func genericLocalFilter[E any](entities []*E, fieldName, expectedFieldValue stri
8281
return filteredValues, nil
8382
}
8483

85-
// genericLocalFilterOneOrError performs local filtering using `genericLocalFilter()` and
84+
// localFilterOneOrError performs local filtering using `genericLocalFilter()` and
8685
// additionally verifies that only a single result is present using `oneOrError()`. Common use case
8786
// for GetXByName methods where API does not support filtering and it must be done on client side.
88-
func genericLocalFilterOneOrError[E any](entities []*E, fieldName, expectedFieldValue string, entityName string) (*E, error) {
87+
func localFilterOneOrError[E any](entities []*E, fieldName, expectedFieldValue string, entityName string) (*E, error) {
8988
if fieldName == "" || expectedFieldValue == "" {
9089
return nil, fmt.Errorf("expected field name and value must be specified to filter %s", entityName)
9190
}
9291

93-
filteredValues, err := genericLocalFilter(entities, fieldName, expectedFieldValue, entityName)
92+
filteredValues, err := localFilter(entities, fieldName, expectedFieldValue, entityName)
9493
if err != nil {
9594
return nil, err
9695
}

govcd/ip_space.go

+53-139
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
2+
* Copyright 2024 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
33
*/
44

55
package govcd
@@ -27,97 +27,37 @@ type IpSpace struct {
2727
vcdClient *VCDClient
2828
}
2929

30+
// wrap is a hidden helper that helps to facilitate usage of generic CRUD function
31+
//
32+
//lint:ignore U1000 this method is used in generic functions, but annoys staticcheck
33+
func (g IpSpace) wrap(inner *types.IpSpace) *IpSpace {
34+
g.IpSpace = inner
35+
return &g
36+
}
37+
3038
// CreateIpSpace creates IP Space with desired configuration
3139
func (vcdClient *VCDClient) CreateIpSpace(ipSpaceConfig *types.IpSpace) (*IpSpace, error) {
32-
client := vcdClient.Client
33-
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaces
34-
apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint)
35-
if err != nil {
36-
return nil, err
37-
}
38-
39-
urlRef, err := client.OpenApiBuildEndpoint(endpoint)
40-
if err != nil {
41-
return nil, err
42-
}
43-
44-
result := &IpSpace{
45-
IpSpace: &types.IpSpace{},
46-
vcdClient: vcdClient,
47-
}
48-
49-
err = client.OpenApiPostItem(apiVersion, urlRef, nil, ipSpaceConfig, result.IpSpace, nil)
50-
if err != nil {
51-
return nil, err
40+
c := crudConfig{
41+
endpoint: types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaces,
42+
entityName: "IP Space",
5243
}
53-
54-
return result, nil
44+
outerType := IpSpace{vcdClient: vcdClient}
45+
return createOuterEntity(&vcdClient.Client, outerType, c, ipSpaceConfig)
5546
}
5647

5748
// GetAllIpSpaceSummaries retrieve summaries of all IP Spaces with an optional filter
5849
// Note. There is no API endpoint to get multiple IP Spaces with their full definitions. Only
5950
// "summaries" endpoint exists, but it does not include all fields. To retrieve complete structure
6051
// one can use `GetIpSpaceById` or `GetIpSpaceByName`
6152
func (vcdClient *VCDClient) GetAllIpSpaceSummaries(queryParameters url.Values) ([]*IpSpace, error) {
62-
client := vcdClient.Client
63-
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaceSummaries
64-
apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint)
65-
if err != nil {
66-
return nil, err
67-
}
68-
69-
urlRef, err := client.OpenApiBuildEndpoint(endpoint)
70-
if err != nil {
71-
return nil, err
72-
}
73-
74-
typeResponses := []*types.IpSpace{{}}
75-
err = client.OpenApiGetAllItems(apiVersion, urlRef, queryParameters, &typeResponses, nil)
76-
if err != nil {
77-
return nil, err
78-
}
79-
80-
// Wrap all typeResponses into IpSpace types with client
81-
results := make([]*IpSpace, len(typeResponses))
82-
for sliceIndex := range typeResponses {
83-
results[sliceIndex] = &IpSpace{
84-
IpSpace: typeResponses[sliceIndex],
85-
vcdClient: vcdClient,
86-
}
53+
c := crudConfig{
54+
endpoint: types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaceSummaries,
55+
entityName: "IP Space",
56+
queryParameters: queryParameters,
8757
}
8858

89-
return results, nil
90-
}
91-
92-
// GetIpSpaceById retrieves IP Space with a given ID
93-
func (vcdClient *VCDClient) GetIpSpaceById(id string) (*IpSpace, error) {
94-
if id == "" {
95-
return nil, fmt.Errorf("IP Space lookup requires ID")
96-
}
97-
98-
client := vcdClient.Client
99-
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaces
100-
apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint)
101-
if err != nil {
102-
return nil, err
103-
}
104-
105-
urlRef, err := client.OpenApiBuildEndpoint(endpoint, id)
106-
if err != nil {
107-
return nil, err
108-
}
109-
110-
response := &IpSpace{
111-
vcdClient: vcdClient,
112-
IpSpace: &types.IpSpace{},
113-
}
114-
115-
err = client.OpenApiGetItem(apiVersion, urlRef, nil, response.IpSpace, nil)
116-
if err != nil {
117-
return nil, err
118-
}
119-
120-
return response, nil
59+
outerType := IpSpace{vcdClient: vcdClient}
60+
return getAllOuterEntities[IpSpace, types.IpSpace](&vcdClient.Client, outerType, c)
12161
}
12262

12363
// GetIpSpaceByName retrieves IP Space with a given name
@@ -127,39 +67,50 @@ func (vcdClient *VCDClient) GetIpSpaceByName(name string) (*IpSpace, error) {
12767
return nil, fmt.Errorf("IP Space lookup requires name")
12868
}
12969

130-
queryParameters := url.Values{}
131-
queryParameters.Add("filter", "name=="+name)
70+
queryParams := url.Values{}
71+
queryParams.Add("filter", "name=="+name)
13272

133-
filteredIpSpaces, err := vcdClient.GetAllIpSpaceSummaries(queryParameters)
73+
filteredEntities, err := vcdClient.GetAllIpSpaceSummaries(queryParams)
13474
if err != nil {
135-
return nil, fmt.Errorf("error getting IP Spaces: %s", err)
75+
return nil, err
13676
}
13777

138-
singleIpSpace, err := oneOrError("name", name, filteredIpSpaces)
78+
singleIpSpace, err := oneOrError("name", name, filteredEntities)
13979
if err != nil {
14080
return nil, err
14181
}
14282

14383
return vcdClient.GetIpSpaceById(singleIpSpace.IpSpace.ID)
14484
}
14585

86+
func (vcdClient *VCDClient) GetIpSpaceById(id string) (*IpSpace, error) {
87+
c := crudConfig{
88+
entityName: "IP Space",
89+
endpoint: types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaces,
90+
endpointParams: []string{id},
91+
}
92+
93+
outerType := IpSpace{vcdClient: vcdClient}
94+
return getOuterEntity[IpSpace, types.IpSpace](&vcdClient.Client, outerType, c)
95+
}
96+
14697
// GetIpSpaceByNameAndOrgId retrieves IP Space with a given name in a particular Org
14798
// Note. Only PRIVATE IP spaces belong to Orgs
14899
func (vcdClient *VCDClient) GetIpSpaceByNameAndOrgId(name, orgId string) (*IpSpace, error) {
149100
if name == "" || orgId == "" {
150101
return nil, fmt.Errorf("IP Space lookup requires name and Org ID")
151102
}
152103

153-
queryParameters := url.Values{}
154-
queryParameters.Add("filter", "name=="+name)
155-
queryParameters = queryParameterFilterAnd("orgRef.id=="+orgId, queryParameters)
104+
queryParams := url.Values{}
105+
queryParams.Add("filter", "name=="+name)
106+
queryParams = queryParameterFilterAnd("orgRef.id=="+orgId, queryParams)
156107

157-
filteredIpSpaces, err := vcdClient.GetAllIpSpaceSummaries(queryParameters)
108+
filteredEntities, err := vcdClient.GetAllIpSpaceSummaries(queryParams)
158109
if err != nil {
159-
return nil, fmt.Errorf("error getting IP Spaces: %s", err)
110+
return nil, err
160111
}
161112

162-
singleIpSpace, err := oneOrError("name", name, filteredIpSpaces)
113+
singleIpSpace, err := oneOrError("name", name, filteredEntities)
163114
if err != nil {
164115
return nil, err
165116
}
@@ -169,58 +120,21 @@ func (vcdClient *VCDClient) GetIpSpaceByNameAndOrgId(name, orgId string) (*IpSpa
169120

170121
// Update updates IP Space with new config
171122
func (ipSpace *IpSpace) Update(ipSpaceConfig *types.IpSpace) (*IpSpace, error) {
172-
client := ipSpace.vcdClient.Client
173-
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaces
174-
apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint)
175-
if err != nil {
176-
return nil, err
177-
}
178-
179-
ipSpaceConfig.ID = ipSpace.IpSpace.ID
180-
urlRef, err := client.OpenApiBuildEndpoint(endpoint, ipSpaceConfig.ID)
181-
if err != nil {
182-
return nil, err
123+
c := crudConfig{
124+
endpoint: types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaces,
125+
endpointParams: []string{ipSpace.IpSpace.ID},
126+
entityName: "IP Space",
183127
}
184-
185-
returnIpSpace := &IpSpace{
186-
IpSpace: &types.IpSpace{},
187-
vcdClient: ipSpace.vcdClient,
188-
}
189-
190-
err = client.OpenApiPutItem(apiVersion, urlRef, nil, ipSpaceConfig, returnIpSpace.IpSpace, nil)
191-
if err != nil {
192-
return nil, fmt.Errorf("error updating IP Space: %s", err)
193-
}
194-
195-
return returnIpSpace, nil
128+
outerType := IpSpace{vcdClient: ipSpace.vcdClient}
129+
return updateOuterEntity(&ipSpace.vcdClient.Client, outerType, c, ipSpaceConfig)
196130
}
197131

198132
// Delete deletes IP Space
199133
func (ipSpace *IpSpace) Delete() error {
200-
if ipSpace == nil || ipSpace.IpSpace == nil || ipSpace.IpSpace.ID == "" {
201-
return fmt.Errorf("IP Space must have ID")
134+
c := crudConfig{
135+
endpoint: types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaces,
136+
endpointParams: []string{ipSpace.IpSpace.ID},
137+
entityName: "IP Space",
202138
}
203-
204-
client := ipSpace.vcdClient.Client
205-
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointIpSpaces
206-
apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint)
207-
if err != nil {
208-
return err
209-
}
210-
211-
urlRef, err := client.OpenApiBuildEndpoint(endpoint, ipSpace.IpSpace.ID)
212-
if err != nil {
213-
return err
214-
}
215-
216-
err = client.OpenApiDeleteItem(apiVersion, urlRef, nil, nil)
217-
if err != nil {
218-
return err
219-
}
220-
221-
if err != nil {
222-
return fmt.Errorf("error deleting IP space: %s", err)
223-
}
224-
225-
return nil
139+
return deleteEntityById(&ipSpace.vcdClient.Client, c)
226140
}

0 commit comments

Comments
 (0)