cache_based_manager_test.go 18 KB

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