Skip to content

Commit

Permalink
Merge pull request #2262 from hashicorp/f-permissions
Browse files Browse the repository at this point in the history
Template destination file permissions.
  • Loading branch information
dadgar committed Feb 2, 2017
2 parents 96a92c4 + 61a8487 commit 15a349d
Show file tree
Hide file tree
Showing 10 changed files with 110 additions and 10 deletions.
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

0 comments on commit 15a349d

Please sign in to comment.