1
16
17 package storageversiongc
18
19 import (
20 "context"
21 "reflect"
22 "testing"
23 "time"
24
25 apiserverinternalv1alpha1 "k8s.io/api/apiserverinternal/v1alpha1"
26 coordinationv1 "k8s.io/api/coordination/v1"
27 apierrors "k8s.io/apimachinery/pkg/api/errors"
28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29 "k8s.io/client-go/informers"
30 "k8s.io/client-go/kubernetes"
31 "k8s.io/client-go/kubernetes/fake"
32 "k8s.io/klog/v2/ktesting"
33 utilpointer "k8s.io/utils/pointer"
34 )
35
36 func setupController(ctx context.Context, clientset kubernetes.Interface) {
37 informerFactory := informers.NewSharedInformerFactory(clientset, 100*time.Millisecond)
38 leaseInformer := informerFactory.Coordination().V1().Leases()
39 storageVersionInformer := informerFactory.Internal().V1alpha1().StorageVersions()
40
41 controller := NewStorageVersionGC(ctx, clientset, leaseInformer, storageVersionInformer)
42 go controller.Run(context.Background())
43 informerFactory.Start(nil)
44 }
45
46 func newKubeApiserverLease(name, holderIdentity string) *coordinationv1.Lease {
47 return &coordinationv1.Lease{
48 ObjectMeta: metav1.ObjectMeta{
49 Name: name,
50 Namespace: metav1.NamespaceSystem,
51 Labels: map[string]string{
52 "apiserver.kubernetes.io/identity": "kube-apiserver",
53 },
54 },
55 Spec: coordinationv1.LeaseSpec{
56 HolderIdentity: utilpointer.StringPtr(holderIdentity),
57 },
58 }
59 }
60
61
62
63
64
65 func Test_StorageVersionUpdatedWithAllEncodingVersionsEqualOnLeaseDeletion(t *testing.T) {
66 lease1 := newKubeApiserverLease("kube-apiserver-1", "kube-apiserver-1")
67 lease2 := newKubeApiserverLease("kube-apiserver-2", "kube-apiserver-2")
68 lease3 := newKubeApiserverLease("kube-apiserver-3", "kube-apiserver-3")
69
70 storageVersion := &apiserverinternalv1alpha1.StorageVersion{
71 ObjectMeta: metav1.ObjectMeta{
72 Name: "k8s.test.resources",
73 },
74 Status: apiserverinternalv1alpha1.StorageVersionStatus{
75 StorageVersions: []apiserverinternalv1alpha1.ServerStorageVersion{
76 {
77 APIServerID: "kube-apiserver-1",
78 EncodingVersion: "v1",
79 DecodableVersions: []string{"v1"},
80 },
81 {
82 APIServerID: "kube-apiserver-2",
83 EncodingVersion: "v2",
84 DecodableVersions: []string{"v2"},
85 },
86 {
87 APIServerID: "kube-apiserver-3",
88 EncodingVersion: "v2",
89 DecodableVersions: []string{"v2"},
90 },
91 },
92 CommonEncodingVersion: utilpointer.String("v1"),
93 },
94 }
95
96 clientset := fake.NewSimpleClientset(lease1, lease2, lease3, storageVersion)
97 _, ctx := ktesting.NewTestContext(t)
98 setupController(ctx, clientset)
99
100
101 if err := clientset.CoordinationV1().Leases(metav1.NamespaceSystem).Delete(context.Background(), "kube-apiserver-1", metav1.DeleteOptions{}); err != nil {
102 t.Fatalf("error deleting lease object: %v", err)
103 }
104
105
106 time.Sleep(2 * time.Second)
107
108 storageVersion, err := clientset.InternalV1alpha1().StorageVersions().Get(context.Background(), "k8s.test.resources", metav1.GetOptions{})
109 if err != nil {
110 t.Fatalf("error getting StorageVersion: %v", err)
111 }
112
113 expectedServerStorageVersions := []apiserverinternalv1alpha1.ServerStorageVersion{
114 {
115 APIServerID: "kube-apiserver-2",
116 EncodingVersion: "v2",
117 DecodableVersions: []string{"v2"},
118 },
119 {
120 APIServerID: "kube-apiserver-3",
121 EncodingVersion: "v2",
122 DecodableVersions: []string{"v2"},
123 },
124 }
125
126 if !reflect.DeepEqual(storageVersion.Status.StorageVersions, expectedServerStorageVersions) {
127 t.Error("unexpected storage version object")
128 t.Logf("got: %+v", storageVersion)
129 t.Logf("expected: %+v", expectedServerStorageVersions)
130 }
131
132 if *storageVersion.Status.CommonEncodingVersion != "v2" {
133 t.Errorf("unexpected common encoding version")
134 t.Logf("got: %q", *storageVersion.Status.CommonEncodingVersion)
135 t.Logf("expected: %q", "v2")
136 }
137
138 if len(storageVersion.Status.Conditions) != 1 {
139 t.Errorf("expected 1 condition, got: %d", len(storageVersion.Status.Conditions))
140 }
141
142 if storageVersion.Status.Conditions[0].Type != apiserverinternalv1alpha1.AllEncodingVersionsEqual {
143 t.Errorf("expected condition type 'AllEncodingVersionsEqual', got: %q", storageVersion.Status.Conditions[0].Type)
144 }
145
146 if storageVersion.Status.Conditions[0].Status != apiserverinternalv1alpha1.ConditionTrue {
147 t.Errorf("expected condition status 'True', got: %q", storageVersion.Status.Conditions[0].Status)
148 }
149 }
150
151
152
153
154
155 func Test_StorageVersionUpdatedWithDifferentEncodingVersionsOnLeaseDeletion(t *testing.T) {
156 lease1 := newKubeApiserverLease("kube-apiserver-1", "kube-apiserver-1")
157 lease2 := newKubeApiserverLease("kube-apiserver-2", "kube-apiserver-2")
158 lease3 := newKubeApiserverLease("kube-apiserver-3", "kube-apiserver-3")
159
160 storageVersion := &apiserverinternalv1alpha1.StorageVersion{
161 ObjectMeta: metav1.ObjectMeta{
162 Name: "k8s.test.resources",
163 },
164 Status: apiserverinternalv1alpha1.StorageVersionStatus{
165 StorageVersions: []apiserverinternalv1alpha1.ServerStorageVersion{
166 {
167 APIServerID: "kube-apiserver-1",
168 EncodingVersion: "v1",
169 DecodableVersions: []string{"v1"},
170 },
171 {
172 APIServerID: "kube-apiserver-3",
173 EncodingVersion: "v2",
174 DecodableVersions: []string{"v2"},
175 },
176 },
177 CommonEncodingVersion: utilpointer.String("v1"),
178 },
179 }
180
181 clientset := fake.NewSimpleClientset(lease1, lease2, lease3, storageVersion)
182 _, ctx := ktesting.NewTestContext(t)
183 setupController(ctx, clientset)
184
185
186 if err := clientset.CoordinationV1().Leases(metav1.NamespaceSystem).Delete(context.Background(), "kube-apiserver-2", metav1.DeleteOptions{}); err != nil {
187 t.Fatalf("error deleting lease object: %v", err)
188 }
189
190
191 time.Sleep(2 * time.Second)
192
193 storageVersion, err := clientset.InternalV1alpha1().StorageVersions().Get(context.Background(), "k8s.test.resources", metav1.GetOptions{})
194 if err != nil {
195 t.Fatalf("error getting StorageVersion: %v", err)
196 }
197
198 expectedServerStorageVersions := []apiserverinternalv1alpha1.ServerStorageVersion{
199 {
200 APIServerID: "kube-apiserver-1",
201 EncodingVersion: "v1",
202 DecodableVersions: []string{"v1"},
203 },
204 {
205 APIServerID: "kube-apiserver-3",
206 EncodingVersion: "v2",
207 DecodableVersions: []string{"v2"},
208 },
209 }
210
211 if !reflect.DeepEqual(storageVersion.Status.StorageVersions, expectedServerStorageVersions) {
212 t.Error("unexpected storage version object")
213 t.Logf("got: %+v", storageVersion)
214 t.Logf("expected: %+v", expectedServerStorageVersions)
215 }
216
217 if *storageVersion.Status.CommonEncodingVersion != "v1" {
218 t.Errorf("unexpected common encoding version")
219 t.Logf("got: %q", *storageVersion.Status.CommonEncodingVersion)
220 t.Logf("expected: %q", "v1")
221 }
222 }
223
224
225
226 func Test_StorageVersionContainsInvalidLeaseID(t *testing.T) {
227 lease1 := newKubeApiserverLease("kube-apiserver-1", "kube-apiserver-1")
228 lease2 := newKubeApiserverLease("kube-apiserver-2", "kube-apiserver-2")
229 lease3 := newKubeApiserverLease("kube-apiserver-3", "kube-apiserver-3")
230
231 storageVersion := &apiserverinternalv1alpha1.StorageVersion{
232 ObjectMeta: metav1.ObjectMeta{
233 Name: "k8s.test.resources",
234 },
235 Status: apiserverinternalv1alpha1.StorageVersionStatus{
236 StorageVersions: []apiserverinternalv1alpha1.ServerStorageVersion{
237 {
238 APIServerID: "kube-apiserver-1",
239 EncodingVersion: "v1",
240 DecodableVersions: []string{"v1"},
241 },
242 {
243 APIServerID: "kube-apiserver-2",
244 EncodingVersion: "v2",
245 DecodableVersions: []string{"v2"},
246 },
247 {
248 APIServerID: "kube-apiserver-3",
249 EncodingVersion: "v2",
250 DecodableVersions: []string{"v2"},
251 },
252 {
253 APIServerID: "kube-apiserver-4",
254 EncodingVersion: "v2",
255 DecodableVersions: []string{"v1"},
256 },
257 },
258 CommonEncodingVersion: utilpointer.String("v1"),
259 },
260 }
261
262 clientset := fake.NewSimpleClientset(lease1, lease2, lease3, storageVersion)
263 _, ctx := ktesting.NewTestContext(t)
264 setupController(ctx, clientset)
265
266
267 time.Sleep(2 * time.Second)
268
269 storageVersion, err := clientset.InternalV1alpha1().StorageVersions().Get(context.Background(), "k8s.test.resources", metav1.GetOptions{})
270 if err != nil {
271 t.Fatalf("error getting StorageVersion: %v", err)
272 }
273
274 expectedServerStorageVersions := []apiserverinternalv1alpha1.ServerStorageVersion{
275 {
276 APIServerID: "kube-apiserver-1",
277 EncodingVersion: "v1",
278 DecodableVersions: []string{"v1"},
279 },
280 {
281 APIServerID: "kube-apiserver-2",
282 EncodingVersion: "v2",
283 DecodableVersions: []string{"v2"},
284 },
285 {
286 APIServerID: "kube-apiserver-3",
287 EncodingVersion: "v2",
288 DecodableVersions: []string{"v2"},
289 },
290 }
291
292 if !reflect.DeepEqual(storageVersion.Status.StorageVersions, expectedServerStorageVersions) {
293 t.Error("unexpected storage version object")
294 t.Logf("got: %+v", storageVersion)
295 t.Logf("expected: %+v", expectedServerStorageVersions)
296 }
297
298 if len(storageVersion.Status.Conditions) != 1 {
299 t.Errorf("expected 1 condition, got: %d", len(storageVersion.Status.Conditions))
300 }
301
302 if storageVersion.Status.Conditions[0].Type != apiserverinternalv1alpha1.AllEncodingVersionsEqual {
303 t.Errorf("expected condition type 'AllEncodingVersionsEqual', got: %q", storageVersion.Status.Conditions[0].Type)
304 }
305
306 if storageVersion.Status.Conditions[0].Status != apiserverinternalv1alpha1.ConditionFalse {
307 t.Errorf("expected condition status 'True', got: %q", storageVersion.Status.Conditions[0].Status)
308 }
309 }
310
311
312
313 func Test_StorageVersionDeletedOnLeaseDeletion(t *testing.T) {
314 lease1 := newKubeApiserverLease("kube-apiserver-1", "kube-apiserver-1")
315
316 storageVersion := &apiserverinternalv1alpha1.StorageVersion{
317 ObjectMeta: metav1.ObjectMeta{
318 Name: "k8s.test.resources",
319 },
320 Status: apiserverinternalv1alpha1.StorageVersionStatus{
321 StorageVersions: []apiserverinternalv1alpha1.ServerStorageVersion{
322 {
323 APIServerID: "kube-apiserver-1",
324 EncodingVersion: "v1",
325 DecodableVersions: []string{"v1"},
326 },
327 },
328 },
329 }
330
331 clientset := fake.NewSimpleClientset(lease1, storageVersion)
332 _, ctx := ktesting.NewTestContext(t)
333 setupController(ctx, clientset)
334
335
336 if err := clientset.CoordinationV1().Leases(metav1.NamespaceSystem).Delete(context.Background(), "kube-apiserver-1", metav1.DeleteOptions{}); err != nil {
337 t.Fatalf("error deleting lease object: %v", err)
338 }
339
340
341 time.Sleep(2 * time.Second)
342
343
344 _, err := clientset.InternalV1alpha1().StorageVersions().Get(context.Background(), "k8s.test.resources", metav1.GetOptions{})
345 if !apierrors.IsNotFound(err) {
346 t.Fatalf("expected IsNotFound error, got: %v", err)
347 }
348 }
349
View as plain text