Merge pull request #970 from hashicorp/f-pass-env

Pass environment variables from host to exec based tasks
This commit is contained in:
Alex Dadgar 2016-03-23 14:07:29 -07:00
commit abcf97e937
7 changed files with 95 additions and 1 deletions

View File

@ -10,6 +10,18 @@ import (
"github.com/hashicorp/nomad/nomad/structs"
)
var (
// DefaultEnvBlacklist is the default set of environment variables that are
// filtered when passing the environment variables of the host to a task.
DefaultEnvBlacklist = strings.Join([]string{
"CONSUL_TOKEN",
"VAULT_TOKEN",
"ATLAS_TOKEN",
"AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN",
"GOOGLE_APPLICATION_CREDENTIALS",
}, ",")
)
// RPCHandler can be provided to the Client if there is a local server
// to avoid going over the network. If not provided, the Client will
// maintain a connection pool to the servers

View File

@ -2,6 +2,7 @@ package env
import (
"fmt"
"os"
"strconv"
"strings"
@ -305,6 +306,39 @@ func (t *TaskEnvironment) AppendEnvvars(m map[string]string) *TaskEnvironment {
return t
}
// AppendHostEnvvars adds the host environment variables to the tasks. The
// filter parameter can be use to filter host environment from entering the
// tasks.
func (t *TaskEnvironment) AppendHostEnvvars(filter []string) *TaskEnvironment {
hostEnv := os.Environ()
if t.Env == nil {
t.Env = make(map[string]string, len(hostEnv))
}
// Index the filtered environment variables.
index := make(map[string]struct{}, len(filter))
for _, f := range filter {
index[f] = struct{}{}
}
for _, e := range hostEnv {
parts := strings.Split(e, "=")
key, value := parts[0], parts[1]
// Skip filtered environment variables
if _, filtered := index[key]; filtered {
continue
}
// Don't override the tasks environment variables.
if _, existing := t.Env[key]; !existing {
t.Env[key] = value
}
}
return t
}
func (t *TaskEnvironment) ClearEnvvars() *TaskEnvironment {
t.Env = nil
return t

View File

@ -2,8 +2,10 @@ package env
import (
"fmt"
"os"
"reflect"
"sort"
"strings"
"testing"
"github.com/hashicorp/nomad/nomad/mock"
@ -204,3 +206,22 @@ func TestEnvironment_Interprolate(t *testing.T) {
t.Fatalf("env.List() returned %v; want %v", act, exp)
}
}
func TestEnvironment_AppendHostEnvVars(t *testing.T) {
host := os.Environ()
if len(host) < 2 {
t.Skip("No host environment variables. Can't test")
}
skip := strings.Split(host[0], "=")[0]
env := testTaskEnvironment().
AppendHostEnvvars([]string{skip}).
Build()
act := env.EnvMap()
if len(act) < 1 {
t.Fatalf("Host environment variables not properly set")
}
if _, ok := act[skip]; ok {
t.Fatalf("Didn't filter environment variable %q", skip)
}
}

View File

@ -6,6 +6,7 @@ import (
"log"
"os/exec"
"path/filepath"
"strings"
"syscall"
"time"
@ -74,13 +75,18 @@ func (d *ExecDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle,
if err := mapstructure.WeakDecode(task.Config, &driverConfig); err != nil {
return nil, err
}
// Get the command to be ran
command := driverConfig.Command
if err := validateCommand(command, "args"); err != nil {
return nil, err
}
// Create a location to download the artifact.
// Set the host environment variables.
filter := strings.Split(d.config.ReadDefault("env.blacklist", config.DefaultEnvBlacklist), ",")
d.taskEnv.AppendHostEnvvars(filter)
// Get the task directory for storing the executor logs.
taskDir, ok := ctx.AllocDir.TaskDirs[d.DriverContext.taskName]
if !ok {
return nil, fmt.Errorf("Could not find task directory for task: %v", d.DriverContext.taskName)

View File

@ -117,6 +117,11 @@ func (d *JavaDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle,
if err := mapstructure.WeakDecode(task.Config, &driverConfig); err != nil {
return nil, err
}
// Set the host environment variables.
filter := strings.Split(d.config.ReadDefault("env.blacklist", config.DefaultEnvBlacklist), ",")
d.taskEnv.AppendHostEnvvars(filter)
taskDir, ok := ctx.AllocDir.TaskDirs[d.DriverContext.taskName]
if !ok {
return nil, fmt.Errorf("Could not find task directory for task: %v", d.DriverContext.taskName)

View File

@ -6,6 +6,7 @@ import (
"log"
"os/exec"
"path/filepath"
"strings"
"time"
"github.com/hashicorp/go-plugin"
@ -82,6 +83,10 @@ func (d *RawExecDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandl
return nil, err
}
// Set the host environment variables.
filter := strings.Split(d.config.ReadDefault("env.blacklist", config.DefaultEnvBlacklist), ",")
d.taskEnv.AppendHostEnvvars(filter)
bin, err := discover.NomadExecutable()
if err != nil {
return nil, fmt.Errorf("unable to find the nomad binary: %v", err)

View File

@ -370,6 +370,17 @@ documentation [here](/docs/drivers/index.html)
If the whitelist is empty, all drivers are fingerprinted and enabled where
applicable.
* `env.blacklist`: Nomad passes the host environment variables to `exec`,
`raw_exec` and `java` tasks. `env.blacklist` is a comma seperated list of
environment variable keys not to pass to these tasks. If specified, the
defaults are overriden. The following are the default:
* `CONSUL_TOKEN`
* `VAULT_TOKEN`
* `ATLAS_TOKEN`
* `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`
* `GOOGLE_APPLICATION_CREDENTIALS`
* `fingerprint.whitelist`: A comma separated list of whitelisted fingerprinters.
If specified, fingerprinters not in the whitelist will be disabled. If the
whitelist is empty, all fingerprinters are used.