summaryrefslogtreecommitdiff
path: root/docker/models
diff options
context:
space:
mode:
Diffstat (limited to 'docker/models')
-rw-r--r--docker/models/configs.py2
-rw-r--r--docker/models/containers.py32
-rw-r--r--docker/models/images.py71
-rw-r--r--docker/models/networks.py2
-rw-r--r--docker/models/plugins.py18
-rw-r--r--docker/models/resource.py13
-rw-r--r--docker/models/secrets.py3
-rw-r--r--docker/models/services.py10
-rw-r--r--docker/models/swarm.py2
9 files changed, 109 insertions, 44 deletions
diff --git a/docker/models/configs.py b/docker/models/configs.py
index 7f23f65..3588c8b 100644
--- a/docker/models/configs.py
+++ b/docker/models/configs.py
@@ -7,7 +7,7 @@ class Config(Model):
id_attribute = 'ID'
def __repr__(self):
- return "<%s: '%s'>" % (self.__class__.__name__, self.name)
+ return f"<{self.__class__.__name__}: '{self.name}'>"
@property
def name(self):
diff --git a/docker/models/containers.py b/docker/models/containers.py
index 19477fe..3d01031 100644
--- a/docker/models/containers.py
+++ b/docker/models/containers.py
@@ -225,7 +225,8 @@ class Container(Model):
"""
return self.client.api.export(self.id, chunk_size)
- def get_archive(self, path, chunk_size=DEFAULT_DATA_CHUNK_SIZE):
+ def get_archive(self, path, chunk_size=DEFAULT_DATA_CHUNK_SIZE,
+ encode_stream=False):
"""
Retrieve a file or folder from the container in the form of a tar
archive.
@@ -235,6 +236,8 @@ class Container(Model):
chunk_size (int): The number of bytes returned by each iteration
of the generator. If ``None``, data will be streamed as it is
received. Default: 2 MB
+ encode_stream (bool): Determines if data should be encoded
+ (gzip-compressed) during transmission. Default: False
Returns:
(tuple): First element is a raw tar data stream. Second element is
@@ -255,7 +258,8 @@ class Container(Model):
... f.write(chunk)
>>> f.close()
"""
- return self.client.api.get_archive(self.id, path, chunk_size)
+ return self.client.api.get_archive(self.id, path,
+ chunk_size, encode_stream)
def kill(self, signal=None):
"""
@@ -549,6 +553,11 @@ class ContainerCollection(Collection):
``["SYS_ADMIN", "MKNOD"]``.
cap_drop (list of str): Drop kernel capabilities.
cgroup_parent (str): Override the default parent cgroup.
+ cgroupns (str): Override the default cgroup namespace mode for the
+ container. One of:
+ - ``private`` the container runs in its own private cgroup
+ namespace.
+ - ``host`` use the host system's cgroup namespace.
cpu_count (int): Number of usable CPUs (Windows only).
cpu_percent (int): Usable percentage of the available CPUs
(Windows only).
@@ -579,6 +588,9 @@ class ContainerCollection(Collection):
For example, ``/dev/sda:/dev/xvda:rwm`` allows the container
to have read-write access to the host's ``/dev/sda`` via a
node named ``/dev/xvda`` inside the container.
+ device_requests (:py:class:`list`): Expose host resources such as
+ GPUs to the container, as a list of
+ :py:class:`docker.types.DeviceRequest` instances.
dns (:py:class:`list`): Set custom DNS servers.
dns_opt (:py:class:`list`): Additional options to be added to the
container's ``resolv.conf`` file.
@@ -662,6 +674,7 @@ class ContainerCollection(Collection):
- ``container:<name|id>`` Reuse another container's network
stack.
- ``host`` Use the host network stack.
+ This mode is incompatible with ``ports``.
Incompatible with ``network``.
oom_kill_disable (bool): Whether to disable OOM killer.
@@ -695,6 +708,7 @@ class ContainerCollection(Collection):
to a single container port. For example,
``{'1111/tcp': [1234, 4567]}``.
+ Incompatible with ``host`` network mode.
privileged (bool): Give extended privileges to this container.
publish_all_ports (bool): Publish all ports to the host.
read_only (bool): Mount the container's root filesystem as read
@@ -772,6 +786,15 @@ class ContainerCollection(Collection):
{'/home/user1/': {'bind': '/mnt/vol2', 'mode': 'rw'},
'/var/www': {'bind': '/mnt/vol1', 'mode': 'ro'}}
+ Or a list of strings which each one of its elements specifies a
+ mount volume.
+
+ For example:
+
+ .. code-block:: python
+
+ ['/home/user1/:/mnt/vol2','/var/www:/mnt/vol1']
+
volumes_from (:py:class:`list`): List of container names or IDs to
get volumes from.
working_dir (str): Path to the working directory.
@@ -803,7 +826,7 @@ class ContainerCollection(Collection):
image = image.id
stream = kwargs.pop('stream', False)
detach = kwargs.pop('detach', False)
- platform = kwargs.pop('platform', None)
+ platform = kwargs.get('platform', None)
if detach and remove:
if version_gte(self.client.api._version, '1.25'):
@@ -987,6 +1010,7 @@ RUN_CREATE_KWARGS = [
'mac_address',
'name',
'network_disabled',
+ 'platform',
'stdin_open',
'stop_signal',
'tty',
@@ -1003,6 +1027,7 @@ RUN_HOST_CONFIG_KWARGS = [
'cap_add',
'cap_drop',
'cgroup_parent',
+ 'cgroupns',
'cpu_count',
'cpu_percent',
'cpu_period',
@@ -1018,6 +1043,7 @@ RUN_HOST_CONFIG_KWARGS = [
'device_write_bps',
'device_write_iops',
'devices',
+ 'device_requests',
'dns_opt',
'dns_search',
'dns',
diff --git a/docker/models/images.py b/docker/models/images.py
index 757a5a4..79ccbe4 100644
--- a/docker/models/images.py
+++ b/docker/models/images.py
@@ -2,8 +2,6 @@ import itertools
import re
import warnings
-import six
-
from ..api import APIClient
from ..constants import DEFAULT_DATA_CHUNK_SIZE
from ..errors import BuildError, ImageLoadError, InvalidArgument
@@ -17,7 +15,10 @@ class Image(Model):
An image on the server.
"""
def __repr__(self):
- return "<%s: '%s'>" % (self.__class__.__name__, "', '".join(self.tags))
+ return "<{}: '{}'>".format(
+ self.__class__.__name__,
+ "', '".join(self.tags),
+ )
@property
def labels(self):
@@ -30,12 +31,12 @@ class Image(Model):
@property
def short_id(self):
"""
- The ID of the image truncated to 10 characters, plus the ``sha256:``
+ The ID of the image truncated to 12 characters, plus the ``sha256:``
prefix.
"""
if self.id.startswith('sha256:'):
- return self.id[:17]
- return self.id[:10]
+ return self.id[:19]
+ return self.id[:12]
@property
def tags(self):
@@ -60,6 +61,24 @@ class Image(Model):
"""
return self.client.api.history(self.id)
+ def remove(self, force=False, noprune=False):
+ """
+ Remove this image.
+
+ Args:
+ force (bool): Force removal of the image
+ noprune (bool): Do not delete untagged parents
+
+ Raises:
+ :py:class:`docker.errors.APIError`
+ If the server returns an error.
+ """
+ return self.client.api.remove_image(
+ self.id,
+ force=force,
+ noprune=noprune,
+ )
+
def save(self, chunk_size=DEFAULT_DATA_CHUNK_SIZE, named=False):
"""
Get a tarball of an image. Similar to the ``docker save`` command.
@@ -84,19 +103,19 @@ class Image(Model):
Example:
- >>> image = cli.get_image("busybox:latest")
+ >>> image = cli.images.get("busybox:latest")
>>> f = open('/tmp/busybox-latest.tar', 'wb')
- >>> for chunk in image:
+ >>> for chunk in image.save():
>>> f.write(chunk)
>>> f.close()
"""
img = self.id
if named:
img = self.tags[0] if self.tags else img
- if isinstance(named, six.string_types):
+ if isinstance(named, str):
if named not in self.tags:
raise InvalidArgument(
- "{} is not a valid tag for this image".format(named)
+ f"{named} is not a valid tag for this image"
)
img = named
@@ -127,7 +146,7 @@ class RegistryData(Model):
Image metadata stored on the registry, including available platforms.
"""
def __init__(self, image_name, *args, **kwargs):
- super(RegistryData, self).__init__(*args, **kwargs)
+ super().__init__(*args, **kwargs)
self.image_name = image_name
@property
@@ -140,10 +159,10 @@ class RegistryData(Model):
@property
def short_id(self):
"""
- The ID of the image truncated to 10 characters, plus the ``sha256:``
+ The ID of the image truncated to 12 characters, plus the ``sha256:``
prefix.
"""
- return self.id[:17]
+ return self.id[:19]
def pull(self, platform=None):
"""
@@ -180,7 +199,7 @@ class RegistryData(Model):
parts = platform.split('/')
if len(parts) > 3 or len(parts) < 1:
raise InvalidArgument(
- '"{0}" is not a valid platform descriptor'.format(platform)
+ f'"{platform}" is not a valid platform descriptor'
)
platform = {'os': parts[0]}
if len(parts) > 2:
@@ -277,7 +296,7 @@ class ImageCollection(Collection):
If neither ``path`` nor ``fileobj`` is specified.
"""
resp = self.client.api.build(**kwargs)
- if isinstance(resp, six.string_types):
+ if isinstance(resp, str):
return self.get(resp)
last_event = None
image_id = None
@@ -395,12 +414,13 @@ class ImageCollection(Collection):
return [self.get(i) for i in images]
- def pull(self, repository, tag=None, **kwargs):
+ def pull(self, repository, tag=None, all_tags=False, **kwargs):
"""
Pull an image of the given name and return it. Similar to the
``docker pull`` command.
- If no tag is specified, all tags from that repository will be
- pulled.
+ If ``tag`` is ``None`` or empty, it is set to ``latest``.
+ If ``all_tags`` is set, the ``tag`` parameter is ignored and all image
+ tags will be pulled.
If you want to get the raw pull output, use the
:py:meth:`~docker.api.image.ImageApiMixin.pull` method in the
@@ -413,10 +433,11 @@ class ImageCollection(Collection):
config for this request. ``auth_config`` should contain the
``username`` and ``password`` keys to be valid.
platform (str): Platform in the format ``os[/arch[/variant]]``
+ all_tags (bool): Pull all image tags
Returns:
(:py:class:`Image` or list): The image that has been pulled.
- If no ``tag`` was specified, the method will return a list
+ If ``all_tags`` is True, the method will return a list
of :py:class:`Image` objects belonging to this repository.
Raises:
@@ -426,13 +447,13 @@ class ImageCollection(Collection):
Example:
>>> # Pull the image tagged `latest` in the busybox repo
- >>> image = client.images.pull('busybox:latest')
+ >>> image = client.images.pull('busybox')
>>> # Pull all tags in the busybox repo
- >>> images = client.images.pull('busybox')
+ >>> images = client.images.pull('busybox', all_tags=True)
"""
- if not tag:
- repository, tag = parse_repository_tag(repository)
+ repository, image_tag = parse_repository_tag(repository)
+ tag = tag or image_tag or 'latest'
if 'stream' in kwargs:
warnings.warn(
@@ -442,14 +463,14 @@ class ImageCollection(Collection):
del kwargs['stream']
pull_log = self.client.api.pull(
- repository, tag=tag, stream=True, **kwargs
+ repository, tag=tag, stream=True, all_tags=all_tags, **kwargs
)
for _ in pull_log:
# We don't do anything with the logs, but we need
# to keep the connection alive and wait for the image
# to be pulled.
pass
- if tag:
+ if not all_tags:
return self.get('{0}{2}{1}'.format(
repository, tag, '@' if tag.startswith('sha256:') else ':'
))
diff --git a/docker/models/networks.py b/docker/models/networks.py
index f944c8e..093deb7 100644
--- a/docker/models/networks.py
+++ b/docker/models/networks.py
@@ -46,6 +46,8 @@ class Network(Model):
network, using the IPv6 protocol. Defaults to ``None``.
link_local_ips (:py:class:`list`): A list of link-local (IPv4/IPv6)
addresses.
+ driver_opt (dict): A dictionary of options to provide to the
+ network driver. Defaults to ``None``.
Raises:
:py:class:`docker.errors.APIError`
diff --git a/docker/models/plugins.py b/docker/models/plugins.py
index 0688018..16f5245 100644
--- a/docker/models/plugins.py
+++ b/docker/models/plugins.py
@@ -7,7 +7,7 @@ class Plugin(Model):
A plugin on the server.
"""
def __repr__(self):
- return "<%s: '%s'>" % (self.__class__.__name__, self.name)
+ return f"<{self.__class__.__name__}: '{self.name}'>"
@property
def name(self):
@@ -44,16 +44,19 @@ class Plugin(Model):
self.client.api.configure_plugin(self.name, options)
self.reload()
- def disable(self):
+ def disable(self, force=False):
"""
Disable the plugin.
+ Args:
+ force (bool): Force disable. Default: False
+
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
- self.client.api.disable_plugin(self.name)
+ self.client.api.disable_plugin(self.name, force)
self.reload()
def enable(self, timeout=0):
@@ -117,9 +120,12 @@ class Plugin(Model):
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()
+ yield from self.client.api.upgrade_plugin(
+ self.name,
+ remote,
+ privileges,
+ )
+ self.reload()
class PluginCollection(Collection):
diff --git a/docker/models/resource.py b/docker/models/resource.py
index ed3900a..89030e5 100644
--- a/docker/models/resource.py
+++ b/docker/models/resource.py
@@ -1,5 +1,4 @@
-
-class Model(object):
+class Model:
"""
A base class for representing a single object on the server.
"""
@@ -18,13 +17,13 @@ class Model(object):
self.attrs = {}
def __repr__(self):
- return "<%s: %s>" % (self.__class__.__name__, self.short_id)
+ return f"<{self.__class__.__name__}: {self.short_id}>"
def __eq__(self, other):
return isinstance(other, self.__class__) and self.id == other.id
def __hash__(self):
- return hash("%s:%s" % (self.__class__.__name__, self.id))
+ return hash(f"{self.__class__.__name__}:{self.id}")
@property
def id(self):
@@ -36,9 +35,9 @@ class Model(object):
@property
def short_id(self):
"""
- The ID of the object, truncated to 10 characters.
+ The ID of the object, truncated to 12 characters.
"""
- return self.id[:10]
+ return self.id[:12]
def reload(self):
"""
@@ -49,7 +48,7 @@ class Model(object):
self.attrs = new_model.attrs
-class Collection(object):
+class Collection:
"""
A base class for representing all objects of a particular type on the
server.
diff --git a/docker/models/secrets.py b/docker/models/secrets.py
index ca11ede..da01d44 100644
--- a/docker/models/secrets.py
+++ b/docker/models/secrets.py
@@ -7,7 +7,7 @@ class Secret(Model):
id_attribute = 'ID'
def __repr__(self):
- return "<%s: '%s'>" % (self.__class__.__name__, self.name)
+ return f"<{self.__class__.__name__}: '{self.name}'>"
@property
def name(self):
@@ -30,6 +30,7 @@ class SecretCollection(Collection):
def create(self, **kwargs):
obj = self.client.api.create_secret(**kwargs)
+ obj.setdefault("Spec", {})["Name"] = kwargs.get("name")
return self.prepare_model(obj)
create.__doc__ = APIClient.create_secret.__doc__
diff --git a/docker/models/services.py b/docker/models/services.py
index a35687b..9255068 100644
--- a/docker/models/services.py
+++ b/docker/models/services.py
@@ -157,6 +157,8 @@ class ServiceCollection(Collection):
constraints.
preferences (list of tuple): :py:class:`~docker.types.Placement`
preferences.
+ maxreplicas (int): :py:class:`~docker.types.Placement` maxreplicas
+ or (int) representing maximum number of replicas per node.
platforms (list of tuple): A list of platform constraints
expressed as ``(arch, os)`` tuples.
container_labels (dict): Labels to apply to the container.
@@ -211,6 +213,10 @@ class ServiceCollection(Collection):
to the service.
privileges (Privileges): Security options for the service's
containers.
+ cap_add (:py:class:`list`): A list of kernel capabilities to add to
+ the default set for the container.
+ cap_drop (:py:class:`list`): A list of kernel capabilities to drop
+ from the default set for the container.
Returns:
:py:class:`Service`: The created service.
@@ -275,6 +281,8 @@ class ServiceCollection(Collection):
# kwargs to copy straight over to ContainerSpec
CONTAINER_SPEC_KWARGS = [
'args',
+ 'cap_add',
+ 'cap_drop',
'command',
'configs',
'dns_config',
@@ -312,6 +320,7 @@ CREATE_SERVICE_KWARGS = [
'labels',
'mode',
'update_config',
+ 'rollback_config',
'endpoint_spec',
]
@@ -319,6 +328,7 @@ PLACEMENT_KWARGS = [
'constraints',
'preferences',
'platforms',
+ 'maxreplicas',
]
diff --git a/docker/models/swarm.py b/docker/models/swarm.py
index 755c17d..b0b1a2e 100644
--- a/docker/models/swarm.py
+++ b/docker/models/swarm.py
@@ -11,7 +11,7 @@ class Swarm(Model):
id_attribute = 'ID'
def __init__(self, *args, **kwargs):
- super(Swarm, self).__init__(*args, **kwargs)
+ super().__init__(*args, **kwargs)
if self.client:
try:
self.reload()