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

client: enable specifying user/group permissions in the template stanza #13755

Merged
merged 20 commits into from
Aug 2, 2022
Merged
Show file tree
Hide file tree
Changes from 14 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
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
14 changes: 14 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 Down Expand Up @@ -512,6 +513,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 +538,17 @@ 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)

if uid != template.Uid {
t.Fatalf("Got uid #{uid}; want #{template.Uid}")
}
if gid != template.Gid {
t.Fatalf("Got gid #{uid}; want #{template.Gid}")
}
pkazmierczak marked this conversation as resolved.
Show resolved Hide resolved
}

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 @@ -7644,6 +7644,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
12 changes: 12 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,18 @@ 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 Linux. Be careful when using the docker driver 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.
pkazmierczak marked this conversation as resolved.
Show resolved Hide resolved

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

~> **Caveat:** Works only on Linux. Be careful when using the docker driver 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