...

Source file src/k8s.io/kubernetes/pkg/controller/serviceaccount/serviceaccounts_controller_test.go

Documentation: k8s.io/kubernetes/pkg/controller/serviceaccount

     1  /*
     2  Copyright 2014 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 serviceaccount
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  	"time"
    23  
    24  	"k8s.io/api/core/v1"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/util/sets"
    27  	"k8s.io/client-go/informers"
    28  	"k8s.io/client-go/kubernetes/fake"
    29  	core "k8s.io/client-go/testing"
    30  	"k8s.io/kubernetes/pkg/controller"
    31  )
    32  
    33  func TestServiceAccountCreation(t *testing.T) {
    34  	ns := metav1.NamespaceDefault
    35  
    36  	defaultName := "default"
    37  	managedName := "managed"
    38  
    39  	activeNS := &v1.Namespace{
    40  		ObjectMeta: metav1.ObjectMeta{Name: ns},
    41  		Status: v1.NamespaceStatus{
    42  			Phase: v1.NamespaceActive,
    43  		},
    44  	}
    45  	terminatingNS := &v1.Namespace{
    46  		ObjectMeta: metav1.ObjectMeta{Name: ns},
    47  		Status: v1.NamespaceStatus{
    48  			Phase: v1.NamespaceTerminating,
    49  		},
    50  	}
    51  	defaultServiceAccount := &v1.ServiceAccount{
    52  		ObjectMeta: metav1.ObjectMeta{
    53  			Name:            defaultName,
    54  			Namespace:       ns,
    55  			ResourceVersion: "1",
    56  		},
    57  	}
    58  	managedServiceAccount := &v1.ServiceAccount{
    59  		ObjectMeta: metav1.ObjectMeta{
    60  			Name:            managedName,
    61  			Namespace:       ns,
    62  			ResourceVersion: "1",
    63  		},
    64  	}
    65  	unmanagedServiceAccount := &v1.ServiceAccount{
    66  		ObjectMeta: metav1.ObjectMeta{
    67  			Name:            "other-unmanaged",
    68  			Namespace:       ns,
    69  			ResourceVersion: "1",
    70  		},
    71  	}
    72  
    73  	testcases := map[string]struct {
    74  		ExistingNamespace       *v1.Namespace
    75  		ExistingServiceAccounts []*v1.ServiceAccount
    76  
    77  		AddedNamespace        *v1.Namespace
    78  		UpdatedNamespace      *v1.Namespace
    79  		DeletedServiceAccount *v1.ServiceAccount
    80  
    81  		ExpectCreatedServiceAccounts []string
    82  	}{
    83  		"new active namespace missing serviceaccounts": {
    84  			ExistingServiceAccounts:      []*v1.ServiceAccount{},
    85  			AddedNamespace:               activeNS,
    86  			ExpectCreatedServiceAccounts: sets.NewString(defaultName, managedName).List(),
    87  		},
    88  		"new active namespace missing serviceaccount": {
    89  			ExistingServiceAccounts:      []*v1.ServiceAccount{managedServiceAccount},
    90  			AddedNamespace:               activeNS,
    91  			ExpectCreatedServiceAccounts: []string{defaultName},
    92  		},
    93  		"new active namespace with serviceaccounts": {
    94  			ExistingServiceAccounts:      []*v1.ServiceAccount{defaultServiceAccount, managedServiceAccount},
    95  			AddedNamespace:               activeNS,
    96  			ExpectCreatedServiceAccounts: []string{},
    97  		},
    98  
    99  		"new terminating namespace": {
   100  			ExistingServiceAccounts:      []*v1.ServiceAccount{},
   101  			AddedNamespace:               terminatingNS,
   102  			ExpectCreatedServiceAccounts: []string{},
   103  		},
   104  
   105  		"updated active namespace missing serviceaccounts": {
   106  			ExistingServiceAccounts:      []*v1.ServiceAccount{},
   107  			UpdatedNamespace:             activeNS,
   108  			ExpectCreatedServiceAccounts: sets.NewString(defaultName, managedName).List(),
   109  		},
   110  		"updated active namespace missing serviceaccount": {
   111  			ExistingServiceAccounts:      []*v1.ServiceAccount{defaultServiceAccount},
   112  			UpdatedNamespace:             activeNS,
   113  			ExpectCreatedServiceAccounts: []string{managedName},
   114  		},
   115  		"updated active namespace with serviceaccounts": {
   116  			ExistingServiceAccounts:      []*v1.ServiceAccount{defaultServiceAccount, managedServiceAccount},
   117  			UpdatedNamespace:             activeNS,
   118  			ExpectCreatedServiceAccounts: []string{},
   119  		},
   120  		"updated terminating namespace": {
   121  			ExistingServiceAccounts:      []*v1.ServiceAccount{},
   122  			UpdatedNamespace:             terminatingNS,
   123  			ExpectCreatedServiceAccounts: []string{},
   124  		},
   125  
   126  		"deleted serviceaccount without namespace": {
   127  			DeletedServiceAccount:        defaultServiceAccount,
   128  			ExpectCreatedServiceAccounts: []string{},
   129  		},
   130  		"deleted serviceaccount with active namespace": {
   131  			ExistingServiceAccounts:      []*v1.ServiceAccount{managedServiceAccount},
   132  			ExistingNamespace:            activeNS,
   133  			DeletedServiceAccount:        defaultServiceAccount,
   134  			ExpectCreatedServiceAccounts: []string{defaultName},
   135  		},
   136  		"deleted serviceaccount with terminating namespace": {
   137  			ExistingNamespace:            terminatingNS,
   138  			DeletedServiceAccount:        defaultServiceAccount,
   139  			ExpectCreatedServiceAccounts: []string{},
   140  		},
   141  		"deleted unmanaged serviceaccount with active namespace": {
   142  			ExistingServiceAccounts:      []*v1.ServiceAccount{defaultServiceAccount, managedServiceAccount},
   143  			ExistingNamespace:            activeNS,
   144  			DeletedServiceAccount:        unmanagedServiceAccount,
   145  			ExpectCreatedServiceAccounts: []string{},
   146  		},
   147  		"deleted unmanaged serviceaccount with terminating namespace": {
   148  			ExistingNamespace:            terminatingNS,
   149  			DeletedServiceAccount:        unmanagedServiceAccount,
   150  			ExpectCreatedServiceAccounts: []string{},
   151  		},
   152  	}
   153  
   154  	for k, tc := range testcases {
   155  		client := fake.NewSimpleClientset(defaultServiceAccount, managedServiceAccount)
   156  		informers := informers.NewSharedInformerFactory(fake.NewSimpleClientset(), controller.NoResyncPeriodFunc())
   157  		options := DefaultServiceAccountsControllerOptions()
   158  		options.ServiceAccounts = []v1.ServiceAccount{
   159  			{ObjectMeta: metav1.ObjectMeta{Name: defaultName}},
   160  			{ObjectMeta: metav1.ObjectMeta{Name: managedName}},
   161  		}
   162  		saInformer := informers.Core().V1().ServiceAccounts()
   163  		nsInformer := informers.Core().V1().Namespaces()
   164  		controller, err := NewServiceAccountsController(
   165  			saInformer,
   166  			nsInformer,
   167  			client,
   168  			options,
   169  		)
   170  		if err != nil {
   171  			t.Fatalf("error creating ServiceAccounts controller: %v", err)
   172  		}
   173  		controller.saListerSynced = alwaysReady
   174  		controller.nsListerSynced = alwaysReady
   175  
   176  		saStore := saInformer.Informer().GetStore()
   177  		nsStore := nsInformer.Informer().GetStore()
   178  
   179  		syncCalls := make(chan struct{}, 1)
   180  		controller.syncHandler = func(ctx context.Context, key string) error {
   181  			err := controller.syncNamespace(ctx, key)
   182  			if err != nil {
   183  				t.Logf("%s: %v", k, err)
   184  			}
   185  
   186  			syncCalls <- struct{}{}
   187  			return err
   188  		}
   189  		stopCh := make(chan struct{})
   190  		defer close(stopCh)
   191  		go controller.Run(context.TODO(), 1)
   192  
   193  		if tc.ExistingNamespace != nil {
   194  			nsStore.Add(tc.ExistingNamespace)
   195  		}
   196  		for _, s := range tc.ExistingServiceAccounts {
   197  			saStore.Add(s)
   198  		}
   199  
   200  		if tc.AddedNamespace != nil {
   201  			nsStore.Add(tc.AddedNamespace)
   202  			controller.namespaceAdded(tc.AddedNamespace)
   203  		}
   204  		if tc.UpdatedNamespace != nil {
   205  			nsStore.Add(tc.UpdatedNamespace)
   206  			controller.namespaceUpdated(nil, tc.UpdatedNamespace)
   207  		}
   208  		if tc.DeletedServiceAccount != nil {
   209  			controller.serviceAccountDeleted(tc.DeletedServiceAccount)
   210  		}
   211  
   212  		// wait to be called
   213  		select {
   214  		case <-syncCalls:
   215  		case <-time.After(10 * time.Second):
   216  			t.Errorf("%s: took too long", k)
   217  		}
   218  
   219  		actions := client.Actions()
   220  		if len(tc.ExpectCreatedServiceAccounts) != len(actions) {
   221  			t.Errorf("%s: Expected to create accounts %#v. Actual actions were: %#v", k, tc.ExpectCreatedServiceAccounts, actions)
   222  			continue
   223  		}
   224  		for i, expectedName := range tc.ExpectCreatedServiceAccounts {
   225  			action := actions[i]
   226  			if !action.Matches("create", "serviceaccounts") {
   227  				t.Errorf("%s: Unexpected action %s", k, action)
   228  				break
   229  			}
   230  			createdAccount := action.(core.CreateAction).GetObject().(*v1.ServiceAccount)
   231  			if createdAccount.Name != expectedName {
   232  				t.Errorf("%s: Expected %s to be created, got %s", k, expectedName, createdAccount.Name)
   233  			}
   234  		}
   235  	}
   236  }
   237  
   238  var alwaysReady = func() bool { return true }
   239  

View as plain text