Skip to content

Commit 46ac25c

Browse files
author
Hoanganh.Mai
committed
add check for tenant existence
1 parent 0508ece commit 46ac25c

12 files changed

+233
-29
lines changed

internal/controller/expected_netboxmock_calls_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ func mockTenancyTenancyTenantsList(tenancyMock *mock_interfaces.MockTenancyInter
234234
}
235235

236236
// -----------------------------
237-
// Restet Mock Functions
237+
// Reset Mock Functions
238238
// -----------------------------
239239

240240
func resetMockFunctions(ipamMockA *mock_interfaces.MockIpamInterface, ipamMockB *mock_interfaces.MockIpamInterface, tenancyMock *mock_interfaces.MockTenancyInterface) {

internal/controller/ipaddress_controller.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,15 @@ func (r *IpAddressReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
101101
return ctrl.Result{}, nil
102102
}
103103

104+
// if PreserveIpInNetbox flag is false then register finalizer if not yet registered
105+
if !o.Spec.PreserveInNetbox && !controllerutil.ContainsFinalizer(o, IpAddressFinalizerName) {
106+
debugLogger.Info("adding the finalizer")
107+
controllerutil.AddFinalizer(o, IpAddressFinalizerName)
108+
if err := r.Update(ctx, o); err != nil {
109+
return ctrl.Result{}, err
110+
}
111+
}
112+
104113
// 1. try to lock lease of parent prefix if IpAddress status condition is not true
105114
// and IpAddress is owned by an IpAddressClaim
106115
or := o.ObjectMeta.OwnerReferences
@@ -193,15 +202,6 @@ func (r *IpAddressReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
193202
r.Recorder.Event(o, corev1.EventTypeWarning, "IpDescriptionTruncated", "ip address was created with truncated description")
194203
}
195204

196-
// if PreserveIpInNetbox flag is false then register finalizer if not yet registered
197-
if !o.Spec.PreserveInNetbox && !controllerutil.ContainsFinalizer(o, IpAddressFinalizerName) {
198-
debugLogger.Info("adding the finalizer")
199-
controllerutil.AddFinalizer(o, IpAddressFinalizerName)
200-
if err := r.Update(ctx, o); err != nil {
201-
return ctrl.Result{}, err
202-
}
203-
}
204-
205205
debugLogger.Info(fmt.Sprintf("reserved ip address in netbox, ip: %s", o.Spec.IpAddress))
206206

207207
// 3. unlock lease of parent prefix

internal/controller/ipaddressclaim_controller.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,14 @@ func (r *IpAddressClaimReconciler) Reconcile(ctx context.Context, req ctrl.Reque
137137
},
138138
})
139139
if err != nil {
140-
return ctrl.Result{}, err
140+
setConditionErr := r.SetConditionAndCreateEvent(ctx, o, netboxv1.ConditionIpAssignedFalse, corev1.EventTypeWarning, err.Error())
141+
if setConditionErr != nil {
142+
return ctrl.Result{}, fmt.Errorf("error updating status: %w, when getting an available IP address failed: %w", setConditionErr, err)
143+
}
144+
145+
return ctrl.Result{Requeue: true}, nil
141146
}
142-
debugLogger.Info(fmt.Sprintf("ip address is not reserved in netbox, assignined new ip address: %s", ipAddressModel.IpAddress))
147+
debugLogger.Info(fmt.Sprintf("ip address is not reserved in netbox, assigned new ip address: %s", ipAddressModel.IpAddress))
143148
} else {
144149
// 5.b reassign reserved ip address from netbox
145150
// do nothing, ip address restored

internal/controller/prefix_controller.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,15 @@ func (r *PrefixReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr
9999
return ctrl.Result{}, nil
100100
}
101101

102+
// register finalizer if not yet registered
103+
if !prefix.Spec.PreserveInNetbox && !controllerutil.ContainsFinalizer(prefix, PrefixFinalizerName) {
104+
debugLogger.Info("adding the finalizer")
105+
controllerutil.AddFinalizer(prefix, PrefixFinalizerName)
106+
if err := r.Update(ctx, prefix); err != nil {
107+
return ctrl.Result{}, err
108+
}
109+
}
110+
102111
/*
103112
1. try to lock the lease of the parent prefix if all of the following conditions are met
104113
- the prefix is owned by at least 1 prefixClaim
@@ -188,15 +197,6 @@ func (r *PrefixReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr
188197
r.Recorder.Event(prefix, corev1.EventTypeWarning, "PrefixDescriptionTruncated", "prefix was created with truncated description")
189198
}
190199

191-
// register finalizer if not yet registered
192-
if !prefix.Spec.PreserveInNetbox && !controllerutil.ContainsFinalizer(prefix, PrefixFinalizerName) {
193-
debugLogger.Info("adding the finalizer")
194-
controllerutil.AddFinalizer(prefix, PrefixFinalizerName)
195-
if err := r.Update(ctx, prefix); err != nil {
196-
return ctrl.Result{}, err
197-
}
198-
}
199-
200200
debugLogger.Info(fmt.Sprintf("reserved prefix in netbox, prefix: %s", prefix.Spec.Prefix))
201201

202202
/* 3. unlock lease of parent prefix */

internal/controller/prefixclaim_controller.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,12 @@ func (r *PrefixClaimReconciler) Reconcile(ctx context.Context, req ctrl.Request)
135135
},
136136
})
137137
if err != nil {
138-
return ctrl.Result{}, err
138+
setConditionErr := r.SetConditionAndCreateEvent(ctx, prefixClaim, netboxv1.ConditionPrefixAssignedFalse, corev1.EventTypeWarning, err.Error())
139+
if setConditionErr != nil {
140+
return ctrl.Result{}, fmt.Errorf("error updating status: %w, when getting an available Prefix failed: %w", setConditionErr, err)
141+
}
142+
143+
return ctrl.Result{Requeue: true}, nil
139144
}
140145
debugLogger.Info(fmt.Sprintf("prefix is not reserved in netbox, assignined new prefix: %s", prefixModel.Prefix))
141146
} else {

pkg/netbox/api/ip_address_claim.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323

2424
"github.com/netbox-community/go-netbox/v3/netbox/client/ipam"
2525
"github.com/netbox-community/netbox-operator/pkg/netbox/models"
26+
"github.com/netbox-community/netbox-operator/pkg/netbox/utils"
2627
)
2728

