@@ -4,13 +4,15 @@ import (
4
4
"context"
5
5
"crypto/sha256"
6
6
"encoding/hex"
7
+ "fmt"
7
8
"strconv"
8
9
9
10
"golang.org/x/exp/maps"
10
11
11
12
"github.com/go-logr/logr"
12
13
"github.com/pkg/errors"
13
14
"github.com/samber/lo"
15
+ corev1 "k8s.io/api/core/v1"
14
16
networking "k8s.io/api/networking/v1"
15
17
"k8s.io/apimachinery/pkg/api/equality"
16
18
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -21,6 +23,8 @@ import (
21
23
policyinfo "github.com/aws/amazon-network-policy-controller-k8s/api/v1alpha1"
22
24
"github.com/aws/amazon-network-policy-controller-k8s/pkg/k8s"
23
25
"github.com/aws/amazon-network-policy-controller-k8s/pkg/resolvers"
26
+ "github.com/aws/amazon-network-policy-controller-k8s/pkg/utils/conditions"
27
+ "github.com/aws/amazon-network-policy-controller-k8s/pkg/utils/conversions"
24
28
)
25
29
26
30
type PolicyEndpointsManager interface {
@@ -39,6 +43,19 @@ func NewPolicyEndpointsManager(k8sClient client.Client, endpointChunkSize int, l
39
43
}
40
44
}
41
45
46
+ const (
47
+ ingressShift = 2
48
+ egressShift = 1
49
+ psShift = 0
50
+
51
+ ingBit = 4
52
+ egBit = 2
53
+ psBit = 1
54
+
55
+ reasonBinPacking = "PEBinPacked"
56
+ reasonPatching = "PEPatched"
57
+ )
58
+
42
59
var _ PolicyEndpointsManager = (* policyEndpointsManager )(nil )
43
60
44
61
type policyEndpointsManager struct {
@@ -60,12 +77,9 @@ func (m *policyEndpointsManager) Reconcile(ctx context.Context, policy *networki
60
77
client.MatchingFields {IndexKeyPolicyReferenceName : policy .Name }); err != nil {
61
78
return err
62
79
}
63
- existingPolicyEndpoints := make ([]policyinfo.PolicyEndpoint , 0 , len (policyEndpointList .Items ))
64
- for _ , policyEndpoint := range policyEndpointList .Items {
65
- existingPolicyEndpoints = append (existingPolicyEndpoints , policyEndpoint )
66
- }
67
80
68
- createList , updateList , deleteList , err := m .computePolicyEndpoints (policy , existingPolicyEndpoints , ingressRules , egressRules , podSelectorEndpoints )
81
+ createList , updateList , deleteList , packed , err := m .computePolicyEndpoints (policy , policyEndpointList .Items , ingressRules , egressRules , podSelectorEndpoints )
82
+ m .logger .Info ("the controller is packing PE rules" , "Packed" , conversions .IntToBool (packed ))
69
83
if err != nil {
70
84
return err
71
85
}
@@ -79,17 +93,42 @@ func (m *policyEndpointsManager) Reconcile(ctx context.Context, policy *networki
79
93
80
94
for _ , policyEndpoint := range updateList {
81
95
oldRes := & policyinfo.PolicyEndpoint {}
82
- if err := m .k8sClient .Get (ctx , k8s .NamespacedName (& policyEndpoint ), oldRes ); err != nil {
96
+ peId := k8s .NamespacedName (& policyEndpoint )
97
+ if err := m .k8sClient .Get (ctx , peId , oldRes ); err != nil {
83
98
return err
84
99
}
85
100
if equality .Semantic .DeepEqual (oldRes .Spec , policyEndpoint .Spec ) {
86
- m .logger .V (1 ).Info ("Policy endpoint already up to date" , "id" , k8s . NamespacedName ( & policyEndpoint ) )
101
+ m .logger .V (1 ).Info ("Policy endpoint already up to date" , "id" , peId )
87
102
continue
88
103
}
104
+
89
105
if err := m .k8sClient .Patch (ctx , & policyEndpoint , client .MergeFrom (oldRes )); err != nil {
106
+ if cErr := conditions .UpdatePEConditions (ctx , m .k8sClient ,
107
+ peId ,
108
+ m .logger ,
109
+ policyinfo .Updated ,
110
+ corev1 .ConditionFalse ,
111
+ reasonPatching ,
112
+ fmt .Sprintf ("patching policy endpoint failed: %s" , err .Error ()),
113
+ ); cErr != nil {
114
+ m .logger .Error (cErr , "Adding PE patch failure condition updates to PE failed" , "PENamespacedName" , peId )
115
+ }
90
116
return err
91
117
}
92
- m .logger .Info ("Updated policy endpoint" , "id" , k8s .NamespacedName (& policyEndpoint ))
118
+ m .logger .Info ("Updated policy endpoint" , "id" , peId )
119
+
120
+ if packed > 0 {
121
+ if err := conditions .UpdatePEConditions (ctx , m .k8sClient ,
122
+ peId ,
123
+ m .logger ,
124
+ policyinfo .Packed ,
125
+ corev1 .ConditionTrue ,
126
+ reasonBinPacking ,
127
+ fmt .Sprintf ("binpacked network policy endpoint slices on Ingress - %t, Egress - %t, PodSelector - %t" , packed & ingBit >> ingressShift == 1 , packed & egBit >> egressShift == 1 , packed & psBit >> psShift == 1 ),
128
+ ); err != nil {
129
+ m .logger .Error (err , "Adding bingpacking condition updates to PE failed" , "PENamespacedName" , peId )
130
+ }
131
+ }
93
132
}
94
133
95
134
for _ , policyEndpoint := range deleteList {
@@ -123,7 +162,7 @@ func (m *policyEndpointsManager) Cleanup(ctx context.Context, policy *networking
123
162
func (m * policyEndpointsManager ) computePolicyEndpoints (policy * networking.NetworkPolicy ,
124
163
existingPolicyEndpoints []policyinfo.PolicyEndpoint , ingressEndpoints []policyinfo.EndpointInfo ,
125
164
egressEndpoints []policyinfo.EndpointInfo , podSelectorEndpoints []policyinfo.PodEndpoint ) ([]policyinfo.PolicyEndpoint ,
126
- []policyinfo.PolicyEndpoint , []policyinfo.PolicyEndpoint , error ) {
165
+ []policyinfo.PolicyEndpoint , []policyinfo.PolicyEndpoint , int , error ) {
127
166
128
167
// Loop through ingressEndpoints, egressEndpoints and podSelectorEndpoints and put in map
129
168
// also populate them into policy endpoints
@@ -138,11 +177,11 @@ func (m *policyEndpointsManager) computePolicyEndpoints(policy *networking.Netwo
138
177
var deletePolicyEndpoints []policyinfo.PolicyEndpoint
139
178
140
179
// packing new ingress rules
141
- createPolicyEndpoints , doNotDeleteIngress := m .packingIngressRules (policy , ingressEndpointsMap , createPolicyEndpoints , modifiedEndpoints , potentialDeletes )
180
+ createPolicyEndpoints , doNotDeleteIngress , ingPacked := m .packingIngressRules (policy , ingressEndpointsMap , createPolicyEndpoints , modifiedEndpoints , potentialDeletes )
142
181
// packing new egress rules
143
- createPolicyEndpoints , doNotDeleteEgress := m .packingEgressRules (policy , egressEndpointsMap , createPolicyEndpoints , modifiedEndpoints , potentialDeletes )
182
+ createPolicyEndpoints , doNotDeleteEgress , egPacked := m .packingEgressRules (policy , egressEndpointsMap , createPolicyEndpoints , modifiedEndpoints , potentialDeletes )
144
183
// packing new pod selector
145
- createPolicyEndpoints , doNotDeletePs := m .packingPodSelectorEndpoints (policy , podSelectorEndpointSet .UnsortedList (), createPolicyEndpoints , modifiedEndpoints , potentialDeletes )
184
+ createPolicyEndpoints , doNotDeletePs , psPacked := m .packingPodSelectorEndpoints (policy , podSelectorEndpointSet .UnsortedList (), createPolicyEndpoints , modifiedEndpoints , potentialDeletes )
146
185
147
186
doNotDelete .Insert (doNotDeleteIngress .UnsortedList ()... )
148
187
doNotDelete .Insert (doNotDeleteEgress .UnsortedList ()... )
@@ -167,7 +206,7 @@ func (m *policyEndpointsManager) computePolicyEndpoints(policy *networking.Netwo
167
206
}
168
207
}
169
208
170
- return createPolicyEndpoints , updatePolicyEndpoints , deletePolicyEndpoints , nil
209
+ return createPolicyEndpoints , updatePolicyEndpoints , deletePolicyEndpoints , ( conversions . BoolToint ( ingPacked ) << ingressShift ) | ( conversions . BoolToint ( egPacked ) << egressShift ) | ( conversions . BoolToint ( psPacked ) << psShift ), nil
171
210
}
172
211
173
212
func (m * policyEndpointsManager ) newPolicyEndpoint (policy * networking.NetworkPolicy ,
@@ -202,6 +241,13 @@ func (m *policyEndpointsManager) newPolicyEndpoint(policy *networking.NetworkPol
202
241
Egress : egressRules ,
203
242
},
204
243
}
244
+
245
+ // if no pod selector is specified, the controller adds a boolean value true to AllPodsInNamespace
246
+ if policy .Spec .PodSelector .Size () == 0 {
247
+ m .logger .Info ("Creating a new PE but requested NP doesn't have pod selector" , "NPName" , policy .Name , "NPNamespace" , policy .Namespace )
248
+ policyEndpoint .Spec .AllPodsInNamespace = true
249
+ }
250
+
205
251
return policyEndpoint
206
252
}
207
253
@@ -319,24 +365,32 @@ func (m *policyEndpointsManager) processExistingPolicyEndpoints(
319
365
// it returns the ingress rules packed in policy endpoints and a set of policy endpoints that need to be kept.
320
366
func (m * policyEndpointsManager ) packingIngressRules (policy * networking.NetworkPolicy ,
321
367
rulesMap map [string ]policyinfo.EndpointInfo ,
322
- createPolicyEndpoints , modifiedEndpoints , potentialDeletes []policyinfo.PolicyEndpoint ) ([]policyinfo.PolicyEndpoint , sets.Set [types.NamespacedName ]) {
368
+ createPolicyEndpoints , modifiedEndpoints , potentialDeletes []policyinfo.PolicyEndpoint ) ([]policyinfo.PolicyEndpoint , sets.Set [types.NamespacedName ], bool ) {
323
369
doNotDelete := sets.Set [types.NamespacedName ]{}
324
370
chunkStartIdx := 0
325
371
chunkEndIdx := 0
326
372
ingressList := maps .Keys (rulesMap )
327
373
374
+ packed := false
375
+
328
376
// try to fill existing polciy endpoints first and then new ones if needed
329
377
for _ , sliceToCheck := range [][]policyinfo.PolicyEndpoint {modifiedEndpoints , potentialDeletes , createPolicyEndpoints } {
330
378
for i := range sliceToCheck {
331
379
// reset start pointer if end pointer is updated
332
380
chunkStartIdx = chunkEndIdx
381
+
333
382
// Instead of adding the entire chunk we should try to add to full the slice
334
- if len (sliceToCheck [i ].Spec .Ingress ) < m .endpointChunkSize && chunkEndIdx < len (ingressList ) {
383
+ // when new ingress rule list is greater than available spots in current non-empty PE rule's list, we do binpacking
384
+ spots := m .endpointChunkSize - len (sliceToCheck [i ].Spec .Ingress )
385
+ packed = spots > 0 && len (sliceToCheck [i ].Spec .Ingress ) > 0 && spots < len (ingressList )
386
+
387
+ if spots > 0 && chunkEndIdx < len (ingressList ) {
335
388
for len (sliceToCheck [i ].Spec .Ingress )+ (chunkEndIdx - chunkStartIdx + 1 ) < m .endpointChunkSize && chunkEndIdx < len (ingressList )- 1 {
336
389
chunkEndIdx ++
337
390
}
338
391
339
392
sliceToCheck [i ].Spec .Ingress = append (sliceToCheck [i ].Spec .Ingress , m .getListOfEndpointInfoFromHash (lo .Slice (ingressList , chunkStartIdx , chunkEndIdx + 1 ), rulesMap )... )
393
+
340
394
// move the end to next available index to prepare next appending
341
395
chunkEndIdx ++
342
396
}
@@ -355,26 +409,33 @@ func (m *policyEndpointsManager) packingIngressRules(policy *networking.NetworkP
355
409
createPolicyEndpoints = append (createPolicyEndpoints , newEP )
356
410
}
357
411
}
358
- return createPolicyEndpoints , doNotDelete
412
+ return createPolicyEndpoints , doNotDelete , packed
359
413
}
360
414
361
415
// packingEgressRules iterates over egress rules across available policy endpoints and required egress rule changes.
362
416
// it returns the egress rules packed in policy endpoints and a set of policy endpoints that need to be kept.
363
417
func (m * policyEndpointsManager ) packingEgressRules (policy * networking.NetworkPolicy ,
364
418
rulesMap map [string ]policyinfo.EndpointInfo ,
365
- createPolicyEndpoints , modifiedEndpoints , potentialDeletes []policyinfo.PolicyEndpoint ) ([]policyinfo.PolicyEndpoint , sets.Set [types.NamespacedName ]) {
419
+ createPolicyEndpoints , modifiedEndpoints , potentialDeletes []policyinfo.PolicyEndpoint ) ([]policyinfo.PolicyEndpoint , sets.Set [types.NamespacedName ], bool ) {
366
420
doNotDelete := sets.Set [types.NamespacedName ]{}
367
421
chunkStartIdx := 0
368
422
chunkEndIdx := 0
369
423
egressList := maps .Keys (rulesMap )
370
424
425
+ packed := false
426
+
371
427
// try to fill existing polciy endpoints first and then new ones if needed
372
428
for _ , sliceToCheck := range [][]policyinfo.PolicyEndpoint {modifiedEndpoints , potentialDeletes , createPolicyEndpoints } {
373
429
for i := range sliceToCheck {
374
430
// reset start pointer if end pointer is updated
375
431
chunkStartIdx = chunkEndIdx
432
+
376
433
// Instead of adding the entire chunk we should try to add to full the slice
377
- if len (sliceToCheck [i ].Spec .Egress ) < m .endpointChunkSize && chunkEndIdx < len (egressList ) {
434
+ // when new egress rule list is greater than available spots in current non-empty PE rule's list, we do binpacking
435
+ spots := m .endpointChunkSize - len (sliceToCheck [i ].Spec .Egress )
436
+ packed = spots > 0 && len (sliceToCheck [i ].Spec .Egress ) > 0 && spots < len (egressList )
437
+
438
+ if spots > 0 && chunkEndIdx < len (egressList ) {
378
439
for len (sliceToCheck [i ].Spec .Egress )+ (chunkEndIdx - chunkStartIdx + 1 ) < m .endpointChunkSize && chunkEndIdx < len (egressList )- 1 {
379
440
chunkEndIdx ++
380
441
}
@@ -398,26 +459,32 @@ func (m *policyEndpointsManager) packingEgressRules(policy *networking.NetworkPo
398
459
createPolicyEndpoints = append (createPolicyEndpoints , newEP )
399
460
}
400
461
}
401
- return createPolicyEndpoints , doNotDelete
462
+ return createPolicyEndpoints , doNotDelete , packed
402
463
}
403
464
404
465
// packingPodSelectorEndpoints iterates over pod selectors across available policy endpoints and required pod selector changes.
405
466
// it returns the pod selectors packed in policy endpoints and a set of policy endpoints that need to be kept.
406
467
func (m * policyEndpointsManager ) packingPodSelectorEndpoints (policy * networking.NetworkPolicy ,
407
468
psList []policyinfo.PodEndpoint ,
408
- createPolicyEndpoints , modifiedEndpoints , potentialDeletes []policyinfo.PolicyEndpoint ) ([]policyinfo.PolicyEndpoint , sets.Set [types.NamespacedName ]) {
469
+ createPolicyEndpoints , modifiedEndpoints , potentialDeletes []policyinfo.PolicyEndpoint ) ([]policyinfo.PolicyEndpoint , sets.Set [types.NamespacedName ], bool ) {
409
470
410
471
doNotDelete := sets.Set [types.NamespacedName ]{}
411
472
chunkStartIdx := 0
412
473
chunkEndIdx := 0
474
+ packed := false
413
475
414
476
// try to fill existing polciy endpoints first and then new ones if needed
415
477
for _ , sliceToCheck := range [][]policyinfo.PolicyEndpoint {modifiedEndpoints , potentialDeletes , createPolicyEndpoints } {
416
478
for i := range sliceToCheck {
417
479
// reset start pointer if end pointer is updated
418
480
chunkStartIdx = chunkEndIdx
481
+
419
482
// Instead of adding the entire chunk we should try to add to full the slice
420
- if len (sliceToCheck [i ].Spec .PodSelectorEndpoints ) < m .endpointChunkSize && chunkEndIdx < len (psList ) {
483
+ // when new pods list is greater than available spots in current non-empty PS list, we do binpacking
484
+ spots := m .endpointChunkSize - len (sliceToCheck [i ].Spec .PodSelectorEndpoints )
485
+ packed = spots > 0 && len (sliceToCheck [i ].Spec .PodSelectorEndpoints ) > 0 && spots < len (psList )
486
+
487
+ if spots > 0 && chunkEndIdx < len (psList ) {
421
488
for len (sliceToCheck [i ].Spec .PodSelectorEndpoints )+ (chunkEndIdx - chunkStartIdx + 1 ) < m .endpointChunkSize && chunkEndIdx < len (psList )- 1 {
422
489
chunkEndIdx ++
423
490
}
@@ -441,5 +508,5 @@ func (m *policyEndpointsManager) packingPodSelectorEndpoints(policy *networking.
441
508
createPolicyEndpoints = append (createPolicyEndpoints , newEP )
442
509
}
443
510
}
444
- return createPolicyEndpoints , doNotDelete
511
+ return createPolicyEndpoints , doNotDelete , packed
445
512
}
0 commit comments