diff --git a/compose/config/config.py b/compose/config/config.py index 84933e9c9..56761d181 100644 --- a/compose/config/config.py +++ b/compose/config/config.py @@ -990,12 +990,17 @@ def translate_deploy_keys_to_container_config(service_dict): deploy_dict = service_dict['deploy'] ignored_keys = [ - k for k in ['endpoint_mode', 'labels', 'update_config', 'rollback_config', 'placement'] + k for k in ['endpoint_mode', 'labels', 'update_config', 'rollback_config'] if k in deploy_dict ] if 'replicas' in deploy_dict and deploy_dict.get('mode', 'replicated') == 'replicated': - service_dict['scale'] = deploy_dict['replicas'] + scale = deploy_dict.get('replicas', 1) + max_replicas = deploy_dict.get('placement', {}).get('max_replicas_per_node', scale) + service_dict['scale'] = min(scale, max_replicas) + if max_replicas < scale: + log.warning("Scale is limited to {} ('max_replicas_per_node' field).".format( + max_replicas)) if 'restart_policy' in deploy_dict: service_dict['restart'] = { diff --git a/compose/config/config_schema_v3.7.json b/compose/config/config_schema_v3.7.json index cd7882f5b..c5906af9f 100644 --- a/compose/config/config_schema_v3.7.json +++ b/compose/config/config_schema_v3.7.json @@ -2,13 +2,13 @@ "$schema": "http://json-schema.org/draft-04/schema#", "id": "config_schema_v3.7.json", "type": "object", - "required": ["version"], - + "required": [ + "version" + ], "properties": { "version": { "type": "string" }, - "services": { "id": "#/properties/services", "type": "object", @@ -19,7 +19,6 @@ }, "additionalProperties": false }, - "networks": { "id": "#/properties/networks", "type": "object", @@ -29,7 +28,6 @@ } } }, - "volumes": { "id": "#/properties/volumes", "type": "object", @@ -40,7 +38,6 @@ }, "additionalProperties": false }, - "secrets": { "id": "#/properties/secrets", "type": "object", @@ -51,7 +48,6 @@ }, "additionalProperties": false }, - "configs": { "id": "#/properties/configs", "type": "object", @@ -63,124 +59,251 @@ "additionalProperties": false } }, - - "patternProperties": {"^x-": {}}, + "patternProperties": { + "^x-": {} + }, "additionalProperties": false, - "definitions": { - "service": { "id": "#/definitions/service", "type": "object", - "properties": { - "deploy": {"$ref": "#/definitions/deployment"}, + "deploy": { + "$ref": "#/definitions/deployment" + }, "build": { "oneOf": [ - {"type": "string"}, + { + "type": "string" + }, { "type": "object", "properties": { - "context": {"type": "string"}, - "dockerfile": {"type": "string"}, - "args": {"$ref": "#/definitions/list_or_dict"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, - "cache_from": {"$ref": "#/definitions/list_of_strings"}, - "network": {"type": "string"}, - "target": {"type": "string"}, - "shm_size": {"type": ["integer", "string"]} + "context": { + "type": "string" + }, + "dockerfile": { + "type": "string" + }, + "args": { + "$ref": "#/definitions/list_or_dict" + }, + "labels": { + "$ref": "#/definitions/list_or_dict" + }, + "cache_from": { + "$ref": "#/definitions/list_of_strings" + }, + "network": { + "type": "string" + }, + "target": { + "type": "string" + }, + "shm_size": { + "type": [ + "integer", + "string" + ] + } }, "additionalProperties": false } ] }, - "cap_add": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, - "cap_drop": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, - "cgroup_parent": {"type": "string"}, + "cap_add": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "cap_drop": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "cgroup_parent": { + "type": "string" + }, "command": { "oneOf": [ - {"type": "string"}, - {"type": "array", "items": {"type": "string"}} + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } ] }, "configs": { "type": "array", "items": { "oneOf": [ - {"type": "string"}, + { + "type": "string" + }, { "type": "object", "properties": { - "source": {"type": "string"}, - "target": {"type": "string"}, - "uid": {"type": "string"}, - "gid": {"type": "string"}, - "mode": {"type": "number"} + "source": { + "type": "string" + }, + "target": { + "type": "string" + }, + "uid": { + "type": "string" + }, + "gid": { + "type": "string" + }, + "mode": { + "type": "number" + } } } ] } }, - "container_name": {"type": "string"}, - "credential_spec": {"type": "object", "properties": { - "file": {"type": "string"}, - "registry": {"type": "string"} - }}, - "depends_on": {"$ref": "#/definitions/list_of_strings"}, - "devices": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, - "dns": {"$ref": "#/definitions/string_or_list"}, - "dns_search": {"$ref": "#/definitions/string_or_list"}, - "domainname": {"type": "string"}, + "container_name": { + "type": "string" + }, + "credential_spec": { + "type": "object", + "properties": { + "file": { + "type": "string" + }, + "registry": { + "type": "string" + } + } + }, + "depends_on": { + "$ref": "#/definitions/list_of_strings" + }, + "devices": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "dns": { + "$ref": "#/definitions/string_or_list" + }, + "dns_search": { + "$ref": "#/definitions/string_or_list" + }, + "domainname": { + "type": "string" + }, "entrypoint": { "oneOf": [ - {"type": "string"}, - {"type": "array", "items": {"type": "string"}} + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } ] }, - "env_file": {"$ref": "#/definitions/string_or_list"}, - "environment": {"$ref": "#/definitions/list_or_dict"}, - + "env_file": { + "$ref": "#/definitions/string_or_list" + }, + "environment": { + "$ref": "#/definitions/list_or_dict" + }, "expose": { "type": "array", "items": { - "type": ["string", "number"], + "type": [ + "string", + "number" + ], "format": "expose" }, "uniqueItems": true }, - - "external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, - "extra_hosts": {"$ref": "#/definitions/list_or_dict"}, - "healthcheck": {"$ref": "#/definitions/healthcheck"}, - "hostname": {"type": "string"}, - "image": {"type": "string"}, - "init": {"type": "boolean"}, - "ipc": {"type": "string"}, - "isolation": {"type": "string"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, - "links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, - - "logging": { - "type": "object", - - "properties": { - "driver": {"type": "string"}, - "options": { - "type": "object", - "patternProperties": { - "^.+$": {"type": ["string", "number", "null"]} - } - } - }, - "additionalProperties": false + "external_links": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "extra_hosts": { + "$ref": "#/definitions/list_or_dict" + }, + "healthcheck": { + "$ref": "#/definitions/healthcheck" + }, + "hostname": { + "type": "string" + }, + "image": { + "type": "string" + }, + "init": { + "type": "boolean" + }, + "ipc": { + "type": "string" + }, + "isolation": { + "type": "string" + }, + "labels": { + "$ref": "#/definitions/list_or_dict" + }, + "links": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "logging": { + "type": "object", + "properties": { + "driver": { + "type": "string" + }, + "options": { + "type": "object", + "patternProperties": { + "^.+$": { + "type": [ + "string", + "number", + "null" + ] + } + } + } + }, + "additionalProperties": false + }, + "mac_address": { + "type": "string" + }, + "network_mode": { + "type": "string" }, - - "mac_address": {"type": "string"}, - "network_mode": {"type": "string"}, - "networks": { "oneOf": [ - {"$ref": "#/definitions/list_of_strings"}, + { + "$ref": "#/definitions/list_of_strings" + }, { "type": "object", "patternProperties": { @@ -189,13 +312,21 @@ { "type": "object", "properties": { - "aliases": {"$ref": "#/definitions/list_of_strings"}, - "ipv4_address": {"type": "string"}, - "ipv6_address": {"type": "string"} + "aliases": { + "$ref": "#/definitions/list_of_strings" + }, + "ipv4_address": { + "type": "string" + }, + "ipv6_address": { + "type": "string" + } }, "additionalProperties": false }, - {"type": "null"} + { + "type": "null" + } ] } }, @@ -203,21 +334,39 @@ } ] }, - "pid": {"type": ["string", "null"]}, - + "pid": { + "type": [ + "string", + "null" + ] + }, "ports": { "type": "array", "items": { "oneOf": [ - {"type": "number", "format": "ports"}, - {"type": "string", "format": "ports"}, + { + "type": "number", + "format": "ports" + }, + { + "type": "string", + "format": "ports" + }, { "type": "object", "properties": { - "mode": {"type": "string"}, - "target": {"type": "integer"}, - "published": {"type": "integer"}, - "protocol": {"type": "string"} + "mode": { + "type": "string" + }, + "target": { + "type": "integer" + }, + "published": { + "type": "integer" + }, + "protocol": { + "type": "string" + } }, "additionalProperties": false } @@ -225,81 +374,153 @@ }, "uniqueItems": true }, - - "privileged": {"type": "boolean"}, - "read_only": {"type": "boolean"}, - "restart": {"type": "string"}, - "security_opt": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, - "shm_size": {"type": ["number", "string"]}, + "privileged": { + "type": "boolean" + }, + "read_only": { + "type": "boolean" + }, + "restart": { + "type": "string" + }, + "security_opt": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "shm_size": { + "type": [ + "number", + "string" + ] + }, "secrets": { "type": "array", "items": { "oneOf": [ - {"type": "string"}, + { + "type": "string" + }, { "type": "object", "properties": { - "source": {"type": "string"}, - "target": {"type": "string"}, - "uid": {"type": "string"}, - "gid": {"type": "string"}, - "mode": {"type": "number"} + "source": { + "type": "string" + }, + "target": { + "type": "string" + }, + "uid": { + "type": "string" + }, + "gid": { + "type": "string" + }, + "mode": { + "type": "number" + } } } ] } }, - "sysctls": {"$ref": "#/definitions/list_or_dict"}, - "stdin_open": {"type": "boolean"}, - "stop_grace_period": {"type": "string", "format": "duration"}, - "stop_signal": {"type": "string"}, - "tmpfs": {"$ref": "#/definitions/string_or_list"}, - "tty": {"type": "boolean"}, + "sysctls": { + "$ref": "#/definitions/list_or_dict" + }, + "stdin_open": { + "type": "boolean" + }, + "stop_grace_period": { + "type": "string", + "format": "duration" + }, + "stop_signal": { + "type": "string" + }, + "tmpfs": { + "$ref": "#/definitions/string_or_list" + }, + "tty": { + "type": "boolean" + }, "ulimits": { "type": "object", "patternProperties": { "^[a-z]+$": { "oneOf": [ - {"type": "integer"}, { - "type":"object", + "type": "integer" + }, + { + "type": "object", "properties": { - "hard": {"type": "integer"}, - "soft": {"type": "integer"} + "hard": { + "type": "integer" + }, + "soft": { + "type": "integer" + } }, - "required": ["soft", "hard"], + "required": [ + "soft", + "hard" + ], "additionalProperties": false } ] } } }, - "user": {"type": "string"}, - "userns_mode": {"type": "string"}, + "user": { + "type": "string" + }, + "userns_mode": { + "type": "string" + }, "volumes": { "type": "array", "items": { "oneOf": [ - {"type": "string"}, + { + "type": "string" + }, { "type": "object", - "required": ["type"], + "required": [ + "type" + ], "properties": { - "type": {"type": "string"}, - "source": {"type": "string"}, - "target": {"type": "string"}, - "read_only": {"type": "boolean"}, - "consistency": {"type": "string"}, + "type": { + "type": "string" + }, + "source": { + "type": "string" + }, + "target": { + "type": "string" + }, + "read_only": { + "type": "boolean" + }, + "consistency": { + "type": "string" + }, "bind": { "type": "object", "properties": { - "propagation": {"type": "string"} + "propagation": { + "type": "string" + } } }, "volume": { "type": "object", "properties": { - "nocopy": {"type": "boolean"} + "nocopy": { + "type": "boolean" + } } }, "tmpfs": { @@ -318,63 +539,129 @@ "uniqueItems": true } }, - "working_dir": {"type": "string"} + "working_dir": { + "type": "string" + } + }, + "patternProperties": { + "^x-": {} }, - "patternProperties": {"^x-": {}}, "additionalProperties": false }, - "healthcheck": { "id": "#/definitions/healthcheck", "type": "object", "additionalProperties": false, "properties": { - "disable": {"type": "boolean"}, - "interval": {"type": "string", "format": "duration"}, - "retries": {"type": "number"}, + "disable": { + "type": "boolean" + }, + "interval": { + "type": "string", + "format": "duration" + }, + "retries": { + "type": "number" + }, "test": { "oneOf": [ - {"type": "string"}, - {"type": "array", "items": {"type": "string"}} + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } ] }, - "timeout": {"type": "string", "format": "duration"}, - "start_period": {"type": "string", "format": "duration"} + "timeout": { + "type": "string", + "format": "duration" + }, + "start_period": { + "type": "string", + "format": "duration" + } } }, "deployment": { "id": "#/definitions/deployment", - "type": ["object", "null"], + "type": [ + "object", + "null" + ], "properties": { - "mode": {"type": "string"}, - "endpoint_mode": {"type": "string"}, - "replicas": {"type": "integer"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "mode": { + "type": "string" + }, + "endpoint_mode": { + "type": "string" + }, + "replicas": { + "type": "integer" + }, + "labels": { + "$ref": "#/definitions/list_or_dict" + }, "rollback_config": { "type": "object", "properties": { - "parallelism": {"type": "integer"}, - "delay": {"type": "string", "format": "duration"}, - "failure_action": {"type": "string"}, - "monitor": {"type": "string", "format": "duration"}, - "max_failure_ratio": {"type": "number"}, - "order": {"type": "string", "enum": [ - "start-first", "stop-first" - ]} + "parallelism": { + "type": "integer" + }, + "delay": { + "type": "string", + "format": "duration" + }, + "failure_action": { + "type": "string" + }, + "monitor": { + "type": "string", + "format": "duration" + }, + "max_failure_ratio": { + "type": "number" + }, + "order": { + "type": "string", + "enum": [ + "start-first", + "stop-first" + ] + } }, "additionalProperties": false }, "update_config": { "type": "object", "properties": { - "parallelism": {"type": "integer"}, - "delay": {"type": "string", "format": "duration"}, - "failure_action": {"type": "string"}, - "monitor": {"type": "string", "format": "duration"}, - "max_failure_ratio": {"type": "number"}, - "order": {"type": "string", "enum": [ - "start-first", "stop-first" - ]} + "parallelism": { + "type": "integer" + }, + "delay": { + "type": "string", + "format": "duration" + }, + "failure_action": { + "type": "string" + }, + "monitor": { + "type": "string", + "format": "duration" + }, + "max_failure_ratio": { + "type": "number" + }, + "order": { + "type": "string", + "enum": [ + "start-first", + "stop-first" + ] + } }, "additionalProperties": false }, @@ -384,17 +671,27 @@ "limits": { "type": "object", "properties": { - "cpus": {"type": "string"}, - "memory": {"type": "string"} + "cpus": { + "type": "string" + }, + "memory": { + "type": "string" + } }, "additionalProperties": false }, "reservations": { "type": "object", "properties": { - "cpus": {"type": "string"}, - "memory": {"type": "string"}, - "generic_resources": {"$ref": "#/definitions/generic_resources"} + "cpus": { + "type": "string" + }, + "memory": { + "type": "string" + }, + "generic_resources": { + "$ref": "#/definitions/generic_resources" + } }, "additionalProperties": false } @@ -404,23 +701,40 @@ "restart_policy": { "type": "object", "properties": { - "condition": {"type": "string"}, - "delay": {"type": "string", "format": "duration"}, - "max_attempts": {"type": "integer"}, - "window": {"type": "string", "format": "duration"} + "condition": { + "type": "string" + }, + "delay": { + "type": "string", + "format": "duration" + }, + "max_attempts": { + "type": "integer" + }, + "window": { + "type": "string", + "format": "duration" + } }, "additionalProperties": false }, "placement": { "type": "object", "properties": { - "constraints": {"type": "array", "items": {"type": "string"}}, + "constraints": { + "type": "array", + "items": { + "type": "string" + } + }, "preferences": { "type": "array", "items": { "type": "object", "properties": { - "spread": {"type": "string"} + "spread": { + "type": "string" + } }, "additionalProperties": false } @@ -431,7 +745,6 @@ }, "additionalProperties": false }, - "generic_resources": { "id": "#/definitions/generic_resources", "type": "array", @@ -441,8 +754,12 @@ "discrete_resource_spec": { "type": "object", "properties": { - "kind": {"type": "string"}, - "value": {"type": "number"} + "kind": { + "type": "string" + }, + "value": { + "type": "number" + } }, "additionalProperties": false } @@ -450,29 +767,44 @@ "additionalProperties": false } }, - "network": { "id": "#/definitions/network", - "type": ["object", "null"], + "type": [ + "object", + "null" + ], "properties": { - "name": {"type": "string"}, - "driver": {"type": "string"}, + "name": { + "type": "string" + }, + "driver": { + "type": "string" + }, "driver_opts": { "type": "object", "patternProperties": { - "^.+$": {"type": ["string", "number"]} + "^.+$": { + "type": [ + "string", + "number" + ] + } } }, "ipam": { "type": "object", "properties": { - "driver": {"type": "string"}, + "driver": { + "type": "string" + }, "config": { "type": "array", "items": { "type": "object", "properties": { - "subnet": {"type": "string"} + "subnet": { + "type": "string" + } }, "additionalProperties": false } @@ -481,119 +813,198 @@ "additionalProperties": false }, "external": { - "type": ["boolean", "object"], + "type": [ + "boolean", + "object" + ], "properties": { - "name": {"type": "string"} + "name": { + "type": "string" + } }, "additionalProperties": false }, - "internal": {"type": "boolean"}, - "attachable": {"type": "boolean"}, - "labels": {"$ref": "#/definitions/list_or_dict"} + "internal": { + "type": "boolean" + }, + "attachable": { + "type": "boolean" + }, + "labels": { + "$ref": "#/definitions/list_or_dict" + } + }, + "patternProperties": { + "^x-": {} }, - "patternProperties": {"^x-": {}}, "additionalProperties": false }, - "volume": { "id": "#/definitions/volume", - "type": ["object", "null"], + "type": [ + "object", + "null" + ], "properties": { - "name": {"type": "string"}, - "driver": {"type": "string"}, + "name": { + "type": "string" + }, + "driver": { + "type": "string" + }, "driver_opts": { "type": "object", "patternProperties": { - "^.+$": {"type": ["string", "number"]} + "^.+$": { + "type": [ + "string", + "number" + ] + } } }, "external": { - "type": ["boolean", "object"], + "type": [ + "boolean", + "object" + ], "properties": { - "name": {"type": "string"} + "name": { + "type": "string" + } }, "additionalProperties": false }, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": { + "$ref": "#/definitions/list_or_dict" + } + }, + "patternProperties": { + "^x-": {} }, - "patternProperties": {"^x-": {}}, "additionalProperties": false }, - "secret": { "id": "#/definitions/secret", "type": "object", "properties": { - "name": {"type": "string"}, - "file": {"type": "string"}, + "name": { + "type": "string" + }, + "file": { + "type": "string" + }, "external": { - "type": ["boolean", "object"], + "type": [ + "boolean", + "object" + ], "properties": { - "name": {"type": "string"} + "name": { + "type": "string" + } } }, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": { + "$ref": "#/definitions/list_or_dict" + } + }, + "patternProperties": { + "^x-": {} }, - "patternProperties": {"^x-": {}}, "additionalProperties": false }, - "config": { "id": "#/definitions/config", "type": "object", "properties": { - "name": {"type": "string"}, - "file": {"type": "string"}, + "name": { + "type": "string" + }, + "file": { + "type": "string" + }, "external": { - "type": ["boolean", "object"], + "type": [ + "boolean", + "object" + ], "properties": { - "name": {"type": "string"} + "name": { + "type": "string" + } } }, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": { + "$ref": "#/definitions/list_or_dict" + } + }, + "patternProperties": { + "^x-": {} }, - "patternProperties": {"^x-": {}}, "additionalProperties": false }, - "string_or_list": { "oneOf": [ - {"type": "string"}, - {"$ref": "#/definitions/list_of_strings"} + { + "type": "string" + }, + { + "$ref": "#/definitions/list_of_strings" + } ] }, - "list_of_strings": { "type": "array", - "items": {"type": "string"}, + "items": { + "type": "string" + }, "uniqueItems": true }, - "list_or_dict": { "oneOf": [ { "type": "object", "patternProperties": { ".+": { - "type": ["string", "number", "null"] + "type": [ + "string", + "number", + "null" + ] } }, "additionalProperties": false }, - {"type": "array", "items": {"type": "string"}, "uniqueItems": true} + { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + } ] }, - "constraints": { "service": { "id": "#/definitions/constraints/service", "anyOf": [ - {"required": ["build"]}, - {"required": ["image"]} + { + "required": [ + "build" + ] + }, + { + "required": [ + "image" + ] + } ], "properties": { "build": { - "required": ["context"] + "required": [ + "context" + ] } } } diff --git a/compose/config/config_schema_v3.8.json b/compose/config/config_schema_v3.8.json new file mode 100644 index 000000000..e9bc20cee --- /dev/null +++ b/compose/config/config_schema_v3.8.json @@ -0,0 +1,1040 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "id": "config_schema_v3.8.json", + "type": "object", + "required": [ + "version" + ], + "properties": { + "version": { + "type": "string" + }, + "services": { + "id": "#/properties/services", + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9._-]+$": { + "$ref": "#/definitions/service" + } + }, + "additionalProperties": false + }, + "networks": { + "id": "#/properties/networks", + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9._-]+$": { + "$ref": "#/definitions/network" + } + } + }, + "volumes": { + "id": "#/properties/volumes", + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9._-]+$": { + "$ref": "#/definitions/volume" + } + }, + "additionalProperties": false + }, + "secrets": { + "id": "#/properties/secrets", + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9._-]+$": { + "$ref": "#/definitions/secret" + } + }, + "additionalProperties": false + }, + "configs": { + "id": "#/properties/configs", + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9._-]+$": { + "$ref": "#/definitions/config" + } + }, + "additionalProperties": false + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false, + "definitions": { + "service": { + "id": "#/definitions/service", + "type": "object", + "properties": { + "deploy": { + "$ref": "#/definitions/deployment" + }, + "build": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "context": { + "type": "string" + }, + "dockerfile": { + "type": "string" + }, + "args": { + "$ref": "#/definitions/list_or_dict" + }, + "labels": { + "$ref": "#/definitions/list_or_dict" + }, + "cache_from": { + "$ref": "#/definitions/list_of_strings" + }, + "network": { + "type": "string" + }, + "target": { + "type": "string" + }, + "shm_size": { + "type": [ + "integer", + "string" + ] + } + }, + "additionalProperties": false + } + ] + }, + "cap_add": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "cap_drop": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "cgroup_parent": { + "type": "string" + }, + "command": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "configs": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "source": { + "type": "string" + }, + "target": { + "type": "string" + }, + "uid": { + "type": "string" + }, + "gid": { + "type": "string" + }, + "mode": { + "type": "number" + } + } + } + ] + } + }, + "container_name": { + "type": "string" + }, + "credential_spec": { + "type": "object", + "properties": { + "config": { + "type": "string" + }, + "file": { + "type": "string" + }, + "registry": { + "type": "string" + } + }, + "additionalProperties": false + }, + "depends_on": { + "$ref": "#/definitions/list_of_strings" + }, + "devices": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "dns": { + "$ref": "#/definitions/string_or_list" + }, + "dns_search": { + "$ref": "#/definitions/string_or_list" + }, + "domainname": { + "type": "string" + }, + "entrypoint": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "env_file": { + "$ref": "#/definitions/string_or_list" + }, + "environment": { + "$ref": "#/definitions/list_or_dict" + }, + "expose": { + "type": "array", + "items": { + "type": [ + "string", + "number" + ], + "format": "expose" + }, + "uniqueItems": true + }, + "external_links": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "extra_hosts": { + "$ref": "#/definitions/list_or_dict" + }, + "healthcheck": { + "$ref": "#/definitions/healthcheck" + }, + "hostname": { + "type": "string" + }, + "image": { + "type": "string" + }, + "init": { + "type": "boolean" + }, + "ipc": { + "type": "string" + }, + "isolation": { + "type": "string" + }, + "labels": { + "$ref": "#/definitions/list_or_dict" + }, + "links": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "logging": { + "type": "object", + "properties": { + "driver": { + "type": "string" + }, + "options": { + "type": "object", + "patternProperties": { + "^.+$": { + "type": [ + "string", + "number", + "null" + ] + } + } + } + }, + "additionalProperties": false + }, + "mac_address": { + "type": "string" + }, + "network_mode": { + "type": "string" + }, + "networks": { + "oneOf": [ + { + "$ref": "#/definitions/list_of_strings" + }, + { + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9._-]+$": { + "oneOf": [ + { + "type": "object", + "properties": { + "aliases": { + "$ref": "#/definitions/list_of_strings" + }, + "ipv4_address": { + "type": "string" + }, + "ipv6_address": { + "type": "string" + } + }, + "additionalProperties": false + }, + { + "type": "null" + } + ] + } + }, + "additionalProperties": false + } + ] + }, + "pid": { + "type": [ + "string", + "null" + ] + }, + "ports": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "number", + "format": "ports" + }, + { + "type": "string", + "format": "ports" + }, + { + "type": "object", + "properties": { + "mode": { + "type": "string" + }, + "target": { + "type": "integer" + }, + "published": { + "type": "integer" + }, + "protocol": { + "type": "string" + } + }, + "additionalProperties": false + } + ] + }, + "uniqueItems": true + }, + "privileged": { + "type": "boolean" + }, + "read_only": { + "type": "boolean" + }, + "restart": { + "type": "string" + }, + "security_opt": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "shm_size": { + "type": [ + "number", + "string" + ] + }, + "secrets": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "source": { + "type": "string" + }, + "target": { + "type": "string" + }, + "uid": { + "type": "string" + }, + "gid": { + "type": "string" + }, + "mode": { + "type": "number" + } + } + } + ] + } + }, + "sysctls": { + "$ref": "#/definitions/list_or_dict" + }, + "stdin_open": { + "type": "boolean" + }, + "stop_grace_period": { + "type": "string", + "format": "duration" + }, + "stop_signal": { + "type": "string" + }, + "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 + } + ] + } + } + }, + "user": { + "type": "string" + }, + "userns_mode": { + "type": "string" + }, + "volumes": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string" + }, + "source": { + "type": "string" + }, + "target": { + "type": "string" + }, + "read_only": { + "type": "boolean" + }, + "consistency": { + "type": "string" + }, + "bind": { + "type": "object", + "properties": { + "propagation": { + "type": "string" + } + } + }, + "volume": { + "type": "object", + "properties": { + "nocopy": { + "type": "boolean" + } + } + }, + "tmpfs": { + "type": "object", + "properties": { + "size": { + "type": "integer", + "minimum": 0 + } + } + } + }, + "additionalProperties": false + } + ], + "uniqueItems": true + } + }, + "working_dir": { + "type": "string" + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "healthcheck": { + "id": "#/definitions/healthcheck", + "type": "object", + "additionalProperties": false, + "properties": { + "disable": { + "type": "boolean" + }, + "interval": { + "type": "string", + "format": "duration" + }, + "retries": { + "type": "number" + }, + "test": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "timeout": { + "type": "string", + "format": "duration" + }, + "start_period": { + "type": "string", + "format": "duration" + } + } + }, + "deployment": { + "id": "#/definitions/deployment", + "type": [ + "object", + "null" + ], + "properties": { + "mode": { + "type": "string" + }, + "endpoint_mode": { + "type": "string" + }, + "replicas": { + "type": "integer" + }, + "labels": { + "$ref": "#/definitions/list_or_dict" + }, + "rollback_config": { + "type": "object", + "properties": { + "parallelism": { + "type": "integer" + }, + "delay": { + "type": "string", + "format": "duration" + }, + "failure_action": { + "type": "string" + }, + "monitor": { + "type": "string", + "format": "duration" + }, + "max_failure_ratio": { + "type": "number" + }, + "order": { + "type": "string", + "enum": [ + "start-first", + "stop-first" + ] + } + }, + "additionalProperties": false + }, + "update_config": { + "type": "object", + "properties": { + "parallelism": { + "type": "integer" + }, + "delay": { + "type": "string", + "format": "duration" + }, + "failure_action": { + "type": "string" + }, + "monitor": { + "type": "string", + "format": "duration" + }, + "max_failure_ratio": { + "type": "number" + }, + "order": { + "type": "string", + "enum": [ + "start-first", + "stop-first" + ] + } + }, + "additionalProperties": false + }, + "resources": { + "type": "object", + "properties": { + "limits": { + "type": "object", + "properties": { + "cpus": { + "type": "string" + }, + "memory": { + "type": "string" + } + }, + "additionalProperties": false + }, + "reservations": { + "type": "object", + "properties": { + "cpus": { + "type": "string" + }, + "memory": { + "type": "string" + }, + "generic_resources": { + "$ref": "#/definitions/generic_resources" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "restart_policy": { + "type": "object", + "properties": { + "condition": { + "type": "string" + }, + "delay": { + "type": "string", + "format": "duration" + }, + "max_attempts": { + "type": "integer" + }, + "window": { + "type": "string", + "format": "duration" + } + }, + "additionalProperties": false + }, + "placement": { + "type": "object", + "properties": { + "constraints": { + "type": "array", + "items": { + "type": "string" + } + }, + "preferences": { + "type": "array", + "items": { + "type": "object", + "properties": { + "spread": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "max_replicas_per_node": { + "type": "integer" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "generic_resources": { + "id": "#/definitions/generic_resources", + "type": "array", + "items": { + "type": "object", + "properties": { + "discrete_resource_spec": { + "type": "object", + "properties": { + "kind": { + "type": "string" + }, + "value": { + "type": "number" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } + }, + "network": { + "id": "#/definitions/network", + "type": [ + "object", + "null" + ], + "properties": { + "name": { + "type": "string" + }, + "driver": { + "type": "string" + }, + "driver_opts": { + "type": "object", + "patternProperties": { + "^.+$": { + "type": [ + "string", + "number" + ] + } + } + }, + "ipam": { + "type": "object", + "properties": { + "driver": { + "type": "string" + }, + "config": { + "type": "array", + "items": { + "type": "object", + "properties": { + "subnet": { + "type": "string" + } + }, + "additionalProperties": false + } + } + }, + "additionalProperties": false + }, + "external": { + "type": [ + "boolean", + "object" + ], + "properties": { + "name": { + "type": "string" + } + }, + "additionalProperties": false + }, + "internal": { + "type": "boolean" + }, + "attachable": { + "type": "boolean" + }, + "labels": { + "$ref": "#/definitions/list_or_dict" + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "volume": { + "id": "#/definitions/volume", + "type": [ + "object", + "null" + ], + "properties": { + "name": { + "type": "string" + }, + "driver": { + "type": "string" + }, + "driver_opts": { + "type": "object", + "patternProperties": { + "^.+$": { + "type": [ + "string", + "number" + ] + } + } + }, + "external": { + "type": [ + "boolean", + "object" + ], + "properties": { + "name": { + "type": "string" + } + }, + "additionalProperties": false + }, + "labels": { + "$ref": "#/definitions/list_or_dict" + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "secret": { + "id": "#/definitions/secret", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "file": { + "type": "string" + }, + "external": { + "type": [ + "boolean", + "object" + ], + "properties": { + "name": { + "type": "string" + } + } + }, + "labels": { + "$ref": "#/definitions/list_or_dict" + }, + "driver": { + "type": "string" + }, + "driver_opts": { + "type": "object", + "patternProperties": { + "^.+$": { + "type": [ + "string", + "number" + ] + } + } + }, + "template_driver": { + "type": "string" + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "config": { + "id": "#/definitions/config", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "file": { + "type": "string" + }, + "external": { + "type": [ + "boolean", + "object" + ], + "properties": { + "name": { + "type": "string" + } + } + }, + "labels": { + "$ref": "#/definitions/list_or_dict" + }, + "template_driver": { + "type": "string" + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "string_or_list": { + "oneOf": [ + { + "type": "string" + }, + { + "$ref": "#/definitions/list_of_strings" + } + ] + }, + "list_of_strings": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "list_or_dict": { + "oneOf": [ + { + "type": "object", + "patternProperties": { + ".+": { + "type": [ + "string", + "number", + "null" + ] + } + }, + "additionalProperties": false + }, + { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + } + ] + }, + "constraints": { + "service": { + "id": "#/definitions/constraints/service", + "anyOf": [ + { + "required": [ + "build" + ] + }, + { + "required": [ + "image" + ] + } + ], + "properties": { + "build": { + "required": [ + "context" + ] + } + } + } + } + } +} diff --git a/compose/const.py b/compose/const.py index ab0389ce0..3d9030520 100644 --- a/compose/const.py +++ b/compose/const.py @@ -41,7 +41,10 @@ COMPOSEFILE_V3_4 = ComposeVersion('3.4') COMPOSEFILE_V3_5 = ComposeVersion('3.5') COMPOSEFILE_V3_6 = ComposeVersion('3.6') COMPOSEFILE_V3_7 = ComposeVersion('3.7') +COMPOSEFILE_V3_8 = ComposeVersion('3.8') +# minimum DOCKER ENGINE API version needed to support +# features for each compose schema version API_VERSIONS = { COMPOSEFILE_V1: '1.21', COMPOSEFILE_V2_0: '1.22', @@ -57,6 +60,7 @@ API_VERSIONS = { COMPOSEFILE_V3_5: '1.30', COMPOSEFILE_V3_6: '1.36', COMPOSEFILE_V3_7: '1.38', + COMPOSEFILE_V3_8: '1.38', } API_VERSION_TO_ENGINE_VERSION = { @@ -74,4 +78,5 @@ API_VERSION_TO_ENGINE_VERSION = { API_VERSIONS[COMPOSEFILE_V3_5]: '17.06.0', API_VERSIONS[COMPOSEFILE_V3_6]: '18.02.0', API_VERSIONS[COMPOSEFILE_V3_7]: '18.06.0', + API_VERSIONS[COMPOSEFILE_V3_8]: '18.06.0', } diff --git a/tests/unit/config/config_test.py b/tests/unit/config/config_test.py index dc346df95..603eddaf2 100644 --- a/tests/unit/config/config_test.py +++ b/tests/unit/config/config_test.py @@ -3637,7 +3637,6 @@ class InterpolationTest(unittest.TestCase): assert 'labels' in warn_message assert 'endpoint_mode' in warn_message assert 'update_config' in warn_message - assert 'placement' in warn_message assert 'resources.reservations.cpus' in warn_message assert 'restart_policy.delay' in warn_message assert 'restart_policy.window' in warn_message