From 82bc59e5d611ec63b10e3a56502f331c1dd41d8f Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Sun, 28 Jan 2018 07:13:48 +0000 Subject: [PATCH 1/2] Fix secret and config mode issue This fix tries to address the issue raised in 36042 where secret and config are not configured with the specified file mode. This fix update the file mode so that it is not impacted with umask. Additional tests have been added. This fix fixes 36042. Signed-off-by: Yong Tang Upstream-commit: 3305221eefd18ba7712a308c1fb05d4eeeac2cc6 Component: engine --- components/engine/daemon/container_operations_unix.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/engine/daemon/container_operations_unix.go b/components/engine/daemon/container_operations_unix.go index a123df3a9a..0aaa6c2253 100644 --- a/components/engine/daemon/container_operations_unix.go +++ b/components/engine/daemon/container_operations_unix.go @@ -239,6 +239,9 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) { if err := os.Chown(fPath, rootIDs.UID+uid, rootIDs.GID+gid); err != nil { return errors.Wrap(err, "error setting ownership for secret") } + if err := os.Chmod(fPath, s.File.Mode); err != nil { + return errors.Wrap(err, "error setting file mode for secret") + } } label.Relabel(localMountPath, c.MountLabel, false) @@ -320,6 +323,9 @@ func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) { if err := os.Chown(fPath, rootIDs.UID+uid, rootIDs.GID+gid); err != nil { return errors.Wrap(err, "error setting ownership for config") } + if err := os.Chmod(fPath, configRef.File.Mode); err != nil { + return errors.Wrap(err, "error setting file mode for config") + } label.Relabel(fPath, c.MountLabel, false) } From b13e2a39e138fc1e4b4983d3cd979a28f765a3ed Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Sun, 28 Jan 2018 07:15:44 +0000 Subject: [PATCH 2/2] Add test cases for file mode with secret and config. Signed-off-by: Yong Tang Upstream-commit: 65ee7fff02111bf696bc2fec442d07c2957f4151 Component: engine --- .../engine/integration/service/create_test.go | 163 ++++++++++++++++++ 1 file changed, 163 insertions(+) diff --git a/components/engine/integration/service/create_test.go b/components/engine/integration/service/create_test.go index 7e78b94992..fb8ea32b43 100644 --- a/components/engine/integration/service/create_test.go +++ b/components/engine/integration/service/create_test.go @@ -1,6 +1,7 @@ package service import ( + "io/ioutil" "runtime" "testing" "time" @@ -144,6 +145,168 @@ func TestCreateWithDuplicateNetworkNames(t *testing.T) { poll.WaitOn(t, networkIsRemoved(client, n1.ID), poll.WithTimeout(1*time.Minute), poll.WithDelay(10*time.Second)) } +func TestCreateServiceSecretFileMode(t *testing.T) { + defer setupTest(t)() + d := newSwarm(t) + defer d.Stop(t) + client, err := request.NewClientForHost(d.Sock()) + require.NoError(t, err) + + ctx := context.Background() + secretResp, err := client.SecretCreate(ctx, swarm.SecretSpec{ + Annotations: swarm.Annotations{ + Name: "TestSecret", + }, + Data: []byte("TESTSECRET"), + }) + require.NoError(t, err) + + var instances uint64 = 1 + serviceSpec := swarm.ServiceSpec{ + Annotations: swarm.Annotations{ + Name: "TestService", + }, + TaskTemplate: swarm.TaskSpec{ + ContainerSpec: &swarm.ContainerSpec{ + Image: "busybox:latest", + Command: []string{"/bin/sh", "-c", "ls -l /etc/secret || /bin/top"}, + Secrets: []*swarm.SecretReference{ + { + File: &swarm.SecretReferenceFileTarget{ + Name: "/etc/secret", + UID: "0", + GID: "0", + Mode: 0777, + }, + SecretID: secretResp.ID, + SecretName: "TestSecret", + }, + }, + }, + }, + Mode: swarm.ServiceMode{ + Replicated: &swarm.ReplicatedService{ + Replicas: &instances, + }, + }, + } + + serviceResp, err := client.ServiceCreate(ctx, serviceSpec, types.ServiceCreateOptions{ + QueryRegistry: false, + }) + require.NoError(t, err) + + poll.WaitOn(t, serviceRunningTasksCount(client, serviceResp.ID, instances)) + + filter := filters.NewArgs() + filter.Add("service", serviceResp.ID) + tasks, err := client.TaskList(ctx, types.TaskListOptions{ + Filters: filter, + }) + require.NoError(t, err) + assert.Equal(t, len(tasks), 1) + + body, err := client.ContainerLogs(ctx, tasks[0].Status.ContainerStatus.ContainerID, types.ContainerLogsOptions{ + ShowStdout: true, + }) + require.NoError(t, err) + defer body.Close() + + content, err := ioutil.ReadAll(body) + require.NoError(t, err) + assert.Contains(t, string(content), "-rwxrwxrwx") + + err = client.ServiceRemove(ctx, serviceResp.ID) + require.NoError(t, err) + + poll.WaitOn(t, serviceIsRemoved(client, serviceResp.ID)) + poll.WaitOn(t, noTasks(client)) + + err = client.SecretRemove(ctx, "TestSecret") + require.NoError(t, err) +} + +func TestCreateServiceConfigFileMode(t *testing.T) { + defer setupTest(t)() + d := newSwarm(t) + defer d.Stop(t) + client, err := request.NewClientForHost(d.Sock()) + require.NoError(t, err) + + ctx := context.Background() + configResp, err := client.ConfigCreate(ctx, swarm.ConfigSpec{ + Annotations: swarm.Annotations{ + Name: "TestConfig", + }, + Data: []byte("TESTCONFIG"), + }) + require.NoError(t, err) + + var instances uint64 = 1 + serviceSpec := swarm.ServiceSpec{ + Annotations: swarm.Annotations{ + Name: "TestService", + }, + TaskTemplate: swarm.TaskSpec{ + ContainerSpec: &swarm.ContainerSpec{ + Image: "busybox:latest", + Command: []string{"/bin/sh", "-c", "ls -l /etc/config || /bin/top"}, + Configs: []*swarm.ConfigReference{ + { + File: &swarm.ConfigReferenceFileTarget{ + Name: "/etc/config", + UID: "0", + GID: "0", + Mode: 0777, + }, + ConfigID: configResp.ID, + ConfigName: "TestConfig", + }, + }, + }, + }, + Mode: swarm.ServiceMode{ + Replicated: &swarm.ReplicatedService{ + Replicas: &instances, + }, + }, + } + + serviceResp, err := client.ServiceCreate(ctx, serviceSpec, types.ServiceCreateOptions{ + QueryRegistry: false, + }) + require.NoError(t, err) + + poll.WaitOn(t, serviceRunningTasksCount(client, serviceResp.ID, instances)) + + filter := filters.NewArgs() + filter.Add("service", serviceResp.ID) + tasks, err := client.TaskList(ctx, types.TaskListOptions{ + Filters: filter, + }) + require.NoError(t, err) + assert.Equal(t, len(tasks), 1) + + body, err := client.ContainerLogs(ctx, tasks[0].Status.ContainerStatus.ContainerID, types.ContainerLogsOptions{ + ShowStdout: true, + }) + require.NoError(t, err) + defer body.Close() + + content, err := ioutil.ReadAll(body) + require.NoError(t, err) + assert.Contains(t, string(content), "-rwxrwxrwx") + + err = client.ServiceRemove(ctx, serviceResp.ID) + require.NoError(t, err) + + poll.WaitOn(t, serviceIsRemoved(client, serviceResp.ID)) + poll.WaitOn(t, noTasks(client)) + + err = client.ConfigRemove(ctx, "TestConfig") + require.NoError(t, err) +} + func swarmServiceSpec(name string, replicas uint64) swarm.ServiceSpec { return swarm.ServiceSpec{ Annotations: swarm.Annotations{