diff --git a/daemon/cluster/convert/container.go b/daemon/cluster/convert/container.go index 77001774fe..d9c4926df6 100644 --- a/daemon/cluster/convert/container.go +++ b/daemon/cluster/convert/container.go @@ -135,6 +135,7 @@ func containerSpecFromGRPC(c *swarmapi.ContainerSpec) *types.ContainerSpec { mount.TmpfsOptions = &mounttypes.TmpfsOptions{ SizeBytes: m.TmpfsOptions.SizeBytes, Mode: m.TmpfsOptions.Mode, + Options: m.TmpfsOptions.Options, } } containerSpec.Mounts = append(containerSpec.Mounts, mount) @@ -421,6 +422,7 @@ func containerToGRPC(c *types.ContainerSpec) (*swarmapi.ContainerSpec, error) { mount.TmpfsOptions = &swarmapi.Mount_TmpfsOptions{ SizeBytes: m.TmpfsOptions.SizeBytes, Mode: m.TmpfsOptions.Mode, + Options: m.TmpfsOptions.Options, } } diff --git a/daemon/cluster/executor/container/container.go b/daemon/cluster/executor/container/container.go index 8aeb9d379c..3922e847e7 100644 --- a/daemon/cluster/executor/container/container.go +++ b/daemon/cluster/executor/container/container.go @@ -363,6 +363,7 @@ func convertMount(m api.Mount) enginemount.Mount { mount.TmpfsOptions = &enginemount.TmpfsOptions{ SizeBytes: m.TmpfsOptions.SizeBytes, Mode: m.TmpfsOptions.Mode, + Options: m.TmpfsOptions.Options, } } diff --git a/daemon/cluster/executor/container/container_test.go b/daemon/cluster/executor/container/container_test.go index 8055e111fe..eebf9918b1 100644 --- a/daemon/cluster/executor/container/container_test.go +++ b/daemon/cluster/executor/container/container_test.go @@ -4,8 +4,10 @@ import ( "testing" "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/mount" swarmapi "github.com/moby/swarmkit/v2/api" "gotest.tools/v3/assert" + is "gotest.tools/v3/assert/cmp" ) func TestIsolationConversion(t *testing.T) { @@ -117,6 +119,7 @@ func TestCredentialSpecConversion(t *testing.T) { to: []string{"credentialspec=registry://testing"}, }, } + for _, c := range cases { c := c t.Run(c.name, func(t *testing.T) { @@ -139,3 +142,75 @@ func TestCredentialSpecConversion(t *testing.T) { }) } } + +func TestTmpfsConversion(t *testing.T) { + cases := []struct { + name string + from []swarmapi.Mount + to []mount.Mount + }{ + { + name: "tmpfs-exec", + from: []swarmapi.Mount{ + { + Source: "/foo", + Target: "/bar", + Type: swarmapi.MountTypeTmpfs, + TmpfsOptions: &swarmapi.Mount_TmpfsOptions{ + Options: "exec", + }, + }, + }, + to: []mount.Mount{ + { + Source: "/foo", + Target: "/bar", + Type: mount.TypeTmpfs, + TmpfsOptions: &mount.TmpfsOptions{ + Options: "exec", + }, + }, + }, + }, + { + name: "tmpfs-noexec", + from: []swarmapi.Mount{ + { + Source: "/foo", + Target: "/bar", + Type: swarmapi.MountTypeTmpfs, + TmpfsOptions: &swarmapi.Mount_TmpfsOptions{ + Options: "noexec", + }, + }, + }, + to: []mount.Mount{ + { + Source: "/foo", + Target: "/bar", + Type: mount.TypeTmpfs, + TmpfsOptions: &mount.TmpfsOptions{ + Options: "noexec", + }, + }, + }, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + task := swarmapi.Task{ + Spec: swarmapi.TaskSpec{ + Runtime: &swarmapi.TaskSpec_Container{ + Container: &swarmapi.ContainerSpec{ + Image: "alpine:latest", + Mounts: c.from, + }, + }, + }, + } + config := containerConfig{task: &task} + assert.Check(t, is.DeepEqual(c.to, config.hostConfig().Mounts)) + }) + } +}