mirror of
https://github.com/kemko/nomad.git
synced 2026-01-05 01:45:44 +03:00
Template destination file permissions.
This PR allows setting the file permissions of the rendered template.
This commit is contained in:
@@ -179,6 +179,7 @@ type Template struct {
|
||||
ChangeMode string
|
||||
ChangeSignal string
|
||||
Splay time.Duration
|
||||
Perms string
|
||||
}
|
||||
|
||||
type Vault struct {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"}}`
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -145,6 +145,7 @@ job "binstore-storagelocker" {
|
||||
template {
|
||||
source = "bar"
|
||||
destination = "bar"
|
||||
perms = "777"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user