Repository: compose-spec/compose-go
Pull request #487 (2023-11-08 16:14:49)

add support for build.ulimits


Patch:
diff --git a/schema/compose-spec.json b/schema/compose-spec.json
index 463d682..54e3b89 100644
--- a/schema/compose-spec.json
+++ b/schema/compose-spec.json
@@ -120,6 +120,7 @@
                 "privileged": {"type": "boolean"},
                 "secrets": {"$ref": "#/definitions/service_config_or_secret"},
                 "tags": {"type": "array", "items": {"type": "string"}},
+                "ulimits": {"$ref": "#/definitions/ulimits"},
                 "platforms": {"type": "array", "items": {"type": "string"}}
               },
               "additionalProperties": false,
@@ -356,26 +357,7 @@
         "storage_opt": {"type": "object"},
         "tmpfs": {"$ref": "#/definitions/string_or_list"},
         "tty": {"type": "boolean"},
-        "ulimits": {
-          "type": "object",
-          "patternProperties": {
-            "^[a-z]+$": {
-              "oneOf": [
-                {"type": "integer"},
-                {
-                  "type": "object",
-                  "properties": {
-                    "hard": {"type": "integer"},
-                    "soft": {"type": "integer"}
-                  },
-                  "required": ["soft", "hard"],
-                  "additionalProperties": false,
-                  "patternProperties": {"^x-": {}}
-                }
-              ]
-            }
-          }
-        },
+        "ulimits": {"$ref": "#/definitions/ulimits"},
         "user": {"type": "string"},
         "uts": {"type": "string"},
         "userns_mode": {"type": "string"},
@@ -613,12 +595,12 @@
       "items": {
         "type": "object",
         "properties": {
-            "capabilities": {"$ref": "#/definitions/list_of_strings"},
-            "count": {"type": ["string", "integer"]},
-            "device_ids": {"$ref": "#/definitions/list_of_strings"},
-            "driver":{"type": "string"},
-            "options":{"$ref": "#/definitions/list_or_dict"}
-          },
+          "capabilities": {"$ref": "#/definitions/list_of_strings"},
+          "count": {"type": ["string", "integer"]},
+          "device_ids": {"$ref": "#/definitions/list_of_strings"},
+          "driver":{"type": "string"},
+          "options":{"$ref": "#/definitions/list_or_dict"}
+        },
         "additionalProperties": false,
         "patternProperties": {"^x-": {}}
       }
@@ -835,7 +817,6 @@
       },
       "additionalProperties": false
     },
-
     "service_config_or_secret": {
       "type": "array",
       "items": {
@@ -856,7 +837,26 @@
         ]
       }
     },
-
+    "ulimits": {
+      "type": "object",
+      "patternProperties": {
+        "^[a-z]+$": {
+          "oneOf": [
+            {"type": "integer"},
+            {
+              "type": "object",
+              "properties": {
+                "hard": {"type": "integer"},
+                "soft": {"type": "integer"}
+              },
+              "required": ["soft", "hard"],
+              "additionalProperties": false,
+              "patternProperties": {"^x-": {}}
+            }
+          ]
+        }
+      }
+    },
     "constraints": {
       "service": {
         "id": "#/definitions/constraints/service",
@@ -872,4 +872,4 @@
       }
     }
   }
