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

Template destination file permissions. #2262

Merged
merged 4 commits into from
Feb 2, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions api/tasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ type Template struct {
ChangeMode string
ChangeSignal string
Splay time.Duration
Perms string
}

type Vault struct {
Expand Down
11 changes: 11 additions & 0 deletions client/consul_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"math/rand"
"os"
"path/filepath"
"strconv"
"strings"
"sync"
"time"
Expand Down Expand Up @@ -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
Expand Down
34 changes: 34 additions & 0 deletions client/consul_template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"}}`
Expand Down
8 changes: 4 additions & 4 deletions jobspec/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions jobspec/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,13 +170,15 @@ func TestParse(t *testing.T) {
ChangeMode: "foo",
ChangeSignal: "foo",
Splay: 10 * time.Second,
Perms: "0644",
},
{
SourcePath: "bar",
DestPath: "bar",
ChangeMode: structs.TemplateChangeModeRestart,
ChangeSignal: "",
Splay: 5 * time.Second,
Perms: "777",
},
},
},
Expand Down
1 change: 1 addition & 0 deletions jobspec/test-fixtures/basic.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ job "binstore-storagelocker" {
template {
source = "bar"
destination = "bar"
perms = "777"
}
}

Expand Down
16 changes: 16 additions & 0 deletions nomad/structs/diff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3544,6 +3544,7 @@ func TestTaskDiff(t *testing.T) {
ChangeMode: "bam",
ChangeSignal: "SIGHUP",
Splay: 1,
Perms: "0644",
},
{
SourcePath: "foo2",
Expand All @@ -3552,6 +3553,7 @@ func TestTaskDiff(t *testing.T) {
ChangeMode: "bam2",
ChangeSignal: "SIGHUP2",
Splay: 2,
Perms: "0666",
},
},
},
Expand All @@ -3564,6 +3566,7 @@ func TestTaskDiff(t *testing.T) {
ChangeMode: "bam",
ChangeSignal: "SIGHUP",
Splay: 1,
Perms: "0644",
},
{
SourcePath: "foo3",
Expand All @@ -3572,6 +3575,7 @@ func TestTaskDiff(t *testing.T) {
ChangeMode: "bam3",
ChangeSignal: "SIGHUP3",
Splay: 3,
Perms: "0776",
},
},
},
Expand Down Expand Up @@ -3606,6 +3610,12 @@ func TestTaskDiff(t *testing.T) {
Old: "",
New: "baz3",
},
{
Type: DiffTypeAdded,
Name: "Perms",
Old: "",
New: "0776",
},
{
Type: DiffTypeAdded,
Name: "SourcePath",
Expand Down Expand Up @@ -3648,6 +3658,12 @@ func TestTaskDiff(t *testing.T) {
Old: "baz2",
New: "",
},
{
Type: DiffTypeDeleted,
Name: "Perms",
Old: "0666",
New: "",
},
{
Type: DiffTypeDeleted,
Name: "SourcePath",
Expand Down
11 changes: 11 additions & 0 deletions nomad/structs/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2589,13 +2589,17 @@ 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.
func DefaultTemplate() *Template {
return &Template{
ChangeMode: TemplateChangeModeRestart,
Splay: 5 * time.Second,
Perms: "0644",
}
}

Expand Down Expand Up @@ -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()
}

Expand Down
21 changes: 21 additions & 0 deletions nomad/structs/structs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
15 changes: 9 additions & 6 deletions website/source/docs/job-specification/template.html.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand All @@ -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 template's 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
Expand Down