Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass environment variables from host to exec based tasks #970

Merged
merged 2 commits into from
Mar 23, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions client/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
24 changes: 24 additions & 0 deletions client/driver/env/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package env

import (
"fmt"
"os"
"strconv"
"strings"

Expand Down Expand Up @@ -305,6 +306,29 @@ func (t *TaskEnvironment) AppendEnvvars(m map[string]string) *TaskEnvironment {
return t
}

func (t *TaskEnvironment) AppendHostEnvvars(filter []string) *TaskEnvironment {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment

hostEnv := os.Environ()
if t.Env == nil {
t.Env = make(map[string]string, len(hostEnv))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is always going to be some Env, can we do this in the factory method?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That guard is if you are building the map for the first time

}

// 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]
if _, filtered := index[key]; !filtered {
t.Env[key] = value
}
}

return t
}

func (t *TaskEnvironment) ClearEnvvars() *TaskEnvironment {
t.Env = nil
return t
Expand Down
21 changes: 21 additions & 0 deletions client/driver/env/env_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package env

import (
"fmt"
"os"
"reflect"
"sort"
"strings"
"testing"

"github.com/hashicorp/nomad/nomad/mock"
Expand Down Expand Up @@ -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)
}
}
8 changes: 7 additions & 1 deletion client/driver/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"log"
"os/exec"
"path/filepath"
"strings"
"syscall"
"time"

Expand Down Expand Up @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions client/driver/java.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions client/driver/raw_exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"log"
"os/exec"
"path/filepath"
"strings"
"time"

"github.com/hashicorp/go-plugin"
Expand Down Expand Up @@ -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)
Expand Down
11 changes: 11 additions & 0 deletions website/source/docs/agent/config.html.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make this an array of strings instead of , separated values?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, options is a map[string]string

`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.
Expand Down