7
7
"context"
8
8
"fmt"
9
9
"strconv"
10
+ "strings"
10
11
11
12
"golang.org/x/sync/errgroup"
12
13
corev1 "k8s.io/api/core/v1"
@@ -15,6 +16,7 @@ import (
15
16
"k8s.io/apimachinery/pkg/labels"
16
17
"k8s.io/apimachinery/pkg/selection"
17
18
"k8s.io/apimachinery/pkg/types"
19
+ "k8s.io/apimachinery/pkg/util/sets"
18
20
"k8s.io/client-go/util/retry"
19
21
"sigs.k8s.io/controller-runtime/pkg/client"
20
22
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
@@ -52,9 +54,12 @@ func (r *Manager) syncResourceQuotas(ctx context.Context, tenant *capsulev1beta2
52
54
group := new (errgroup.Group )
53
55
54
56
for i , q := range tenant .Spec .ResourceQuota .Items {
55
- index := i
57
+ index , resourceQuota := i , q
56
58
57
- resourceQuota := q
59
+ toKeep := sets .New [corev1.ResourceName ]()
60
+ for k := range resourceQuota .Hard {
61
+ toKeep .Insert (k )
62
+ }
58
63
59
64
group .Go (func () (scopeErr error ) {
60
65
// Calculating the Resource Budget at Tenant scope just if this is put in place.
@@ -120,9 +125,15 @@ func (r *Manager) syncResourceQuotas(ctx context.Context, tenant *capsulev1beta2
120
125
list .Items [item ].Spec .Hard = map [corev1.ResourceName ]resource.Quantity {}
121
126
}
122
127
list .Items [item ].Spec .Hard [name ] = resourceQuota .Hard [name ]
128
+
129
+ for k := range list .Items [item ].Spec .Hard {
130
+ if ! toKeep .Has (k ) {
131
+ delete (list .Items [item ].Spec .Hard , k )
132
+ }
133
+ }
123
134
}
124
135
}
125
- if scopeErr = r .resourceQuotasUpdate (ctx , name , quantity , resourceQuota .Hard [name ], list .Items ... ); scopeErr != nil {
136
+ if scopeErr = r .resourceQuotasUpdate (ctx , name , quantity , toKeep , resourceQuota .Hard [name ], list .Items ... ); scopeErr != nil {
126
137
r .Log .Error (scopeErr , "cannot proceed with outer ResourceQuota" )
127
138
128
139
return
@@ -217,9 +228,21 @@ func (r *Manager) syncResourceQuota(ctx context.Context, tenant *capsulev1beta2.
217
228
// Serial ResourceQuota processing is expensive: using Go routines we can speed it up.
218
229
// In case of multiple errors these are logged properly, returning a generic error since we have to repush back the
219
230
// reconciliation loop.
220
- func (r * Manager ) resourceQuotasUpdate (ctx context.Context , resourceName corev1.ResourceName , actual , limit resource.Quantity , list ... corev1.ResourceQuota ) (err error ) {
231
+ func (r * Manager ) resourceQuotasUpdate (ctx context.Context , resourceName corev1.ResourceName , actual resource. Quantity , toKeep sets. Set [corev1. ResourceName ] , limit resource.Quantity , list ... corev1.ResourceQuota ) (err error ) {
221
232
group := new (errgroup.Group )
222
233
234
+ annotationsToKeep := sets .New [string ]()
235
+
236
+ for _ , item := range toKeep .UnsortedList () {
237
+ if v , vErr := capsulev1beta2 .UsedQuotaFor (item ); vErr == nil {
238
+ annotationsToKeep .Insert (v )
239
+ }
240
+
241
+ if v , vErr := capsulev1beta2 .HardQuotaFor (item ); vErr == nil {
242
+ annotationsToKeep .Insert (v )
243
+ }
244
+ }
245
+
223
246
for _ , item := range list {
224
247
rq := item
225
248
@@ -236,6 +259,16 @@ func (r *Manager) resourceQuotasUpdate(ctx context.Context, resourceName corev1.
236
259
if found .Annotations == nil {
237
260
found .Annotations = make (map [string ]string )
238
261
}
262
+ // Pruning the Capsule quota annotations:
263
+ // if the ResourceQuota is updated by removing some objects,
264
+ // we could still have left-overs which could be misleading.
265
+ // This will not lead to a reconciliation loop since the whole code is idempotent.
266
+ for k := range found .Annotations {
267
+ if (strings .HasPrefix (k , capsulev1beta2 .HardCapsuleQuotaAnnotation ) || strings .HasPrefix (k , capsulev1beta2 .UsedCapsuleQuotaAnnotation )) && ! annotationsToKeep .Has (k ) {
268
+ delete (found .Annotations , k )
269
+ }
270
+ }
271
+
239
272
found .Labels = rq .Labels
240
273
if actualKey , keyErr := capsulev1beta2 .UsedQuotaFor (resourceName ); keyErr == nil {
241
274
found .Annotations [actualKey ] = actual .String ()
0 commit comments