k8s.io/kubernetes@v1.29.3/pkg/kubelet/util/manager/cache_based_manager_test.go (about) 1 /* 2 Copyright 2018 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package manager 18 19 import ( 20 "context" 21 "fmt" 22 "reflect" 23 "strings" 24 "sync" 25 "testing" 26 "time" 27 28 v1 "k8s.io/api/core/v1" 29 30 apierrors "k8s.io/apimachinery/pkg/api/errors" 31 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 32 "k8s.io/apimachinery/pkg/runtime" 33 "k8s.io/apimachinery/pkg/types" 34 "k8s.io/apimachinery/pkg/util/sets" 35 36 clientset "k8s.io/client-go/kubernetes" 37 "k8s.io/client-go/kubernetes/fake" 38 core "k8s.io/client-go/testing" 39 podutil "k8s.io/kubernetes/pkg/api/v1/pod" 40 "k8s.io/utils/clock" 41 testingclock "k8s.io/utils/clock/testing" 42 43 "github.com/stretchr/testify/assert" 44 ) 45 46 func checkObject(t *testing.T, store *objectStore, ns, name string, shouldExist bool) { 47 _, err := store.Get(ns, name) 48 if shouldExist && err != nil { 49 t.Errorf("unexpected actions: %#v", err) 50 } 51 if !shouldExist && (err == nil || !strings.Contains(err.Error(), fmt.Sprintf("object %q/%q not registered", ns, name))) { 52 t.Errorf("unexpected actions: %#v", err) 53 } 54 } 55 56 func noObjectTTL() (time.Duration, bool) { 57 return time.Duration(0), false 58 } 59 60 func getSecret(fakeClient clientset.Interface) GetObjectFunc { 61 return func(namespace, name string, opts metav1.GetOptions) (runtime.Object, error) { 62 return fakeClient.CoreV1().Secrets(namespace).Get(context.TODO(), name, opts) 63 } 64 } 65 66 func newSecretStore(fakeClient clientset.Interface, clock clock.Clock, getTTL GetObjectTTLFunc, ttl time.Duration) *objectStore { 67 return &objectStore{ 68 getObject: getSecret(fakeClient), 69 clock: clock, 70 items: make(map[objectKey]*objectStoreItem), 71 defaultTTL: ttl, 72 getTTL: getTTL, 73 } 74 } 75 76 func getSecretNames(pod *v1.Pod) sets.String { 77 result := sets.NewString() 78 podutil.VisitPodSecretNames(pod, func(name string) bool { 79 result.Insert(name) 80 return true 81 }) 82 return result 83 } 84 85 func newCacheBasedSecretManager(store Store) Manager { 86 return NewCacheBasedManager(store, getSecretNames) 87 } 88 89 func TestSecretStore(t *testing.T) { 90 fakeClient := &fake.Clientset{} 91 store := newSecretStore(fakeClient, clock.RealClock{}, noObjectTTL, 0) 92 store.AddReference("ns1", "name1", "pod1") 93 store.AddReference("ns2", "name2", "pod2") 94 store.AddReference("ns1", "name1", "pod3") 95 store.AddReference("ns1", "name1", "pod4") 96 store.DeleteReference("ns1", "name1", "pod1") 97 store.DeleteReference("ns2", "name2", "pod2") 98 store.AddReference("ns3", "name3", "pod5") 99 100 // Adds don't issue Get requests. 101 actions := fakeClient.Actions() 102 assert.Equal(t, 0, len(actions), "unexpected actions: %#v", actions) 103 // Should issue Get request 104 store.Get("ns1", "name1") 105 // Shouldn't issue Get request, as secret is not registered 106 store.Get("ns2", "name2") 107 // Should issue Get request 108 store.Get("ns3", "name3") 109 110 actions = fakeClient.Actions() 111 assert.Equal(t, 2, len(actions), "unexpected actions: %#v", actions) 112 113 for _, a := range actions { 114 assert.True(t, a.Matches("get", "secrets"), "unexpected actions: %#v", a) 115 } 116 117 checkObject(t, store, "ns1", "name1", true) 118 checkObject(t, store, "ns2", "name2", false) 119 checkObject(t, store, "ns3", "name3", true) 120 checkObject(t, store, "ns4", "name4", false) 121 } 122 123 func TestSecretStoreDeletingSecret(t *testing.T) { 124 fakeClient := &fake.Clientset{} 125 store := newSecretStore(fakeClient, clock.RealClock{}, noObjectTTL, 0) 126 store.AddReference("ns", "name", "pod") 127 128 result := &v1.Secret{ObjectMeta: metav1.ObjectMeta{Namespace: "ns", Name: "name", ResourceVersion: "10"}} 129 fakeClient.AddReactor("get", "secrets", func(action core.Action) (bool, runtime.Object, error) { 130 return true, result, nil 131 }) 132 secret, err := store.Get("ns", "name") 133 if err != nil { 134 t.Errorf("Unexpected error: %v", err) 135 } 136 if !reflect.DeepEqual(secret, result) { 137 t.Errorf("Unexpected secret: %v", secret) 138 } 139 140 fakeClient.PrependReactor("get", "secrets", func(action core.Action) (bool, runtime.Object, error) { 141 return true, &v1.Secret{}, apierrors.NewNotFound(v1.Resource("secret"), "name") 142 }) 143 secret, err = store.Get("ns", "name") 144 if err == nil || !apierrors.IsNotFound(err) { 145 t.Errorf("Unexpected error: %v", err) 146 } 147 if !reflect.DeepEqual(secret, &v1.Secret{}) { 148 t.Errorf("Unexpected secret: %v", secret) 149 } 150 } 151 152 func TestSecretStoreGetAlwaysRefresh(t *testing.T) { 153 fakeClient := &fake.Clientset{} 154 fakeClock := testingclock.NewFakeClock(time.Now()) 155 store := newSecretStore(fakeClient, fakeClock, noObjectTTL, 0) 156 157 for i := 0; i < 10; i++ { 158 store.AddReference(fmt.Sprintf("ns-%d", i), fmt.Sprintf("name-%d", i), types.UID(fmt.Sprintf("pod-%d", i))) 159 } 160 fakeClient.ClearActions() 161 162 wg := sync.WaitGroup{} 163 wg.Add(100) 164 for i := 0; i < 100; i++ { 165 go func(i int) { 166 store.Get(fmt.Sprintf("ns-%d", i%10), fmt.Sprintf("name-%d", i%10)) 167 wg.Done() 168 }(i) 169 } 170 wg.Wait() 171 actions := fakeClient.Actions() 172 assert.Equal(t, 100, len(actions), "unexpected actions: %#v", actions) 173 174 for _, a := range actions { 175 assert.True(t, a.Matches("get", "secrets"), "unexpected actions: %#v", a) 176 } 177 } 178 179 func TestSecretStoreGetNeverRefresh(t *testing.T) { 180 fakeClient := &fake.Clientset{} 181 fakeClock := testingclock.NewFakeClock(time.Now()) 182 store := newSecretStore(fakeClient, fakeClock, noObjectTTL, time.Minute) 183 184 for i := 0; i < 10; i++ { 185 store.AddReference(fmt.Sprintf("ns-%d", i), fmt.Sprintf("name-%d", i), types.UID(fmt.Sprintf("pod-%d", i))) 186 } 187 fakeClient.ClearActions() 188 189 wg := sync.WaitGroup{} 190 wg.Add(100) 191 for i := 0; i < 100; i++ { 192 go func(i int) { 193 store.Get(fmt.Sprintf("ns-%d", i%10), fmt.Sprintf("name-%d", i%10)) 194 wg.Done() 195 }(i) 196 } 197 wg.Wait() 198 actions := fakeClient.Actions() 199 // Only first Get, should forward the Get request. 200 assert.Equal(t, 10, len(actions), "unexpected actions: %#v", actions) 201 } 202 203 func TestCustomTTL(t *testing.T) { 204 ttl := time.Duration(0) 205 ttlExists := false 206 customTTL := func() (time.Duration, bool) { 207 return ttl, ttlExists 208 } 209 210 fakeClient := &fake.Clientset{} 211 fakeClock := testingclock.NewFakeClock(time.Time{}) 212 store := newSecretStore(fakeClient, fakeClock, customTTL, time.Minute) 213 214 store.AddReference("ns", "name", "pod") 215 store.Get("ns", "name") 216 fakeClient.ClearActions() 217 218 // Set 0-ttl and see if that works. 219 ttl = time.Duration(0) 220 ttlExists = true 221 store.Get("ns", "name") 222 actions := fakeClient.Actions() 223 assert.Equal(t, 1, len(actions), "unexpected actions: %#v", actions) 224 fakeClient.ClearActions() 225 226 // Set 5-minute ttl and see if this works. 227 ttl = time.Duration(5) * time.Minute 228 store.Get("ns", "name") 229 actions = fakeClient.Actions() 230 assert.Equal(t, 0, len(actions), "unexpected actions: %#v", actions) 231 // Still no effect after 4 minutes. 232 fakeClock.Step(4 * time.Minute) 233 store.Get("ns", "name") 234 actions = fakeClient.Actions() 235 assert.Equal(t, 0, len(actions), "unexpected actions: %#v", actions) 236 // Now it should have an effect. 237 fakeClock.Step(time.Minute) 238 store.Get("ns", "name") 239 actions = fakeClient.Actions() 240 assert.Equal(t, 1, len(actions), "unexpected actions: %#v", actions) 241 fakeClient.ClearActions() 242 243 // Now remove the custom ttl and see if that works. 244 ttlExists = false 245 fakeClock.Step(55 * time.Second) 246 store.Get("ns", "name") 247 actions = fakeClient.Actions() 248 assert.Equal(t, 0, len(actions), "unexpected actions: %#v", actions) 249 // Pass the minute and it should be triggered now. 250 fakeClock.Step(5 * time.Second) 251 store.Get("ns", "name") 252 actions = fakeClient.Actions() 253 assert.Equal(t, 1, len(actions), "unexpected actions: %#v", actions) 254 } 255 256 func TestParseNodeAnnotation(t *testing.T) { 257 testCases := []struct { 258 node *v1.Node 259 err error 260 exists bool 261 ttl time.Duration 262 }{ 263 { 264 node: nil, 265 err: fmt.Errorf("error"), 266 exists: false, 267 }, 268 { 269 node: &v1.Node{ 270 ObjectMeta: metav1.ObjectMeta{ 271 Name: "node", 272 }, 273 }, 274 exists: false, 275 }, 276 { 277 node: &v1.Node{ 278 ObjectMeta: metav1.ObjectMeta{ 279 Name: "node", 280 Annotations: map[string]string{}, 281 }, 282 }, 283 exists: false, 284 }, 285 { 286 node: &v1.Node{ 287 ObjectMeta: metav1.ObjectMeta{ 288 Name: "node", 289 Annotations: map[string]string{v1.ObjectTTLAnnotationKey: "bad"}, 290 }, 291 }, 292 exists: false, 293 }, 294 { 295 node: &v1.Node{ 296 ObjectMeta: metav1.ObjectMeta{ 297 Name: "node", 298 Annotations: map[string]string{v1.ObjectTTLAnnotationKey: "0"}, 299 }, 300 }, 301 exists: true, 302 ttl: time.Duration(0), 303 }, 304 { 305 node: &v1.Node{ 306 ObjectMeta: metav1.ObjectMeta{ 307 Name: "node", 308 Annotations: map[string]string{v1.ObjectTTLAnnotationKey: "60"}, 309 }, 310 }, 311 exists: true, 312 ttl: time.Minute, 313 }, 314 } 315 for i, testCase := range testCases { 316 getNode := func() (*v1.Node, error) { return testCase.node, testCase.err } 317 ttl, exists := GetObjectTTLFromNodeFunc(getNode)() 318 if exists != testCase.exists { 319 t.Errorf("%d: incorrect parsing: %t", i, exists) 320 continue 321 } 322 if exists && ttl != testCase.ttl { 323 t.Errorf("%d: incorrect ttl: %v", i, ttl) 324 } 325 } 326 } 327 328 type envSecrets struct { 329 envVarNames []string 330 envFromNames []string 331 } 332 333 type secretsToAttach struct { 334 imagePullSecretNames []string 335 containerEnvSecrets []envSecrets 336 } 337 338 func podWithSecrets(ns, podName string, toAttach secretsToAttach) *v1.Pod { 339 return podWithSecretsAndUID(ns, podName, fmt.Sprintf("%s/%s", ns, podName), toAttach) 340 } 341 342 func podWithSecretsAndUID(ns, podName, podUID string, toAttach secretsToAttach) *v1.Pod { 343 pod := &v1.Pod{ 344 ObjectMeta: metav1.ObjectMeta{ 345 Namespace: ns, 346 Name: podName, 347 UID: types.UID(podUID), 348 }, 349 Spec: v1.PodSpec{}, 350 } 351 for _, name := range toAttach.imagePullSecretNames { 352 pod.Spec.ImagePullSecrets = append( 353 pod.Spec.ImagePullSecrets, v1.LocalObjectReference{Name: name}) 354 } 355 for i, secrets := range toAttach.containerEnvSecrets { 356 container := v1.Container{ 357 Name: fmt.Sprintf("container-%d", i), 358 } 359 for _, name := range secrets.envFromNames { 360 envFrom := v1.EnvFromSource{ 361 SecretRef: &v1.SecretEnvSource{ 362 LocalObjectReference: v1.LocalObjectReference{ 363 Name: name, 364 }, 365 }, 366 } 367 container.EnvFrom = append(container.EnvFrom, envFrom) 368 } 369 370 for _, name := range secrets.envVarNames { 371 envSource := &v1.EnvVarSource{ 372 SecretKeyRef: &v1.SecretKeySelector{ 373 LocalObjectReference: v1.LocalObjectReference{ 374 Name: name, 375 }, 376 }, 377 } 378 container.Env = append(container.Env, v1.EnvVar{ValueFrom: envSource}) 379 } 380 pod.Spec.Containers = append(pod.Spec.Containers, container) 381 } 382 return pod 383 } 384 385 func TestCacheInvalidation(t *testing.T) { 386 fakeClient := &fake.Clientset{} 387 fakeClock := testingclock.NewFakeClock(time.Now()) 388 store := newSecretStore(fakeClient, fakeClock, noObjectTTL, time.Minute) 389 manager := newCacheBasedSecretManager(store) 390 391 // Create a pod with some secrets. 392 s1 := secretsToAttach{ 393 imagePullSecretNames: []string{"s1"}, 394 containerEnvSecrets: []envSecrets{ 395 {envVarNames: []string{"s1"}, envFromNames: []string{"s10"}}, 396 {envVarNames: []string{"s2"}}, 397 }, 398 } 399 manager.RegisterPod(podWithSecrets("ns1", "name1", s1)) 400 // Fetch both secrets - this should trigger get operations. 401 store.Get("ns1", "s1") 402 store.Get("ns1", "s10") 403 store.Get("ns1", "s2") 404 actions := fakeClient.Actions() 405 assert.Equal(t, 3, len(actions), "unexpected actions: %#v", actions) 406 fakeClient.ClearActions() 407 408 // Update a pod with a new secret. 409 s2 := secretsToAttach{ 410 imagePullSecretNames: []string{"s1"}, 411 containerEnvSecrets: []envSecrets{ 412 {envVarNames: []string{"s1"}}, 413 {envVarNames: []string{"s2"}, envFromNames: []string{"s20"}}, 414 {envVarNames: []string{"s3"}}, 415 }, 416 } 417 manager.RegisterPod(podWithSecrets("ns1", "name1", s2)) 418 // Fetch only s3 and s20 secrets - this should trigger get operations. 419 store.Get("ns1", "s1") 420 store.Get("ns1", "s2") 421 store.Get("ns1", "s20") 422 store.Get("ns1", "s3") 423 actions = fakeClient.Actions() 424 assert.Equal(t, 2, len(actions), "unexpected actions: %#v", actions) 425 fakeClient.ClearActions() 426 427 // Create a new pod that is refencing the first three secrets - those should 428 // be invalidated. 429 manager.RegisterPod(podWithSecrets("ns1", "name2", s1)) 430 store.Get("ns1", "s1") 431 store.Get("ns1", "s10") 432 store.Get("ns1", "s2") 433 store.Get("ns1", "s20") 434 store.Get("ns1", "s3") 435 actions = fakeClient.Actions() 436 assert.Equal(t, 3, len(actions), "unexpected actions: %#v", actions) 437 fakeClient.ClearActions() 438 } 439 440 func TestRegisterIdempotence(t *testing.T) { 441 fakeClient := &fake.Clientset{} 442 fakeClock := testingclock.NewFakeClock(time.Now()) 443 store := newSecretStore(fakeClient, fakeClock, noObjectTTL, time.Minute) 444 manager := newCacheBasedSecretManager(store) 445 446 s1 := secretsToAttach{ 447 imagePullSecretNames: []string{"s1"}, 448 } 449 450 refs := func(ns, name string) int { 451 store.lock.Lock() 452 defer store.lock.Unlock() 453 item, ok := store.items[objectKey{namespace: ns, name: name}] 454 if !ok { 455 return 0 456 } 457 return item.refCount 458 } 459 460 manager.RegisterPod(podWithSecrets("ns1", "name1", s1)) 461 assert.Equal(t, 1, refs("ns1", "s1")) 462 manager.RegisterPod(podWithSecrets("ns1", "name1", s1)) 463 assert.Equal(t, 1, refs("ns1", "s1")) 464 manager.RegisterPod(podWithSecrets("ns1", "name2", s1)) 465 assert.Equal(t, 2, refs("ns1", "s1")) 466 467 manager.UnregisterPod(podWithSecrets("ns1", "name1", s1)) 468 assert.Equal(t, 1, refs("ns1", "s1")) 469 manager.UnregisterPod(podWithSecrets("ns1", "name1", s1)) 470 assert.Equal(t, 1, refs("ns1", "s1")) 471 manager.UnregisterPod(podWithSecrets("ns1", "name2", s1)) 472 assert.Equal(t, 0, refs("ns1", "s1")) 473 } 474 475 func TestCacheRefcounts(t *testing.T) { 476 fakeClient := &fake.Clientset{} 477 fakeClock := testingclock.NewFakeClock(time.Now()) 478 store := newSecretStore(fakeClient, fakeClock, noObjectTTL, time.Minute) 479 manager := newCacheBasedSecretManager(store) 480 481 s1 := secretsToAttach{ 482 imagePullSecretNames: []string{"s1"}, 483 containerEnvSecrets: []envSecrets{ 484 {envVarNames: []string{"s1"}, envFromNames: []string{"s10"}}, 485 {envVarNames: []string{"s2"}}, 486 {envVarNames: []string{"s3"}}, 487 }, 488 } 489 manager.RegisterPod(podWithSecrets("ns1", "name1", s1)) 490 manager.RegisterPod(podWithSecrets("ns1", "name2", s1)) 491 s2 := secretsToAttach{ 492 imagePullSecretNames: []string{"s2"}, 493 containerEnvSecrets: []envSecrets{ 494 {envVarNames: []string{"s4"}}, 495 {envVarNames: []string{"s5"}, envFromNames: []string{"s50"}}, 496 }, 497 } 498 manager.RegisterPod(podWithSecrets("ns1", "name2", s2)) 499 manager.RegisterPod(podWithSecrets("ns1", "name3", s2)) 500 manager.RegisterPod(podWithSecrets("ns1", "name4", s2)) 501 manager.UnregisterPod(podWithSecrets("ns1", "name3", s2)) 502 s3 := secretsToAttach{ 503 imagePullSecretNames: []string{"s1"}, 504 containerEnvSecrets: []envSecrets{ 505 {envVarNames: []string{"s3"}, envFromNames: []string{"s30"}}, 506 {envVarNames: []string{"s5"}}, 507 }, 508 } 509 manager.RegisterPod(podWithSecrets("ns1", "name5", s3)) 510 manager.RegisterPod(podWithSecrets("ns1", "name6", s3)) 511 s4 := secretsToAttach{ 512 imagePullSecretNames: []string{"s3"}, 513 containerEnvSecrets: []envSecrets{ 514 {envVarNames: []string{"s6"}}, 515 {envFromNames: []string{"s60"}}, 516 }, 517 } 518 manager.RegisterPod(podWithSecrets("ns1", "name7", s4)) 519 manager.UnregisterPod(podWithSecrets("ns1", "name7", s4)) 520 521 // Also check the Add + Update + Remove scenario. 522 manager.RegisterPod(podWithSecrets("ns1", "other-name", s1)) 523 manager.RegisterPod(podWithSecrets("ns1", "other-name", s2)) 524 manager.UnregisterPod(podWithSecrets("ns1", "other-name", s2)) 525 526 s5 := secretsToAttach{ 527 containerEnvSecrets: []envSecrets{ 528 {envVarNames: []string{"s7"}}, 529 {envFromNames: []string{"s70"}}, 530 }, 531 } 532 // Check the no-op update scenario 533 manager.RegisterPod(podWithSecrets("ns1", "noop-pod", s5)) 534 manager.RegisterPod(podWithSecrets("ns1", "noop-pod", s5)) 535 536 // Now we have: 3 pods with s1, 2 pods with s2 and 2 pods with s3, 0 pods with s4. 537 refs := func(ns, name string) int { 538 store.lock.Lock() 539 defer store.lock.Unlock() 540 item, ok := store.items[objectKey{namespace: ns, name: name}] 541 if !ok { 542 return 0 543 } 544 return item.refCount 545 } 546 assert.Equal(t, 3, refs("ns1", "s1")) 547 assert.Equal(t, 1, refs("ns1", "s10")) 548 assert.Equal(t, 3, refs("ns1", "s2")) 549 assert.Equal(t, 3, refs("ns1", "s3")) 550 assert.Equal(t, 2, refs("ns1", "s30")) 551 assert.Equal(t, 2, refs("ns1", "s4")) 552 assert.Equal(t, 4, refs("ns1", "s5")) 553 assert.Equal(t, 2, refs("ns1", "s50")) 554 assert.Equal(t, 0, refs("ns1", "s6")) 555 assert.Equal(t, 0, refs("ns1", "s60")) 556 assert.Equal(t, 1, refs("ns1", "s7")) 557 assert.Equal(t, 1, refs("ns1", "s70")) 558 559 // Check the interleaved registerpod/unregisterpod with identical names and different uids scenario 560 secret1 := secretsToAttach{ 561 containerEnvSecrets: []envSecrets{ 562 {envVarNames: []string{"secret1"}}, 563 }, 564 } 565 secret2 := secretsToAttach{ 566 containerEnvSecrets: []envSecrets{ 567 {envVarNames: []string{"secret2"}}, 568 }, 569 } 570 571 // precondition: no references 572 assert.Equal(t, 0, refs("nsinterleaved", "secret1")) 573 assert.Equal(t, 0, refs("nsinterleaved", "secret2")) 574 575 // add first pod that references secret1 only 576 manager.RegisterPod(podWithSecretsAndUID("nsinterleaved", "pod", "poduid1", secret1)) 577 assert.Equal(t, 1, refs("nsinterleaved", "secret1")) 578 assert.Equal(t, 0, refs("nsinterleaved", "secret2")) 579 580 // add second pod that references secret2 only, retain references to secret1 581 manager.RegisterPod(podWithSecretsAndUID("nsinterleaved", "pod", "poduid2", secret2)) 582 assert.Equal(t, 1, refs("nsinterleaved", "secret1")) 583 assert.Equal(t, 1, refs("nsinterleaved", "secret2")) 584 585 // remove first pod that references secret1, retain references to secret2 586 manager.UnregisterPod(podWithSecretsAndUID("nsinterleaved", "pod", "poduid1", secretsToAttach{})) 587 assert.Equal(t, 0, refs("nsinterleaved", "secret1")) 588 assert.Equal(t, 1, refs("nsinterleaved", "secret2")) 589 590 // remove second pod that references secret2 591 manager.UnregisterPod(podWithSecretsAndUID("nsinterleaved", "pod", "poduid2", secretsToAttach{})) 592 assert.Equal(t, 0, refs("nsinterleaved", "secret1")) 593 assert.Equal(t, 0, refs("nsinterleaved", "secret2")) 594 } 595 596 func TestCacheBasedSecretManager(t *testing.T) { 597 fakeClient := &fake.Clientset{} 598 store := newSecretStore(fakeClient, clock.RealClock{}, noObjectTTL, 0) 599 manager := newCacheBasedSecretManager(store) 600 601 // Create a pod with some secrets. 602 s1 := secretsToAttach{ 603 imagePullSecretNames: []string{"s1"}, 604 containerEnvSecrets: []envSecrets{ 605 {envVarNames: []string{"s1"}}, 606 {envVarNames: []string{"s2"}}, 607 {envFromNames: []string{"s20"}}, 608 }, 609 } 610 manager.RegisterPod(podWithSecrets("ns1", "name1", s1)) 611 // Update the pod with a different secrets. 612 s2 := secretsToAttach{ 613 imagePullSecretNames: []string{"s1"}, 614 containerEnvSecrets: []envSecrets{ 615 {envVarNames: []string{"s3"}}, 616 {envVarNames: []string{"s4"}}, 617 {envFromNames: []string{"s40"}}, 618 }, 619 } 620 manager.RegisterPod(podWithSecrets("ns1", "name1", s2)) 621 // Create another pod, but with same secrets in different namespace. 622 manager.RegisterPod(podWithSecrets("ns2", "name2", s2)) 623 // Create and delete a pod with some other secrets. 624 s3 := secretsToAttach{ 625 imagePullSecretNames: []string{"s5"}, 626 containerEnvSecrets: []envSecrets{ 627 {envVarNames: []string{"s6"}}, 628 {envFromNames: []string{"s60"}}, 629 }, 630 } 631 manager.RegisterPod(podWithSecrets("ns3", "name", s3)) 632 manager.UnregisterPod(podWithSecrets("ns3", "name", s3)) 633 634 // We should have only: s1, s3 and s4 secrets in namespaces: ns1 and ns2. 635 for _, ns := range []string{"ns1", "ns2", "ns3"} { 636 for _, secret := range []string{"s1", "s2", "s3", "s4", "s5", "s6", "s20", "s40", "s50"} { 637 shouldExist := 638 (secret == "s1" || secret == "s3" || secret == "s4" || secret == "s40") && (ns == "ns1" || ns == "ns2") 639 checkObject(t, store, ns, secret, shouldExist) 640 } 641 } 642 }