1
16
17 package storageversionmigrator
18
19 import (
20 "bytes"
21 "context"
22 "testing"
23 "time"
24
25 etcd3watcher "k8s.io/apiserver/pkg/storage/etcd3"
26 "k8s.io/klog/v2/ktesting"
27
28 svmv1alpha1 "k8s.io/api/storagemigration/v1alpha1"
29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30 encryptionconfigcontroller "k8s.io/apiserver/pkg/server/options/encryptionconfig/controller"
31 utilfeature "k8s.io/apiserver/pkg/util/feature"
32 clientgofeaturegate "k8s.io/client-go/features"
33 "k8s.io/component-base/featuregate"
34 featuregatetesting "k8s.io/component-base/featuregate/testing"
35 "k8s.io/kubernetes/pkg/features"
36 )
37
38
39
40
41
42
43
44
45
46
47
48 func TestStorageVersionMigration(t *testing.T) {
49 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.StorageVersionMigrator, true)()
50 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, featuregate.Feature(clientgofeaturegate.InformerResourceVersion), true)()
51
52
53 encryptionconfigcontroller.EncryptionConfigFileChangePollDuration = time.Millisecond
54
55 _, ctx := ktesting.NewTestContext(t)
56 ctx, cancel := context.WithCancel(ctx)
57 defer cancel()
58
59 svmTest := svmSetup(ctx, t)
60
61
62 secret, err := svmTest.createSecret(ctx, t, secretName, defaultNamespace)
63 if err != nil {
64 t.Fatalf("Failed to create secret: %v", err)
65 }
66
67 metricBeforeUpdate := svmTest.getAutomaticReloadSuccessTotal(ctx, t)
68 svmTest.updateFile(t, svmTest.filePathForEncryptionConfig, encryptionConfigFileName, []byte(resources["updatedEncryptionConfig"]))
69 if !svmTest.isEncryptionConfigFileUpdated(ctx, t, metricBeforeUpdate) {
70 t.Fatalf("Failed to update encryption config file")
71 }
72
73 svm, err := svmTest.createSVMResource(
74 ctx,
75 t,
76 svmName,
77 svmv1alpha1.GroupVersionResource{
78 Group: "",
79 Version: "v1",
80 Resource: "secrets",
81 },
82 )
83 if err != nil {
84 t.Fatalf("Failed to create SVM resource: %v", err)
85 }
86 if !svmTest.waitForResourceMigration(ctx, t, svm.Name, secret.Name, 1) {
87 t.Fatalf("Failed to migrate resource %s/%s", secret.Namespace, secret.Name)
88 }
89
90 wantPrefix := "k8s:enc:aescbc:v1:key2"
91 etcdSecret, err := svmTest.getRawSecretFromETCD(t, secret.Name, secret.Namespace)
92 if err != nil {
93 t.Fatalf("Failed to get secret from etcd: %v", err)
94 }
95
96 if !bytes.HasPrefix(etcdSecret, []byte(wantPrefix)) {
97 t.Fatalf("expected secret to be prefixed with %s, but got %s", wantPrefix, etcdSecret)
98 }
99
100 secretAfterMigration, err := svmTest.client.CoreV1().Secrets(secret.Namespace).Get(ctx, secret.Name, metav1.GetOptions{})
101 if err != nil {
102 t.Fatalf("Failed to get secret: %v", err)
103 }
104
105
106 if secret.ResourceVersion == secretAfterMigration.ResourceVersion {
107 t.Fatalf("Expected resource version to be different, but got the same, rv before: %s, rv after: %s", secret.ResourceVersion, secretAfterMigration.ResourceVersion)
108 }
109
110 secondSVM, err := svmTest.createSVMResource(
111 ctx,
112 t,
113 secondSVMName,
114 svmv1alpha1.GroupVersionResource{
115 Group: "",
116 Version: "v1",
117 Resource: "secrets",
118 },
119 )
120 if err != nil {
121 t.Fatalf("Failed to create SVM resource: %v", err)
122 }
123 if !svmTest.waitForResourceMigration(ctx, t, secondSVM.Name, secretAfterMigration.Name, 2) {
124 t.Fatalf("Failed to migrate resource %s/%s", secretAfterMigration.Namespace, secretAfterMigration.Name)
125 }
126
127 secretAfterSecondMigration, err := svmTest.client.CoreV1().Secrets(secretAfterMigration.Namespace).Get(ctx, secretAfterMigration.Name, metav1.GetOptions{})
128 if err != nil {
129 t.Fatalf("Failed to get secret: %v", err)
130 }
131
132 if secretAfterMigration.ResourceVersion != secretAfterSecondMigration.ResourceVersion {
133 t.Fatalf("Expected resource version to be same, but got different, rv before: %s, rv after: %s", secretAfterMigration.ResourceVersion, secretAfterSecondMigration.ResourceVersion)
134 }
135 }
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150 func TestStorageVersionMigrationWithCRD(t *testing.T) {
151 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.StorageVersionMigrator, true)()
152 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, featuregate.Feature(clientgofeaturegate.InformerResourceVersion), true)()
153
154 etcd3watcher.TestOnlySetFatalOnDecodeError(false)
155 defer etcd3watcher.TestOnlySetFatalOnDecodeError(true)
156
157 _, ctx := ktesting.NewTestContext(t)
158 ctx, cancel := context.WithCancel(ctx)
159 defer cancel()
160
161 crVersions := make(map[string]versions)
162
163 svmTest := svmSetup(ctx, t)
164 certCtx := svmTest.setupServerCert(t)
165
166
167 crd := svmTest.createCRD(t, crdName, crdGroup, certCtx, v1CRDVersion)
168
169
170 cr1 := svmTest.createCR(ctx, t, "cr1", "v1")
171 if ok := svmTest.isCRStoredAtVersion(t, "v1", cr1.GetName()); !ok {
172 t.Fatalf("CR not stored at version v1")
173 }
174 crVersions[cr1.GetName()] = versions{
175 generation: cr1.GetGeneration(),
176 rv: cr1.GetResourceVersion(),
177 isRVUpdated: true,
178 }
179
180
181 shutdownServer := svmTest.createConversionWebhook(ctx, t, certCtx)
182
183
184 svmTest.updateCRD(ctx, t, crd.Name, v2CRDVersion)
185
186
187 cr2 := svmTest.createCR(ctx, t, "cr2", "v2")
188 if ok := svmTest.isCRStoredAtVersion(t, "v1", cr2.GetName()); !ok {
189 t.Fatalf("CR not stored at version v1")
190 }
191 crVersions[cr2.GetName()] = versions{
192 generation: cr2.GetGeneration(),
193 rv: cr2.GetResourceVersion(),
194 isRVUpdated: true,
195 }
196
197
198 svmTest.updateCRD(ctx, t, crd.Name, v2StorageCRDVersion)
199
200
201 cr3 := svmTest.createCR(ctx, t, "cr3", "v1")
202 if ok := svmTest.isCRStoredAtVersion(t, "v2", cr3.GetName()); !ok {
203 t.Fatalf("CR not stored at version v2")
204 }
205 crVersions[cr3.GetName()] = versions{
206 generation: cr3.GetGeneration(),
207 rv: cr3.GetResourceVersion(),
208 isRVUpdated: false,
209 }
210
211
212 cr4 := svmTest.createCR(ctx, t, "cr4", "v2")
213 if ok := svmTest.isCRStoredAtVersion(t, "v2", cr4.GetName()); !ok {
214 t.Fatalf("CR not stored at version v2")
215 }
216 crVersions[cr4.GetName()] = versions{
217 generation: cr4.GetGeneration(),
218 rv: cr4.GetResourceVersion(),
219 isRVUpdated: false,
220 }
221
222
223 if ok := svmTest.isCRStoredAtVersion(t, "v1", cr1.GetName()); !ok {
224 t.Fatalf("CR not stored at version v1")
225 }
226 if ok := svmTest.isCRStoredAtVersion(t, "v1", cr2.GetName()); !ok {
227 t.Fatalf("CR not stored at version v1")
228 }
229
230
231 svm, err := svmTest.createSVMResource(
232 ctx, t, "crdsvm",
233 svmv1alpha1.GroupVersionResource{
234 Group: crd.Spec.Group,
235 Version: "v1",
236 Resource: crd.Spec.Names.Plural,
237 })
238 if err != nil {
239 t.Fatalf("Failed to create SVM resource: %v", err)
240 }
241 if ok := svmTest.isCRDMigrated(ctx, t, svm.Name); !ok {
242 t.Fatalf("CRD not migrated")
243 }
244
245
246 if ok := svmTest.isCRStoredAtVersion(t, "v2", cr1.GetName()); !ok {
247 t.Fatalf("CR not stored at version v2")
248 }
249 if ok := svmTest.isCRStoredAtVersion(t, "v2", cr2.GetName()); !ok {
250 t.Fatalf("CR not stored at version v2")
251 }
252 if ok := svmTest.isCRStoredAtVersion(t, "v2", cr3.GetName()); !ok {
253 t.Fatalf("CR not stored at version v2")
254 }
255 if ok := svmTest.isCRStoredAtVersion(t, "v2", cr4.GetName()); !ok {
256 t.Fatalf("CR not stored at version v2")
257 }
258
259
260 svmTest.updateCRD(ctx, t, crd.Name, v1NotServingCRDVersion)
261 shutdownServer()
262
263
264 svmTest.validateRVAndGeneration(ctx, t, crVersions)
265
266
267 if err := svmTest.listCR(ctx, t, "v2"); err != nil {
268 t.Fatalf("Failed to list CRs at version v2: %v", err)
269 }
270 }
271
View as plain text