Merge branch 'main' into patch-1

This commit is contained in:
Milas Bowman 2023-11-20 16:15:52 -05:00 committed by GitHub
commit 911f866f72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 397 additions and 136 deletions

View File

@ -5,7 +5,6 @@ from functools import partial
import requests import requests
import requests.exceptions import requests.exceptions
import websocket
from .. import auth from .. import auth
from ..constants import (DEFAULT_NUM_POOLS, DEFAULT_NUM_POOLS_SSH, from ..constants import (DEFAULT_NUM_POOLS, DEFAULT_NUM_POOLS_SSH,
@ -309,7 +308,16 @@ class APIClient(
return self._create_websocket_connection(full_url) return self._create_websocket_connection(full_url)
def _create_websocket_connection(self, url): def _create_websocket_connection(self, url):
return websocket.create_connection(url) try:
import websocket
return websocket.create_connection(url)
except ImportError as ie:
raise DockerException(
'The `websocket-client` library is required '
'for using websocket connections. '
'You can install the `docker` library '
'with the [websocket] extra to install it.'
) from ie
def _get_raw_response_socket(self, response): def _get_raw_response_socket(self, response):
self._raise_for_status(response) self._raise_for_status(response)

View File

@ -2,16 +2,16 @@ import copy
import ntpath import ntpath
from collections import namedtuple from collections import namedtuple
from .images import Image
from .resource import Collection, Model
from ..api import APIClient from ..api import APIClient
from ..constants import DEFAULT_DATA_CHUNK_SIZE from ..constants import DEFAULT_DATA_CHUNK_SIZE
from ..errors import ( from ..errors import (
ContainerError, DockerException, ImageNotFound, ContainerError, DockerException, ImageNotFound,
NotFound, create_unexpected_kwargs_error NotFound, create_unexpected_kwargs_error
) )
from ..types import HostConfig from ..types import HostConfig, NetworkingConfig
from ..utils import version_gte from ..utils import version_gte
from .images import Image
from .resource import Collection, Model
class Container(Model): class Container(Model):
@ -21,6 +21,7 @@ class Container(Model):
query the Docker daemon for the current properties, causing query the Docker daemon for the current properties, causing
:py:attr:`attrs` to be refreshed. :py:attr:`attrs` to be refreshed.
""" """
@property @property
def name(self): def name(self):
""" """
@ -688,10 +689,14 @@ class ContainerCollection(Collection):
This mode is incompatible with ``ports``. This mode is incompatible with ``ports``.
Incompatible with ``network``. Incompatible with ``network``.
network_driver_opt (dict): A dictionary of options to provide networking_config (Dict[str, EndpointConfig]):
to the network driver. Defaults to ``None``. Used in Dictionary of EndpointConfig objects for each container network.
conjuction with ``network``. Incompatible The key is the name of the network.
with ``network_mode``. Defaults to ``None``.
Used in conjuction with ``network``.
Incompatible with ``network_mode``.
oom_kill_disable (bool): Whether to disable OOM killer. oom_kill_disable (bool): Whether to disable OOM killer.
oom_score_adj (int): An integer value containing the score given oom_score_adj (int): An integer value containing the score given
to the container in order to tune OOM killer preferences. to the container in order to tune OOM killer preferences.
@ -856,9 +861,9 @@ class ContainerCollection(Collection):
'together.' 'together.'
) )
if kwargs.get('network_driver_opt') and not kwargs.get('network'): if kwargs.get('networking_config') and not kwargs.get('network'):
raise RuntimeError( raise RuntimeError(
'The options "network_driver_opt" can not be used ' 'The option "networking_config" can not be used '
'without "network".' 'without "network".'
) )
@ -1014,6 +1019,7 @@ class ContainerCollection(Collection):
def prune(self, filters=None): def prune(self, filters=None):
return self.client.api.prune_containers(filters=filters) return self.client.api.prune_containers(filters=filters)
prune.__doc__ = APIClient.prune_containers.__doc__ prune.__doc__ = APIClient.prune_containers.__doc__
@ -1132,12 +1138,17 @@ def _create_container_args(kwargs):
host_config_kwargs['binds'] = volumes host_config_kwargs['binds'] = volumes
network = kwargs.pop('network', None) network = kwargs.pop('network', None)
network_driver_opt = kwargs.pop('network_driver_opt', None) networking_config = kwargs.pop('networking_config', None)
if network: if network:
network_configuration = {'driver_opt': network_driver_opt} \ if networking_config:
if network_driver_opt else None # 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'] = {network: network_configuration} create_kwargs['networking_config'] = NetworkingConfig(
networking_config
) if networking_config else {network: None}
host_config_kwargs['network_mode'] = network host_config_kwargs['network_mode'] = network
# All kwargs should have been consumed by this point, so raise # All kwargs should have been consumed by this point, so raise

