github.com/imran-kn/cilium-fork@v1.6.9/pkg/policy/selectorcache_test.go (about) 1 // Copyright 2019 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // +build !privileged_tests 16 17 package policy 18 19 import ( 20 "github.com/cilium/cilium/pkg/checker" 21 "github.com/cilium/cilium/pkg/identity" 22 "github.com/cilium/cilium/pkg/identity/cache" 23 k8sConst "github.com/cilium/cilium/pkg/k8s/apis/cilium.io" 24 "github.com/cilium/cilium/pkg/labels" 25 "github.com/cilium/cilium/pkg/policy/api" 26 "github.com/cilium/cilium/pkg/testutils" 27 28 . "gopkg.in/check.v1" 29 ) 30 31 type SelectorCacheTestSuite struct{} 32 33 var _ = Suite(&SelectorCacheTestSuite{}) 34 35 type DummySelectorCacheUser struct{} 36 37 func (d *DummySelectorCacheUser) IdentitySelectionUpdated(selector CachedSelector, selections, added, deleted []identity.NumericIdentity) { 38 } 39 40 type cachedSelectionUser struct { 41 c *C 42 sc *SelectorCache 43 name string 44 selections map[CachedSelector][]identity.NumericIdentity 45 notifications int 46 adds int 47 deletes int 48 } 49 50 func newUser(c *C, name string, sc *SelectorCache) *cachedSelectionUser { 51 return &cachedSelectionUser{ 52 c: c, 53 sc: sc, 54 name: name, 55 selections: make(map[CachedSelector][]identity.NumericIdentity), 56 } 57 } 58 59 func haveNid(nid identity.NumericIdentity, selections []identity.NumericIdentity) bool { 60 for i := range selections { 61 if selections[i] == nid { 62 return true 63 } 64 } 65 return false 66 } 67 68 func (csu *cachedSelectionUser) AddIdentitySelector(sel api.EndpointSelector) CachedSelector { 69 notifications := csu.notifications 70 cached, added := csu.sc.AddIdentitySelector(csu, sel) 71 csu.c.Assert(cached, Not(Equals), nil) 72 73 _, exists := csu.selections[cached] 74 // Not added if already exists for this user 75 csu.c.Assert(added, Equals, !exists) 76 csu.selections[cached] = cached.GetSelections() 77 78 // Pre-existing selections are not notified as updates 79 csu.c.Assert(csu.notifications, Equals, notifications) 80 81 return cached 82 } 83 84 func (csu *cachedSelectionUser) AddFQDNSelector(sel api.FQDNSelector) CachedSelector { 85 notifications := csu.notifications 86 cached, added := csu.sc.AddFQDNSelector(csu, sel) 87 csu.c.Assert(cached, Not(Equals), nil) 88 89 _, exists := csu.selections[cached] 90 // Not added if already exists for this user 91 csu.c.Assert(added, Equals, !exists) 92 csu.selections[cached] = cached.GetSelections() 93 94 // Pre-existing selections are not notified as updates 95 csu.c.Assert(csu.notifications, Equals, notifications) 96 97 return cached 98 } 99 100 func (csu *cachedSelectionUser) RemoveSelector(sel CachedSelector) { 101 notifications := csu.notifications 102 csu.sc.RemoveSelector(sel, csu) 103 delete(csu.selections, sel) 104 105 // No notifications for a removed selector 106 csu.c.Assert(csu.notifications, Equals, notifications) 107 } 108 109 func (csu *cachedSelectionUser) IdentitySelectionUpdated(selector CachedSelector, selections, added, deleted []identity.NumericIdentity) { 110 csu.notifications++ 111 csu.adds += len(added) 112 csu.deletes += len(deleted) 113 114 // Validate added & deleted against the selections 115 for _, add := range added { 116 csu.c.Assert(haveNid(add, selections), Equals, true) 117 } 118 for _, del := range deleted { 119 csu.c.Assert(haveNid(del, selections), Equals, false) 120 } 121 122 // update selections 123 csu.selections[selector] = selections 124 } 125 126 func (ds *SelectorCacheTestSuite) SetUpTest(c *C) { 127 } 128 129 func (ds *SelectorCacheTestSuite) TearDownTest(c *C) { 130 } 131 132 func (ds *SelectorCacheTestSuite) TestAddRemoveSelector(c *C) { 133 sc := testNewSelectorCache(cache.IdentityCache{}) 134 135 // Add some identities to the identity cache 136 sc.UpdateIdentities(cache.IdentityCache{ 137 1234: labels.Labels{"app": labels.NewLabel("app", "test", labels.LabelSourceK8s), 138 k8sConst.PodNamespaceLabel: labels.NewLabel(k8sConst.PodNamespaceLabel, "default", labels.LabelSourceK8s)}.LabelArray(), 139 2345: labels.Labels{"app": labels.NewLabel("app", "test2", labels.LabelSourceK8s)}.LabelArray(), 140 }, nil) 141 142 testSelector := api.NewESFromLabels(labels.NewLabel("app", "test", labels.LabelSourceK8s), 143 labels.NewLabel(k8sConst.PodNamespaceLabel, "default", labels.LabelSourceK8s)) 144 145 user1 := newUser(c, "user1", sc) 146 cached := user1.AddIdentitySelector(testSelector) 147 148 // Current selections contain the numeric identities of existing identities that match 149 selections := cached.GetSelections() 150 c.Assert(len(selections), Equals, 1) 151 c.Assert(selections[0], Equals, identity.NumericIdentity(1234)) 152 153 // Try add the same selector from the same user the second time 154 testSelector = api.NewESFromLabels(labels.NewLabel("app", "test", labels.LabelSourceK8s), 155 labels.NewLabel(k8sConst.PodNamespaceLabel, "default", labels.LabelSourceK8s)) 156 cached2 := user1.AddIdentitySelector(testSelector) 157 c.Assert(cached2, Equals, cached) 158 159 // Add the same selector from a different user 160 testSelector = api.NewESFromLabels(labels.NewLabel("app", "test", labels.LabelSourceK8s), 161 labels.NewLabel(k8sConst.PodNamespaceLabel, "default", labels.LabelSourceK8s)) 162 user2 := newUser(c, "user2", sc) 163 cached3 := user2.AddIdentitySelector(testSelector) 164 165 // Same old CachedSelector is returned, nothing new is cached 166 c.Assert(cached3, Equals, cached) 167 168 // Removing the first user does not remove the cached selector 169 user1.RemoveSelector(cached) 170 // Remove is idempotent 171 user1.RemoveSelector(cached) 172 173 // Removing the last user removes the cached selector 174 user2.RemoveSelector(cached3) 175 // Remove is idempotent 176 user2.RemoveSelector(cached3) 177 178 // All identities removed 179 c.Assert(len(sc.selectors), Equals, 0) 180 } 181 182 func (ds *SelectorCacheTestSuite) TestMultipleIdentitySelectors(c *C) { 183 sc := testNewSelectorCache(cache.IdentityCache{}) 184 185 // Add some identities to the identity cache 186 sc.UpdateIdentities(cache.IdentityCache{ 187 1234: labels.Labels{"app": labels.NewLabel("app", "test", labels.LabelSourceK8s)}.LabelArray(), 188 2345: labels.Labels{"app": labels.NewLabel("app", "test2", labels.LabelSourceK8s)}.LabelArray(), 189 }, nil) 190 191 testSelector := api.NewESFromLabels(labels.NewLabel("app", "test", labels.LabelSourceK8s)) 192 test2Selector := api.NewESFromLabels(labels.NewLabel("app", "test2", labels.LabelSourceK8s)) 193 194 user1 := newUser(c, "user1", sc) 195 cached := user1.AddIdentitySelector(testSelector) 196 197 // Current selections contain the numeric identities of existing identities that match 198 selections := cached.GetSelections() 199 c.Assert(len(selections), Equals, 1) 200 c.Assert(selections[0], Equals, identity.NumericIdentity(1234)) 201 202 // Add another selector from the same user 203 cached2 := user1.AddIdentitySelector(test2Selector) 204 c.Assert(cached2, Not(Equals), cached) 205 206 // Current selections contain the numeric identities of existing identities that match 207 selections2 := cached2.GetSelections() 208 c.Assert(len(selections2), Equals, 1) 209 c.Assert(selections2[0], Equals, identity.NumericIdentity(2345)) 210 211 user1.RemoveSelector(cached) 212 user1.RemoveSelector(cached2) 213 214 // All identities removed 215 c.Assert(len(sc.selectors), Equals, 0) 216 } 217 218 func (ds *SelectorCacheTestSuite) TestIdentityUpdates(c *C) { 219 sc := testNewSelectorCache(cache.IdentityCache{}) 220 221 // Add some identities to the identity cache 222 sc.UpdateIdentities(cache.IdentityCache{ 223 1234: labels.Labels{"app": labels.NewLabel("app", "test", labels.LabelSourceK8s)}.LabelArray(), 224 2345: labels.Labels{"app": labels.NewLabel("app", "test2", labels.LabelSourceK8s)}.LabelArray(), 225 }, nil) 226 227 testSelector := api.NewESFromLabels(labels.NewLabel("app", "test", labels.LabelSourceK8s)) 228 test2Selector := api.NewESFromLabels(labels.NewLabel("app", "test2", labels.LabelSourceK8s)) 229 230 user1 := newUser(c, "user1", sc) 231 cached := user1.AddIdentitySelector(testSelector) 232 233 // Current selections contain the numeric identities of existing identities that match 234 selections := cached.GetSelections() 235 c.Assert(len(selections), Equals, 1) 236 c.Assert(selections[0], Equals, identity.NumericIdentity(1234)) 237 238 // Add another selector from the same user 239 cached2 := user1.AddIdentitySelector(test2Selector) 240 c.Assert(cached2, Not(Equals), cached) 241 242 // Current selections contain the numeric identities of existing identities that match 243 selections2 := cached2.GetSelections() 244 c.Assert(len(selections2), Equals, 1) 245 c.Assert(selections2[0], Equals, identity.NumericIdentity(2345)) 246 247 // Add some identities to the identity cache 248 sc.UpdateIdentities(cache.IdentityCache{ 249 12345: labels.Labels{"app": labels.NewLabel("app", "test", labels.LabelSourceK8s)}.LabelArray(), 250 }, nil) 251 c.Assert(user1.adds, Equals, 1) 252 c.Assert(user1.deletes, Equals, 0) 253 254 // Current selections contain the numeric identities of existing identities that match 255 selections = cached.GetSelections() 256 c.Assert(len(selections), Equals, 2) 257 c.Assert(selections[0], Equals, identity.NumericIdentity(1234)) 258 c.Assert(selections[1], Equals, identity.NumericIdentity(12345)) 259 260 // Remove some identities from the identity cache 261 sc.UpdateIdentities(nil, cache.IdentityCache{ 262 12345: labels.Labels{"app": labels.NewLabel("app", "test", labels.LabelSourceK8s)}.LabelArray(), 263 }) 264 c.Assert(user1.adds, Equals, 1) 265 c.Assert(user1.deletes, Equals, 1) 266 267 // Current selections contain the numeric identities of existing identities that match 268 selections = cached.GetSelections() 269 c.Assert(len(selections), Equals, 1) 270 c.Assert(selections[0], Equals, identity.NumericIdentity(1234)) 271 272 user1.RemoveSelector(cached) 273 user1.RemoveSelector(cached2) 274 275 // All identities removed 276 c.Assert(len(sc.selectors), Equals, 0) 277 } 278 279 func (ds *SelectorCacheTestSuite) TestFQDNSelectorUpdates(c *C) { 280 sc := testNewSelectorCache(cache.IdentityCache{}) 281 282 // Add some identities to the identity cache 283 googleSel := api.FQDNSelector{MatchName: "google.com"} 284 ciliumSel := api.FQDNSelector{MatchName: "cilium.io"} 285 286 googleIdentities := []identity.NumericIdentity{321, 456, 987} 287 ciliumIdentities := []identity.NumericIdentity{123, 456, 789} 288 289 sc.UpdateFQDNSelector(ciliumSel, ciliumIdentities) 290 sc.UpdateFQDNSelector(googleSel, googleIdentities) 291 292 _, exists := sc.selectors[ciliumSel.String()] 293 c.Assert(exists, Equals, true) 294 295 user1 := newUser(c, "user1", sc) 296 cached := user1.AddFQDNSelector(ciliumSel) 297 298 selections := cached.GetSelections() 299 c.Assert(len(selections), Equals, 3) 300 for i, selection := range selections { 301 c.Assert(selection, Equals, ciliumIdentities[i]) 302 } 303 304 // Add another selector from the same user 305 cached2 := user1.AddFQDNSelector(googleSel) 306 c.Assert(cached2, Not(Equals), cached) 307 308 // Current selections contain the numeric identities of existing identities that match 309 selections2 := cached2.GetSelections() 310 c.Assert(len(selections2), Equals, 3) 311 for i, selection := range selections2 { 312 c.Assert(selection, Equals, googleIdentities[i]) 313 } 314 315 // Add some identities to the identity cache 316 ciliumIdentities = append(ciliumIdentities, identity.NumericIdentity(123456)) 317 sc.UpdateFQDNSelector(ciliumSel, ciliumIdentities) 318 c.Assert(user1.adds, Equals, 1) 319 c.Assert(user1.deletes, Equals, 0) 320 321 ciliumIdentities = ciliumIdentities[:1] 322 sc.UpdateFQDNSelector(ciliumSel, ciliumIdentities) 323 c.Assert(user1.adds, Equals, 1) 324 c.Assert(user1.deletes, Equals, 3) 325 326 ciliumIdentities = []identity.NumericIdentity{} 327 sc.UpdateFQDNSelector(ciliumSel, ciliumIdentities) 328 c.Assert(user1.deletes, Equals, 4) 329 330 user1.RemoveSelector(cached) 331 user1.RemoveSelector(cached2) 332 333 // All identities removed 334 c.Assert(len(sc.selectors), Equals, 0) 335 336 yahooSel := api.FQDNSelector{MatchName: "yahoo.com"} 337 _, added := sc.AddFQDNSelector(user1, yahooSel) 338 c.Assert(added, Equals, true) 339 } 340 341 func (ds *SelectorCacheTestSuite) TestRemoveIdentitiesFQDNSelectors(c *C) { 342 sc := testNewSelectorCache(cache.IdentityCache{}) 343 344 // Add some identities to the identity cache 345 googleSel := api.FQDNSelector{MatchName: "google.com"} 346 ciliumSel := api.FQDNSelector{MatchName: "cilium.io"} 347 348 googleIdentities := []identity.NumericIdentity{321, 456, 987} 349 ciliumIdentities := []identity.NumericIdentity{123, 456, 789} 350 351 sc.UpdateFQDNSelector(ciliumSel, ciliumIdentities) 352 sc.UpdateFQDNSelector(googleSel, googleIdentities) 353 354 _, exists := sc.selectors[ciliumSel.String()] 355 c.Assert(exists, Equals, true) 356 357 user1 := newUser(c, "user1", sc) 358 cached := user1.AddFQDNSelector(ciliumSel) 359 360 selections := cached.GetSelections() 361 c.Assert(len(selections), Equals, 3) 362 for i, selection := range selections { 363 c.Assert(selection, Equals, ciliumIdentities[i]) 364 } 365 366 // Add another selector from the same user 367 cached2 := user1.AddFQDNSelector(googleSel) 368 c.Assert(cached2, Not(Equals), cached) 369 370 // Current selections contain the numeric identities of existing identities that match 371 selections2 := cached2.GetSelections() 372 c.Assert(len(selections2), Equals, 3) 373 for i, selection := range selections2 { 374 c.Assert(selection, Equals, googleIdentities[i]) 375 } 376 377 sc.RemoveIdentitiesFQDNSelectors([]api.FQDNSelector{ 378 googleSel, 379 ciliumSel, 380 }) 381 382 selections = cached.GetSelections() 383 c.Assert(len(selections), Equals, 0) 384 385 selections2 = cached2.GetSelections() 386 c.Assert(len(selections2), Equals, 0) 387 } 388 389 func (ds *SelectorCacheTestSuite) TestIdentityUpdatesMultipleUsers(c *C) { 390 sc := testNewSelectorCache(cache.IdentityCache{}) 391 392 // Add some identities to the identity cache 393 sc.UpdateIdentities(cache.IdentityCache{ 394 1234: labels.Labels{"app": labels.NewLabel("app", "test", labels.LabelSourceK8s)}.LabelArray(), 395 2345: labels.Labels{"app": labels.NewLabel("app", "test2", labels.LabelSourceK8s)}.LabelArray(), 396 }, nil) 397 398 testSelector := api.NewESFromLabels(labels.NewLabel("app", "test", labels.LabelSourceK8s)) 399 400 user1 := newUser(c, "user1", sc) 401 cached := user1.AddIdentitySelector(testSelector) 402 403 // Add same selector from a different user 404 user2 := newUser(c, "user2", sc) 405 cached2 := user2.AddIdentitySelector(testSelector) 406 c.Assert(cached2, Equals, cached) 407 408 // Add some identities to the identity cache 409 sc.UpdateIdentities(cache.IdentityCache{ 410 123: labels.Labels{"app": labels.NewLabel("app", "test", labels.LabelSourceK8s)}.LabelArray(), 411 234: labels.Labels{"app": labels.NewLabel("app", "test2", labels.LabelSourceK8s)}.LabelArray(), 412 345: labels.Labels{"app": labels.NewLabel("app", "test", labels.LabelSourceK8s)}.LabelArray(), 413 }, nil) 414 c.Assert(user1.adds, Equals, 2) 415 c.Assert(user1.deletes, Equals, 0) 416 c.Assert(user2.adds, Equals, 2) 417 c.Assert(user2.deletes, Equals, 0) 418 419 // Current selections contain the numeric identities of existing identities that match 420 selections := cached.GetSelections() 421 c.Assert(len(selections), Equals, 3) 422 c.Assert(selections[0], Equals, identity.NumericIdentity(123)) 423 c.Assert(selections[1], Equals, identity.NumericIdentity(345)) 424 c.Assert(selections[2], Equals, identity.NumericIdentity(1234)) 425 426 c.Assert(cached.GetSelections(), checker.DeepEquals, cached2.GetSelections()) 427 428 // Remove some identities from the identity cache 429 sc.UpdateIdentities(nil, cache.IdentityCache{ 430 123: labels.Labels{"app": labels.NewLabel("app", "test", labels.LabelSourceK8s)}.LabelArray(), 431 234: labels.Labels{"app": labels.NewLabel("app", "test2", labels.LabelSourceK8s)}.LabelArray(), 432 }) 433 c.Assert(user1.adds, Equals, 2) 434 c.Assert(user1.deletes, Equals, 1) 435 c.Assert(user2.adds, Equals, 2) 436 c.Assert(user2.deletes, Equals, 1) 437 438 // Current selections contain the numeric identities of existing identities that match 439 selections = cached.GetSelections() 440 c.Assert(len(selections), Equals, 2) 441 c.Assert(selections[0], Equals, identity.NumericIdentity(345)) 442 c.Assert(selections[1], Equals, identity.NumericIdentity(1234)) 443 444 c.Assert(cached.GetSelections(), checker.DeepEquals, cached2.GetSelections()) 445 446 user1.RemoveSelector(cached) 447 user2.RemoveSelector(cached2) 448 449 // All identities removed 450 c.Assert(len(sc.selectors), Equals, 0) 451 } 452 453 func (ds *SelectorCacheTestSuite) TestIdentityNotifier(c *C) { 454 sc := testNewSelectorCache(cache.IdentityCache{}) 455 idNotifier, ok := sc.localIdentityNotifier.(*testutils.DummyIdentityNotifier) 456 c.Assert(ok, Equals, true) 457 c.Assert(idNotifier, Not(IsNil)) 458 459 // Add some identities to the identity cache 460 googleSel := api.FQDNSelector{MatchName: "google.com"} 461 ciliumSel := api.FQDNSelector{MatchName: "cilium.io"} 462 463 // Nothing should be registered yet. 464 c.Assert(idNotifier.IsRegistered(ciliumSel), Equals, false) 465 c.Assert(idNotifier.IsRegistered(googleSel), Equals, false) 466 467 injectedIDs := []identity.NumericIdentity{1000, 1001, 1002} 468 idNotifier.InjectIdentitiesForSelector(ciliumSel, injectedIDs) 469 470 // Add a user without adding identities explicitly. The identityNotifier 471 // should have populated them for us. 472 user1 := newUser(c, "user1", sc) 473 cached := user1.AddFQDNSelector(ciliumSel) 474 _, exists := sc.selectors[ciliumSel.String()] 475 c.Assert(exists, Equals, true) 476 477 selections := cached.GetSelections() 478 c.Assert(len(selections), Equals, 3) 479 for i, selection := range selections { 480 c.Assert(selection, Equals, injectedIDs[i]) 481 } 482 483 // Add another selector from the same user 484 cached2 := user1.AddFQDNSelector(googleSel) 485 c.Assert(cached2, Not(Equals), cached) 486 487 selections2 := cached2.GetSelections() 488 c.Assert(len(selections2), Equals, 0) 489 490 sc.RemoveIdentitiesFQDNSelectors([]api.FQDNSelector{ 491 googleSel, 492 ciliumSel, 493 }) 494 495 selections = cached.GetSelections() 496 c.Assert(len(selections), Equals, 0) 497 498 selections2 = cached2.GetSelections() 499 c.Assert(len(selections2), Equals, 0) 500 501 sc.RemoveSelector(cached, user1) 502 c.Assert(idNotifier.IsRegistered(ciliumSel), Equals, false) 503 c.Assert(idNotifier.IsRegistered(googleSel), Equals, true) 504 505 sc.RemoveSelector(cached2, user1) 506 c.Assert(idNotifier.IsRegistered(googleSel), Equals, false) 507 508 } 509 510 func testNewSelectorCache(ids cache.IdentityCache) *SelectorCache { 511 sc := NewSelectorCache(ids) 512 sc.SetLocalIdentityNotifier(testutils.NewDummyIdentityNotifier()) 513 return sc 514 }