From 83f35e132b37bf20baec264e49905c3ecc944ace Mon Sep 17 00:00:00 2001 From: Jonathan Giannuzzi Date: Mon, 11 Jul 2016 11:34:01 +0200 Subject: [PATCH] Add support for creating internal networks Signed-off-by: Jonathan Giannuzzi --- compose/config/config_schema_v2.0.json | 3 ++- compose/network.py | 5 +++- docs/compose-file.md | 6 ++++- tests/acceptance/cli_test.py | 18 +++++++++++++ tests/fixtures/networks/network-internal.yml | 13 ++++++++++ tests/integration/project_test.py | 27 ++++++++++++++++++++ tests/unit/config/config_test.py | 8 ++++++ 7 files changed, 77 insertions(+), 3 deletions(-) create mode 100755 tests/fixtures/networks/network-internal.yml diff --git a/compose/config/config_schema_v2.0.json b/compose/config/config_schema_v2.0.json index c08fa4d7a..ac46944cc 100644 --- a/compose/config/config_schema_v2.0.json +++ b/compose/config/config_schema_v2.0.json @@ -246,7 +246,8 @@ "name": {"type": "string"} }, "additionalProperties": false - } + }, + "internal": {"type": "boolean"} }, "additionalProperties": false }, diff --git a/compose/network.py b/compose/network.py index affba7c2d..8962a8920 100644 --- a/compose/network.py +++ b/compose/network.py @@ -15,7 +15,7 @@ log = logging.getLogger(__name__) class Network(object): def __init__(self, client, project, name, driver=None, driver_opts=None, - ipam=None, external_name=None): + ipam=None, external_name=None, internal=False): self.client = client self.project = project self.name = name @@ -23,6 +23,7 @@ class Network(object): self.driver_opts = driver_opts self.ipam = create_ipam_config_from_dict(ipam) self.external_name = external_name + self.internal = internal def ensure(self): if self.external_name: @@ -68,6 +69,7 @@ class Network(object): driver=self.driver, options=self.driver_opts, ipam=self.ipam, + internal=self.internal, ) def remove(self): @@ -115,6 +117,7 @@ def build_networks(name, config_data, client): driver_opts=data.get('driver_opts'), ipam=data.get('ipam'), external_name=data.get('external_name'), + internal=data.get('internal'), ) for network_name, data in network_config.items() } diff --git a/docs/compose-file.md b/docs/compose-file.md index f7b5a931c..59fcf3317 100644 --- a/docs/compose-file.md +++ b/docs/compose-file.md @@ -859,6 +859,10 @@ A full example: host2: 172.28.1.6 host3: 172.28.1.7 +### internal + +By default, Docker also connects a bridge network to it to provide external connectivity. If you want to create an externally isolated overlay network, you can set this option to `true`. + ### external If set to `true`, specifies that this network has been created outside of @@ -866,7 +870,7 @@ Compose. `docker-compose up` will not attempt to create it, and will raise an error if it doesn't exist. `external` cannot be used in conjunction with other network configuration keys -(`driver`, `driver_opts`, `ipam`). +(`driver`, `driver_opts`, `ipam`, `internal`). In the example below, `proxy` is the gateway to the outside world. Instead of attemping to create a network called `[projectname]_outside`, Compose will diff --git a/tests/acceptance/cli_test.py b/tests/acceptance/cli_test.py index a8fd3249d..dad23bec5 100644 --- a/tests/acceptance/cli_test.py +++ b/tests/acceptance/cli_test.py @@ -576,6 +576,24 @@ class CLITestCase(DockerClientTestCase): assert 'forward_facing' in front_aliases assert 'ahead' in front_aliases + @v2_only() + def test_up_with_network_internal(self): + self.require_api_version('1.23') + filename = 'network-internal.yml' + self.base_dir = 'tests/fixtures/networks' + self.dispatch(['-f', filename, 'up', '-d'], None) + internal_net = '{}_internal'.format(self.project.name) + + networks = [ + n for n in self.client.networks() + if n['Name'].startswith('{}_'.format(self.project.name)) + ] + + # One network was created: internal + assert sorted(n['Name'] for n in networks) == [internal_net] + + assert networks[0]['Internal'] is True + @v2_only() def test_up_with_network_static_addresses(self): filename = 'network-static-addresses.yml' diff --git a/tests/fixtures/networks/network-internal.yml b/tests/fixtures/networks/network-internal.yml new file mode 100755 index 000000000..1fa339b1f --- /dev/null +++ b/tests/fixtures/networks/network-internal.yml @@ -0,0 +1,13 @@ +version: "2" + +services: + web: + image: busybox + command: top + networks: + - internal + +networks: + internal: + driver: bridge + internal: True diff --git a/tests/integration/project_test.py b/tests/integration/project_test.py index 6e82e931f..80915c1ae 100644 --- a/tests/integration/project_test.py +++ b/tests/integration/project_test.py @@ -756,6 +756,33 @@ class ProjectTest(DockerClientTestCase): with self.assertRaises(ProjectError): project.up() + @v2_only() + def test_project_up_with_network_internal(self): + self.require_api_version('1.23') + config_data = config.Config( + version=V2_0, + services=[{ + 'name': 'web', + 'image': 'busybox:latest', + 'networks': {'internal': None}, + }], + volumes={}, + networks={ + 'internal': {'driver': 'bridge', 'internal': True}, + }, + ) + + project = Project.from_config( + client=self.client, + name='composetest', + config_data=config_data, + ) + project.up() + + network = self.client.networks(names=['composetest_internal'])[0] + + assert network['Internal'] is True + @v2_only() def test_project_up_volumes(self): vol_name = '{0:x}'.format(random.getrandbits(32)) diff --git a/tests/unit/config/config_test.py b/tests/unit/config/config_test.py index 1be8aefa2..d88c1d47e 100644 --- a/tests/unit/config/config_test.py +++ b/tests/unit/config/config_test.py @@ -101,6 +101,10 @@ class ConfigTest(unittest.TestCase): {'subnet': '172.28.0.0/16'} ] } + }, + 'internal': { + 'driver': 'bridge', + 'internal': True } } }, 'working_dir', 'filename.yml') @@ -140,6 +144,10 @@ class ConfigTest(unittest.TestCase): {'subnet': '172.28.0.0/16'} ] } + }, + 'internal': { + 'driver': 'bridge', + 'internal': True } })