mirror of https://github.com/docker/docker-py.git
Merge pull request #304 from shreyu86/dev-restart-policy
Restart Policy for Containers Implemented fixes #302
This commit is contained in:
commit
e6af420aeb
23
README.md
23
README.md
|
|
@ -232,7 +232,7 @@ Identical to the `docker search` command.
|
||||||
```python
|
```python
|
||||||
c.start(container, binds=None, port_bindings=None, lxc_conf=None,
|
c.start(container, binds=None, port_bindings=None, lxc_conf=None,
|
||||||
publish_all_ports=False, links=None, privileged=False,
|
publish_all_ports=False, links=None, privileged=False,
|
||||||
dns=None, dns_search=None, volumes_from=None, network_mode=None)
|
dns=None, dns_search=None, volumes_from=None, network_mode=None, restart_policy=None)
|
||||||
```
|
```
|
||||||
|
|
||||||
Similar to the `docker start` command, but doesn't support attach
|
Similar to the `docker start` command, but doesn't support attach
|
||||||
|
|
@ -258,6 +258,27 @@ docker bridge, 'none': no networking for this container, 'container:[name|id]':
|
||||||
reuses another container network stack), 'host': use the host network stack
|
reuses another container network stack), 'host': use the host network stack
|
||||||
inside the container.
|
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:
|
||||||
|
for example:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"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:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"MaximumRetryCount": 5,
|
||||||
|
"Name": "on-failure"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
c.stop(container, timeout=10)
|
c.stop(container, timeout=10)
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -806,7 +806,8 @@ class Client(requests.Session):
|
||||||
|
|
||||||
def start(self, container, binds=None, port_bindings=None, lxc_conf=None,
|
def start(self, container, binds=None, port_bindings=None, lxc_conf=None,
|
||||||
publish_all_ports=False, links=None, privileged=False,
|
publish_all_ports=False, links=None, privileged=False,
|
||||||
dns=None, dns_search=None, volumes_from=None, network_mode=None):
|
dns=None, dns_search=None, volumes_from=None, network_mode=None,
|
||||||
|
restart_policy=None):
|
||||||
if isinstance(container, dict):
|
if isinstance(container, dict):
|
||||||
container = container.get('Id')
|
container = container.get('Id')
|
||||||
|
|
||||||
|
|
@ -859,13 +860,15 @@ class Client(requests.Session):
|
||||||
if volumes_from is not None:
|
if volumes_from is not None:
|
||||||
warnings.warn(warning_message.format('volumes_from'),
|
warnings.warn(warning_message.format('volumes_from'),
|
||||||
DeprecationWarning)
|
DeprecationWarning)
|
||||||
|
|
||||||
if dns_search:
|
if dns_search:
|
||||||
start_config['DnsSearch'] = dns_search
|
start_config['DnsSearch'] = dns_search
|
||||||
|
|
||||||
if network_mode:
|
if network_mode:
|
||||||
start_config['NetworkMode'] = network_mode
|
start_config['NetworkMode'] = network_mode
|
||||||
|
|
||||||
|
if restart_policy:
|
||||||
|
start_config['RestartPolicy'] = restart_policy
|
||||||
|
|
||||||
url = self._url("/containers/{0}/start".format(container))
|
url = self._url("/containers/{0}/start".format(container))
|
||||||
res = self._post_json(url, data=start_config)
|
res = self._post_json(url, data=start_config)
|
||||||
self._raise_for_status(res)
|
self._raise_for_status(res)
|
||||||
|
|
|
||||||
|
|
@ -612,6 +612,23 @@ class TestStartContainerWithLinks(BaseTestCase):
|
||||||
self.assertIn('{0}_NAME='.format(link_env_prefix2), logs)
|
self.assertIn('{0}_NAME='.format(link_env_prefix2), logs)
|
||||||
self.assertIn('{0}_ENV_FOO=1'.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('busybox', ['false'])
|
||||||
|
id = container['Id']
|
||||||
|
self.client.start(id, restart_policy={
|
||||||
|
{
|
||||||
|
"Name": "on-failure",
|
||||||
|
"MaximumRetryCount": 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
self.client.wait(id)
|
||||||
|
self.client.remove_container(id)
|
||||||
|
containers = self.client.containers(all=True)
|
||||||
|
res = [x for x in containers if 'Id' in x and x['Id'].startswith(id)]
|
||||||
|
self.assertEqual(len(res), 0)
|
||||||
|
|
||||||
#################
|
#################
|
||||||
# LINKS TESTS #
|
# LINKS TESTS #
|
||||||
#################
|
#################
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
# Copyright 2013 dotCloud inc.
|
# Copyright 2013 dotCloud inc.
|
||||||
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
# You may obtain a copy of the License at
|
# You may obtain a copy of the License at
|
||||||
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
@ -60,6 +60,7 @@ def fake_resp(url, data=None, **kwargs):
|
||||||
status_code, content = fake_api.fake_responses[url]()
|
status_code, content = fake_api.fake_responses[url]()
|
||||||
return response(status_code=status_code, content=content)
|
return response(status_code=status_code, content=content)
|
||||||
|
|
||||||
|
|
||||||
fake_request = mock.Mock(side_effect=fake_resp)
|
fake_request = mock.Mock(side_effect=fake_resp)
|
||||||
url_prefix = 'http+unix://var/run/docker.sock/v{0}/'.format(
|
url_prefix = 'http+unix://var/run/docker.sock/v{0}/'.format(
|
||||||
docker.client.DEFAULT_DOCKER_API_VERSION)
|
docker.client.DEFAULT_DOCKER_API_VERSION)
|
||||||
|
|
@ -616,7 +617,7 @@ class DockerClientTest(Cleanup, unittest.TestCase):
|
||||||
mount_origin = '/tmp'
|
mount_origin = '/tmp'
|
||||||
self.client.start(fake_api.FAKE_CONTAINER_ID,
|
self.client.start(fake_api.FAKE_CONTAINER_ID,
|
||||||
binds={mount_origin: {
|
binds={mount_origin: {
|
||||||
"bind": mount_dest, "ro": False}})
|
"bind": mount_dest, "ro": False}})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.fail('Command should not raise exception: {0}'.format(e))
|
self.fail('Command should not raise exception: {0}'.format(e))
|
||||||
|
|
||||||
|
|
@ -812,6 +813,34 @@ class DockerClientTest(Cleanup, unittest.TestCase):
|
||||||
docker.client.DEFAULT_TIMEOUT_SECONDS
|
docker.client.DEFAULT_TIMEOUT_SECONDS
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_start_container_with_restart_policy(self):
|
||||||
|
try:
|
||||||
|
self.client.start(fake_api.FAKE_CONTAINER_ID,
|
||||||
|
restart_policy={
|
||||||
|
"Name": "always",
|
||||||
|
"MaximumRetryCount": 0
|
||||||
|
})
|
||||||
|
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']),
|
||||||
|
{"PublishAllPorts": False, "Privileged": False,
|
||||||
|
"RestartPolicy": {"MaximumRetryCount": 0, "Name": "always"}}
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
args[1]['headers'],
|
||||||
|
{'Content-Type': 'application/json'}
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
args[1]['timeout'],
|
||||||
|
docker.client.DEFAULT_TIMEOUT_SECONDS
|
||||||
|
)
|
||||||
|
|
||||||
def test_resize_container(self):
|
def test_resize_container(self):
|
||||||
try:
|
try:
|
||||||
self.client.resize(
|
self.client.resize(
|
||||||
|
|
@ -1536,11 +1565,11 @@ class DockerClientTest(Cleanup, unittest.TestCase):
|
||||||
f.write("content")
|
f.write("content")
|
||||||
|
|
||||||
for exclude, names in (
|
for exclude, names in (
|
||||||
(['*.py'], ['bar/a.txt', 'bar/other.png',
|
(['*.py'], ['bar/a.txt', 'bar/other.png',
|
||||||
'test/foo/a.txt', 'test/foo/other.png']),
|
'test/foo/a.txt', 'test/foo/other.png']),
|
||||||
(['*.png', 'bar'], ['test/foo/a.txt', 'test/foo/b.py']),
|
(['*.png', 'bar'], ['test/foo/a.txt', 'test/foo/b.py']),
|
||||||
(['test/foo', 'a.txt'], ['bar/a.txt', 'bar/b.py',
|
(['test/foo', 'a.txt'], ['bar/a.txt', 'bar/b.py',
|
||||||
'bar/other.png']),
|
'bar/other.png']),
|
||||||
):
|
):
|
||||||
archive = docker.utils.tar(base, exclude=exclude)
|
archive = docker.utils.tar(base, exclude=exclude)
|
||||||
tar = tarfile.open(fileobj=archive)
|
tar = tarfile.open(fileobj=archive)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue