Skip to content

Commit 599ea8f

Browse files
authored
[NPM] Supporting Namespace label updates (#773)
* Supporting Namespace label updates * first pass at saving NS labels in nsmap * Strengthing testcases
1 parent 899c3a3 commit 599ea8f

File tree

3 files changed

+239
-8
lines changed

3 files changed

+239
-8
lines changed

npm/namespace.go

Lines changed: 77 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717

1818
type namespace struct {
1919
name string
20+
labelsMap map[string]string
2021
setMap map[string]string
2122
podMap map[types.UID]*corev1.Pod
2223
rawNpMap map[string]*networkingv1.NetworkPolicy
@@ -29,6 +30,7 @@ type namespace struct {
2930
func newNs(name string) (*namespace, error) {
3031
ns := &namespace{
3132
name: name,
33+
labelsMap: make(map[string]string),
3234
setMap: make(map[string]string),
3335
podMap: make(map[types.UID]*corev1.Pod),
3436
rawNpMap: make(map[string]*networkingv1.NetworkPolicy),
@@ -138,6 +140,9 @@ func (npMgr *NetworkPolicyManager) AddNamespace(nsObj *corev1.Namespace) error {
138140
if err != nil {
139141
log.Errorf("Error: failed to create namespace %s", nsName)
140142
}
143+
144+
// Append all labels to the cache NS obj
145+
ns.labelsMap = util.AppendMap(ns.labelsMap, nsLabel)
141146
npMgr.nsMap[nsName] = ns
142147

143148
return nil
@@ -157,16 +162,84 @@ func (npMgr *NetworkPolicyManager) UpdateNamespace(oldNsObj *corev1.Namespace, n
157162
oldNsNs, oldNsLabel, newNsNs, newNsLabel,
158163
)
159164

160-
if err = npMgr.DeleteNamespace(oldNsObj); err != nil {
161-
return err
165+
if oldNsNs != newNsNs {
166+
if err = npMgr.DeleteNamespace(oldNsObj); err != nil {
167+
return err
168+
}
169+
170+
if newNsObj.ObjectMeta.DeletionTimestamp == nil && newNsObj.ObjectMeta.DeletionGracePeriodSeconds == nil {
171+
if err = npMgr.AddNamespace(newNsObj); err != nil {
172+
return err
173+
}
174+
}
175+
176+
return nil
177+
}
178+
179+
// If orignal AddNamespace failed for some reason, then NS will not be found
180+
// in nsMap, resulting in retry of ADD.
181+
curNsObj, exists := npMgr.nsMap[newNsNs]
182+
if !exists {
183+
if newNsObj.ObjectMeta.DeletionTimestamp == nil && newNsObj.ObjectMeta.DeletionGracePeriodSeconds == nil {
184+
if err = npMgr.AddNamespace(newNsObj); err != nil {
185+
return err
186+
}
187+
}
188+
189+
return nil
190+
}
191+
192+
//if no change in labels then return
193+
if reflect.DeepEqual(curNsObj.labelsMap, newNsLabel) {
194+
log.Logf(
195+
"NAMESPACE UPDATING:\n nothing to delete or add. old namespace: [%s/%v]\n cache namespace: [%s/%v] new namespace: [%s/%v]",
196+
oldNsNs, oldNsLabel, curNsObj.name, curNsObj.labelsMap, newNsNs, newNsLabel,
197+
)
198+
return nil
199+
}
200+
201+
//If the Namespace is not deleted, delete removed labels and create new labels
202+
toAddNsLabels, toDeleteNsLabels := util.CompareMapDiff(curNsObj.labelsMap, newNsLabel)
203+
204+
// Delete the namespace from its label's ipset list.
205+
ipsMgr := npMgr.nsMap[util.KubeAllNamespacesFlag].ipsMgr
206+
for nsLabelKey, nsLabelVal := range toDeleteNsLabels {
207+
labelKey := "ns-" + nsLabelKey
208+
log.Logf("Deleting namespace %s from ipset list %s", oldNsNs, labelKey)
209+
if err = ipsMgr.DeleteFromList(labelKey, oldNsNs); err != nil {
210+
log.Errorf("Error: failed to delete namespace %s from ipset list %s", oldNsNs, labelKey)
211+
return err
212+
}
213+
214+
label := "ns-" + nsLabelKey + ":" + nsLabelVal
215+
log.Logf("Deleting namespace %s from ipset list %s", oldNsNs, label)
216+
if err = ipsMgr.DeleteFromList(label, oldNsNs); err != nil {
217+
log.Errorf("Error: failed to delete namespace %s from ipset list %s", oldNsNs, label)
218+
return err
219+
}
162220
}
163221

164-
if newNsObj.ObjectMeta.DeletionTimestamp == nil && newNsObj.ObjectMeta.DeletionGracePeriodSeconds == nil {
165-
if err = npMgr.AddNamespace(newNsObj); err != nil {
222+
// Add the namespace to its label's ipset list.
223+
for nsLabelKey, nsLabelVal := range toAddNsLabels {
224+
labelKey := "ns-" + nsLabelKey
225+
log.Logf("Adding namespace %s to ipset list %s", oldNsNs, labelKey)
226+
if err = ipsMgr.AddToList(labelKey, oldNsNs); err != nil {
227+
log.Errorf("Error: failed to add namespace %s to ipset list %s", oldNsNs, labelKey)
228+
return err
229+
}
230+
231+
label := "ns-" + nsLabelKey + ":" + nsLabelVal
232+
log.Logf("Adding namespace %s to ipset list %s", oldNsNs, label)
233+
if err = ipsMgr.AddToList(label, oldNsNs); err != nil {
234+
log.Errorf("Error: failed to add namespace %s to ipset list %s", oldNsNs, label)
166235
return err
167236
}
168237
}
169238

239+
// Append all labels to the cache NS obj
240+
curNsObj.labelsMap = util.ClearAndAppendMap(curNsObj.labelsMap, newNsLabel)
241+
npMgr.nsMap[newNsNs] = curNsObj
242+
170243
return nil
171244
}
172245

npm/namespace_test.go

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package npm
44

55
import (
66
"os"
7+
"reflect"
78
"testing"
89

910
"github.com/Azure/azure-container-networking/npm/iptm"
@@ -135,6 +136,123 @@ func TestUpdateNamespace(t *testing.T) {
135136
npMgr.Unlock()
136137
}
137138

139+
func TestAddNamespaceLabel(t *testing.T) {
140+
npMgr := &NetworkPolicyManager{
141+
nsMap: make(map[string]*namespace),
142+
TelemetryEnabled: false,
143+
}
144+
145+
allNs, err := newNs(util.KubeAllNamespacesFlag)
146+
if err != nil {
147+
t.Fatal(err.Error())
148+
}
149+
npMgr.nsMap[util.KubeAllNamespacesFlag] = allNs
150+
151+
ipsMgr := ipsm.NewIpsetManager()
152+
if err := ipsMgr.Save(util.IpsetTestConfigFile); err != nil {
153+
t.Errorf("TestAddNamespaceLabel failed @ ipsMgr.Save")
154+
}
155+
156+
defer func() {
157+
if err := ipsMgr.Restore(util.IpsetTestConfigFile); err != nil {
158+
t.Errorf("TestAddNamespaceLabel failed @ ipsMgr.Restore")
159+
}
160+
}()
161+
162+
oldNsObj := &corev1.Namespace{
163+
ObjectMeta: metav1.ObjectMeta{
164+
Name: "old-test-namespace",
165+
Labels: map[string]string{
166+
"app": "old-test-namespace",
167+
},
168+
},
169+
}
170+
171+
newNsObj := &corev1.Namespace{
172+
ObjectMeta: metav1.ObjectMeta{
173+
Name: "old-test-namespace",
174+
Labels: map[string]string{
175+
"app": "old-test-namespace",
176+
"update": "true",
177+
},
178+
},
179+
}
180+
181+
npMgr.Lock()
182+
if err := npMgr.AddNamespace(oldNsObj); err != nil {
183+
t.Errorf("TestAddNamespaceLabel failed @ npMgr.AddNamespace")
184+
}
185+
186+
if err := npMgr.UpdateNamespace(oldNsObj, newNsObj); err != nil {
187+
t.Errorf("TestAddNamespaceLabel failed @ npMgr.UpdateNamespace")
188+
}
189+
190+
if !reflect.DeepEqual(npMgr.nsMap["ns-"+newNsObj.Name].labelsMap, newNsObj.ObjectMeta.Labels) {
191+
t.Errorf("TestAddNamespaceLabel failed @ npMgr.nsMap labelMap check")
192+
}
193+
194+
npMgr.Unlock()
195+
}
196+
197+
func TestDeleteandUpdateNamespaceLabel(t *testing.T) {
198+
npMgr := &NetworkPolicyManager{
199+
nsMap: make(map[string]*namespace),
200+
TelemetryEnabled: false,
201+
}
202+
203+
allNs, err := newNs(util.KubeAllNamespacesFlag)
204+
if err != nil {
205+
t.Fatal(err.Error())
206+
}
207+
npMgr.nsMap[util.KubeAllNamespacesFlag] = allNs
208+
209+
ipsMgr := ipsm.NewIpsetManager()
210+
if err := ipsMgr.Save(util.IpsetTestConfigFile); err != nil {
211+
t.Errorf("TestDeleteandUpdateNamespaceLabel failed @ ipsMgr.Save")
212+
}
213+
214+
defer func() {
215+
if err := ipsMgr.Restore(util.IpsetTestConfigFile); err != nil {
216+
t.Errorf("TestDeleteandUpdateNamespaceLabel failed @ ipsMgr.Restore")
217+
}
218+
}()
219+
220+
oldNsObj := &corev1.Namespace{
221+
ObjectMeta: metav1.ObjectMeta{
222+
Name: "old-test-namespace",
223+
Labels: map[string]string{
224+
"app": "old-test-namespace",
225+
"update": "true",
226+
"group": "test",
227+
},
228+
},
229+
}
230+
231+
newNsObj := &corev1.Namespace{
232+
ObjectMeta: metav1.ObjectMeta{
233+
Name: "old-test-namespace",
234+
Labels: map[string]string{
235+
"app": "old-test-namespace",
236+
"update": "false",
237+
},
238+
},
239+
}
240+
241+
npMgr.Lock()
242+
if err := npMgr.AddNamespace(oldNsObj); err != nil {
243+
t.Errorf("TestDeleteandUpdateNamespaceLabel failed @ npMgr.AddNamespace")
244+
}
245+
246+
if err := npMgr.UpdateNamespace(oldNsObj, newNsObj); err != nil {
247+
t.Errorf("TestDeleteandUpdateNamespaceLabel failed @ npMgr.UpdateNamespace")
248+
}
249+
250+
if !reflect.DeepEqual(npMgr.nsMap["ns-"+newNsObj.Name].labelsMap, newNsObj.ObjectMeta.Labels) {
251+
t.Errorf("TestDeleteandUpdateNamespaceLabel failed @ npMgr.nsMap labelMap check")
252+
}
253+
npMgr.Unlock()
254+
}
255+
138256
func TestDeleteNamespace(t *testing.T) {
139257
npMgr := &NetworkPolicyManager{
140258
nsMap: make(map[string]*namespace),
@@ -175,6 +293,10 @@ func TestDeleteNamespace(t *testing.T) {
175293
if err := npMgr.DeleteNamespace(nsObj); err != nil {
176294
t.Errorf("TestDeleteNamespace @ npMgr.DeleteNamespace")
177295
}
296+
297+
if _, exists := npMgr.nsMap["ns-"+nsObj.Name]; exists {
298+
t.Errorf("TestDeleteNamespace failed @ npMgr.nsMap check")
299+
}
178300
npMgr.Unlock()
179301
}
180302

npm/util/util.go

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import (
77
"hash/fnv"
88
"os"
99
"regexp"
10-
"strings"
1110
"sort"
11+
"strings"
1212

1313
"github.com/Masterminds/semver"
1414
"k8s.io/apimachinery/pkg/version"
@@ -69,6 +69,32 @@ func SortMap(m *map[string]string) ([]string, []string) {
6969
return sortedKeys, sortedVals
7070
}
7171

72+
// CompareMapDiff will compare two maps string[string] and returns
73+
// missing values in both
74+
func CompareMapDiff(orig map[string]string, new map[string]string) (map[string]string, map[string]string) {
75+
notInOrig := make(map[string]string)
76+
notInNew := make(map[string]string)
77+
78+
for keyOrig, valOrig := range orig {
79+
if valNew, ok := new[keyOrig]; ok {
80+
if valNew != valOrig {
81+
notInNew[keyOrig] = valOrig
82+
notInOrig[keyOrig] = valNew
83+
}
84+
} else {
85+
notInNew[keyOrig] = valOrig
86+
}
87+
}
88+
89+
for keyNew, valNew := range new {
90+
if _, ok := orig[keyNew]; !ok {
91+
notInOrig[keyNew] = valNew
92+
}
93+
}
94+
95+
return notInOrig, notInNew
96+
}
97+
7298
// UniqueStrSlice removes duplicate elements from the input string.
7399
func UniqueStrSlice(s []string) []string {
74100
m, unique := map[string]bool{}, []string{}
@@ -84,6 +110,16 @@ func UniqueStrSlice(s []string) []string {
84110
return unique
85111
}
86112

113+
// ClearAndAppendMap clears base and appends new to base.
114+
func ClearAndAppendMap(base, new map[string]string) map[string]string {
115+
base = make(map[string]string)
116+
for k, v := range new {
117+
base[k] = v
118+
}
119+
120+
return base
121+
}
122+
87123
// AppendMap appends new to base.
88124
func AppendMap(base, new map[string]string) map[string]string {
89125
for k, v := range new {
@@ -106,15 +142,15 @@ func CompareK8sVer(firstVer *version.Info, secondVer *version.Info) int {
106142
if len(v1Minor) < 1 {
107143
return -2
108144
}
109-
v1, err := semver.NewVersion(firstVer.Major+"."+v1Minor[0])
145+
v1, err := semver.NewVersion(firstVer.Major + "." + v1Minor[0])
110146
if err != nil {
111147
return -2
112148
}
113149
v2Minor := re.FindAllString(secondVer.Minor, -1)
114150
if len(v2Minor) < 1 {
115151
return -2
116152
}
117-
v2, err := semver.NewVersion(secondVer.Major+"."+v2Minor[0])
153+
v2, err := semver.NewVersion(secondVer.Major + "." + v2Minor[0])
118154
if err != nil {
119155
return -2
120156
}
@@ -201,4 +237,4 @@ func DropEmptyFields(s []string) []string {
201237
}
202238

203239
return s
204-
}
240+
}

0 commit comments

Comments
 (0)