Skip to content

Commit da7f2c7

Browse files
authored
fix management of deletefinalstateUnknown object on deletion event in each controller. Add Unit test for them. Correct log messages. (#856)
1 parent a736954 commit da7f2c7

File tree

7 files changed

+201
-28
lines changed

7 files changed

+201
-28
lines changed

npm/nameSpaceController.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ func (nsc *nameSpaceController) deleteNamespace(obj interface{}) {
192192

193193
var err error
194194
var key string
195-
if key, err = cache.MetaNamespaceKeyFunc(obj); err != nil {
195+
if key, err = cache.MetaNamespaceKeyFunc(nsObj); err != nil {
196196
utilruntime.HandleError(err)
197197
metrics.SendErrorLogAndMetric(util.NSID, "[NAMESPACE DELETE EVENT] Error: nameSpaceKey is empty for %s namespace", util.GetNSNameWithPrefix(nsObj.Name))
198198
return
@@ -287,7 +287,7 @@ func (nsc *nameSpaceController) syncNameSpace(key string) error {
287287
defer nsc.npMgr.Unlock()
288288
if err != nil {
289289
if errors.IsNotFound(err) {
290-
utilruntime.HandleError(fmt.Errorf("NameSpace '%s' in work queue no longer exists", key))
290+
klog.Infof("NameSpace %s not found, may be it is deleted", key)
291291
// find the nsMap key and start cleaning up process (calling cleanDeletedNamespace function)
292292
cachedNsKey := util.GetNSNameWithPrefix(key)
293293
// cleanDeletedNamespace will check if the NS exists in cache, if it does, then proceeds with deletion

npm/nameSpaceController_test.go

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
kubeinformers "k8s.io/client-go/informers"
1717
k8sfake "k8s.io/client-go/kubernetes/fake"
1818
core "k8s.io/client-go/testing"
19+
"k8s.io/client-go/tools/cache"
1920
)
2021

2122
var (
@@ -124,15 +125,24 @@ func updateNamespace(t *testing.T, f *nameSpaceFixture, oldNsObj, newNsObj *core
124125
f.nsController.processNextWorkItem()
125126
}
126127

127-
func deleteNamespace(t *testing.T, f *nameSpaceFixture, nsObj *corev1.Namespace) {
128+
func deleteNamespace(t *testing.T, f *nameSpaceFixture, nsObj *corev1.Namespace, isDeletedFinalStateUnknownObject IsDeletedFinalStateUnknownObject) {
128129
addNamespace(t, f, nsObj)
129130
t.Logf("Complete add namespace event")
130131

131132
t.Logf("Updating kubeinformer namespace object")
132133
f.kubeInformer.Core().V1().Namespaces().Informer().GetIndexer().Delete(nsObj)
133134

134135
t.Logf("Calling delete namespace event")
135-
f.nsController.deleteNamespace(nsObj)
136+
if isDeletedFinalStateUnknownObject {
137+
tombstone := cache.DeletedFinalStateUnknown{
138+
Key: nsObj.Name,
139+
Obj: nsObj,
140+
}
141+
f.nsController.deleteNamespace(tombstone)
142+
} else {
143+
f.nsController.deleteNamespace(nsObj)
144+
}
145+
136146
if f.nsController.workqueue.Len() == 0 {
137147
t.Logf("Delete Namespace: worker queue length is 0 ")
138148
return
@@ -432,7 +442,7 @@ func TestDeleteNamespace(t *testing.T) {
432442
stopCh := make(chan struct{})
433443
defer close(stopCh)
434444
f.newNsController(stopCh)
435-
deleteNamespace(t, f, nsObj)
445+
deleteNamespace(t, f, nsObj, DeletedFinalStateknownObject)
436446

437447
testCases := []expectedNsValues{
438448
{0, 1, 0},
@@ -444,6 +454,57 @@ func TestDeleteNamespace(t *testing.T) {
444454
}
445455
}
446456

457+
func TestDeleteNamespaceWithTombstone(t *testing.T) {
458+
f := newNsFixture(t)
459+
f.ipSetSave(util.IpsetTestConfigFile)
460+
defer f.ipSetRestore(util.IpsetTestConfigFile)
461+
stopCh := make(chan struct{})
462+
defer close(stopCh)
463+
f.newNsController(stopCh)
464+
465+
nsObj := newNameSpace(
466+
"test-namespace",
467+
"0",
468+
map[string]string{
469+
"app": "test-namespace",
470+
},
471+
)
472+
tombstone := cache.DeletedFinalStateUnknown{
473+
Key: nsObj.Name,
474+
Obj: nsObj,
475+
}
476+
477+
f.nsController.deleteNamespace(tombstone)
478+
479+
testCases := []expectedNsValues{
480+
{0, 1, 0},
481+
}
482+
checkNsTestResult("TestDeleteNamespaceWithTombstone", f, testCases)
483+
}
484+
485+
func TestDeleteNamespaceWithTombstoneAfterAddingNameSpace(t *testing.T) {
486+
nsObj := newNameSpace(
487+
"test-namespace",
488+
"0",
489+
map[string]string{
490+
"app": "test-namespace",
491+
},
492+
)
493+
494+
f := newNsFixture(t)
495+
f.nsLister = append(f.nsLister, nsObj)
496+
f.kubeobjects = append(f.kubeobjects, nsObj)
497+
stopCh := make(chan struct{})
498+
defer close(stopCh)
499+
f.newNsController(stopCh)
500+
501+
deleteNamespace(t, f, nsObj, DeletedFinalStateUnknownObject)
502+
testCases := []expectedNsValues{
503+
{0, 1, 0},
504+
}
505+
checkNsTestResult("TestDeleteNamespaceWithTombstoneAfterAddingNameSpace", f, testCases)
506+
}
507+
447508
func TestGetNamespaceObjFromNsObj(t *testing.T) {
448509
ns, _ := newNs("test-ns")
449510
ns.LabelsMap = map[string]string{
@@ -471,7 +532,7 @@ func checkNsTestResult(testName string, f *nameSpaceFixture, testCases []expecte
471532
f.t.Errorf("PodMap length = %d, want %d. Map: %+v", got, test.expectedLenOfPodMap, f.npMgr.PodMap)
472533
}
473534
if got := len(f.npMgr.NsMap); got != test.expectedLenOfNsMap {
474-
f.t.Errorf("npMgr length = %d, want %d. Map: %+v", got, test.expectedLenOfNsMap, f.npMgr.NsMap)
535+
f.t.Errorf("NsMap length = %d, want %d. Map: %+v", got, test.expectedLenOfNsMap, f.npMgr.NsMap)
475536
}
476537
if got := f.nsController.workqueue.Len(); got != test.expectedLenOfWorkQueue {
477538
f.t.Errorf("Workqueue length = %d, want %d", got, test.expectedLenOfWorkQueue)

npm/networkPolicyController.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ func (c *networkPolicyController) updateNetworkPolicy(old, new interface{}) {
122122
}
123123

124124
func (c *networkPolicyController) deleteNetworkPolicy(obj interface{}) {
125-
_, ok := obj.(*networkingv1.NetworkPolicy)
125+
netPolObj, ok := obj.(*networkingv1.NetworkPolicy)
126126
// DeleteFunc gets the final state of the resource (if it is known).
127127
// Otherwise, it gets an object of type DeletedFinalStateUnknown.
128128
// This can happen if the watch is closed and misses the delete event and
@@ -135,7 +135,7 @@ func (c *networkPolicyController) deleteNetworkPolicy(obj interface{}) {
135135
return
136136
}
137137

138-
if _, ok = tombstone.Obj.(*networkingv1.NetworkPolicy); !ok {
138+
if netPolObj, ok = tombstone.Obj.(*networkingv1.NetworkPolicy); !ok {
139139
metrics.SendErrorLogAndMetric(util.NetpolID, "[NETPOL DELETE EVENT] Received unexpected object type (error decoding object tombstone, invalid type): %v", obj)
140140
utilruntime.HandleError(fmt.Errorf("error decoding object tombstone, invalid type"))
141141
return
@@ -144,7 +144,7 @@ func (c *networkPolicyController) deleteNetworkPolicy(obj interface{}) {
144144

145145
var netPolkey string
146146
var err error
147-
if netPolkey, err = cache.MetaNamespaceKeyFunc(obj); err != nil {
147+
if netPolkey, err = cache.MetaNamespaceKeyFunc(netPolObj); err != nil {
148148
utilruntime.HandleError(err)
149149
return
150150
}

npm/networkPolicyController_test.go

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
kubeinformers "k8s.io/client-go/informers"
2121
k8sfake "k8s.io/client-go/kubernetes/fake"
2222
core "k8s.io/client-go/testing"
23+
"k8s.io/client-go/tools/cache"
2324
)
2425

2526
type netPolFixture struct {
@@ -165,13 +166,22 @@ func addNetPol(t *testing.T, f *netPolFixture, netPolObj *networkingv1.NetworkPo
165166
f.netPolController.processNextWorkItem()
166167
}
167168

168-
func deleteNetPol(t *testing.T, f *netPolFixture, netPolObj *networkingv1.NetworkPolicy) {
169+
func deleteNetPol(t *testing.T, f *netPolFixture, netPolObj *networkingv1.NetworkPolicy, isDeletedFinalStateUnknownObject IsDeletedFinalStateUnknownObject) {
169170
addNetPol(t, f, netPolObj)
170171
t.Logf("Complete adding network policy event")
171172

172173
// simulate network policy deletion event and delete network policy object from sharedInformer cache
173174
f.kubeInformer.Networking().V1().NetworkPolicies().Informer().GetIndexer().Delete(netPolObj)
174-
f.netPolController.deleteNetworkPolicy(netPolObj)
175+
if isDeletedFinalStateUnknownObject {
176+
netPolKey := getKey(netPolObj, t)
177+
tombstone := cache.DeletedFinalStateUnknown{
178+
Key: netPolKey,
179+
Obj: netPolObj,
180+
}
181+
f.netPolController.deleteNetworkPolicy(tombstone)
182+
} else {
183+
f.netPolController.deleteNetworkPolicy(netPolObj)
184+
}
175185

176186
if f.netPolController.workqueue.Len() == 0 {
177187
f.isEnqueueEventIntoWorkQueue = false
@@ -305,13 +315,54 @@ func TestDeleteNetworkPolicy(t *testing.T) {
305315
defer close(stopCh)
306316
f.newNetPolController(stopCh)
307317

308-
deleteNetPol(t, f, netPolObj)
318+
deleteNetPol(t, f, netPolObj, DeletedFinalStateknownObject)
309319
testCases := []expectedNetPolValues{
310320
{1, 0, 0, false, true, 0, nil, 1, nil},
311321
}
312322
checkNetPolTestResult("TestDelNetPol", f, testCases)
313323
}
314324

325+
func TestDeleteNetworkPolicyWithTombstone(t *testing.T) {
326+
netPolObj := createNetPol()
327+
328+
f := newNetPolFixture(t)
329+
f.isEnqueueEventIntoWorkQueue = false
330+
f.netPolLister = append(f.netPolLister, netPolObj)
331+
f.kubeobjects = append(f.kubeobjects, netPolObj)
332+
stopCh := make(chan struct{})
333+
defer close(stopCh)
334+
f.newNetPolController(stopCh)
335+
336+
netPolKey := getKey(netPolObj, t)
337+
tombstone := cache.DeletedFinalStateUnknown{
338+
Key: netPolKey,
339+
Obj: netPolObj,
340+
}
341+
342+
f.netPolController.deleteNetworkPolicy(tombstone)
343+
testCases := []expectedNetPolValues{
344+
{1, 0, 0, false, false, 0, nil, 0, nil},
345+
}
346+
checkNetPolTestResult("TestDeleteNetworkPolicyWithTombstone", f, testCases)
347+
}
348+
349+
func TestDeleteNetworkPolicyWithTombstoneAfterAddingNetworkPolicy(t *testing.T) {
350+
netPolObj := createNetPol()
351+
352+
f := newNetPolFixture(t)
353+
f.netPolLister = append(f.netPolLister, netPolObj)
354+
f.kubeobjects = append(f.kubeobjects, netPolObj)
355+
stopCh := make(chan struct{})
356+
defer close(stopCh)
357+
f.newNetPolController(stopCh)
358+
359+
deleteNetPol(t, f, netPolObj, DeletedFinalStateUnknownObject)
360+
testCases := []expectedNetPolValues{
361+
{1, 0, 0, false, true, 0, nil, 1, nil},
362+
}
363+
checkNetPolTestResult("TestDeleteNetworkPolicyWithTombstoneAfterAddingNetworkPolicy", f, testCases)
364+
}
365+
315366
// this unit test is for the case where states of network policy are changed, but network policy controller does not need to reconcile.
316367
// Check it with expectedEnqueueEventIntoWorkQueue variable.
317368
func TestUpdateNetworkPolicy(t *testing.T) {

npm/npm_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,26 @@ import (
88
"github.com/Azure/azure-container-networking/npm/iptm"
99
"github.com/Azure/azure-container-networking/npm/metrics"
1010
"github.com/Azure/azure-container-networking/npm/util"
11+
"k8s.io/client-go/tools/cache"
1112
)
1213

14+
// To indicate the object is needed to be DeletedFinalStateUnknown Object
15+
type IsDeletedFinalStateUnknownObject bool
16+
17+
const (
18+
DeletedFinalStateUnknownObject IsDeletedFinalStateUnknownObject = true
19+
DeletedFinalStateknownObject IsDeletedFinalStateUnknownObject = false
20+
)
21+
22+
func getKey(obj interface{}, t *testing.T) string {
23+
key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
24+
if err != nil {
25+
t.Errorf("Unexpected error getting key for obj %v: %v", obj, err)
26+
return ""
27+
}
28+
return key
29+
}
30+
1331
func newNPMgr(t *testing.T) *NetworkPolicyManager {
1432
npMgr := &NetworkPolicyManager{
1533
NsMap: make(map[string]*Namespace),

npm/podController.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ func (c *podController) deletePod(obj interface{}) {
245245

246246
var err error
247247
var key string
248-
if key, err = cache.MetaNamespaceKeyFunc(obj); err != nil {
248+
if key, err = cache.MetaNamespaceKeyFunc(podObj); err != nil {
249249
utilruntime.HandleError(err)
250250
metrics.SendErrorLogAndMetric(util.PodID, "[POD DELETE EVENT] Error: podKey is empty for %s pod in %s with UID %s",
251251
podObj.ObjectMeta.Name, util.GetNSNameWithPrefix(podObj.Namespace), podObj.UID)

0 commit comments

Comments
 (0)