...

Source file src/k8s.io/kubernetes/test/e2e/common/node/configmap.go

Documentation: k8s.io/kubernetes/test/e2e/common/node

     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/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  	/*
    43  		Release: v1.9
    44  		Testname: ConfigMap, from environment field
    45  		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.
    46  	*/
    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  	/*
    91  		Release: v1.9
    92  		Testname: ConfigMap, from environment variables
    93  		Description: Create a Pod with a environment source from ConfigMap. All ConfigMap values MUST be available as environment variables in the container.
    94  	*/
    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  	/*
   136  	   Release: v1.14
   137  	   Testname: ConfigMap, with empty-key
   138  	   Description: Attempt to create a ConfigMap with an empty key. The creation MUST fail.
   139  	*/
   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  	/*
   166  	   Release: v1.19
   167  	   Testname: ConfigMap lifecycle
   168  	   Description: Attempt to create a ConfigMap. Patch the created ConfigMap. Fetching the ConfigMap MUST reflect changes.
   169  	   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.
   170  	*/
   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  	/*
   248  		Release: v1.30
   249  		Testname: ConfigMap, from environment field
   250  		Description: Create a Pod with an environment variable value set using a value from ConfigMap.
   251  		Allows users to use envFrom to set prefix starting with a digit as environment variable names.
   252  	*/
   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  									// prefix start with a digit can be consumed as environment variables.
   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