2829
const (
@@ -57,6 +58,10 @@ func (r *NetboxClient) RestoreExistingIpByHash(customFieldName string, hash stri
5758

5859
// GetAvailableIpAddressByClaim searches an available IpAddress in Netbox matching IpAddressClaim requirements
5960
func (r *NetboxClient) GetAvailableIpAddressByClaim(ipAddressClaim *models.IPAddressClaim) (*models.IPAddress, error) {
61+
_, err := r.GetTenantDetails(ipAddressClaim.Metadata.Tenant)
62+
if err != nil {
63+
return nil, err
64+
}
6065

6166
responseParentPrefix, err := r.GetPrefix(&models.Prefix{
6267
Prefix: ipAddressClaim.ParentPrefix,
@@ -66,7 +71,7 @@ func (r *NetboxClient) GetAvailableIpAddressByClaim(ipAddressClaim *models.IPAdd
6671
return nil, err
6772
}
6873
if len(responseParentPrefix.Payload.Results) == 0 {
69-
return nil, errors.New("parent prefix not found")
74+
return nil, utils.NetboxNotFoundError("parent prefix")
7075
}
7176

7277
parentPrefixId := responseParentPrefix.Payload.Results[0].ID

pkg/netbox/api/ip_address_claim_test.go

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package api
1818

1919
import (
20+
"errors"
2021
"testing"
2122

2223
"github.com/netbox-community/go-netbox/v3/netbox/client/ipam"
@@ -166,8 +167,10 @@ func TestIPAddressClaim(t *testing.T) {
166167
},
167168
})
168169

170+
expectedErrMsg := "failed to fetch parent prefix: not found"
171+
169172
// assert error
170-
AssertError(t, err, "parent prefix not found")
173+
AssertError(t, err, expectedErrMsg)
171174
// assert nil output
172175
assert.Nil(t, actual)
173176
})
@@ -231,3 +234,78 @@ func TestIPAddressClaim(t *testing.T) {
231234
assert.Equal(t, ipAddressRestore, actual.IpAddress)
232235
})
233236
}
237+
238+
func TestIPAddressClaim_GetNoAvailableIPAddressWithTenancyChecks(t *testing.T) {
239+
ctrl := gomock.NewController(t)
240+
defer ctrl.Finish()
241+
242+
mockTenancy := mock_interfaces.NewMockTenancyInterface(ctrl)
243+
244+
parentPrefix := "10.112.140.0/24"
245+
t.Run("No IP address asigned with an error when getting the tenant list", func(t *testing.T) {
246+
247+
tenantName := "Tenant1"
248+
249+
inputTenant := tenancy.NewTenancyTenantsListParams().WithName(&tenantName)
250+
251+
// expected error
252+
expectedErrorMsg := "cannot get the list" // testcase-defined error
253+
254+
mockTenancy.EXPECT().TenancyTenantsList(inputTenant, nil).Return(nil, errors.New(expectedErrorMsg)).AnyTimes()
255+
256+
// init client
257+
client := &NetboxClient{
258+
Tenancy: mockTenancy,
259+
}
260+
261+
actual, err := client.GetAvailableIpAddressByClaim(&models.IPAddressClaim{
262+
ParentPrefix: parentPrefix,
263+
Metadata: &models.NetboxMetadata{
264+
Tenant: tenantName,
265+
},
266+
})
267+
268+
// assert error
269+
assert.Containsf(t, err.Error(), expectedErrorMsg, "Error should contain: %v, got: %v", expectedErrorMsg, err.Error())
270+
// assert nil output
271+
assert.Equal(t, actual, (*models.IPAddress)(nil))
272+
})
273+
274+
t.Run("No IP address asigned with non-existing tenant", func(t *testing.T) {
275+
276+
// non existing tenant
277+
nonExistingTenant := "non-existing-tenant"
278+
279+
inputTenant := tenancy.NewTenancyTenantsListParams().WithName(&nonExistingTenant)
280+
281+
// empty tenant list
282+
emptyTenantList := &tenancy.TenancyTenantsListOK{
283+
Payload: &tenancy.TenancyTenantsListOKBody{
284+
Results: []*netboxModels.Tenant{},
285+
},
286+
}
287+
288+
// expected error
289+
expectedErrorMsg := "failed to fetch tenant: not found"
290+
291+
// mock empty list call
292+
mockTenancy.EXPECT().TenancyTenantsList(inputTenant, nil).Return(emptyTenantList, nil).AnyTimes()
293+
294+
// init client
295+
client := &NetboxClient{
296+
Tenancy: mockTenancy,
297+
}
298+
299+
actual, err := client.GetAvailableIpAddressByClaim(&models.IPAddressClaim{
300+
ParentPrefix: parentPrefix,
301+
Metadata: &models.NetboxMetadata{
302+
Tenant: nonExistingTenant,
303+
},
304+
})
305+
306+
// assert error
307+
assert.EqualErrorf(t, err, expectedErrorMsg, "Error should be: %v, got: %v", expectedErrorMsg, err)
308+
// assert nil output
309+
assert.Equal(t, actual, (*models.IPAddress)(nil))
310+
})
311+
}

