mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 19:01:49 +00:00
ConfigMaps populate environment variables
This commit is contained in:
parent
63eec9608d
commit
2d803afc98
@ -376,6 +376,17 @@ func FuzzerFor(t *testing.T, version schema.GroupVersion, src rand.Source) *fuzz
|
||||
ev.ValueFrom.FieldRef.FieldPath = c.RandString()
|
||||
}
|
||||
},
|
||||
func(ev *api.EnvFromSource, c fuzz.Continue) {
|
||||
if c.RandBool() {
|
||||
ev.Prefix = "p_"
|
||||
}
|
||||
if c.RandBool() {
|
||||
c.Fuzz(&ev.ConfigMapRef)
|
||||
}
|
||||
},
|
||||
func(cm *api.ConfigMapEnvSource, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(cm) // fuzz self without calling this function again
|
||||
},
|
||||
func(sc *api.SecurityContext, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(sc) // fuzz self without calling this function again
|
||||
if c.RandBool() {
|
||||
|
@ -1133,6 +1133,26 @@ type SecretKeySelector struct {
|
||||
Key string
|
||||
}
|
||||
|
||||
// EnvFromSource represents the source of a set of ConfigMaps
|
||||
type EnvFromSource struct {
|
||||
// An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER.
|
||||
// +optional
|
||||
Prefix string
|
||||
// The ConfigMap to select from.
|
||||
//+optional
|
||||
ConfigMapRef *ConfigMapEnvSource
|
||||
}
|
||||
|
||||
// ConfigMapEnvSource selects a ConfigMap to populate the environment
|
||||
// variables with.
|
||||
//
|
||||
// The contents of the target ConfigMap's Data field will represent the
|
||||
// key-value pairs as environment variables.
|
||||
type ConfigMapEnvSource struct {
|
||||
// The ConfigMap to select from.
|
||||
LocalObjectReference
|
||||
}
|
||||
|
||||
// HTTPHeader describes a custom header to be used in HTTP probes
|
||||
type HTTPHeader struct {
|
||||
// The header field name
|
||||
@ -1274,6 +1294,14 @@ type Container struct {
|
||||
WorkingDir string
|
||||
// +optional
|
||||
Ports []ContainerPort
|
||||
// List of sources to populate environment variables in the container.
|
||||
// The keys defined within a source must be a C_IDENTIFIER. An invalid key
|
||||
// will prevent the container from starting. When a key exists in multiple
|
||||
// sources, the value associated with the last source will take precedence.
|
||||
// Values defined by an Env with a duplicate key will take precedence.
|
||||
// Cannot be updated.
|
||||
// +optional
|
||||
EnvFrom []EnvFromSource
|
||||
// +optional
|
||||
Env []EnvVar
|
||||
// Compute resource requirements.
|
||||
|
@ -1233,6 +1233,26 @@ type SecretKeySelector struct {
|
||||
Key string `json:"key" protobuf:"bytes,2,opt,name=key"`
|
||||
}
|
||||
|
||||
// EnvFromSource represents the source of a set of ConfigMaps
|
||||
type EnvFromSource struct {
|
||||
// An optional identifer to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER.
|
||||
// +optional
|
||||
Prefix string `json:"prefix,omitempty" protobuf:"bytes,1,opt,name=prefix"`
|
||||
// The ConfigMap to select from
|
||||
// +optional
|
||||
ConfigMapRef *ConfigMapEnvSource `json:"configMapRef,omitempty" protobuf:"bytes,2,opt,name=configMapRef"`
|
||||
}
|
||||
|
||||
// ConfigMapEnvSource selects a ConfigMap to populate the environment
|
||||
// variables with.
|
||||
//
|
||||
// The contents of the target ConfigMap's Data field will represent the
|
||||
// key-value pairs as environment variables.
|
||||
type ConfigMapEnvSource struct {
|
||||
// The ConfigMap to select from.
|
||||
LocalObjectReference `json:",inline" protobuf:"bytes,1,opt,name=localObjectReference"`
|
||||
}
|
||||
|
||||
// HTTPHeader describes a custom header to be used in HTTP probes
|
||||
type HTTPHeader struct {
|
||||
// The header field name
|
||||
@ -1409,6 +1429,14 @@ type Container struct {
|
||||
// Cannot be updated.
|
||||
// +optional
|
||||
Ports []ContainerPort `json:"ports,omitempty" patchStrategy:"merge" patchMergeKey:"containerPort" protobuf:"bytes,6,rep,name=ports"`
|
||||
// List of sources to populate environment variables in the container.
|
||||
// The keys defined within a source must be a C_IDENTIFIER. An invalid key
|
||||
// will prevent the container from starting. When a key exists in multiple
|
||||
// sources, the value associated with the last source will take precedence.
|
||||
// Values defined by an Env with a duplicate key will take precedence.
|
||||
// Cannot be updated.
|
||||
// +optional
|
||||
EnvFrom []EnvFromSource `json:"envFrom,omitempty" protobuf:"bytes,19,rep,name=envFrom"`
|
||||
// List of environment variables to set in the container.
|
||||
// Cannot be updated.
|
||||
// +optional
|
||||
|
@ -1435,6 +1435,30 @@ func validateContainerResourceFieldSelector(fs *api.ResourceFieldSelector, expre
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateEnvFrom(vars []api.EnvFromSource, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
for i, ev := range vars {
|
||||
idxPath := fldPath.Index(i)
|
||||
if len(ev.Prefix) > 0 {
|
||||
for _, msg := range validation.IsCIdentifier(ev.Prefix) {
|
||||
allErrs = append(allErrs, field.Invalid(idxPath.Child("prefix"), ev.Prefix, msg))
|
||||
}
|
||||
}
|
||||
if ev.ConfigMapRef != nil {
|
||||
allErrs = append(allErrs, validateConfigMapEnvSource(ev.ConfigMapRef, idxPath.Child("configMapRef"))...)
|
||||
}
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateConfigMapEnvSource(configMapSource *api.ConfigMapEnvSource, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if len(configMapSource.Name) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("name"), ""))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
var validContainerResourceDivisorForCPU = sets.NewString("1m", "1")
|
||||
var validContainerResourceDivisorForMemory = sets.NewString("1", "1k", "1M", "1G", "1T", "1P", "1E", "1Ki", "1Mi", "1Gi", "1Ti", "1Pi", "1Ei")
|
||||
|
||||
|
@ -2719,6 +2719,65 @@ func TestValidateEnv(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateEnvFrom(t *testing.T) {
|
||||
successCase := []api.EnvFromSource{
|
||||
{
|
||||
ConfigMapRef: &api.ConfigMapEnvSource{
|
||||
LocalObjectReference: api.LocalObjectReference{Name: "abc"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Prefix: "pre_",
|
||||
ConfigMapRef: &api.ConfigMapEnvSource{
|
||||
LocalObjectReference: api.LocalObjectReference{Name: "abc"},
|
||||
},
|
||||
},
|
||||
}
|
||||
if errs := validateEnvFrom(successCase, field.NewPath("field")); len(errs) != 0 {
|
||||
t.Errorf("expected success: %v", errs)
|
||||
}
|
||||
|
||||
errorCases := []struct {
|
||||
name string
|
||||
envs []api.EnvFromSource
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
name: "zero-length name",
|
||||
envs: []api.EnvFromSource{
|
||||
{
|
||||
ConfigMapRef: &api.ConfigMapEnvSource{
|
||||
LocalObjectReference: api.LocalObjectReference{Name: ""}},
|
||||
},
|
||||
},
|
||||
expectedError: "field[0].configMapRef.name: Required value",
|
||||
},
|
||||
{
|
||||
name: "invalid prefix",
|
||||
envs: []api.EnvFromSource{
|
||||
{
|
||||
Prefix: "a.b",
|
||||
ConfigMapRef: &api.ConfigMapEnvSource{
|
||||
LocalObjectReference: api.LocalObjectReference{Name: "abc"}},
|
||||
},
|
||||
},
|
||||
expectedError: `field[0].prefix: Invalid value: "a.b": ` + idErrMsg,
|
||||
},
|
||||
}
|
||||
for _, tc := range errorCases {
|
||||
if errs := validateEnvFrom(tc.envs, field.NewPath("field")); len(errs) == 0 {
|
||||
t.Errorf("expected failure for %s", tc.name)
|
||||
} else {
|
||||
for i := range errs {
|
||||
str := errs[i].Error()
|
||||
if str != "" && !strings.Contains(str, tc.expectedError) {
|
||||
t.Errorf("%s: expected error detail either empty or %q, got %q", tc.name, tc.expectedError, str)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateVolumeMounts(t *testing.T) {
|
||||
volumes := sets.NewString("abc", "123", "abc-123")
|
||||
|
||||
|
@ -890,6 +890,7 @@ func describeContainers(label string, containers []api.Container, containerStatu
|
||||
}
|
||||
describeContainerProbe(container, w)
|
||||
describeContainerVolumes(container, w)
|
||||
describeContainerEnvFrom(container, resolverFn, w)
|
||||
describeContainerEnvVars(container, resolverFn, w)
|
||||
}
|
||||
}
|
||||
@ -1012,6 +1013,7 @@ func describeContainerEnvVars(container api.Container, resolverFn EnvVarResolver
|
||||
none = "\t<none>"
|
||||
}
|
||||
w.Write(LEVEL_2, "Environment Variables:%s\n", none)
|
||||
|
||||
for _, e := range container.Env {
|
||||
if e.ValueFrom == nil {
|
||||
w.Write(LEVEL_3, "%s:\t%s\n", e.Name, e.Value)
|
||||
@ -1043,6 +1045,22 @@ func describeContainerEnvVars(container api.Container, resolverFn EnvVarResolver
|
||||
}
|
||||
}
|
||||
|
||||
func describeContainerEnvFrom(container api.Container, resolverFn EnvVarResolverFunc, w *PrefixWriter) {
|
||||
none := ""
|
||||
if len(container.EnvFrom) == 0 {
|
||||
none = "\t<none>"
|
||||
}
|
||||
w.Write(LEVEL_2, "Environment Variables from:%s\n", none)
|
||||
|
||||
for _, e := range container.EnvFrom {
|
||||
if len(e.Prefix) == 0 {
|
||||
w.Write(LEVEL_3, "%s\tConfigMap\n", e.ConfigMapRef.Name)
|
||||
} else {
|
||||
w.Write(LEVEL_3, "%s\tConfigMap with prefix '%s'\n", e.ConfigMapRef.Name, e.Prefix)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DescribeProbe is exported for consumers in other API groups that have probes
|
||||
func DescribeProbe(probe *api.Probe) string {
|
||||
attrs := fmt.Sprintf("delay=%ds timeout=%ds period=%ds #success=%d #failure=%d", probe.InitialDelaySeconds, probe.TimeoutSeconds, probe.PeriodSeconds, probe.SuccessThreshold, probe.FailureThreshold)
|
||||
|
@ -288,13 +288,22 @@ func TestDescribeContainers(t *testing.T) {
|
||||
},
|
||||
// Env
|
||||
{
|
||||
container: api.Container{Name: "test", Image: "image", Env: []api.EnvVar{{Name: "envname", Value: "xyz"}}},
|
||||
container: api.Container{Name: "test", Image: "image", Env: []api.EnvVar{{Name: "envname", Value: "xyz"}}, EnvFrom: []api.EnvFromSource{{ConfigMapRef: &api.ConfigMapEnvSource{LocalObjectReference: api.LocalObjectReference{Name: "a123"}}}}},
|
||||
status: api.ContainerStatus{
|
||||
Name: "test",
|
||||
Ready: true,
|
||||
RestartCount: 7,
|
||||
},
|
||||
expectedElements: []string{"test", "State", "Waiting", "Ready", "True", "Restart Count", "7", "Image", "image", "envname", "xyz"},
|
||||
expectedElements: []string{"test", "State", "Waiting", "Ready", "True", "Restart Count", "7", "Image", "image", "envname", "xyz", "a123\tConfigMap"},
|
||||
},
|
||||
{
|
||||
container: api.Container{Name: "test", Image: "image", Env: []api.EnvVar{{Name: "envname", Value: "xyz"}}, EnvFrom: []api.EnvFromSource{{Prefix: "p_", ConfigMapRef: &api.ConfigMapEnvSource{LocalObjectReference: api.LocalObjectReference{Name: "a123"}}}}},
|
||||
status: api.ContainerStatus{
|
||||
Name: "test",
|
||||
Ready: true,
|
||||
RestartCount: 7,
|
||||
},
|
||||
expectedElements: []string{"test", "State", "Waiting", "Ready", "True", "Restart Count", "7", "Image", "image", "envname", "xyz", "a123\tConfigMap with prefix 'p_'"},
|
||||
},
|
||||
// Command
|
||||
{
|
||||
|
@ -414,6 +414,47 @@ func (kl *Kubelet) makeEnvironmentVariables(pod *v1.Pod, container *v1.Container
|
||||
return result, err
|
||||
}
|
||||
|
||||
var (
|
||||
configMaps = make(map[string]*v1.ConfigMap)
|
||||
tmpEnv = make(map[string]string)
|
||||
)
|
||||
|
||||
// Env will override EnvFrom variables.
|
||||
// Process EnvFrom first then allow Env to replace existing values.
|
||||
for _, envFrom := range container.EnvFrom {
|
||||
if envFrom.ConfigMapRef != nil {
|
||||
name := envFrom.ConfigMapRef.Name
|
||||
configMap, ok := configMaps[name]
|
||||
if !ok {
|
||||
if kl.kubeClient == nil {
|
||||
return result, fmt.Errorf("Couldn't get configMap %v/%v, no kubeClient defined", pod.Namespace, name)
|
||||
}
|
||||
configMap, err = kl.kubeClient.Core().ConfigMaps(pod.Namespace).Get(name, metav1.GetOptions{})
|
||||
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
configMaps[name] = configMap
|
||||
}
|
||||
for k, v := range configMap.Data {
|
||||
if errMsgs := utilvalidation.IsCIdentifier(k); len(errMsgs) != 0 {
|
||||
return result, fmt.Errorf("Invalid environment variable name, %v, from configmap %v/%v: %s", k, pod.Namespace, name, errMsgs[0])
|
||||
}
|
||||
|
||||
if len(envFrom.Prefix) > 0 {
|
||||
k = envFrom.Prefix + k
|
||||
}
|
||||
// Accesses apiserver+Pods.
|
||||
// So, the master may set service env vars, or kubelet may. In case both are doing
|
||||
// it, we delete the key from the kubelet-generated ones so we don't have duplicate
|
||||
// env vars.
|
||||
// TODO: remove this next line once all platforms use apiserver+Pods.
|
||||
delete(serviceEnv, k)
|
||||
tmpEnv[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Determine the final values of variables:
|
||||
//
|
||||
// 1. Determine the final value of each variable:
|
||||
@ -424,8 +465,6 @@ func (kl *Kubelet) makeEnvironmentVariables(pod *v1.Pod, container *v1.Container
|
||||
// 2. Create the container's environment in the order variables are declared
|
||||
// 3. Add remaining service environment vars
|
||||
var (
|
||||
tmpEnv = make(map[string]string)
|
||||
configMaps = make(map[string]*v1.ConfigMap)
|
||||
secrets = make(map[string]*v1.Secret)
|
||||
mappingFunc = expansion.MappingFuncFor(tmpEnv, serviceEnv)
|
||||
)
|
||||
@ -434,7 +473,7 @@ func (kl *Kubelet) makeEnvironmentVariables(pod *v1.Pod, container *v1.Container
|
||||
// So, the master may set service env vars, or kubelet may. In case both are doing
|
||||
// it, we delete the key from the kubelet-generated ones so we don't have duplicate
|
||||
// env vars.
|
||||
// TODO: remove this net line once all platforms use apiserver+Pods.
|
||||
// TODO: remove this next line once all platforms use apiserver+Pods.
|
||||
delete(serviceEnv, envVar.Name)
|
||||
|
||||
runtimeVal := envVar.Value
|
||||
@ -499,7 +538,11 @@ func (kl *Kubelet) makeEnvironmentVariables(pod *v1.Pod, container *v1.Container
|
||||
}
|
||||
|
||||
tmpEnv[envVar.Name] = runtimeVal
|
||||
result = append(result, kubecontainer.EnvVar{Name: envVar.Name, Value: tmpEnv[envVar.Name]})
|
||||
}
|
||||
|
||||
// Append the env vars
|
||||
for k, v := range tmpEnv {
|
||||
result = append(result, kubecontainer.EnvVar{Name: k, Value: v})
|
||||
}
|
||||
|
||||
// Append remaining service env vars.
|
||||
|
@ -268,7 +268,9 @@ func TestMakeEnvironmentVariables(t *testing.T) {
|
||||
container *v1.Container // the container to use
|
||||
masterServiceNs string // the namespace to read master service info from
|
||||
nilLister bool // whether the lister should be nil
|
||||
configMap *v1.ConfigMap // an optional ConfigMap to pull from
|
||||
expectedEnvs []kubecontainer.EnvVar // a set of expected environment vars
|
||||
expectedError bool // does the test fail
|
||||
}{
|
||||
{
|
||||
name: "api server = Y, kubelet = Y",
|
||||
@ -605,6 +607,132 @@ func TestMakeEnvironmentVariables(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "configmap",
|
||||
ns: "test1",
|
||||
container: &v1.Container{
|
||||
EnvFrom: []v1.EnvFromSource{
|
||||
{
|
||||
ConfigMapRef: &v1.ConfigMapEnvSource{LocalObjectReference: v1.LocalObjectReference{Name: "test-config-map"}},
|
||||
},
|
||||
{
|
||||
Prefix: "p_",
|
||||
ConfigMapRef: &v1.ConfigMapEnvSource{LocalObjectReference: v1.LocalObjectReference{Name: "test-config-map"}},
|
||||
},
|
||||
},
|
||||
Env: []v1.EnvVar{
|
||||
{
|
||||
Name: "TEST_LITERAL",
|
||||
Value: "test-test-test",
|
||||
},
|
||||
{
|
||||
Name: "EXPANSION_TEST",
|
||||
Value: "$(REPLACE_ME)",
|
||||
},
|
||||
{
|
||||
Name: "DUPE_TEST",
|
||||
Value: "ENV_VAR",
|
||||
},
|
||||
},
|
||||
},
|
||||
masterServiceNs: "nothing",
|
||||
nilLister: false,
|
||||
configMap: &v1.ConfigMap{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "test1",
|
||||
Name: "test-configmap",
|
||||
},
|
||||
Data: map[string]string{
|
||||
"REPLACE_ME": "FROM_CONFIG_MAP",
|
||||
"DUPE_TEST": "CONFIG_MAP",
|
||||
},
|
||||
},
|
||||
expectedEnvs: []kubecontainer.EnvVar{
|
||||
{
|
||||
Name: "TEST_LITERAL",
|
||||
Value: "test-test-test",
|
||||
},
|
||||
{
|
||||
Name: "TEST_SERVICE_HOST",
|
||||
Value: "1.2.3.3",
|
||||
},
|
||||
{
|
||||
Name: "TEST_SERVICE_PORT",
|
||||
Value: "8083",
|
||||
},
|
||||
{
|
||||
Name: "TEST_PORT",
|
||||
Value: "tcp://1.2.3.3:8083",
|
||||
},
|
||||
{
|
||||
Name: "TEST_PORT_8083_TCP",
|
||||
Value: "tcp://1.2.3.3:8083",
|
||||
},
|
||||
{
|
||||
Name: "TEST_PORT_8083_TCP_PROTO",
|
||||
Value: "tcp",
|
||||
},
|
||||
{
|
||||
Name: "TEST_PORT_8083_TCP_PORT",
|
||||
Value: "8083",
|
||||
},
|
||||
{
|
||||
Name: "TEST_PORT_8083_TCP_ADDR",
|
||||
Value: "1.2.3.3",
|
||||
},
|
||||
{
|
||||
Name: "REPLACE_ME",
|
||||
Value: "FROM_CONFIG_MAP",
|
||||
},
|
||||
{
|
||||
Name: "EXPANSION_TEST",
|
||||
Value: "FROM_CONFIG_MAP",
|
||||
},
|
||||
{
|
||||
Name: "DUPE_TEST",
|
||||
Value: "ENV_VAR",
|
||||
},
|
||||
{
|
||||
Name: "p_REPLACE_ME",
|
||||
Value: "FROM_CONFIG_MAP",
|
||||
},
|
||||
{
|
||||
Name: "p_DUPE_TEST",
|
||||
Value: "CONFIG_MAP",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "configmap_missing",
|
||||
ns: "test1",
|
||||
container: &v1.Container{
|
||||
EnvFrom: []v1.EnvFromSource{
|
||||
{ConfigMapRef: &v1.ConfigMapEnvSource{LocalObjectReference: v1.LocalObjectReference{Name: "test-config-map"}}},
|
||||
},
|
||||
},
|
||||
masterServiceNs: "nothing",
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "configmap_invalid_keys",
|
||||
ns: "test1",
|
||||
container: &v1.Container{
|
||||
EnvFrom: []v1.EnvFromSource{
|
||||
{ConfigMapRef: &v1.ConfigMapEnvSource{LocalObjectReference: v1.LocalObjectReference{Name: "test-config-map"}}},
|
||||
},
|
||||
},
|
||||
masterServiceNs: "nothing",
|
||||
configMap: &v1.ConfigMap{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "test1",
|
||||
Name: "test-configmap",
|
||||
},
|
||||
Data: map[string]string{
|
||||
"-1234": "abc",
|
||||
},
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
@ -617,6 +745,14 @@ func TestMakeEnvironmentVariables(t *testing.T) {
|
||||
kl.serviceLister = testServiceLister{services}
|
||||
}
|
||||
|
||||
testKubelet.fakeKubeClient.AddReactor("get", "configmaps", func(action core.Action) (bool, runtime.Object, error) {
|
||||
var err error
|
||||
if tc.configMap == nil {
|
||||
err = errors.New("no configmap defined")
|
||||
}
|
||||
return true, tc.configMap, err
|
||||
})
|
||||
|
||||
testPod := &v1.Pod{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: tc.ns,
|
||||
@ -630,11 +766,15 @@ func TestMakeEnvironmentVariables(t *testing.T) {
|
||||
podIP := "1.2.3.4"
|
||||
|
||||
result, err := kl.makeEnvironmentVariables(testPod, tc.container, podIP)
|
||||
assert.NoError(t, err, "[%s]", tc.name)
|
||||
if tc.expectedError {
|
||||
assert.Error(t, err, tc.name)
|
||||
} else {
|
||||
assert.NoError(t, err, "[%s]", tc.name)
|
||||
|
||||
sort.Sort(envs(result))
|
||||
sort.Sort(envs(tc.expectedEnvs))
|
||||
assert.Equal(t, tc.expectedEnvs, result, "[%s] env entries", tc.name)
|
||||
sort.Sort(envs(result))
|
||||
sort.Sort(envs(tc.expectedEnvs))
|
||||
assert.Equal(t, tc.expectedEnvs, result, "[%s] env entries", tc.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,6 +196,46 @@ var _ = framework.KubeDescribe("ConfigMap", func() {
|
||||
})
|
||||
})
|
||||
|
||||
It("should be consumable via the environment [Conformance]", func() {
|
||||
name := "configmap-test-" + string(uuid.NewUUID())
|
||||
configMap := newEnvFromConfigMap(f, name)
|
||||
By(fmt.Sprintf("Creating configMap %v/%v", f.Namespace.Name, configMap.Name))
|
||||
var err error
|
||||
if configMap, err = f.ClientSet.Core().ConfigMaps(f.Namespace.Name).Create(configMap); err != nil {
|
||||
framework.Failf("unable to create test configMap %s: %v", configMap.Name, err)
|
||||
}
|
||||
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "pod-configmaps-" + string(uuid.NewUUID()),
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "env-test",
|
||||
Image: "gcr.io/google_containers/busybox:1.24",
|
||||
Command: []string{"sh", "-c", "env"},
|
||||
EnvFrom: []v1.EnvFromSource{
|
||||
{
|
||||
ConfigMapRef: &v1.ConfigMapEnvSource{LocalObjectReference: v1.LocalObjectReference{Name: name}},
|
||||
},
|
||||
{
|
||||
Prefix: "p_",
|
||||
ConfigMapRef: &v1.ConfigMapEnvSource{LocalObjectReference: v1.LocalObjectReference{Name: name}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
},
|
||||
}
|
||||
|
||||
f.TestContainerOutput("consume configMaps", pod, 0, []string{
|
||||
"data_1=value-1", "data_2=value-2", "data_3=value-3",
|
||||
"p_data_1=value-1", "p_data_2=value-2", "p_data_3=value-3",
|
||||
})
|
||||
})
|
||||
|
||||
It("should be consumable in multiple volumes in the same pod [Conformance]", func() {
|
||||
var (
|
||||
name = "configmap-test-volume-" + string(uuid.NewUUID())
|
||||
@ -283,6 +323,20 @@ func newConfigMap(f *framework.Framework, name string) *v1.ConfigMap {
|
||||
}
|
||||
}
|
||||
|
||||
func newEnvFromConfigMap(f *framework.Framework, name string) *v1.ConfigMap {
|
||||
return &v1.ConfigMap{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: f.Namespace.Name,
|
||||
Name: name,
|
||||
},
|
||||
Data: map[string]string{
|
||||
"data_1": "value-1",
|
||||
"data_2": "value-2",
|
||||
"data_3": "value-3",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func doConfigMapE2EWithoutMappings(f *framework.Framework, uid, fsGroup int64, defaultMode *int32) {
|
||||
var (
|
||||
name = "configmap-test-volume-" + string(uuid.NewUUID())
|
||||
|
Loading…
Reference in New Issue
Block a user