Przeglądaj źródła

Merge pull request #5566 from docker/mhank-5042-network-priorities

Add support for network priority
Joffrey F 7 lat temu
rodzic
commit
7f22744658

+ 2 - 1
compose/config/config_schema_v2.0.json

@@ -191,7 +191,8 @@
                       "properties": {
                         "aliases": {"$ref": "#/definitions/list_of_strings"},
                         "ipv4_address": {"type": "string"},
-                        "ipv6_address": {"type": "string"}
+                        "ipv6_address": {"type": "string"},
+                        "priority": {"type": "number"}
                       },
                       "additionalProperties": false
                     },

+ 2 - 1
compose/config/config_schema_v2.1.json

@@ -217,7 +217,8 @@
                         "aliases": {"$ref": "#/definitions/list_of_strings"},
                         "ipv4_address": {"type": "string"},
                         "ipv6_address": {"type": "string"},
-                        "link_local_ips": {"$ref": "#/definitions/list_of_strings"}
+                        "link_local_ips": {"$ref": "#/definitions/list_of_strings"},
+                        "priority": {"type": "number"}
                       },
                       "additionalProperties": false
                     },

+ 2 - 1
compose/config/config_schema_v2.2.json

@@ -223,7 +223,8 @@
                         "aliases": {"$ref": "#/definitions/list_of_strings"},
                         "ipv4_address": {"type": "string"},
                         "ipv6_address": {"type": "string"},
-                        "link_local_ips": {"$ref": "#/definitions/list_of_strings"}
+                        "link_local_ips": {"$ref": "#/definitions/list_of_strings"},
+                        "priority": {"type": "number"}
                       },
                       "additionalProperties": false
                     },

+ 2 - 1
compose/config/config_schema_v2.3.json

@@ -226,7 +226,8 @@
                         "aliases": {"$ref": "#/definitions/list_of_strings"},
                         "ipv4_address": {"type": "string"},
                         "ipv6_address": {"type": "string"},
-                        "link_local_ips": {"$ref": "#/definitions/list_of_strings"}
+                        "link_local_ips": {"$ref": "#/definitions/list_of_strings"},
+                        "priority": {"type": "number"}
                       },
                       "additionalProperties": false
                     },

+ 5 - 1
compose/network.py

@@ -2,6 +2,7 @@ from __future__ import absolute_import
 from __future__ import unicode_literals
 
 import logging
+from collections import OrderedDict
 
 from docker.errors import NotFound
 from docker.types import IPAMConfig
@@ -286,4 +287,7 @@ def get_networks(service_dict, network_definitions):
                 'Service "{}" uses an undefined network "{}"'
                 .format(service_dict['name'], name))
 
-    return networks
+    return OrderedDict(sorted(
+        networks.items(),
+        key=lambda t: t[1].get('priority') or 0, reverse=True
+    ))

+ 13 - 5
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,18 +558,25 @@ class Service(object):
             raise OperationFailedError("Cannot start service %s: %s" % (self.name, ex.explanation))
         return container
 
+    @property
+    def prioritized_networks(self):
+        return OrderedDict(
+            sorted(
+                self.networks.items(),
+                key=lambda t: t[1].get('priority') or 0, reverse=True
+            )
+        )
+
     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
+                self.client.disconnect_container_from_network(container.id, network)
 
-                self.client.disconnect_container_from_network(
-                    container.id,
-                    network)
-
+            log.debug('Connecting to {}'.format(network))
             self.client.connect_container_to_network(
                 container.id, network,
                 aliases=self._get_aliases(netdefs, container),

+ 1 - 1
tests/acceptance/cli_test.py

@@ -1887,7 +1887,7 @@ class CLITestCase(DockerClientTestCase):
         result = self.dispatch(['run', 'simple'])
 
         if six.PY2:  # Can't retrieve output on Py3. See issue #3670
-            assert value == result.stdout.strip()
+            assert value in result.stdout.strip()
 
         container = self.project.containers(one_off=OneOffFilter.only, stopped=True)[0]
         environment = container.get('Config.Env')

+ 65 - 0
tests/integration/project_test.py

@@ -829,6 +829,71 @@ class ProjectTest(DockerClientTestCase):
         assert ipam_config.get('IPv4Address') == '172.16.100.100'
         assert ipam_config.get('IPv6Address') == 'fe80::1001:102'
 
+    @v2_3_only()
+    def test_up_with_network_priorities(self):
+        mac_address = '74:6f:75:68:6f:75'
+
+        def get_config_data(p1, p2, p3):
+            return build_config(
+                version=V2_3,
+                services=[{
+                    'name': 'web',
+                    'image': 'busybox:latest',
+                    'networks': {
+                        'n1': {
+                            'priority': p1,
+                        },
+                        'n2': {
+                            'priority': p2,
+                        },
+                        'n3': {
+                            'priority': p3,
+                        }
+                    },
+                    'command': 'top',
+                    'mac_address': mac_address
+                }],
+                networks={
+                    'n1': {},
+                    'n2': {},
+                    'n3': {}
+                }
+            )
+
+        config1 = get_config_data(1000, 1, 1)
+        config2 = get_config_data(2, 3, 1)
+        config3 = get_config_data(5, 40, 100)
+
+        project = Project.from_config(
+            client=self.client,
+            name='composetest',
+            config_data=config1
+        )
+        project.up(detached=True)
+        service_container = project.get_service('web').containers()[0]
+        net_config = service_container.inspect()['NetworkSettings']['Networks']['composetest_n1']
+        assert net_config['MacAddress'] == mac_address
+
+        project = Project.from_config(
+            client=self.client,
+            name='composetest',
+            config_data=config2
+        )
+        project.up(detached=True)
+        service_container = project.get_service('web').containers()[0]
+        net_config = service_container.inspect()['NetworkSettings']['Networks']['composetest_n2']
+        assert net_config['MacAddress'] == mac_address
+
+        project = Project.from_config(
+            client=self.client,
+            name='composetest',
+            config_data=config3
+        )
+        project.up(detached=True)
+        service_container = project.get_service('web').containers()[0]
+        net_config = service_container.inspect()['NetworkSettings']['Networks']['composetest_n3']
+        assert net_config['MacAddress'] == mac_address
+
     @v2_1_only()
     def test_up_with_enable_ipv6(self):
         self.require_api_version('1.23')