Allow absolute paths for template sources
This commit is contained in:
parent
b08f4e0b97
commit
2a5ac5e7ee
|
@ -18,6 +18,12 @@ import (
|
|||
"github.com/hashicorp/nomad/nomad/structs"
|
||||
)
|
||||
|
||||
const (
|
||||
// hostSrcOption is the Client option that determines whether the template
|
||||
// source may be from the host
|
||||
hostSrcOption = "template.allow_host_source"
|
||||
)
|
||||
|
||||
var (
|
||||
// testRetryRate is used to speed up tests by setting consul-templates retry
|
||||
// rate to something low
|
||||
|
@ -319,7 +325,11 @@ func templateRunner(tmpls []*structs.Template, config *config.Config,
|
|||
}
|
||||
|
||||
// Parse the templates
|
||||
ctmplMapping := parseTemplateConfigs(tmpls, taskDir, taskEnv)
|
||||
allowAbs := config.ReadBoolDefault(hostSrcOption, true)
|
||||
ctmplMapping, err := parseTemplateConfigs(tmpls, taskDir, taskEnv, allowAbs)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Set the config
|
||||
flat := make([]*ctconf.ConfigTemplate, 0, len(ctmplMapping))
|
||||
|
@ -349,7 +359,8 @@ func templateRunner(tmpls []*structs.Template, config *config.Config,
|
|||
}
|
||||
|
||||
// parseTemplateConfigs converts the tasks templates into consul-templates
|
||||
func parseTemplateConfigs(tmpls []*structs.Template, taskDir string, taskEnv *env.TaskEnvironment) map[ctconf.ConfigTemplate]*structs.Template {
|
||||
func parseTemplateConfigs(tmpls []*structs.Template, taskDir string,
|
||||
taskEnv *env.TaskEnvironment, allowAbs bool) (map[ctconf.ConfigTemplate]*structs.Template, error) {
|
||||
// Build the task environment
|
||||
// TODO Should be able to inject the Nomad env vars into Consul-template for
|
||||
// rendering
|
||||
|
@ -359,7 +370,15 @@ func parseTemplateConfigs(tmpls []*structs.Template, taskDir string, taskEnv *en
|
|||
for _, tmpl := range tmpls {
|
||||
var src, dest string
|
||||
if tmpl.SourcePath != "" {
|
||||
src = filepath.Join(taskDir, taskEnv.ReplaceEnv(tmpl.SourcePath))
|
||||
if filepath.IsAbs(tmpl.SourcePath) {
|
||||
if !allowAbs {
|
||||
return nil, fmt.Errorf("Specifying absolute template paths disallowed by client config: %q", tmpl.SourcePath)
|
||||
}
|
||||
|
||||
src = tmpl.SourcePath
|
||||
} else {
|
||||
src = filepath.Join(taskDir, taskEnv.ReplaceEnv(tmpl.SourcePath))
|
||||
}
|
||||
}
|
||||
if tmpl.DestPath != "" {
|
||||
dest = filepath.Join(taskDir, taskEnv.ReplaceEnv(tmpl.DestPath))
|
||||
|
@ -376,7 +395,7 @@ func parseTemplateConfigs(tmpls []*structs.Template, taskDir string, taskEnv *en
|
|||
ctmpls[ct] = tmpl
|
||||
}
|
||||
|
||||
return ctmpls
|
||||
return ctmpls, nil
|
||||
}
|
||||
|
||||
// runnerConfig returns a consul-template runner configuration, setting the
|
||||
|
|
|
@ -2,6 +2,7 @@ package client
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -139,6 +140,13 @@ func (h *testHarness) start(t *testing.T) {
|
|||
h.manager = manager
|
||||
}
|
||||
|
||||
func (h *testHarness) startWithErr() error {
|
||||
manager, err := NewTaskTemplateManager(h.mockHooks, h.templates,
|
||||
h.config, h.vaultToken, h.taskDir, h.taskEnv)
|
||||
h.manager = manager
|
||||
return err
|
||||
}
|
||||
|
||||
// stop is used to stop any running Vault or Consul server plus the task manager
|
||||
func (h *testHarness) stop() {
|
||||
if h.vault != nil {
|
||||
|
@ -210,6 +218,59 @@ func TestTaskTemplateManager_Invalid(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestTaskTemplateManager_HostPath(t *testing.T) {
|
||||
// Make a template that will render immediately and write it to a tmp file
|
||||
f, err := ioutil.TempFile("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Bad: %v", err)
|
||||
}
|
||||
defer f.Close()
|
||||
defer os.Remove(f.Name())
|
||||
|
||||
content := "hello, world!"
|
||||
if _, err := io.WriteString(f, content); err != nil {
|
||||
t.Fatalf("Bad: %v", err)
|
||||
}
|
||||
|
||||
file := "my.tmpl"
|
||||
template := &structs.Template{
|
||||
SourcePath: f.Name(),
|
||||
DestPath: file,
|
||||
ChangeMode: structs.TemplateChangeModeNoop,
|
||||
}
|
||||
|
||||
harness := newTestHarness(t, []*structs.Template{template}, false, false)
|
||||
harness.start(t)
|
||||
defer harness.stop()
|
||||
|
||||
// Wait for the unblock
|
||||
select {
|
||||
case <-harness.mockHooks.UnblockCh:
|
||||
case <-time.After(time.Duration(5*testutil.TestMultiplier()) * time.Second):
|
||||
t.Fatalf("Task unblock should have been called")
|
||||
}
|
||||
|
||||
// Check the file is there
|
||||
path := filepath.Join(harness.taskDir, file)
|
||||
raw, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read rendered template from %q: %v", path, err)
|
||||
}
|
||||
|
||||
if s := string(raw); s != content {
|
||||
t.Fatalf("Unexpected template data; got %q, want %q", s, content)
|
||||
}
|
||||
|
||||
// Change the config to disallow host sources
|
||||
harness = newTestHarness(t, []*structs.Template{template}, false, false)
|
||||
harness.config.Options = map[string]string{
|
||||
hostSrcOption: "false",
|
||||
}
|
||||
if err := harness.startWithErr(); err == nil || !strings.Contains(err.Error(), "absolute") {
|
||||
t.Fatalf("Expected absolute template path disallowed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTaskTemplateManager_Unblock_Static(t *testing.T) {
|
||||
// Make a template that will render immediately
|
||||
content := "hello, world!"
|
||||
|
|
|
@ -121,5 +121,13 @@ template {
|
|||
}
|
||||
```
|
||||
|
||||
### Client Configuration
|
||||
|
||||
The `template` block has the following [client configuration
|
||||
options](/docs/agent/config.html#options):
|
||||
|
||||
* `template.allow_host_source` - Allows templates to specify their source
|
||||
template as an absolute path referencing host directories. Defaults to `true`.
|
||||
|
||||
[ct]: https://github.com/hashicorp/consul-template "Consul Template by HashiCorp"
|
||||
[artifact]: /docs/job-specification/artifact.html "Nomad artifact Job Specification"
|
||||
|
|
Loading…
Reference in New Issue