pkg/netbox/api/prefix_claim.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ func isRequestingTheEntireParentPrefix(prefixClaim *models.PrefixClaim) (bool, e
6767

6868
// GetAvailablePrefixByClaim searches an available Prefix in Netbox matching PrefixClaim requirements
6969
func (r *NetboxClient) GetAvailablePrefixByClaim(prefixClaim *models.PrefixClaim) (*models.Prefix, error) {
70+
_, err := r.GetTenantDetails(prefixClaim.Metadata.Tenant)
71+
if err != nil {
72+
return nil, err
73+
}
74+
7075
responseParentPrefix, err := r.GetPrefix(&models.Prefix{
7176
Prefix: prefixClaim.ParentPrefix,
7277
Metadata: prefixClaim.Metadata,

pkg/netbox/api/prefix_claim_test.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ func TestPrefixClaim_GetAvailablePrefixesByParentPrefix(t *testing.T) {
3838
//prefix mock input
3939
parentPrefixId := int64(3)
4040
availablePrefixListInput := ipam.NewIpamPrefixesAvailablePrefixesListParams().WithID(parentPrefixId)
41+
4142
//prefix mock output
4243
childPrefix1 := "10.112.140.0/24"
4344
childPrefix2 := "10.120.180.0/24"
@@ -129,6 +130,9 @@ func TestPrefixClaim_GetAvailablePrefixByClaim_WithWrongParent(t *testing.T) {
129130
actual, err := netboxClient.GetAvailablePrefixByClaim(&models.PrefixClaim{
130131
ParentPrefix: prefix,
131132
PrefixLength: "/28",
133+
Metadata: &models.NetboxMetadata{
134+
Tenant: tenantName,
135+
},
132136
})
133137
assert.Nil(t, actual)
134138
assert.EqualError(t, err, "parent prefix not found")
@@ -196,6 +200,9 @@ func TestPrefixClaim_GetBestFitPrefixByClaim(t *testing.T) {
196200
actual, err := netboxClient.GetAvailablePrefixByClaim(&models.PrefixClaim{
197201
ParentPrefix: parentPrefix,
198202
PrefixLength: "/28",
203+
Metadata: &models.NetboxMetadata{
204+
Tenant: tenantName,
205+
},
199206
})
200207

201208
assert.Nil(t, err)
@@ -272,6 +279,9 @@ func TestPrefixClaim_GetBestFitPrefixByClaimNoAvailablePrefixMatchesSize(t *test
272279
actual, err := netboxClient.GetAvailablePrefixByClaim(&models.PrefixClaim{
273280
ParentPrefix: parentPrefix,
274281
PrefixLength: "/28",
282+
Metadata: &models.NetboxMetadata{
283+
Tenant: tenantName,
284+
},
275285
})
276286

277287
assert.Nil(t, err)
@@ -340,6 +350,9 @@ func TestPrefixClaim_GetBestFitPrefixByClaimNoAvailablePrefixMatchesSizeCriteria
340350
_, err := netboxClient.GetAvailablePrefixByClaim(&models.PrefixClaim{
341351
ParentPrefix: parentPrefix,
342352
PrefixLength: "/28",
353+
Metadata: &models.NetboxMetadata{
354+
Tenant: tenantName,
355+
},
343356
})
344357

345358
assert.True(t, errors.Is(err, ErrNoPrefixMatchsSizeCriteria))
@@ -415,6 +428,9 @@ func TestPrefixClaim_GetBestFitPrefixByClaimInvalidFormatFromNetbox(t *testing.T
415428
actual, err := netboxClient.GetAvailablePrefixByClaim(&models.PrefixClaim{
416429
ParentPrefix: parentPrefix,
417430
PrefixLength: "/28",
431+
Metadata: &models.NetboxMetadata{
432+
Tenant: tenantName,
433+
},
418434
})
419435

420436
assert.Nil(t, err)
@@ -483,7 +499,92 @@ func TestPrefixClaim_GetBestFitPrefixByClaimInvalidPrefixClaim(t *testing.T) {
483499
_, err := netboxClient.GetAvailablePrefixByClaim(&models.PrefixClaim{
484500
ParentPrefix: parentPrefix,
485501
PrefixLength: "/28.",
502+
Metadata: &models.NetboxMetadata{
503+
Tenant: tenantName,
504+
},
486505
})
487506

488507
assert.True(t, errors.Is(err, strconv.ErrSyntax))
489508
}
509+
510+
func TestPrefixClaim_GetNoAvailablePrefixesWithNonExistingTenant(t *testing.T) {
511+
ctrl := gomock.NewController(t)
512+
defer ctrl.Finish()
513+
514+
mockTenancy := mock_interfaces.NewMockTenancyInterface(ctrl)
515+
516+
// non-existing tenant
517+
tenantName := "non-existing-tenant"
518+
519+
inputTenant := tenancy.NewTenancyTenantsListParams().WithName(&tenantName)
520+
521+
// expected error
522+
expectedErrorMsg := "failed to fetch tenant: not found"
523+
524+
// empty tenant list
525+
emptyTenantList := &tenancy.TenancyTenantsListOK{
526+
Payload: &tenancy.TenancyTenantsListOKBody{
527+
Results: []*netboxModels.Tenant{},
528+
},
529+
}
530+
531+
parentPrefix := "10.112.140.0/24"
532+
533+
mockTenancy.EXPECT().TenancyTenantsList(inputTenant, nil).Return(emptyTenantList, nil).AnyTimes()
534+
535+
netboxClient := &NetboxClient{
536+
Tenancy: mockTenancy,
537+
}
538+
539+
prefix, err := netboxClient.GetAvailablePrefixByClaim(&models.PrefixClaim{
540+
ParentPrefix: parentPrefix,
541+
PrefixLength: "/28.",
542+
Metadata: &models.NetboxMetadata{
543+
Tenant: tenantName,
544+
},
545+
})
546+
547+
assert.EqualErrorf(t, err, expectedErrorMsg, "Error should be: %v, got: %v", expectedErrorMsg, err)
548+
assert.Equal(t, prefix, (*models.Prefix)(nil))
549+
}
550+
551+
func TestPrefixClaim_GetNoAvailablePrefixesWithErrorWhenGettingTenantList(t *testing.T) {
552+
ctrl := gomock.NewController(t)
553+
defer ctrl.Finish()
554+
555+
mockTenancy := mock_interfaces.NewMockTenancyInterface(ctrl)
556+
557+
// non-existing tenant
558+
tenantName := "non-existing tenant"
559+
560+
inputTenant := tenancy.NewTenancyTenantsListParams().WithName(&tenantName)
561+
562+
// expected errors
563+
getTenantDetailsErrorMsg := "failed to fetch Tenant details"
564+
tenancyTenantsListErrorMsg := "cannot get the list" // testcase defined error
565+
566+
parentPrefix := "10.112.140.0/24"
567+
568+
mockTenancy.EXPECT().TenancyTenantsList(inputTenant, nil).Return(nil, errors.New(tenancyTenantsListErrorMsg)).AnyTimes()
569+
570+
netboxClient := &NetboxClient{
571+
Tenancy: mockTenancy,
572+
}
573+
574+
prefix, err := netboxClient.GetAvailablePrefixByClaim(&models.PrefixClaim{
575+
ParentPrefix: parentPrefix,
576+
PrefixLength: "/28.",
577+
Metadata: &models.NetboxMetadata{
578+
Tenant: tenantName,
579+
},
580+
})
581+
582+
// assert 1st level error - GetTenantDetails()
583+
assert.Containsf(t, err.Error(), getTenantDetailsErrorMsg, "expected error containing %q, got %s", getTenantDetailsErrorMsg, err)
584+
585+
// assert 2nd level error - TenanyTenantsList()
586+
assert.Containsf(t, err.Error(), tenancyTenantsListErrorMsg, "expected error containing %q, got %s", tenancyTenantsListErrorMsg, err)
587+
588+
// assert nil output
589+
assert.Equal(t, prefix, (*models.Prefix)(nil))
590+
}

0 commit comments

Comments
 (0)