Refactor env.go

This copies and pastes the loop that used to exist in

func populateEnvironmentVariables(..) {
	...
	for _, env := range container.Env {
		... <--- This code
	}
}

Into getEnvironmentVariableValue. getEnvironmentVariableValue
returns val, err, where val is a pointer to a string
to indicate optionality.
This commit is contained in:
Sargun Dhillon
2020-11-13 10:29:29 -08:00
parent affbd27827
commit 06c089843e
2 changed files with 141 additions and 133 deletions

1
go.mod
View File

@@ -27,6 +27,7 @@ require (
k8s.io/klog v1.0.0 k8s.io/klog v1.0.0
k8s.io/klog/v2 v2.0.0 k8s.io/klog/v2 v2.0.0
k8s.io/kubernetes v1.18.4 k8s.io/kubernetes v1.18.4
k8s.io/utils v0.0.0-20200603063816-c1c6865ac451
sigs.k8s.io/controller-runtime v0.6.3 sigs.k8s.io/controller-runtime v0.6.3
) )

View File

@@ -20,6 +20,8 @@ import (
"sort" "sort"
"strings" "strings"
"github.com/virtual-kubelet/virtual-kubelet/internal/manager"
"github.com/virtual-kubelet/virtual-kubelet/log"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -31,9 +33,7 @@ import (
fieldpath "k8s.io/kubernetes/pkg/fieldpath" fieldpath "k8s.io/kubernetes/pkg/fieldpath"
"k8s.io/kubernetes/pkg/kubelet/envvars" "k8s.io/kubernetes/pkg/kubelet/envvars"
"k8s.io/kubernetes/third_party/forked/golang/expansion" "k8s.io/kubernetes/third_party/forked/golang/expansion"
"k8s.io/utils/pointer"
"github.com/virtual-kubelet/virtual-kubelet/internal/manager"
"github.com/virtual-kubelet/virtual-kubelet/log"
) )
const ( const (
@@ -292,7 +292,6 @@ loop:
// makeEnvironmentMap returns a map representing the resolved environment of the specified container after being populated from the entries in the ".env" and ".envFrom" field. // makeEnvironmentMap returns a map representing the resolved environment of the specified container after being populated from the entries in the ".env" and ".envFrom" field.
func makeEnvironmentMap(ctx context.Context, pod *corev1.Pod, container *corev1.Container, rm *manager.ResourceManager, recorder record.EventRecorder, res map[string]string) error { func makeEnvironmentMap(ctx context.Context, pod *corev1.Pod, container *corev1.Container, rm *manager.ResourceManager, recorder record.EventRecorder, res map[string]string) error {
// TODO If pod.Spec.EnableServiceLinks is nil then fail as per 1.14 kubelet. // TODO If pod.Spec.EnableServiceLinks is nil then fail as per 1.14 kubelet.
enableServiceLinks := corev1.DefaultEnableServiceLinks enableServiceLinks := corev1.DefaultEnableServiceLinks
if pod.Spec.EnableServiceLinks != nil { if pod.Spec.EnableServiceLinks != nil {
@@ -314,14 +313,32 @@ func makeEnvironmentMap(ctx context.Context, pod *corev1.Pod, container *corev1.
mappingFunc := expansion.MappingFuncFor(res, svcEnv) mappingFunc := expansion.MappingFuncFor(res, svcEnv)
// Iterate over environment variables in order to populate the map. // Iterate over environment variables in order to populate the map.
loop:
for _, env := range container.Env { for _, env := range container.Env {
val, err := getEnvironmentVariableValue(ctx, &env, mappingFunc, pod, container, rm, recorder)
if err != nil {
return err
}
if val != nil {
res[env.Name] = *val
}
}
// Append service env vars.
for k, v := range svcEnv {
if _, present := res[k]; !present {
res[k] = v
}
}
return nil
}
func getEnvironmentVariableValue(ctx context.Context, env *corev1.EnvVar, mappingFunc func(string) string, pod *corev1.Pod, container *corev1.Container, rm *manager.ResourceManager, recorder record.EventRecorder) (*string, error) {
switch { switch {
// Handle values that have been directly provided. // Handle values that have been directly provided.
case env.Value != "": case env.Value != "":
// Expand variable references // Expand variable references
res[env.Name] = expansion.Expand(env.Value, mappingFunc) return pointer.StringPtr(expansion.Expand(env.Value, mappingFunc)), nil
continue loop
// Handle population from a configmap key. // Handle population from a configmap key.
case env.ValueFrom != nil && env.ValueFrom.ConfigMapKeyRef != nil: case env.ValueFrom != nil && env.ValueFrom.ConfigMapKeyRef != nil:
// The environment variable must be set from a configmap. // The environment variable must be set from a configmap.
@@ -342,16 +359,16 @@ loop:
recorder.Eventf(pod, corev1.EventTypeWarning, ReasonFailedToReadOptionalConfigMap, "skipping optional envvar %q: failed to read configmap %q", env.Name, vf.Name) recorder.Eventf(pod, corev1.EventTypeWarning, ReasonFailedToReadOptionalConfigMap, "skipping optional envvar %q: failed to read configmap %q", env.Name, vf.Name)
} }
// Continue on to the next reference. // Continue on to the next reference.
continue loop return nil, nil
} }
// At this point we know the key reference is mandatory. // At this point we know the key reference is mandatory.
// Hence, we should return a meaningful error. // Hence, we should return a meaningful error.
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
recorder.Eventf(pod, corev1.EventTypeWarning, ReasonMandatoryConfigMapNotFound, "configmap %q not found", vf.Name) recorder.Eventf(pod, corev1.EventTypeWarning, ReasonMandatoryConfigMapNotFound, "configmap %q not found", vf.Name)
return fmt.Errorf("configmap %q not found", vf.Name) return nil, fmt.Errorf("configmap %q not found", vf.Name)
} }
recorder.Eventf(pod, corev1.EventTypeWarning, ReasonFailedToReadMandatoryConfigMap, "failed to read configmap %q", vf.Name) recorder.Eventf(pod, corev1.EventTypeWarning, ReasonFailedToReadMandatoryConfigMap, "failed to read configmap %q", vf.Name)
return fmt.Errorf("failed to read configmap %q: %v", vf.Name, err) return nil, fmt.Errorf("failed to read configmap %q: %v", vf.Name, err)
} }
// At this point we have successfully fetched the target configmap. // At this point we have successfully fetched the target configmap.
// We must now try to grab the requested key. // We must now try to grab the requested key.
@@ -365,16 +382,15 @@ loop:
if optional { if optional {
// Continue on to the next reference. // Continue on to the next reference.
recorder.Eventf(pod, corev1.EventTypeWarning, ReasonOptionalConfigMapKeyNotFound, "skipping optional envvar %q: key %q does not exist in configmap %q", env.Name, vf.Key, vf.Name) recorder.Eventf(pod, corev1.EventTypeWarning, ReasonOptionalConfigMapKeyNotFound, "skipping optional envvar %q: key %q does not exist in configmap %q", env.Name, vf.Key, vf.Name)
continue loop return nil, nil
} }
// At this point we know the key reference is mandatory. // At this point we know the key reference is mandatory.
// Hence, we should fail. // Hence, we should fail.
recorder.Eventf(pod, corev1.EventTypeWarning, ReasonMandatoryConfigMapKeyNotFound, "key %q does not exist in configmap %q", vf.Key, vf.Name) recorder.Eventf(pod, corev1.EventTypeWarning, ReasonMandatoryConfigMapKeyNotFound, "key %q does not exist in configmap %q", vf.Key, vf.Name)
return fmt.Errorf("configmap %q doesn't contain the %q key required by pod %s", vf.Name, vf.Key, pod.Name) return nil, fmt.Errorf("configmap %q doesn't contain the %q key required by pod %s", vf.Name, vf.Key, pod.Name)
} }
// Populate the environment variable and continue on to the next reference. // Populate the environment variable and continue on to the next reference.
res[env.Name] = keyValue return pointer.StringPtr(keyValue), nil
continue loop
// Handle population from a secret key. // Handle population from a secret key.
case env.ValueFrom != nil && env.ValueFrom.SecretKeyRef != nil: case env.ValueFrom != nil && env.ValueFrom.SecretKeyRef != nil:
vf := env.ValueFrom.SecretKeyRef vf := env.ValueFrom.SecretKeyRef
@@ -394,16 +410,16 @@ loop:
recorder.Eventf(pod, corev1.EventTypeWarning, ReasonFailedToReadOptionalSecret, "skipping optional envvar %q: failed to read secret %q", env.Name, vf.Name) recorder.Eventf(pod, corev1.EventTypeWarning, ReasonFailedToReadOptionalSecret, "skipping optional envvar %q: failed to read secret %q", env.Name, vf.Name)
} }
// Continue on to the next reference. // Continue on to the next reference.
continue loop return nil, nil
} }
// At this point we know the key reference is mandatory. // At this point we know the key reference is mandatory.
// Hence, we should return a meaningful error. // Hence, we should return a meaningful error.
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
recorder.Eventf(pod, corev1.EventTypeWarning, ReasonMandatorySecretNotFound, "secret %q not found", vf.Name) recorder.Eventf(pod, corev1.EventTypeWarning, ReasonMandatorySecretNotFound, "secret %q not found", vf.Name)
return fmt.Errorf("secret %q not found", vf.Name) return nil, fmt.Errorf("secret %q not found", vf.Name)
} }
recorder.Eventf(pod, corev1.EventTypeWarning, ReasonFailedToReadMandatorySecret, "failed to read secret %q", vf.Name) recorder.Eventf(pod, corev1.EventTypeWarning, ReasonFailedToReadMandatorySecret, "failed to read secret %q", vf.Name)
return fmt.Errorf("failed to read secret %q: %v", vf.Name, err) return nil, fmt.Errorf("failed to read secret %q: %v", vf.Name, err)
} }
// At this point we have successfully fetched the target secret. // At this point we have successfully fetched the target secret.
// We must now try to grab the requested key. // We must now try to grab the requested key.
@@ -417,16 +433,15 @@ loop:
if optional { if optional {
// Continue on to the next reference. // Continue on to the next reference.
recorder.Eventf(pod, corev1.EventTypeWarning, ReasonOptionalSecretKeyNotFound, "skipping optional envvar %q: key %q does not exist in secret %q", env.Name, vf.Key, vf.Name) recorder.Eventf(pod, corev1.EventTypeWarning, ReasonOptionalSecretKeyNotFound, "skipping optional envvar %q: key %q does not exist in secret %q", env.Name, vf.Key, vf.Name)
continue loop return nil, nil
} }
// At this point we know the key reference is mandatory. // At this point we know the key reference is mandatory.
// Hence, we should fail. // Hence, we should fail.
recorder.Eventf(pod, corev1.EventTypeWarning, ReasonMandatorySecretKeyNotFound, "key %q does not exist in secret %q", vf.Key, vf.Name) recorder.Eventf(pod, corev1.EventTypeWarning, ReasonMandatorySecretKeyNotFound, "key %q does not exist in secret %q", vf.Key, vf.Name)
return fmt.Errorf("secret %q doesn't contain the %q key required by pod %s", vf.Name, vf.Key, pod.Name) return nil, fmt.Errorf("secret %q doesn't contain the %q key required by pod %s", vf.Name, vf.Key, pod.Name)
} }
// Populate the environment variable and continue on to the next reference. // Populate the environment variable and continue on to the next reference.
res[env.Name] = string(keyValue) return pointer.StringPtr(string(keyValue)), nil
continue loop
// Handle population from a field (downward API). // Handle population from a field (downward API).
case env.ValueFrom != nil && env.ValueFrom.FieldRef != nil: case env.ValueFrom != nil && env.ValueFrom.FieldRef != nil:
// https://github.com/virtual-kubelet/virtual-kubelet/issues/123 // https://github.com/virtual-kubelet/virtual-kubelet/issues/123
@@ -434,29 +449,21 @@ loop:
runtimeVal, err := podFieldSelectorRuntimeValue(vf, pod) runtimeVal, err := podFieldSelectorRuntimeValue(vf, pod)
if err != nil { if err != nil {
return err return nil, err
} }
res[env.Name] = runtimeVal return pointer.StringPtr(runtimeVal), nil
continue loop
// Handle population from a resource request/limit. // Handle population from a resource request/limit.
case env.ValueFrom != nil && env.ValueFrom.ResourceFieldRef != nil: case env.ValueFrom != nil && env.ValueFrom.ResourceFieldRef != nil:
// TODO Implement populating resource requests. // TODO Implement populating resource requests.
continue loop return nil, nil
default:
// TODO: Should we throw an error here?
log.G(ctx).WithField("env", env).Error("Unhandled environment variable, do not know how to populate")
return nil, nil
} }
} }
// Append service env vars.
for k, v := range svcEnv {
if _, present := res[k]; !present {
res[k] = v
}
}
return nil
}
// podFieldSelectorRuntimeValue returns the runtime value of the given // podFieldSelectorRuntimeValue returns the runtime value of the given
// selector for a pod. // selector for a pod.
func podFieldSelectorRuntimeValue(fs *corev1.ObjectFieldSelector, pod *corev1.Pod) (string, error) { func podFieldSelectorRuntimeValue(fs *corev1.ObjectFieldSelector, pod *corev1.Pod) (string, error) {