1
16
17 package storage
18
19 import (
20 "context"
21 "fmt"
22 "path"
23
24 "github.com/onsi/ginkgo/v2"
25 "github.com/onsi/gomega"
26 v1 "k8s.io/api/core/v1"
27 apierrors "k8s.io/apimachinery/pkg/api/errors"
28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29 "k8s.io/apimachinery/pkg/util/uuid"
30 "k8s.io/kubernetes/test/e2e/framework"
31 e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
32 e2epodoutput "k8s.io/kubernetes/test/e2e/framework/pod/output"
33 e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
34 "k8s.io/kubernetes/test/e2e/nodefeature"
35 imageutils "k8s.io/kubernetes/test/utils/image"
36 admissionapi "k8s.io/pod-security-admission/api"
37 )
38
39 var _ = SIGDescribe("ConfigMap", func() {
40 f := framework.NewDefaultFramework("configmap")
41 f.NamespacePodSecurityLevel = admissionapi.LevelBaseline
42
43
48 framework.ConformanceIt("should be consumable from pods in volume", f.WithNodeConformance(), func(ctx context.Context) {
49 doConfigMapE2EWithoutMappings(ctx, f, false, 0, nil)
50 })
51
52
58 framework.ConformanceIt("should be consumable from pods in volume with defaultMode set [LinuxOnly]", f.WithNodeConformance(), func(ctx context.Context) {
59 defaultMode := int32(0400)
60 doConfigMapE2EWithoutMappings(ctx, f, false, 0, &defaultMode)
61 })
62
63 f.It("should be consumable from pods in volume as non-root with defaultMode and fsGroup set [LinuxOnly]", nodefeature.FSGroup, func(ctx context.Context) {
64
65 e2eskipper.SkipIfNodeOSDistroIs("windows")
66 defaultMode := int32(0440)
67 doConfigMapE2EWithoutMappings(ctx, f, true, 1001, &defaultMode)
68 })
69
70
75 framework.ConformanceIt("should be consumable from pods in volume as non-root", f.WithNodeConformance(), func(ctx context.Context) {
76 doConfigMapE2EWithoutMappings(ctx, f, true, 0, nil)
77 })
78
79 f.It("should be consumable from pods in volume as non-root with FSGroup [LinuxOnly]", nodefeature.FSGroup, func(ctx context.Context) {
80
81 e2eskipper.SkipIfNodeOSDistroIs("windows")
82 doConfigMapE2EWithoutMappings(ctx, f, true, 1001, nil)
83 })
84
85
90 framework.ConformanceIt("should be consumable from pods in volume with mappings", f.WithNodeConformance(), func(ctx context.Context) {
91 doConfigMapE2EWithMappings(ctx, f, false, 0, nil)
92 })
93
94
100 framework.ConformanceIt("should be consumable from pods in volume with mappings and Item mode set [LinuxOnly]", f.WithNodeConformance(), func(ctx context.Context) {
101 mode := int32(0400)
102 doConfigMapE2EWithMappings(ctx, f, false, 0, &mode)
103 })
104
105
110 framework.ConformanceIt("should be consumable from pods in volume with mappings as non-root", f.WithNodeConformance(), func(ctx context.Context) {
111 doConfigMapE2EWithMappings(ctx, f, true, 0, nil)
112 })
113
114 f.It("should be consumable from pods in volume with mappings as non-root with FSGroup [LinuxOnly]", nodefeature.FSGroup, func(ctx context.Context) {
115
116 e2eskipper.SkipIfNodeOSDistroIs("windows")
117 doConfigMapE2EWithMappings(ctx, f, true, 1001, nil)
118 })
119
120
125 framework.ConformanceIt("updates should be reflected in volume", f.WithNodeConformance(), func(ctx context.Context) {
126 podLogTimeout := e2epod.GetPodSecretUpdateTimeout(ctx, f.ClientSet)
127 containerTimeoutArg := fmt.Sprintf("--retry_time=%v", int(podLogTimeout.Seconds()))
128
129 name := "configmap-test-upd-" + string(uuid.NewUUID())
130 volumeName := "configmap-volume"
131 volumeMountPath := "/etc/configmap-volume"
132
133 configMap := &v1.ConfigMap{
134 ObjectMeta: metav1.ObjectMeta{
135 Namespace: f.Namespace.Name,
136 Name: name,
137 },
138 Data: map[string]string{
139 "data-1": "value-1",
140 },
141 }
142
143 ginkgo.By(fmt.Sprintf("Creating configMap with name %s", configMap.Name))
144 var err error
145 if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, configMap, metav1.CreateOptions{}); err != nil {
146 framework.Failf("unable to create test configMap %s: %v", configMap.Name, err)
147 }
148
149 pod := createConfigMapVolumeMounttestPod(f.Namespace.Name, volumeName, name, volumeMountPath,
150 "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/configmap-volume/data-1")
151
152 ginkgo.By("Creating the pod")
153 e2epod.NewPodClient(f).CreateSync(ctx, pod)
154
155 pollLogs := func() (string, error) {
156 return e2epod.GetPodLogs(ctx, f.ClientSet, f.Namespace.Name, pod.Name, pod.Spec.Containers[0].Name)
157 }
158
159 gomega.Eventually(ctx, pollLogs, podLogTimeout, framework.Poll).Should(gomega.ContainSubstring("value-1"))
160
161 ginkgo.By(fmt.Sprintf("Updating configmap %v", configMap.Name))
162 configMap.ResourceVersion = ""
163 configMap.Data["data-1"] = "value-2"
164 _, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Update(ctx, configMap, metav1.UpdateOptions{})
165 framework.ExpectNoError(err, "Failed to update configmap %q in namespace %q", configMap.Name, f.Namespace.Name)
166
167 ginkgo.By("waiting to observe update in volume")
168 gomega.Eventually(ctx, pollLogs, podLogTimeout, framework.Poll).Should(gomega.ContainSubstring("value-2"))
169 })
170
171
176 framework.ConformanceIt("binary data should be reflected in volume", f.WithNodeConformance(), func(ctx context.Context) {
177 podLogTimeout := e2epod.GetPodSecretUpdateTimeout(ctx, f.ClientSet)
178 containerTimeoutArg := fmt.Sprintf("--retry_time=%v", int(podLogTimeout.Seconds()))
179
180 name := "configmap-test-upd-" + string(uuid.NewUUID())
181 volumeName := "configmap-volume"
182 volumeMountPath := "/etc/configmap-volume"
183 containerName := "configmap-volume-binary-test"
184
185 configMap := &v1.ConfigMap{
186 ObjectMeta: metav1.ObjectMeta{
187 Namespace: f.Namespace.Name,
188 Name: name,
189 },
190 Data: map[string]string{
191 "data-1": "value-1",
192 },
193 BinaryData: map[string][]byte{
194 "dump.bin": {0xde, 0xca, 0xfe, 0xba, 0xd0, 0xfe, 0xff},
195 },
196 }
197
198 ginkgo.By(fmt.Sprintf("Creating configMap with name %s", configMap.Name))
199 var err error
200 if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, configMap, metav1.CreateOptions{}); err != nil {
201 framework.Failf("unable to create test configMap %s: %v", configMap.Name, err)
202 }
203
204 pod := createConfigMapVolumeMounttestPod(f.Namespace.Name, volumeName, name, volumeMountPath,
205 "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/configmap-volume/data-1")
206 pod.Spec.Containers = append(pod.Spec.Containers, v1.Container{
207 Name: containerName,
208 Image: imageutils.GetE2EImage(imageutils.BusyBox),
209 Command: []string{"hexdump", "-C", "/etc/configmap-volume/dump.bin"},
210 VolumeMounts: []v1.VolumeMount{
211 {
212 Name: volumeName,
213 MountPath: volumeMountPath,
214 ReadOnly: true,
215 },
216 },
217 })
218
219 ginkgo.By("Creating the pod")
220 e2epod.NewPodClient(f).Create(ctx, pod)
221 framework.ExpectNoError(e2epod.WaitForPodNameRunningInNamespace(ctx, f.ClientSet, pod.Name, f.Namespace.Name))
222
223 pollLogs1 := func() (string, error) {
224 return e2epod.GetPodLogs(ctx, f.ClientSet, f.Namespace.Name, pod.Name, pod.Spec.Containers[0].Name)
225 }
226 pollLogs2 := func() (string, error) {
227 return e2epod.GetPodLogs(ctx, f.ClientSet, f.Namespace.Name, pod.Name, pod.Spec.Containers[1].Name)
228 }
229
230 ginkgo.By("Waiting for pod with text data")
231 gomega.Eventually(ctx, pollLogs1, podLogTimeout, framework.Poll).Should(gomega.ContainSubstring("value-1"))
232 ginkgo.By("Waiting for pod with binary data")
233 gomega.Eventually(ctx, pollLogs2, podLogTimeout, framework.Poll).Should(gomega.ContainSubstring("de ca fe ba d0 fe ff"))
234 })
235
236
241 framework.ConformanceIt("optional updates should be reflected in volume", f.WithNodeConformance(), func(ctx context.Context) {
242 podLogTimeout := e2epod.GetPodSecretUpdateTimeout(ctx, f.ClientSet)
243 containerTimeoutArg := fmt.Sprintf("--retry_time=%v", int(podLogTimeout.Seconds()))
244 trueVal := true
245 volumeMountPath := "/etc/configmap-volumes"
246
247 deleteName := "cm-test-opt-del-" + string(uuid.NewUUID())
248 deleteContainerName := "delcm-volume-test"
249 deleteVolumeName := "deletecm-volume"
250 deleteConfigMap := &v1.ConfigMap{
251 ObjectMeta: metav1.ObjectMeta{
252 Namespace: f.Namespace.Name,
253 Name: deleteName,
254 },
255 Data: map[string]string{
256 "data-1": "value-1",
257 },
258 }
259
260 updateName := "cm-test-opt-upd-" + string(uuid.NewUUID())
261 updateContainerName := "updcm-volume-test"
262 updateVolumeName := "updatecm-volume"
263 updateConfigMap := &v1.ConfigMap{
264 ObjectMeta: metav1.ObjectMeta{
265 Namespace: f.Namespace.Name,
266 Name: updateName,
267 },
268 Data: map[string]string{
269 "data-1": "value-1",
270 },
271 }
272
273 createName := "cm-test-opt-create-" + string(uuid.NewUUID())
274 createContainerName := "createcm-volume-test"
275 createVolumeName := "createcm-volume"
276 createConfigMap := &v1.ConfigMap{
277 ObjectMeta: metav1.ObjectMeta{
278 Namespace: f.Namespace.Name,
279 Name: createName,
280 },
281 Data: map[string]string{
282 "data-1": "value-1",
283 },
284 }
285
286 ginkgo.By(fmt.Sprintf("Creating configMap with name %s", deleteConfigMap.Name))
287 var err error
288 if deleteConfigMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, deleteConfigMap, metav1.CreateOptions{}); err != nil {
289 framework.Failf("unable to create test configMap %s: %v", deleteConfigMap.Name, err)
290 }
291
292 ginkgo.By(fmt.Sprintf("Creating configMap with name %s", updateConfigMap.Name))
293 if updateConfigMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, updateConfigMap, metav1.CreateOptions{}); err != nil {
294 framework.Failf("unable to create test configMap %s: %v", updateConfigMap.Name, err)
295 }
296
297 pod := &v1.Pod{
298 ObjectMeta: metav1.ObjectMeta{
299 Name: "pod-configmaps-" + string(uuid.NewUUID()),
300 },
301 Spec: v1.PodSpec{
302 Volumes: []v1.Volume{
303 {
304 Name: deleteVolumeName,
305 VolumeSource: v1.VolumeSource{
306 ConfigMap: &v1.ConfigMapVolumeSource{
307 LocalObjectReference: v1.LocalObjectReference{
308 Name: deleteName,
309 },
310 Optional: &trueVal,
311 },
312 },
313 },
314 {
315 Name: updateVolumeName,
316 VolumeSource: v1.VolumeSource{
317 ConfigMap: &v1.ConfigMapVolumeSource{
318 LocalObjectReference: v1.LocalObjectReference{
319 Name: updateName,
320 },
321 Optional: &trueVal,
322 },
323 },
324 },
325 {
326 Name: createVolumeName,
327 VolumeSource: v1.VolumeSource{
328 ConfigMap: &v1.ConfigMapVolumeSource{
329 LocalObjectReference: v1.LocalObjectReference{
330 Name: createName,
331 },
332 Optional: &trueVal,
333 },
334 },
335 },
336 },
337 Containers: []v1.Container{
338 {
339 Name: deleteContainerName,
340 Image: imageutils.GetE2EImage(imageutils.Agnhost),
341 Args: []string{"mounttest", "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/configmap-volumes/delete/data-1"},
342 VolumeMounts: []v1.VolumeMount{
343 {
344 Name: deleteVolumeName,
345 MountPath: path.Join(volumeMountPath, "delete"),
346 ReadOnly: true,
347 },
348 },
349 },
350 {
351 Name: updateContainerName,
352 Image: imageutils.GetE2EImage(imageutils.Agnhost),
353 Args: []string{"mounttest", "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/configmap-volumes/update/data-3"},
354 VolumeMounts: []v1.VolumeMount{
355 {
356 Name: updateVolumeName,
357 MountPath: path.Join(volumeMountPath, "update"),
358 ReadOnly: true,
359 },
360 },
361 },
362 {
363 Name: createContainerName,
364 Image: imageutils.GetE2EImage(imageutils.Agnhost),
365 Args: []string{"mounttest", "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/configmap-volumes/create/data-1"},
366 VolumeMounts: []v1.VolumeMount{
367 {
368 Name: createVolumeName,
369 MountPath: path.Join(volumeMountPath, "create"),
370 ReadOnly: true,
371 },
372 },
373 },
374 },
375 RestartPolicy: v1.RestartPolicyNever,
376 },
377 }
378 ginkgo.By("Creating the pod")
379 e2epod.NewPodClient(f).CreateSync(ctx, pod)
380
381 pollCreateLogs := func() (string, error) {
382 return e2epod.GetPodLogs(ctx, f.ClientSet, f.Namespace.Name, pod.Name, createContainerName)
383 }
384 gomega.Eventually(ctx, pollCreateLogs, podLogTimeout, framework.Poll).Should(gomega.ContainSubstring("Error reading file /etc/configmap-volumes/create/data-1"))
385
386 pollUpdateLogs := func() (string, error) {
387 return e2epod.GetPodLogs(ctx, f.ClientSet, f.Namespace.Name, pod.Name, updateContainerName)
388 }
389 gomega.Eventually(ctx, pollUpdateLogs, podLogTimeout, framework.Poll).Should(gomega.ContainSubstring("Error reading file /etc/configmap-volumes/update/data-3"))
390
391 pollDeleteLogs := func() (string, error) {
392 return e2epod.GetPodLogs(ctx, f.ClientSet, f.Namespace.Name, pod.Name, deleteContainerName)
393 }
394 gomega.Eventually(ctx, pollDeleteLogs, podLogTimeout, framework.Poll).Should(gomega.ContainSubstring("value-1"))
395
396 ginkgo.By(fmt.Sprintf("Deleting configmap %v", deleteConfigMap.Name))
397 err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Delete(ctx, deleteConfigMap.Name, metav1.DeleteOptions{})
398 framework.ExpectNoError(err, "Failed to delete configmap %q in namespace %q", deleteConfigMap.Name, f.Namespace.Name)
399
400 ginkgo.By(fmt.Sprintf("Updating configmap %v", updateConfigMap.Name))
401 updateConfigMap.ResourceVersion = ""
402 delete(updateConfigMap.Data, "data-1")
403 updateConfigMap.Data["data-3"] = "value-3"
404 _, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Update(ctx, updateConfigMap, metav1.UpdateOptions{})
405 framework.ExpectNoError(err, "Failed to update configmap %q in namespace %q", updateConfigMap.Name, f.Namespace.Name)
406
407 ginkgo.By(fmt.Sprintf("Creating configMap with name %s", createConfigMap.Name))
408 if createConfigMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, createConfigMap, metav1.CreateOptions{}); err != nil {
409 framework.Failf("unable to create test configMap %s: %v", createConfigMap.Name, err)
410 }
411
412 ginkgo.By("waiting to observe update in volume")
413
414 gomega.Eventually(ctx, pollCreateLogs, podLogTimeout, framework.Poll).Should(gomega.ContainSubstring("value-1"))
415 gomega.Eventually(ctx, pollUpdateLogs, podLogTimeout, framework.Poll).Should(gomega.ContainSubstring("value-3"))
416 gomega.Eventually(ctx, pollDeleteLogs, podLogTimeout, framework.Poll).Should(gomega.ContainSubstring("Error reading file /etc/configmap-volumes/delete/data-1"))
417 })
418
419
424 framework.ConformanceIt("should be consumable in multiple volumes in the same pod", f.WithNodeConformance(), func(ctx context.Context) {
425 var (
426 name = "configmap-test-volume-" + string(uuid.NewUUID())
427 volumeName = "configmap-volume"
428 volumeMountPath = "/etc/configmap-volume"
429 volumeName2 = "configmap-volume-2"
430 volumeMountPath2 = "/etc/configmap-volume-2"
431 configMap = newConfigMap(f, name)
432 )
433
434 ginkgo.By(fmt.Sprintf("Creating configMap with name %s", configMap.Name))
435 var err error
436 if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, configMap, metav1.CreateOptions{}); err != nil {
437 framework.Failf("unable to create test configMap %s: %v", configMap.Name, err)
438 }
439
440 pod := &v1.Pod{
441 ObjectMeta: metav1.ObjectMeta{
442 Name: "pod-configmaps-" + string(uuid.NewUUID()),
443 },
444 Spec: v1.PodSpec{
445 Volumes: []v1.Volume{
446 {
447 Name: volumeName,
448 VolumeSource: v1.VolumeSource{
449 ConfigMap: &v1.ConfigMapVolumeSource{
450 LocalObjectReference: v1.LocalObjectReference{
451 Name: name,
452 },
453 },
454 },
455 },
456 {
457 Name: volumeName2,
458 VolumeSource: v1.VolumeSource{
459 ConfigMap: &v1.ConfigMapVolumeSource{
460 LocalObjectReference: v1.LocalObjectReference{
461 Name: name,
462 },
463 },
464 },
465 },
466 },
467 Containers: []v1.Container{
468 {
469 Name: "configmap-volume-test",
470 Image: imageutils.GetE2EImage(imageutils.Agnhost),
471 Args: []string{"mounttest", "--file_content=/etc/configmap-volume/data-1"},
472 VolumeMounts: []v1.VolumeMount{
473 {
474 Name: volumeName,
475 MountPath: volumeMountPath,
476 ReadOnly: true,
477 },
478 {
479 Name: volumeName2,
480 MountPath: volumeMountPath2,
481 ReadOnly: true,
482 },
483 },
484 },
485 },
486 RestartPolicy: v1.RestartPolicyNever,
487 },
488 }
489
490 e2epodoutput.TestContainerOutput(ctx, f, "consume configMaps", pod, 0, []string{
491 "content of file \"/etc/configmap-volume/data-1\": value-1",
492 })
493
494 })
495
496
505 framework.ConformanceIt("should be immutable if `immutable` field is set", func(ctx context.Context) {
506 name := "immutable"
507 configMap := newConfigMap(f, name)
508
509 currentConfigMap, err := f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, configMap, metav1.CreateOptions{})
510 framework.ExpectNoError(err, "Failed to create config map %q in namespace %q", configMap.Name, configMap.Namespace)
511
512 currentConfigMap.Data["data-4"] = "value-4"
513 currentConfigMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Update(ctx, currentConfigMap, metav1.UpdateOptions{})
514 framework.ExpectNoError(err, "Failed to update config map %q in namespace %q", configMap.Name, configMap.Namespace)
515
516
517 trueVal := true
518 currentConfigMap.Immutable = &trueVal
519 currentConfigMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Update(ctx, currentConfigMap, metav1.UpdateOptions{})
520 framework.ExpectNoError(err, "Failed to mark config map %q in namespace %q as immutable", configMap.Name, configMap.Namespace)
521
522
523 currentConfigMap.Data["data-5"] = "value-5"
524 _, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Update(ctx, currentConfigMap, metav1.UpdateOptions{})
525 if !apierrors.IsInvalid(err) {
526 framework.Failf("expected 'invalid' as error, got instead: %v", err)
527 }
528
529
530 currentConfigMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Get(ctx, name, metav1.GetOptions{})
531 framework.ExpectNoError(err, "Failed to get config map %q in namespace %q", configMap.Name, configMap.Namespace)
532 if !*currentConfigMap.Immutable {
533 framework.Failf("currentConfigMap %s can be switched from immutable to mutable", currentConfigMap.Name)
534 }
535
536 falseVal := false
537 currentConfigMap.Immutable = &falseVal
538 _, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Update(ctx, currentConfigMap, metav1.UpdateOptions{})
539 if !apierrors.IsInvalid(err) {
540 framework.Failf("expected 'invalid' as error, got instead: %v", err)
541 }
542
543
544 currentConfigMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Get(ctx, name, metav1.GetOptions{})
545 framework.ExpectNoError(err, "Failed to get config map %q in namespace %q", configMap.Name, configMap.Namespace)
546 currentConfigMap.Labels = map[string]string{"label1": "value1"}
547 _, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Update(ctx, currentConfigMap, metav1.UpdateOptions{})
548 framework.ExpectNoError(err, "Failed to update config map %q in namespace %q", configMap.Name, configMap.Namespace)
549
550
551 err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Delete(ctx, name, metav1.DeleteOptions{})
552 framework.ExpectNoError(err, "Failed to delete config map %q in namespace %q", configMap.Name, configMap.Namespace)
553 })
554
555
556
557
558 f.It("Should fail non-optional pod creation due to configMap object does not exist", f.WithSlow(), func(ctx context.Context) {
559 volumeMountPath := "/etc/configmap-volumes"
560 pod := createNonOptionalConfigMapPod(ctx, f, volumeMountPath)
561 getPod := e2epod.Get(f.ClientSet, pod)
562 gomega.Consistently(ctx, getPod).WithTimeout(f.Timeouts.PodStart).Should(e2epod.BeInPhase(v1.PodPending))
563 })
564
565
566
567
568 f.It("Should fail non-optional pod creation due to the key in the configMap object does not exist", f.WithSlow(), func(ctx context.Context) {
569 volumeMountPath := "/etc/configmap-volumes"
570 pod := createNonOptionalConfigMapPodWithConfig(ctx, f, volumeMountPath)
571 getPod := e2epod.Get(f.ClientSet, pod)
572 gomega.Consistently(ctx, getPod).WithTimeout(f.Timeouts.PodStart).Should(e2epod.BeInPhase(v1.PodPending))
573 })
574 })
575
576 func newConfigMap(f *framework.Framework, name string) *v1.ConfigMap {
577 return &v1.ConfigMap{
578 ObjectMeta: metav1.ObjectMeta{
579 Namespace: f.Namespace.Name,
580 Name: name,
581 },
582 Data: map[string]string{
583 "data-1": "value-1",
584 "data-2": "value-2",
585 "data-3": "value-3",
586 },
587 }
588 }
589
590 func doConfigMapE2EWithoutMappings(ctx context.Context, f *framework.Framework, asUser bool, fsGroup int64, defaultMode *int32) {
591 groupID := int64(fsGroup)
592
593 var (
594 name = "configmap-test-volume-" + string(uuid.NewUUID())
595 volumeName = "configmap-volume"
596 volumeMountPath = "/etc/configmap-volume"
597 configMap = newConfigMap(f, name)
598 )
599
600 ginkgo.By(fmt.Sprintf("Creating configMap with name %s", configMap.Name))
601 var err error
602 if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, configMap, metav1.CreateOptions{}); err != nil {
603 framework.Failf("unable to create test configMap %s: %v", configMap.Name, err)
604 }
605
606 pod := createConfigMapVolumeMounttestPod(f.Namespace.Name, volumeName, name, volumeMountPath,
607 "--file_content=/etc/configmap-volume/data-1", "--file_mode=/etc/configmap-volume/data-1")
608 one := int64(1)
609 pod.Spec.TerminationGracePeriodSeconds = &one
610
611 if asUser {
612 setPodNonRootUser(pod)
613 }
614
615 if groupID != 0 {
616 pod.Spec.SecurityContext.FSGroup = &groupID
617 }
618
619 if defaultMode != nil {
620 pod.Spec.Volumes[0].VolumeSource.ConfigMap.DefaultMode = defaultMode
621 }
622
623 fileModeRegexp := getFileModeRegex("/etc/configmap-volume/data-1", defaultMode)
624 output := []string{
625 "content of file \"/etc/configmap-volume/data-1\": value-1",
626 fileModeRegexp,
627 }
628 e2epodoutput.TestContainerOutputRegexp(ctx, f, "consume configMaps", pod, 0, output)
629 }
630
631 func doConfigMapE2EWithMappings(ctx context.Context, f *framework.Framework, asUser bool, fsGroup int64, itemMode *int32) {
632 groupID := int64(fsGroup)
633
634 var (
635 name = "configmap-test-volume-map-" + string(uuid.NewUUID())
636 volumeName = "configmap-volume"
637 volumeMountPath = "/etc/configmap-volume"
638 configMap = newConfigMap(f, name)
639 )
640
641 ginkgo.By(fmt.Sprintf("Creating configMap with name %s", configMap.Name))
642
643 var err error
644 if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, configMap, metav1.CreateOptions{}); err != nil {
645 framework.Failf("unable to create test configMap %s: %v", configMap.Name, err)
646 }
647
648 pod := createConfigMapVolumeMounttestPod(f.Namespace.Name, volumeName, name, volumeMountPath,
649 "--file_content=/etc/configmap-volume/path/to/data-2", "--file_mode=/etc/configmap-volume/path/to/data-2")
650 one := int64(1)
651 pod.Spec.TerminationGracePeriodSeconds = &one
652 pod.Spec.Volumes[0].VolumeSource.ConfigMap.Items = []v1.KeyToPath{
653 {
654 Key: "data-2",
655 Path: "path/to/data-2",
656 },
657 }
658
659 if asUser {
660 setPodNonRootUser(pod)
661 }
662
663 if groupID != 0 {
664 pod.Spec.SecurityContext.FSGroup = &groupID
665 }
666
667 if itemMode != nil {
668 pod.Spec.Volumes[0].VolumeSource.ConfigMap.Items[0].Mode = itemMode
669 }
670
671
672
673 output := []string{
674 "content of file \"/etc/configmap-volume/path/to/data-2\": value-2",
675 }
676 if fsGroup == 0 {
677 fileModeRegexp := getFileModeRegex("/etc/configmap-volume/path/to/data-2", itemMode)
678 output = append(output, fileModeRegexp)
679 }
680 e2epodoutput.TestContainerOutputRegexp(ctx, f, "consume configMaps", pod, 0, output)
681 }
682
683 func createNonOptionalConfigMapPod(ctx context.Context, f *framework.Framework, volumeMountPath string) *v1.Pod {
684 podLogTimeout := e2epod.GetPodSecretUpdateTimeout(ctx, f.ClientSet)
685 containerTimeoutArg := fmt.Sprintf("--retry_time=%v", int(podLogTimeout.Seconds()))
686 falseValue := false
687
688 createName := "cm-test-opt-create-" + string(uuid.NewUUID())
689 createVolumeName := "createcm-volume"
690
691
692 pod := createConfigMapVolumeMounttestPod(f.Namespace.Name, createVolumeName, createName, path.Join(volumeMountPath, "create"),
693 "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/configmap-volumes/create/data-1")
694 pod.Spec.Volumes[0].VolumeSource.ConfigMap.Optional = &falseValue
695
696 ginkgo.By("Creating the pod")
697 pod = e2epod.NewPodClient(f).Create(ctx, pod)
698 return pod
699 }
700
701 func createNonOptionalConfigMapPodWithConfig(ctx context.Context, f *framework.Framework, volumeMountPath string) *v1.Pod {
702 podLogTimeout := e2epod.GetPodSecretUpdateTimeout(ctx, f.ClientSet)
703 containerTimeoutArg := fmt.Sprintf("--retry_time=%v", int(podLogTimeout.Seconds()))
704 falseValue := false
705
706 createName := "cm-test-opt-create-" + string(uuid.NewUUID())
707 createVolumeName := "createcm-volume"
708 configMap := newConfigMap(f, createName)
709
710 ginkgo.By(fmt.Sprintf("Creating configMap with name %s", configMap.Name))
711 var err error
712 if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, configMap, metav1.CreateOptions{}); err != nil {
713 framework.Failf("unable to create test configMap %s: %v", configMap.Name, err)
714 }
715
716 pod := createConfigMapVolumeMounttestPod(f.Namespace.Name, createVolumeName, createName, path.Join(volumeMountPath, "create"),
717 "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/configmap-volumes/create/data-1")
718 pod.Spec.Volumes[0].VolumeSource.ConfigMap.Optional = &falseValue
719 pod.Spec.Volumes[0].VolumeSource.ConfigMap.Items = []v1.KeyToPath{
720 {
721 Key: "data-4",
722 Path: "path/to/data-4",
723 },
724 }
725
726 ginkgo.By("Creating the pod")
727 pod = e2epod.NewPodClient(f).Create(ctx, pod)
728 return pod
729 }
730
731 func createConfigMapVolumeMounttestPod(namespace, volumeName, referenceName, mountPath string, mounttestArgs ...string) *v1.Pod {
732 volumes := []v1.Volume{
733 {
734 Name: volumeName,
735 VolumeSource: v1.VolumeSource{
736 ConfigMap: &v1.ConfigMapVolumeSource{
737 LocalObjectReference: v1.LocalObjectReference{
738 Name: referenceName,
739 },
740 },
741 },
742 },
743 }
744 podName := "pod-configmaps-" + string(uuid.NewUUID())
745 mounttestArgs = append([]string{"mounttest"}, mounttestArgs...)
746 pod := e2epod.NewAgnhostPod(namespace, podName, volumes, createMounts(volumeName, mountPath, true), nil, mounttestArgs...)
747 pod.Spec.RestartPolicy = v1.RestartPolicyNever
748 return pod
749 }
750
View as plain text