summaryrefslogtreecommitdiff
path: root/docker
diff options
context:
space:
mode:
Diffstat (limited to 'docker')
-rw-r--r--docker/api/container.py64
-rw-r--r--docker/api/exec_api.py10
-rw-r--r--docker/api/service.py4
-rw-r--r--docker/constants.py2
-rw-r--r--docker/models/containers.py9
-rw-r--r--docker/models/services.py3
-rw-r--r--docker/types/services.py9
7 files changed, 77 insertions, 24 deletions
diff --git a/docker/api/container.py b/docker/api/container.py
index 494f7b4..b08032c 100644
--- a/docker/api/container.py
+++ b/docker/api/container.py
@@ -786,7 +786,8 @@ class ContainerApiMixin(object):
@utils.check_resource('container')
def logs(self, container, stdout=True, stderr=True, stream=False,
- timestamps=False, tail='all', since=None, follow=None):
+ timestamps=False, tail='all', since=None, follow=None,
+ until=None):
"""
Get logs from a container. Similar to the ``docker logs`` command.
@@ -805,6 +806,8 @@ class ContainerApiMixin(object):
since (datetime or int): Show logs since a given datetime or
integer epoch (in seconds)
follow (bool): Follow log output
+ until (datetime or int): Show logs that occurred before the given
+ datetime or integer epoch (in seconds)
Returns:
(generator or str)
@@ -827,21 +830,35 @@ class ContainerApiMixin(object):
params['tail'] = tail
if since is not None:
- if utils.compare_version('1.19', self._version) < 0:
+ if utils.version_lt(self._version, '1.19'):
raise errors.InvalidVersion(
- 'since is not supported in API < 1.19'
+ 'since is not supported for API version < 1.19'
)
+ if isinstance(since, datetime):
+ params['since'] = utils.datetime_to_timestamp(since)
+ elif (isinstance(since, int) and since > 0):
+ params['since'] = since
else:
- if isinstance(since, datetime):
- params['since'] = utils.datetime_to_timestamp(since)
- elif (isinstance(since, int) and since > 0):
- params['since'] = since
- else:
- raise errors.InvalidArgument(
- 'since value should be datetime or positive int, '
- 'not {}'.
- format(type(since))
- )
+ raise errors.InvalidArgument(
+ 'since value should be datetime or positive int, '
+ 'not {}'.format(type(since))
+ )
+
+ if until is not None:
+ if utils.version_lt(self._version, '1.35'):
+ raise errors.InvalidVersion(
+ 'until is not supported for API version < 1.35'
+ )
+ if isinstance(until, datetime):
+ params['until'] = utils.datetime_to_timestamp(until)
+ elif (isinstance(until, int) and until > 0):
+ params['until'] = until
+ else:
+ raise errors.InvalidArgument(
+ 'until value should be datetime or positive int, '
+ 'not {}'.format(type(until))
+ )
+
url = self._url("/containers/{0}/logs", container)
res = self._get(url, params=params, stream=stream)
return self._get_result(container, stream, res)
@@ -1241,7 +1258,7 @@ class ContainerApiMixin(object):
return self._result(res, True)
@utils.check_resource('container')
- def wait(self, container, timeout=None):
+ def wait(self, container, timeout=None, condition=None):
"""
Block until a container stops, then return its exit code. Similar to
the ``docker wait`` command.
@@ -1250,10 +1267,13 @@ class ContainerApiMixin(object):
container (str or dict): The container to wait on. If a dict, the
``Id`` key is used.
timeout (int): Request timeout
+ condition (str): Wait until a container state reaches the given
+ condition, either ``not-running`` (default), ``next-exit``,
+ or ``removed``
Returns:
- (int): The exit code of the container. Returns ``-1`` if the API
- responds without a ``StatusCode`` attribute.
+ (int or dict): The exit code of the container. Returns the full API
+ response if no ``StatusCode`` field is included.
Raises:
:py:class:`requests.exceptions.ReadTimeout`
@@ -1262,9 +1282,17 @@ class ContainerApiMixin(object):
If the server returns an error.
"""
url = self._url("/containers/{0}/wait", container)
- res = self._post(url, timeout=timeout)
+ params = {}
+ if condition is not None:
+ if utils.version_lt(self._version, '1.30'):
+ raise errors.InvalidVersion(
+ 'wait condition is not supported for API version < 1.30'
+ )
+ params['condition'] = condition
+
+ res = self._post(url, timeout=timeout, params=params)
self._raise_for_status(res)
json_ = res.json()
if 'StatusCode' in json_:
return json_['StatusCode']
- return -1
+ return json_
diff --git a/docker/api/exec_api.py b/docker/api/exec_api.py
index cff5cfa..029c984 100644
--- a/docker/api/exec_api.py
+++ b/docker/api/exec_api.py
@@ -9,7 +9,7 @@ class ExecApiMixin(object):
@utils.check_resource('container')
def exec_create(self, container, cmd, stdout=True, stderr=True,
stdin=False, tty=False, privileged=False, user='',
- environment=None):
+ environment=None, workdir=None):
"""
Sets up an exec instance in a running container.
@@ -26,6 +26,7 @@ class ExecApiMixin(object):
environment (dict or list): A dictionary or a list of strings in
the following format ``["PASSWORD=xxx"]`` or
``{"PASSWORD": "xxx"}``.
+ workdir (str): Path to working directory for this exec session
Returns:
(dict): A dictionary with an exec ``Id`` key.
@@ -66,6 +67,13 @@ class ExecApiMixin(object):
'Env': environment,
}
+ if workdir is not None:
+ if utils.version_lt(self._version, '1.35'):
+ raise errors.InvalidVersion(
+ 'workdir is not supported for API version < 1.35'
+ )
+ data['WorkingDir'] = workdir
+
url = self._url('/containers/{0}/exec', container)
res = self._post_json(url, data=data)
return self._result(res, True)
diff --git a/docker/api/service.py b/docker/api/service.py
index 1a8b8b5..4f7123e 100644
--- a/docker/api/service.py
+++ b/docker/api/service.py
@@ -65,6 +65,10 @@ def _check_api_features(version, task_template, update_config):
if container_spec.get('Privileges') is not None:
raise_version_error('ContainerSpec.privileges', '1.30')
+ if utils.version_lt(version, '1.35'):
+ if container_spec.get('Isolation') is not None:
+ raise_version_error('ContainerSpec.isolation', '1.35')
+
def _merge_task_template(current, override):
merged = current.copy()
diff --git a/docker/constants.py b/docker/constants.py
index 6de8fad..9ab3673 100644
--- a/docker/constants.py
+++ b/docker/constants.py
@@ -1,7 +1,7 @@
import sys
from .version import version
-DEFAULT_DOCKER_API_VERSION = '1.30'
+DEFAULT_DOCKER_API_VERSION = '1.35'
MINIMUM_DOCKER_API_VERSION = '1.21'
DEFAULT_TIMEOUT_SECONDS = 60
STREAM_HEADER_SIZE_BYTES = 8
diff --git a/docker/models/containers.py b/docker/models/containers.py
index 5e2aa88..e8380f9 100644
--- a/docker/models/containers.py
+++ b/docker/models/containers.py
@@ -126,7 +126,7 @@ class Container(Model):
def exec_run(self, cmd, stdout=True, stderr=True, stdin=False, tty=False,
privileged=False, user='', detach=False, stream=False,
- socket=False, environment=None):
+ socket=False, environment=None, workdir=None):
"""
Run a command inside this container. Similar to
``docker exec``.
@@ -147,6 +147,7 @@ class Container(Model):
environment (dict or list): A dictionary or a list of strings in
the following format ``["PASSWORD=xxx"]`` or
``{"PASSWORD": "xxx"}``.
+ workdir (str): Path to working directory for this exec session
Returns:
(generator or str):
@@ -159,7 +160,8 @@ class Container(Model):
"""
resp = self.client.api.exec_create(
self.id, cmd, stdout=stdout, stderr=stderr, stdin=stdin, tty=tty,
- privileged=privileged, user=user, environment=environment
+ privileged=privileged, user=user, environment=environment,
+ workdir=workdir
)
return self.client.api.exec_start(
resp['Id'], detach=detach, tty=tty, stream=stream, socket=socket
@@ -427,6 +429,9 @@ class Container(Model):
Args:
timeout (int): Request timeout
+ condition (str): Wait until a container state reaches the given
+ condition, either ``not-running`` (default), ``next-exit``,
+ or ``removed``
Returns:
(int): The exit code of the container. Returns ``-1`` if the API
diff --git a/docker/models/services.py b/docker/models/services.py
index 337ed44..8a633df 100644
--- a/docker/models/services.py
+++ b/docker/models/services.py
@@ -144,6 +144,8 @@ class ServiceCollection(Collection):
env (list of str): Environment variables, in the form
``KEY=val``.
hostname (string): Hostname to set on the container.
+ isolation (string): Isolation technology used by the service's
+ containers. Only used for Windows containers.
labels (dict): Labels to apply to the service.
log_driver (str): Log driver to use for containers.
log_driver_options (dict): Log driver options.
@@ -255,6 +257,7 @@ CONTAINER_SPEC_KWARGS = [
'hostname',
'hosts',
'image',
+ 'isolation',
'labels',
'mounts',
'open_stdin',
diff --git a/docker/types/services.py b/docker/types/services.py
index a1f34e0..ef1ca69 100644
--- a/docker/types/services.py
+++ b/docker/types/services.py
@@ -102,19 +102,21 @@ class ContainerSpec(dict):
healthcheck (Healthcheck): Healthcheck
configuration for this service.
hosts (:py:class:`dict`): A set of host to IP mappings to add to
- the container's `hosts` file.
+ the container's ``hosts`` file.
dns_config (DNSConfig): Specification for DNS
related configurations in resolver configuration file.
configs (:py:class:`list`): List of :py:class:`ConfigReference` that
will be exposed to the service.
privileges (Privileges): Security options for the service's containers.
+ isolation (string): Isolation technology used by the service's
+ containers. Only used for Windows containers.
"""
def __init__(self, image, command=None, args=None, hostname=None, env=None,
workdir=None, user=None, labels=None, mounts=None,
stop_grace_period=None, secrets=None, tty=None, groups=None,
open_stdin=None, read_only=None, stop_signal=None,
healthcheck=None, hosts=None, dns_config=None, configs=None,
- privileges=None):
+ privileges=None, isolation=None):
self['Image'] = image
if isinstance(command, six.string_types):
@@ -178,6 +180,9 @@ class ContainerSpec(dict):
if read_only is not None:
self['ReadOnly'] = read_only
+ if isolation is not None:
+ self['Isolation'] = isolation
+
class Mount(dict):
"""