diff options
author | Alban Bedel <albeu@free.fr> | 2021-03-26 10:54:26 +0100 |
---|---|---|
committer | Alban Bedel <albeu@free.fr> | 2021-03-28 15:02:31 +0200 |
commit | e5ff694855820e8bf5b7f17680c3dc6586241bdd (patch) | |
tree | 5c57744226efd8b4dc3610c25f5e14c1f3f49fe1 /pkg/specgen | |
parent | 9f92b8b0d8ac34c02100579a5acf6c127392aff5 (diff) | |
download | podman-e5ff694855820e8bf5b7f17680c3dc6586241bdd.tar.gz podman-e5ff694855820e8bf5b7f17680c3dc6586241bdd.tar.bz2 podman-e5ff694855820e8bf5b7f17680c3dc6586241bdd.zip |
play kube: support optional/mandatory env var from config map
In K8S the pod creation fails if an env var reference a non existing
config map key. It can be marked as optional, but per default it is
mandatory. Podman on the other hand always treat such references as
optional.
Rework envVarsFrom() and envVarValue() to additionaly return an error
and add support for the optional attribute in configMapRef and
configMapKeyRef.
Signed-off-by: Alban Bedel <albeu@free.fr>
Diffstat (limited to 'pkg/specgen')
-rw-r--r-- | pkg/specgen/generate/kube/kube.go | 43 | ||||
-rw-r--r-- | pkg/specgen/generate/kube/play_test.go | 109 |
2 files changed, 139 insertions, 13 deletions
diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go index 6adbef2dc..f31f5e711 100644 --- a/pkg/specgen/generate/kube/kube.go +++ b/pkg/specgen/generate/kube/kube.go @@ -210,12 +210,18 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener } for _, env := range opts.Container.Env { - value := envVarValue(env, opts) + value, err := envVarValue(env, opts) + if err != nil { + return nil, err + } envs[env.Name] = value } for _, envFrom := range opts.Container.EnvFrom { - cmEnvs := envVarsFrom(envFrom, opts) + cmEnvs, err := envVarsFrom(envFrom, opts) + if err != nil { + return nil, err + } for k, v := range cmEnvs { envs[k] = v @@ -326,39 +332,54 @@ func quantityToInt64(quantity *resource.Quantity) (int64, error) { } // envVarsFrom returns all key-value pairs as env vars from a configMap that matches the envFrom setting of a container -func envVarsFrom(envFrom v1.EnvFromSource, opts *CtrSpecGenOptions) map[string]string { +func envVarsFrom(envFrom v1.EnvFromSource, opts *CtrSpecGenOptions) (map[string]string, error) { envs := map[string]string{} if envFrom.ConfigMapRef != nil { - cmName := envFrom.ConfigMapRef.Name + cmRef := envFrom.ConfigMapRef + err := errors.Errorf("Configmap %v not found", cmRef.Name) for _, c := range opts.ConfigMaps { - if cmName == c.Name { + if cmRef.Name == c.Name { envs = c.Data + err = nil break } } + + if err != nil && (cmRef.Optional == nil || !*cmRef.Optional) { + return nil, err + } } - return envs + return envs, nil } // envVarValue returns the environment variable value configured within the container's env setting. // It gets the value from a configMap if specified, otherwise returns env.Value -func envVarValue(env v1.EnvVar, opts *CtrSpecGenOptions) string { +func envVarValue(env v1.EnvVar, opts *CtrSpecGenOptions) (string, error) { if env.ValueFrom != nil { if env.ValueFrom.ConfigMapKeyRef != nil { + cmKeyRef := env.ValueFrom.ConfigMapKeyRef + err := errors.Errorf("Cannot set env %v: configmap %v not found", env.Name, cmKeyRef.Name) + for _, c := range opts.ConfigMaps { - if env.ValueFrom.ConfigMapKeyRef.Name == c.Name { - if value, ok := c.Data[env.ValueFrom.ConfigMapKeyRef.Key]; ok { - return value + if cmKeyRef.Name == c.Name { + if value, ok := c.Data[cmKeyRef.Key]; ok { + return value, nil } + err = errors.Errorf("Cannot set env %v: key %s not found in configmap %v", env.Name, cmKeyRef.Key, cmKeyRef.Name) + break } } + if cmKeyRef.Optional == nil || !*cmKeyRef.Optional { + return "", err + } + return "", nil } } - return env.Value + return env.Value, nil } // getPodPorts converts a slice of kube container descriptions to an diff --git a/pkg/specgen/generate/kube/play_test.go b/pkg/specgen/generate/kube/play_test.go index 35975a70b..c38b3e40b 100644 --- a/pkg/specgen/generate/kube/play_test.go +++ b/pkg/specgen/generate/kube/play_test.go @@ -13,6 +13,7 @@ func TestEnvVarsFrom(t *testing.T) { name string envFrom v1.EnvFromSource options CtrSpecGenOptions + succeed bool expected map[string]string }{ { @@ -27,6 +28,7 @@ func TestEnvVarsFrom(t *testing.T) { CtrSpecGenOptions{ ConfigMaps: configMapList, }, + true, map[string]string{ "myvar": "foo", }, @@ -43,6 +45,23 @@ func TestEnvVarsFrom(t *testing.T) { CtrSpecGenOptions{ ConfigMaps: configMapList, }, + false, + nil, + }, + { + "OptionalConfigMapDoesNotExist", + v1.EnvFromSource{ + ConfigMapRef: &v1.ConfigMapEnvSource{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "doesnotexist", + }, + Optional: &optional, + }, + }, + CtrSpecGenOptions{ + ConfigMaps: configMapList, + }, + true, map[string]string{}, }, { @@ -57,6 +76,23 @@ func TestEnvVarsFrom(t *testing.T) { CtrSpecGenOptions{ ConfigMaps: []v1.ConfigMap{}, }, + false, + nil, + }, + { + "OptionalEmptyConfigMapList", + v1.EnvFromSource{ + ConfigMapRef: &v1.ConfigMapEnvSource{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "foo", + }, + Optional: &optional, + }, + }, + CtrSpecGenOptions{ + ConfigMaps: []v1.ConfigMap{}, + }, + true, map[string]string{}, }, } @@ -64,7 +100,8 @@ func TestEnvVarsFrom(t *testing.T) { for _, test := range tests { test := test t.Run(test.name, func(t *testing.T) { - result := envVarsFrom(test.envFrom, &test.options) + result, err := envVarsFrom(test.envFrom, &test.options) + assert.Equal(t, err == nil, test.succeed) assert.Equal(t, test.expected, result) }) } @@ -75,6 +112,7 @@ func TestEnvVarValue(t *testing.T) { name string envVar v1.EnvVar options CtrSpecGenOptions + succeed bool expected string }{ { @@ -93,6 +131,7 @@ func TestEnvVarValue(t *testing.T) { CtrSpecGenOptions{ ConfigMaps: configMapList, }, + true, "foo", }, { @@ -111,6 +150,27 @@ func TestEnvVarValue(t *testing.T) { CtrSpecGenOptions{ ConfigMaps: configMapList, }, + false, + "", + }, + { + "OptionalContainerKeyDoesNotExistInConfigMap", + v1.EnvVar{ + Name: "FOO", + ValueFrom: &v1.EnvVarSource{ + ConfigMapKeyRef: &v1.ConfigMapKeySelector{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "foo", + }, + Key: "doesnotexist", + Optional: &optional, + }, + }, + }, + CtrSpecGenOptions{ + ConfigMaps: configMapList, + }, + true, "", }, { @@ -129,6 +189,27 @@ func TestEnvVarValue(t *testing.T) { CtrSpecGenOptions{ ConfigMaps: configMapList, }, + false, + "", + }, + { + "OptionalConfigMapDoesNotExist", + v1.EnvVar{ + Name: "FOO", + ValueFrom: &v1.EnvVarSource{ + ConfigMapKeyRef: &v1.ConfigMapKeySelector{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "doesnotexist", + }, + Key: "myvar", + Optional: &optional, + }, + }, + }, + CtrSpecGenOptions{ + ConfigMaps: configMapList, + }, + true, "", }, { @@ -147,6 +228,27 @@ func TestEnvVarValue(t *testing.T) { CtrSpecGenOptions{ ConfigMaps: []v1.ConfigMap{}, }, + false, + "", + }, + { + "OptionalEmptyConfigMapList", + v1.EnvVar{ + Name: "FOO", + ValueFrom: &v1.EnvVarSource{ + ConfigMapKeyRef: &v1.ConfigMapKeySelector{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "foo", + }, + Key: "myvar", + Optional: &optional, + }, + }, + }, + CtrSpecGenOptions{ + ConfigMaps: []v1.ConfigMap{}, + }, + true, "", }, } @@ -154,7 +256,8 @@ func TestEnvVarValue(t *testing.T) { for _, test := range tests { test := test t.Run(test.name, func(t *testing.T) { - result := envVarValue(test.envVar, &test.options) + result, err := envVarValue(test.envVar, &test.options) + assert.Equal(t, err == nil, test.succeed) assert.Equal(t, test.expected, result) }) } @@ -184,3 +287,5 @@ var configMapList = []v1.ConfigMap{ }, }, } + +var optional = true |