View File

@ -13,7 +13,6 @@ requirements = [
'packaging >= 14.0', 'packaging >= 14.0',
'requests >= 2.26.0', 'requests >= 2.26.0',
'urllib3 >= 1.26.0', 'urllib3 >= 1.26.0',
'websocket-client >= 0.32.0',
] ]
extras_require = { extras_require = {
@ -27,6 +26,9 @@ extras_require = {
# Only required when connecting using the ssh:// protocol # Only required when connecting using the ssh:// protocol
'ssh': ['paramiko>=2.4.3'], 'ssh': ['paramiko>=2.4.3'],
# Only required when using websockets
'websockets': ['websocket-client >= 1.3.0'],
} }
with open('./test-requirements.txt') as test_reqs_txt: with open('./test-requirements.txt') as test_reqs_txt:

View File

@ -5,10 +5,10 @@ import threading
import pytest import pytest
import docker import docker
from ..helpers import random_name
from ..helpers import requires_api_version
from .base import BaseIntegrationTest from .base import BaseIntegrationTest
from .base import TEST_API_VERSION from .base import TEST_API_VERSION
from ..helpers import random_name
from ..helpers import requires_api_version
class ContainerCollectionTest(BaseIntegrationTest): class ContainerCollectionTest(BaseIntegrationTest):
@ -104,6 +104,96 @@ class ContainerCollectionTest(BaseIntegrationTest):
assert 'Networks' in attrs['NetworkSettings'] assert 'Networks' in attrs['NetworkSettings']
assert list(attrs['NetworkSettings']['Networks'].keys()) == [net_name] assert list(attrs['NetworkSettings']['Networks'].keys()) == [net_name]
def test_run_with_networking_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'}
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,
networking_config=networking_config,
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_networking_config_with_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)
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):
container = client.containers.run(
'alpine', 'echo hello world', network=net_name,
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)
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'] is None
assert (attrs['NetworkSettings']['Networks'][net_name]['DriverOpts']
is None)
def test_run_with_none_driver(self): def test_run_with_none_driver(self):
client = docker.from_env(version=TEST_API_VERSION) client = docker.from_env(version=TEST_API_VERSION)
@ -187,7 +277,7 @@ class ContainerCollectionTest(BaseIntegrationTest):
container = client.containers.run("alpine", "sleep 300", detach=True) container = client.containers.run("alpine", "sleep 300", detach=True)
self.tmp_containers.append(container.id) self.tmp_containers.append(container.id)
assert client.containers.get(container.id).attrs[ assert client.containers.get(container.id).attrs[
'Config']['Image'] == "alpine" 'Config']['Image'] == "alpine"
def test_list(self): def test_list(self):
client = docker.from_env(version=TEST_API_VERSION) client = docker.from_env(version=TEST_API_VERSION)

View File

