diff --git a/compose/config/config_schema_v1.json b/compose/config/config_schema_v1.json index 94354cda7..2771f9958 100644 --- a/compose/config/config_schema_v1.json +++ b/compose/config/config_schema_v1.json @@ -78,7 +78,7 @@ "hostname": {"type": "string"}, "image": {"type": "string"}, "ipc": {"type": "string"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "log_driver": {"type": "string"}, "log_opt": {"type": "object"}, @@ -166,6 +166,21 @@ ] }, + "labels": { + "oneOf": [ + { + "type": "object", + "patternProperties": { + ".+": { + "type": "string" + } + }, + "additionalProperties": false + }, + {"type": "array", "items": {"type": "string"}, "uniqueItems": true} + ] + }, + "constraints": { "service": { "id": "#/definitions/constraints/service", diff --git a/compose/config/config_schema_v2.0.json b/compose/config/config_schema_v2.0.json index 8ab451a62..eddf787ea 100644 --- a/compose/config/config_schema_v2.0.json +++ b/compose/config/config_schema_v2.0.json @@ -158,7 +158,7 @@ "hostname": {"type": "string"}, "image": {"type": "string"}, "ipc": {"type": "string"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "logging": { @@ -355,6 +355,21 @@ ] }, + "labels": { + "oneOf": [ + { + "type": "object", + "patternProperties": { + ".+": { + "type": "string" + } + }, + "additionalProperties": false + }, + {"type": "array", "items": {"type": "string"}, "uniqueItems": true} + ] + }, + "blkio_limit": { "type": "object", "properties": { diff --git a/compose/config/config_schema_v2.1.json b/compose/config/config_schema_v2.1.json index f2ee2ce40..984c46c53 100644 --- a/compose/config/config_schema_v2.1.json +++ b/compose/config/config_schema_v2.1.json @@ -88,7 +88,7 @@ "context": {"type": "string"}, "dockerfile": {"type": "string"}, "args": {"$ref": "#/definitions/list_or_dict"}, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/labels"} }, "additionalProperties": false } @@ -183,7 +183,7 @@ "image": {"type": "string"}, "ipc": {"type": "string"}, "isolation": {"type": "string"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "logging": { @@ -351,7 +351,7 @@ }, "internal": {"type": "boolean"}, "enable_ipv6": {"type": "boolean"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "name": {"type": "string"} }, "additionalProperties": false @@ -375,7 +375,7 @@ }, "additionalProperties": false }, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "name": {"type": "string"} }, "additionalProperties": false @@ -409,6 +409,21 @@ ] }, + "labels": { + "oneOf": [ + { + "type": "object", + "patternProperties": { + ".+": { + "type": "string" + } + }, + "additionalProperties": false + }, + {"type": "array", "items": {"type": "string"}, "uniqueItems": true} + ] + }, + "blkio_limit": { "type": "object", "properties": { diff --git a/compose/config/config_schema_v2.2.json b/compose/config/config_schema_v2.2.json index b25aa71e2..8e3927e1d 100644 --- a/compose/config/config_schema_v2.2.json +++ b/compose/config/config_schema_v2.2.json @@ -88,7 +88,7 @@ "context": {"type": "string"}, "dockerfile": {"type": "string"}, "args": {"$ref": "#/definitions/list_or_dict"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "cache_from": {"$ref": "#/definitions/list_of_strings"}, "network": {"type": "string"} }, @@ -189,7 +189,7 @@ "init": {"type": ["boolean", "string"]}, "ipc": {"type": "string"}, "isolation": {"type": "string"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "logging": { @@ -358,7 +358,7 @@ }, "internal": {"type": "boolean"}, "enable_ipv6": {"type": "boolean"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "name": {"type": "string"} }, "additionalProperties": false @@ -382,7 +382,7 @@ }, "additionalProperties": false }, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "name": {"type": "string"} }, "additionalProperties": false @@ -416,6 +416,21 @@ ] }, + "labels": { + "oneOf": [ + { + "type": "object", + "patternProperties": { + ".+": { + "type": "string" + } + }, + "additionalProperties": false + }, + {"type": "array", "items": {"type": "string"}, "uniqueItems": true} + ] + }, + "blkio_limit": { "type": "object", "properties": { diff --git a/compose/config/config_schema_v2.3.json b/compose/config/config_schema_v2.3.json index 30f00dfe4..42e2afdad 100644 --- a/compose/config/config_schema_v2.3.json +++ b/compose/config/config_schema_v2.3.json @@ -88,7 +88,7 @@ "context": {"type": "string"}, "dockerfile": {"type": "string"}, "args": {"$ref": "#/definitions/list_or_dict"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "cache_from": {"$ref": "#/definitions/list_of_strings"}, "network": {"type": "string"}, "target": {"type": "string"}, @@ -192,7 +192,7 @@ "init": {"type": ["boolean", "string"]}, "ipc": {"type": "string"}, "isolation": {"type": "string"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "logging": { @@ -395,7 +395,7 @@ }, "internal": {"type": "boolean"}, "enable_ipv6": {"type": "boolean"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "name": {"type": "string"} }, "additionalProperties": false @@ -419,7 +419,7 @@ }, "additionalProperties": false }, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "name": {"type": "string"} }, "additionalProperties": false @@ -453,6 +453,21 @@ ] }, + "labels": { + "oneOf": [ + { + "type": "object", + "patternProperties": { + ".+": { + "type": "string" + } + }, + "additionalProperties": false + }, + {"type": "array", "items": {"type": "string"}, "uniqueItems": true} + ] + }, + "blkio_limit": { "type": "object", "properties": { diff --git a/compose/config/config_schema_v3.0.json b/compose/config/config_schema_v3.0.json index fa601bed2..10c363521 100644 --- a/compose/config/config_schema_v3.0.json +++ b/compose/config/config_schema_v3.0.json @@ -105,7 +105,7 @@ "hostname": {"type": "string"}, "image": {"type": "string"}, "ipc": {"type": "string"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "logging": { @@ -223,7 +223,7 @@ "properties": { "mode": {"type": "string"}, "replicas": {"type": "integer"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "update_config": { "type": "object", "properties": { @@ -310,7 +310,7 @@ "additionalProperties": false }, "internal": {"type": "boolean"}, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/labels"} }, "additionalProperties": false }, @@ -333,7 +333,7 @@ }, "additionalProperties": false }, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/labels"} }, "additionalProperties": false }, @@ -366,6 +366,21 @@ ] }, + "labels": { + "oneOf": [ + { + "type": "object", + "patternProperties": { + ".+": { + "type": "string" + } + }, + "additionalProperties": false + }, + {"type": "array", "items": {"type": "string"}, "uniqueItems": true} + ] + }, + "constraints": { "service": { "id": "#/definitions/constraints/service", diff --git a/compose/config/config_schema_v3.1.json b/compose/config/config_schema_v3.1.json index 41da89650..8630ec317 100644 --- a/compose/config/config_schema_v3.1.json +++ b/compose/config/config_schema_v3.1.json @@ -116,7 +116,7 @@ "hostname": {"type": "string"}, "image": {"type": "string"}, "ipc": {"type": "string"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "logging": { @@ -252,7 +252,7 @@ "properties": { "mode": {"type": "string"}, "replicas": {"type": "integer"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "update_config": { "type": "object", "properties": { @@ -339,7 +339,7 @@ "additionalProperties": false }, "internal": {"type": "boolean"}, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/labels"} }, "additionalProperties": false }, @@ -362,7 +362,7 @@ }, "additionalProperties": false }, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/labels"} }, "additionalProperties": false }, @@ -378,7 +378,7 @@ "name": {"type": "string"} } }, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/labels"} }, "additionalProperties": false }, @@ -411,6 +411,21 @@ ] }, + "labels": { + "oneOf": [ + { + "type": "object", + "patternProperties": { + ".+": { + "type": "string" + } + }, + "additionalProperties": false + }, + {"type": "array", "items": {"type": "string"}, "uniqueItems": true} + ] + }, + "constraints": { "service": { "id": "#/definitions/constraints/service", diff --git a/compose/config/config_schema_v3.2.json b/compose/config/config_schema_v3.2.json index 0baf6a1a9..5eccdea72 100644 --- a/compose/config/config_schema_v3.2.json +++ b/compose/config/config_schema_v3.2.json @@ -118,7 +118,7 @@ "hostname": {"type": "string"}, "image": {"type": "string"}, "ipc": {"type": "string"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "logging": { @@ -299,7 +299,7 @@ "mode": {"type": "string"}, "endpoint_mode": {"type": "string"}, "replicas": {"type": "integer"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "update_config": { "type": "object", "properties": { @@ -387,7 +387,7 @@ }, "internal": {"type": "boolean"}, "attachable": {"type": "boolean"}, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/labels"} }, "additionalProperties": false }, @@ -410,7 +410,7 @@ }, "additionalProperties": false }, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/labels"} }, "additionalProperties": false }, @@ -426,7 +426,7 @@ "name": {"type": "string"} } }, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/labels"} }, "additionalProperties": false }, @@ -459,6 +459,21 @@ ] }, + "labels": { + "oneOf": [ + { + "type": "object", + "patternProperties": { + ".+": { + "type": "string" + } + }, + "additionalProperties": false + }, + {"type": "array", "items": {"type": "string"}, "uniqueItems": true} + ] + }, + "constraints": { "service": { "id": "#/definitions/constraints/service", diff --git a/compose/config/config_schema_v3.3.json b/compose/config/config_schema_v3.3.json index efc0fdbd7..f63842b9d 100644 --- a/compose/config/config_schema_v3.3.json +++ b/compose/config/config_schema_v3.3.json @@ -83,7 +83,7 @@ "context": {"type": "string"}, "dockerfile": {"type": "string"}, "args": {"$ref": "#/definitions/list_or_dict"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "cache_from": {"$ref": "#/definitions/list_of_strings"} }, "additionalProperties": false @@ -151,7 +151,7 @@ "hostname": {"type": "string"}, "image": {"type": "string"}, "ipc": {"type": "string"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "logging": { @@ -332,7 +332,7 @@ "mode": {"type": "string"}, "endpoint_mode": {"type": "string"}, "replicas": {"type": "integer"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "update_config": { "type": "object", "properties": { @@ -430,7 +430,7 @@ }, "internal": {"type": "boolean"}, "attachable": {"type": "boolean"}, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/labels"} }, "additionalProperties": false }, @@ -453,7 +453,7 @@ }, "additionalProperties": false }, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/labels"} }, "additionalProperties": false }, @@ -469,7 +469,7 @@ "name": {"type": "string"} } }, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/labels"} }, "additionalProperties": false }, @@ -485,7 +485,7 @@ "name": {"type": "string"} } }, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/labels"} }, "additionalProperties": false }, @@ -518,6 +518,21 @@ ] }, + "labels": { + "oneOf": [ + { + "type": "object", + "patternProperties": { + ".+": { + "type": "string" + } + }, + "additionalProperties": false + }, + {"type": "array", "items": {"type": "string"}, "uniqueItems": true} + ] + }, + "constraints": { "service": { "id": "#/definitions/constraints/service", diff --git a/compose/config/config_schema_v3.4.json b/compose/config/config_schema_v3.4.json index 576ecfd84..23e955446 100644 --- a/compose/config/config_schema_v3.4.json +++ b/compose/config/config_schema_v3.4.json @@ -85,7 +85,7 @@ "context": {"type": "string"}, "dockerfile": {"type": "string"}, "args": {"$ref": "#/definitions/list_or_dict"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "cache_from": {"$ref": "#/definitions/list_of_strings"}, "network": {"type": "string"}, "target": {"type": "string"} @@ -155,7 +155,7 @@ "hostname": {"type": "string"}, "image": {"type": "string"}, "ipc": {"type": "string"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "logging": { @@ -337,7 +337,7 @@ "mode": {"type": "string"}, "endpoint_mode": {"type": "string"}, "replicas": {"type": "integer"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "update_config": { "type": "object", "properties": { @@ -438,7 +438,7 @@ }, "internal": {"type": "boolean"}, "attachable": {"type": "boolean"}, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/labels"} }, "additionalProperties": false }, @@ -462,7 +462,7 @@ }, "additionalProperties": false }, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/labels"} }, "additionalProperties": false }, @@ -478,7 +478,7 @@ "name": {"type": "string"} } }, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/labels"} }, "additionalProperties": false }, @@ -494,7 +494,7 @@ "name": {"type": "string"} } }, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/labels"} }, "additionalProperties": false }, @@ -527,6 +527,21 @@ ] }, + "labels": { + "oneOf": [ + { + "type": "object", + "patternProperties": { + ".+": { + "type": "string" + } + }, + "additionalProperties": false + }, + {"type": "array", "items": {"type": "string"}, "uniqueItems": true} + ] + }, + "constraints": { "service": { "id": "#/definitions/constraints/service", diff --git a/compose/config/config_schema_v3.5.json b/compose/config/config_schema_v3.5.json index 565da0193..e3bdecbc1 100644 --- a/compose/config/config_schema_v3.5.json +++ b/compose/config/config_schema_v3.5.json @@ -84,7 +84,7 @@ "context": {"type": "string"}, "dockerfile": {"type": "string"}, "args": {"$ref": "#/definitions/list_or_dict"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "cache_from": {"$ref": "#/definitions/list_of_strings"}, "network": {"type": "string"}, "target": {"type": "string"}, @@ -156,7 +156,7 @@ "image": {"type": "string"}, "ipc": {"type": "string"}, "isolation": {"type": "string"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "logging": { @@ -338,7 +338,7 @@ "mode": {"type": "string"}, "endpoint_mode": {"type": "string"}, "replicas": {"type": "integer"}, - "labels": {"$ref": "#/definitions/list_or_dict"}, + "labels": {"$ref": "#/definitions/labels"}, "update_config": { "type": "object", "properties": { @@ -464,7 +464,7 @@ }, "internal": {"type": "boolean"}, "attachable": {"type": "boolean"}, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/labels"} }, "additionalProperties": false }, @@ -488,7 +488,7 @@ }, "additionalProperties": false }, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/labels"} }, "additionalProperties": false }, @@ -505,7 +505,7 @@ "name": {"type": "string"} } }, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/labels"} }, "additionalProperties": false }, @@ -522,7 +522,7 @@ "name": {"type": "string"} } }, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/labels"} }, "additionalProperties": false }, @@ -555,6 +555,21 @@ ] }, + "labels": { + "oneOf": [ + { + "type": "object", + "patternProperties": { + ".+": { + "type": "string" + } + }, + "additionalProperties": false + }, + {"type": "array", "items": {"type": "string"}, "uniqueItems": true} + ] + }, + "constraints": { "service": { "id": "#/definitions/constraints/service", diff --git a/tests/unit/config/config_test.py b/tests/unit/config/config_test.py index cfbd4cf33..04e495f96 100644 --- a/tests/unit/config/config_test.py +++ b/tests/unit/config/config_test.py @@ -2747,6 +2747,25 @@ class ConfigTest(unittest.TestCase): ] assert service_sort(service_dicts) == service_sort(expected) + def test_config_invalid_service_label_validation(self): + config_details = build_config_details( + { + 'version': '3.5', + 'services': { + 'web': { + 'image': 'busybox', + 'labels': { + "key": 12345 + } + }, + }, + } + ) + with pytest.raises(ConfigurationError) as exc: + config.load(config_details) + + assert "which is an invalid type, it should be a string" in exc.exconly() + def test_service_volume_invalid_config(self): config_details = build_config_details( { @@ -2766,14 +2785,31 @@ class ConfigTest(unittest.TestCase): } } ] - }, - }, + } + } } ) with pytest.raises(ConfigurationError) as exc: config.load(config_details) + assert "services.web.volumes contains unsupported option: 'garbage'" in exc.exconly() + def test_config_valid_service_label_validation(self): + config_details = build_config_details( + { + 'version': '3.5', + 'services': { + 'web': { + 'image': 'busybox', + 'labels': { + "key": "string" + } + }, + }, + } + ) + config.load(config_details) + class NetworkModeTest(unittest.TestCase):