k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/test/e2e/common/storage/projected_configmap.go (about) 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 storage 18 19 import ( 20 "context" 21 "fmt" 22 "path" 23 24 v1 "k8s.io/api/core/v1" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/apimachinery/pkg/util/uuid" 27 "k8s.io/kubernetes/test/e2e/framework" 28 e2epod "k8s.io/kubernetes/test/e2e/framework/pod" 29 e2epodoutput "k8s.io/kubernetes/test/e2e/framework/pod/output" 30 e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper" 31 "k8s.io/kubernetes/test/e2e/nodefeature" 32 imageutils "k8s.io/kubernetes/test/utils/image" 33 admissionapi "k8s.io/pod-security-admission/api" 34 35 "github.com/onsi/ginkgo/v2" 36 "github.com/onsi/gomega" 37 ) 38 39 var _ = SIGDescribe("Projected configMap", func() { 40 f := framework.NewDefaultFramework("projected") 41 f.NamespacePodSecurityLevel = admissionapi.LevelBaseline 42 43 /* 44 Release: v1.9 45 Testname: Projected Volume, ConfigMap, volume mode default 46 Description: A Pod is created with projected volume source 'ConfigMap' to store a configMap with default permission mode. Pod MUST be able to read the content of the ConfigMap successfully and the mode on the volume MUST be -rw-r--r--. 47 */ 48 framework.ConformanceIt("should be consumable from pods in volume", f.WithNodeConformance(), func(ctx context.Context) { 49 doProjectedConfigMapE2EWithoutMappings(ctx, f, false, 0, nil) 50 }) 51 52 /* 53 Release: v1.9 54 Testname: Projected Volume, ConfigMap, volume mode 0400 55 Description: A Pod is created with projected volume source 'ConfigMap' to store a configMap with permission mode set to 0400. Pod MUST be able to read the content of the ConfigMap successfully and the mode on the volume MUST be -r--------. 56 This test is marked LinuxOnly since Windows does not support setting specific file permissions. 57 */ 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 doProjectedConfigMapE2EWithoutMappings(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 // Windows does not support RunAsUser / FSGroup SecurityContext options, and it does not support setting file permissions. 65 e2eskipper.SkipIfNodeOSDistroIs("windows") 66 defaultMode := int32(0440) /* setting fsGroup sets mode to at least 440 */ 67 doProjectedConfigMapE2EWithoutMappings(ctx, f, true, 1001, &defaultMode) 68 }) 69 70 /* 71 Release: v1.9 72 Testname: Projected Volume, ConfigMap, non-root user 73 Description: A Pod is created with projected volume source 'ConfigMap' to store a configMap as non-root user with uid 1000. Pod MUST be able to read the content of the ConfigMap successfully and the mode on the volume MUST be -rw-r--r--. 74 */ 75 framework.ConformanceIt("should be consumable from pods in volume as non-root", f.WithNodeConformance(), func(ctx context.Context) { 76 doProjectedConfigMapE2EWithoutMappings(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 // Windows does not support RunAsUser / FSGroup SecurityContext options. 81 e2eskipper.SkipIfNodeOSDistroIs("windows") 82 doProjectedConfigMapE2EWithoutMappings(ctx, f, true, 1001, nil) 83 }) 84 85 /* 86 Release: v1.9 87 Testname: Projected Volume, ConfigMap, mapped 88 Description: A Pod is created with projected volume source 'ConfigMap' to store a configMap with default permission mode. The ConfigMap is also mapped to a custom path. Pod MUST be able to read the content of the ConfigMap from the custom location successfully and the mode on the volume MUST be -rw-r--r--. 89 */ 90 framework.ConformanceIt("should be consumable from pods in volume with mappings", f.WithNodeConformance(), func(ctx context.Context) { 91 doProjectedConfigMapE2EWithMappings(ctx, f, false, 0, nil) 92 }) 93 94 /* 95 Release: v1.9 96 Testname: Projected Volume, ConfigMap, mapped, volume mode 0400 97 Description: A Pod is created with projected volume source 'ConfigMap' to store a configMap with permission mode set to 0400. The ConfigMap is also mapped to a custom path. Pod MUST be able to read the content of the ConfigMap from the custom location successfully and the mode on the volume MUST be -r--r--r--. 98 This test is marked LinuxOnly since Windows does not support setting specific file permissions. 99 */ 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 doProjectedConfigMapE2EWithMappings(ctx, f, false, 0, &mode) 103 }) 104 105 /* 106 Release: v1.9 107 Testname: Projected Volume, ConfigMap, mapped, non-root user 108 Description: A Pod is created with projected volume source 'ConfigMap' to store a configMap as non-root user with uid 1000. The ConfigMap is also mapped to a custom path. Pod MUST be able to read the content of the ConfigMap from the custom location successfully and the mode on the volume MUST be -r--r--r--. 109 */ 110 framework.ConformanceIt("should be consumable from pods in volume with mappings as non-root", f.WithNodeConformance(), func(ctx context.Context) { 111 doProjectedConfigMapE2EWithMappings(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 // Windows does not support RunAsUser / FSGroup SecurityContext options. 116 e2eskipper.SkipIfNodeOSDistroIs("windows") 117 doProjectedConfigMapE2EWithMappings(ctx, f, true, 1001, nil) 118 }) 119 120 /* 121 Release: v1.9 122 Testname: Projected Volume, ConfigMap, update 123 Description: A Pod is created with projected volume source 'ConfigMap' to store a configMap and performs a create and update to new value. Pod MUST be able to create the configMap with value-1. Pod MUST be able to update the value in the confgiMap to value-2. 124 */ 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 := "projected-configmap-test-upd-" + string(uuid.NewUUID()) 130 volumeName := "projected-configmap-volume" 131 volumeMountPath := "/etc/projected-configmap-volume" 132 configMap := &v1.ConfigMap{ 133 ObjectMeta: metav1.ObjectMeta{ 134 Namespace: f.Namespace.Name, 135 Name: name, 136 }, 137 Data: map[string]string{ 138 "data-1": "value-1", 139 }, 140 } 141 142 ginkgo.By(fmt.Sprintf("Creating projection with configMap that has name %s", configMap.Name)) 143 var err error 144 if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, configMap, metav1.CreateOptions{}); err != nil { 145 framework.Failf("unable to create test configMap %s: %v", configMap.Name, err) 146 } 147 148 pod := createProjectedConfigMapMounttestPod(f.Namespace.Name, volumeName, name, volumeMountPath, 149 "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/projected-configmap-volume/data-1") 150 151 ginkgo.By("Creating the pod") 152 e2epod.NewPodClient(f).CreateSync(ctx, pod) 153 154 pollLogs := func() (string, error) { 155 return e2epod.GetPodLogs(ctx, f.ClientSet, f.Namespace.Name, pod.Name, pod.Spec.Containers[0].Name) 156 } 157 158 gomega.Eventually(ctx, pollLogs, podLogTimeout, framework.Poll).Should(gomega.ContainSubstring("value-1")) 159 160 ginkgo.By(fmt.Sprintf("Updating configmap %v", configMap.Name)) 161 configMap.ResourceVersion = "" // to force update 162 configMap.Data["data-1"] = "value-2" 163 _, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Update(ctx, configMap, metav1.UpdateOptions{}) 164 framework.ExpectNoError(err, "Failed to update configmap %q in namespace %q", configMap.Name, f.Namespace.Name) 165 166 ginkgo.By("waiting to observe update in volume") 167 gomega.Eventually(ctx, pollLogs, podLogTimeout, framework.Poll).Should(gomega.ContainSubstring("value-2")) 168 }) 169 170 /* 171 Release: v1.9 172 Testname: Projected Volume, ConfigMap, create, update and delete 173 Description: Create a Pod with three containers with ConfigMaps namely a create, update and delete container. Create Container when started MUST not have configMap, update and delete containers MUST be created with a ConfigMap value as 'value-1'. Create a configMap in the create container, the Pod MUST be able to read the configMap from the create container. Update the configMap in the update container, Pod MUST be able to read the updated configMap value. Delete the configMap in the delete container. Pod MUST fail to read the configMap from the delete container. 174 */ 175 framework.ConformanceIt("optional updates should be reflected in volume", f.WithNodeConformance(), func(ctx context.Context) { 176 podLogTimeout := e2epod.GetPodSecretUpdateTimeout(ctx, f.ClientSet) 177 containerTimeoutArg := fmt.Sprintf("--retry_time=%v", int(podLogTimeout.Seconds())) 178 trueVal := true 179 volumeMountPath := "/etc/projected-configmap-volumes" 180 181 deleteName := "cm-test-opt-del-" + string(uuid.NewUUID()) 182 deleteContainerName := "delcm-volume-test" 183 deleteVolumeName := "deletecm-volume" 184 deleteConfigMap := &v1.ConfigMap{ 185 ObjectMeta: metav1.ObjectMeta{ 186 Namespace: f.Namespace.Name, 187 Name: deleteName, 188 }, 189 Data: map[string]string{ 190 "data-1": "value-1", 191 }, 192 } 193 194 updateName := "cm-test-opt-upd-" + string(uuid.NewUUID()) 195 updateContainerName := "updcm-volume-test" 196 updateVolumeName := "updatecm-volume" 197 updateConfigMap := &v1.ConfigMap{ 198 ObjectMeta: metav1.ObjectMeta{ 199 Namespace: f.Namespace.Name, 200 Name: updateName, 201 }, 202 Data: map[string]string{ 203 "data-1": "value-1", 204 }, 205 } 206 207 createName := "cm-test-opt-create-" + string(uuid.NewUUID()) 208 createContainerName := "createcm-volume-test" 209 createVolumeName := "createcm-volume" 210 createConfigMap := &v1.ConfigMap{ 211 ObjectMeta: metav1.ObjectMeta{ 212 Namespace: f.Namespace.Name, 213 Name: createName, 214 }, 215 Data: map[string]string{ 216 "data-1": "value-1", 217 }, 218 } 219 220 ginkgo.By(fmt.Sprintf("Creating configMap with name %s", deleteConfigMap.Name)) 221 var err error 222 if deleteConfigMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, deleteConfigMap, metav1.CreateOptions{}); err != nil { 223 framework.Failf("unable to create test configMap %s: %v", deleteConfigMap.Name, err) 224 } 225 226 ginkgo.By(fmt.Sprintf("Creating configMap with name %s", updateConfigMap.Name)) 227 if updateConfigMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, updateConfigMap, metav1.CreateOptions{}); err != nil { 228 framework.Failf("unable to create test configMap %s: %v", updateConfigMap.Name, err) 229 } 230 231 pod := &v1.Pod{ 232 ObjectMeta: metav1.ObjectMeta{ 233 Name: "pod-projected-configmaps-" + string(uuid.NewUUID()), 234 }, 235 Spec: v1.PodSpec{ 236 Volumes: []v1.Volume{ 237 { 238 Name: deleteVolumeName, 239 VolumeSource: v1.VolumeSource{ 240 Projected: &v1.ProjectedVolumeSource{ 241 Sources: []v1.VolumeProjection{ 242 { 243 ConfigMap: &v1.ConfigMapProjection{ 244 LocalObjectReference: v1.LocalObjectReference{ 245 Name: deleteName, 246 }, 247 Optional: &trueVal, 248 }, 249 }, 250 }, 251 }, 252 }, 253 }, 254 { 255 Name: updateVolumeName, 256 VolumeSource: v1.VolumeSource{ 257 Projected: &v1.ProjectedVolumeSource{ 258 Sources: []v1.VolumeProjection{ 259 { 260 ConfigMap: &v1.ConfigMapProjection{ 261 LocalObjectReference: v1.LocalObjectReference{ 262 Name: updateName, 263 }, 264 Optional: &trueVal, 265 }, 266 }, 267 }, 268 }, 269 }, 270 }, 271 { 272 Name: createVolumeName, 273 VolumeSource: v1.VolumeSource{ 274 Projected: &v1.ProjectedVolumeSource{ 275 Sources: []v1.VolumeProjection{ 276 { 277 ConfigMap: &v1.ConfigMapProjection{ 278 LocalObjectReference: v1.LocalObjectReference{ 279 Name: createName, 280 }, 281 Optional: &trueVal, 282 }, 283 }, 284 }, 285 }, 286 }, 287 }, 288 }, 289 Containers: []v1.Container{ 290 { 291 Name: deleteContainerName, 292 Image: imageutils.GetE2EImage(imageutils.Agnhost), 293 Args: []string{"mounttest", "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/projected-configmap-volumes/delete/data-1"}, 294 VolumeMounts: []v1.VolumeMount{ 295 { 296 Name: deleteVolumeName, 297 MountPath: path.Join(volumeMountPath, "delete"), 298 ReadOnly: true, 299 }, 300 }, 301 }, 302 { 303 Name: updateContainerName, 304 Image: imageutils.GetE2EImage(imageutils.Agnhost), 305 Args: []string{"mounttest", "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/projected-configmap-volumes/update/data-3"}, 306 VolumeMounts: []v1.VolumeMount{ 307 { 308 Name: updateVolumeName, 309 MountPath: path.Join(volumeMountPath, "update"), 310 ReadOnly: true, 311 }, 312 }, 313 }, 314 { 315 Name: createContainerName, 316 Image: imageutils.GetE2EImage(imageutils.Agnhost), 317 Args: []string{"mounttest", "--break_on_expected_content=false", containerTimeoutArg, "--file_content_in_loop=/etc/projected-configmap-volumes/create/data-1"}, 318 VolumeMounts: []v1.VolumeMount{ 319 { 320 Name: createVolumeName, 321 MountPath: path.Join(volumeMountPath, "create"), 322 ReadOnly: true, 323 }, 324 }, 325 }, 326 }, 327 RestartPolicy: v1.RestartPolicyNever, 328 }, 329 } 330 ginkgo.By("Creating the pod") 331 e2epod.NewPodClient(f).CreateSync(ctx, pod) 332 333 pollCreateLogs := func() (string, error) { 334 return e2epod.GetPodLogs(ctx, f.ClientSet, f.Namespace.Name, pod.Name, createContainerName) 335 } 336 gomega.Eventually(ctx, pollCreateLogs, podLogTimeout, framework.Poll).Should(gomega.ContainSubstring("Error reading file /etc/projected-configmap-volumes/create/data-1")) 337 338 pollUpdateLogs := func() (string, error) { 339 return e2epod.GetPodLogs(ctx, f.ClientSet, f.Namespace.Name, pod.Name, updateContainerName) 340 } 341 gomega.Eventually(ctx, pollUpdateLogs, podLogTimeout, framework.Poll).Should(gomega.ContainSubstring("Error reading file /etc/projected-configmap-volumes/update/data-3")) 342 343 pollDeleteLogs := func() (string, error) { 344 return e2epod.GetPodLogs(ctx, f.ClientSet, f.Namespace.Name, pod.Name, deleteContainerName) 345 } 346 gomega.Eventually(ctx, pollDeleteLogs, podLogTimeout, framework.Poll).Should(gomega.ContainSubstring("value-1")) 347 348 ginkgo.By(fmt.Sprintf("Deleting configmap %v", deleteConfigMap.Name)) 349 err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Delete(ctx, deleteConfigMap.Name, metav1.DeleteOptions{}) 350 framework.ExpectNoError(err, "Failed to delete configmap %q in namespace %q", deleteConfigMap.Name, f.Namespace.Name) 351 352 ginkgo.By(fmt.Sprintf("Updating configmap %v", updateConfigMap.Name)) 353 updateConfigMap.ResourceVersion = "" // to force update 354 delete(updateConfigMap.Data, "data-1") 355 updateConfigMap.Data["data-3"] = "value-3" 356 _, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Update(ctx, updateConfigMap, metav1.UpdateOptions{}) 357 framework.ExpectNoError(err, "Failed to update configmap %q in namespace %q", updateConfigMap.Name, f.Namespace.Name) 358 359 ginkgo.By(fmt.Sprintf("Creating configMap with name %s", createConfigMap.Name)) 360 if createConfigMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, createConfigMap, metav1.CreateOptions{}); err != nil { 361 framework.Failf("unable to create test configMap %s: %v", createConfigMap.Name, err) 362 } 363 364 ginkgo.By("waiting to observe update in volume") 365 366 gomega.Eventually(ctx, pollCreateLogs, podLogTimeout, framework.Poll).Should(gomega.ContainSubstring("value-1")) 367 gomega.Eventually(ctx, pollUpdateLogs, podLogTimeout, framework.Poll).Should(gomega.ContainSubstring("value-3")) 368 gomega.Eventually(ctx, pollDeleteLogs, podLogTimeout, framework.Poll).Should(gomega.ContainSubstring("Error reading file /etc/projected-configmap-volumes/delete/data-1")) 369 }) 370 371 /* 372 Release: v1.9 373 Testname: Projected Volume, ConfigMap, multiple volume paths 374 Description: A Pod is created with a projected volume source 'ConfigMap' to store a configMap. The configMap is mapped to two different volume mounts. Pod MUST be able to read the content of the configMap successfully from the two volume mounts. 375 */ 376 framework.ConformanceIt("should be consumable in multiple volumes in the same pod", f.WithNodeConformance(), func(ctx context.Context) { 377 var ( 378 name = "projected-configmap-test-volume-" + string(uuid.NewUUID()) 379 volumeName = "projected-configmap-volume" 380 volumeMountPath = "/etc/projected-configmap-volume" 381 volumeName2 = "projected-configmap-volume-2" 382 volumeMountPath2 = "/etc/projected-configmap-volume-2" 383 configMap = newConfigMap(f, name) 384 ) 385 386 ginkgo.By(fmt.Sprintf("Creating configMap with name %s", configMap.Name)) 387 var err error 388 if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, configMap, metav1.CreateOptions{}); err != nil { 389 framework.Failf("unable to create test configMap %s: %v", configMap.Name, err) 390 } 391 392 pod := &v1.Pod{ 393 ObjectMeta: metav1.ObjectMeta{ 394 Name: "pod-projected-configmaps-" + string(uuid.NewUUID()), 395 }, 396 Spec: v1.PodSpec{ 397 Volumes: []v1.Volume{ 398 { 399 Name: volumeName, 400 VolumeSource: v1.VolumeSource{ 401 Projected: &v1.ProjectedVolumeSource{ 402 Sources: []v1.VolumeProjection{ 403 { 404 ConfigMap: &v1.ConfigMapProjection{ 405 LocalObjectReference: v1.LocalObjectReference{ 406 Name: name, 407 }, 408 }, 409 }, 410 }, 411 }, 412 }, 413 }, 414 { 415 Name: volumeName2, 416 VolumeSource: v1.VolumeSource{ 417 Projected: &v1.ProjectedVolumeSource{ 418 Sources: []v1.VolumeProjection{ 419 { 420 421 ConfigMap: &v1.ConfigMapProjection{ 422 LocalObjectReference: v1.LocalObjectReference{ 423 Name: name, 424 }, 425 }, 426 }, 427 }, 428 }, 429 }, 430 }, 431 }, 432 Containers: []v1.Container{ 433 { 434 Name: "projected-configmap-volume-test", 435 Image: imageutils.GetE2EImage(imageutils.Agnhost), 436 Args: []string{"mounttest", "--file_content=/etc/projected-configmap-volume/data-1"}, 437 VolumeMounts: []v1.VolumeMount{ 438 { 439 Name: volumeName, 440 MountPath: volumeMountPath, 441 ReadOnly: true, 442 }, 443 { 444 Name: volumeName2, 445 MountPath: volumeMountPath2, 446 ReadOnly: true, 447 }, 448 }, 449 }, 450 }, 451 RestartPolicy: v1.RestartPolicyNever, 452 }, 453 } 454 455 e2epodoutput.TestContainerOutput(ctx, f, "consume configMaps", pod, 0, []string{ 456 "content of file \"/etc/projected-configmap-volume/data-1\": value-1", 457 }) 458 459 }) 460 461 //The pod is in pending during volume creation until the configMap objects are available 462 //or until mount the configMap volume times out. There is no configMap object defined for the pod, so it should return timeout exception unless it is marked optional. 463 //Slow (~5 mins) 464 f.It("Should fail non-optional pod creation due to configMap object does not exist", f.WithSlow(), func(ctx context.Context) { 465 volumeMountPath := "/etc/projected-configmap-volumes" 466 pod := createNonOptionalConfigMapPod(ctx, f, volumeMountPath) 467 getPod := e2epod.Get(f.ClientSet, pod) 468 gomega.Consistently(ctx, getPod).WithTimeout(f.Timeouts.PodStart).Should(e2epod.BeInPhase(v1.PodPending)) 469 }) 470 471 //ConfigMap object defined for the pod, If a key is specified which is not present in the ConfigMap, 472 // the volume setup will error unless it is marked optional, during the pod creation. 473 //Slow (~5 mins) 474 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) { 475 volumeMountPath := "/etc/configmap-volumes" 476 pod := createNonOptionalConfigMapPodWithConfig(ctx, f, volumeMountPath) 477 getPod := e2epod.Get(f.ClientSet, pod) 478 gomega.Consistently(ctx, getPod).WithTimeout(f.Timeouts.PodStart).Should(e2epod.BeInPhase(v1.PodPending)) 479 }) 480 }) 481 482 func doProjectedConfigMapE2EWithoutMappings(ctx context.Context, f *framework.Framework, asUser bool, fsGroup int64, defaultMode *int32) { 483 groupID := int64(fsGroup) 484 485 var ( 486 name = "projected-configmap-test-volume-" + string(uuid.NewUUID()) 487 volumeName = "projected-configmap-volume" 488 volumeMountPath = "/etc/projected-configmap-volume" 489 configMap = newConfigMap(f, name) 490 ) 491 492 ginkgo.By(fmt.Sprintf("Creating configMap with name %s", configMap.Name)) 493 var err error 494 if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, configMap, metav1.CreateOptions{}); err != nil { 495 framework.Failf("unable to create test configMap %s: %v", configMap.Name, err) 496 } 497 498 pod := createProjectedConfigMapMounttestPod(f.Namespace.Name, volumeName, name, volumeMountPath, 499 "--file_content=/etc/projected-configmap-volume/data-1", "--file_mode=/etc/projected-configmap-volume/data-1") 500 501 if asUser { 502 setPodNonRootUser(pod) 503 } 504 505 if groupID != 0 { 506 pod.Spec.SecurityContext.FSGroup = &groupID 507 } 508 509 if defaultMode != nil { 510 //pod.Spec.Volumes[0].VolumeSource.Projected.Sources[0].ConfigMap.DefaultMode = defaultMode 511 pod.Spec.Volumes[0].VolumeSource.Projected.DefaultMode = defaultMode 512 } 513 514 fileModeRegexp := getFileModeRegex("/etc/projected-configmap-volume/data-1", defaultMode) 515 output := []string{ 516 "content of file \"/etc/projected-configmap-volume/data-1\": value-1", 517 fileModeRegexp, 518 } 519 e2epodoutput.TestContainerOutputRegexp(ctx, f, "consume configMaps", pod, 0, output) 520 } 521 522 func doProjectedConfigMapE2EWithMappings(ctx context.Context, f *framework.Framework, asUser bool, fsGroup int64, itemMode *int32) { 523 groupID := int64(fsGroup) 524 525 var ( 526 name = "projected-configmap-test-volume-map-" + string(uuid.NewUUID()) 527 volumeName = "projected-configmap-volume" 528 volumeMountPath = "/etc/projected-configmap-volume" 529 configMap = newConfigMap(f, name) 530 ) 531 532 ginkgo.By(fmt.Sprintf("Creating configMap with name %s", configMap.Name)) 533 534 var err error 535 if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, configMap, metav1.CreateOptions{}); err != nil { 536 framework.Failf("unable to create test configMap %s: %v", configMap.Name, err) 537 } 538 539 pod := createProjectedConfigMapMounttestPod(f.Namespace.Name, volumeName, name, volumeMountPath, 540 "--file_content=/etc/projected-configmap-volume/path/to/data-2", "--file_mode=/etc/projected-configmap-volume/path/to/data-2") 541 pod.Spec.Volumes[0].VolumeSource.Projected.Sources[0].ConfigMap.Items = []v1.KeyToPath{ 542 { 543 Key: "data-2", 544 Path: "path/to/data-2", 545 }, 546 } 547 548 if asUser { 549 setPodNonRootUser(pod) 550 } 551 552 if groupID != 0 { 553 pod.Spec.SecurityContext.FSGroup = &groupID 554 } 555 556 if itemMode != nil { 557 //pod.Spec.Volumes[0].VolumeSource.ConfigMap.Items[0].Mode = itemMode 558 pod.Spec.Volumes[0].VolumeSource.Projected.DefaultMode = itemMode 559 } 560 561 // Just check file mode if fsGroup is not set. If fsGroup is set, the 562 // final mode is adjusted and we are not testing that case. 563 output := []string{ 564 "content of file \"/etc/projected-configmap-volume/path/to/data-2\": value-2", 565 } 566 if fsGroup == 0 { 567 fileModeRegexp := getFileModeRegex("/etc/projected-configmap-volume/path/to/data-2", itemMode) 568 output = append(output, fileModeRegexp) 569 } 570 e2epodoutput.TestContainerOutputRegexp(ctx, f, "consume configMaps", pod, 0, output) 571 } 572 573 func createProjectedConfigMapMounttestPod(namespace, volumeName, referenceName, mountPath string, mounttestArgs ...string) *v1.Pod { 574 volumes := []v1.Volume{ 575 { 576 Name: volumeName, 577 VolumeSource: v1.VolumeSource{ 578 Projected: &v1.ProjectedVolumeSource{ 579 Sources: []v1.VolumeProjection{ 580 { 581 ConfigMap: &v1.ConfigMapProjection{ 582 LocalObjectReference: v1.LocalObjectReference{ 583 Name: referenceName, 584 }, 585 }, 586 }, 587 }, 588 }, 589 }, 590 }, 591 } 592 podName := "pod-projected-configmaps-" + string(uuid.NewUUID()) 593 mounttestArgs = append([]string{"mounttest"}, mounttestArgs...) 594 pod := e2epod.NewAgnhostPod(namespace, podName, volumes, createMounts(volumeName, mountPath, true), nil, mounttestArgs...) 595 pod.Spec.RestartPolicy = v1.RestartPolicyNever 596 return pod 597 }