summaryrefslogtreecommitdiff
path: root/docker
diff options
context:
space:
mode:
Diffstat (limited to 'docker')
-rw-r--r--docker/api/container.py3
-rw-r--r--docker/api/daemon.py18
-rw-r--r--docker/api/plugin.py37
-rw-r--r--docker/api/service.py50
-rw-r--r--docker/client.py4
-rw-r--r--docker/constants.py2
-rw-r--r--docker/models/containers.py7
-rw-r--r--docker/models/plugins.py25
-rw-r--r--docker/models/services.py34
-rw-r--r--docker/types/containers.py13
-rw-r--r--docker/types/services.py9
-rw-r--r--docker/utils/ports.py20
-rw-r--r--docker/version.py2
13 files changed, 210 insertions, 14 deletions
diff --git a/docker/api/container.py b/docker/api/container.py
index 453e378..4e7364b 100644
--- a/docker/api/container.py
+++ b/docker/api/container.py
@@ -498,6 +498,9 @@ class ContainerApiMixin(object):
container, as a mapping of hostname to IP address.
group_add (:py:class:`list`): List of additional group names and/or
IDs that the container process will run as.
+ init (bool): Run an init inside the container that forwards
+ signals and reaps processes
+ init_path (str): Path to the docker-init binary
ipc_mode (str): Set the IPC mode for the container.
isolation (str): Isolation technology to use. Default: `None`.
links (dict or list of tuples): Either a dictionary mapping name
diff --git a/docker/api/daemon.py b/docker/api/daemon.py
index d40631f..00367bc 100644
--- a/docker/api/daemon.py
+++ b/docker/api/daemon.py
@@ -7,6 +7,22 @@ from ..constants import INSECURE_REGISTRY_DEPRECATION_WARNING
class DaemonApiMixin(object):
+ @utils.minimum_version('1.25')
+ def df(self):
+ """
+ Get data usage information.
+
+ Returns:
+ (dict): A dictionary representing different resource categories
+ and their respective data usage.
+
+ Raises:
+ :py:class:`docker.errors.APIError`
+ If the server returns an error.
+ """
+ url = self._url('/system/df')
+ return self._result(self._get(url), True)
+
def events(self, since=None, until=None, filters=None, decode=None):
"""
Get real-time events from the server. Similar to the ``docker events``
@@ -54,7 +70,7 @@ class DaemonApiMixin(object):
}
return self._stream_helper(
- self.get(self._url('/events'), params=params, stream=True),
+ self._get(self._url('/events'), params=params, stream=True),
decode=decode
)
diff --git a/docker/api/plugin.py b/docker/api/plugin.py
index 772d263..ba40c88 100644
--- a/docker/api/plugin.py
+++ b/docker/api/plugin.py
@@ -195,6 +195,7 @@ class PluginApiMixin(object):
return self._stream_helper(res, decode=True)
@utils.minimum_version('1.25')
+ @utils.check_resource
def remove_plugin(self, name, force=False):
"""
Remove an installed plugin.
@@ -212,3 +213,39 @@ class PluginApiMixin(object):
res = self._delete(url, params={'force': force})
self._raise_for_status(res)
return True
+
+ @utils.minimum_version('1.26')
+ @utils.check_resource
+ def upgrade_plugin(self, name, remote, privileges):
+ """
+ Upgrade an installed plugin.
+
+ Args:
+ name (string): Name of the plugin to upgrade. The ``:latest``
+ tag is optional and is the default if omitted.
+ remote (string): Remote reference to upgrade to. The
+ ``:latest`` tag is optional and is the default if omitted.
+ privileges (list): A list of privileges the user consents to
+ grant to the plugin. Can be retrieved using
+ :py:meth:`~plugin_privileges`.
+
+ Returns:
+ An iterable object streaming the decoded API logs
+ """
+
+ url = self._url('/plugins/{0}/upgrade', name)
+ params = {
+ 'remote': remote,
+ }
+
+ headers = {}
+ registry, repo_name = auth.resolve_repository_name(remote)
+ header = auth.get_config_header(self, registry)
+ if header:
+ headers['X-Registry-Auth'] = header
+ response = self._post_json(
+ url, params=params, headers=headers, data=privileges,
+ stream=True
+ )
+ self._raise_for_status(response)
+ return self._stream_helper(response, decode=True)
diff --git a/docker/api/service.py b/docker/api/service.py
index 0b2abdc..4972c16 100644
--- a/docker/api/service.py
+++ b/docker/api/service.py
@@ -166,6 +166,56 @@ class ServiceApiMixin(object):
url = self._url('/services')
return self._result(self._get(url, params=params), True)
+ @utils.minimum_version('1.25')
+ @utils.check_resource
+ def service_logs(self, service, details=False, follow=False, stdout=False,
+ stderr=False, since=0, timestamps=False, tail='all',
+ is_tty=None):
+ """
+ Get log stream for a service.
+ Note: This endpoint works only for services with the ``json-file``
+ or ``journald`` logging drivers.
+
+ Args:
+ service (str): ID or name of the service
+ details (bool): Show extra details provided to logs.
+ Default: ``False``
+ follow (bool): Keep connection open to read logs as they are
+ sent by the Engine. Default: ``False``
+ stdout (bool): Return logs from ``stdout``. Default: ``False``
+ stderr (bool): Return logs from ``stderr``. Default: ``False``
+ since (int): UNIX timestamp for the logs staring point.
+ Default: 0
+ timestamps (bool): Add timestamps to every log line.
+ tail (string or int): Number of log lines to be returned,
+ counting from the current end of the logs. Specify an
+ integer or ``'all'`` to output all log lines.
+ Default: ``all``
+ is_tty (bool): Whether the service's :py:class:`ContainerSpec`
+ enables the TTY option. If omitted, the method will query
+ the Engine for the information, causing an additional
+ roundtrip.
+
+ Returns (generator): Logs for the service.
+ """
+ params = {
+ 'details': details,
+ 'follow': follow,
+ 'stdout': stdout,
+ 'stderr': stderr,
+ 'since': since,
+ 'timestamps': timestamps,
+ 'tail': tail
+ }
+
+ url = self._url('/services/{0}/logs', service)
+ res = self._get(url, params=params, stream=True)
+ if is_tty is None:
+ is_tty = self.inspect_service(
+ service
+ )['Spec']['TaskTemplate']['ContainerSpec'].get('TTY', False)
+ return self._get_result_tty(True, res, is_tty)
+
@utils.minimum_version('1.24')
def tasks(self, filters=None):
"""
diff --git a/docker/client.py b/docker/client.py
index 09bda67..151e194 100644
--- a/docker/client.py
+++ b/docker/client.py
@@ -155,6 +155,10 @@ class DockerClient(object):
return self.api.events(*args, **kwargs)
events.__doc__ = APIClient.events.__doc__
+ def df(self):
+ return self.api.df()
+ df.__doc__ = APIClient.df.__doc__
+
def info(self, *args, **kwargs):
return self.api.info(*args, **kwargs)
info.__doc__ = APIClient.info.__doc__
diff --git a/docker/constants.py b/docker/constants.py
index 4337fed..91a6528 100644
--- a/docker/constants.py
+++ b/docker/constants.py
@@ -1,7 +1,7 @@
import sys
from .version import version
-DEFAULT_DOCKER_API_VERSION = '1.24'
+DEFAULT_DOCKER_API_VERSION = '1.26'
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 b7a7787..0d328e7 100644
--- a/docker/models/containers.py
+++ b/docker/models/containers.py
@@ -491,6 +491,9 @@ class ContainerCollection(Collection):
group_add (:py:class:`list`): List of additional group names and/or
IDs that the container process will run as.
hostname (str): Optional hostname for the container.
+ init (bool): Run an init inside the container that forwards
+ signals and reaps processes
+ init_path (str): Path to the docker-init binary
ipc_mode (str): Set the IPC mode for the container.
isolation (str): Isolation technology to use. Default: `None`.
labels (dict or list): A dictionary of name-value labels (e.g.
@@ -726,7 +729,7 @@ class ContainerCollection(Collection):
Args:
all (bool): Show all containers. Only running containers are shown
- by default trunc (bool): Truncate output
+ by default
since (str): Show only containers created since Id or Name, include
non-running ones
before (str): Show only container created before Id or Name,
@@ -814,6 +817,8 @@ RUN_HOST_CONFIG_KWARGS = [
'dns',
'extra_hosts',
'group_add',
+ 'init',
+ 'init_path',
'ipc_mode',
'isolation',
'kernel_memory',
diff --git a/docker/models/plugins.py b/docker/models/plugins.py
index 8b6ede9..6cdf01c 100644
--- a/docker/models/plugins.py
+++ b/docker/models/plugins.py
@@ -1,3 +1,4 @@
+from .. import errors
from .resource import Collection, Model
@@ -96,6 +97,30 @@ class Plugin(Model):
"""
return self.client.api.remove_plugin(self.name, force=force)
+ def upgrade(self, remote=None):
+ """
+ Upgrade the plugin.
+
+ Args:
+ remote (string): Remote reference to upgrade to. The
+ ``:latest`` tag is optional and is the default if omitted.
+ Default: this plugin's name.
+
+ Returns:
+ A generator streaming the decoded API logs
+ """
+ if self.enabled:
+ raise errors.DockerError(
+ 'Plugin must be disabled before upgrading.'
+ )
+
+ if remote is None:
+ remote = self.name
+ privileges = self.client.api.plugin_privileges(remote)
+ for d in self.client.api.upgrade_plugin(self.name, remote, privileges):
+ yield d
+ self._reload()
+
class PluginCollection(Collection):
model = Plugin
diff --git a/docker/models/services.py b/docker/models/services.py
index bd95b5f..c10804d 100644
--- a/docker/models/services.py
+++ b/docker/models/services.py
@@ -77,6 +77,34 @@ class Service(Model):
**create_kwargs
)
+ def logs(self, **kwargs):
+ """
+ Get log stream for the service.
+ Note: This method works only for services with the ``json-file``
+ or ``journald`` logging drivers.
+
+ Args:
+ details (bool): Show extra details provided to logs.
+ Default: ``False``
+ follow (bool): Keep connection open to read logs as they are
+ sent by the Engine. Default: ``False``
+ stdout (bool): Return logs from ``stdout``. Default: ``False``
+ stderr (bool): Return logs from ``stderr``. Default: ``False``
+ since (int): UNIX timestamp for the logs staring point.
+ Default: 0
+ timestamps (bool): Add timestamps to every log line.
+ tail (string or int): Number of log lines to be returned,
+ counting from the current end of the logs. Specify an
+ integer or ``'all'`` to output all log lines.
+ Default: ``all``
+
+ Returns (generator): Logs for the service.
+ """
+ is_tty = self.attrs['Spec']['TaskTemplate']['ContainerSpec'].get(
+ 'TTY', False
+ )
+ return self.client.api.service_logs(self.id, is_tty=is_tty, **kwargs)
+
class ServiceCollection(Collection):
"""Services on the Docker server."""
@@ -96,11 +124,12 @@ class ServiceCollection(Collection):
access and load balance a service. Default: ``None``.
env (list of str): Environment variables, in the form
``KEY=val``.
+ hostname (string): Hostname to set on the container.
labels (dict): Labels to apply to the service.
log_driver (str): Log driver to use for containers.
log_driver_options (dict): Log driver options.
- mode (str): Scheduling mode for the service (``replicated`` or
- ``global``). Defaults to ``replicated``.
+ mode (ServiceMode): Scheduling mode for the service.
+ Default:``None``
mounts (list of str): Mounts for the containers, in the form
``source:target:options``, where options is either
``ro`` or ``rw``.
@@ -176,6 +205,7 @@ CONTAINER_SPEC_KWARGS = [
'command',
'args',
'env',
+ 'hostname',
'workdir',
'user',
'labels',
diff --git a/docker/types/containers.py b/docker/types/containers.py
index 9a8d157..5a5079a 100644
--- a/docker/types/containers.py
+++ b/docker/types/containers.py
@@ -117,7 +117,8 @@ class HostConfig(dict):
oom_kill_disable=False, shm_size=None, sysctls=None,
tmpfs=None, oom_score_adj=None, dns_opt=None, cpu_shares=None,
cpuset_cpus=None, userns_mode=None, pids_limit=None,
- isolation=None, auto_remove=False, storage_opt=None):
+ isolation=None, auto_remove=False, storage_opt=None,
+ init=None, init_path=None):
if mem_limit is not None:
self['Memory'] = parse_bytes(mem_limit)
@@ -417,6 +418,16 @@ class HostConfig(dict):
raise host_config_version_error('storage_opt', '1.24')
self['StorageOpt'] = storage_opt
+ if init is not None:
+ if version_lt(version, '1.25'):
+ raise host_config_version_error('init', '1.25')
+ self['Init'] = init
+
+ if init_path is not None:
+ if version_lt(version, '1.25'):
+ raise host_config_version_error('init_path', '1.25')
+ self['InitPath'] = init_path
+
def host_config_type_error(param, param_value, expected):
error_msg = 'Invalid type for {0} param: expected {1} but found {2}'
diff --git a/docker/types/services.py b/docker/types/services.py
index b903fa4..9291c9b 100644
--- a/docker/types/services.py
+++ b/docker/types/services.py
@@ -70,6 +70,7 @@ class ContainerSpec(dict):
image (string): The image name to use for the container.
command (string or list): The command to be run in the image.
args (:py:class:`list`): Arguments to the command.
+ hostname (string): The hostname to set on the container.
env (dict): Environment variables.
dir (string): The working directory for commands to run in.
user (string): The user inside the container.
@@ -82,9 +83,9 @@ class ContainerSpec(dict):
secrets (list of py:class:`SecretReference`): List of secrets to be
made available inside the containers.
"""
- def __init__(self, image, command=None, args=None, env=None, workdir=None,
- user=None, labels=None, mounts=None, stop_grace_period=None,
- secrets=None):
+ 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):
self['Image'] = image
if isinstance(command, six.string_types):
@@ -92,6 +93,8 @@ class ContainerSpec(dict):
self['Command'] = command
self['Args'] = args
+ if hostname is not None:
+ self['Hostname'] = hostname
if env is not None:
if isinstance(env, dict):
self['Env'] = format_environment(env)
diff --git a/docker/utils/ports.py b/docker/utils/ports.py
index 326ef94..3708958 100644
--- a/docker/utils/ports.py
+++ b/docker/utils/ports.py
@@ -24,7 +24,7 @@ def build_port_bindings(ports):
return port_bindings
-def to_port_range(port):
+def to_port_range(port, randomly_available_port=False):
if not port:
return None
@@ -37,6 +37,9 @@ def to_port_range(port):
port, protocol = parts
protocol = "/" + protocol
+ if randomly_available_port:
+ return ["%s%s" % (port, protocol)]
+
parts = str(port).split('-')
if len(parts) == 1:
@@ -64,14 +67,18 @@ def split_port(port):
if len(parts) == 1:
internal_port, = parts
+ if not internal_port:
+ _raise_invalid_port(port)
return to_port_range(internal_port), None
if len(parts) == 2:
external_port, internal_port = parts
internal_range = to_port_range(internal_port)
- external_range = to_port_range(external_port)
+ if internal_range is None:
+ _raise_invalid_port(port)
- if internal_range is None or external_range is None:
+ external_range = to_port_range(external_port, len(internal_range) == 1)
+ if external_range is None:
_raise_invalid_port(port)
if len(internal_range) != len(external_range):
@@ -80,8 +87,13 @@ def split_port(port):
return internal_range, external_range
external_ip, external_port, internal_port = parts
+
+ if not internal_port:
+ _raise_invalid_port(port)
+
internal_range = to_port_range(internal_port)
- external_range = to_port_range(external_port)
+ external_range = to_port_range(external_port, len(internal_range) == 1)
+
if not external_range:
external_range = [None] * len(internal_range)
diff --git a/docker/version.py b/docker/version.py
index 491566c..b2474bd 100644
--- a/docker/version.py
+++ b/docker/version.py
@@ -1,2 +1,2 @@
-version = "2.1.0"
+version = "2.2.0"
version_info = tuple([int(d) for d in version.split("-")[0].split(".")])