1
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
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