Replace `network_config` with a dict of EndpointConfig

- Renamed parameter from `network_config` to `networking_config` to be more semantically correct with the rest of the API.
This commit is contained in:
Mariano Scazzariello 2023-09-30 00:20:44 +02:00
parent 0318ad8e7e
commit 7752996f78
No known key found for this signature in database
GPG Key ID: 95C376C0221294BF
3 changed files with 159 additions and 107 deletions

View File

@ -2,16 +2,16 @@ import copy
import ntpath
from collections import namedtuple
from .images import Image
from .resource import Collection, Model
from ..api import APIClient
from ..constants import DEFAULT_DATA_CHUNK_SIZE
from ..errors import (
ContainerError, DockerException, ImageNotFound,
NotFound, create_unexpected_kwargs_error
)
from ..types import EndpointConfig, HostConfig, NetworkingConfig
from ..types import HostConfig, NetworkingConfig
from ..utils import version_gte
from .images import Image
from .resource import Collection, Model
class Container(Model):
@ -21,6 +21,7 @@ class Container(Model):
query the Docker daemon for the current properties, causing
:py:attr:`attrs` to be refreshed.
"""
@property
def name(self):
"""
@ -680,33 +681,13 @@ class ContainerCollection(Collection):
This mode is incompatible with ``ports``.
Incompatible with ``network``.
network_config (dict): A dictionary containing options that are
passed to the network driver during the connection.
networking_config (Dict[str, EndpointConfig]):
Dictionary of EndpointConfig objects for each container network.
The key is the name of the network.
Defaults to ``None``.
The dictionary contains the following keys:
- ``aliases`` (:py:class:`list`): A list of aliases for
the network endpoint.
Names in that list can be used within the network to
reach this container. Defaults to ``None``.
- ``links`` (:py:class:`list`): A list of links for
the network endpoint endpoint.
Containers declared in this list will be linked to this
container. Defaults to ``None``.
- ``ipv4_address`` (str): The IP address to assign to
this container on the network, using the IPv4 protocol.
Defaults to ``None``.
- ``ipv6_address`` (str): The IP address to assign to
this container on the network, using the IPv6 protocol.
Defaults to ``None``.
- ``link_local_ips`` (:py:class:`list`): A list of link-local
(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``.
oom_kill_disable (bool): Whether to disable OOM killer.
oom_score_adj (int): An integer value containing the score given
@ -872,9 +853,9 @@ class ContainerCollection(Collection):
'together.'
)
if kwargs.get('network_config') and not kwargs.get('network'):
if kwargs.get('networking_config') and not kwargs.get('network'):
raise RuntimeError(
'The option "network_config" can not be used '
'The option "networking_config" can not be used '
'without "network".'
)
@ -1030,6 +1011,7 @@ class ContainerCollection(Collection):
def prune(self, filters=None):
return self.client.api.prune_containers(filters=filters)
prune.__doc__ = APIClient.prune_containers.__doc__
@ -1124,17 +1106,6 @@ 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().
@ -1159,24 +1130,17 @@ def _create_container_args(kwargs):
host_config_kwargs['binds'] = volumes
network = kwargs.pop('network', None)
network_config = kwargs.pop('network_config', None)
networking_config = kwargs.pop('networking_config', None)
if network:
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
)
if networking_config:
# Sanity check: check if the network is defined in the
# networking config dict, otherwise switch to None
if network not in networking_config:
networking_config = None
create_kwargs['networking_config'] = NetworkingConfig(
{network: endpoint_config}
) if endpoint_config else {network: None}
networking_config
) if networking_config else {network: None}
host_config_kwargs['network_mode'] = network
# All kwargs should have been consumed by this point, so raise

View File

