Fix env templates having interpolated destinations

Fixes an issue where env templates that had interpolated destinations
would not work.

Fixes https://github.com/hashicorp/nomad/issues/5250
This commit is contained in:
Alex Dadgar 2019-01-28 10:28:53 -08:00
parent 144535203d
commit 5da21635fb
3 changed files with 56 additions and 8 deletions

View File

@ -205,7 +205,7 @@ func (tm *TaskTemplateManager) run() {
}
// Read environment variables from env templates before we unblock
envMap, err := loadTemplateEnv(tm.config.Templates, tm.config.TaskDir)
envMap, err := loadTemplateEnv(tm.config.Templates, tm.config.TaskDir, tm.config.EnvBuilder.Build())
if err != nil {
tm.config.Lifecycle.Kill(context.Background(),
structs.NewTaskEvent(structs.TaskKilling).
@ -393,7 +393,7 @@ func (tm *TaskTemplateManager) handleTemplateRerenders(allRenderedTime time.Time
}
// Read environment variables from templates
envMap, err := loadTemplateEnv(tm.config.Templates, tm.config.TaskDir)
envMap, err := loadTemplateEnv(tm.config.Templates, tm.config.TaskDir, tm.config.EnvBuilder.Build())
if err != nil {
tm.config.Lifecycle.Kill(context.Background(),
structs.NewTaskEvent(structs.TaskKilling).
@ -676,13 +676,15 @@ func newRunnerConfig(config *TaskTemplateManagerConfig,
}
// loadTemplateEnv loads task environment variables from all templates.
func loadTemplateEnv(tmpls []*structs.Template, taskDir string) (map[string]string, error) {
func loadTemplateEnv(tmpls []*structs.Template, taskDir string, taskEnv *taskenv.TaskEnv) (map[string]string, error) {
all := make(map[string]string, 50)
for _, t := range tmpls {
if !t.Envvars {
continue
}
f, err := os.Open(filepath.Join(taskDir, t.DestPath))
dest := filepath.Join(taskDir, taskEnv.ReplaceEnv(t.DestPath))
f, err := os.Open(dest)
if err != nil {
return nil, fmt.Errorf("error opening env template: %v", err)
}
@ -691,7 +693,7 @@ func loadTemplateEnv(tmpls []*structs.Template, taskDir string) (map[string]stri
// Parse environment fil
vars, err := envparse.Parse(f)
if err != nil {
return nil, fmt.Errorf("error parsing env template %q: %v", t.DestPath, err)
return nil, fmt.Errorf("error parsing env template %q: %v", dest, err)
}
for k, v := range vars {
all[k] = v

View File

@ -1087,11 +1087,48 @@ func TestTaskTemplateManager_Env_Missing(t *testing.T) {
},
}
if vars, err := loadTemplateEnv(templates, d); err == nil {
if vars, err := loadTemplateEnv(templates, d, taskenv.NewEmptyTaskEnv()); err == nil {
t.Fatalf("expected an error but instead got env vars: %#v", vars)
}
}
// TestTaskTemplateManager_Env_InterpolatedDest asserts the core env
// template processing function handles interpolated destinations
func TestTaskTemplateManager_Env_InterpolatedDest(t *testing.T) {
t.Parallel()
require := require.New(t)
d, err := ioutil.TempDir("", "ct_env_interpolated")
if err != nil {
t.Fatalf("err: %v", err)
}
defer os.RemoveAll(d)
// Fake writing the file so we don't have to run the whole template manager
err = ioutil.WriteFile(filepath.Join(d, "exists.env"), []byte("FOO=bar\n"), 0644)
if err != nil {
t.Fatalf("error writing template file: %v", err)
}
templates := []*structs.Template{
{
EmbeddedTmpl: "FOO=bar\n",
DestPath: "${NOMAD_META_path}.env",
Envvars: true,
},
}
// Build the env
taskEnv := taskenv.NewTaskEnv(
map[string]string{"NOMAD_META_path": "exists"},
map[string]string{}, map[string]string{})
vars, err := loadTemplateEnv(templates, d, taskEnv)
require.NoError(err)
require.Contains(vars, "FOO")
require.Equal(vars["FOO"], "bar")
}
// TestTaskTemplateManager_Env_Multi asserts the core env
// template processing function returns combined env vars from multiple
// templates correctly.
@ -1125,9 +1162,9 @@ func TestTaskTemplateManager_Env_Multi(t *testing.T) {
},
}
vars, err := loadTemplateEnv(templates, d)
vars, err := loadTemplateEnv(templates, d, taskenv.NewEmptyTaskEnv())
if err != nil {
t.Fatalf("expected an error but instead got env vars: %#v", vars)
t.Fatalf("expected no error: %v", err)
}
if vars["FOO"] != "bar" {
t.Errorf("expected FOO=bar but found %q", vars["FOO"])

View File

@ -126,6 +126,15 @@ func NewTaskEnv(env, deviceEnv, node map[string]string) *TaskEnv {
}
}
// NewEmptyTaskEnv creates a new empty task environment.
func NewEmptyTaskEnv() *TaskEnv {
return &TaskEnv{
NodeAttrs: make(map[string]string),
deviceEnv: make(map[string]string),
EnvMap: make(map[string]string),
}
}
// List returns the task's environment as a slice of NAME=value pair strings.
func (t *TaskEnv) List() []string {
if t.envList != nil {