From e011ff5be89f84f999847d73d73ff695b9c8c4d4 Mon Sep 17 00:00:00 2001 From: Mariano Scazzariello Date: Sun, 7 May 2023 12:40:08 +0200 Subject: [PATCH] More sanity checking of EndpointConfig params Signed-off-by: Mariano Scazzariello --- docker/models/containers.py | 29 ++++++-- tests/integration/models_containers_test.py | 57 ++++++++++++++++ tests/unit/models_containers_test.py | 75 +++++++++++++++++++++ 3 files changed, 157 insertions(+), 4 deletions(-) diff --git a/docker/models/containers.py b/docker/models/containers.py index bc2ed011..3312b0e2 100644 --- a/docker/models/containers.py +++ b/docker/models/containers.py @@ -703,6 +703,8 @@ class ContainerCollection(Collection): (IPv4/IPv6) addresses. - ``driver_opt`` (dict): A dictionary of options to provide to the network driver. Defaults to ``None``. + - ``mac_address`` (str): MAC Address to assign to the network + interface. Defaults to ``None``. Requires API >= 1.25. Used in conjuction with ``network``. Incompatible with ``network_mode``. @@ -1122,6 +1124,17 @@ RUN_HOST_CONFIG_KWARGS = [ ] +NETWORKING_CONFIG_ARGS = [ + 'aliases', + 'links', + 'ipv4_address', + 'ipv6_address', + 'link_local_ips', + 'driver_opt', + 'mac_address' +] + + def _create_container_args(kwargs): """ Convert arguments to create() to arguments to create_container(). @@ -1148,10 +1161,18 @@ def _create_container_args(kwargs): network = kwargs.pop('network', None) network_config = kwargs.pop('network_config', None) if network: - endpoint_config = EndpointConfig( - host_config_kwargs['version'], - **network_config - ) if network_config else None + endpoint_config = None + + if network_config: + clean_endpoint_args = {} + for arg_name in NETWORKING_CONFIG_ARGS: + if arg_name in network_config: + clean_endpoint_args[arg_name] = network_config[arg_name] + + if clean_endpoint_args: + endpoint_config = EndpointConfig( + host_config_kwargs['version'], **clean_endpoint_args + ) create_kwargs['networking_config'] = NetworkingConfig( {network: endpoint_config} diff --git a/tests/integration/models_containers_test.py b/tests/integration/models_containers_test.py index eac4c979..050efa01 100644 --- a/tests/integration/models_containers_test.py +++ b/tests/integration/models_containers_test.py @@ -104,6 +104,63 @@ class ContainerCollectionTest(BaseIntegrationTest): assert 'Networks' in attrs['NetworkSettings'] assert list(attrs['NetworkSettings']['Networks'].keys()) == [net_name] + def test_run_with_network_config(self): + net_name = random_name() + client = docker.from_env(version=TEST_API_VERSION) + client.networks.create(net_name) + self.tmp_networks.append(net_name) + + test_aliases = ['hello'] + test_driver_opt = {'key1': 'a'} + + container = client.containers.run( + 'alpine', 'echo hello world', network=net_name, + network_config={'aliases': test_aliases, + 'driver_opt': test_driver_opt}, + detach=True + ) + self.tmp_containers.append(container.id) + + attrs = container.attrs + + assert 'NetworkSettings' in attrs + assert 'Networks' in attrs['NetworkSettings'] + assert list(attrs['NetworkSettings']['Networks'].keys()) == [net_name] + assert attrs['NetworkSettings']['Networks'][net_name]['Aliases'] == \ + test_aliases + assert attrs['NetworkSettings']['Networks'][net_name]['DriverOpts'] \ + == test_driver_opt + + def test_run_with_network_config_undeclared_params(self): + net_name = random_name() + client = docker.from_env(version=TEST_API_VERSION) + client.networks.create(net_name) + self.tmp_networks.append(net_name) + + test_aliases = ['hello'] + test_driver_opt = {'key1': 'a'} + + container = client.containers.run( + 'alpine', 'echo hello world', network=net_name, + network_config={'aliases': test_aliases, + 'driver_opt': test_driver_opt, + 'undeclared_param': 'random_value'}, + detach=True + ) + self.tmp_containers.append(container.id) + + attrs = container.attrs + + assert 'NetworkSettings' in attrs + assert 'Networks' in attrs['NetworkSettings'] + assert list(attrs['NetworkSettings']['Networks'].keys()) == [net_name] + assert attrs['NetworkSettings']['Networks'][net_name]['Aliases'] == \ + test_aliases + assert attrs['NetworkSettings']['Networks'][net_name]['DriverOpts'] \ + == test_driver_opt + assert 'undeclared_param' not in \ + attrs['NetworkSettings']['Networks'][net_name] + def test_run_with_none_driver(self): client = docker.from_env(version=TEST_API_VERSION) diff --git a/tests/unit/models_containers_test.py b/tests/unit/models_containers_test.py index f721bedb..3425ea89 100644 --- a/tests/unit/models_containers_test.py +++ b/tests/unit/models_containers_test.py @@ -390,6 +390,44 @@ class ContainerCollectionTest(unittest.TestCase): host_config={'NetworkMode': 'foo'} ) + def test_run_network_config_undeclared_params(self): + client = make_fake_client() + + client.containers.run( + image='alpine', + network='foo', + network_config={'aliases': ['test'], + 'driver_opt': {'key1': 'a'}, + 'undeclared_param': 'random_value'} + ) + + client.api.create_container.assert_called_with( + detach=False, + image='alpine', + command=None, + networking_config={'EndpointsConfig': { + 'foo': {'Aliases': ['test'], 'DriverOpts': {'key1': 'a'}}} + }, + host_config={'NetworkMode': 'foo'} + ) + + def test_run_network_config_only_undeclared_params(self): + client = make_fake_client() + + client.containers.run( + image='alpine', + network='foo', + network_config={'undeclared_param': 'random_value'} + ) + + client.api.create_container.assert_called_with( + detach=False, + image='alpine', + command=None, + networking_config={'foo': None}, + host_config={'NetworkMode': 'foo'} + ) + def test_create(self): client = make_fake_client() container = client.containers.create( @@ -467,6 +505,43 @@ class ContainerCollectionTest(unittest.TestCase): host_config={'NetworkMode': 'foo'} ) + def test_create_network_config_undeclared_params(self): + client = make_fake_client() + + client.containers.create( + image='alpine', + network='foo', + network_config={'aliases': ['test'], + 'driver_opt': {'key1': 'a'}, + 'undeclared_param': 'random_value'} + ) + + client.api.create_container.assert_called_with( + image='alpine', + command=None, + networking_config={'EndpointsConfig': { + 'foo': {'Aliases': ['test'], 'DriverOpts': {'key1': 'a'}}} + }, + host_config={'NetworkMode': 'foo'} + ) + + def test_create_network_config_only_undeclared_params(self): + client = make_fake_client() + + client.containers.create( + image='alpine', + network='foo', + network_config={'undeclared_param': 'random_value'} + ) + + client.api.create_container.assert_called_with( + image='alpine', + command=None, + networking_config={'foo': None}, + host_config={'NetworkMode': 'foo'} + ) + + def test_get(self): client = make_fake_client() container = client.containers.get(FAKE_CONTAINER_ID)