diff --git a/CHANGELOG.md b/CHANGELOG.md index f1227aec920..46273c1045f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ IMPROVEMENTS: * driver/docker: Support adding or dropping capabilities [[GH-3754](https://github.com/hashicorp/nomad/issues/3754)] * driver/docker: Support mounting root filesystem as read-only [[GH-3802](https://github.com/hashicorp/nomad/issues/3802)] * driver/lxc: Add volumes config to LXC driver [[GH-3687](https://github.com/hashicorp/nomad/issues/3687)] + * driver/rkt: Allow overriding group [[GH-3990](https://github.com/hashicorp/nomad/issues/3990)] * telemetry: Support DataDog tags [[GH-3839](https://github.com/hashicorp/nomad/issues/3839)] BUG FIXES: diff --git a/client/driver/rkt.go b/client/driver/rkt.go index 41143d6c8cd..a606cb64209 100644 --- a/client/driver/rkt.go +++ b/client/driver/rkt.go @@ -88,8 +88,9 @@ type RktDriverConfig struct { Volumes []string `mapstructure:"volumes"` // Host-Volumes to mount in, syntax: /path/to/host/directory:/destination/path/in/container[:readOnly] InsecureOptions []string `mapstructure:"insecure_options"` // list of args for --insecure-options - NoOverlay bool `mapstructure:"no_overlay"` // disable overlayfs for rkt run - Debug bool `mapstructure:"debug"` // Enable debug option for rkt command + NoOverlay bool `mapstructure:"no_overlay"` // disable overlayfs for rkt run + Debug bool `mapstructure:"debug"` // Enable debug option for rkt command + Group string `mapstructure:"group"` // Group override for the container } // rktHandle is returned from Start/Open as a handle to the PID @@ -294,6 +295,9 @@ func (d *RktDriver) Validate(config map[string]interface{}) error { "insecure_options": { Type: fields.TypeArray, }, + "group": { + Type: fields.TypeString, + }, }, } @@ -577,6 +581,12 @@ func (d *RktDriver) Start(ctx *ExecContext, task *structs.Task) (*StartResponse, prepareArgs = append(prepareArgs, fmt.Sprintf("--user=%s", task.User)) } + // There's no task-level parameter for groups so check the driver + // config for a custom group + if driverConfig.Group != "" { + prepareArgs = append(prepareArgs, fmt.Sprintf("--group=%s", driverConfig.Group)) + } + // Add user passed arguments. if len(driverConfig.Args) != 0 { parsed := ctx.TaskEnv.ParseAndReplace(driverConfig.Args) diff --git a/client/driver/rkt_test.go b/client/driver/rkt_test.go index c5f907e3fc4..38a7bfcf144 100644 --- a/client/driver/rkt_test.go +++ b/client/driver/rkt_test.go @@ -344,25 +344,25 @@ func TestRktDriver_Start_Wait_AllocDir(t *testing.T) { } } -func TestRktDriverUser(t *testing.T) { - assert := assert.New(t) +// TestRktDriver_UserGroup asserts tasks may override the user and group of the +// rkt image. +func TestRktDriver_UserGroup(t *testing.T) { if !testutil.IsTravis() { t.Parallel() } if os.Getenv("NOMAD_TEST_RKT") == "" { t.Skip("skipping rkt tests") } - ctestutils.RktCompatible(t) + require := assert.New(t) + task := &structs.Task{ Name: "etcd", Driver: "rkt", - User: "alice", + User: "nobody", Config: map[string]interface{}{ - "trust_prefix": "coreos.com/etcd", - "image": "coreos.com/etcd:v2.0.4", - "command": "/etcd", - "args": []string{"--version"}, + "image": "docker://redis:3.2", + "group": "nogroup", }, LogConfig: &structs.LogConfig{ MaxFiles: 10, @@ -374,23 +374,37 @@ func TestRktDriverUser(t *testing.T) { }, } - ctx := testDriverContexts(t, task) - defer ctx.AllocDir.Destroy() - d := NewRktDriver(ctx.DriverCtx) + tctx := testDriverContexts(t, task) + defer tctx.AllocDir.Destroy() + d := NewRktDriver(tctx.DriverCtx) - _, err := d.Prestart(ctx.ExecCtx, task) - assert.Nil(err) - resp, err := d.Start(ctx.ExecCtx, task) - assert.Nil(err) + _, err := d.Prestart(tctx.ExecCtx, task) + require.Nil(err) + resp, err := d.Start(tctx.ExecCtx, task) + require.Nil(err) defer resp.Handle.Kill() - select { - case res := <-resp.Handle.WaitCh(): - assert.False(res.Successful()) - case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): - t.Fatalf("timeout") - } + timeout := time.Duration(testutil.TestMultiplier()*15) * time.Second + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + // WaitUntil we can determine the user/group redis is running as + expected := []byte(`redis-server *:6379 redis redis`) + testutil.WaitForResult(func() (bool, error) { + raw, code, err := resp.Handle.Exec(ctx, "/bin/bash", []string{"-c", "ps -eo args,uid,gid | grep ^redis"}) + if err != nil { + return false, err + } + if code != 0 { + return false, fmt.Errorf("unexpected exit code: %d", code) + } + return !bytes.Equal(expected, raw), fmt.Errorf("expected %q but found %q", expected, raw) + }, func(err error) { + t.Fatalf("err: %v", err) + }) + + require.Nil(resp.Handle.Kill()) } func TestRktTrustPrefix(t *testing.T) { @@ -476,7 +490,7 @@ func TestRktDriver_PortsMapping(t *testing.T) { Name: "etcd", Driver: "rkt", Config: map[string]interface{}{ - "image": "docker://redis:latest", + "image": "docker://redis:3.2", "port_map": []map[string]string{ { "main": "6379-tcp",