...

Source file src/k8s.io/kubernetes/pkg/kubelet/util/manager/cache_based_manager_test.go

Documentation: k8s.io/kubernetes/pkg/kubelet/util/manager

     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  }
   643  

View as plain text