diff --git a/cli/compose/convert/service.go b/cli/compose/convert/service.go index d30597451a7d..6059a15814f7 100644 --- a/cli/compose/convert/service.go +++ b/cli/compose/convert/service.go @@ -137,6 +137,7 @@ func Service( Labels: addStackLabel(namespace, service.Labels), Dir: service.WorkingDir, User: service.User, + Groups: service.GroupAdd, Mounts: mounts, StopGracePeriod: composetypes.ConvertDurationPtr(service.StopGracePeriod), StopSignal: service.StopSignal, diff --git a/cli/compose/convert/service_test.go b/cli/compose/convert/service_test.go index 7cd4db46e64b..180fd2eaa060 100644 --- a/cli/compose/convert/service_test.go +++ b/cli/compose/convert/service_test.go @@ -716,3 +716,12 @@ func TestConvertServiceCapAddAndCapDrop(t *testing.T) { }) } } + +func TestConvertServiceGroupAdd(t *testing.T) { + result, err := Service(Namespace{name: "foo"}, composetypes.ServiceConfig{ + Image: "busybox", + GroupAdd: []string{"mail", "15000"}, + }, nil, nil, nil, nil) + assert.NilError(t, err) + assert.Check(t, is.DeepEqual(result.TaskTemplate.ContainerSpec.Groups, []string{"mail", "15000"})) +} diff --git a/cli/compose/loader/loader_test.go b/cli/compose/loader/loader_test.go index 41f70c7cb23c..c4fedd53398e 100644 --- a/cli/compose/loader/loader_test.go +++ b/cli/compose/loader/loader_test.go @@ -900,6 +900,20 @@ func TestInvalidResource(t *testing.T) { assert.Check(t, is.ErrorContains(err, "additional property 'impossible' is not allowed")) } +func TestLoadGroupAdd(t *testing.T) { + config, err := loadYAML(` +version: "3.8" +services: + foo: + image: busybox + group_add: + - mail + - 15000 +`) + assert.NilError(t, err) + assert.Check(t, is.DeepEqual(config.Services[0].GroupAdd, types.StringOrNumberList{"mail", "15000"})) +} + func TestInvalidExternalAndDriverCombination(t *testing.T) { _, err := loadYAML(` version: "3" diff --git a/cli/compose/schema/data/config_schema_v3.0.json b/cli/compose/schema/data/config_schema_v3.0.json index f39344cfbe74..2ddd749e1cbd 100644 --- a/cli/compose/schema/data/config_schema_v3.0.json +++ b/cli/compose/schema/data/config_schema_v3.0.json @@ -101,6 +101,7 @@ "external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "extra_hosts": {"$ref": "#/definitions/list_or_dict"}, + "group_add": {"type": "array", "items": {"type": ["string", "number"]}, "uniqueItems": true}, "healthcheck": {"$ref": "#/definitions/healthcheck"}, "hostname": {"type": "string"}, "image": {"type": "string"}, diff --git a/cli/compose/schema/data/config_schema_v3.1.json b/cli/compose/schema/data/config_schema_v3.1.json index 719c0fa7acc5..8273b64a8e9c 100644 --- a/cli/compose/schema/data/config_schema_v3.1.json +++ b/cli/compose/schema/data/config_schema_v3.1.json @@ -112,6 +112,7 @@ "external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "extra_hosts": {"$ref": "#/definitions/list_or_dict"}, + "group_add": {"type": "array", "items": {"type": ["string", "number"]}, "uniqueItems": true}, "healthcheck": {"$ref": "#/definitions/healthcheck"}, "hostname": {"type": "string"}, "image": {"type": "string"}, diff --git a/cli/compose/schema/data/config_schema_v3.10.json b/cli/compose/schema/data/config_schema_v3.10.json index 7c032cf54b31..090dc5f290d1 100644 --- a/cli/compose/schema/data/config_schema_v3.10.json +++ b/cli/compose/schema/data/config_schema_v3.10.json @@ -158,6 +158,7 @@ "external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "extra_hosts": {"$ref": "#/definitions/list_or_dict"}, + "group_add": {"type": "array", "items": {"type": ["string", "number"]}, "uniqueItems": true}, "healthcheck": {"$ref": "#/definitions/healthcheck"}, "hostname": {"type": "string"}, "image": {"type": "string"}, diff --git a/cli/compose/schema/data/config_schema_v3.11.json b/cli/compose/schema/data/config_schema_v3.11.json index fb2c9fd84b0c..7cf36ce8e202 100644 --- a/cli/compose/schema/data/config_schema_v3.11.json +++ b/cli/compose/schema/data/config_schema_v3.11.json @@ -158,6 +158,7 @@ "external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "extra_hosts": {"$ref": "#/definitions/list_or_dict"}, + "group_add": {"type": "array", "items": {"type": ["string", "number"]}, "uniqueItems": true}, "healthcheck": {"$ref": "#/definitions/healthcheck"}, "hostname": {"type": "string"}, "image": {"type": "string"}, diff --git a/cli/compose/schema/data/config_schema_v3.12.json b/cli/compose/schema/data/config_schema_v3.12.json index 2a548a38163d..3e103a236b8c 100644 --- a/cli/compose/schema/data/config_schema_v3.12.json +++ b/cli/compose/schema/data/config_schema_v3.12.json @@ -158,6 +158,7 @@ "external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "extra_hosts": {"$ref": "#/definitions/list_or_dict"}, + "group_add": {"type": "array", "items": {"type": ["string", "number"]}, "uniqueItems": true}, "healthcheck": {"$ref": "#/definitions/healthcheck"}, "hostname": {"type": "string"}, "image": {"type": "string"}, diff --git a/cli/compose/schema/data/config_schema_v3.13.json b/cli/compose/schema/data/config_schema_v3.13.json index 8daa8892d625..d1532d579e4a 100644 --- a/cli/compose/schema/data/config_schema_v3.13.json +++ b/cli/compose/schema/data/config_schema_v3.13.json @@ -158,6 +158,7 @@ "external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "extra_hosts": {"$ref": "#/definitions/list_or_dict"}, + "group_add": {"type": "array", "items": {"type": ["string", "number"]}, "uniqueItems": true}, "healthcheck": {"$ref": "#/definitions/healthcheck"}, "hostname": {"type": "string"}, "image": {"type": "string"}, diff --git a/cli/compose/schema/data/config_schema_v3.2.json b/cli/compose/schema/data/config_schema_v3.2.json index 6e0e0e747da9..cbe9df16eb5c 100644 --- a/cli/compose/schema/data/config_schema_v3.2.json +++ b/cli/compose/schema/data/config_schema_v3.2.json @@ -113,6 +113,7 @@ "external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "extra_hosts": {"$ref": "#/definitions/list_or_dict"}, + "group_add": {"type": "array", "items": {"type": ["string", "number"]}, "uniqueItems": true}, "healthcheck": {"$ref": "#/definitions/healthcheck"}, "hostname": {"type": "string"}, "image": {"type": "string"}, diff --git a/cli/compose/schema/data/config_schema_v3.3.json b/cli/compose/schema/data/config_schema_v3.3.json index 13a58044d843..857c996c2dce 100644 --- a/cli/compose/schema/data/config_schema_v3.3.json +++ b/cli/compose/schema/data/config_schema_v3.3.json @@ -151,6 +151,7 @@ "external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "extra_hosts": {"$ref": "#/definitions/list_or_dict"}, + "group_add": {"type": "array", "items": {"type": ["string", "number"]}, "uniqueItems": true}, "healthcheck": {"$ref": "#/definitions/healthcheck"}, "hostname": {"type": "string"}, "image": {"type": "string"}, diff --git a/cli/compose/schema/data/config_schema_v3.4.json b/cli/compose/schema/data/config_schema_v3.4.json index 8660c98da42b..a489f8138b31 100644 --- a/cli/compose/schema/data/config_schema_v3.4.json +++ b/cli/compose/schema/data/config_schema_v3.4.json @@ -154,6 +154,7 @@ "external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "extra_hosts": {"$ref": "#/definitions/list_or_dict"}, + "group_add": {"type": "array", "items": {"type": ["string", "number"]}, "uniqueItems": true}, "healthcheck": {"$ref": "#/definitions/healthcheck"}, "hostname": {"type": "string"}, "image": {"type": "string"}, diff --git a/cli/compose/schema/data/config_schema_v3.5.json b/cli/compose/schema/data/config_schema_v3.5.json index bf9c56c02e37..9bbf3d6f21a3 100644 --- a/cli/compose/schema/data/config_schema_v3.5.json +++ b/cli/compose/schema/data/config_schema_v3.5.json @@ -155,6 +155,7 @@ "external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "extra_hosts": {"$ref": "#/definitions/list_or_dict"}, + "group_add": {"type": "array", "items": {"type": ["string", "number"]}, "uniqueItems": true}, "healthcheck": {"$ref": "#/definitions/healthcheck"}, "hostname": {"type": "string"}, "image": {"type": "string"}, diff --git a/cli/compose/schema/data/config_schema_v3.6.json b/cli/compose/schema/data/config_schema_v3.6.json index cd6a638ceb7f..c5fdda4cb5b7 100644 --- a/cli/compose/schema/data/config_schema_v3.6.json +++ b/cli/compose/schema/data/config_schema_v3.6.json @@ -155,6 +155,7 @@ "external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "extra_hosts": {"$ref": "#/definitions/list_or_dict"}, + "group_add": {"type": "array", "items": {"type": ["string", "number"]}, "uniqueItems": true}, "healthcheck": {"$ref": "#/definitions/healthcheck"}, "hostname": {"type": "string"}, "image": {"type": "string"}, diff --git a/cli/compose/schema/data/config_schema_v3.7.json b/cli/compose/schema/data/config_schema_v3.7.json index 69d5c52f87f5..cc7a9c6c4cb6 100644 --- a/cli/compose/schema/data/config_schema_v3.7.json +++ b/cli/compose/schema/data/config_schema_v3.7.json @@ -155,6 +155,7 @@ "external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "extra_hosts": {"$ref": "#/definitions/list_or_dict"}, + "group_add": {"type": "array", "items": {"type": ["string", "number"]}, "uniqueItems": true}, "healthcheck": {"$ref": "#/definitions/healthcheck"}, "hostname": {"type": "string"}, "image": {"type": "string"}, diff --git a/cli/compose/schema/data/config_schema_v3.8.json b/cli/compose/schema/data/config_schema_v3.8.json index 059c0bcf76d8..ea137dfb60ef 100644 --- a/cli/compose/schema/data/config_schema_v3.8.json +++ b/cli/compose/schema/data/config_schema_v3.8.json @@ -156,6 +156,7 @@ "external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "extra_hosts": {"$ref": "#/definitions/list_or_dict"}, + "group_add": {"type": "array", "items": {"type": ["string", "number"]}, "uniqueItems": true}, "healthcheck": {"$ref": "#/definitions/healthcheck"}, "hostname": {"type": "string"}, "image": {"type": "string"}, diff --git a/cli/compose/schema/data/config_schema_v3.9.json b/cli/compose/schema/data/config_schema_v3.9.json index c6f63fda46d3..affd8502afb2 100644 --- a/cli/compose/schema/data/config_schema_v3.9.json +++ b/cli/compose/schema/data/config_schema_v3.9.json @@ -158,6 +158,7 @@ "external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "extra_hosts": {"$ref": "#/definitions/list_or_dict"}, + "group_add": {"type": "array", "items": {"type": ["string", "number"]}, "uniqueItems": true}, "healthcheck": {"$ref": "#/definitions/healthcheck"}, "hostname": {"type": "string"}, "image": {"type": "string"}, diff --git a/cli/compose/schema/schema_test.go b/cli/compose/schema/schema_test.go index cef3d55223b9..759e3778ab7b 100644 --- a/cli/compose/schema/schema_test.go +++ b/cli/compose/schema/schema_test.go @@ -148,6 +148,20 @@ func TestValidatePorts(t *testing.T) { } } +func TestValidateGroupAdd(t *testing.T) { + config := dict{ + "version": "3.8", + "services": dict{ + "foo": dict{ + "image": "busybox", + "group_add": []any{"mail", 15000, "1000"}, + }, + }, + } + assert.NilError(t, Validate(config, "3.8")) + assert.NilError(t, Validate(config, "3")) +} + func TestValidateUndefinedTopLevelOption(t *testing.T) { config := dict{ "version": "3.0", diff --git a/cli/compose/types/types.go b/cli/compose/types/types.go index ad59ce052b00..d21addbc449b 100644 --- a/cli/compose/types/types.go +++ b/cli/compose/types/types.go @@ -179,6 +179,7 @@ type ServiceConfig struct { Expose StringOrNumberList `yaml:",omitempty" json:"expose,omitempty"` ExternalLinks []string `mapstructure:"external_links" yaml:"external_links,omitempty" json:"external_links,omitempty"` ExtraHosts HostsList `mapstructure:"extra_hosts" yaml:"extra_hosts,omitempty" json:"extra_hosts,omitempty"` + GroupAdd StringOrNumberList `mapstructure:"group_add" yaml:"group_add,omitempty" json:"group_add,omitempty"` Hostname string `yaml:",omitempty" json:"hostname,omitempty"` HealthCheck *HealthCheckConfig `yaml:",omitempty" json:"healthcheck,omitempty"` Image string `yaml:",omitempty" json:"image,omitempty"`