Merge branch 'master' of github.com:docker/docker-py

This commit is contained in:
Joffrey F 2015-05-13 13:24:08 -07:00
commit f044b5e3f7
9 changed files with 234 additions and 612 deletions

View File

@ -526,7 +526,7 @@ class Client(requests.Session):
'exec_start instead', DeprecationWarning
)
create_res = self.exec_create(
container, cmd, detach, stdout, stderr, tty
container, cmd, stdout, stderr, tty
)
return self.exec_start(create_res, detach, tty, stream)
@ -730,7 +730,7 @@ class Client(requests.Session):
raise errors.DeprecatedMethod(
'insert is not available for API version >=1.12'
)
api_url = self._url("/images/{0}/insert".fornat(image))
api_url = self._url("/images/{0}/insert".format(image))
params = {
'url': url,
'path': path
@ -1059,6 +1059,12 @@ class Client(requests.Session):
url = self._url("/containers/{0}/start".format(container))
if not start_config:
start_config = None
elif utils.compare_version('1.15', self._version) > 0:
warnings.warn(
'Passing host config parameters in start() is deprecated. '
'Please use host_config in create_container instead!',
DeprecationWarning
)
res = self._post_json(url, data=start_config)
self._raise_for_status(res)

View File

@ -577,6 +577,7 @@ def create_container_config(
'Entrypoint': entrypoint,
'CpuShares': cpu_shares,
'Cpuset': cpuset,
'CpusetCpus': cpuset,
'WorkingDir': working_dir,
'MemorySwap': memswap_limit,
'HostConfig': host_config,

View File

@ -188,8 +188,7 @@ character, bytes are assumed as an intended unit.
`volumes_from` and `dns` arguments raise [TypeError](
https://docs.python.org/3.4/library/exceptions.html#TypeError) exception if
they are used against v1.10 and above of the Docker remote API. Those
arguments should be passed to `start()` instead, or as part of the `host_config`
dictionary.
arguments should be passed as part of the `host_config` dictionary.
**Params**:
@ -715,83 +714,9 @@ Identical to the `docker search` command.
Similar to the `docker start` command, but doesn't support attach options. Use
`.logs()` to recover `stdout`/`stderr`.
`binds` allows to bind a directory in the host to the container. See [Using
volumes](volumes.md) for more information.
`port_bindings` exposes container ports to the host.
See [Port bindings](port-bindings.md) for more information.
`lxc_conf` allows to pass LXC configuration options using a dictionary.
`privileged` starts the container in privileged mode.
[Links](http://docs.docker.io/en/latest/use/working_with_links_names/) can be
specified with the `links` argument. They can either be specified as a
dictionary mapping name to alias or as a list of `(name, alias)` tuples.
`dns` and `volumes_from` are only available if they are used with version v1.10
of docker remote API. Otherwise they are ignored.
`network_mode` is available since v1.11 and sets the Network mode for the
container ('bridge': creates a new network stack for the container on the
Docker bridge, 'none': no networking for this container, 'container:[name|id]':
reuses another container network stack), 'host': use the host network stack
inside the container.
`restart_policy` is available since v1.2.0 and sets the RestartPolicy for how a
container should or should not be restarted on exit. By default the policy is
set to no meaning do not restart the container when it exits. The user may
specify the restart policy as a dictionary for example:
```python
{
"MaximumRetryCount": 0,
"Name": "always"
}
```
For always restarting the container on exit or can specify to restart the
container to restart on failure and can limit number of restarts. For example:
```python
{
"MaximumRetryCount": 5,
"Name": "on-failure"
}
```
`cap_add` and `cap_drop` are available since v1.2.0 and can be used to add or
drop certain capabilities. The user may specify the capabilities as an array
for example:
```python
[
"SYS_ADMIN",
"MKNOD"
]
```
**Params**:
* container (str): The container to start
* binds: Volumes to bind
* port_bindings (dict): Port bindings. See note above
* lxc_conf (dict): LXC config
* publish_all_ports (bool): Whether to publish all ports to the host
* links (dict or list of tuples): See note above
* privileged (bool): Give extended privileges to this container
* dns (list): Set custom DNS servers
* dns_search (list): DNS search domains
* volumes_from (str or list): List of container names or Ids to get volumes
from. Optionally a single string joining container id's with commas
* network_mode (str): One of `['bridge', None, 'container:<name|id>',
'host']`
* restart_policy (dict): See note above. "Name" param must be one of
`['on-failure', 'always']`
* cap_add (list of str): See note above
* cap_drop (list of str): See note above
* extra_hosts (dict): custom host-to-IP mappings (host:ip)
* pid_mode (str): if set to "host", use the host PID namespace inside the
container
* security_opt (list): A list of string values to customize labels for MLS systems, such as SELinux.
* ulimits (list): A list of dicts or `docker.utils.Ulimit` objects.
**Deprecation warning:** For API version > 1.15, it is highly recommended to
provide host config options in the
[`host_config` parameter of `create_container`](#create_container)
```python
>>> from docker import Client

View File

@ -1,10 +1,15 @@
# Access to devices on the host
If you need to directly expose some host devices to a container, you can use
the devices parameter in the `Client.start` method as shown below
the devices parameter in the `host_config` param in `Client.create_container`
as shown below:
```python
c.start(container_id, devices=['/dev/sda:/dev/xvda:rwm'])
c.create_container(
'busybox', 'true', host_config=docker.utils.create_host_config(devices=[
'/dev/sda:/dev/xvda:rwm'
])
)
```
Each string is a single mapping using the colon (':') as the separator. So the

View File

@ -1,6 +1,8 @@
# HostConfig object
The Docker Remote API introduced [support for HostConfig in version 1.15](http://docs.docker.com/reference/api/docker_remote_api_v1.15/#create-a-container). This object contains all the parameters you can pass to `Client.start`.
The Docker Remote API introduced [support for HostConfig in version 1.15](http://docs.docker.com/reference/api/docker_remote_api_v1.15/#create-a-container). This object contains all the parameters you could previously pass to `Client.start`.
*It is highly recommended that users pass the HostConfig in the `host_config`*
*param of `Client.create_container` instead of `Client.start`*
## HostConfig helper

View File

@ -1,38 +1,39 @@
# Port bindings
Port bindings is done in two parts. Firstly, by providing a list of ports to
open inside the container in the `Client().create_container()` method.
Bindings are declared in the `host_config` parameter.
```python
container_id = c.create_container('busybox', 'ls', ports=[1111, 2222])
container_id = c.create_container(
'busybox', 'ls', ports=[1111, 2222],
host_config=docker.utils.create_host_config(port_bindings={
1111: 4567,
2222: None
})
)
```
Bindings are then declared in the `Client.start` method.
```python
c.start(container_id, port_bindings={1111: 4567, 2222: None})
```
You can limit the host address on which the port will be exposed like such:
```python
c.start(container_id, port_bindings={1111: ('127.0.0.1', 4567)})
docker.utils.create_host_config(port_bindings={1111: ('127.0.0.1', 4567)})
```
Or without host port assignment:
```python
c.start(container_id, port_bindings={1111: ('127.0.0.1',)})
docker.utils.create_host_config(port_bindings={1111: ('127.0.0.1',)})
```
If you wish to use UDP instead of TCP (default), you need to declare it
like such in both the `create_container()` and `start()` calls:
If you wish to use UDP instead of TCP (default), you need to declare ports
as such in both the config and host config:
```python
container_id = c.create_container(
'busybox',
'ls',
ports=[(1111, 'udp'), 2222]
'busybox', 'ls', ports=[(1111, 'udp'), 2222],
host_config=docker.utils.create_host_config(port_bindings={
'1111/udp': 4567, 2222: None
})
)
c.start(container_id, port_bindings={'1111/udp': 4567, 2222: None})
```

View File

@ -1,25 +1,21 @@
# Using volumes
Volume declaration is done in two parts. First, you have to provide
a list of mountpoints to the `Client().create_container()` method.
Volume declaration is done in two parts. Provide a list of mountpoints to
the `Client().create_container()` method, and declare mappings in the
`host_config` section.
```python
container_id = c.create_container('busybox', 'ls', volumes=['/mnt/vol1', '/mnt/vol2'])
```
Volume mappings are then declared inside the `Client.start` method like this:
```python
c.start(container_id, binds={
'/home/user1/':
{
container_id = c.create_container(
'busybox', 'ls', volumes=['/mnt/vol1', '/mnt/vol2'],
host_config=docker.utils.create_host_config(binds={
'/home/user1/': {
'bind': '/mnt/vol2',
'ro': False
},
'/var/www':
{
'/var/www': {
'bind': '/mnt/vol1',
'ro': True
}
})
})
)
```

View File

@ -242,113 +242,6 @@ class TestCreateContainerWithRoBinds(BaseTestCase):
self.assertFalse(inspect_data['VolumesRW'][mount_dest])
class TestStartContainerWithBinds(BaseTestCase):
def runTest(self):
mount_dest = '/mnt'
mount_origin = tempfile.mkdtemp()
self.tmp_folders.append(mount_origin)
filename = 'shared.txt'
shared_file = os.path.join(mount_origin, filename)
binds = {
mount_origin: {
'bind': mount_dest,
'ro': False,
},
}
with open(shared_file, 'w'):
container = self.client.create_container(
'busybox', ['ls', mount_dest], volumes={mount_dest: {}}
)
container_id = container['Id']
self.client.start(container_id, binds=binds)
self.tmp_containers.append(container_id)
exitcode = self.client.wait(container_id)
self.assertEqual(exitcode, 0)
logs = self.client.logs(container_id)
os.unlink(shared_file)
if six.PY3:
logs = logs.decode('utf-8')
self.assertIn(filename, logs)
inspect_data = self.client.inspect_container(container_id)
self.assertIn('Volumes', inspect_data)
self.assertIn(mount_dest, inspect_data['Volumes'])
self.assertEqual(mount_origin, inspect_data['Volumes'][mount_dest])
self.assertIn(mount_dest, inspect_data['VolumesRW'])
self.assertTrue(inspect_data['VolumesRW'][mount_dest])
class TestStartContainerWithRoBinds(BaseTestCase):
def runTest(self):
mount_dest = '/mnt'
mount_origin = tempfile.mkdtemp()
self.tmp_folders.append(mount_origin)
filename = 'shared.txt'
shared_file = os.path.join(mount_origin, filename)
binds = {
mount_origin: {
'bind': mount_dest,
'ro': True,
},
}
with open(shared_file, 'w'):
container = self.client.create_container(
'busybox', ['ls', mount_dest], volumes={mount_dest: {}}
)
container_id = container['Id']
self.client.start(container_id, binds=binds)
self.tmp_containers.append(container_id)
exitcode = self.client.wait(container_id)
self.assertEqual(exitcode, 0)
logs = self.client.logs(container_id)
os.unlink(shared_file)
if six.PY3:
logs = logs.decode('utf-8')
self.assertIn(filename, logs)
inspect_data = self.client.inspect_container(container_id)
self.assertIn('Volumes', inspect_data)
self.assertIn(mount_dest, inspect_data['Volumes'])
self.assertEqual(mount_origin, inspect_data['Volumes'][mount_dest])
self.assertIn('VolumesRW', inspect_data)
self.assertIn(mount_dest, inspect_data['VolumesRW'])
self.assertFalse(inspect_data['VolumesRW'][mount_dest])
class TestStartContainerWithFileBind(BaseTestCase):
def runTest(self):
mount_dest = '/myfile/myfile'
mount_origin = tempfile.mktemp()
try:
binds = {
mount_origin: {
'bind': mount_dest,
'ro': True
},
}
with open(mount_origin, 'w') as f:
f.write('sakuya izayoi')
container = self.client.create_container(
'busybox', ['cat', mount_dest], volumes={mount_dest: {}}
)
self.client.start(container, binds=binds)
exitcode = self.client.wait(container)
self.assertEqual(exitcode, 0)
logs = self.client.logs(container)
if six.PY3:
logs = logs.decode('utf-8')
self.assertIn('sakuya izayoi', logs)
finally:
os.unlink(mount_origin)
class TestCreateContainerWithLogConfig(BaseTestCase):
def runTest(self):
config = docker.utils.LogConfig(
@ -388,21 +281,6 @@ class TestCreateContainerReadOnlyFs(BaseTestCase):
self.assertNotEqual(res, 0)
@unittest.skipIf(not EXEC_DRIVER_IS_NATIVE, 'Exec driver not native')
class TestStartContainerReadOnlyFs(BaseTestCase):
def runTest(self):
# Presumably a bug in 1.5.0
# https://github.com/docker/docker/issues/10695
ctnr = self.client.create_container(
'busybox', ['mkdir', '/shrine'],
)
self.assertIn('Id', ctnr)
self.tmp_containers.append(ctnr['Id'])
self.client.start(ctnr, read_only=True)
# res = self.client.wait(ctnr)
# self.assertNotEqual(res, 0)
class TestCreateContainerWithName(BaseTestCase):
def runTest(self):
res = self.client.create_container('busybox', 'true', name='foobar')
@ -490,29 +368,6 @@ class TestCreateContainerPrivileged(BaseTestCase):
self.assertEqual(inspect['Config']['Privileged'], True)
class TestStartContainerPrivileged(BaseTestCase):
def runTest(self):
res = self.client.create_container('busybox', 'true')
self.assertIn('Id', res)
self.tmp_containers.append(res['Id'])
self.client.start(res['Id'], privileged=True)
inspect = self.client.inspect_container(res['Id'])
self.assertIn('Config', inspect)
self.assertIn('Id', inspect)
self.assertTrue(inspect['Id'].startswith(res['Id']))
self.assertIn('Image', inspect)
self.assertIn('State', inspect)
self.assertIn('Running', inspect['State'])
if not inspect['State']['Running']:
self.assertIn('ExitCode', inspect['State'])
self.assertEqual(inspect['State']['ExitCode'], 0)
# Since Nov 2013, the Privileged flag is no longer part of the
# container's config exposed via the API (safety concerns?).
#
if 'Privileged' in inspect['Config']:
self.assertEqual(inspect['Config']['Privileged'], True)
class TestWait(BaseTestCase):
def runTest(self):
res = self.client.create_container('busybox', ['sleep', '3'])
@ -754,34 +609,6 @@ class TestPort(BaseTestCase):
self.client.kill(id)
class TestStartWithPortBindings(BaseTestCase):
def runTest(self):
port_bindings = {
'1111': ('127.0.0.1', '4567'),
'2222': ('127.0.0.1', '4568')
}
container = self.client.create_container(
'busybox', ['sleep', '60'], ports=list(port_bindings.keys())
)
id = container['Id']
self.client.start(container, port_bindings=port_bindings)
# Call the port function on each biding and compare expected vs actual
for port in port_bindings:
actual_bindings = self.client.port(container, port)
port_binding = actual_bindings.pop()
ip, host_port = port_binding['HostIp'], port_binding['HostPort']
self.assertEqual(ip, port_bindings[port][0])
self.assertEqual(host_port, port_bindings[port][1])
self.client.kill(id)
class TestMacAddress(BaseTestCase):
def runTest(self):
mac_address_expected = "02:42:ac:11:00:0a"
@ -949,101 +776,6 @@ class TestCreateContainerWithLinks(BaseTestCase):
self.assertIn('{0}_ENV_FOO=1'.format(link_env_prefix2), logs)
class TestStartContainerWithVolumesFrom(BaseTestCase):
def runTest(self):
vol_names = ['foobar_vol0', 'foobar_vol1']
res0 = self.client.create_container(
'busybox', 'true',
name=vol_names[0])
container1_id = res0['Id']
self.tmp_containers.append(container1_id)
self.client.start(container1_id)
res1 = self.client.create_container(
'busybox', 'true',
name=vol_names[1])
container2_id = res1['Id']
self.tmp_containers.append(container2_id)
self.client.start(container2_id)
with self.assertRaises(docker.errors.DockerException):
res2 = self.client.create_container(
'busybox', 'cat',
detach=True, stdin_open=True,
volumes_from=vol_names)
res2 = self.client.create_container(
'busybox', 'cat',
detach=True, stdin_open=True)
container3_id = res2['Id']
self.tmp_containers.append(container3_id)
self.client.start(container3_id, volumes_from=vol_names)
info = self.client.inspect_container(res2['Id'])
self.assertCountEqual(info['HostConfig']['VolumesFrom'], vol_names)
class TestStartContainerWithUlimits(BaseTestCase):
def runTest(self):
ulimit = docker.utils.Ulimit(name='nofile', soft=4096, hard=4096)
res0 = self.client.create_container('busybox', 'true')
container1_id = res0['Id']
self.tmp_containers.append(container1_id)
self.client.start(container1_id, ulimits=[ulimit])
info = self.client.inspect_container(container1_id)
self.assertCountEqual(info['HostConfig']['Ulimits'], [ulimit])
class TestStartContainerWithLinks(BaseTestCase):
def runTest(self):
res0 = self.client.create_container(
'busybox', 'cat',
detach=True, stdin_open=True,
environment={'FOO': '1'})
container1_id = res0['Id']
self.tmp_containers.append(container1_id)
self.client.start(container1_id)
res1 = self.client.create_container(
'busybox', 'cat',
detach=True, stdin_open=True,
environment={'FOO': '1'})
container2_id = res1['Id']
self.tmp_containers.append(container2_id)
self.client.start(container2_id)
# we don't want the first /
link_path1 = self.client.inspect_container(container1_id)['Name'][1:]
link_alias1 = 'mylink1'
link_env_prefix1 = link_alias1.upper()
link_path2 = self.client.inspect_container(container2_id)['Name'][1:]
link_alias2 = 'mylink2'
link_env_prefix2 = link_alias2.upper()
res2 = self.client.create_container('busybox', 'env')
container3_id = res2['Id']
self.tmp_containers.append(container3_id)
self.client.start(
container3_id,
links={link_path1: link_alias1, link_path2: link_alias2}
)
self.assertEqual(self.client.wait(container3_id), 0)
logs = self.client.logs(container3_id)
if six.PY3:
logs = logs.decode('utf-8')
self.assertIn('{0}_NAME='.format(link_env_prefix1), logs)
self.assertIn('{0}_ENV_FOO=1'.format(link_env_prefix1), logs)
self.assertIn('{0}_NAME='.format(link_env_prefix2), logs)
self.assertIn('{0}_ENV_FOO=1'.format(link_env_prefix2), logs)
class TestRestartingContainer(BaseTestCase):
def runTest(self):
container = self.client.create_container(
@ -1190,20 +922,6 @@ class TestCreateContainerWithHostPidMode(BaseTestCase):
self.assertEqual(host_config['PidMode'], 'host')
class TestStartContainerWithHostPidMode(BaseTestCase):
def runTest(self):
ctnr = self.client.create_container(
'busybox', 'true'
)
self.assertIn('Id', ctnr)
self.tmp_containers.append(ctnr['Id'])
self.client.start(ctnr, pid_mode='host')
inspect = self.client.inspect_container(ctnr)
self.assertIn('HostConfig', inspect)
host_config = inspect['HostConfig']
self.assertIn('PidMode', host_config)
self.assertEqual(host_config['PidMode'], 'host')
#################
# LINKS TESTS #
#################

View File

@ -47,6 +47,7 @@ except ImportError:
DEFAULT_TIMEOUT_SECONDS = docker.client.constants.DEFAULT_TIMEOUT_SECONDS
warnings.simplefilter('error')
warnings.filterwarnings('error')
create_host_config = docker.utils.create_host_config
@ -489,6 +490,7 @@ class DockerClientTest(Cleanup, base.BaseTestCase):
"StdinOnce": false,
"NetworkDisabled": false,
"Cpuset": "0,1",
"CpusetCpus": "0,1",
"MemorySwap": 0}'''))
self.assertEqual(args[1]['headers'],
{'Content-Type': 'application/json'})
@ -972,244 +974,210 @@ class DockerClientTest(Cleanup, base.BaseTestCase):
)
def test_start_container_with_lxc_conf(self):
try:
self.client.start(
fake_api.FAKE_CONTAINER_ID,
lxc_conf={'lxc.conf.k': 'lxc.conf.value'}
)
except Exception as e:
self.fail('Command should not raise exception: {0}'.format(e))
args = fake_request.call_args
self.assertEqual(
args[0][0],
url_prefix + 'containers/3cc2351ab11b/start'
)
self.assertEqual(
json.loads(args[1]['data']),
{"LxcConf": [{"Value": "lxc.conf.value", "Key": "lxc.conf.k"}]}
)
self.assertEqual(
args[1]['headers'],
{'Content-Type': 'application/json'}
)
self.assertEqual(
args[1]['timeout'],
DEFAULT_TIMEOUT_SECONDS
)
if six.PY2:
try:
self.client.start(
fake_api.FAKE_CONTAINER_ID,
lxc_conf={'lxc.conf.k': 'lxc.conf.value'}
)
except DeprecationWarning as e:
return
except Exception as e:
self.fail('Command should not raise exception: {0}'.format(e))
else:
self.fail('Expected a DeprecationWarning')
else:
with self.assertWarns(DeprecationWarning):
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):
try:
self.client.start(
fake_api.FAKE_CONTAINER_ID,
lxc_conf=[{'Key': 'lxc.conf.k', 'Value': 'lxc.conf.value'}]
)
except Exception as e:
self.fail('Command should not raise exception: {0}'.format(e))
args = fake_request.call_args
self.assertEqual(args[0][0], url_prefix +
'containers/3cc2351ab11b/start')
self.assertEqual(
json.loads(args[1]['data']),
{"LxcConf": [{"Key": "lxc.conf.k", "Value": "lxc.conf.value"}]}
)
self.assertEqual(args[1]['headers'],
{'Content-Type': 'application/json'})
self.assertEqual(
args[1]['timeout'],
DEFAULT_TIMEOUT_SECONDS
)
if six.PY2:
try:
self.client.start(
fake_api.FAKE_CONTAINER_ID,
lxc_conf=[{'Key': 'lxc.conf.k', 'Value': 'lxc.conf.value'}]
)
except DeprecationWarning as e:
return
except Exception as e:
self.fail('Command should not raise exception: {0}'.format(e))
else:
self.fail('Expected a DeprecationWarning')
else:
with self.assertWarns(DeprecationWarning):
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):
try:
mount_dest = '/mnt'
mount_origin = '/tmp'
self.client.start(fake_api.FAKE_CONTAINER_ID,
binds={mount_origin: {
"bind": mount_dest,
"ro": True
}})
except Exception as e:
self.fail('Command should not raise exception: {0}'.format(e))
mount_dest = '/mnt'
mount_origin = '/tmp'
args = fake_request.call_args
self.assertEqual(args[0][0], url_prefix +
'containers/3cc2351ab11b/start')
self.assertEqual(
json.loads(args[1]['data']), {"Binds": ["/tmp:/mnt:ro"]}
)
self.assertEqual(args[1]['headers'],
{'Content-Type': 'application/json'})
self.assertEqual(
args[1]['timeout'],
DEFAULT_TIMEOUT_SECONDS)
if six.PY2:
try:
self.client.start(
fake_api.FAKE_CONTAINER_ID, binds={
mount_origin: {
"bind": mount_dest,
"ro": True
}
}
)
except DeprecationWarning as e:
return
except Exception as e:
self.fail('Command should not raise exception: {0}'.format(e))
else:
self.fail('Expected a DeprecationWarning')
else:
with self.assertWarns(DeprecationWarning):
self.client.start(
fake_api.FAKE_CONTAINER_ID, binds={
mount_origin: {
"bind": mount_dest,
"ro": True
}
}
)
def test_start_container_with_binds_rw(self):
try:
mount_dest = '/mnt'
mount_origin = '/tmp'
self.client.start(fake_api.FAKE_CONTAINER_ID,
binds={mount_origin: {
"bind": mount_dest, "ro": False}})
except Exception as e:
self.fail('Command should not raise exception: {0}'.format(e))
args = fake_request.call_args
self.assertEqual(args[0][0], url_prefix +
'containers/3cc2351ab11b/start')
self.assertEqual(
json.loads(args[1]['data']), {"Binds": ["/tmp:/mnt:rw"]}
)
self.assertEqual(args[1]['headers'],
{'Content-Type': 'application/json'})
self.assertEqual(
args[1]['timeout'],
DEFAULT_TIMEOUT_SECONDS
)
mount_dest = '/mnt'
mount_origin = '/tmp'
if six.PY2:
try:
self.client.start(
fake_api.FAKE_CONTAINER_ID, binds={
mount_origin: {"bind": mount_dest, "ro": False}
}
)
except DeprecationWarning as e:
return
except Exception as e:
self.fail('Command should not raise exception: {0}'.format(e))
else:
self.fail('Expected a DeprecationWarning')
else:
with self.assertWarns(DeprecationWarning):
self.client.start(
fake_api.FAKE_CONTAINER_ID, binds={
mount_origin: {"bind": mount_dest, "ro": False}
}
)
def test_start_container_with_port_binds(self):
self.maxDiff = None
try:
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',)]
})
except Exception as e:
self.fail('Command should not raise exception: {0}'.format(e))
args = fake_request.call_args
self.assertEqual(args[0][0], url_prefix +
'containers/3cc2351ab11b/start')
data = json.loads(args[1]['data'])
self.assertTrue('1111/tcp' in data['PortBindings'])
self.assertTrue('2222/tcp' in data['PortBindings'])
self.assertTrue('3333/udp' in data['PortBindings'])
self.assertTrue('4444/tcp' in data['PortBindings'])
self.assertTrue('5555/tcp' in data['PortBindings'])
self.assertTrue('6666/tcp' in data['PortBindings'])
self.assertEqual(
[{"HostPort": "", "HostIp": ""}],
data['PortBindings']['1111/tcp']
)
self.assertEqual(
[{"HostPort": "2222", "HostIp": ""}],
data['PortBindings']['2222/tcp']
)
self.assertEqual(
[{"HostPort": "3333", "HostIp": ""}],
data['PortBindings']['3333/udp']
)
self.assertEqual(
[{"HostPort": "", "HostIp": "127.0.0.1"}],
data['PortBindings']['4444/tcp']
)
self.assertEqual(
[{"HostPort": "5555", "HostIp": "127.0.0.1"}],
data['PortBindings']['5555/tcp']
)
self.assertEqual(len(data['PortBindings']['6666/tcp']), 2)
self.assertEqual(args[1]['headers'],
{'Content-Type': 'application/json'})
self.assertEqual(
args[1]['timeout'],
DEFAULT_TIMEOUT_SECONDS
)
if six.PY2:
try:
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',)]
})
except DeprecationWarning as e:
return
except Exception as e:
self.fail('Command should not raise exception: {0}'.format(e))
else:
self.fail('Expected a DeprecationWarning')
else:
with self.assertWarns(DeprecationWarning):
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):
# one link
try:
link_path = 'path'
alias = 'alias'
self.client.start(fake_api.FAKE_CONTAINER_ID,
links={link_path: alias})
except Exception as e:
self.fail('Command should not raise exception: {0}'.format(e))
link_path = 'path'
alias = 'alias'
args = fake_request.call_args
self.assertEqual(
args[0][0],
url_prefix + 'containers/3cc2351ab11b/start'
)
self.assertEqual(
json.loads(args[1]['data']), {"Links": ["path:alias"]}
)
self.assertEqual(
args[1]['headers'],
{'Content-Type': 'application/json'}
)
if six.PY2:
try:
self.client.start(fake_api.FAKE_CONTAINER_ID,
links={link_path: alias})
except DeprecationWarning as e:
return
except Exception as e:
self.fail('Command should not raise exception: {0}'.format(e))
else:
self.fail('Expected a DeprecationWarning')
else:
with self.assertWarns(DeprecationWarning):
self.client.start(
fake_api.FAKE_CONTAINER_ID, links={link_path: alias}
)
def test_start_container_with_multiple_links(self):
try:
link_path = 'path'
alias = 'alias'
self.client.start(
fake_api.FAKE_CONTAINER_ID,
links={
link_path + '1': alias + '1',
link_path + '2': alias + '2'
}
)
except Exception as e:
self.fail('Command should not raise exception: {0}'.format(e))
args = fake_request.call_args
self.assertEqual(
args[0][0],
url_prefix + 'containers/3cc2351ab11b/start'
)
self.assertEqual(
json.loads(args[1]['data']),
{"Links": ["path1:alias1", "path2:alias2"]}
)
self.assertEqual(
args[1]['headers'],
{'Content-Type': 'application/json'}
)
link_path = 'path'
alias = 'alias'
if six.PY2:
try:
self.client.start(
fake_api.FAKE_CONTAINER_ID,
links={
link_path + '1': alias + '1',
link_path + '2': alias + '2'
}
)
except DeprecationWarning as e:
return
except Exception as e:
self.fail('Command should not raise exception: {0}'.format(e))
else:
self.fail('Expected a DeprecationWarning')
else:
with self.assertWarns(DeprecationWarning):
self.client.start(
fake_api.FAKE_CONTAINER_ID,
links={
link_path + '1': alias + '1',
link_path + '2': alias + '2'
}
)
def test_start_container_with_links_as_list_of_tuples(self):
# one link
try:
link_path = 'path'
alias = 'alias'
self.client.start(fake_api.FAKE_CONTAINER_ID,
links=[(link_path, alias)])
except Exception as e:
self.fail('Command should not raise exception: {0}'.format(e))
args = fake_request.call_args
self.assertEqual(
args[0][0],
url_prefix + 'containers/3cc2351ab11b/start'
)
self.assertEqual(
json.loads(args[1]['data']), {"Links": ["path:alias"]}
)
self.assertEqual(
args[1]['headers'], {'Content-Type': 'application/json'}
)
link_path = 'path'
alias = 'alias'
if six.PY2:
try:
self.client.start(fake_api.FAKE_CONTAINER_ID,
links=[(link_path, alias)])
except DeprecationWarning as e:
return
except Exception as e:
self.fail('Command should not raise exception: {0}'.format(e))
else:
self.fail('Expected a DeprecationWarning')
else:
with self.assertWarns(DeprecationWarning):
self.client.start(fake_api.FAKE_CONTAINER_ID,
links=[(link_path, alias)])
def test_start_container_privileged(self):
try:
self.client.start(fake_api.FAKE_CONTAINER_ID, privileged=True)
except Exception as e:
self.fail('Command should not raise exception: {0}'.format(e))
args = fake_request.call_args
self.assertEqual(
args[0][0],
url_prefix + 'containers/3cc2351ab11b/start'
)
self.assertEqual(json.loads(args[1]['data']), {"Privileged": True})
self.assertEqual(args[1]['headers'],
{'Content-Type': 'application/json'})
self.assertEqual(
args[1]['timeout'],
DEFAULT_TIMEOUT_SECONDS
)
if six.PY2:
try:
self.client.start(fake_api.FAKE_CONTAINER_ID, privileged=True)
except DeprecationWarning as e:
return
except Exception as e:
self.fail('Command should not raise exception: {0}'.format(e))
else:
self.fail('Expected a DeprecationWarning')
else:
with self.assertWarns(DeprecationWarning):
self.client.start(fake_api.FAKE_CONTAINER_ID, privileged=True)
def test_start_container_with_dict_instead_of_id(self):
try: