mirror of https://github.com/docker/docker-py.git
1595 lines
58 KiB
Python
1595 lines
58 KiB
Python
import datetime
|
|
import json
|
|
import signal
|
|
from unittest import mock
|
|
|
|
import pytest
|
|
|
|
import docker
|
|
from docker.api import APIClient
|
|
|
|
from ..helpers import requires_api_version
|
|
from . import fake_api
|
|
from .api_test import (
|
|
DEFAULT_TIMEOUT_SECONDS,
|
|
BaseAPIClientTest,
|
|
fake_inspect_container,
|
|
fake_request,
|
|
url_base,
|
|
url_prefix,
|
|
)
|
|
|
|
|
|
def fake_inspect_container_tty(self, container):
|
|
return fake_inspect_container(self, container, tty=True)
|
|
|
|
|
|
class StartContainerTest(BaseAPIClientTest):
|
|
def test_start_container(self):
|
|
self.client.start(fake_api.FAKE_CONTAINER_ID)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == (url_prefix + 'containers/' +
|
|
fake_api.FAKE_CONTAINER_ID + '/start')
|
|
assert 'data' not in args[1]
|
|
assert args[1]['timeout'] == DEFAULT_TIMEOUT_SECONDS
|
|
|
|
def test_start_container_none(self):
|
|
with pytest.raises(ValueError) as excinfo:
|
|
self.client.start(container=None)
|
|
|
|
assert str(excinfo.value) == 'Resource ID was not provided'
|
|
|
|
with pytest.raises(ValueError) as excinfo:
|
|
self.client.start(None)
|
|
|
|
assert str(excinfo.value) == 'Resource ID was not provided'
|
|
|
|
def test_start_container_regression_573(self):
|
|
self.client.start(**{'container': fake_api.FAKE_CONTAINER_ID})
|
|
|
|
def test_start_container_with_lxc_conf(self):
|
|
with pytest.raises(docker.errors.DeprecatedMethod):
|
|
self.client.start(
|
|
fake_api.FAKE_CONTAINER_ID,
|
|
lxc_conf={'lxc.conf.k': 'lxc.conf.value'}
|
|
)
|
|
|
|
def test_start_container_with_lxc_conf_compat(self):
|
|
with pytest.raises(docker.errors.DeprecatedMethod):
|
|
self.client.start(
|
|
fake_api.FAKE_CONTAINER_ID,
|
|
lxc_conf=[{'Key': 'lxc.conf.k', 'Value': 'lxc.conf.value'}]
|
|
)
|
|
|
|
def test_start_container_with_binds_ro(self):
|
|
with pytest.raises(docker.errors.DeprecatedMethod):
|
|
self.client.start(
|
|
fake_api.FAKE_CONTAINER_ID, binds={
|
|
'/tmp': {
|
|
"bind": '/mnt',
|
|
"ro": True
|
|
}
|
|
}
|
|
)
|
|
|
|
def test_start_container_with_binds_rw(self):
|
|
with pytest.raises(docker.errors.DeprecatedMethod):
|
|
self.client.start(
|
|
fake_api.FAKE_CONTAINER_ID, binds={
|
|
'/tmp': {"bind": '/mnt', "ro": False}
|
|
}
|
|
)
|
|
|
|
def test_start_container_with_port_binds(self):
|
|
self.maxDiff = None
|
|
|
|
with pytest.raises(docker.errors.DeprecatedMethod):
|
|
self.client.start(fake_api.FAKE_CONTAINER_ID, port_bindings={
|
|
1111: None,
|
|
2222: 2222,
|
|
'3333/udp': (3333,),
|
|
4444: ('127.0.0.1',),
|
|
5555: ('127.0.0.1', 5555),
|
|
6666: [('127.0.0.1',), ('192.168.0.1',)]
|
|
})
|
|
|
|
def test_start_container_with_links(self):
|
|
with pytest.raises(docker.errors.DeprecatedMethod):
|
|
self.client.start(
|
|
fake_api.FAKE_CONTAINER_ID, links={'path': 'alias'}
|
|
)
|
|
|
|
def test_start_container_with_multiple_links(self):
|
|
with pytest.raises(docker.errors.DeprecatedMethod):
|
|
self.client.start(
|
|
fake_api.FAKE_CONTAINER_ID,
|
|
links={
|
|
'path1': 'alias1',
|
|
'path2': 'alias2'
|
|
}
|
|
)
|
|
|
|
def test_start_container_with_links_as_list_of_tuples(self):
|
|
with pytest.raises(docker.errors.DeprecatedMethod):
|
|
self.client.start(fake_api.FAKE_CONTAINER_ID,
|
|
links=[('path', 'alias')])
|
|
|
|
def test_start_container_privileged(self):
|
|
with pytest.raises(docker.errors.DeprecatedMethod):
|
|
self.client.start(fake_api.FAKE_CONTAINER_ID, privileged=True)
|
|
|
|
def test_start_container_with_dict_instead_of_id(self):
|
|
self.client.start({'Id': fake_api.FAKE_CONTAINER_ID})
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == (url_prefix + 'containers/' +
|
|
fake_api.FAKE_CONTAINER_ID + '/start')
|
|
assert 'data' not in args[1]
|
|
assert args[1]['timeout'] == DEFAULT_TIMEOUT_SECONDS
|
|
|
|
|
|
class CreateContainerTest(BaseAPIClientTest):
|
|
def test_create_container(self):
|
|
self.client.create_container('busybox', 'true')
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
assert json.loads(args[1]['data']) == json.loads('''
|
|
{"Tty": false, "Image": "busybox", "Cmd": ["true"],
|
|
"AttachStdin": false,
|
|
"AttachStderr": true, "AttachStdout": true,
|
|
"StdinOnce": false,
|
|
"OpenStdin": false, "NetworkDisabled": false}
|
|
''')
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
|
|
def test_create_container_with_binds(self):
|
|
mount_dest = '/mnt'
|
|
|
|
self.client.create_container('busybox', ['ls', mount_dest],
|
|
volumes=[mount_dest])
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
assert json.loads(args[1]['data']) == json.loads('''
|
|
{"Tty": false, "Image": "busybox",
|
|
"Cmd": ["ls", "/mnt"], "AttachStdin": false,
|
|
"Volumes": {"/mnt": {}},
|
|
"AttachStderr": true,
|
|
"AttachStdout": true, "OpenStdin": false,
|
|
"StdinOnce": false,
|
|
"NetworkDisabled": false}
|
|
''')
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
|
|
def test_create_container_with_volume_string(self):
|
|
mount_dest = '/mnt'
|
|
|
|
self.client.create_container('busybox', ['ls', mount_dest],
|
|
volumes=mount_dest)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
assert json.loads(args[1]['data']) == json.loads('''
|
|
{"Tty": false, "Image": "busybox",
|
|
"Cmd": ["ls", "/mnt"], "AttachStdin": false,
|
|
"Volumes": {"/mnt": {}},
|
|
"AttachStderr": true,
|
|
"AttachStdout": true, "OpenStdin": false,
|
|
"StdinOnce": false,
|
|
"NetworkDisabled": false}
|
|
''')
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
|
|
def test_create_container_with_ports(self):
|
|
self.client.create_container('busybox', 'ls',
|
|
ports=[1111, (2222, 'udp'), (3333,)])
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
assert json.loads(args[1]['data']) == json.loads('''
|
|
{"Tty": false, "Image": "busybox",
|
|
"Cmd": ["ls"], "AttachStdin": false,
|
|
"ExposedPorts": {
|
|
"1111/tcp": {},
|
|
"2222/udp": {},
|
|
"3333/tcp": {}
|
|
},
|
|
"AttachStderr": true,
|
|
"AttachStdout": true, "OpenStdin": false,
|
|
"StdinOnce": false,
|
|
"NetworkDisabled": false}
|
|
''')
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
|
|
def test_create_container_with_entrypoint(self):
|
|
self.client.create_container('busybox', 'hello',
|
|
entrypoint='cowsay entry')
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
assert json.loads(args[1]['data']) == json.loads('''
|
|
{"Tty": false, "Image": "busybox",
|
|
"Cmd": ["hello"], "AttachStdin": false,
|
|
"AttachStderr": true,
|
|
"AttachStdout": true, "OpenStdin": false,
|
|
"StdinOnce": false,
|
|
"NetworkDisabled": false,
|
|
"Entrypoint": ["cowsay", "entry"]}
|
|
''')
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
|
|
def test_create_container_with_host_config_cpu_shares(self):
|
|
self.client.create_container(
|
|
'busybox', 'ls', host_config=self.client.create_host_config(
|
|
cpu_shares=512
|
|
)
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
|
|
assert json.loads(args[1]['data']) == json.loads('''
|
|
{"Tty": false, "Image": "busybox",
|
|
"Cmd": ["ls"], "AttachStdin": false,
|
|
"AttachStderr": true,
|
|
"AttachStdout": true, "OpenStdin": false,
|
|
"StdinOnce": false,
|
|
"NetworkDisabled": false,
|
|
"HostConfig": {
|
|
"CpuShares": 512,
|
|
"NetworkMode": "default"
|
|
}}
|
|
''')
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
|
|
def test_create_container_with_host_config_cpuset(self):
|
|
self.client.create_container(
|
|
'busybox', 'ls', host_config=self.client.create_host_config(
|
|
cpuset_cpus='0,1'
|
|
)
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
|
|
assert json.loads(args[1]['data']) == json.loads('''
|
|
{"Tty": false, "Image": "busybox",
|
|
"Cmd": ["ls"], "AttachStdin": false,
|
|
"AttachStderr": true,
|
|
"AttachStdout": true, "OpenStdin": false,
|
|
"StdinOnce": false,
|
|
"NetworkDisabled": false,
|
|
"HostConfig": {
|
|
"CpusetCpus": "0,1",
|
|
"NetworkMode": "default"
|
|
}}
|
|
''')
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
|
|
def test_create_container_with_host_config_cpuset_mems(self):
|
|
self.client.create_container(
|
|
'busybox', 'ls', host_config=self.client.create_host_config(
|
|
cpuset_mems='0'
|
|
)
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
|
|
assert json.loads(args[1]['data']) == json.loads('''
|
|
{"Tty": false, "Image": "busybox",
|
|
"Cmd": ["ls"], "AttachStdin": false,
|
|
"AttachStderr": true,
|
|
"AttachStdout": true, "OpenStdin": false,
|
|
"StdinOnce": false,
|
|
"NetworkDisabled": false,
|
|
"HostConfig": {
|
|
"CpusetMems": "0",
|
|
"NetworkMode": "default"
|
|
}}
|
|
''')
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
|
|
def test_create_container_with_cgroup_parent(self):
|
|
self.client.create_container(
|
|
'busybox', 'ls', host_config=self.client.create_host_config(
|
|
cgroup_parent='test'
|
|
)
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
data = json.loads(args[1]['data'])
|
|
assert 'HostConfig' in data
|
|
assert 'CgroupParent' in data['HostConfig']
|
|
assert data['HostConfig']['CgroupParent'] == 'test'
|
|
|
|
def test_create_container_with_working_dir(self):
|
|
self.client.create_container('busybox', 'ls',
|
|
working_dir='/root')
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
assert json.loads(args[1]['data']) == json.loads('''
|
|
{"Tty": false, "Image": "busybox",
|
|
"Cmd": ["ls"], "AttachStdin": false,
|
|
"AttachStderr": true,
|
|
"AttachStdout": true, "OpenStdin": false,
|
|
"StdinOnce": false,
|
|
"NetworkDisabled": false,
|
|
"WorkingDir": "/root"}
|
|
''')
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
|
|
def test_create_container_with_stdin_open(self):
|
|
self.client.create_container('busybox', 'true', stdin_open=True)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
assert json.loads(args[1]['data']) == json.loads('''
|
|
{"Tty": false, "Image": "busybox", "Cmd": ["true"],
|
|
"AttachStdin": true,
|
|
"AttachStderr": true, "AttachStdout": true,
|
|
"StdinOnce": true,
|
|
"OpenStdin": true, "NetworkDisabled": false}
|
|
''')
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
|
|
def test_create_named_container(self):
|
|
self.client.create_container('busybox', 'true',
|
|
name='marisa-kirisame')
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
assert json.loads(args[1]['data']) == json.loads('''
|
|
{"Tty": false, "Image": "busybox", "Cmd": ["true"],
|
|
"AttachStdin": false,
|
|
"AttachStderr": true, "AttachStdout": true,
|
|
"StdinOnce": false,
|
|
"OpenStdin": false, "NetworkDisabled": false}
|
|
''')
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
assert args[1]['params'] == {'name': 'marisa-kirisame'}
|
|
|
|
def test_create_container_with_platform(self):
|
|
self.client.create_container('busybox', 'true',
|
|
platform='linux')
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
assert json.loads(args[1]['data']) == json.loads('''
|
|
{"Tty": false, "Image": "busybox", "Cmd": ["true"],
|
|
"AttachStdin": false,
|
|
"AttachStderr": true, "AttachStdout": true,
|
|
"StdinOnce": false,
|
|
"OpenStdin": false, "NetworkDisabled": false}
|
|
''')
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
assert args[1]['params'] == {'name': None, 'platform': 'linux'}
|
|
|
|
def test_create_container_with_mem_limit_as_int(self):
|
|
self.client.create_container(
|
|
'busybox', 'true', host_config=self.client.create_host_config(
|
|
mem_limit=128.0
|
|
)
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
data = json.loads(args[1]['data'])
|
|
assert data['HostConfig']['Memory'] == 128.0
|
|
|
|
def test_create_container_with_mem_limit_as_string(self):
|
|
self.client.create_container(
|
|
'busybox', 'true', host_config=self.client.create_host_config(
|
|
mem_limit='128'
|
|
)
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
data = json.loads(args[1]['data'])
|
|
assert data['HostConfig']['Memory'] == 128.0
|
|
|
|
def test_create_container_with_mem_limit_as_string_with_k_unit(self):
|
|
self.client.create_container(
|
|
'busybox', 'true', host_config=self.client.create_host_config(
|
|
mem_limit='128k'
|
|
)
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
data = json.loads(args[1]['data'])
|
|
assert data['HostConfig']['Memory'] == 128.0 * 1024
|
|
|
|
def test_create_container_with_mem_limit_as_string_with_m_unit(self):
|
|
self.client.create_container(
|
|
'busybox', 'true', host_config=self.client.create_host_config(
|
|
mem_limit='128m'
|
|
)
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
data = json.loads(args[1]['data'])
|
|
assert data['HostConfig']['Memory'] == 128.0 * 1024 * 1024
|
|
|
|
def test_create_container_with_mem_limit_as_string_with_g_unit(self):
|
|
self.client.create_container(
|
|
'busybox', 'true', host_config=self.client.create_host_config(
|
|
mem_limit='128g'
|
|
)
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
data = json.loads(args[1]['data'])
|
|
assert data['HostConfig']['Memory'] == 128.0 * 1024 * 1024 * 1024
|
|
|
|
def test_create_container_with_mem_limit_as_string_with_wrong_value(self):
|
|
with pytest.raises(docker.errors.DockerException):
|
|
self.client.create_host_config(mem_limit='128p')
|
|
|
|
with pytest.raises(docker.errors.DockerException):
|
|
self.client.create_host_config(mem_limit='1f28')
|
|
|
|
def test_create_container_with_lxc_conf(self):
|
|
self.client.create_container(
|
|
'busybox', 'true', host_config=self.client.create_host_config(
|
|
lxc_conf={'lxc.conf.k': 'lxc.conf.value'}
|
|
)
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
expected_payload = self.base_create_payload()
|
|
expected_payload['HostConfig'] = self.client.create_host_config()
|
|
expected_payload['HostConfig']['LxcConf'] = [
|
|
{"Value": "lxc.conf.value", "Key": "lxc.conf.k"}
|
|
]
|
|
|
|
assert json.loads(args[1]['data']) == expected_payload
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
assert args[1]['timeout'] == DEFAULT_TIMEOUT_SECONDS
|
|
|
|
def test_create_container_with_lxc_conf_compat(self):
|
|
self.client.create_container(
|
|
'busybox', 'true', host_config=self.client.create_host_config(
|
|
lxc_conf=[{'Key': 'lxc.conf.k', 'Value': 'lxc.conf.value'}]
|
|
)
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
expected_payload = self.base_create_payload()
|
|
expected_payload['HostConfig'] = self.client.create_host_config()
|
|
expected_payload['HostConfig']['LxcConf'] = [
|
|
{"Value": "lxc.conf.value", "Key": "lxc.conf.k"}
|
|
]
|
|
assert json.loads(args[1]['data']) == expected_payload
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
assert args[1]['timeout'] == DEFAULT_TIMEOUT_SECONDS
|
|
|
|
def test_create_container_with_binds_ro(self):
|
|
mount_dest = '/mnt'
|
|
mount_origin = '/tmp'
|
|
|
|
self.client.create_container(
|
|
'busybox', 'true', host_config=self.client.create_host_config(
|
|
binds={mount_origin: {
|
|
"bind": mount_dest,
|
|
"ro": True
|
|
}}
|
|
)
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
expected_payload = self.base_create_payload()
|
|
expected_payload['HostConfig'] = self.client.create_host_config()
|
|
expected_payload['HostConfig']['Binds'] = ["/tmp:/mnt:ro"]
|
|
assert json.loads(args[1]['data']) == expected_payload
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
assert args[1]['timeout'] == DEFAULT_TIMEOUT_SECONDS
|
|
|
|
def test_create_container_with_binds_rw(self):
|
|
mount_dest = '/mnt'
|
|
mount_origin = '/tmp'
|
|
|
|
self.client.create_container(
|
|
'busybox', 'true', host_config=self.client.create_host_config(
|
|
binds={mount_origin: {
|
|
"bind": mount_dest,
|
|
"ro": False
|
|
}}
|
|
)
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
expected_payload = self.base_create_payload()
|
|
expected_payload['HostConfig'] = self.client.create_host_config()
|
|
expected_payload['HostConfig']['Binds'] = ["/tmp:/mnt:rw"]
|
|
assert json.loads(args[1]['data']) == expected_payload
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
assert args[1]['timeout'] == DEFAULT_TIMEOUT_SECONDS
|
|
|
|
def test_create_container_with_binds_mode(self):
|
|
mount_dest = '/mnt'
|
|
mount_origin = '/tmp'
|
|
|
|
self.client.create_container(
|
|
'busybox', 'true', host_config=self.client.create_host_config(
|
|
binds={mount_origin: {
|
|
"bind": mount_dest,
|
|
"mode": "z",
|
|
}}
|
|
)
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
expected_payload = self.base_create_payload()
|
|
expected_payload['HostConfig'] = self.client.create_host_config()
|
|
expected_payload['HostConfig']['Binds'] = ["/tmp:/mnt:z"]
|
|
assert json.loads(args[1]['data']) == expected_payload
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
assert args[1]['timeout'] == DEFAULT_TIMEOUT_SECONDS
|
|
|
|
def test_create_container_with_binds_mode_and_ro_error(self):
|
|
with pytest.raises(ValueError):
|
|
mount_dest = '/mnt'
|
|
mount_origin = '/tmp'
|
|
self.client.create_container(
|
|
'busybox', 'true', host_config=self.client.create_host_config(
|
|
binds={mount_origin: {
|
|
"bind": mount_dest,
|
|
"mode": "z",
|
|
"ro": True,
|
|
}}
|
|
)
|
|
)
|
|
|
|
def test_create_container_with_binds_list(self):
|
|
self.client.create_container(
|
|
'busybox', 'true', host_config=self.client.create_host_config(
|
|
binds=[
|
|
"/tmp:/mnt/1:ro",
|
|
"/tmp:/mnt/2",
|
|
],
|
|
)
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
expected_payload = self.base_create_payload()
|
|
expected_payload['HostConfig'] = self.client.create_host_config()
|
|
expected_payload['HostConfig']['Binds'] = [
|
|
"/tmp:/mnt/1:ro",
|
|
"/tmp:/mnt/2",
|
|
]
|
|
assert json.loads(args[1]['data']) == expected_payload
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
assert args[1]['timeout'] == DEFAULT_TIMEOUT_SECONDS
|
|
|
|
def test_create_container_with_port_binds(self):
|
|
self.maxDiff = None
|
|
|
|
self.client.create_container(
|
|
'busybox', 'true', host_config=self.client.create_host_config(
|
|
port_bindings={
|
|
1111: None,
|
|
2222: 2222,
|
|
'3333/udp': (3333,),
|
|
4444: ('127.0.0.1',),
|
|
5555: ('127.0.0.1', 5555),
|
|
6666: [('127.0.0.1',), ('192.168.0.1',)]
|
|
}
|
|
)
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
data = json.loads(args[1]['data'])
|
|
port_bindings = data['HostConfig']['PortBindings']
|
|
assert '1111/tcp' in port_bindings
|
|
assert '2222/tcp' in port_bindings
|
|
assert '3333/udp' in port_bindings
|
|
assert '4444/tcp' in port_bindings
|
|
assert '5555/tcp' in port_bindings
|
|
assert '6666/tcp' in port_bindings
|
|
assert [{"HostPort": "", "HostIp": ""}] == port_bindings['1111/tcp']
|
|
assert [
|
|
{"HostPort": "2222", "HostIp": ""}
|
|
] == port_bindings['2222/tcp']
|
|
assert [
|
|
{"HostPort": "3333", "HostIp": ""}
|
|
] == port_bindings['3333/udp']
|
|
assert [
|
|
{"HostPort": "", "HostIp": "127.0.0.1"}
|
|
] == port_bindings['4444/tcp']
|
|
assert [
|
|
{"HostPort": "5555", "HostIp": "127.0.0.1"}
|
|
] == port_bindings['5555/tcp']
|
|
assert len(port_bindings['6666/tcp']) == 2
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
assert args[1]['timeout'] == DEFAULT_TIMEOUT_SECONDS
|
|
|
|
def test_create_container_with_mac_address(self):
|
|
expected = "02:42:ac:11:00:0a"
|
|
|
|
self.client.create_container(
|
|
'busybox',
|
|
['sleep', '60'],
|
|
mac_address=expected
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
data = json.loads(args[1]['data'])
|
|
assert data['MacAddress'] == expected
|
|
|
|
def test_create_container_with_links(self):
|
|
link_path = 'path'
|
|
alias = 'alias'
|
|
|
|
self.client.create_container(
|
|
'busybox', 'true', host_config=self.client.create_host_config(
|
|
links={link_path: alias}
|
|
)
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
expected_payload = self.base_create_payload()
|
|
expected_payload['HostConfig'] = self.client.create_host_config()
|
|
expected_payload['HostConfig']['Links'] = ['path:alias']
|
|
|
|
assert json.loads(args[1]['data']) == expected_payload
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
|
|
def test_create_container_with_multiple_links(self):
|
|
link_path = 'path'
|
|
alias = 'alias'
|
|
|
|
self.client.create_container(
|
|
'busybox', 'true', host_config=self.client.create_host_config(
|
|
links={
|
|
link_path + '1': alias + '1',
|
|
link_path + '2': alias + '2'
|
|
}
|
|
)
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
expected_payload = self.base_create_payload()
|
|
expected_payload['HostConfig'] = self.client.create_host_config()
|
|
expected_payload['HostConfig']['Links'] = [
|
|
'path1:alias1', 'path2:alias2'
|
|
]
|
|
assert json.loads(args[1]['data']) == expected_payload
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
|
|
def test_create_container_with_links_as_list_of_tuples(self):
|
|
link_path = 'path'
|
|
alias = 'alias'
|
|
|
|
self.client.create_container(
|
|
'busybox', 'true', host_config=self.client.create_host_config(
|
|
links=[(link_path, alias)]
|
|
)
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
expected_payload = self.base_create_payload()
|
|
expected_payload['HostConfig'] = self.client.create_host_config()
|
|
expected_payload['HostConfig']['Links'] = ['path:alias']
|
|
|
|
assert json.loads(args[1]['data']) == expected_payload
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
|
|
def test_create_container_privileged(self):
|
|
self.client.create_container(
|
|
'busybox', 'true',
|
|
host_config=self.client.create_host_config(privileged=True)
|
|
)
|
|
|
|
expected_payload = self.base_create_payload()
|
|
expected_payload['HostConfig'] = self.client.create_host_config()
|
|
expected_payload['HostConfig']['Privileged'] = True
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
assert json.loads(args[1]['data']) == expected_payload
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
assert args[1]['timeout'] == DEFAULT_TIMEOUT_SECONDS
|
|
|
|
def test_create_container_with_restart_policy(self):
|
|
self.client.create_container(
|
|
'busybox', 'true', host_config=self.client.create_host_config(
|
|
restart_policy={
|
|
"Name": "always",
|
|
"MaximumRetryCount": 0
|
|
}
|
|
)
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
|
|
expected_payload = self.base_create_payload()
|
|
expected_payload['HostConfig'] = self.client.create_host_config()
|
|
expected_payload['HostConfig']['RestartPolicy'] = {
|
|
"MaximumRetryCount": 0, "Name": "always"
|
|
}
|
|
assert json.loads(args[1]['data']) == expected_payload
|
|
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
assert args[1]['timeout'] == DEFAULT_TIMEOUT_SECONDS
|
|
|
|
def test_create_container_with_added_capabilities(self):
|
|
self.client.create_container(
|
|
'busybox', 'true',
|
|
host_config=self.client.create_host_config(cap_add=['MKNOD'])
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
expected_payload = self.base_create_payload()
|
|
expected_payload['HostConfig'] = self.client.create_host_config()
|
|
expected_payload['HostConfig']['CapAdd'] = ['MKNOD']
|
|
assert json.loads(args[1]['data']) == expected_payload
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
assert args[1]['timeout'] == DEFAULT_TIMEOUT_SECONDS
|
|
|
|
def test_create_container_with_dropped_capabilities(self):
|
|
self.client.create_container(
|
|
'busybox', 'true',
|
|
host_config=self.client.create_host_config(cap_drop=['MKNOD'])
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
expected_payload = self.base_create_payload()
|
|
expected_payload['HostConfig'] = self.client.create_host_config()
|
|
expected_payload['HostConfig']['CapDrop'] = ['MKNOD']
|
|
assert json.loads(args[1]['data']) == expected_payload
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
assert args[1]['timeout'] == DEFAULT_TIMEOUT_SECONDS
|
|
|
|
def test_create_container_with_devices(self):
|
|
self.client.create_container(
|
|
'busybox', 'true', host_config=self.client.create_host_config(
|
|
devices=['/dev/sda:/dev/xvda:rwm',
|
|
'/dev/sdb:/dev/xvdb',
|
|
'/dev/sdc']
|
|
)
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
expected_payload = self.base_create_payload()
|
|
expected_payload['HostConfig'] = self.client.create_host_config()
|
|
expected_payload['HostConfig']['Devices'] = [
|
|
{'CgroupPermissions': 'rwm',
|
|
'PathInContainer': '/dev/xvda',
|
|
'PathOnHost': '/dev/sda'},
|
|
{'CgroupPermissions': 'rwm',
|
|
'PathInContainer': '/dev/xvdb',
|
|
'PathOnHost': '/dev/sdb'},
|
|
{'CgroupPermissions': 'rwm',
|
|
'PathInContainer': '/dev/sdc',
|
|
'PathOnHost': '/dev/sdc'}
|
|
]
|
|
assert json.loads(args[1]['data']) == expected_payload
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
assert args[1]['timeout'] == DEFAULT_TIMEOUT_SECONDS
|
|
|
|
def test_create_container_with_device_requests(self):
|
|
client = APIClient(version='1.40')
|
|
fake_api.fake_responses.setdefault(
|
|
f'{fake_api.prefix}/v1.40/containers/create',
|
|
fake_api.post_fake_create_container,
|
|
)
|
|
client.create_container(
|
|
'busybox', 'true', host_config=client.create_host_config(
|
|
device_requests=[
|
|
{
|
|
'device_ids': [
|
|
'0',
|
|
'GPU-3a23c669-1f69-c64e-cf85-44e9b07e7a2a'
|
|
]
|
|
},
|
|
{
|
|
'driver': 'nvidia',
|
|
'Count': -1,
|
|
'capabilities': [
|
|
['gpu', 'utility']
|
|
],
|
|
'options': {
|
|
'key': 'value'
|
|
}
|
|
}
|
|
]
|
|
)
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_base + 'v1.40/' + 'containers/create'
|
|
expected_payload = self.base_create_payload()
|
|
expected_payload['HostConfig'] = client.create_host_config()
|
|
expected_payload['HostConfig']['DeviceRequests'] = [
|
|
{
|
|
'Driver': '',
|
|
'Count': 0,
|
|
'DeviceIDs': [
|
|
'0',
|
|
'GPU-3a23c669-1f69-c64e-cf85-44e9b07e7a2a'
|
|
],
|
|
'Capabilities': [],
|
|
'Options': {}
|
|
},
|
|
{
|
|
'Driver': 'nvidia',
|
|
'Count': -1,
|
|
'DeviceIDs': [],
|
|
'Capabilities': [
|
|
['gpu', 'utility']
|
|
],
|
|
'Options': {
|
|
'key': 'value'
|
|
}
|
|
}
|
|
]
|
|
assert json.loads(args[1]['data']) == expected_payload
|
|
assert args[1]['headers']['Content-Type'] == 'application/json'
|
|
assert set(args[1]['headers']) <= {'Content-Type', 'User-Agent'}
|
|
assert args[1]['timeout'] == DEFAULT_TIMEOUT_SECONDS
|
|
|
|
def test_create_container_with_labels_dict(self):
|
|
labels_dict = {
|
|
'foo': '1',
|
|
'bar': '2',
|
|
}
|
|
|
|
self.client.create_container(
|
|
'busybox', 'true',
|
|
labels=labels_dict,
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
assert json.loads(args[1]['data'])['Labels'] == labels_dict
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
assert args[1]['timeout'] == DEFAULT_TIMEOUT_SECONDS
|
|
|
|
def test_create_container_with_labels_list(self):
|
|
labels_list = [
|
|
'foo',
|
|
'bar',
|
|
]
|
|
labels_dict = {
|
|
'foo': '',
|
|
'bar': '',
|
|
}
|
|
|
|
self.client.create_container(
|
|
'busybox', 'true',
|
|
labels=labels_list,
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
assert json.loads(args[1]['data'])['Labels'] == labels_dict
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
assert args[1]['timeout'] == DEFAULT_TIMEOUT_SECONDS
|
|
|
|
def test_create_container_with_named_volume(self):
|
|
mount_dest = '/mnt'
|
|
volume_name = 'name'
|
|
|
|
self.client.create_container(
|
|
'busybox', 'true',
|
|
host_config=self.client.create_host_config(
|
|
volume_driver='foodriver',
|
|
binds={volume_name: {
|
|
"bind": mount_dest,
|
|
"ro": False
|
|
}}),
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
expected_payload = self.base_create_payload()
|
|
expected_payload['HostConfig'] = self.client.create_host_config()
|
|
expected_payload['HostConfig']['VolumeDriver'] = 'foodriver'
|
|
expected_payload['HostConfig']['Binds'] = ["name:/mnt:rw"]
|
|
assert json.loads(args[1]['data']) == expected_payload
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
assert args[1]['timeout'] == DEFAULT_TIMEOUT_SECONDS
|
|
|
|
def test_create_container_with_stop_signal(self):
|
|
self.client.create_container('busybox', 'ls',
|
|
stop_signal='SIGINT')
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
assert json.loads(args[1]['data']) == json.loads('''
|
|
{"Tty": false, "Image": "busybox",
|
|
"Cmd": ["ls"], "AttachStdin": false,
|
|
"AttachStderr": true,
|
|
"AttachStdout": true, "OpenStdin": false,
|
|
"StdinOnce": false,
|
|
"NetworkDisabled": false,
|
|
"StopSignal": "SIGINT"}
|
|
''')
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
|
|
@requires_api_version('1.22')
|
|
def test_create_container_with_aliases(self):
|
|
self.client.create_container(
|
|
'busybox', 'ls',
|
|
host_config=self.client.create_host_config(
|
|
network_mode='some-network',
|
|
),
|
|
networking_config=self.client.create_networking_config({
|
|
'some-network': self.client.create_endpoint_config(
|
|
aliases=['foo', 'bar'],
|
|
),
|
|
}),
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert json.loads(args[1]['data']) == json.loads('''
|
|
{"Tty": false, "Image": "busybox",
|
|
"Cmd": ["ls"], "AttachStdin": false,
|
|
"AttachStderr": true,
|
|
"AttachStdout": true, "OpenStdin": false,
|
|
"StdinOnce": false,
|
|
"NetworkDisabled": false,
|
|
"HostConfig": {
|
|
"NetworkMode": "some-network"
|
|
},
|
|
"NetworkingConfig": {
|
|
"EndpointsConfig": {
|
|
"some-network": {"Aliases": ["foo", "bar"]}
|
|
}
|
|
}}
|
|
''')
|
|
|
|
@requires_api_version('1.22')
|
|
def test_create_container_with_tmpfs_list(self):
|
|
|
|
self.client.create_container(
|
|
'busybox', 'true', host_config=self.client.create_host_config(
|
|
tmpfs=[
|
|
"/tmp",
|
|
"/mnt:size=3G,uid=100"
|
|
]
|
|
)
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
expected_payload = self.base_create_payload()
|
|
expected_payload['HostConfig'] = self.client.create_host_config()
|
|
expected_payload['HostConfig']['Tmpfs'] = {
|
|
"/tmp": "",
|
|
"/mnt": "size=3G,uid=100"
|
|
}
|
|
assert json.loads(args[1]['data']) == expected_payload
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
assert args[1]['timeout'] == DEFAULT_TIMEOUT_SECONDS
|
|
|
|
@requires_api_version('1.22')
|
|
def test_create_container_with_tmpfs_dict(self):
|
|
|
|
self.client.create_container(
|
|
'busybox', 'true', host_config=self.client.create_host_config(
|
|
tmpfs={
|
|
"/tmp": "",
|
|
"/mnt": "size=3G,uid=100"
|
|
}
|
|
)
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
expected_payload = self.base_create_payload()
|
|
expected_payload['HostConfig'] = self.client.create_host_config()
|
|
expected_payload['HostConfig']['Tmpfs'] = {
|
|
"/tmp": "",
|
|
"/mnt": "size=3G,uid=100"
|
|
}
|
|
assert json.loads(args[1]['data']) == expected_payload
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
assert args[1]['timeout'] == DEFAULT_TIMEOUT_SECONDS
|
|
|
|
@requires_api_version('1.24')
|
|
def test_create_container_with_sysctl(self):
|
|
self.client.create_container(
|
|
'busybox', 'true',
|
|
host_config=self.client.create_host_config(
|
|
sysctls={
|
|
'net.core.somaxconn': 1024,
|
|
'net.ipv4.tcp_syncookies': '0',
|
|
}
|
|
)
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
expected_payload = self.base_create_payload()
|
|
expected_payload['HostConfig'] = self.client.create_host_config()
|
|
expected_payload['HostConfig']['Sysctls'] = {
|
|
'net.core.somaxconn': '1024', 'net.ipv4.tcp_syncookies': '0',
|
|
}
|
|
assert json.loads(args[1]['data']) == expected_payload
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
assert args[1]['timeout'] == DEFAULT_TIMEOUT_SECONDS
|
|
|
|
def test_create_container_with_unicode_envvars(self):
|
|
envvars_dict = {
|
|
'foo': '☃',
|
|
}
|
|
|
|
expected = [
|
|
'foo=☃'
|
|
]
|
|
|
|
self.client.create_container(
|
|
'busybox', 'true',
|
|
environment=envvars_dict,
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
assert json.loads(args[1]['data'])['Env'] == expected
|
|
|
|
@requires_api_version('1.25')
|
|
def test_create_container_with_host_config_cpus(self):
|
|
self.client.create_container(
|
|
'busybox', 'ls', host_config=self.client.create_host_config(
|
|
cpu_count=1,
|
|
cpu_percent=20,
|
|
nano_cpus=1000
|
|
)
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
|
|
assert json.loads(args[1]['data']) == json.loads('''
|
|
{"Tty": false, "Image": "busybox",
|
|
"Cmd": ["ls"], "AttachStdin": false,
|
|
"AttachStderr": true,
|
|
"AttachStdout": true, "OpenStdin": false,
|
|
"StdinOnce": false,
|
|
"NetworkDisabled": false,
|
|
"HostConfig": {
|
|
"CpuCount": 1,
|
|
"CpuPercent": 20,
|
|
"NanoCpus": 1000,
|
|
"NetworkMode": "default"
|
|
}}
|
|
''')
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
|
|
@requires_api_version('1.41')
|
|
def test_create_container_with_cgroupns(self):
|
|
self.client.create_container(
|
|
image='busybox',
|
|
command='true',
|
|
host_config=self.client.create_host_config(
|
|
cgroupns='private',
|
|
),
|
|
)
|
|
|
|
args = fake_request.call_args
|
|
assert args[0][1] == url_prefix + 'containers/create'
|
|
|
|
expected_payload = self.base_create_payload()
|
|
expected_payload['HostConfig'] = self.client.create_host_config()
|
|
expected_payload['HostConfig']['CgroupnsMode'] = 'private'
|
|
assert json.loads(args[1]['data']) == expected_payload
|
|
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
|
|
|
|
|
class ContainerTest(BaseAPIClientTest):
|
|
def test_list_containers(self):
|
|
self.client.containers(all=True)
|
|
|
|
fake_request.assert_called_with(
|
|
'GET',
|
|
url_prefix + 'containers/json',
|
|
params={
|
|
'all': 1,
|
|
'since': None,
|
|
'size': 0,
|
|
'limit': -1,
|
|
'trunc_cmd': 0,
|
|
'before': None
|
|
},
|
|
timeout=DEFAULT_TIMEOUT_SECONDS
|
|
)
|
|
|
|
def test_resize_container(self):
|
|
self.client.resize(
|
|
{'Id': fake_api.FAKE_CONTAINER_ID},
|
|
height=15,
|
|
width=120
|
|
)
|
|
|
|
fake_request.assert_called_with(
|
|
'POST',
|
|
(url_prefix + 'containers/' +
|
|
fake_api.FAKE_CONTAINER_ID + '/resize'),
|
|
params={'h': 15, 'w': 120},
|
|
timeout=DEFAULT_TIMEOUT_SECONDS
|
|
)
|
|
|
|
def test_rename_container(self):
|
|
self.client.rename(
|
|
{'Id': fake_api.FAKE_CONTAINER_ID},
|
|
name='foobar'
|
|
)
|
|
|
|
fake_request.assert_called_with(
|
|
'POST',
|
|
(url_prefix + 'containers/' +
|
|
fake_api.FAKE_CONTAINER_ID + '/rename'),
|
|
params={'name': 'foobar'},
|
|
timeout=DEFAULT_TIMEOUT_SECONDS
|
|
)
|
|
|
|
def test_wait(self):
|
|
self.client.wait(fake_api.FAKE_CONTAINER_ID)
|
|
|
|
fake_request.assert_called_with(
|
|
'POST',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/wait',
|
|
timeout=None,
|
|
params={}
|
|
)
|
|
|
|
def test_wait_with_dict_instead_of_id(self):
|
|
self.client.wait({'Id': fake_api.FAKE_CONTAINER_ID})
|
|
|
|
fake_request.assert_called_with(
|
|
'POST',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/wait',
|
|
timeout=None,
|
|
params={}
|
|
)
|
|
|
|
def test_logs(self):
|
|
with mock.patch('docker.api.client.APIClient.inspect_container',
|
|
fake_inspect_container):
|
|
logs = self.client.logs(fake_api.FAKE_CONTAINER_ID)
|
|
|
|
fake_request.assert_called_with(
|
|
'GET',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/logs',
|
|
params={'timestamps': 0, 'follow': 0, 'stderr': 1, 'stdout': 1,
|
|
'tail': 'all'},
|
|
timeout=DEFAULT_TIMEOUT_SECONDS,
|
|
stream=False
|
|
)
|
|
|
|
assert logs == b'Flowering Nights\n(Sakuya Iyazoi)\n'
|
|
|
|
def test_logs_with_dict_instead_of_id(self):
|
|
with mock.patch('docker.api.client.APIClient.inspect_container',
|
|
fake_inspect_container):
|
|
logs = self.client.logs({'Id': fake_api.FAKE_CONTAINER_ID})
|
|
|
|
fake_request.assert_called_with(
|
|
'GET',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/logs',
|
|
params={'timestamps': 0, 'follow': 0, 'stderr': 1, 'stdout': 1,
|
|
'tail': 'all'},
|
|
timeout=DEFAULT_TIMEOUT_SECONDS,
|
|
stream=False
|
|
)
|
|
|
|
assert logs == b'Flowering Nights\n(Sakuya Iyazoi)\n'
|
|
|
|
def test_log_streaming(self):
|
|
with mock.patch('docker.api.client.APIClient.inspect_container',
|
|
fake_inspect_container):
|
|
self.client.logs(fake_api.FAKE_CONTAINER_ID, stream=True,
|
|
follow=False)
|
|
|
|
fake_request.assert_called_with(
|
|
'GET',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/logs',
|
|
params={'timestamps': 0, 'follow': 0, 'stderr': 1, 'stdout': 1,
|
|
'tail': 'all'},
|
|
timeout=DEFAULT_TIMEOUT_SECONDS,
|
|
stream=True
|
|
)
|
|
|
|
def test_log_following(self):
|
|
with mock.patch('docker.api.client.APIClient.inspect_container',
|
|
fake_inspect_container):
|
|
self.client.logs(fake_api.FAKE_CONTAINER_ID, stream=False,
|
|
follow=True)
|
|
|
|
fake_request.assert_called_with(
|
|
'GET',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/logs',
|
|
params={'timestamps': 0, 'follow': 1, 'stderr': 1, 'stdout': 1,
|
|
'tail': 'all'},
|
|
timeout=DEFAULT_TIMEOUT_SECONDS,
|
|
stream=False
|
|
)
|
|
|
|
def test_log_following_backwards(self):
|
|
with mock.patch('docker.api.client.APIClient.inspect_container',
|
|
fake_inspect_container):
|
|
self.client.logs(fake_api.FAKE_CONTAINER_ID, stream=True)
|
|
|
|
fake_request.assert_called_with(
|
|
'GET',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/logs',
|
|
params={'timestamps': 0, 'follow': 1, 'stderr': 1, 'stdout': 1,
|
|
'tail': 'all'},
|
|
timeout=DEFAULT_TIMEOUT_SECONDS,
|
|
stream=True
|
|
)
|
|
|
|
def test_log_streaming_and_following(self):
|
|
with mock.patch('docker.api.client.APIClient.inspect_container',
|
|
fake_inspect_container):
|
|
self.client.logs(fake_api.FAKE_CONTAINER_ID, stream=True,
|
|
follow=True)
|
|
|
|
fake_request.assert_called_with(
|
|
'GET',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/logs',
|
|
params={'timestamps': 0, 'follow': 1, 'stderr': 1, 'stdout': 1,
|
|
'tail': 'all'},
|
|
timeout=DEFAULT_TIMEOUT_SECONDS,
|
|
stream=True
|
|
)
|
|
|
|
def test_log_tail(self):
|
|
|
|
with mock.patch('docker.api.client.APIClient.inspect_container',
|
|
fake_inspect_container):
|
|
self.client.logs(fake_api.FAKE_CONTAINER_ID, stream=False,
|
|
follow=False, tail=10)
|
|
|
|
fake_request.assert_called_with(
|
|
'GET',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/logs',
|
|
params={'timestamps': 0, 'follow': 0, 'stderr': 1, 'stdout': 1,
|
|
'tail': 10},
|
|
timeout=DEFAULT_TIMEOUT_SECONDS,
|
|
stream=False
|
|
)
|
|
|
|
def test_log_since(self):
|
|
ts = 809222400
|
|
with mock.patch('docker.api.client.APIClient.inspect_container',
|
|
fake_inspect_container):
|
|
self.client.logs(fake_api.FAKE_CONTAINER_ID, stream=False,
|
|
follow=False, since=ts)
|
|
|
|
fake_request.assert_called_with(
|
|
'GET',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/logs',
|
|
params={'timestamps': 0, 'follow': 0, 'stderr': 1, 'stdout': 1,
|
|
'tail': 'all', 'since': ts},
|
|
timeout=DEFAULT_TIMEOUT_SECONDS,
|
|
stream=False
|
|
)
|
|
|
|
def test_log_since_with_float(self):
|
|
ts = 809222400.000000
|
|
with mock.patch('docker.api.client.APIClient.inspect_container',
|
|
fake_inspect_container):
|
|
self.client.logs(fake_api.FAKE_CONTAINER_ID, stream=False,
|
|
follow=False, since=ts)
|
|
|
|
fake_request.assert_called_with(
|
|
'GET',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/logs',
|
|
params={'timestamps': 0, 'follow': 0, 'stderr': 1, 'stdout': 1,
|
|
'tail': 'all', 'since': ts},
|
|
timeout=DEFAULT_TIMEOUT_SECONDS,
|
|
stream=False
|
|
)
|
|
|
|
def test_log_since_with_datetime(self):
|
|
ts = 809222400
|
|
time = datetime.datetime.utcfromtimestamp(ts)
|
|
with mock.patch('docker.api.client.APIClient.inspect_container',
|
|
fake_inspect_container):
|
|
self.client.logs(fake_api.FAKE_CONTAINER_ID, stream=False,
|
|
follow=False, since=time)
|
|
|
|
fake_request.assert_called_with(
|
|
'GET',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/logs',
|
|
params={'timestamps': 0, 'follow': 0, 'stderr': 1, 'stdout': 1,
|
|
'tail': 'all', 'since': ts},
|
|
timeout=DEFAULT_TIMEOUT_SECONDS,
|
|
stream=False
|
|
)
|
|
|
|
def test_log_since_with_invalid_value_raises_error(self):
|
|
with mock.patch('docker.api.client.APIClient.inspect_container',
|
|
fake_inspect_container):
|
|
with pytest.raises(docker.errors.InvalidArgument):
|
|
self.client.logs(fake_api.FAKE_CONTAINER_ID, stream=False,
|
|
follow=False, since="42.42")
|
|
|
|
def test_log_tty(self):
|
|
m = mock.Mock()
|
|
with mock.patch('docker.api.client.APIClient.inspect_container',
|
|
fake_inspect_container_tty):
|
|
with mock.patch('docker.api.client.APIClient._stream_raw_result',
|
|
m):
|
|
self.client.logs(fake_api.FAKE_CONTAINER_ID,
|
|
follow=True, stream=True)
|
|
|
|
assert m.called
|
|
fake_request.assert_called_with(
|
|
'GET',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/logs',
|
|
params={'timestamps': 0, 'follow': 1, 'stderr': 1, 'stdout': 1,
|
|
'tail': 'all'},
|
|
timeout=DEFAULT_TIMEOUT_SECONDS,
|
|
stream=True
|
|
)
|
|
|
|
def test_diff(self):
|
|
self.client.diff(fake_api.FAKE_CONTAINER_ID)
|
|
|
|
fake_request.assert_called_with(
|
|
'GET',
|
|
(url_prefix + 'containers/' +
|
|
fake_api.FAKE_CONTAINER_ID + '/changes'),
|
|
timeout=DEFAULT_TIMEOUT_SECONDS
|
|
)
|
|
|
|
def test_diff_with_dict_instead_of_id(self):
|
|
self.client.diff({'Id': fake_api.FAKE_CONTAINER_ID})
|
|
|
|
fake_request.assert_called_with(
|
|
'GET',
|
|
(url_prefix + 'containers/' +
|
|
fake_api.FAKE_CONTAINER_ID + '/changes'),
|
|
timeout=DEFAULT_TIMEOUT_SECONDS
|
|
)
|
|
|
|
def test_port(self):
|
|
self.client.port({'Id': fake_api.FAKE_CONTAINER_ID}, 1111)
|
|
|
|
fake_request.assert_called_with(
|
|
'GET',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/json',
|
|
timeout=DEFAULT_TIMEOUT_SECONDS
|
|
)
|
|
|
|
def test_stop_container(self):
|
|
timeout = 2
|
|
|
|
self.client.stop(fake_api.FAKE_CONTAINER_ID, timeout=timeout)
|
|
|
|
fake_request.assert_called_with(
|
|
'POST',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/stop',
|
|
params={'t': timeout},
|
|
timeout=(DEFAULT_TIMEOUT_SECONDS + timeout)
|
|
)
|
|
|
|
def test_stop_container_with_dict_instead_of_id(self):
|
|
timeout = 2
|
|
|
|
self.client.stop({'Id': fake_api.FAKE_CONTAINER_ID},
|
|
timeout=timeout)
|
|
|
|
fake_request.assert_called_with(
|
|
'POST',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/stop',
|
|
params={'t': timeout},
|
|
timeout=(DEFAULT_TIMEOUT_SECONDS + timeout)
|
|
)
|
|
|
|
def test_pause_container(self):
|
|
self.client.pause(fake_api.FAKE_CONTAINER_ID)
|
|
|
|
fake_request.assert_called_with(
|
|
'POST',
|
|
(url_prefix + 'containers/' +
|
|
fake_api.FAKE_CONTAINER_ID + '/pause'),
|
|
timeout=(DEFAULT_TIMEOUT_SECONDS)
|
|
)
|
|
|
|
def test_unpause_container(self):
|
|
self.client.unpause(fake_api.FAKE_CONTAINER_ID)
|
|
|
|
fake_request.assert_called_with(
|
|
'POST',
|
|
(url_prefix + 'containers/' +
|
|
fake_api.FAKE_CONTAINER_ID + '/unpause'),
|
|
timeout=(DEFAULT_TIMEOUT_SECONDS)
|
|
)
|
|
|
|
def test_kill_container(self):
|
|
self.client.kill(fake_api.FAKE_CONTAINER_ID)
|
|
|
|
fake_request.assert_called_with(
|
|
'POST',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/kill',
|
|
params={},
|
|
timeout=DEFAULT_TIMEOUT_SECONDS
|
|
)
|
|
|
|
def test_kill_container_with_dict_instead_of_id(self):
|
|
self.client.kill({'Id': fake_api.FAKE_CONTAINER_ID})
|
|
|
|
fake_request.assert_called_with(
|
|
'POST',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/kill',
|
|
params={},
|
|
timeout=DEFAULT_TIMEOUT_SECONDS
|
|
)
|
|
|
|
def test_kill_container_with_signal(self):
|
|
self.client.kill(fake_api.FAKE_CONTAINER_ID, signal=signal.SIGTERM)
|
|
|
|
fake_request.assert_called_with(
|
|
'POST',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/kill',
|
|
params={'signal': signal.SIGTERM},
|
|
timeout=DEFAULT_TIMEOUT_SECONDS
|
|
)
|
|
|
|
def test_restart_container(self):
|
|
self.client.restart(fake_api.FAKE_CONTAINER_ID, timeout=2)
|
|
|
|
fake_request.assert_called_with(
|
|
'POST',
|
|
(url_prefix + 'containers/' +
|
|
fake_api.FAKE_CONTAINER_ID + '/restart'),
|
|
params={'t': 2},
|
|
timeout=(DEFAULT_TIMEOUT_SECONDS + 2)
|
|
)
|
|
|
|
def test_restart_container_with_dict_instead_of_id(self):
|
|
self.client.restart({'Id': fake_api.FAKE_CONTAINER_ID}, timeout=2)
|
|
|
|
fake_request.assert_called_with(
|
|
'POST',
|
|
(url_prefix + 'containers/' +
|
|
fake_api.FAKE_CONTAINER_ID + '/restart'),
|
|
params={'t': 2},
|
|
timeout=(DEFAULT_TIMEOUT_SECONDS + 2)
|
|
)
|
|
|
|
def test_remove_container(self):
|
|
self.client.remove_container(fake_api.FAKE_CONTAINER_ID)
|
|
|
|
fake_request.assert_called_with(
|
|
'DELETE',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID,
|
|
params={'v': False, 'link': False, 'force': False},
|
|
timeout=DEFAULT_TIMEOUT_SECONDS
|
|
)
|
|
|
|
def test_remove_container_with_dict_instead_of_id(self):
|
|
self.client.remove_container({'Id': fake_api.FAKE_CONTAINER_ID})
|
|
|
|
fake_request.assert_called_with(
|
|
'DELETE',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID,
|
|
params={'v': False, 'link': False, 'force': False},
|
|
timeout=DEFAULT_TIMEOUT_SECONDS
|
|
)
|
|
|
|
def test_export(self):
|
|
self.client.export(fake_api.FAKE_CONTAINER_ID)
|
|
|
|
fake_request.assert_called_with(
|
|
'GET',
|
|
(url_prefix + 'containers/' +
|
|
fake_api.FAKE_CONTAINER_ID + '/export'),
|
|
stream=True,
|
|
timeout=DEFAULT_TIMEOUT_SECONDS
|
|
)
|
|
|
|
def test_export_with_dict_instead_of_id(self):
|
|
self.client.export({'Id': fake_api.FAKE_CONTAINER_ID})
|
|
|
|
fake_request.assert_called_with(
|
|
'GET',
|
|
(url_prefix + 'containers/' +
|
|
fake_api.FAKE_CONTAINER_ID + '/export'),
|
|
stream=True,
|
|
timeout=DEFAULT_TIMEOUT_SECONDS
|
|
)
|
|
|
|
def test_inspect_container(self):
|
|
self.client.inspect_container(fake_api.FAKE_CONTAINER_ID)
|
|
|
|
fake_request.assert_called_with(
|
|
'GET',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/json',
|
|
timeout=DEFAULT_TIMEOUT_SECONDS
|
|
)
|
|
|
|
def test_inspect_container_undefined_id(self):
|
|
for arg in None, '', {True: True}:
|
|
with pytest.raises(docker.errors.NullResource) as excinfo:
|
|
self.client.inspect_container(arg)
|
|
|
|
assert excinfo.value.args[0] == 'Resource ID was not provided'
|
|
|
|
def test_container_stats(self):
|
|
self.client.stats(fake_api.FAKE_CONTAINER_ID)
|
|
|
|
fake_request.assert_called_with(
|
|
'GET',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/stats',
|
|
stream=True,
|
|
timeout=60,
|
|
params={'stream': True}
|
|
)
|
|
|
|
def test_container_stats_without_streaming(self):
|
|
self.client.stats(fake_api.FAKE_CONTAINER_ID, stream=False)
|
|
|
|
fake_request.assert_called_with(
|
|
'GET',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/stats',
|
|
timeout=60,
|
|
params={'stream': False}
|
|
)
|
|
|
|
def test_container_stats_with_one_shot(self):
|
|
self.client.stats(
|
|
fake_api.FAKE_CONTAINER_ID, stream=False, one_shot=True)
|
|
|
|
fake_request.assert_called_with(
|
|
'GET',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/stats',
|
|
timeout=60,
|
|
params={'stream': False, 'one-shot': True}
|
|
)
|
|
|
|
def test_container_top(self):
|
|
self.client.top(fake_api.FAKE_CONTAINER_ID)
|
|
|
|
fake_request.assert_called_with(
|
|
'GET',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/top',
|
|
params={},
|
|
timeout=DEFAULT_TIMEOUT_SECONDS
|
|
)
|
|
|
|
def test_container_top_with_psargs(self):
|
|
self.client.top(fake_api.FAKE_CONTAINER_ID, 'waux')
|
|
|
|
fake_request.assert_called_with(
|
|
'GET',
|
|
url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/top',
|
|
params={'ps_args': 'waux'},
|
|
timeout=DEFAULT_TIMEOUT_SECONDS
|
|
)
|
|
|
|
@requires_api_version('1.22')
|
|
def test_container_update(self):
|
|
self.client.update_container(
|
|
fake_api.FAKE_CONTAINER_ID, mem_limit='2k', cpu_shares=124,
|
|
blkio_weight=345
|
|
)
|
|
args = fake_request.call_args
|
|
assert args[0][1] == (url_prefix + 'containers/' +
|
|
fake_api.FAKE_CONTAINER_ID + '/update')
|
|
assert json.loads(args[1]['data']) == {
|
|
'Memory': 2 * 1024, 'CpuShares': 124, 'BlkioWeight': 345
|
|
}
|
|
assert args[1]['headers']['Content-Type'] == 'application/json'
|