@ -5,10 +5,10 @@ import threading
import pytest
import docker
from ..helpers import random_name
from ..helpers import requires_api_version
from .base import BaseIntegrationTest
from .base import TEST_API_VERSION
from ..helpers import random_name
from ..helpers import requires_api_version
class ContainerCollectionTest(BaseIntegrationTest):
@ -104,7 +104,7 @@ class ContainerCollectionTest(BaseIntegrationTest):
assert 'Networks' in attrs['NetworkSettings']
assert list(attrs['NetworkSettings']['Networks'].keys()) == [net_name]
def test_run_with_network_config(self):
def test_run_with_networking_config(self):
net_name = random_name()
client = docker.from_env(version=TEST_API_VERSION)
client.networks.create(net_name)
@ -113,10 +113,16 @@ class ContainerCollectionTest(BaseIntegrationTest):
test_aliases = ['hello']
test_driver_opt = {'key1': 'a'}
networking_config = {
net_name: client.api.create_endpoint_config(
aliases=test_aliases,
driver_opt=test_driver_opt
)
}
container = client.containers.run(
'alpine', 'echo hello world', network=net_name,
network_config={'aliases': test_aliases,
'driver_opt': test_driver_opt},
networking_config=networking_config,
detach=True
)
self.tmp_containers.append(container.id)
@ -131,7 +137,7 @@ class ContainerCollectionTest(BaseIntegrationTest):
assert attrs['NetworkSettings']['Networks'][net_name]['DriverOpts'] \
== test_driver_opt
def test_run_with_network_config_undeclared_params(self):
def test_run_with_networking_config_with_undeclared_network(self):
net_name = random_name()
client = docker.from_env(version=TEST_API_VERSION)
client.networks.create(net_name)
@ -140,11 +146,41 @@ class ContainerCollectionTest(BaseIntegrationTest):
test_aliases = ['hello']
test_driver_opt = {'key1': 'a'}
networking_config = {
net_name: client.api.create_endpoint_config(
aliases=test_aliases,
driver_opt=test_driver_opt
),
'bar': client.api.create_endpoint_config(
aliases=['test'],
driver_opt={'key2': 'b'}
),
}
with pytest.raises(docker.errors.APIError) as e:
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'},
networking_config=networking_config,
detach=True
)
self.tmp_containers.append(container.id)
def test_run_with_networking_config_only_undeclared_network(self):
net_name = random_name()
client = docker.from_env(version=TEST_API_VERSION)
client.networks.create(net_name)
self.tmp_networks.append(net_name)
networking_config = {
'bar': client.api.create_endpoint_config(
aliases=['hello'],
driver_opt={'key1': 'a'}
),
}
container = client.containers.run(
'alpine', 'echo hello world', network=net_name,
networking_config=networking_config,
detach=True
)
self.tmp_containers.append(container.id)
@ -154,12 +190,9 @@ class ContainerCollectionTest(BaseIntegrationTest):
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]
assert attrs['NetworkSettings']['Networks'][net_name]['Aliases'] is None
assert (attrs['NetworkSettings']['Networks'][net_name]['DriverOpts']
is None)
def test_run_with_none_driver(self):
client = docker.from_env(version=TEST_API_VERSION)

View File