@ -1,12 +1,15 @@
import docker
from docker.constants import DEFAULT_DATA_CHUNK_SIZE
from docker.models.containers import Container, _create_container_args
from docker.models.images import Image
import unittest 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 import FAKE_CONTAINER_ID, FAKE_IMAGE_ID, FAKE_EXEC_ID
from .fake_api_client import make_fake_client from .fake_api_client import make_fake_client
import pytest
class ContainerCollectionTest(unittest.TestCase): class ContainerCollectionTest(unittest.TestCase):
@ -31,77 +34,80 @@ class ContainerCollectionTest(unittest.TestCase):
) )
def test_create_container_args(self): 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({ create_kwargs = _create_container_args({
"image": 'alpine', 'image': 'alpine',
"command": 'echo hello world', 'command': 'echo hello world',
"blkio_weight_device": [{'Path': 'foo', 'Weight': 3}], 'blkio_weight_device': [{'Path': 'foo', 'Weight': 3}],
"blkio_weight": 2, 'blkio_weight': 2,
"cap_add": ['foo'], 'cap_add': ['foo'],
"cap_drop": ['bar'], 'cap_drop': ['bar'],
"cgroup_parent": 'foobar', 'cgroup_parent': 'foobar',
"cgroupns": 'host', 'cgroupns': 'host',
"cpu_period": 1, 'cpu_period': 1,
"cpu_quota": 2, 'cpu_quota': 2,
"cpu_shares": 5, 'cpu_shares': 5,
"cpuset_cpus": '0-3', 'cpuset_cpus': '0-3',
"detach": False, 'detach': False,
"device_read_bps": [{'Path': 'foo', 'Rate': 3}], 'device_read_bps': [{'Path': 'foo', 'Rate': 3}],
"device_read_iops": [{'Path': 'foo', 'Rate': 3}], 'device_read_iops': [{'Path': 'foo', 'Rate': 3}],
"device_write_bps": [{'Path': 'foo', 'Rate': 3}], 'device_write_bps': [{'Path': 'foo', 'Rate': 3}],
"device_write_iops": [{'Path': 'foo', 'Rate': 3}], 'device_write_iops': [{'Path': 'foo', 'Rate': 3}],
"devices": ['/dev/sda:/dev/xvda:rwm'], 'devices': ['/dev/sda:/dev/xvda:rwm'],
"dns": ['8.8.8.8'], 'dns': ['8.8.8.8'],
"domainname": 'example.com', 'domainname': 'example.com',
"dns_opt": ['foo'], 'dns_opt': ['foo'],
"dns_search": ['example.com'], 'dns_search': ['example.com'],
"entrypoint": '/bin/sh', 'entrypoint': '/bin/sh',
"environment": {'FOO': 'BAR'}, 'environment': {'FOO': 'BAR'},
"extra_hosts": {'foo': '1.2.3.4'}, 'extra_hosts': {'foo': '1.2.3.4'},
"group_add": ['blah'], 'group_add': ['blah'],
"ipc_mode": 'foo', 'ipc_mode': 'foo',
"kernel_memory": 123, 'kernel_memory': 123,
"labels": {'key': 'value'}, 'labels': {'key': 'value'},
"links": {'foo': 'bar'}, 'links': {'foo': 'bar'},
"log_config": {'Type': 'json-file', 'Config': {}}, 'log_config': {'Type': 'json-file', 'Config': {}},
"lxc_conf": {'foo': 'bar'}, 'lxc_conf': {'foo': 'bar'},
"healthcheck": {'test': 'true'}, 'healthcheck': {'test': 'true'},
"hostname": 'somehost', 'hostname': 'somehost',
"mac_address": 'abc123', 'mac_address': 'abc123',
"mem_limit": 123, 'mem_limit': 123,
"mem_reservation": 123, 'mem_reservation': 123,
"mem_swappiness": 2, 'mem_swappiness': 2,
"memswap_limit": 456, 'memswap_limit': 456,
"name": 'somename', 'name': 'somename',
"network_disabled": False, 'network_disabled': False,
"network": 'foo', 'network': 'foo',
"network_driver_opt": {'key1': 'a'}, 'networking_config': networking_config,
"oom_kill_disable": True, 'oom_kill_disable': True,
"oom_score_adj": 5, 'oom_score_adj': 5,
"pid_mode": 'host', 'pid_mode': 'host',
"pids_limit": 500, 'pids_limit': 500,
"platform": 'linux', 'platform': 'linux',
"ports": { 'ports': {1111: 4567, 2222: None},
1111: 4567, 'privileged': True,
2222: None 'publish_all_ports': True,
}, 'read_only': True,
"privileged": True, 'restart_policy': {'Name': 'always'},
"publish_all_ports": True, 'security_opt': ['blah'],
"read_only": True, 'shm_size': 123,
"restart_policy": {'Name': 'always'}, 'stdin_open': True,
"security_opt": ['blah'], 'stop_signal': 9,
"shm_size": 123, 'sysctls': {'foo': 'bar'},
"stdin_open": True, 'tmpfs': {'/blah': ''},
"stop_signal": 9, 'tty': True,
"sysctls": {'foo': 'bar'}, 'ulimits': [{"Name": "nofile", "Soft": 1024, "Hard": 2048}],
"tmpfs": {'/blah': ''}, 'user': 'bob',
"tty": True, 'userns_mode': 'host',
"ulimits": [{"Name": "nofile", "Soft": 1024, "Hard": 2048}], 'uts_mode': 'host',
"user": 'bob', 'version': DEFAULT_DOCKER_API_VERSION,
"userns_mode": 'host', 'volume_driver': 'some_driver', 'volumes': [
"uts_mode": 'host',
"version": '1.23',
"volume_driver": 'some_driver',
"volumes": [
'/home/user1/:/mnt/vol2', '/home/user1/:/mnt/vol2',
'/var/www:/mnt/vol1:ro', '/var/www:/mnt/vol1:ro',
'volumename:/mnt/vol3r', 'volumename:/mnt/vol3r',
@ -109,18 +115,18 @@ class ContainerCollectionTest(unittest.TestCase):
'/anothervolumewithnohostpath:ro', '/anothervolumewithnohostpath:ro',
'C:\\windows\\path:D:\\hello\\world:rw' 'C:\\windows\\path:D:\\hello\\world:rw'
], ],
"volumes_from": ['container'], 'volumes_from': ['container'],
"working_dir": '/code' 'working_dir': '/code',
}) })
expected = { expected = {
"image": 'alpine', 'image': 'alpine',
"command": 'echo hello world', 'command': 'echo hello world',
"domainname": 'example.com', 'domainname': 'example.com',
"detach": False, 'detach': False,
"entrypoint": '/bin/sh', 'entrypoint': '/bin/sh',
"environment": {'FOO': 'BAR'}, 'environment': {'FOO': 'BAR'},
"host_config": { 'host_config': {
'Binds': [ 'Binds': [
'/home/user1/:/mnt/vol2', '/home/user1/:/mnt/vol2',
'/var/www:/mnt/vol1:ro', '/var/www:/mnt/vol1:ro',
@ -143,9 +149,13 @@ class ContainerCollectionTest(unittest.TestCase):
'CpuQuota': 2, 'CpuQuota': 2,
'CpuShares': 5, 'CpuShares': 5,
'CpusetCpus': '0-3', 'CpusetCpus': '0-3',
'Devices': [{'PathOnHost': '/dev/sda', 'Devices': [
'CgroupPermissions': 'rwm', {
'PathInContainer': '/dev/xvda'}], 'PathOnHost': '/dev/sda',
'CgroupPermissions': 'rwm',
'PathInContainer': '/dev/xvda',
},
],
'Dns': ['8.8.8.8'], 'Dns': ['8.8.8.8'],
'DnsOptions': ['foo'], 'DnsOptions': ['foo'],
'DnsSearch': ['example.com'], 'DnsSearch': ['example.com'],
@ -177,26 +187,35 @@ class ContainerCollectionTest(unittest.TestCase):
'ShmSize': 123, 'ShmSize': 123,
'Sysctls': {'foo': 'bar'}, 'Sysctls': {'foo': 'bar'},
'Tmpfs': {'/blah': ''}, 'Tmpfs': {'/blah': ''},
'Ulimits': [{"Name": "nofile", "Soft": 1024, "Hard": 2048}], 'Ulimits': [
{"Name": "nofile", "Soft": 1024, "Hard": 2048},
],
'UsernsMode': 'host', 'UsernsMode': 'host',
'UTSMode': 'host', 'UTSMode': 'host',
'VolumeDriver': 'some_driver', 'VolumeDriver': 'some_driver',
'VolumesFrom': ['container'], 'VolumesFrom': ['container'],
}, },
"healthcheck": {'test': 'true'}, 'healthcheck': {'test': 'true'},
"hostname": 'somehost', 'hostname': 'somehost',
"labels": {'key': 'value'}, 'labels': {'key': 'value'},
"mac_address": 'abc123', 'mac_address': 'abc123',
"name": 'somename', 'name': 'somename',
"network_disabled": False, 'network_disabled': False,
"networking_config": {'foo': {'driver_opt': {'key1': 'a'}}}, 'networking_config': {
"platform": 'linux', 'EndpointsConfig': {
"ports": [('1111', 'tcp'), ('2222', 'tcp')], 'foo': {
"stdin_open": True, 'Aliases': ['test'],
"stop_signal": 9, 'DriverOpts': {'key1': 'a'},
"tty": True, },
"user": 'bob', }
"volumes": [ },
'platform': 'linux',
'ports': [('1111', 'tcp'), ('2222', 'tcp')],
'stdin_open': True,
'stop_signal': 9,
'tty': True,
'user': 'bob',
'volumes': [
'/mnt/vol2', '/mnt/vol2',
'/mnt/vol1', '/mnt/vol1',
'/mnt/vol3r', '/mnt/vol3r',
@ -204,7 +223,7 @@ class ContainerCollectionTest(unittest.TestCase):
'/anothervolumewithnohostpath', '/anothervolumewithnohostpath',
'D:\\hello\\world' 'D:\\hello\\world'
], ],
"working_dir": '/code' 'working_dir': '/code',
} }
assert create_kwargs == expected assert create_kwargs == expected
@ -346,39 +365,105 @@ class ContainerCollectionTest(unittest.TestCase):
host_config={'NetworkMode': 'default'}, host_config={'NetworkMode': 'default'},
) )
def test_run_network_driver_opts_without_network(self): def test_run_networking_config_without_network(self):
client = make_fake_client() client = make_fake_client()
with pytest.raises(RuntimeError): with pytest.raises(RuntimeError):
client.containers.run( client.containers.run(
image='alpine', image='alpine',
network_driver_opt={'key1': 'a'} networking_config={'aliases': ['test'],
'driver_opt': {'key1': 'a'}}
) )
def test_run_network_driver_opts_with_network_mode(self): def test_run_networking_config_with_network_mode(self):
client = make_fake_client() client = make_fake_client()
with pytest.raises(RuntimeError): with pytest.raises(RuntimeError):
client.containers.run( client.containers.run(
image='alpine', image='alpine',
network_mode='none', network_mode='none',
network_driver_opt={'key1': 'a'} networking_config={'aliases': ['test'],
'driver_opt': {'key1': 'a'}}
) )
def test_run_network_driver_opts(self): def test_run_networking_config(self):
client = make_fake_client() client = make_fake_client()
networking_config = {
'foo': EndpointConfig(
DEFAULT_DOCKER_API_VERSION, aliases=['test'],
driver_opt={'key1': 'a'}
)
}
client.containers.run( client.containers.run(
image='alpine', image='alpine',
network='foo', network='foo',
network_driver_opt={'key1': 'a'} networking_config=networking_config
) )
client.api.create_container.assert_called_with( client.api.create_container.assert_called_with(
detach=False, detach=False,
image='alpine', image='alpine',
command=None, command=None,
networking_config={'foo': {'driver_opt': {'key1': 'a'}}}, networking_config={'EndpointsConfig': {
'foo': {'Aliases': ['test'], 'DriverOpts': {'key1': 'a'}}}
},
host_config={'NetworkMode': 'foo'}
)
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',
networking_config=networking_config
)
client.api.create_container.assert_called_with(
detach=False,
image='alpine',
command=None,
networking_config={'EndpointsConfig': {
'foo': {'Aliases': ['test_foo'], 'DriverOpts': {'key2': 'b'}},
'bar': {'Aliases': ['test'], 'DriverOpts': {'key1': 'a'}},
}},
host_config={'NetworkMode': 'foo'}
)
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',
networking_config=networking_config
)
client.api.create_container.assert_called_with(
detach=False,
image='alpine',
command=None,
networking_config={'foo': None},
host_config={'NetworkMode': 'foo'} host_config={'NetworkMode': 'foo'}
) )
@ -409,12 +494,13 @@ class ContainerCollectionTest(unittest.TestCase):
host_config={'NetworkMode': 'default'} host_config={'NetworkMode': 'default'}
) )
def test_create_network_driver_opts_without_network(self): def test_create_networking_config_without_network(self):
client = make_fake_client() client = make_fake_client()
client.containers.create( client.containers.create(
image='alpine', image='alpine',
network_driver_opt={'key1': 'a'} networking_config={'aliases': ['test'],
'driver_opt': {'key1': 'a'}}
) )
client.api.create_container.assert_called_with( client.api.create_container.assert_called_with(
@ -423,13 +509,14 @@ class ContainerCollectionTest(unittest.TestCase):
host_config={'NetworkMode': 'default'} host_config={'NetworkMode': 'default'}
) )
def test_create_network_driver_opts_with_network_mode(self): def test_create_networking_config_with_network_mode(self):
client = make_fake_client() client = make_fake_client()
client.containers.create( client.containers.create(
image='alpine', image='alpine',
network_mode='none', network_mode='none',
network_driver_opt={'key1': 'a'} networking_config={'aliases': ['test'],
'driver_opt': {'key1': 'a'}}
) )
client.api.create_container.assert_called_with( client.api.create_container.assert_called_with(
@ -438,19 +525,81 @@ class ContainerCollectionTest(unittest.TestCase):
host_config={'NetworkMode': 'none'} host_config={'NetworkMode': 'none'}
) )
def test_create_network_driver_opts(self): def test_create_networking_config(self):
client = make_fake_client() client = make_fake_client()
networking_config = {
'foo': EndpointConfig(
DEFAULT_DOCKER_API_VERSION, aliases=['test'],
driver_opt={'key1': 'a'}
)
}
client.containers.create( client.containers.create(
image='alpine', image='alpine',
network='foo', network='foo',
network_driver_opt={'key1': 'a'} networking_config=networking_config
) )
client.api.create_container.assert_called_with( client.api.create_container.assert_called_with(
image='alpine', image='alpine',
command=None, command=None,
networking_config={'foo': {'driver_opt': {'key1': 'a'}}}, networking_config={'EndpointsConfig': {
'foo': {'Aliases': ['test'], 'DriverOpts': {'key1': 'a'}}}
},
host_config={'NetworkMode': 'foo'}
)
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',
networking_config=networking_config
)
client.api.create_container.assert_called_with(
image='alpine',
command=None,
networking_config={'EndpointsConfig': {
'foo': {'Aliases': ['test_foo'], 'DriverOpts': {'key2': 'b'}},
'bar': {'Aliases': ['test'], 'DriverOpts': {'key1': 'a'}},
}},
host_config={'NetworkMode': 'foo'}
)
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',
networking_config=networking_config
)
client.api.create_container.assert_called_with(
image='alpine',
command=None,
networking_config={'foo': None},
host_config={'NetworkMode': 'foo'} host_config={'NetworkMode': 'foo'}
) )
@ -479,6 +628,7 @@ class ContainerCollectionTest(unittest.TestCase):
def test_list_ignore_removed(self): def test_list_ignore_removed(self):
def side_effect(*args, **kwargs): def side_effect(*args, **kwargs):
raise docker.errors.NotFound('Container not found') raise docker.errors.NotFound('Container not found')
client = make_fake_client({ client = make_fake_client({
'inspect_container.side_effect': side_effect 'inspect_container.side_effect': side_effect
}) })