Template destination file permissions.

This PR allows setting the file permissions of the rendered template.
This commit is contained in:
Alex Dadgar
2017-01-31 20:00:33 -08:00
parent 8e2b0a8d26
commit 9afa48310e
10 changed files with 110 additions and 10 deletions

View File

@@ -179,6 +179,7 @@ type Template struct {
ChangeMode string
ChangeSignal string
Splay time.Duration
Perms string
}
type Vault struct {

View File

@@ -5,6 +5,7 @@ import (
"math/rand"
"os"
"path/filepath"
"strconv"
"strings"
"sync"
"time"
@@ -393,6 +394,16 @@ func parseTemplateConfigs(tmpls []*structs.Template, taskDir string,
ct.Source = &src
ct.Destination = &dest
ct.Contents = &tmpl.EmbeddedTmpl
// Set the permissions
if tmpl.Perms != "" {
v, err := strconv.ParseUint(tmpl.Perms, 8, 12)
if err != nil {
return nil, fmt.Errorf("Failed to parse %q as octal: %v", tmpl.Perms, err)
}
m := os.FileMode(v)
ct.Perms = &m
}
ct.Finalize()
ctmpls[*ct] = tmpl

View File

@@ -310,6 +310,40 @@ func TestTaskTemplateManager_Unblock_Static(t *testing.T) {
}
}
func TestTaskTemplateManager_Permissions(t *testing.T) {
// Make a template that will render immediately
content := "hello, world!"
file := "my.tmpl"
template := &structs.Template{
EmbeddedTmpl: content,
DestPath: file,
ChangeMode: structs.TemplateChangeModeNoop,
Perms: "777",
}
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)
fi, err := os.Stat(path)
if err != nil {
t.Fatalf("Failed to stat file: %v", err)
}
if m := fi.Mode(); m != os.ModePerm {
t.Fatalf("Got mode %v; want %v", m, os.ModePerm)
}
}
func TestTaskTemplateManager_Unblock_Static_NomadEnv(t *testing.T) {
// Make a template that will render immediately
content := `Hello Nomad Task: {{env "NOMAD_TASK_NAME"}}`

View File

@@ -854,13 +854,13 @@ func parseTemplates(result *[]*structs.Template, list *ast.ObjectList) error {
for _, o := range list.Elem().Items {
// Check for invalid keys
valid := []string{
"source",
"destination",
"data",
"change_mode",
"change_signal",
"data",
"destination",
"perms",
"source",
"splay",
"once",
}
if err := checkHCLKeys(o.Val, valid); err != nil {
return err

View File

@@ -170,6 +170,7 @@ func TestParse(t *testing.T) {
ChangeMode: "foo",
ChangeSignal: "foo",
Splay: 10 * time.Second,
Perms: "0644",
},
{
SourcePath: "bar",
@@ -177,6 +178,7 @@ func TestParse(t *testing.T) {
ChangeMode: structs.TemplateChangeModeRestart,
ChangeSignal: "",
Splay: 5 * time.Second,
Perms: "777",
},
},
},

View File

@@ -145,6 +145,7 @@ job "binstore-storagelocker" {
template {
source = "bar"
destination = "bar"
perms = "777"
}
}

View File

@@ -3544,6 +3544,7 @@ func TestTaskDiff(t *testing.T) {
ChangeMode: "bam",
ChangeSignal: "SIGHUP",
Splay: 1,
Perms: "0644",
},
{
SourcePath: "foo2",
@@ -3552,6 +3553,7 @@ func TestTaskDiff(t *testing.T) {
ChangeMode: "bam2",
ChangeSignal: "SIGHUP2",
Splay: 2,
Perms: "0666",
},
},
},
@@ -3564,6 +3566,7 @@ func TestTaskDiff(t *testing.T) {
ChangeMode: "bam",
ChangeSignal: "SIGHUP",
Splay: 1,
Perms: "0644",
},
{
SourcePath: "foo3",
@@ -3572,6 +3575,7 @@ func TestTaskDiff(t *testing.T) {
ChangeMode: "bam3",
ChangeSignal: "SIGHUP3",
Splay: 3,
Perms: "0776",
},
},
},
@@ -3606,6 +3610,12 @@ func TestTaskDiff(t *testing.T) {
Old: "",
New: "baz3",
},
{
Type: DiffTypeAdded,
Name: "Perms",
Old: "",
New: "0776",
},
{
Type: DiffTypeAdded,
Name: "SourcePath",
@@ -3648,6 +3658,12 @@ func TestTaskDiff(t *testing.T) {
Old: "baz2",
New: "",
},
{
Type: DiffTypeDeleted,
Name: "Perms",
Old: "0666",
New: "",
},
{
Type: DiffTypeDeleted,
Name: "SourcePath",

View File

@@ -2589,6 +2589,9 @@ type Template struct {
// random wait between 0 and the given splay value before signalling the
// application of a change
Splay time.Duration `mapstructure:"splay"`
// Perms is the permission the file should be written out with.
Perms string `mapstructure:"perms"`
}
// DefaultTemplate returns a default template.
@@ -2596,6 +2599,7 @@ func DefaultTemplate() *Template {
return &Template{
ChangeMode: TemplateChangeModeRestart,
Splay: 5 * time.Second,
Perms: "0644",
}
}
@@ -2651,6 +2655,13 @@ func (t *Template) Validate() error {
multierror.Append(&mErr, fmt.Errorf("Must specify positive splay value"))
}
// Verify the permissions
if t.Perms != "" {
if _, err := strconv.ParseUint(t.Perms, 8, 12); err != nil {
multierror.Append(&mErr, fmt.Errorf("Failed to parse %q as octal: %v", t.Perms, err))
}
}
return mErr.ErrorOrNil()
}

View File

@@ -733,6 +733,27 @@ func TestTemplate_Validate(t *testing.T) {
},
Fail: false,
},
{
Tmpl: &Template{
SourcePath: "foo",
DestPath: "local/foo",
ChangeMode: "noop",
Perms: "0444",
},
Fail: false,
},
{
Tmpl: &Template{
SourcePath: "foo",
DestPath: "local/foo",
ChangeMode: "noop",
Perms: "zza",
},
Fail: true,
ContainsErrs: []string{
"as octal",
},
},
}
for i, c := range cases {

View File

@@ -47,6 +47,13 @@ README][ct].
## `template` Parameters
- `change_mode` `(string: "restart")` - Specifies the behavior Nomad should take
if the rendered template changes. The possible values are:
- `"noop"` - take no action (continue running the task)
- `"restart"` - restart the task
- `"signal"` - send a configurable signal to the task
- `change_signal` `(string: "")` - Specifies the signal to send to the task as a
string like `"SIGUSR1"` or `"SIGINT"`. This option is required if the
`change_mode` is `signal`.
@@ -58,12 +65,8 @@ README][ct].
- `destination` `(string: <required>)` - Specifies the location where the
resulting template should be rendered, relative to the task directory.
- `change_mode` `(string: "restart")` - Specifies the behavior Nomad should take
if the rendered template changes. The possible values are:
- `"noop"` - take no action (continue running the task)
- `"restart"` - restart the task
- `"signal"` - send a configurable signal to the task
- `perms` `(string: "666")` - Specifies the rendered templates permissions. File
permissions are given as octal of the unix file permissions rwxrwxrwx.
- `source` `(string: "")` - Specifies the path to the template to be rendered.
One of `source` or `data` must be specified, but not both. This source can