@ -1,11 +1,13 @@
import pytest
import unittest
import pytest
import docker
from docker.constants import DEFAULT_DATA_CHUNK_SIZE, \
DEFAULT_DOCKER_API_VERSION
from docker.models.containers import Container, _create_container_args
from docker.models.images import Image
from docker.types import EndpointConfig
from .fake_api import FAKE_CONTAINER_ID, FAKE_IMAGE_ID, FAKE_EXEC_ID
from .fake_api_client import make_fake_client
@ -32,6 +34,13 @@ class ContainerCollectionTest(unittest.TestCase):
)
def test_create_container_args(self):
networking_config = {
'foo': EndpointConfig(
DEFAULT_DOCKER_API_VERSION, aliases=['test'],
driver_opt={'key1': 'a'}
)
}
create_kwargs = _create_container_args(dict(
image='alpine',
command='echo hello world',
@ -75,7 +84,7 @@ class ContainerCollectionTest(unittest.TestCase):
name='somename',
network_disabled=False,
network='foo',
network_config={'aliases': ['test'], 'driver_opt': {'key1': 'a'}},
networking_config=networking_config,
oom_kill_disable=True,
oom_score_adj=5,
pid_mode='host',
@ -349,35 +358,41 @@ class ContainerCollectionTest(unittest.TestCase):
host_config={'NetworkMode': 'default'},
)
def test_run_network_config_without_network(self):
def test_run_networking_config_without_network(self):
client = make_fake_client()
with pytest.raises(RuntimeError):
client.containers.run(
image='alpine',
network_config={'aliases': ['test'],
networking_config={'aliases': ['test'],
'driver_opt': {'key1': 'a'}}
)
def test_run_network_config_with_network_mode(self):
def test_run_networking_config_with_network_mode(self):
client = make_fake_client()
with pytest.raises(RuntimeError):
client.containers.run(
image='alpine',
network_mode='none',
network_config={'aliases': ['test'],
networking_config={'aliases': ['test'],
'driver_opt': {'key1': 'a'}}
)
def test_run_network_config(self):
def test_run_networking_config(self):
client = make_fake_client()
networking_config = {
'foo': EndpointConfig(
DEFAULT_DOCKER_API_VERSION, aliases=['test'],
driver_opt={'key1': 'a'}
)
}
client.containers.run(
image='alpine',
network='foo',
network_config={'aliases': ['test'],
'driver_opt': {'key1': 'a'}}
networking_config=networking_config
)
client.api.create_container.assert_called_with(
@ -390,15 +405,24 @@ class ContainerCollectionTest(unittest.TestCase):
host_config={'NetworkMode': 'foo'}
)
def test_run_network_config_undeclared_params(self):
def test_run_networking_config_with_undeclared_network(self):
client = make_fake_client()
networking_config = {
'foo': EndpointConfig(
DEFAULT_DOCKER_API_VERSION, aliases=['test_foo'],
driver_opt={'key2': 'b'}
),
'bar': EndpointConfig(
DEFAULT_DOCKER_API_VERSION, aliases=['test'],
driver_opt={'key1': 'a'}
)
}
client.containers.run(
image='alpine',
network='foo',
network_config={'aliases': ['test'],
'driver_opt': {'key1': 'a'},
'undeclared_param': 'random_value'}
networking_config=networking_config
)
client.api.create_container.assert_called_with(
@ -406,18 +430,26 @@ class ContainerCollectionTest(unittest.TestCase):
image='alpine',
command=None,
networking_config={'EndpointsConfig': {
'foo': {'Aliases': ['test'], 'DriverOpts': {'key1': 'a'}}}
},
'foo': {'Aliases': ['test_foo'], 'DriverOpts': {'key2': 'b'}},
'bar': {'Aliases': ['test'], 'DriverOpts': {'key1': 'a'}},
}},
host_config={'NetworkMode': 'foo'}
)
def test_run_network_config_only_undeclared_params(self):
def test_run_networking_config_only_undeclared_network(self):
client = make_fake_client()
networking_config = {
'bar': EndpointConfig(
DEFAULT_DOCKER_API_VERSION, aliases=['test'],
driver_opt={'key1': 'a'}
)
}
client.containers.run(
image='alpine',
network='foo',
network_config={'undeclared_param': 'random_value'}
networking_config=networking_config
)
client.api.create_container.assert_called_with(
@ -455,12 +487,12 @@ class ContainerCollectionTest(unittest.TestCase):
host_config={'NetworkMode': 'default'}
)
def test_create_network_config_without_network(self):
def test_create_networking_config_without_network(self):
client = make_fake_client()
client.containers.create(
image='alpine',
network_config={'aliases': ['test'],
networking_config={'aliases': ['test'],
'driver_opt': {'key1': 'a'}}
)
@ -470,13 +502,13 @@ class ContainerCollectionTest(unittest.TestCase):
host_config={'NetworkMode': 'default'}
)
def test_create_network_config_with_network_mode(self):
def test_create_networking_config_with_network_mode(self):
client = make_fake_client()
client.containers.create(
image='alpine',
network_mode='none',
network_config={'aliases': ['test'],
networking_config={'aliases': ['test'],
'driver_opt': {'key1': 'a'}}
)
@ -486,14 +518,20 @@ class ContainerCollectionTest(unittest.TestCase):
host_config={'NetworkMode': 'none'}
)
def test_create_network_config(self):
def test_create_networking_config(self):
client = make_fake_client()
networking_config = {
'foo': EndpointConfig(
DEFAULT_DOCKER_API_VERSION, aliases=['test'],
driver_opt={'key1': 'a'}
)
}
client.containers.create(
image='alpine',
network='foo',
network_config={'aliases': ['test'],
'driver_opt': {'key1': 'a'}}
networking_config=networking_config
)
client.api.create_container.assert_called_with(
@ -505,33 +543,50 @@ class ContainerCollectionTest(unittest.TestCase):
host_config={'NetworkMode': 'foo'}
)
def test_create_network_config_undeclared_params(self):
def test_create_networking_config_with_undeclared_network(self):
client = make_fake_client()
networking_config = {
'foo': EndpointConfig(
DEFAULT_DOCKER_API_VERSION, aliases=['test_foo'],
driver_opt={'key2': 'b'}
),
'bar': EndpointConfig(
DEFAULT_DOCKER_API_VERSION, aliases=['test'],
driver_opt={'key1': 'a'}
)
}
client.containers.create(
image='alpine',
network='foo',
network_config={'aliases': ['test'],
'driver_opt': {'key1': 'a'},
'undeclared_param': 'random_value'}
networking_config=networking_config
)
client.api.create_container.assert_called_with(
image='alpine',
command=None,
networking_config={'EndpointsConfig': {
'foo': {'Aliases': ['test'], 'DriverOpts': {'key1': 'a'}}}
},
'foo': {'Aliases': ['test_foo'], 'DriverOpts': {'key2': 'b'}},
'bar': {'Aliases': ['test'], 'DriverOpts': {'key1': 'a'}},
}},
host_config={'NetworkMode': 'foo'}
)
def test_create_network_config_only_undeclared_params(self):
def test_create_networking_config_only_undeclared_network(self):
client = make_fake_client()
networking_config = {
'bar': EndpointConfig(
DEFAULT_DOCKER_API_VERSION, aliases=['test'],
driver_opt={'key1': 'a'}
)
}
client.containers.create(
image='alpine',
network='foo',
network_config={'undeclared_param': 'random_value'}
networking_config=networking_config
)
client.api.create_container.assert_called_with(