aboutsummaryrefslogtreecommitdiff
path: root/pkg/specgen/generate/kube
diff options
context:
space:
mode:
authorYaron Dayagi <ydayagi@redhat.com>2022-01-30 20:45:30 +0200
committerYaron Dayagi <ydayagi@redhat.com>2022-01-31 21:49:38 +0200
commit2ceab119478502fd06703036bc79953ed6f37f74 (patch)
treed44d98cc7a1b166c9cccf383f8aa6f1cc0440730 /pkg/specgen/generate/kube
parentc96aa23adb9f1cb7e195d3585a2c78af7aab2ce5 (diff)
downloadpodman-2ceab119478502fd06703036bc79953ed6f37f74.tar.gz
podman-2ceab119478502fd06703036bc79953ed6f37f74.tar.bz2
podman-2ceab119478502fd06703036bc79953ed6f37f74.zip
play kube envVar.valueFrom.fieldRef
add support for env vars values from pod spec fields see https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#envvarsource-v1-core relates to issue https://github.com/containers/podman/issues/12756 Signed-off-by: Yaron Dayagi <ydayagi@redhat.com>
Diffstat (limited to 'pkg/specgen/generate/kube')
-rw-r--r--pkg/specgen/generate/kube/kube.go61
-rw-r--r--pkg/specgen/generate/kube/play_test.go194
2 files changed, 231 insertions, 24 deletions
diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go
index 2fd149b49..beaec1135 100644
--- a/pkg/specgen/generate/kube/kube.go
+++ b/pkg/specgen/generate/kube/kube.go
@@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"net"
+ "regexp"
"strings"
"time"
@@ -291,9 +292,9 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener
return nil, err
}
- // Only set the env if the value is not ""
- if value != "" {
- envs[env.Name] = value
+ // Only set the env if the value is not nil
+ if value != nil {
+ envs[env.Name] = *value
}
}
for _, envFrom := range opts.Container.EnvFrom {
@@ -609,7 +610,7 @@ func envVarsFrom(envFrom v1.EnvFromSource, opts *CtrSpecGenOptions) (map[string]
// envVarValue returns the environment variable value configured within the container's env setting.
// It gets the value from a configMap or secret if specified, otherwise returns env.Value
-func envVarValue(env v1.EnvVar, opts *CtrSpecGenOptions) (string, error) {
+func envVarValue(env v1.EnvVar, opts *CtrSpecGenOptions) (*string, error) {
if env.ValueFrom != nil {
if env.ValueFrom.ConfigMapKeyRef != nil {
cmKeyRef := env.ValueFrom.ConfigMapKeyRef
@@ -618,16 +619,16 @@ func envVarValue(env v1.EnvVar, opts *CtrSpecGenOptions) (string, error) {
for _, c := range opts.ConfigMaps {
if cmKeyRef.Name == c.Name {
if value, ok := c.Data[cmKeyRef.Key]; ok {
- return value, nil
+ 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, err
}
- return "", nil
+ return nil, nil
}
if env.ValueFrom.SecretKeyRef != nil {
@@ -635,18 +636,56 @@ func envVarValue(env v1.EnvVar, opts *CtrSpecGenOptions) (string, error) {
secret, err := k8sSecretFromSecretManager(secKeyRef.Name, opts.SecretsManager)
if err == nil {
if val, ok := secret[secKeyRef.Key]; ok {
- return string(val), nil
+ value := string(val)
+ return &value, 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, errors.Errorf("Cannot set env %v: %v", env.Name, err)
}
- return "", nil
+ return nil, nil
+ }
+
+ if env.ValueFrom.FieldRef != nil {
+ return envVarValueFieldRef(env, opts)
}
}
- return env.Value, nil
+ return &env.Value, nil
+}
+
+func envVarValueFieldRef(env v1.EnvVar, opts *CtrSpecGenOptions) (*string, error) {
+ fieldRef := env.ValueFrom.FieldRef
+
+ fieldPathLabelPattern := `^metadata.labels\['(.+)'\]$`
+ fieldPathLabelRegex := regexp.MustCompile(fieldPathLabelPattern)
+ fieldPathAnnotationPattern := `^metadata.annotations\['(.+)'\]$`
+ fieldPathAnnotationRegex := regexp.MustCompile(fieldPathAnnotationPattern)
+
+ fieldPath := fieldRef.FieldPath
+
+ if fieldPath == "metadata.name" {
+ return &opts.PodName, nil
+ }
+ if fieldPath == "metadata.uid" {
+ return &opts.PodID, nil
+ }
+ fieldPathMatches := fieldPathLabelRegex.FindStringSubmatch(fieldPath)
+ if len(fieldPathMatches) == 2 { // 1 for entire regex and 1 for subexp
+ labelValue := opts.Labels[fieldPathMatches[1]] // not existent label is OK
+ return &labelValue, nil
+ }
+ fieldPathMatches = fieldPathAnnotationRegex.FindStringSubmatch(fieldPath)
+ if len(fieldPathMatches) == 2 { // 1 for entire regex and 1 for subexp
+ annotationValue := opts.Annotations[fieldPathMatches[1]] // not existent annotation is OK
+ return &annotationValue, nil
+ }
+
+ return nil, errors.Errorf(
+ "Can not set env %v. Reason: fieldPath %v is either not valid or not supported",
+ env.Name, fieldPath,
+ )
}
// 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 f714826f0..2ac268c79 100644
--- a/pkg/specgen/generate/kube/play_test.go
+++ b/pkg/specgen/generate/kube/play_test.go
@@ -189,13 +189,15 @@ func TestEnvVarValue(t *testing.T) {
assert.NoError(t, err)
defer os.RemoveAll(d)
secretsManager := createSecrets(t, d)
+ value := "foo"
+ emptyValue := ""
tests := []struct {
name string
envVar v1.EnvVar
options CtrSpecGenOptions
succeed bool
- expected string
+ expected *string
}{
{
"ConfigMapExists",
@@ -214,7 +216,7 @@ func TestEnvVarValue(t *testing.T) {
ConfigMaps: configMapList,
},
true,
- "foo",
+ &value,
},
{
"ContainerKeyDoesNotExistInConfigMap",
@@ -233,7 +235,7 @@ func TestEnvVarValue(t *testing.T) {
ConfigMaps: configMapList,
},
false,
- "",
+ nil,
},
{
"OptionalContainerKeyDoesNotExistInConfigMap",
@@ -253,7 +255,7 @@ func TestEnvVarValue(t *testing.T) {
ConfigMaps: configMapList,
},
true,
- "",
+ nil,
},
{
"ConfigMapDoesNotExist",
@@ -272,7 +274,7 @@ func TestEnvVarValue(t *testing.T) {
ConfigMaps: configMapList,
},
false,
- "",
+ nil,
},
{
"OptionalConfigMapDoesNotExist",
@@ -292,7 +294,7 @@ func TestEnvVarValue(t *testing.T) {
ConfigMaps: configMapList,
},
true,
- "",
+ nil,
},
{
"EmptyConfigMapList",
@@ -311,7 +313,7 @@ func TestEnvVarValue(t *testing.T) {
ConfigMaps: []v1.ConfigMap{},
},
false,
- "",
+ nil,
},
{
"OptionalEmptyConfigMapList",
@@ -331,7 +333,7 @@ func TestEnvVarValue(t *testing.T) {
ConfigMaps: []v1.ConfigMap{},
},
true,
- "",
+ nil,
},
{
"SecretExists",
@@ -350,7 +352,7 @@ func TestEnvVarValue(t *testing.T) {
SecretsManager: secretsManager,
},
true,
- "foo",
+ &value,
},
{
"ContainerKeyDoesNotExistInSecret",
@@ -369,7 +371,7 @@ func TestEnvVarValue(t *testing.T) {
SecretsManager: secretsManager,
},
false,
- "",
+ nil,
},
{
"OptionalContainerKeyDoesNotExistInSecret",
@@ -389,7 +391,7 @@ func TestEnvVarValue(t *testing.T) {
SecretsManager: secretsManager,
},
true,
- "",
+ nil,
},
{
"SecretDoesNotExist",
@@ -408,7 +410,7 @@ func TestEnvVarValue(t *testing.T) {
SecretsManager: secretsManager,
},
false,
- "",
+ nil,
},
{
"OptionalSecretDoesNotExist",
@@ -428,7 +430,173 @@ func TestEnvVarValue(t *testing.T) {
SecretsManager: secretsManager,
},
true,
- "",
+ nil,
+ },
+ {
+ "FieldRefMetadataName",
+ v1.EnvVar{
+ Name: "FOO",
+ ValueFrom: &v1.EnvVarSource{
+ FieldRef: &v1.ObjectFieldSelector{
+ FieldPath: "metadata.name",
+ },
+ },
+ },
+ CtrSpecGenOptions{
+ PodName: value,
+ },
+ true,
+ &value,
+ },
+ {
+ "FieldRefMetadataUID",
+ v1.EnvVar{
+ Name: "FOO",
+ ValueFrom: &v1.EnvVarSource{
+ FieldRef: &v1.ObjectFieldSelector{
+ FieldPath: "metadata.uid",
+ },
+ },
+ },
+ CtrSpecGenOptions{
+ PodID: value,
+ },
+ true,
+ &value,
+ },
+ {
+ "FieldRefMetadataLabelsExist",
+ v1.EnvVar{
+ Name: "FOO",
+ ValueFrom: &v1.EnvVarSource{
+ FieldRef: &v1.ObjectFieldSelector{
+ FieldPath: "metadata.labels['label']",
+ },
+ },
+ },
+ CtrSpecGenOptions{
+ Labels: map[string]string{"label": value},
+ },
+ true,
+ &value,
+ },
+ {
+ "FieldRefMetadataLabelsEmpty",
+ v1.EnvVar{
+ Name: "FOO",
+ ValueFrom: &v1.EnvVarSource{
+ FieldRef: &v1.ObjectFieldSelector{
+ FieldPath: "metadata.labels['label']",
+ },
+ },
+ },
+ CtrSpecGenOptions{
+ Labels: map[string]string{"label": ""},
+ },
+ true,
+ &emptyValue,
+ },
+ {
+ "FieldRefMetadataLabelsNotExist",
+ v1.EnvVar{
+ Name: "FOO",
+ ValueFrom: &v1.EnvVarSource{
+ FieldRef: &v1.ObjectFieldSelector{
+ FieldPath: "metadata.labels['label']",
+ },
+ },
+ },
+ CtrSpecGenOptions{},
+ true,
+ &emptyValue,
+ },
+ {
+ "FieldRefMetadataAnnotationsExist",
+ v1.EnvVar{
+ Name: "FOO",
+ ValueFrom: &v1.EnvVarSource{
+ FieldRef: &v1.ObjectFieldSelector{
+ FieldPath: "metadata.annotations['annotation']",
+ },
+ },
+ },
+ CtrSpecGenOptions{
+ Annotations: map[string]string{"annotation": value},
+ },
+ true,
+ &value,
+ },
+ {
+ "FieldRefMetadataAnnotationsEmpty",
+ v1.EnvVar{
+ Name: "FOO",
+ ValueFrom: &v1.EnvVarSource{
+ FieldRef: &v1.ObjectFieldSelector{
+ FieldPath: "metadata.annotations['annotation']",
+ },
+ },
+ },
+ CtrSpecGenOptions{
+ Annotations: map[string]string{"annotation": ""},
+ },
+ true,
+ &emptyValue,
+ },
+ {
+ "FieldRefMetadataAnnotationsNotExist",
+ v1.EnvVar{
+ Name: "FOO",
+ ValueFrom: &v1.EnvVarSource{
+ FieldRef: &v1.ObjectFieldSelector{
+ FieldPath: "metadata.annotations['annotation']",
+ },
+ },
+ },
+ CtrSpecGenOptions{},
+ true,
+ &emptyValue,
+ },
+ {
+ "FieldRefInvalid1",
+ v1.EnvVar{
+ Name: "FOO",
+ ValueFrom: &v1.EnvVarSource{
+ FieldRef: &v1.ObjectFieldSelector{
+ FieldPath: "metadata.annotations['annotation]",
+ },
+ },
+ },
+ CtrSpecGenOptions{},
+ false,
+ nil,
+ },
+ {
+ "FieldRefInvalid2",
+ v1.EnvVar{
+ Name: "FOO",
+ ValueFrom: &v1.EnvVarSource{
+ FieldRef: &v1.ObjectFieldSelector{
+ FieldPath: "metadata.dummy['annotation']",
+ },
+ },
+ },
+ CtrSpecGenOptions{},
+ false,
+ nil,
+ },
+ {
+ "FieldRefNotSupported",
+ v1.EnvVar{
+ Name: "FOO",
+ ValueFrom: &v1.EnvVarSource{
+ FieldRef: &v1.ObjectFieldSelector{
+ FieldPath: "metadata.namespace",
+ },
+ },
+ },
+ CtrSpecGenOptions{},
+ false,
+ nil,
},
}