k8s.io/kubernetes@v1.29.3/test/e2e/common/node/configmap.go (about) 1 /* 2 Copyright 2016 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 node 18 19 import ( 20 "context" 21 "encoding/json" 22 "fmt" 23 24 v1 "k8s.io/api/core/v1" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/apimachinery/pkg/types" 27 "k8s.io/apimachinery/pkg/util/uuid" 28 "k8s.io/kubernetes/test/e2e/framework" 29 e2epodoutput "k8s.io/kubernetes/test/e2e/framework/pod/output" 30 imageutils "k8s.io/kubernetes/test/utils/image" 31 admissionapi "k8s.io/pod-security-admission/api" 32 33 "github.com/onsi/ginkgo/v2" 34 "github.com/onsi/gomega" 35 ) 36 37 var _ = SIGDescribe("ConfigMap", func() { 38 f := framework.NewDefaultFramework("configmap") 39 f.NamespacePodSecurityLevel = admissionapi.LevelBaseline 40 41 /* 42 Release: v1.9 43 Testname: ConfigMap, from environment field 44 Description: Create a Pod with an environment variable value set using a value from ConfigMap. A ConfigMap value MUST be accessible in the container environment. 45 */ 46 framework.ConformanceIt("should be consumable via environment variable", f.WithNodeConformance(), func(ctx context.Context) { 47 name := "configmap-test-" + string(uuid.NewUUID()) 48 configMap := newConfigMap(f, name) 49 ginkgo.By(fmt.Sprintf("Creating configMap %v/%v", f.Namespace.Name, configMap.Name)) 50 var err error 51 if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, configMap, metav1.CreateOptions{}); err != nil { 52 framework.Failf("unable to create test configMap %s: %v", configMap.Name, err) 53 } 54 55 pod := &v1.Pod{ 56 ObjectMeta: metav1.ObjectMeta{ 57 Name: "pod-configmaps-" + string(uuid.NewUUID()), 58 }, 59 Spec: v1.PodSpec{ 60 Containers: []v1.Container{ 61 { 62 Name: "env-test", 63 Image: imageutils.GetE2EImage(imageutils.BusyBox), 64 Command: []string{"sh", "-c", "env"}, 65 Env: []v1.EnvVar{ 66 { 67 Name: "CONFIG_DATA_1", 68 ValueFrom: &v1.EnvVarSource{ 69 ConfigMapKeyRef: &v1.ConfigMapKeySelector{ 70 LocalObjectReference: v1.LocalObjectReference{ 71 Name: name, 72 }, 73 Key: "data-1", 74 }, 75 }, 76 }, 77 }, 78 }, 79 }, 80 RestartPolicy: v1.RestartPolicyNever, 81 }, 82 } 83 84 e2epodoutput.TestContainerOutput(ctx, f, "consume configMaps", pod, 0, []string{ 85 "CONFIG_DATA_1=value-1", 86 }) 87 }) 88 89 /* 90 Release: v1.9 91 Testname: ConfigMap, from environment variables 92 Description: Create a Pod with a environment source from ConfigMap. All ConfigMap values MUST be available as environment variables in the container. 93 */ 94 framework.ConformanceIt("should be consumable via the environment", f.WithNodeConformance(), func(ctx context.Context) { 95 name := "configmap-test-" + string(uuid.NewUUID()) 96 configMap := newConfigMap(f, name) 97 ginkgo.By(fmt.Sprintf("Creating configMap %v/%v", f.Namespace.Name, configMap.Name)) 98 var err error 99 if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, configMap, metav1.CreateOptions{}); err != nil { 100 framework.Failf("unable to create test configMap %s: %v", configMap.Name, err) 101 } 102 103 pod := &v1.Pod{ 104 ObjectMeta: metav1.ObjectMeta{ 105 Name: "pod-configmaps-" + string(uuid.NewUUID()), 106 }, 107 Spec: v1.PodSpec{ 108 Containers: []v1.Container{ 109 { 110 Name: "env-test", 111 Image: imageutils.GetE2EImage(imageutils.BusyBox), 112 Command: []string{"sh", "-c", "env"}, 113 EnvFrom: []v1.EnvFromSource{ 114 { 115 ConfigMapRef: &v1.ConfigMapEnvSource{LocalObjectReference: v1.LocalObjectReference{Name: name}}, 116 }, 117 { 118 Prefix: "p-", 119 ConfigMapRef: &v1.ConfigMapEnvSource{LocalObjectReference: v1.LocalObjectReference{Name: name}}, 120 }, 121 }, 122 }, 123 }, 124 RestartPolicy: v1.RestartPolicyNever, 125 }, 126 } 127 128 e2epodoutput.TestContainerOutput(ctx, f, "consume configMaps", pod, 0, []string{ 129 "data-1=value-1", "data-2=value-2", "data-3=value-3", 130 "p-data-1=value-1", "p-data-2=value-2", "p-data-3=value-3", 131 }) 132 }) 133 134 /* 135 Release: v1.14 136 Testname: ConfigMap, with empty-key 137 Description: Attempt to create a ConfigMap with an empty key. The creation MUST fail. 138 */ 139 framework.ConformanceIt("should fail to create ConfigMap with empty key", func(ctx context.Context) { 140 configMap, err := newConfigMapWithEmptyKey(ctx, f) 141 gomega.Expect(err).To(gomega.HaveOccurred(), "created configMap %q with empty key in namespace %q", configMap.Name, f.Namespace.Name) 142 }) 143 144 ginkgo.It("should update ConfigMap successfully", func(ctx context.Context) { 145 name := "configmap-test-" + string(uuid.NewUUID()) 146 configMap := newConfigMap(f, name) 147 ginkgo.By(fmt.Sprintf("Creating ConfigMap %v/%v", f.Namespace.Name, configMap.Name)) 148 _, err := f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, configMap, metav1.CreateOptions{}) 149 framework.ExpectNoError(err, "failed to create ConfigMap") 150 151 configMap.Data = map[string]string{ 152 "data": "value", 153 } 154 ginkgo.By(fmt.Sprintf("Updating configMap %v/%v", f.Namespace.Name, configMap.Name)) 155 _, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Update(ctx, configMap, metav1.UpdateOptions{}) 156 framework.ExpectNoError(err, "failed to update ConfigMap") 157 158 configMapFromUpdate, err := f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Get(ctx, name, metav1.GetOptions{}) 159 framework.ExpectNoError(err, "failed to get ConfigMap") 160 ginkgo.By(fmt.Sprintf("Verifying update of ConfigMap %v/%v", f.Namespace.Name, configMap.Name)) 161 gomega.Expect(configMapFromUpdate.Data).To(gomega.Equal(configMap.Data)) 162 }) 163 164 /* 165 Release: v1.19 166 Testname: ConfigMap lifecycle 167 Description: Attempt to create a ConfigMap. Patch the created ConfigMap. Fetching the ConfigMap MUST reflect changes. 168 By fetching all the ConfigMaps via a Label selector it MUST find the ConfigMap by it's static label and updated value. The ConfigMap must be deleted by Collection. 169 */ 170 framework.ConformanceIt("should run through a ConfigMap lifecycle", func(ctx context.Context) { 171 testNamespaceName := f.Namespace.Name 172 testConfigMapName := "test-configmap" + string(uuid.NewUUID()) 173 174 testConfigMap := v1.ConfigMap{ 175 ObjectMeta: metav1.ObjectMeta{ 176 Name: testConfigMapName, 177 Labels: map[string]string{ 178 "test-configmap-static": "true", 179 }, 180 }, 181 Data: map[string]string{ 182 "valueName": "value", 183 }, 184 } 185 186 ginkgo.By("creating a ConfigMap") 187 _, err := f.ClientSet.CoreV1().ConfigMaps(testNamespaceName).Create(ctx, &testConfigMap, metav1.CreateOptions{}) 188 framework.ExpectNoError(err, "failed to create ConfigMap") 189 190 ginkgo.By("fetching the ConfigMap") 191 configMap, err := f.ClientSet.CoreV1().ConfigMaps(testNamespaceName).Get(ctx, testConfigMapName, metav1.GetOptions{}) 192 framework.ExpectNoError(err, "failed to get ConfigMap") 193 gomega.Expect(configMap.Data["valueName"]).To(gomega.Equal(testConfigMap.Data["valueName"])) 194 gomega.Expect(configMap.Labels["test-configmap-static"]).To(gomega.Equal(testConfigMap.Labels["test-configmap-static"])) 195 196 configMapPatchPayload, err := json.Marshal(v1.ConfigMap{ 197 ObjectMeta: metav1.ObjectMeta{ 198 Labels: map[string]string{ 199 "test-configmap": "patched", 200 }, 201 }, 202 Data: map[string]string{ 203 "valueName": "value1", 204 }, 205 }) 206 framework.ExpectNoError(err, "failed to marshal patch data") 207 208 ginkgo.By("patching the ConfigMap") 209 _, err = f.ClientSet.CoreV1().ConfigMaps(testNamespaceName).Patch(ctx, testConfigMapName, types.StrategicMergePatchType, []byte(configMapPatchPayload), metav1.PatchOptions{}) 210 framework.ExpectNoError(err, "failed to patch ConfigMap") 211 212 ginkgo.By("listing all ConfigMaps in all namespaces with a label selector") 213 configMapList, err := f.ClientSet.CoreV1().ConfigMaps("").List(ctx, metav1.ListOptions{ 214 LabelSelector: "test-configmap=patched", 215 }) 216 framework.ExpectNoError(err, "failed to list ConfigMaps with LabelSelector") 217 testConfigMapFound := false 218 for _, cm := range configMapList.Items { 219 if cm.ObjectMeta.Name == testConfigMap.ObjectMeta.Name && 220 cm.ObjectMeta.Namespace == testNamespaceName && 221 cm.ObjectMeta.Labels["test-configmap-static"] == testConfigMap.ObjectMeta.Labels["test-configmap-static"] && 222 cm.ObjectMeta.Labels["test-configmap"] == "patched" && 223 cm.Data["valueName"] == "value1" { 224 testConfigMapFound = true 225 break 226 } 227 } 228 if !testConfigMapFound { 229 framework.Failf("failed to find ConfigMap %s/%s by label selector", testNamespaceName, testConfigMap.ObjectMeta.Name) 230 } 231 232 ginkgo.By("deleting the ConfigMap by collection with a label selector") 233 err = f.ClientSet.CoreV1().ConfigMaps(testNamespaceName).DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{ 234 LabelSelector: "test-configmap-static=true", 235 }) 236 framework.ExpectNoError(err, "failed to delete ConfigMap collection with LabelSelector") 237 238 ginkgo.By("listing all ConfigMaps in test namespace") 239 configMapList, err = f.ClientSet.CoreV1().ConfigMaps(testNamespaceName).List(ctx, metav1.ListOptions{ 240 LabelSelector: "test-configmap-static=true", 241 }) 242 framework.ExpectNoError(err, "failed to list ConfigMap by LabelSelector") 243 gomega.Expect(configMapList.Items).To(gomega.BeEmpty(), "ConfigMap is still present after being deleted by collection") 244 }) 245 }) 246 247 func newConfigMap(f *framework.Framework, name string) *v1.ConfigMap { 248 return &v1.ConfigMap{ 249 ObjectMeta: metav1.ObjectMeta{ 250 Namespace: f.Namespace.Name, 251 Name: name, 252 }, 253 Data: map[string]string{ 254 "data-1": "value-1", 255 "data-2": "value-2", 256 "data-3": "value-3", 257 }, 258 } 259 } 260 261 func newConfigMapWithEmptyKey(ctx context.Context, f *framework.Framework) (*v1.ConfigMap, error) { 262 name := "configmap-test-emptyKey-" + string(uuid.NewUUID()) 263 configMap := &v1.ConfigMap{ 264 ObjectMeta: metav1.ObjectMeta{ 265 Namespace: f.Namespace.Name, 266 Name: name, 267 }, 268 Data: map[string]string{ 269 "": "value-1", 270 }, 271 } 272 273 ginkgo.By(fmt.Sprintf("Creating configMap that has name %s", configMap.Name)) 274 return f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, configMap, metav1.CreateOptions{}) 275 }