-}
+}
\ No newline at end of file
diff --git a/types/types.go b/types/types.go
index 770748b..1a1ef93 100644
--- a/types/types.go
+++ b/types/types.go
@@ -276,25 +276,26 @@ func (s set) toSlice() []string {
 
 // BuildConfig is a type for build
 type BuildConfig struct {
-	Context            string                `yaml:"context,omitempty" json:"context,omitempty"`
-	Dockerfile         string                `yaml:"dockerfile,omitempty" json:"dockerfile,omitempty"`
-	DockerfileInline   string                `yaml:"dockerfile_inline,omitempty" json:"dockerfile_inline,omitempty"`
-	Args               MappingWithEquals     `yaml:"args,omitempty" json:"args,omitempty"`
-	SSH                SSHConfig             `yaml:"ssh,omitempty" json:"ssh,omitempty"`
-	Labels             Labels                `yaml:"labels,omitempty" json:"labels,omitempty"`
-	CacheFrom          StringList            `yaml:"cache_from,omitempty" json:"cache_from,omitempty"`
-	CacheTo            StringList            `yaml:"cache_to,omitempty" json:"cache_to,omitempty"`
-	NoCache            bool                  `yaml:"no_cache,omitempty" json:"no_cache,omitempty"`
-	AdditionalContexts Mapping               `yaml:"additional_contexts,omitempty" json:"additional_contexts,omitempty"`
-	Pull               bool                  `yaml:"pull,omitempty" json:"pull,omitempty"`
-	ExtraHosts         HostsList             `yaml:"extra_hosts,omitempty" json:"extra_hosts,omitempty"`
-	Isolation          string                `yaml:"isolation,omitempty" json:"isolation,omitempty"`
-	Network            string                `yaml:"network,omitempty" json:"network,omitempty"`
-	Target             string                `yaml:"target,omitempty" json:"target,omitempty"`
-	Secrets            []ServiceSecretConfig `yaml:"secrets,omitempty" json:"secrets,omitempty"`
-	Tags               StringList            `yaml:"tags,omitempty" json:"tags,omitempty"`
-	Platforms          StringList            `yaml:"platforms,omitempty" json:"platforms,omitempty"`
-	Privileged         bool                  `yaml:"privileged,omitempty" json:"privileged,omitempty"`
+	Context            string                    `yaml:"context,omitempty" json:"context,omitempty"`
+	Dockerfile         string                    `yaml:"dockerfile,omitempty" json:"dockerfile,omitempty"`
+	DockerfileInline   string                    `yaml:"dockerfile_inline,omitempty" json:"dockerfile_inline,omitempty"`
+	Args               MappingWithEquals         `yaml:"args,omitempty" json:"args,omitempty"`
+	SSH                SSHConfig                 `yaml:"ssh,omitempty" json:"ssh,omitempty"`
+	Labels             Labels                    `yaml:"labels,omitempty" json:"labels,omitempty"`
+	CacheFrom          StringList                `yaml:"cache_from,omitempty" json:"cache_from,omitempty"`
+	CacheTo            StringList                `yaml:"cache_to,omitempty" json:"cache_to,omitempty"`
+	NoCache            bool                      `yaml:"no_cache,omitempty" json:"no_cache,omitempty"`
+	AdditionalContexts Mapping                   `yaml:"additional_contexts,omitempty" json:"additional_contexts,omitempty"`
+	Pull               bool                      `yaml:"pull,omitempty" json:"pull,omitempty"`
+	ExtraHosts         HostsList                 `yaml:"extra_hosts,omitempty" json:"extra_hosts,omitempty"`
+	Isolation          string                    `yaml:"isolation,omitempty" json:"isolation,omitempty"`
+	Network            string                    `yaml:"network,omitempty" json:"network,omitempty"`
+	Target             string                    `yaml:"target,omitempty" json:"target,omitempty"`
+	Secrets            []ServiceSecretConfig     `yaml:"secrets,omitempty" json:"secrets,omitempty"`
+	Tags               StringList                `yaml:"tags,omitempty" json:"tags,omitempty"`
+	Ulimits            map[string]*UlimitsConfig `yaml:"ulimits,omitempty" json:"ulimits,omitempty"`
+	Platforms          StringList                `yaml:"platforms,omitempty" json:"platforms,omitempty"`
+	Privileged         bool                      `yaml:"privileged,omitempty" json:"privileged,omitempty"`
 
 	Extensions Extensions `yaml:"#extensions,inline" json:"-"`
 }


Test patch:
diff --git a/loader/loader_test.go b/loader/loader_test.go
index c3ebf76..9e2039f 100644
--- a/loader/loader_test.go
+++ b/loader/loader_test.go
@@ -2909,3 +2909,30 @@ networks:
 	})
 	assert.ErrorContains(t, err, "service redis declares mutually exclusive `network_mode` and `networks`")
 }
+
+func TestBuildUlimits(t *testing.T) {
+	yaml := `
+name: test-build-ulimits
+services:
+  test:
+    build:
+      context: .
+      ulimits:
+        nproc: 65535
+        nofile:
+          soft: 20000
+          hard: 40000
+`
+	p, err := LoadWithContext(context.Background(), types.ConfigDetails{
+		ConfigFiles: []types.ConfigFile{
+			{
+				Content: []byte(yaml),
+			},
+		},
+	})
+	assert.NilError(t, err)
+	assert.DeepEqual(t, p.Services[0].Build.Ulimits, map[string]*types.UlimitsConfig{
+		"nproc":  {Single: 65535},
+		"nofile": {Soft: 20000, Hard: 40000},
+	})
+}