1
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/feature"
29 "k8s.io/kubernetes/test/e2e/framework"
30 e2epodoutput "k8s.io/kubernetes/test/e2e/framework/pod/output"
31 imageutils "k8s.io/kubernetes/test/utils/image"
32 admissionapi "k8s.io/pod-security-admission/api"
33
34 "github.com/onsi/ginkgo/v2"
35 "github.com/onsi/gomega"
36 )
37
38 var _ = SIGDescribe("ConfigMap", func() {
39 f := framework.NewDefaultFramework("configmap")
40 f.NamespacePodSecurityLevel = admissionapi.LevelBaseline
41
42
47 framework.ConformanceIt("should be consumable via environment variable", f.WithNodeConformance(), func(ctx context.Context) {
48 name := "configmap-test-" + string(uuid.NewUUID())
49 configMap := newConfigMap(f, name)
50 ginkgo.By(fmt.Sprintf("Creating configMap %v/%v", f.Namespace.Name, configMap.Name))
51 var err error
52 if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, configMap, metav1.CreateOptions{}); err != nil {
53 framework.Failf("unable to create test configMap %s: %v", configMap.Name, err)
54 }
55
56 pod := &v1.Pod{
57 ObjectMeta: metav1.ObjectMeta{
58 Name: "pod-configmaps-" + string(uuid.NewUUID()),
59 },
60 Spec: v1.PodSpec{
61 Containers: []v1.Container{
62 {
63 Name: "env-test",
64 Image: imageutils.GetE2EImage(imageutils.BusyBox),
65 Command: []string{"sh", "-c", "env"},
66 Env: []v1.EnvVar{
67 {
68 Name: "CONFIG_DATA_1",
69 ValueFrom: &v1.EnvVarSource{
70 ConfigMapKeyRef: &v1.ConfigMapKeySelector{
71 LocalObjectReference: v1.LocalObjectReference{
72 Name: name,
73 },
74 Key: "data-1",
75 },
76 },
77 },
78 },
79 },
80 },
81 RestartPolicy: v1.RestartPolicyNever,
82 },
83 }
84
85 e2epodoutput.TestContainerOutput(ctx, f, "consume configMaps", pod, 0, []string{
86 "CONFIG_DATA_1=value-1",
87 })
88 })
89
90
95 framework.ConformanceIt("should be consumable via the environment", f.WithNodeConformance(), func(ctx context.Context) {
96 name := "configmap-test-" + string(uuid.NewUUID())
97 configMap := newConfigMap(f, name)
98 ginkgo.By(fmt.Sprintf("Creating configMap %v/%v", f.Namespace.Name, configMap.Name))
99 var err error
100 if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, configMap, metav1.CreateOptions{}); err != nil {
101 framework.Failf("unable to create test configMap %s: %v", configMap.Name, err)
102 }
103
104 pod := &v1.Pod{
105 ObjectMeta: metav1.ObjectMeta{
106 Name: "pod-configmaps-" + string(uuid.NewUUID()),
107 },
108 Spec: v1.PodSpec{
109 Containers: []v1.Container{
110 {
111 Name: "env-test",
112 Image: imageutils.GetE2EImage(imageutils.BusyBox),
113 Command: []string{"sh", "-c", "env"},
114 EnvFrom: []v1.EnvFromSource{
115 {
116 ConfigMapRef: &v1.ConfigMapEnvSource{LocalObjectReference: v1.LocalObjectReference{Name: name}},
117 },
118 {
119 Prefix: "p-",
120 ConfigMapRef: &v1.ConfigMapEnvSource{LocalObjectReference: v1.LocalObjectReference{Name: name}},
121 },
122 },
123 },
124 },
125 RestartPolicy: v1.RestartPolicyNever,
126 },
127 }
128
129 e2epodoutput.TestContainerOutput(ctx, f, "consume configMaps", pod, 0, []string{
130 "data-1=value-1", "data-2=value-2", "data-3=value-3",
131 "p-data-1=value-1", "p-data-2=value-2", "p-data-3=value-3",
132 })
133 })
134
135
140 framework.ConformanceIt("should fail to create ConfigMap with empty key", func(ctx context.Context) {
141 configMap, err := newConfigMapWithEmptyKey(ctx, f)
142 gomega.Expect(err).To(gomega.HaveOccurred(), "created configMap %q with empty key in namespace %q", configMap.Name, f.Namespace.Name)
143 })
144
145 ginkgo.It("should update ConfigMap successfully", func(ctx context.Context) {
146 name := "configmap-test-" + string(uuid.NewUUID())
147 configMap := newConfigMap(f, name)
148 ginkgo.By(fmt.Sprintf("Creating ConfigMap %v/%v", f.Namespace.Name, configMap.Name))
149 _, err := f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, configMap, metav1.CreateOptions{})
150 framework.ExpectNoError(err, "failed to create ConfigMap")
151
152 configMap.Data = map[string]string{
153 "data": "value",
154 }
155 ginkgo.By(fmt.Sprintf("Updating configMap %v/%v", f.Namespace.Name, configMap.Name))
156 _, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Update(ctx, configMap, metav1.UpdateOptions{})
157 framework.ExpectNoError(err, "failed to update ConfigMap")
158
159 configMapFromUpdate, err := f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Get(ctx, name, metav1.GetOptions{})
160 framework.ExpectNoError(err, "failed to get ConfigMap")
161 ginkgo.By(fmt.Sprintf("Verifying update of ConfigMap %v/%v", f.Namespace.Name, configMap.Name))
162 gomega.Expect(configMapFromUpdate.Data).To(gomega.Equal(configMap.Data))
163 })
164
165
171 framework.ConformanceIt("should run through a ConfigMap lifecycle", func(ctx context.Context) {
172 testNamespaceName := f.Namespace.Name
173 testConfigMapName := "test-configmap" + string(uuid.NewUUID())
174
175 testConfigMap := v1.ConfigMap{
176 ObjectMeta: metav1.ObjectMeta{
177 Name: testConfigMapName,
178 Labels: map[string]string{
179 "test-configmap-static": "true",
180 },
181 },
182 Data: map[string]string{
183 "valueName": "value",
184 },
185 }
186
187 ginkgo.By("creating a ConfigMap")
188 _, err := f.ClientSet.CoreV1().ConfigMaps(testNamespaceName).Create(ctx, &testConfigMap, metav1.CreateOptions{})
189 framework.ExpectNoError(err, "failed to create ConfigMap")
190
191 ginkgo.By("fetching the ConfigMap")
192 configMap, err := f.ClientSet.CoreV1().ConfigMaps(testNamespaceName).Get(ctx, testConfigMapName, metav1.GetOptions{})
193 framework.ExpectNoError(err, "failed to get ConfigMap")
194 gomega.Expect(configMap.Data["valueName"]).To(gomega.Equal(testConfigMap.Data["valueName"]))
195 gomega.Expect(configMap.Labels["test-configmap-static"]).To(gomega.Equal(testConfigMap.Labels["test-configmap-static"]))
196
197 configMapPatchPayload, err := json.Marshal(v1.ConfigMap{
198 ObjectMeta: metav1.ObjectMeta{
199 Labels: map[string]string{
200 "test-configmap": "patched",
201 },
202 },
203 Data: map[string]string{
204 "valueName": "value1",
205 },
206 })
207 framework.ExpectNoError(err, "failed to marshal patch data")
208
209 ginkgo.By("patching the ConfigMap")
210 _, err = f.ClientSet.CoreV1().ConfigMaps(testNamespaceName).Patch(ctx, testConfigMapName, types.StrategicMergePatchType, []byte(configMapPatchPayload), metav1.PatchOptions{})
211 framework.ExpectNoError(err, "failed to patch ConfigMap")
212
213 ginkgo.By("listing all ConfigMaps in all namespaces with a label selector")
214 configMapList, err := f.ClientSet.CoreV1().ConfigMaps("").List(ctx, metav1.ListOptions{
215 LabelSelector: "test-configmap=patched",
216 })
217 framework.ExpectNoError(err, "failed to list ConfigMaps with LabelSelector")
218 testConfigMapFound := false
219 for _, cm := range configMapList.Items {
220 if cm.ObjectMeta.Name == testConfigMap.ObjectMeta.Name &&
221 cm.ObjectMeta.Namespace == testNamespaceName &&
222 cm.ObjectMeta.Labels["test-configmap-static"] == testConfigMap.ObjectMeta.Labels["test-configmap-static"] &&
223 cm.ObjectMeta.Labels["test-configmap"] == "patched" &&
224 cm.Data["valueName"] == "value1" {
225 testConfigMapFound = true
226 break
227 }
228 }
229 if !testConfigMapFound {
230 framework.Failf("failed to find ConfigMap %s/%s by label selector", testNamespaceName, testConfigMap.ObjectMeta.Name)
231 }
232
233 ginkgo.By("deleting the ConfigMap by collection with a label selector")
234 err = f.ClientSet.CoreV1().ConfigMaps(testNamespaceName).DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{
235 LabelSelector: "test-configmap-static=true",
236 })
237 framework.ExpectNoError(err, "failed to delete ConfigMap collection with LabelSelector")
238
239 ginkgo.By("listing all ConfigMaps in test namespace")
240 configMapList, err = f.ClientSet.CoreV1().ConfigMaps(testNamespaceName).List(ctx, metav1.ListOptions{
241 LabelSelector: "test-configmap-static=true",
242 })
243 framework.ExpectNoError(err, "failed to list ConfigMap by LabelSelector")
244 gomega.Expect(configMapList.Items).To(gomega.BeEmpty(), "ConfigMap is still present after being deleted by collection")
245 })
246
247
253 framework.It("should be consumable as environment variable names when configmap keys start with a digit",
254 feature.RelaxedEnvironmentVariableValidation, func(ctx context.Context) {
255 name := "configmap-test-" + string(uuid.NewUUID())
256 configMap := newConfigMap(f, name)
257 ginkgo.By(fmt.Sprintf("Creating configMap %v/%v", f.Namespace.Name, configMap.Name))
258 var err error
259 if configMap, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, configMap, metav1.CreateOptions{}); err != nil {
260 framework.Failf("unable to create test configMap %s: %v", configMap.Name, err)
261 }
262
263 pod := &v1.Pod{
264 ObjectMeta: metav1.ObjectMeta{
265 Name: "pod-configmaps-" + string(uuid.NewUUID()),
266 },
267 Spec: v1.PodSpec{
268 Containers: []v1.Container{
269 {
270 Name: "env-test",
271 Image: imageutils.GetE2EImage(imageutils.BusyBox),
272 Command: []string{"sh", "-c", "env"},
273 EnvFrom: []v1.EnvFromSource{
274 {
275 ConfigMapRef: &v1.ConfigMapEnvSource{LocalObjectReference: v1.LocalObjectReference{Name: name}},
276 },
277 {
278
279 Prefix: "1-",
280 ConfigMapRef: &v1.ConfigMapEnvSource{LocalObjectReference: v1.LocalObjectReference{Name: name}},
281 },
282 },
283 },
284 },
285 RestartPolicy: v1.RestartPolicyNever,
286 },
287 }
288
289 e2epodoutput.TestContainerOutput(ctx, f, "consume configMaps", pod, 0, []string{
290 "data-1=value-1", "data-2=value-2", "data-3=value-3",
291 "1-data-1=value-1", "1-data-2=value-2", "1-data-3=value-3",
292 })
293 })
294 })
295
296 func newConfigMap(f *framework.Framework, name string) *v1.ConfigMap {
297 return &v1.ConfigMap{
298 ObjectMeta: metav1.ObjectMeta{
299 Namespace: f.Namespace.Name,
300 Name: name,
301 },
302 Data: map[string]string{
303 "data-1": "value-1",
304 "data-2": "value-2",
305 "data-3": "value-3",
306 },
307 }
308 }
309
310 func newConfigMapWithEmptyKey(ctx context.Context, f *framework.Framework) (*v1.ConfigMap, error) {
311 name := "configmap-test-emptyKey-" + string(uuid.NewUUID())
312 configMap := &v1.ConfigMap{
313 ObjectMeta: metav1.ObjectMeta{
314 Namespace: f.Namespace.Name,
315 Name: name,
316 },
317 Data: map[string]string{
318 "": "value-1",
319 },
320 }
321
322 ginkgo.By(fmt.Sprintf("Creating configMap that has name %s", configMap.Name))
323 return f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, configMap, metav1.CreateOptions{})
324 }
325
View as plain text