mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-31 07:20:13 +00:00
Add support for ConfigMap keys in env vars
This commit is contained in:
parent
c059dfdb9b
commit
6cfd101251
@ -715,9 +715,12 @@ type EnvVar struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EnvVarSource represents a source for the value of an EnvVar.
|
// EnvVarSource represents a source for the value of an EnvVar.
|
||||||
|
// Only one of its fields may be set.
|
||||||
type EnvVarSource struct {
|
type EnvVarSource struct {
|
||||||
// Required: Selects a field of the pod; only name and namespace are supported.
|
// Selects a field of the pod; only name and namespace are supported.
|
||||||
FieldRef *ObjectFieldSelector `json:"fieldRef"`
|
FieldRef *ObjectFieldSelector `json:"fieldRef,omitempty"`
|
||||||
|
// Selects a key of a ConfigMap.
|
||||||
|
ConfigMapKeyRef *ConfigMapKeySelector `json:"configMapKeyRef,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ObjectFieldSelector selects an APIVersioned field of an object.
|
// ObjectFieldSelector selects an APIVersioned field of an object.
|
||||||
@ -730,6 +733,14 @@ type ObjectFieldSelector struct {
|
|||||||
FieldPath string `json:"fieldPath"`
|
FieldPath string `json:"fieldPath"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Selects a key from a ConfigMap.
|
||||||
|
type ConfigMapKeySelector struct {
|
||||||
|
// The ConfigMap to select from.
|
||||||
|
LocalObjectReference `json:",inline"`
|
||||||
|
// The key to select.
|
||||||
|
Key string `json:"key"`
|
||||||
|
}
|
||||||
|
|
||||||
// HTTPGetAction describes an action based on HTTP Get requests.
|
// HTTPGetAction describes an action based on HTTP Get requests.
|
||||||
type HTTPGetAction struct {
|
type HTTPGetAction struct {
|
||||||
// Optional: Path to access on the HTTP server.
|
// Optional: Path to access on the HTTP server.
|
||||||
|
@ -843,8 +843,10 @@ type EnvVar struct {
|
|||||||
|
|
||||||
// EnvVarSource represents a source for the value of an EnvVar.
|
// EnvVarSource represents a source for the value of an EnvVar.
|
||||||
type EnvVarSource struct {
|
type EnvVarSource struct {
|
||||||
// Selects a field of the pod. Only name and namespace are supported.
|
// Selects a field of the pod; only name and namespace are supported.
|
||||||
FieldRef *ObjectFieldSelector `json:"fieldRef"`
|
FieldRef *ObjectFieldSelector `json:"fieldRef,omitempty"`
|
||||||
|
// Selects a key of a ConfigMap.
|
||||||
|
ConfigMapKeyRef *ConfigMapKeySelector `json:"configMapKeyRef,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ObjectFieldSelector selects an APIVersioned field of an object.
|
// ObjectFieldSelector selects an APIVersioned field of an object.
|
||||||
@ -855,6 +857,14 @@ type ObjectFieldSelector struct {
|
|||||||
FieldPath string `json:"fieldPath"`
|
FieldPath string `json:"fieldPath"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Selects a key from a ConfigMap.
|
||||||
|
type ConfigMapKeySelector struct {
|
||||||
|
// The ConfigMap to select from.
|
||||||
|
LocalObjectReference `json:",inline"`
|
||||||
|
// The key to select.
|
||||||
|
Key string `json:"key"`
|
||||||
|
}
|
||||||
|
|
||||||
// HTTPGetAction describes an action based on HTTP Get requests.
|
// HTTPGetAction describes an action based on HTTP Get requests.
|
||||||
type HTTPGetAction struct {
|
type HTTPGetAction struct {
|
||||||
// Path to access on the HTTP server.
|
// Path to access on the HTTP server.
|
||||||
|
@ -968,6 +968,9 @@ func validateEnvVarValueFrom(ev api.EnvVar, fldPath *field.Path) field.ErrorList
|
|||||||
case ev.ValueFrom.FieldRef != nil:
|
case ev.ValueFrom.FieldRef != nil:
|
||||||
numSources++
|
numSources++
|
||||||
allErrs = append(allErrs, validateObjectFieldSelector(ev.ValueFrom.FieldRef, &validFieldPathExpressionsEnv, fldPath.Child("fieldRef"))...)
|
allErrs = append(allErrs, validateObjectFieldSelector(ev.ValueFrom.FieldRef, &validFieldPathExpressionsEnv, fldPath.Child("fieldRef"))...)
|
||||||
|
case ev.ValueFrom.ConfigMapKeyRef != nil:
|
||||||
|
numSources++
|
||||||
|
allErrs = append(allErrs, validateConfigMapKeySelector(ev.ValueFrom.ConfigMapKeyRef, fldPath.Child("configMapKeyRef"))...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(ev.Value) != 0 && numSources != 0 {
|
if len(ev.Value) != 0 && numSources != 0 {
|
||||||
@ -996,6 +999,21 @@ func validateObjectFieldSelector(fs *api.ObjectFieldSelector, expressions *sets.
|
|||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateConfigMapKeySelector(s *api.ConfigMapKeySelector, fldPath *field.Path) field.ErrorList {
|
||||||
|
allErrs := field.ErrorList{}
|
||||||
|
|
||||||
|
if len(s.Name) == 0 {
|
||||||
|
allErrs = append(allErrs, field.Required(fldPath.Child("name"), ""))
|
||||||
|
}
|
||||||
|
if len(s.Key) == 0 {
|
||||||
|
allErrs = append(allErrs, field.Required(fldPath.Child("key"), ""))
|
||||||
|
} else if !IsSecretKey(s.Key) {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fldPath.Child("key"), s.Key, fmt.Sprintf("must have at most %d characters and match regex %s", validation.DNS1123SubdomainMaxLength, SecretKeyFmt)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
|
||||||
func validateVolumeMounts(mounts []api.VolumeMount, volumes sets.String, fldPath *field.Path) field.ErrorList {
|
func validateVolumeMounts(mounts []api.VolumeMount, volumes sets.String, fldPath *field.Path) field.ErrorList {
|
||||||
allErrs := field.ErrorList{}
|
allErrs := field.ErrorList{}
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api/resource"
|
"k8s.io/kubernetes/pkg/api/resource"
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/api/validation"
|
"k8s.io/kubernetes/pkg/api/validation"
|
||||||
|
apiextensions "k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
"k8s.io/kubernetes/pkg/client/cache"
|
"k8s.io/kubernetes/pkg/client/cache"
|
||||||
"k8s.io/kubernetes/pkg/client/record"
|
"k8s.io/kubernetes/pkg/client/record"
|
||||||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||||
@ -1391,9 +1392,11 @@ func (kl *Kubelet) makeEnvironmentVariables(pod *api.Pod, container *api.Contain
|
|||||||
// b. If a source is defined for an environment variable, resolve the source
|
// b. If a source is defined for an environment variable, resolve the source
|
||||||
// 2. Create the container's environment in the order variables are declared
|
// 2. Create the container's environment in the order variables are declared
|
||||||
// 3. Add remaining service environment vars
|
// 3. Add remaining service environment vars
|
||||||
|
var (
|
||||||
tmpEnv := make(map[string]string)
|
tmpEnv = make(map[string]string)
|
||||||
mappingFunc := expansion.MappingFuncFor(tmpEnv, serviceEnv)
|
configMaps = make(map[string]*apiextensions.ConfigMap)
|
||||||
|
mappingFunc = expansion.MappingFuncFor(tmpEnv, serviceEnv)
|
||||||
|
)
|
||||||
for _, envVar := range container.Env {
|
for _, envVar := range container.Env {
|
||||||
// Accesses apiserver+Pods.
|
// Accesses apiserver+Pods.
|
||||||
// So, the master may set service env vars, or kubelet may. In case both are doing
|
// So, the master may set service env vars, or kubelet may. In case both are doing
|
||||||
@ -1406,11 +1409,28 @@ func (kl *Kubelet) makeEnvironmentVariables(pod *api.Pod, container *api.Contain
|
|||||||
if runtimeVal != "" {
|
if runtimeVal != "" {
|
||||||
// Step 1a: expand variable references
|
// Step 1a: expand variable references
|
||||||
runtimeVal = expansion.Expand(runtimeVal, mappingFunc)
|
runtimeVal = expansion.Expand(runtimeVal, mappingFunc)
|
||||||
} else if envVar.ValueFrom != nil && envVar.ValueFrom.FieldRef != nil {
|
} else if envVar.ValueFrom != nil {
|
||||||
// Step 1b: resolve alternate env var sources
|
// Step 1b: resolve alternate env var sources
|
||||||
runtimeVal, err = kl.podFieldSelectorRuntimeValue(envVar.ValueFrom.FieldRef, pod)
|
switch {
|
||||||
if err != nil {
|
case envVar.ValueFrom.FieldRef != nil:
|
||||||
return result, err
|
runtimeVal, err = kl.podFieldSelectorRuntimeValue(envVar.ValueFrom.FieldRef, pod)
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
case envVar.ValueFrom.ConfigMapKeyRef != nil:
|
||||||
|
name := envVar.ValueFrom.ConfigMapKeyRef.Name
|
||||||
|
key := envVar.ValueFrom.ConfigMapKeyRef.Key
|
||||||
|
configMap, ok := configMaps[name]
|
||||||
|
if !ok {
|
||||||
|
configMap, err = kl.kubeClient.Extensions().ConfigMaps(pod.Namespace).Get(name)
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
runtimeVal, ok = configMap.Data[key]
|
||||||
|
if !ok {
|
||||||
|
return result, fmt.Errorf("Couldn't find key %v in ConfigMap %v/%v", key, pod.Namespace, name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
91
test/e2e/configmap.go
Normal file
91
test/e2e/configmap.go
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package e2e
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
|
"k8s.io/kubernetes/pkg/util"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("ConfigMap", func() {
|
||||||
|
f := NewFramework("configmap")
|
||||||
|
|
||||||
|
It("should be consumable via environment variable [Conformance]", func() {
|
||||||
|
name := "configmap-test-" + string(util.NewUUID())
|
||||||
|
configMap := &extensions.ConfigMap{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Namespace: f.Namespace.Name,
|
||||||
|
Name: name,
|
||||||
|
},
|
||||||
|
Data: map[string]string{
|
||||||
|
"data-1": "value-1",
|
||||||
|
"data-2": "value-2",
|
||||||
|
"data-3": "value-3",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
By(fmt.Sprintf("Creating configMap %v/%v", f.Namespace.Name, configMap.Name))
|
||||||
|
defer func() {
|
||||||
|
By("Cleaning up the configMap")
|
||||||
|
if err := f.Client.Extensions().ConfigMaps(f.Namespace.Name).Delete(configMap.Name); err != nil {
|
||||||
|
Failf("unable to delete configMap %v: %v", configMap.Name, err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
var err error
|
||||||
|
if configMap, err = f.Client.Extensions().ConfigMaps(f.Namespace.Name).Create(configMap); err != nil {
|
||||||
|
Failf("unable to create test configMap %s: %v", configMap.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pod := &api.Pod{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "pod-configmaps-" + string(util.NewUUID()),
|
||||||
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
Containers: []api.Container{
|
||||||
|
{
|
||||||
|
Name: "env-test",
|
||||||
|
Image: "gcr.io/google_containers/busybox",
|
||||||
|
Command: []string{"sh", "-c", "env"},
|
||||||
|
Env: []api.EnvVar{
|
||||||
|
{
|
||||||
|
Name: "CONFIG_DATA_1",
|
||||||
|
ValueFrom: &api.EnvVarSource{
|
||||||
|
ConfigMapKeyRef: &api.ConfigMapKeySelector{
|
||||||
|
LocalObjectReference: api.LocalObjectReference{
|
||||||
|
Name: name,
|
||||||
|
},
|
||||||
|
Key: "data-1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
RestartPolicy: api.RestartPolicyNever,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
testContainerOutput("consume configMaps", f.Client, pod, 0, []string{
|
||||||
|
"CONFIG_DATA_1=value-1",
|
||||||
|
}, f.Namespace.Name)
|
||||||
|
})
|
||||||
|
})
|
Loading…
Reference in New Issue
Block a user