func ExpandContainerCommandAndArgs(container *v1.Container, envs []EnvVar) (command []string, args []string) { mapping := expansion.MappingFuncFor(EnvVarsToMap(envs)) if len(container.Command) != 0 { for _, cmd := range container.Command { command = append(command, expansion.Expand(cmd, mapping)) } } if len(container.Args) != 0 { for _, arg := range container.Args { args = append(args, expansion.Expand(arg, mapping)) } } return command, args }
// Make the environment variables for a pod in the given namespace. func (kl *Kubelet) makeEnvironmentVariables(pod *api.Pod, container *api.Container, podIP string) ([]kubecontainer.EnvVar, error) { var result []kubecontainer.EnvVar // Note: These are added to the docker Config, but are not included in the checksum computed // by dockertools.BuildDockerName(...). That way, we can still determine whether an // api.Container is already running by its hash. (We don't want to restart a container just // because some service changed.) // // Note that there is a race between Kubelet seeing the pod and kubelet seeing the service. // To avoid this users can: (1) wait between starting a service and starting; or (2) detect // missing service env var and exit and be restarted; or (3) use DNS instead of env vars // and keep trying to resolve the DNS name of the service (recommended). serviceEnv, err := kl.getServiceEnvVarMap(pod.Namespace) if err != nil { return result, err } // Determine the final values of variables: // // 1. Determine the final value of each variable: // a. If the variable's Value is set, expand the `$(var)` references to other // variables in the .Value field; the sources of variables are the declared // variables of the container and the service environment variables // b. If a source is defined for an environment variable, resolve the source // 2. Create the container's environment in the order variables are declared // 3. Add remaining service environment vars var ( tmpEnv = make(map[string]string) configMaps = make(map[string]*api.ConfigMap) secrets = make(map[string]*api.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 net line once all platforms use apiserver+Pods. delete(serviceEnv, envVar.Name) runtimeVal := envVar.Value if runtimeVal != "" { // Step 1a: expand variable references runtimeVal = expansion.Expand(runtimeVal, mappingFunc) } else if envVar.ValueFrom != nil { // Step 1b: resolve alternate env var sources switch { case envVar.ValueFrom.FieldRef != nil: runtimeVal, err = kl.podFieldSelectorRuntimeValue(envVar.ValueFrom.FieldRef, pod, podIP) if err != nil { return result, err } case envVar.ValueFrom.ResourceFieldRef != nil: defaultedPod, defaultedContainer, err := kl.defaultPodLimitsForDownwardApi(pod, container) if err != nil { return result, err } runtimeVal, err = containerResourceRuntimeValue(envVar.ValueFrom.ResourceFieldRef, defaultedPod, defaultedContainer) if err != nil { return result, err } case envVar.ValueFrom.ConfigMapKeyRef != nil: name := envVar.ValueFrom.ConfigMapKeyRef.Name key := envVar.ValueFrom.ConfigMapKeyRef.Key configMap, ok := configMaps[name] if !ok { if kl.kubeClient == nil { 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) if err != nil { return result, err } configMaps[name] = configMap } runtimeVal, ok = configMap.Data[key] if !ok { return result, fmt.Errorf("Couldn't find key %v in ConfigMap %v/%v", key, pod.Namespace, name) } case envVar.ValueFrom.SecretKeyRef != nil: name := envVar.ValueFrom.SecretKeyRef.Name key := envVar.ValueFrom.SecretKeyRef.Key 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) if err != nil { return result, err } secrets[name] = secret } runtimeValBytes, ok := secret.Data[key] if !ok { return result, fmt.Errorf("Couldn't find key %v in Secret %v/%v", key, pod.Namespace, name) } runtimeVal = string(runtimeValBytes) } } tmpEnv[envVar.Name] = runtimeVal result = append(result, kubecontainer.EnvVar{Name: envVar.Name, Value: tmpEnv[envVar.Name]}) } // Append remaining service env vars. for k, v := range serviceEnv { result = append(result, kubecontainer.EnvVar{Name: k, Value: v}) } return result, nil }