diff --git a/compose/config/config_schema_v2.0.json b/compose/config/config_schema_v2.0.json index 2ad62ac52..7f4e10592 100644 --- a/compose/config/config_schema_v2.0.json +++ b/compose/config/config_schema_v2.0.json @@ -299,7 +299,8 @@ }, "additionalProperties": false }, - "internal": {"type": "boolean"} + "internal": {"type": "boolean"}, + "priority": {"type": "number"} }, "additionalProperties": false }, diff --git a/compose/config/config_schema_v2.1.json b/compose/config/config_schema_v2.1.json index 15b78e5db..14fc89a1d 100644 --- a/compose/config/config_schema_v2.1.json +++ b/compose/config/config_schema_v2.1.json @@ -351,7 +351,8 @@ "internal": {"type": "boolean"}, "enable_ipv6": {"type": "boolean"}, "labels": {"$ref": "#/definitions/list_or_dict"}, - "name": {"type": "string"} + "name": {"type": "string"}, + "priority": {"type": "number"} }, "additionalProperties": false }, diff --git a/compose/config/config_schema_v2.2.json b/compose/config/config_schema_v2.2.json index 7a3eed0a9..3fbc4aeda 100644 --- a/compose/config/config_schema_v2.2.json +++ b/compose/config/config_schema_v2.2.json @@ -358,7 +358,8 @@ "internal": {"type": "boolean"}, "enable_ipv6": {"type": "boolean"}, "labels": {"$ref": "#/definitions/list_or_dict"}, - "name": {"type": "string"} + "name": {"type": "string"}, + "priority": {"type": "number"} }, "additionalProperties": false }, diff --git a/compose/config/config_schema_v2.3.json b/compose/config/config_schema_v2.3.json index 3a6397a7e..ab8eeafe9 100644 --- a/compose/config/config_schema_v2.3.json +++ b/compose/config/config_schema_v2.3.json @@ -395,7 +395,8 @@ "internal": {"type": "boolean"}, "enable_ipv6": {"type": "boolean"}, "labels": {"$ref": "#/definitions/list_or_dict"}, - "name": {"type": "string"} + "name": {"type": "string"}, + "priority": {"type": "number"} }, "additionalProperties": false }, diff --git a/compose/config/config_schema_v3.0.json b/compose/config/config_schema_v3.0.json index fa601bed2..2b0308123 100644 --- a/compose/config/config_schema_v3.0.json +++ b/compose/config/config_schema_v3.0.json @@ -310,7 +310,8 @@ "additionalProperties": false }, "internal": {"type": "boolean"}, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/list_or_dict"}, + "priority": {"type": "number"} }, "additionalProperties": false }, diff --git a/compose/config/config_schema_v3.1.json b/compose/config/config_schema_v3.1.json index 41da89650..1fc5c6ead 100644 --- a/compose/config/config_schema_v3.1.json +++ b/compose/config/config_schema_v3.1.json @@ -339,7 +339,8 @@ "additionalProperties": false }, "internal": {"type": "boolean"}, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/list_or_dict"}, + "priority": {"type": "number"} }, "additionalProperties": false }, diff --git a/compose/config/config_schema_v3.2.json b/compose/config/config_schema_v3.2.json index 0baf6a1a9..c2d1ec7c8 100644 --- a/compose/config/config_schema_v3.2.json +++ b/compose/config/config_schema_v3.2.json @@ -387,7 +387,8 @@ }, "internal": {"type": "boolean"}, "attachable": {"type": "boolean"}, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/list_or_dict"}, + "priority": {"type": "number"} }, "additionalProperties": false }, diff --git a/compose/config/config_schema_v3.3.json b/compose/config/config_schema_v3.3.json index efc0fdbd7..cdc8cbf77 100644 --- a/compose/config/config_schema_v3.3.json +++ b/compose/config/config_schema_v3.3.json @@ -430,7 +430,8 @@ }, "internal": {"type": "boolean"}, "attachable": {"type": "boolean"}, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/list_or_dict"}, + "priority": {"type": "number"} }, "additionalProperties": false }, diff --git a/compose/config/config_schema_v3.4.json b/compose/config/config_schema_v3.4.json index 576ecfd84..0d41fd148 100644 --- a/compose/config/config_schema_v3.4.json +++ b/compose/config/config_schema_v3.4.json @@ -438,7 +438,8 @@ }, "internal": {"type": "boolean"}, "attachable": {"type": "boolean"}, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/list_or_dict"}, + "priority": {"type": "number"} }, "additionalProperties": false }, diff --git a/compose/config/config_schema_v3.5.json b/compose/config/config_schema_v3.5.json index 565da0193..c09dc7ea6 100644 --- a/compose/config/config_schema_v3.5.json +++ b/compose/config/config_schema_v3.5.json @@ -464,7 +464,8 @@ }, "internal": {"type": "boolean"}, "attachable": {"type": "boolean"}, - "labels": {"$ref": "#/definitions/list_or_dict"} + "labels": {"$ref": "#/definitions/list_or_dict"}, + "priority": {"type": "number"} }, "additionalProperties": false }, diff --git a/compose/network.py b/compose/network.py index 95e2bf60e..3bc28a99c 100644 --- a/compose/network.py +++ b/compose/network.py @@ -26,7 +26,7 @@ OPTS_EXCEPTIONS = [ class Network(object): def __init__(self, client, project, name, driver=None, driver_opts=None, ipam=None, external=False, internal=False, enable_ipv6=False, - labels=None, custom_name=False): + labels=None, custom_name=False, priority=0): self.client = client self.project = project self.name = name @@ -38,6 +38,7 @@ class Network(object): self.enable_ipv6 = enable_ipv6 self.labels = labels self.custom_name = custom_name + self.priority = priority def ensure(self): if self.external: @@ -214,6 +215,7 @@ def build_networks(name, config_data, client): enable_ipv6=data.get('enable_ipv6'), labels=data.get('labels'), custom_name=data.get('name') is not None, + priority=data.get('priority'), ) for network_name, data in network_config.items() } diff --git a/compose/service.py b/compose/service.py index 420eb3f09..f6a9d12a8 100644 --- a/compose/service.py +++ b/compose/service.py @@ -6,6 +6,7 @@ import os import re import sys from collections import namedtuple +from collections import OrderedDict from operator import attrgetter import enum @@ -557,10 +558,15 @@ class Service(object): raise OperationFailedError("Cannot start service %s: %s" % (self.name, ex.explanation)) return container + def prioritized_networks(self): + prioritized_networks = OrderedDict( + sorted(self.networks.items(), key=lambda t: t[1].get('priority', 0), reverse=True)) + return prioritized_networks + def connect_container_to_networks(self, container): connected_networks = container.get('NetworkSettings.Networks') - for network, netdefs in self.networks.items(): + for network, netdefs in self.prioritized_networks().items(): if network in connected_networks: if short_id_alias_exists(container, network): continue diff --git a/tests/acceptance/cli_test.py b/tests/acceptance/cli_test.py index fa051fecb..87599f351 100644 --- a/tests/acceptance/cli_test.py +++ b/tests/acceptance/cli_test.py @@ -1274,6 +1274,18 @@ class CLITestCase(DockerClientTestCase): bar_container.id ) + def test_up_ordered_networks(self): + self.base_dir = 'tests/fixtures/networks' + + self.dispatch(['-f', 'ordered-networks.yml', 'up', '-d']) + + containers = self.project.get_service('web').containers() + + for container in containers: + networks = container.get('NetworkSettings.Networks') + assert networks.keys()[0] == "networks_bar" + assert networks.keys()[1] == "networks_foo" + @v3_only() def test_up_with_healthcheck(self): def wait_on_health_status(container, status): diff --git a/tests/fixtures/networks/ordered-networks.yml b/tests/fixtures/networks/ordered-networks.yml new file mode 100644 index 000000000..598148f6d --- /dev/null +++ b/tests/fixtures/networks/ordered-networks.yml @@ -0,0 +1,13 @@ +version: "2" + +services: + web: + image: busybox + command: top + networks: ["foo", "bar"] + +networks: + foo: + priority: 1 + bar: + priority: 2