diff --git a/cli/compose/convert/volume.go b/cli/compose/convert/volume.go index 8eaa934cc097..273d43d43971 100644 --- a/cli/compose/convert/volume.go +++ b/cli/compose/convert/volume.go @@ -3,6 +3,7 @@ package convert import ( "errors" "fmt" + "os" "strings" composetypes "github.com/docker/cli/cli/compose/types" @@ -164,6 +165,7 @@ func handleTmpfsToMount(volume composetypes.ServiceVolumeConfig) (mount.Mount, e if volume.Tmpfs != nil { result.TmpfsOptions = &mount.TmpfsOptions{ SizeBytes: volume.Tmpfs.Size, + Mode: os.FileMode(volume.Tmpfs.Mode), } } return result, nil diff --git a/cli/compose/convert/volume_test.go b/cli/compose/convert/volume_test.go index 44865a0d7525..a9c10208cb1d 100644 --- a/cli/compose/convert/volume_test.go +++ b/cli/compose/convert/volume_test.go @@ -466,6 +466,28 @@ func TestConvertTmpfsToMountVolume(t *testing.T) { assert.Check(t, is.DeepEqual(expected, mnt)) } +func TestConvertTmpfsToMountVolumeWithMode(t *testing.T) { + config := composetypes.ServiceVolumeConfig{ + Type: "tmpfs", + Target: "/run", + Tmpfs: &composetypes.ServiceVolumeTmpfs{ + Size: 268435456, + Mode: 0o1777, + }, + } + expected := mount.Mount{ + Type: mount.TypeTmpfs, + Target: "/run", + TmpfsOptions: &mount.TmpfsOptions{ + SizeBytes: 268435456, + Mode: 0o1777, + }, + } + mnt, err := convertVolumeToMount(config, volumes{}, NewNamespace("foo")) + assert.NilError(t, err) + assert.Check(t, is.DeepEqual(expected, mnt)) +} + func TestConvertTmpfsToMountVolumeWithSource(t *testing.T) { config := composetypes.ServiceVolumeConfig{ Type: "tmpfs", diff --git a/cli/compose/loader/loader_test.go b/cli/compose/loader/loader_test.go index 41f70c7cb23c..18132360588d 100644 --- a/cli/compose/loader/loader_test.go +++ b/cli/compose/loader/loader_test.go @@ -1006,6 +1006,35 @@ services: assert.Check(t, is.DeepEqual(expected, config.Services[0].Volumes[0])) } +func TestLoadTmpfsVolumeWithMode(t *testing.T) { + config, err := loadYAML(` +version: "3.6" +services: + tmpfs: + image: nginx:latest + volumes: + - type: tmpfs + target: /app + tmpfs: + size: 10000 + mode: 01777 +`) + assert.NilError(t, err) + + expected := types.ServiceVolumeConfig{ + Target: "/app", + Type: "tmpfs", + Tmpfs: &types.ServiceVolumeTmpfs{ + Size: int64(10000), + Mode: uint32(0o1777), + }, + } + + assert.Assert(t, is.Len(config.Services, 1)) + assert.Check(t, is.Len(config.Services[0].Volumes, 1)) + assert.Check(t, is.DeepEqual(expected, config.Services[0].Volumes[0])) +} + func TestLoadTmpfsVolumeAdditionalPropertyNotAllowed(t *testing.T) { _, err := loadYAML(` version: "3.5" diff --git a/internal/volumespec/types.go b/internal/volumespec/types.go index 7eb9a5006ef0..7d6399bcb689 100644 --- a/internal/volumespec/types.go +++ b/internal/volumespec/types.go @@ -32,7 +32,8 @@ type ImageOpts struct { // TmpFsOpts are options for a service volume of type tmpfs type TmpFsOpts struct { - Size int64 `yaml:",omitempty" json:"size,omitempty"` + Size int64 `yaml:",omitempty" json:"size,omitempty"` + Mode uint32 `yaml:",omitempty" json:"mode,omitempty"` } // ClusterOpts are options for a service volume of type cluster.