Skip to content

Commit

Permalink
client: enable specifying user/group permissions in the template stan…
Browse files Browse the repository at this point in the history
…za (#13755)

* Adds Uid/Gid parameters to template.

* Updated diff_test

* fixed order

* update jobspec and api

* removed obsolete code

* helper functions for jobspec parse test

* updated documentation

* adjusted API jobs test.

* propagate uid/gid setting to job_endpoint

* adjusted job_endpoint tests

* making uid/gid into pointers

* refactor

* updated documentation

* updated documentation

* Update client/allocrunner/taskrunner/template/template_test.go

Co-authored-by: Luiz Aoqui <luiz@hashicorp.com>

* Update website/content/api-docs/json-jobs.mdx

Co-authored-by: Luiz Aoqui <luiz@hashicorp.com>

* propagating documentation change from Luiz

* formatting

* changelog entry

* changed changelog entry

Co-authored-by: Luiz Aoqui <luiz@hashicorp.com>
  • Loading branch information
pkazmierczak and lgfa29 committed Aug 2, 2022
1 parent 9dd905d commit 2e0b875
Show file tree
Hide file tree
Showing 18 changed files with 146 additions and 30 deletions.
3 changes: 3 additions & 0 deletions .changelog/13755.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
template: Templates support new uid/gid parameter pair
```
4 changes: 4 additions & 0 deletions api/jobs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,8 @@ func TestJobs_Canonicalize(t *testing.T) {
ChangeSignal: stringToPtr(""),
Splay: timeToPtr(5 * time.Second),
Perms: stringToPtr("0644"),
Uid: intToPtr(0),
Gid: intToPtr(0),
LeftDelim: stringToPtr("{{"),
RightDelim: stringToPtr("}}"),
Envvars: boolToPtr(false),
Expand All @@ -778,6 +780,8 @@ func TestJobs_Canonicalize(t *testing.T) {
ChangeSignal: stringToPtr(""),
Splay: timeToPtr(5 * time.Second),
Perms: stringToPtr("0644"),
Uid: intToPtr(0),
Gid: intToPtr(0),
LeftDelim: stringToPtr("{{"),
RightDelim: stringToPtr("}}"),
Envvars: boolToPtr(true),
Expand Down
8 changes: 8 additions & 0 deletions api/tasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,8 @@ type Template struct {
ChangeSignal *string `mapstructure:"change_signal" hcl:"change_signal,optional"`
Splay *time.Duration `mapstructure:"splay" hcl:"splay,optional"`
Perms *string `mapstructure:"perms" hcl:"perms,optional"`
Uid *int `mapstructure:"uid" hcl:"uid,optional"`
Gid *int `mapstructure:"gid" hcl:"gid,optional"`
LeftDelim *string `mapstructure:"left_delimiter" hcl:"left_delimiter,optional"`
RightDelim *string `mapstructure:"right_delimiter" hcl:"right_delimiter,optional"`
Envvars *bool `mapstructure:"env" hcl:"env,optional"`
Expand Down Expand Up @@ -835,6 +837,12 @@ func (tmpl *Template) Canonicalize() {
if tmpl.Perms == nil {
tmpl.Perms = stringToPtr("0644")
}
if tmpl.Uid == nil {
tmpl.Uid = intToPtr(0)
}
if tmpl.Gid == nil {
tmpl.Gid = intToPtr(0)
}
if tmpl.LeftDelim == nil {
tmpl.LeftDelim = stringToPtr("{{")
}
Expand Down
6 changes: 6 additions & 0 deletions client/allocrunner/taskrunner/template/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,12 @@ func parseTemplateConfigs(config *TaskTemplateManagerConfig) (map[*ctconf.Templa
m := os.FileMode(v)
ct.Perms = &m
}
// Set ownership
if tmpl.Uid >= 0 && tmpl.Gid >= 0 {
ct.Uid = &tmpl.Uid
ct.Gid = &tmpl.Gid
}

ct.Finalize()

ctmpls[ct] = tmpl
Expand Down
11 changes: 11 additions & 0 deletions client/allocrunner/taskrunner/template/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"strconv"
"strings"
"sync"
"syscall"
"testing"
"time"

Expand All @@ -33,6 +34,7 @@ import (
sconfig "github.com/hashicorp/nomad/nomad/structs/config"
"github.com/hashicorp/nomad/testutil"
"github.com/kr/pretty"
"github.com/shoenig/test/must"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -512,6 +514,8 @@ func TestTaskTemplateManager_Permissions(t *testing.T) {
DestPath: file,
ChangeMode: structs.TemplateChangeModeNoop,
Perms: "777",
Uid: 503,
Gid: 20,
}

harness := newTestHarness(t, []*structs.Template{template}, false, false)
Expand All @@ -535,6 +539,13 @@ func TestTaskTemplateManager_Permissions(t *testing.T) {
if m := fi.Mode(); m != os.ModePerm {
t.Fatalf("Got mode %v; want %v", m, os.ModePerm)
}

sys := fi.Sys()
uid := int(sys.(*syscall.Stat_t).Uid)
gid := int(sys.(*syscall.Stat_t).Gid)

must.Eq(t, template.Uid, uid)
must.Eq(t, template.Gid, gid)
}

func TestTaskTemplateManager_Unblock_Static_NomadEnv(t *testing.T) {
Expand Down
10 changes: 10 additions & 0 deletions command/agent/job_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -1209,6 +1209,14 @@ func ApiTaskToStructsTask(job *structs.Job, group *structs.TaskGroup,
if len(apiTask.Templates) > 0 {
structsTask.Templates = []*structs.Template{}
for _, template := range apiTask.Templates {
uid := -1
if template.Uid != nil {
uid = *template.Uid
}
gid := -1
if template.Gid != nil {
gid = *template.Gid
}
structsTask.Templates = append(structsTask.Templates,
&structs.Template{
SourcePath: *template.SourcePath,
Expand All @@ -1218,6 +1226,8 @@ func ApiTaskToStructsTask(job *structs.Job, group *structs.TaskGroup,
ChangeSignal: *template.ChangeSignal,
Splay: *template.Splay,
Perms: *template.Perms,
Uid: uid,
Gid: gid,
LeftDelim: *template.LeftDelim,
RightDelim: *template.RightDelim,
Envvars: *template.Envvars,
Expand Down
4 changes: 4 additions & 0 deletions command/agent/job_endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2733,6 +2733,8 @@ func TestJobs_ApiJobToStructsJob(t *testing.T) {
ChangeSignal: helper.StringToPtr("signal"),
Splay: helper.TimeToPtr(1 * time.Minute),
Perms: helper.StringToPtr("666"),
Uid: helper.IntToPtr(1000),
Gid: helper.IntToPtr(1000),
LeftDelim: helper.StringToPtr("abc"),
RightDelim: helper.StringToPtr("def"),
Envvars: helper.BoolToPtr(true),
Expand Down Expand Up @@ -3138,6 +3140,8 @@ func TestJobs_ApiJobToStructsJob(t *testing.T) {
ChangeSignal: "SIGNAL",
Splay: 1 * time.Minute,
Perms: "666",
Uid: 1000,
Gid: 1000,
LeftDelim: "abc",
RightDelim: "def",
Envvars: true,
Expand Down
5 changes: 5 additions & 0 deletions jobspec/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ func stringToPtr(str string) *string {
return &str
}

// intToPtr returns the pointer to an int
func intToPtr(i int) *int {
return &i
}

// timeToPtr returns the pointer to a time.Duration.
func timeToPtr(t time.Duration) *time.Duration {
return &t
Expand Down
24 changes: 0 additions & 24 deletions jobspec/helper_test.go

This file was deleted.

4 changes: 4 additions & 0 deletions jobspec/parse_task.go
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,8 @@ func parseTemplates(result *[]*api.Template, list *ast.ObjectList) error {
"destination",
"left_delimiter",
"perms",
"uid",
"gid",
"right_delimiter",
"source",
"splay",
Expand All @@ -460,6 +462,8 @@ func parseTemplates(result *[]*api.Template, list *ast.ObjectList) error {
ChangeMode: stringToPtr("restart"),
Splay: timeToPtr(5 * time.Second),
Perms: stringToPtr("0644"),
Uid: intToPtr(0),
Gid: intToPtr(0),
}

dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
Expand Down
15 changes: 15 additions & 0 deletions jobspec/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,17 @@ const (
templateChangeModeRestart = "restart"
)

// Helper functions below are only used by this test suite
func int8ToPtr(i int8) *int8 {
return &i
}
func uint64ToPtr(u uint64) *uint64 {
return &u
}
func int64ToPtr(i int64) *int64 {
return &i
}

func TestParse(t *testing.T) {
ci.Parallel(t)

Expand Down Expand Up @@ -363,6 +374,8 @@ func TestParse(t *testing.T) {
ChangeSignal: stringToPtr("foo"),
Splay: timeToPtr(10 * time.Second),
Perms: stringToPtr("0644"),
Uid: intToPtr(0),
Gid: intToPtr(0),
Envvars: boolToPtr(true),
VaultGrace: timeToPtr(33 * time.Second),
},
Expand All @@ -372,6 +385,8 @@ func TestParse(t *testing.T) {
ChangeMode: stringToPtr(templateChangeModeRestart),
Splay: timeToPtr(5 * time.Second),
Perms: stringToPtr("777"),
Uid: intToPtr(1001),
Gid: intToPtr(20),
LeftDelim: stringToPtr("--"),
RightDelim: stringToPtr("__"),
},
Expand Down
2 changes: 2 additions & 0 deletions jobspec/test-fixtures/basic.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,8 @@ job "binstore-storagelocker" {
source = "bar"
destination = "bar"
perms = "777"
uid = 1001
gid = 20
left_delimiter = "--"
right_delimiter = "__"
}
Expand Down
5 changes: 0 additions & 5 deletions jobspec2/helper_test.go

This file was deleted.

10 changes: 10 additions & 0 deletions jobspec2/parse_job.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ func normalizeTemplates(templates []*api.Template) {
if t.Perms == nil {
t.Perms = stringToPtr("0644")
}
if t.Uid == nil {
t.Uid = intToPtr(0)
}
if t.Gid == nil {
t.Gid = intToPtr(0)
}
if t.Splay == nil {
t.Splay = durationToPtr(5 * time.Second)
}
Expand All @@ -121,6 +127,10 @@ func boolToPtr(v bool) *bool {
return &v
}

func intToPtr(v int) *int {
return &v
}

func stringToPtr(v string) *string {
return &v
}
Expand Down
32 changes: 32 additions & 0 deletions nomad/structs/diff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7044,6 +7044,8 @@ func TestTaskDiff(t *testing.T) {
ChangeSignal: "SIGHUP",
Splay: 1,
Perms: "0644",
Uid: 1001,
Gid: 21,
Wait: &WaitConfig{
Min: helper.TimeToPtr(5 * time.Second),
Max: helper.TimeToPtr(5 * time.Second),
Expand All @@ -7057,6 +7059,8 @@ func TestTaskDiff(t *testing.T) {
ChangeSignal: "SIGHUP2",
Splay: 2,
Perms: "0666",
Uid: 1000,
Gid: 20,
Envvars: true,
},
},
Expand All @@ -7071,6 +7075,8 @@ func TestTaskDiff(t *testing.T) {
ChangeSignal: "SIGHUP",
Splay: 1,
Perms: "0644",
Uid: 1001,
Gid: 21,
Wait: &WaitConfig{
Min: helper.TimeToPtr(5 * time.Second),
Max: helper.TimeToPtr(10 * time.Second),
Expand All @@ -7084,6 +7090,8 @@ func TestTaskDiff(t *testing.T) {
ChangeSignal: "SIGHUP3",
Splay: 3,
Perms: "0776",
Uid: 1002,
Gid: 22,
Wait: &WaitConfig{
Min: helper.TimeToPtr(5 * time.Second),
Max: helper.TimeToPtr(10 * time.Second),
Expand Down Expand Up @@ -7154,6 +7162,12 @@ func TestTaskDiff(t *testing.T) {
Old: "",
New: "false",
},
{
Type: DiffTypeAdded,
Name: "Gid",
Old: "",
New: "22",
},
{
Type: DiffTypeAdded,
Name: "Perms",
Expand All @@ -7172,6 +7186,12 @@ func TestTaskDiff(t *testing.T) {
Old: "",
New: "3",
},
{
Type: DiffTypeAdded,
Name: "Uid",
Old: "",
New: "1002",
},
{
Type: DiffTypeAdded,
Name: "VaultGrace",
Expand Down Expand Up @@ -7234,6 +7254,12 @@ func TestTaskDiff(t *testing.T) {
Old: "true",
New: "",
},
{
Type: DiffTypeDeleted,
Name: "Gid",
Old: "20",
New: "",
},
{
Type: DiffTypeDeleted,
Name: "Perms",
Expand All @@ -7252,6 +7278,12 @@ func TestTaskDiff(t *testing.T) {
Old: "2",
New: "",
},
{
Type: DiffTypeDeleted,
Name: "Uid",
Old: "1000",
New: "",
},
{
Type: DiffTypeDeleted,
Name: "VaultGrace",
Expand Down
3 changes: 3 additions & 0 deletions nomad/structs/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -7711,6 +7711,9 @@ type Template struct {

// Perms is the permission the file should be written out with.
Perms string
// User and group that should own the file.
Uid int
Gid int

// LeftDelim and RightDelim are optional configurations to control what
// delimiter is utilized when parsing the template.
Expand Down
14 changes: 14 additions & 0 deletions website/content/api-docs/json-jobs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1077,6 +1077,20 @@ README][ct].
- `Perms` - Specifies the rendered template's permissions. File permissions are
given as octal of the Unix file permissions `rwxrwxrwx`.

- `Uid` - Specifies the rendered template owner's user ID.

~> **Caveat:** Works only on Unix-based systems. Be careful when using
containerized drivers, suck as `docker` or `podman`, as groups and users
inside the container may have different IDs than on the host system. This
feature will also **not** work with Docker Desktop.

- `Gid` - Specifies the rendered template owner's group ID.

~> **Caveat:** Works only on Unix-based systems. Be careful when using
containerized drivers, suck as `docker` or `podman`, as groups and users
inside the container may have different IDs than on the host system. This
feature will also **not** work with Docker Desktop.

- `RightDelim` - Specifies the right delimiter to use in the template. The default
is "}}" for some templates, it may be easier to use a different delimiter that
does not conflict with the output file itself.
Expand Down
Loading

0 comments on commit 2e0b875

Please sign in to comment.