mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 06:27:05 +00:00
Secrets can populate environment variables
This commit is contained in:
parent
6e268e6f83
commit
13d693d220
@ -386,11 +386,16 @@ func FuzzerFor(t *testing.T, version schema.GroupVersion, src rand.Source) *fuzz
|
||||
}
|
||||
if c.RandBool() {
|
||||
c.Fuzz(&ev.ConfigMapRef)
|
||||
} else {
|
||||
c.Fuzz(&ev.SecretRef)
|
||||
}
|
||||
},
|
||||
func(cm *api.ConfigMapEnvSource, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(cm) // fuzz self without calling this function again
|
||||
},
|
||||
func(s *api.SecretEnvSource, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(s) // 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() {
|
||||
|
@ -1142,6 +1142,9 @@ type EnvFromSource struct {
|
||||
// The ConfigMap to select from.
|
||||
//+optional
|
||||
ConfigMapRef *ConfigMapEnvSource
|
||||
// The Secret to select from.
|
||||
//+optional
|
||||
SecretRef *SecretEnvSource
|
||||
}
|
||||
|
||||
// ConfigMapEnvSource selects a ConfigMap to populate the environment
|
||||
@ -1154,6 +1157,16 @@ type ConfigMapEnvSource struct {
|
||||
LocalObjectReference
|
||||
}
|
||||
|
||||
// SecretEnvSource selects a Secret to populate the environment
|
||||
// variables with.
|
||||
//
|
||||
// The contents of the target Secret's Data field will represent the
|
||||
// key-value pairs as environment variables.
|
||||
type SecretEnvSource struct {
|
||||
// The Secret to select from.
|
||||
LocalObjectReference
|
||||
}
|
||||
|
||||
// HTTPHeader describes a custom header to be used in HTTP probes
|
||||
type HTTPHeader struct {
|
||||
// The header field name
|
||||
|
@ -1243,6 +1243,9 @@ type EnvFromSource struct {
|
||||
// The ConfigMap to select from
|
||||
// +optional
|
||||
ConfigMapRef *ConfigMapEnvSource `json:"configMapRef,omitempty" protobuf:"bytes,2,opt,name=configMapRef"`
|
||||
// The Secret to select from
|
||||
// +optional
|
||||
SecretRef *SecretEnvSource `json:"secretRef,omitempty" protobuf:"bytes,3,opt,name=secretRef"`
|
||||
}
|
||||
|
||||
// ConfigMapEnvSource selects a ConfigMap to populate the environment
|
||||
@ -1255,6 +1258,16 @@ type ConfigMapEnvSource struct {
|
||||
LocalObjectReference `json:",inline" protobuf:"bytes,1,opt,name=localObjectReference"`
|
||||
}
|
||||
|
||||
// SecretEnvSource selects a Secret to populate the environment
|
||||
// variables with.
|
||||
//
|
||||
// The contents of the target Secret's Data field will represent the
|
||||
// key-value pairs as environment variables.
|
||||
type SecretEnvSource struct {
|
||||
// The Secret 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
|
||||
|
@ -1260,9 +1260,22 @@ func validateEnvFrom(vars []api.EnvFromSource, fldPath *field.Path) field.ErrorL
|
||||
allErrs = append(allErrs, field.Invalid(idxPath.Child("prefix"), ev.Prefix, msg))
|
||||
}
|
||||
}
|
||||
|
||||
numSources := 0
|
||||
if ev.ConfigMapRef != nil {
|
||||
numSources++
|
||||
allErrs = append(allErrs, validateConfigMapEnvSource(ev.ConfigMapRef, idxPath.Child("configMapRef"))...)
|
||||
}
|
||||
if ev.SecretRef != nil {
|
||||
numSources++
|
||||
allErrs = append(allErrs, validateSecretEnvSource(ev.SecretRef, idxPath.Child("secretRef"))...)
|
||||
}
|
||||
|
||||
if numSources == 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, "", "must specify one of: `configMapRef` or `secretRef`"))
|
||||
} else if numSources > 1 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, "", "may not have more than one field specified at a time"))
|
||||
}
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
@ -1275,6 +1288,14 @@ func validateConfigMapEnvSource(configMapSource *api.ConfigMapEnvSource, fldPath
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateSecretEnvSource(secretSource *api.SecretEnvSource, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if len(secretSource.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")
|
||||
|
||||
|
@ -2285,6 +2285,17 @@ func TestValidateEnvFrom(t *testing.T) {
|
||||
LocalObjectReference: api.LocalObjectReference{Name: "abc"},
|
||||
},
|
||||
},
|
||||
{
|
||||
SecretRef: &api.SecretEnvSource{
|
||||
LocalObjectReference: api.LocalObjectReference{Name: "abc"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Prefix: "pre_",
|
||||
SecretRef: &api.SecretEnvSource{
|
||||
LocalObjectReference: api.LocalObjectReference{Name: "abc"},
|
||||
},
|
||||
},
|
||||
}
|
||||
if errs := validateEnvFrom(successCase, field.NewPath("field")); len(errs) != 0 {
|
||||
t.Errorf("expected success: %v", errs)
|
||||
@ -2316,6 +2327,46 @@ func TestValidateEnvFrom(t *testing.T) {
|
||||
},
|
||||
expectedError: `field[0].prefix: Invalid value: "a.b": ` + idErrMsg,
|
||||
},
|
||||
{
|
||||
name: "zero-length name",
|
||||
envs: []api.EnvFromSource{
|
||||
{
|
||||
SecretRef: &api.SecretEnvSource{
|
||||
LocalObjectReference: api.LocalObjectReference{Name: ""}},
|
||||
},
|
||||
},
|
||||
expectedError: "field[0].secretRef.name: Required value",
|
||||
},
|
||||
{
|
||||
name: "invalid prefix",
|
||||
envs: []api.EnvFromSource{
|
||||
{
|
||||
Prefix: "a.b",
|
||||
SecretRef: &api.SecretEnvSource{
|
||||
LocalObjectReference: api.LocalObjectReference{Name: "abc"}},
|
||||
},
|
||||
},
|
||||
expectedError: `field[0].prefix: Invalid value: "a.b": ` + idErrMsg,
|
||||
},
|
||||
{
|
||||
name: "no refs",
|
||||
envs: []api.EnvFromSource{
|
||||
{},
|
||||
},
|
||||
expectedError: "field: Invalid value: \"\": must specify one of: `configMapRef` or `secretRef`",
|
||||
},
|
||||
{
|
||||
name: "multiple refs",
|
||||
envs: []api.EnvFromSource{
|
||||
{
|
||||
SecretRef: &api.SecretEnvSource{
|
||||
LocalObjectReference: api.LocalObjectReference{Name: "abc"}},
|
||||
ConfigMapRef: &api.ConfigMapEnvSource{
|
||||
LocalObjectReference: api.LocalObjectReference{Name: "abc"}},
|
||||
},
|
||||
},
|
||||
expectedError: "field: Invalid value: \"\": may not have more than one field specified at a time",
|
||||
},
|
||||
}
|
||||
for _, tc := range errorCases {
|
||||
if errs := validateEnvFrom(tc.envs, field.NewPath("field")); len(errs) == 0 {
|
||||
|
@ -1052,10 +1052,19 @@ func describeContainerEnvFrom(container api.Container, resolverFn EnvVarResolver
|
||||
w.Write(LEVEL_2, "Environment Variables from:%s\n", none)
|
||||
|
||||
for _, e := range container.EnvFrom {
|
||||
from := ""
|
||||
name := ""
|
||||
if e.ConfigMapRef != nil {
|
||||
from = "ConfigMap"
|
||||
name = e.ConfigMapRef.Name
|
||||
} else if e.SecretRef != nil {
|
||||
from = "Secret"
|
||||
name = e.SecretRef.Name
|
||||
}
|
||||
if len(e.Prefix) == 0 {
|
||||
w.Write(LEVEL_3, "%s\tConfigMap\n", e.ConfigMapRef.Name)
|
||||
w.Write(LEVEL_3, "%s\t%s\n", name, from)
|
||||
} else {
|
||||
w.Write(LEVEL_3, "%s\tConfigMap with prefix '%s'\n", e.ConfigMapRef.Name, e.Prefix)
|
||||
w.Write(LEVEL_3, "%s\t%s with prefix '%s'\n", name, from, e.Prefix)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -306,6 +306,24 @@ func TestDescribeContainers(t *testing.T) {
|
||||
},
|
||||
expectedElements: []string{"test", "State", "Waiting", "Ready", "True", "Restart Count", "7", "Image", "image", "envname", "xyz", "a123\tConfigMap with prefix 'p_'"},
|
||||
},
|
||||
{
|
||||
container: api.Container{Name: "test", Image: "image", Env: []api.EnvVar{{Name: "envname", Value: "xyz"}}, EnvFrom: []api.EnvFromSource{{SecretRef: &api.SecretEnvSource{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\tSecret"},
|
||||
},
|
||||
{
|
||||
container: api.Container{Name: "test", Image: "image", Env: []api.EnvVar{{Name: "envname", Value: "xyz"}}, EnvFrom: []api.EnvFromSource{{Prefix: "p_", SecretRef: &api.SecretEnvSource{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\tSecret with prefix 'p_'"},
|
||||
},
|
||||
// Command
|
||||
{
|
||||
container: api.Container{Name: "test", Image: "image", Command: []string{"sleep", "1000"}},
|
||||
|
@ -418,13 +418,15 @@ func (kl *Kubelet) makeEnvironmentVariables(pod *v1.Pod, container *v1.Container
|
||||
|
||||
var (
|
||||
configMaps = make(map[string]*v1.ConfigMap)
|
||||
secrets = make(map[string]*v1.Secret)
|
||||
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 {
|
||||
switch {
|
||||
case envFrom.ConfigMapRef != nil:
|
||||
name := envFrom.ConfigMapRef.Name
|
||||
configMap, ok := configMaps[name]
|
||||
if !ok {
|
||||
@ -432,12 +434,12 @@ func (kl *Kubelet) makeEnvironmentVariables(pod *v1.Pod, container *v1.Container
|
||||
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 len(envFrom.Prefix) > 0 {
|
||||
k = envFrom.Prefix + k
|
||||
@ -445,14 +447,31 @@ func (kl *Kubelet) makeEnvironmentVariables(pod *v1.Pod, container *v1.Container
|
||||
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])
|
||||
}
|
||||
// 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
|
||||
}
|
||||
case envFrom.SecretRef != nil:
|
||||
name := envFrom.SecretRef.Name
|
||||
secret, ok := secrets[name]
|
||||
if !ok {
|
||||
if kl.kubeClient == nil {
|
||||
return result, fmt.Errorf("Couldn't get secret %v/%v, no kubeClient defined", pod.Namespace, name)
|
||||
}
|
||||
secret, err = kl.kubeClient.Core().Secrets(pod.Namespace).Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
secrets[name] = secret
|
||||
}
|
||||
|
||||
for k, v := range secret.Data {
|
||||
if len(envFrom.Prefix) > 0 {
|
||||
k = envFrom.Prefix + k
|
||||
}
|
||||
if errMsgs := utilvalidation.IsCIdentifier(k); len(errMsgs) != 0 {
|
||||
return result, fmt.Errorf("Invalid environment variable name, %v, from secret %v/%v: %s", k, pod.Namespace, name, errMsgs[0])
|
||||
}
|
||||
tmpEnv[k] = string(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -466,17 +485,9 @@ 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 (
|
||||
secrets = make(map[string]*v1.Secret)
|
||||
mappingFunc = expansion.MappingFuncFor(tmpEnv, serviceEnv)
|
||||
)
|
||||
for _, envVar := range container.Env {
|
||||
// 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, envVar.Name)
|
||||
|
||||
runtimeVal := envVar.Value
|
||||
if runtimeVal != "" {
|
||||
// Step 1a: expand variable references
|
||||
@ -548,7 +559,14 @@ func (kl *Kubelet) makeEnvironmentVariables(pod *v1.Pod, container *v1.Container
|
||||
|
||||
// Append remaining service env vars.
|
||||
for k, v := range serviceEnv {
|
||||
result = append(result, kubecontainer.EnvVar{Name: k, Value: v})
|
||||
// Accesses apiserver+Pods.
|
||||
// So, the master may set service env vars, or kubelet may. In case both are doing
|
||||
// it, we skip 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.
|
||||
if _, present := tmpEnv[k]; !present {
|
||||
result = append(result, kubecontainer.EnvVar{Name: k, Value: v})
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
@ -274,6 +274,7 @@ func TestMakeEnvironmentVariables(t *testing.T) {
|
||||
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
|
||||
secret *v1.Secret // an optional Secret to pull from
|
||||
expectedEnvs []kubecontainer.EnvVar // a set of expected environment vars
|
||||
expectedError bool // does the test fail
|
||||
}{
|
||||
@ -766,6 +767,160 @@ func TestMakeEnvironmentVariables(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "secret",
|
||||
ns: "test1",
|
||||
container: &v1.Container{
|
||||
EnvFrom: []v1.EnvFromSource{
|
||||
{
|
||||
SecretRef: &v1.SecretEnvSource{LocalObjectReference: v1.LocalObjectReference{Name: "test-secret"}},
|
||||
},
|
||||
{
|
||||
Prefix: "p_",
|
||||
SecretRef: &v1.SecretEnvSource{LocalObjectReference: v1.LocalObjectReference{Name: "test-secret"}},
|
||||
},
|
||||
},
|
||||
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,
|
||||
secret: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "test1",
|
||||
Name: "test-secret",
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"REPLACE_ME": []byte("FROM_SECRET"),
|
||||
"DUPE_TEST": []byte("SECRET"),
|
||||
},
|
||||
},
|
||||
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_SECRET",
|
||||
},
|
||||
{
|
||||
Name: "EXPANSION_TEST",
|
||||
Value: "FROM_SECRET",
|
||||
},
|
||||
{
|
||||
Name: "DUPE_TEST",
|
||||
Value: "ENV_VAR",
|
||||
},
|
||||
{
|
||||
Name: "p_REPLACE_ME",
|
||||
Value: "FROM_SECRET",
|
||||
},
|
||||
{
|
||||
Name: "p_DUPE_TEST",
|
||||
Value: "SECRET",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "secret_missing",
|
||||
ns: "test1",
|
||||
container: &v1.Container{
|
||||
EnvFrom: []v1.EnvFromSource{
|
||||
{SecretRef: &v1.SecretEnvSource{LocalObjectReference: v1.LocalObjectReference{Name: "test-secret"}}},
|
||||
},
|
||||
},
|
||||
masterServiceNs: "nothing",
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "secret_invalid_keys",
|
||||
ns: "test1",
|
||||
container: &v1.Container{
|
||||
EnvFrom: []v1.EnvFromSource{
|
||||
{SecretRef: &v1.SecretEnvSource{LocalObjectReference: v1.LocalObjectReference{Name: "test-secret"}}},
|
||||
},
|
||||
},
|
||||
masterServiceNs: "nothing",
|
||||
secret: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "test1",
|
||||
Name: "test-secret",
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"1234": []byte("abc"),
|
||||
},
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "secret_invalid_keys_valid",
|
||||
ns: "test",
|
||||
container: &v1.Container{
|
||||
EnvFrom: []v1.EnvFromSource{
|
||||
{
|
||||
Prefix: "p_",
|
||||
SecretRef: &v1.SecretEnvSource{LocalObjectReference: v1.LocalObjectReference{Name: "test-secret"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
masterServiceNs: "",
|
||||
secret: &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "test1",
|
||||
Name: "test-secret",
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"1234": []byte("abc"),
|
||||
},
|
||||
},
|
||||
expectedEnvs: []kubecontainer.EnvVar{
|
||||
{
|
||||
Name: "p_1234",
|
||||
Value: "abc",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
@ -786,6 +941,14 @@ func TestMakeEnvironmentVariables(t *testing.T) {
|
||||
return true, tc.configMap, err
|
||||
})
|
||||
|
||||
testKubelet.fakeKubeClient.AddReactor("get", "secrets", func(action core.Action) (bool, runtime.Object, error) {
|
||||
var err error
|
||||
if tc.secret == nil {
|
||||
err = errors.New("no secret defined")
|
||||
}
|
||||
return true, tc.secret, err
|
||||
})
|
||||
|
||||
testPod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: tc.ns,
|
||||
|
@ -193,8 +193,62 @@ var _ = framework.KubeDescribe("Secrets", func() {
|
||||
"SECRET_DATA=value-1",
|
||||
})
|
||||
})
|
||||
|
||||
It("should be consumable via the environment [Conformance]", func() {
|
||||
name := "secret-test-" + string(uuid.NewUUID())
|
||||
secret := newEnvFromSecret(f.Namespace.Name, name)
|
||||
By(fmt.Sprintf("creating secret %v/%v", f.Namespace.Name, secret.Name))
|
||||
var err error
|
||||
if secret, err = f.ClientSet.Core().Secrets(f.Namespace.Name).Create(secret); err != nil {
|
||||
framework.Failf("unable to create test secret %s: %v", secret.Name, err)
|
||||
}
|
||||
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.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{
|
||||
{
|
||||
SecretRef: &v1.SecretEnvSource{LocalObjectReference: v1.LocalObjectReference{Name: name}},
|
||||
},
|
||||
{
|
||||
Prefix: "p_",
|
||||
SecretRef: &v1.SecretEnvSource{LocalObjectReference: v1.LocalObjectReference{Name: name}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
},
|
||||
}
|
||||
|
||||
f.TestContainerOutput("consume secrets", 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",
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
func newEnvFromSecret(namespace, name string) *v1.Secret {
|
||||
return &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"data_1": []byte("value-1\n"),
|
||||
"data_2": []byte("value-2\n"),
|
||||
"data_3": []byte("value-3\n"),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func secretForTest(namespace, name string) *v1.Secret {
|
||||
return &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
Loading…
Reference in New Issue
Block a user