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..db8bdc2ce8ea 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: "/foo/bar", + Tmpfs: &composetypes.ServiceVolumeTmpfs{ + Size: 1000, + Mode: 0o1777, + }, + } + expected := mount.Mount{ + Type: mount.TypeTmpfs, + Target: "/foo/bar", + TmpfsOptions: &mount.TmpfsOptions{ + SizeBytes: 1000, + 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..e371f6ceed3a 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 TestLoadTmpfsVolumeMode(t *testing.T) { + config, err := loadYAML(` +version: "3.6" +services: + tmpfs: + image: nginx:latest + volumes: + - type: tmpfs + target: /run + tmpfs: + size: 268435456 + mode: 01777 +`) + assert.NilError(t, err) + + expected := types.ServiceVolumeConfig{ + Target: "/run", + Type: "tmpfs", + Tmpfs: &types.ServiceVolumeTmpfs{ + Size: int64(268435456), + Mode: 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/cli/compose/schema/data/config_schema_v3.10.json b/cli/compose/schema/data/config_schema_v3.10.json index 7c032cf54b31..3d289ee9764b 100644 --- a/cli/compose/schema/data/config_schema_v3.10.json +++ b/cli/compose/schema/data/config_schema_v3.10.json @@ -315,6 +315,10 @@ "size": { "type": "integer", "minimum": 0 + }, + "mode": { + "type": "integer", + "minimum": 0 } } } diff --git a/cli/compose/schema/data/config_schema_v3.11.json b/cli/compose/schema/data/config_schema_v3.11.json index fb2c9fd84b0c..30289db31d41 100644 --- a/cli/compose/schema/data/config_schema_v3.11.json +++ b/cli/compose/schema/data/config_schema_v3.11.json @@ -315,6 +315,10 @@ "size": { "type": "integer", "minimum": 0 + }, + "mode": { + "type": "integer", + "minimum": 0 } } } diff --git a/cli/compose/schema/data/config_schema_v3.12.json b/cli/compose/schema/data/config_schema_v3.12.json index 2a548a38163d..8c93aeb0651f 100644 --- a/cli/compose/schema/data/config_schema_v3.12.json +++ b/cli/compose/schema/data/config_schema_v3.12.json @@ -315,6 +315,10 @@ "size": { "type": "integer", "minimum": 0 + }, + "mode": { + "type": "integer", + "minimum": 0 } } } diff --git a/cli/compose/schema/data/config_schema_v3.13.json b/cli/compose/schema/data/config_schema_v3.13.json index 8daa8892d625..6d1ca3083852 100644 --- a/cli/compose/schema/data/config_schema_v3.13.json +++ b/cli/compose/schema/data/config_schema_v3.13.json @@ -322,6 +322,10 @@ "size": { "type": "integer", "minimum": 0 + }, + "mode": { + "type": "integer", + "minimum": 0 } } } diff --git a/cli/compose/schema/data/config_schema_v3.6.json b/cli/compose/schema/data/config_schema_v3.6.json index cd6a638ceb7f..05ad3175b5eb 100644 --- a/cli/compose/schema/data/config_schema_v3.6.json +++ b/cli/compose/schema/data/config_schema_v3.6.json @@ -311,6 +311,10 @@ "size": { "type": "integer", "minimum": 0 + }, + "mode": { + "type": "integer", + "minimum": 0 } } } diff --git a/cli/compose/schema/data/config_schema_v3.7.json b/cli/compose/schema/data/config_schema_v3.7.json index 69d5c52f87f5..5567545c8650 100644 --- a/cli/compose/schema/data/config_schema_v3.7.json +++ b/cli/compose/schema/data/config_schema_v3.7.json @@ -312,6 +312,10 @@ "size": { "type": "integer", "minimum": 0 + }, + "mode": { + "type": "integer", + "minimum": 0 } } } diff --git a/cli/compose/schema/data/config_schema_v3.8.json b/cli/compose/schema/data/config_schema_v3.8.json index 059c0bcf76d8..f245a2bd4ae8 100644 --- a/cli/compose/schema/data/config_schema_v3.8.json +++ b/cli/compose/schema/data/config_schema_v3.8.json @@ -313,6 +313,10 @@ "size": { "type": "integer", "minimum": 0 + }, + "mode": { + "type": "integer", + "minimum": 0 } } } diff --git a/cli/compose/schema/data/config_schema_v3.9.json b/cli/compose/schema/data/config_schema_v3.9.json index c6f63fda46d3..21336be045ae 100644 --- a/cli/compose/schema/data/config_schema_v3.9.json +++ b/cli/compose/schema/data/config_schema_v3.9.json @@ -315,6 +315,10 @@ "size": { "type": "integer", "minimum": 0 + }, + "mode": { + "type": "integer", + "minimum": 0 } } } 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.