diff options
author | OpenShift Merge Robot <openshift-merge-robot@users.noreply.github.com> | 2021-03-29 17:10:25 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-29 17:10:25 +0000 |
commit | b7bb8a1fb942a0568a1ff257798702bd0cde5d37 (patch) | |
tree | 35c403f30e1b4f1b98646b26b9192a2d58b4ede0 | |
parent | bb3e8a4d13d3ffc2ff6f57b0509febcb4ed0c17a (diff) | |
parent | c59eb6f12b2e53819ef0c1ff561cc0df125398b2 (diff) | |
download | podman-b7bb8a1fb942a0568a1ff257798702bd0cde5d37.tar.gz podman-b7bb8a1fb942a0568a1ff257798702bd0cde5d37.tar.bz2 podman-b7bb8a1fb942a0568a1ff257798702bd0cde5d37.zip |
Merge pull request #9842 from AlbanBedel/play-kube-env-from-secrets
Add support for env from secrets in play kube
-rw-r--r-- | pkg/domain/infra/abi/play.go | 28 | ||||
-rw-r--r-- | pkg/specgen/generate/kube/kube.go | 100 | ||||
-rw-r--r-- | pkg/specgen/generate/kube/play_test.go | 359 | ||||
-rw-r--r-- | test/e2e/play_kube_test.go | 236 |
4 files changed, 669 insertions, 54 deletions
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index 7d87fc83a..3b5c141d7 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -9,6 +9,7 @@ import ( "os" "strings" + "github.com/containers/common/pkg/secrets" "github.com/containers/image/v5/types" "github.com/containers/podman/v3/libpod" "github.com/containers/podman/v3/libpod/define" @@ -135,6 +136,12 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY report entities.PlayKubeReport ) + // Create the secret manager before hand + secretsManager, err := secrets.NewManager(ic.Libpod.GetSecretsStorageDir()) + if err != nil { + return nil, err + } + // check for name collision between pod and container if podName == "" { return nil, errors.Errorf("pod does not have a name") @@ -261,16 +268,17 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY } specgenOpts := kube.CtrSpecGenOptions{ - Container: container, - Image: newImage, - Volumes: volumes, - PodID: pod.ID(), - PodName: podName, - PodInfraID: podInfraID, - ConfigMaps: configMaps, - SeccompPaths: seccompPaths, - RestartPolicy: ctrRestartPolicy, - NetNSIsHost: p.NetNS.IsHost(), + Container: container, + Image: newImage, + Volumes: volumes, + PodID: pod.ID(), + PodName: podName, + PodInfraID: podInfraID, + ConfigMaps: configMaps, + SeccompPaths: seccompPaths, + RestartPolicy: ctrRestartPolicy, + NetNSIsHost: p.NetNS.IsHost(), + SecretsManager: secretsManager, } specGen, err := kube.ToSpecGen(ctx, &specgenOpts) if err != nil { diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go index d61c8bd19..31ed3fd7c 100644 --- a/pkg/specgen/generate/kube/kube.go +++ b/pkg/specgen/generate/kube/kube.go @@ -2,11 +2,13 @@ package kube import ( "context" + "encoding/json" "fmt" "net" "strings" "github.com/containers/common/pkg/parse" + "github.com/containers/common/pkg/secrets" "github.com/containers/podman/v3/libpod/image" ann "github.com/containers/podman/v3/pkg/annotations" "github.com/containers/podman/v3/pkg/specgen" @@ -94,6 +96,8 @@ type CtrSpecGenOptions struct { RestartPolicy string // NetNSIsHost tells the container to use the host netns NetNSIsHost bool + // SecretManager to access the secrets + SecretsManager *secrets.SecretsManager } func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGenerator, error) { @@ -210,12 +214,18 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener } for _, env := range opts.Container.Env { - value := envVarValue(env, opts.ConfigMaps) + value, err := envVarValue(env, opts) + if err != nil { + return nil, err + } envs[env.Name] = value } for _, envFrom := range opts.Container.EnvFrom { - cmEnvs := envVarsFromConfigMap(envFrom, opts.ConfigMaps) + cmEnvs, err := envVarsFrom(envFrom, opts) + if err != nil { + return nil, err + } for k, v := range cmEnvs { envs[k] = v @@ -325,40 +335,96 @@ func quantityToInt64(quantity *resource.Quantity) (int64, error) { return 0, errors.Errorf("Quantity cannot be represented as int64: %v", quantity) } -// envVarsFromConfigMap returns all key-value pairs as env vars from a configMap that matches the envFrom setting of a container -func envVarsFromConfigMap(envFrom v1.EnvFromSource, configMaps []v1.ConfigMap) map[string]string { +// read a k8s secret in JSON format from the secret manager +func k8sSecretFromSecretManager(name string, secretsManager *secrets.SecretsManager) (map[string][]byte, error) { + _, jsonSecret, err := secretsManager.LookupSecretData(name) + if err != nil { + return nil, err + } + + var secrets map[string][]byte + if err := json.Unmarshal(jsonSecret, &secrets); err != nil { + return nil, errors.Errorf("Secret %v is not valid JSON: %v", name, err) + } + return secrets, nil +} + +// envVarsFrom returns all key-value pairs as env vars from a configMap or secret that matches the envFrom setting of a container +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 configMaps { - if cmName == c.Name { + for _, c := range opts.ConfigMaps { + if cmRef.Name == c.Name { envs = c.Data + err = nil break } } + + if err != nil && (cmRef.Optional == nil || !*cmRef.Optional) { + return nil, err + } } - return envs + if envFrom.SecretRef != nil { + secRef := envFrom.SecretRef + secret, err := k8sSecretFromSecretManager(secRef.Name, opts.SecretsManager) + if err == nil { + for k, v := range secret { + envs[k] = string(v) + } + } else if secRef.Optional == nil || !*secRef.Optional { + return nil, err + } + } + + 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, configMaps []v1.ConfigMap) string { - for _, c := range configMaps { - if env.ValueFrom != nil { - if env.ValueFrom.ConfigMapKeyRef != nil { - if env.ValueFrom.ConfigMapKeyRef.Name == c.Name { - if value, ok := c.Data[env.ValueFrom.ConfigMapKeyRef.Key]; ok { - return value +// It gets the value from a configMap or secret if specified, otherwise returns env.Value +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 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 + } + + if env.ValueFrom.SecretKeyRef != nil { + secKeyRef := env.ValueFrom.SecretKeyRef + secret, err := k8sSecretFromSecretManager(secKeyRef.Name, opts.SecretsManager) + if err == nil { + if val, ok := secret[secKeyRef.Key]; ok { + return string(val), nil } + err = errors.Errorf("Secret %v has not %v key", secKeyRef.Name, secKeyRef.Key) + } + if secKeyRef.Optional == nil || !*secKeyRef.Optional { + return "", errors.Errorf("Cannot set env %v: %v", env.Name, 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 148540e9f..f714826f0 100644 --- a/pkg/specgen/generate/kube/play_test.go +++ b/pkg/specgen/generate/kube/play_test.go @@ -1,19 +1,49 @@ package kube import ( + "encoding/json" + "io/ioutil" + "os" "testing" + "github.com/containers/common/pkg/secrets" "github.com/stretchr/testify/assert" v1 "k8s.io/api/core/v1" v12 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -func TestEnvVarsFromConfigMap(t *testing.T) { +func createSecrets(t *testing.T, d string) *secrets.SecretsManager { + secretsManager, err := secrets.NewManager(d) + assert.NoError(t, err) + + driver := "file" + driverOpts := map[string]string{ + "path": d, + } + + for _, s := range k8sSecrets { + data, err := json.Marshal(s.Data) + assert.NoError(t, err) + + _, err = secretsManager.Store(s.ObjectMeta.Name, data, driver, driverOpts) + assert.NoError(t, err) + } + + return secretsManager +} + +func TestEnvVarsFrom(t *testing.T) { + d, err := ioutil.TempDir("", "secrets") + assert.NoError(t, err) + defer os.RemoveAll(d) + secretsManager := createSecrets(t, d) + tests := []struct { - name string - envFrom v1.EnvFromSource - configMapList []v1.ConfigMap - expected map[string]string + name string + envFrom v1.EnvFromSource + options CtrSpecGenOptions + succeed bool + expected map[string]string }{ { "ConfigMapExists", @@ -24,7 +54,10 @@ func TestEnvVarsFromConfigMap(t *testing.T) { }, }, }, - configMapList, + CtrSpecGenOptions{ + ConfigMaps: configMapList, + }, + true, map[string]string{ "myvar": "foo", }, @@ -38,7 +71,26 @@ func TestEnvVarsFromConfigMap(t *testing.T) { }, }, }, - configMapList, + 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{}, }, { @@ -50,7 +102,74 @@ func TestEnvVarsFromConfigMap(t *testing.T) { }, }, }, - []v1.ConfigMap{}, + 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{}, + }, + { + "SecretExists", + v1.EnvFromSource{ + SecretRef: &v1.SecretEnvSource{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "foo", + }, + }, + }, + CtrSpecGenOptions{ + SecretsManager: secretsManager, + }, + true, + map[string]string{ + "myvar": "foo", + }, + }, + { + "SecretDoesNotExist", + v1.EnvFromSource{ + SecretRef: &v1.SecretEnvSource{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "doesnotexist", + }, + }, + }, + CtrSpecGenOptions{ + SecretsManager: secretsManager, + }, + false, + nil, + }, + { + "OptionalSecretDoesNotExist", + v1.EnvFromSource{ + SecretRef: &v1.SecretEnvSource{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "doesnotexist", + }, + Optional: &optional, + }, + }, + CtrSpecGenOptions{ + SecretsManager: secretsManager, + }, + true, map[string]string{}, }, } @@ -58,18 +177,25 @@ func TestEnvVarsFromConfigMap(t *testing.T) { for _, test := range tests { test := test t.Run(test.name, func(t *testing.T) { - result := envVarsFromConfigMap(test.envFrom, test.configMapList) + result, err := envVarsFrom(test.envFrom, &test.options) + assert.Equal(t, err == nil, test.succeed) assert.Equal(t, test.expected, result) }) } } func TestEnvVarValue(t *testing.T) { + d, err := ioutil.TempDir("", "secrets") + assert.NoError(t, err) + defer os.RemoveAll(d) + secretsManager := createSecrets(t, d) + tests := []struct { - name string - envVar v1.EnvVar - configMapList []v1.ConfigMap - expected string + name string + envVar v1.EnvVar + options CtrSpecGenOptions + succeed bool + expected string }{ { "ConfigMapExists", @@ -84,7 +210,10 @@ func TestEnvVarValue(t *testing.T) { }, }, }, - configMapList, + CtrSpecGenOptions{ + ConfigMaps: configMapList, + }, + true, "foo", }, { @@ -100,7 +229,30 @@ func TestEnvVarValue(t *testing.T) { }, }, }, - configMapList, + 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, "", }, { @@ -116,7 +268,30 @@ func TestEnvVarValue(t *testing.T) { }, }, }, - configMapList, + 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, "", }, { @@ -132,7 +307,127 @@ func TestEnvVarValue(t *testing.T) { }, }, }, - []v1.ConfigMap{}, + 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, + "", + }, + { + "SecretExists", + v1.EnvVar{ + Name: "FOO", + ValueFrom: &v1.EnvVarSource{ + SecretKeyRef: &v1.SecretKeySelector{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "foo", + }, + Key: "myvar", + }, + }, + }, + CtrSpecGenOptions{ + SecretsManager: secretsManager, + }, + true, + "foo", + }, + { + "ContainerKeyDoesNotExistInSecret", + v1.EnvVar{ + Name: "FOO", + ValueFrom: &v1.EnvVarSource{ + SecretKeyRef: &v1.SecretKeySelector{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "foo", + }, + Key: "doesnotexist", + }, + }, + }, + CtrSpecGenOptions{ + SecretsManager: secretsManager, + }, + false, + "", + }, + { + "OptionalContainerKeyDoesNotExistInSecret", + v1.EnvVar{ + Name: "FOO", + ValueFrom: &v1.EnvVarSource{ + SecretKeyRef: &v1.SecretKeySelector{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "foo", + }, + Key: "doesnotexist", + Optional: &optional, + }, + }, + }, + CtrSpecGenOptions{ + SecretsManager: secretsManager, + }, + true, + "", + }, + { + "SecretDoesNotExist", + v1.EnvVar{ + Name: "FOO", + ValueFrom: &v1.EnvVarSource{ + SecretKeyRef: &v1.SecretKeySelector{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "doesnotexist", + }, + Key: "myvar", + }, + }, + }, + CtrSpecGenOptions{ + SecretsManager: secretsManager, + }, + false, + "", + }, + { + "OptionalSecretDoesNotExist", + v1.EnvVar{ + Name: "FOO", + ValueFrom: &v1.EnvVarSource{ + SecretKeyRef: &v1.SecretKeySelector{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "doesnotexist", + }, + Key: "myvar", + Optional: &optional, + }, + }, + }, + CtrSpecGenOptions{ + SecretsManager: secretsManager, + }, + true, "", }, } @@ -140,7 +435,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.configMapList) + result, err := envVarValue(test.envVar, &test.options) + assert.Equal(t, err == nil, test.succeed) assert.Equal(t, test.expected, result) }) } @@ -170,3 +466,30 @@ var configMapList = []v1.ConfigMap{ }, }, } + +var optional = true + +var k8sSecrets = []v1.Secret{ + { + TypeMeta: v12.TypeMeta{ + Kind: "Secret", + }, + ObjectMeta: v12.ObjectMeta{ + Name: "bar", + }, + Data: map[string][]byte{ + "myvar": []byte("bar"), + }, + }, + { + TypeMeta: v12.TypeMeta{ + Kind: "Secret", + }, + ObjectMeta: v12.ObjectMeta{ + Name: "foo", + }, + Data: map[string][]byte{ + "myvar": []byte("foo"), + }, + }, +} diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go index a4c738f17..93c8426a7 100644 --- a/test/e2e/play_kube_test.go +++ b/test/e2e/play_kube_test.go @@ -141,7 +141,16 @@ spec: configMapKeyRef: name: {{ .RefName }} key: {{ .RefKey }} - {{ else }} + optional: {{ .Optional }} + {{ end }} + {{ if (eq .ValueFrom "secret") }} + valueFrom: + secretKeyRef: + name: {{ .RefName }} + key: {{ .RefKey }} + optional: {{ .Optional }} + {{ end }} + {{ if (eq .ValueFrom "") }} value: {{ .Value }} {{ end }} {{ end }} @@ -151,6 +160,12 @@ spec: {{ if (eq .From "configmap") }} - configMapRef: name: {{ .Name }} + optional: {{ .Optional }} + {{ end }} + {{ if (eq .From "secret") }} + - secretRef: + name: {{ .Name }} + optional: {{ .Optional }} {{ end }} {{ end }} {{ end }} @@ -340,6 +355,8 @@ var ( seccompPwdEPERM = []byte(`{"defaultAction":"SCMP_ACT_ALLOW","syscalls":[{"name":"getcwd","action":"SCMP_ACT_ERRNO"}]}`) // CPU Period in ms defaultCPUPeriod = 100 + // Default secret in JSON. Note that the values ("foo" and "bar") are base64 encoded. + defaultSecret = []byte(`{"FOO":"Zm9v","BAR":"YmFy"}`) ) func writeYaml(content string, fileName string) error { @@ -407,6 +424,16 @@ func generateMultiDocKubeYaml(kubeObjects []string, pathname string) error { return writeYaml(multiKube, pathname) } +func createSecret(podmanTest *PodmanTestIntegration, name string, value []byte) { + secretFilePath := filepath.Join(podmanTest.TempDir, "secret") + err := ioutil.WriteFile(secretFilePath, value, 0755) + Expect(err).To(BeNil()) + + secret := podmanTest.Podman([]string{"secret", "create", name, secretFilePath}) + secret.WaitWithDefaultTimeout() + Expect(secret.ExitCode()).To(Equal(0)) +} + // ConfigMap describes the options a kube yaml can be configured at configmap level type ConfigMap struct { Name string @@ -746,7 +773,7 @@ func withVolumeMount(mountPath string, readonly bool) ctrOption { } } -func withEnv(name, value, valueFrom, refName, refKey string) ctrOption { +func withEnv(name, value, valueFrom, refName, refKey string, optional bool) ctrOption { return func(c *Ctr) { e := Env{ Name: name, @@ -754,17 +781,19 @@ func withEnv(name, value, valueFrom, refName, refKey string) ctrOption { ValueFrom: valueFrom, RefName: refName, RefKey: refKey, + Optional: optional, } c.Env = append(c.Env, e) } } -func withEnvFrom(name, from string) ctrOption { +func withEnvFrom(name, from string, optional bool) ctrOption { return func(c *Ctr) { e := EnvFrom{ - Name: name, - From: from, + Name: name, + From: from, + Optional: optional, } c.EnvFrom = append(c.EnvFrom, e) @@ -822,11 +851,13 @@ type Env struct { ValueFrom string RefName string RefKey string + Optional bool } type EnvFrom struct { - Name string - From string + Name string + From string + Optional bool } func milliCPUToQuota(milliCPU string) int { @@ -1062,7 +1093,7 @@ var _ = Describe("Podman play kube", func() { err := generateKubeYaml("configmap", cm, cmYamlPathname) Expect(err).To(BeNil()) - pod := getPod(withCtr(getCtr(withEnv("FOO", "", "configmap", "foo", "FOO")))) + pod := getPod(withCtr(getCtr(withEnv("FOO", "", "configmap", "foo", "FOO", false)))) err = generateKubeYaml("pod", pod, kubeYaml) Expect(err).To(BeNil()) @@ -1076,6 +1107,68 @@ var _ = Describe("Podman play kube", func() { Expect(inspect.OutputToString()).To(ContainSubstring(`FOO=foo`)) }) + It("podman play kube test required env value from configmap with missing key", func() { + SkipIfRemote("configmap list is not supported as a param") + cmYamlPathname := filepath.Join(podmanTest.TempDir, "foo-cm.yaml") + cm := getConfigMap(withConfigMapName("foo"), withConfigMapData("FOO", "foo")) + err := generateKubeYaml("configmap", cm, cmYamlPathname) + Expect(err).To(BeNil()) + + pod := getPod(withCtr(getCtr(withEnv("FOO", "", "configmap", "foo", "MISSING_KEY", false)))) + err = generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml, "--configmap", cmYamlPathname}) + kube.WaitWithDefaultTimeout() + Expect(kube.ExitCode()).To(Not(Equal(0))) + }) + + It("podman play kube test required env value from missing configmap", func() { + pod := getPod(withCtr(getCtr(withEnv("FOO", "", "configmap", "missing_cm", "FOO", false)))) + err = generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube.ExitCode()).To(Not(Equal(0))) + }) + + It("podman play kube test optional env value from configmap with missing key", func() { + SkipIfRemote("configmap list is not supported as a param") + cmYamlPathname := filepath.Join(podmanTest.TempDir, "foo-cm.yaml") + cm := getConfigMap(withConfigMapName("foo"), withConfigMapData("FOO", "foo")) + err := generateKubeYaml("configmap", cm, cmYamlPathname) + Expect(err).To(BeNil()) + + pod := getPod(withCtr(getCtr(withEnv("FOO", "", "configmap", "foo", "MISSING_KEY", true)))) + err = generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml, "--configmap", cmYamlPathname}) + kube.WaitWithDefaultTimeout() + Expect(kube.ExitCode()).To(Equal(0)) + + inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(pod), "--format", "'{{ range .Config.Env }}[{{ . }}]{{end}}'"}) + inspect.WaitWithDefaultTimeout() + Expect(inspect.ExitCode()).To(Equal(0)) + Expect(inspect.OutputToString()).To(ContainSubstring(`[FOO=]`)) + }) + + It("podman play kube test optional env value from missing configmap", func() { + pod := getPod(withCtr(getCtr(withEnv("FOO", "", "configmap", "missing_cm", "FOO", true)))) + err = generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube.ExitCode()).To(Equal(0)) + + inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(pod), "--format", "'{{ range .Config.Env }}[{{ . }}]{{end}}'"}) + inspect.WaitWithDefaultTimeout() + Expect(inspect.ExitCode()).To(Equal(0)) + Expect(inspect.OutputToString()).To(ContainSubstring(`[FOO=]`)) + }) + It("podman play kube test get all key-value pairs from configmap as envs", func() { SkipIfRemote("configmap list is not supported as a param") cmYamlPathname := filepath.Join(podmanTest.TempDir, "foo-cm.yaml") @@ -1083,7 +1176,7 @@ var _ = Describe("Podman play kube", func() { err := generateKubeYaml("configmap", cm, cmYamlPathname) Expect(err).To(BeNil()) - pod := getPod(withCtr(getCtr(withEnvFrom("foo", "configmap")))) + pod := getPod(withCtr(getCtr(withEnvFrom("foo", "configmap", false)))) err = generateKubeYaml("pod", pod, kubeYaml) Expect(err).To(BeNil()) @@ -1098,6 +1191,131 @@ var _ = Describe("Podman play kube", func() { Expect(inspect.OutputToString()).To(ContainSubstring(`FOO2=foo2`)) }) + It("podman play kube test get all key-value pairs from required configmap as envs", func() { + pod := getPod(withCtr(getCtr(withEnvFrom("missing_cm", "configmap", false)))) + err = generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube.ExitCode()).To(Not(Equal(0))) + }) + + It("podman play kube test get all key-value pairs from optional configmap as envs", func() { + pod := getPod(withCtr(getCtr(withEnvFrom("missing_cm", "configmap", true)))) + err = generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube.ExitCode()).To(Equal(0)) + }) + + It("podman play kube test env value from secret", func() { + createSecret(podmanTest, "foo", defaultSecret) + pod := getPod(withCtr(getCtr(withEnv("FOO", "", "secret", "foo", "FOO", false)))) + err = generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube.ExitCode()).To(Equal(0)) + + inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(pod), "--format", "'{{ .Config.Env }}'"}) + inspect.WaitWithDefaultTimeout() + Expect(inspect.ExitCode()).To(Equal(0)) + Expect(inspect.OutputToString()).To(ContainSubstring(`FOO=foo`)) + }) + + It("podman play kube test required env value from missing secret", func() { + pod := getPod(withCtr(getCtr(withEnv("FOO", "", "secret", "foo", "FOO", false)))) + err = generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube.ExitCode()).To(Not(Equal(0))) + }) + + It("podman play kube test required env value from secret with missing key", func() { + createSecret(podmanTest, "foo", defaultSecret) + pod := getPod(withCtr(getCtr(withEnv("FOO", "", "secret", "foo", "MISSING", false)))) + err = generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube.ExitCode()).To(Not(Equal(0))) + }) + + It("podman play kube test optional env value from missing secret", func() { + pod := getPod(withCtr(getCtr(withEnv("FOO", "", "secret", "foo", "FOO", true)))) + err = generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube.ExitCode()).To(Equal(0)) + + inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(pod), "--format", "'{{ range .Config.Env }}[{{ . }}]{{end}}'"}) + inspect.WaitWithDefaultTimeout() + Expect(inspect.ExitCode()).To(Equal(0)) + Expect(inspect.OutputToString()).To(ContainSubstring(`[FOO=]`)) + }) + + It("podman play kube test optional env value from secret with missing key", func() { + createSecret(podmanTest, "foo", defaultSecret) + pod := getPod(withCtr(getCtr(withEnv("FOO", "", "secret", "foo", "MISSING", true)))) + err = generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube.ExitCode()).To(Equal(0)) + + inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(pod), "--format", "'{{ range .Config.Env }}[{{ . }}]{{end}}'"}) + inspect.WaitWithDefaultTimeout() + Expect(inspect.ExitCode()).To(Equal(0)) + Expect(inspect.OutputToString()).To(ContainSubstring(`[FOO=]`)) + }) + + It("podman play kube test get all key-value pairs from secret as envs", func() { + createSecret(podmanTest, "foo", defaultSecret) + pod := getPod(withCtr(getCtr(withEnvFrom("foo", "secret", false)))) + err = generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube.ExitCode()).To(Equal(0)) + + inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(pod), "--format", "'{{ .Config.Env }}'"}) + inspect.WaitWithDefaultTimeout() + Expect(inspect.ExitCode()).To(Equal(0)) + Expect(inspect.OutputToString()).To(ContainSubstring(`FOO=foo`)) + Expect(inspect.OutputToString()).To(ContainSubstring(`BAR=bar`)) + }) + + It("podman play kube test get all key-value pairs from required secret as envs", func() { + pod := getPod(withCtr(getCtr(withEnvFrom("missing_secret", "secret", false)))) + err = generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube.ExitCode()).To(Not(Equal(0))) + }) + + It("podman play kube test get all key-value pairs from optional secret as envs", func() { + pod := getPod(withCtr(getCtr(withEnvFrom("missing_secret", "secret", true)))) + err = generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube.ExitCode()).To(Equal(0)) + }) + It("podman play kube test hostname", func() { pod := getPod() err := generateKubeYaml("pod", pod, kubeYaml) |