Kaydet (Commit) 269a15e4 authored tarafından Joffrey F's avatar Joffrey F Kaydeden (comit) GitHub

Merge pull request #1402 from docker/2.0.2-release

2.0.2 release
......@@ -18,16 +18,20 @@ from .service import ServiceApiMixin
from .swarm import SwarmApiMixin
from .volume import VolumeApiMixin
from .. import auth
from ..constants import (DEFAULT_TIMEOUT_SECONDS, DEFAULT_USER_AGENT,
IS_WINDOWS_PLATFORM, DEFAULT_DOCKER_API_VERSION,
STREAM_HEADER_SIZE_BYTES, DEFAULT_NUM_POOLS,
MINIMUM_DOCKER_API_VERSION)
from ..errors import (DockerException, TLSParameterError,
create_api_error_from_http_exception)
from ..constants import (
DEFAULT_TIMEOUT_SECONDS, DEFAULT_USER_AGENT, IS_WINDOWS_PLATFORM,
DEFAULT_DOCKER_API_VERSION, STREAM_HEADER_SIZE_BYTES, DEFAULT_NUM_POOLS,
MINIMUM_DOCKER_API_VERSION
)
from ..errors import (
DockerException, TLSParameterError,
create_api_error_from_http_exception
)
from ..tls import TLSConfig
from ..transport import SSLAdapter, UnixAdapter
from ..utils import utils, check_resource, update_headers
from ..utils.socket import frames_iter
from ..utils.json_stream import json_stream
try:
from ..transport import NpipeAdapter
except ImportError:
......@@ -274,27 +278,20 @@ class APIClient(
def _stream_helper(self, response, decode=False):
"""Generator for data coming from a chunked-encoded HTTP response."""
if response.raw._fp.chunked:
reader = response.raw
while not reader.closed:
# this read call will block until we get a chunk
data = reader.read(1)
if not data:
break
if reader._fp.chunk_left:
data += reader.read(reader._fp.chunk_left)
if decode:
if six.PY3:
data = data.decode('utf-8')
# remove the trailing newline
data = data.strip()
# split the data at any newlines
data_list = data.split("\r\n")
# load and yield each line seperately
for data in data_list:
data = json.loads(data)
yield data
else:
if decode:
for chunk in json_stream(self._stream_helper(response, False)):
yield chunk
else:
reader = response.raw
while not reader.closed:
# this read call will block until we get a chunk
data = reader.read(1)
if not data:
break
if reader._fp.chunk_left:
data += reader.read(reader._fp.chunk_left)
yield data
else:
# Response isn't chunked, meaning we probably
......
......@@ -388,13 +388,13 @@ class ContainerApiMixin(object):
environment (dict or list): A dictionary or a list of strings in
the following format ``["PASSWORD=xxx"]`` or
``{"PASSWORD": "xxx"}``.
dns (list): DNS name servers. Deprecated since API version 1.10.
Use ``host_config`` instead.
dns_opt (list): Additional options to be added to the container's
``resolv.conf`` file
dns (:py:class:`list`): DNS name servers. Deprecated since API
version 1.10. Use ``host_config`` instead.
dns_opt (:py:class:`list`): Additional options to be added to the
container's ``resolv.conf`` file
volumes (str or list):
volumes_from (list): List of container names or Ids to get
volumes from.
volumes_from (:py:class:`list`): List of container names or Ids to
get volumes from.
network_disabled (bool): Disable networking
name (str): A name for the container
entrypoint (str or list): An entrypoint
......@@ -478,19 +478,19 @@ class ContainerApiMixin(object):
device_write_bps: Limit write rate (bytes per second) from a
device.
device_write_iops: Limit write rate (IO per second) from a device.
devices (list): Expose host devices to the container, as a list
of strings in the form
devices (:py:class:`list`): Expose host devices to the container,
as a list of strings in the form
``<path_on_host>:<path_in_container>:<cgroup_permissions>``.
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.
dns (list): Set custom DNS servers.
dns_search (list): DNS search domains.
dns (:py:class:`list`): Set custom DNS servers.
dns_search (:py:class:`list`): DNS search domains.
extra_hosts (dict): Addtional hostnames to resolve inside the
container, as a mapping of hostname to IP address.
group_add (list): List of additional group names and/or IDs that
the container process will run as.
group_add (:py:class:`list`): List of additional group names and/or
IDs that the container process will run as.
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
......@@ -539,8 +539,8 @@ class ContainerApiMixin(object):
- ``Name`` One of ``on-failure``, or ``always``.
- ``MaximumRetryCount`` Number of times to restart the
container on failure.
security_opt (list): A list of string values to customize labels
for MLS systems, such as SELinux.
security_opt (:py:class:`list`): A list of string values to
customize labels for MLS systems, such as SELinux.
shm_size (str or int): Size of /dev/shm (e.g. ``1G``).
sysctls (dict): Kernel parameters to set in the container.
tmpfs (dict): Temporary filesystems to mount, as a dictionary
......@@ -555,13 +555,13 @@ class ContainerApiMixin(object):
'/mnt/vol1': 'size=3G,uid=1000'
}
ulimits (list): Ulimits to set inside the container, as a list of
dicts.
ulimits (:py:class:`list`): Ulimits to set inside the container,
as a list of dicts.
userns_mode (str): Sets the user namespace mode for the container
when user namespace remapping option is enabled. Supported
values are: ``host``
volumes_from (list): List of container names or IDs to get
volumes from.
volumes_from (:py:class:`list`): List of container names or IDs to
get volumes from.
Returns:
......@@ -618,17 +618,17 @@ class ContainerApiMixin(object):
:py:meth:`create_networking_config`.
Args:
aliases (list): A list of aliases for this endpoint. Names in
that list can be used within the network to reach the
aliases (:py:class:`list`): A list of aliases for this endpoint.
Names in that list can be used within the network to reach the
container. Defaults to ``None``.
links (:py:class:`list`): A list of links for this endpoint.
Containers declared in this list will be linked to this
container. Defaults to ``None``.
links (list): A list of links for this endpoint. Containers
declared in this list will be linked to this container.
Defaults to ``None``.
ipv4_address (str): The IP address of this container on the
network, using the IPv4 protocol. Defaults to ``None``.
ipv6_address (str): The IP address of this container on the
network, using the IPv6 protocol. Defaults to ``None``.
link_local_ips (list): A list of link-local (IPv4/IPv6)
link_local_ips (:py:class:`list`): A list of link-local (IPv4/IPv6)
addresses.
Returns:
......
import json
from ..errors import InvalidVersion
from ..utils import check_resource, minimum_version
from ..utils import version_lt
from .. import utils
class NetworkApiMixin(object):
@minimum_version('1.21')
def networks(self, names=None, ids=None):
def networks(self, names=None, ids=None, filters=None):
"""
List networks. Similar to the ``docker networks ls`` command.
Args:
names (list): List of names to filter by
ids (list): List of ids to filter by
names (:py:class:`list`): List of names to filter by
ids (:py:class:`list`): List of ids to filter by
filters (dict): Filters to be processed on the network list.
Available filters:
- ``driver=[<driver-name>]`` Matches a network's driver.
- ``label=[<key>]`` or ``label=[<key>=<value>]``.
- ``type=["custom"|"builtin"]`` Filters networks by type.
Returns:
(dict): List of network objects.
......@@ -23,14 +27,13 @@ class NetworkApiMixin(object):
If the server returns an error.
"""
filters = {}
if filters is None:
filters = {}
if names:
filters['name'] = names
if ids:
filters['id'] = ids
params = {'filters': json.dumps(filters)}
params = {'filters': utils.convert_filters(filters)}
url = self._url("/networks")
res = self._get(url, params=params)
return self._result(res, json=True)
......@@ -166,17 +169,18 @@ class NetworkApiMixin(object):
Args:
container (str): container-id/name to be connected to the network
net_id (str): network id
aliases (list): A list of aliases for this endpoint. Names in that
list can be used within the network to reach the container.
Defaults to ``None``.
links (list): A list of links for this endpoint. Containers
declared in this list will be linkedto this container.
Defaults to ``None``.
aliases (:py:class:`list`): A list of aliases for this endpoint.
Names in that list can be used within the network to reach the
container. Defaults to ``None``.
links (:py:class:`list`): A list of links for this endpoint.
Containers declared in this list will be linked to this
container. Defaults to ``None``.
ipv4_address (str): The IP address of this container on the
network, using the IPv4 protocol. Defaults to ``None``.
ipv6_address (str): The IP address of this container on the
network, using the IPv6 protocol. Defaults to ``None``.
link_local_ips (list): A list of link-local (IPv4/IPv6) addresses.
link_local_ips (:py:class:`list`): A list of link-local
(IPv4/IPv6) addresses.
"""
data = {
"Container": container,
......
import warnings
from .. import auth, errors, utils
from ..types import ServiceMode
class ServiceApiMixin(object):
......@@ -13,18 +14,18 @@ class ServiceApiMixin(object):
Create a service.
Args:
task_template (dict): Specification of the task to start as part
of the new service.
task_template (TaskTemplate): Specification of the task to start as
part of the new service.
name (string): User-defined name for the service. Optional.
labels (dict): A map of labels to associate with the service.
Optional.
mode (string): Scheduling mode for the service (``replicated`` or
``global``). Defaults to ``replicated``.
update_config (dict): Specification for the update strategy of the
service. Default: ``None``
networks (list): List of network names or IDs to attach the
service to. Default: ``None``.
endpoint_config (dict): Properties that can be configured to
mode (ServiceMode): Scheduling mode for the service (replicated
or global). Defaults to replicated.
update_config (UpdateConfig): Specification for the update strategy
of the service. Default: ``None``
networks (:py:class:`list`): List of network names or IDs to attach
the service to. Default: ``None``.
endpoint_spec (EndpointSpec): Properties that can be configured to
access and load balance a service. Default: ``None``.
Returns:
......@@ -49,6 +50,9 @@ class ServiceApiMixin(object):
raise errors.DockerException(
'Missing mandatory Image key in ContainerSpec'
)
if mode and not isinstance(mode, dict):
mode = ServiceMode(mode)
registry, repo_name = auth.resolve_repository_name(image)
auth_header = auth.get_config_header(self, registry)
if auth_header:
......@@ -159,7 +163,7 @@ class ServiceApiMixin(object):
``label`` and ``desired-state``.
Returns:
(list): List of task dictionaries.
(:py:class:`list`): List of task dictionaries.
Raises:
:py:class:`docker.errors.APIError`
......@@ -186,20 +190,18 @@ class ServiceApiMixin(object):
ID).
version (int): The version number of the service object being
updated. This is required to avoid conflicting writes.
task_template (dict): Specification of the updated task to start
as part of the service. See the [TaskTemplate
class](#TaskTemplate) for details.
task_template (TaskTemplate): Specification of the updated task to
start as part of the service.
name (string): New name for the service. Optional.
labels (dict): A map of labels to associate with the service.
Optional.
mode (string): Scheduling mode for the service (``replicated`` or
``global``). Defaults to ``replicated``.
update_config (dict): Specification for the update strategy of the
service. See the [UpdateConfig class](#UpdateConfig) for
details. Default: ``None``.
networks (list): List of network names or IDs to attach the
service to. Default: ``None``.
endpoint_config (dict): Properties that can be configured to
mode (ServiceMode): Scheduling mode for the service (replicated
or global). Defaults to replicated.
update_config (UpdateConfig): Specification for the update strategy
of the service. Default: ``None``.
networks (:py:class:`list`): List of network names or IDs to attach
the service to. Default: ``None``.
endpoint_spec (EndpointSpec): Properties that can be configured to
access and load balance a service. Default: ``None``.
Returns:
......@@ -224,6 +226,8 @@ class ServiceApiMixin(object):
if labels is not None:
data['Labels'] = labels
if mode is not None:
if not isinstance(mode, dict):
mode = ServiceMode(mode)
data['Mode'] = mode
if task_template is not None:
image = task_template.get('ContainerSpec', {}).get('Image', None)
......
......@@ -143,8 +143,8 @@ class SwarmApiMixin(object):
Make this Engine join a swarm that has already been created.
Args:
remote_addrs (list): Addresses of one or more manager nodes already
participating in the Swarm to join.
remote_addrs (:py:class:`list`): Addresses of one or more manager
nodes already participating in the Swarm to join.
join_token (string): Secret token for joining this Swarm.
listen_addr (string): Listen address used for inter-manager
communication if the node gets promoted to manager, as well as
......
......@@ -468,17 +468,17 @@ class ContainerCollection(Collection):
device_write_bps: Limit write rate (bytes per second) from a
device.
device_write_iops: Limit write rate (IO per second) from a device.
devices (list): Expose host devices to the container, as a list
of strings in the form
devices (:py:class:`list`): Expose host devices to the container,
as a list of strings in the form
``<path_on_host>:<path_in_container>:<cgroup_permissions>``.
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.
dns (list): Set custom DNS servers.
dns_opt (list): Additional options to be added to the container's
``resolv.conf`` file.
dns_search (list): DNS search domains.
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.
dns_search (:py:class:`list`): DNS search domains.
domainname (str or list): Set custom DNS search domains.
entrypoint (str or list): The entrypoint for the container.
environment (dict or list): Environment variables to set inside
......@@ -486,8 +486,8 @@ class ContainerCollection(Collection):
format ``["SOMEVARIABLE=xxx"]``.
extra_hosts (dict): Addtional hostnames to resolve inside the
container, as a mapping of hostname to IP address.
group_add (list): List of additional group names and/or IDs that
the container process will run as.
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.
ipc_mode (str): Set the IPC mode for the container.
isolation (str): Isolation technology to use. Default: `None`.
......@@ -517,8 +517,8 @@ class ContainerCollection(Collection):
behavior. Accepts number between 0 and 100.
memswap_limit (str or int): Maximum amount of memory + swap a
container is allowed to consume.
networks (list): A list of network names to connect this
container to.
networks (:py:class:`list`): A list of network names to connect
this container to.
name (str): The name for this container.
network_disabled (bool): Disable networking.
network_mode (str): One of:
......@@ -574,8 +574,8 @@ class ContainerCollection(Collection):
For example:
``{"Name": "on-failure", "MaximumRetryCount": 5}``
security_opt (list): A list of string values to customize labels
for MLS systems, such as SELinux.
security_opt (:py:class:`list`): A list of string values to
customize labels for MLS systems, such as SELinux.
shm_size (str or int): Size of /dev/shm (e.g. ``1G``).
stdin_open (bool): Keep ``STDIN`` open even if not attached.
stdout (bool): Return logs from ``STDOUT`` when ``detach=False``.
......@@ -598,8 +598,8 @@ class ContainerCollection(Collection):
}
tty (bool): Allocate a pseudo-TTY.
ulimits (list): Ulimits to set inside the container, as a list of
dicts.
ulimits (:py:class:`list`): Ulimits to set inside the container, as
a list of dicts.
user (str or int): Username or UID to run commands as inside the
container.
userns_mode (str): Sets the user namespace mode for the container
......@@ -621,8 +621,8 @@ class ContainerCollection(Collection):
{'/home/user1/': {'bind': '/mnt/vol2', 'mode': 'rw'},
'/var/www': {'bind': '/mnt/vol1', 'mode': 'ro'}}
volumes_from (list): List of container names or IDs to get
volumes from.
volumes_from (:py:class:`list`): List of container names or IDs to
get volumes from.
working_dir (str): Path to the working directory.
Returns:
......
......@@ -30,10 +30,10 @@ class Image(Model):
"""
The image's tags.
"""
return [
tag for tag in self.attrs.get('RepoTags', [])
if tag != '<none>:<none>'
]
tags = self.attrs.get('RepoTags')
if tags is None:
tags = []
return [tag for tag in tags if tag != '<none>:<none>']
def history(self):
"""
......
......@@ -32,17 +32,18 @@ class Network(Model):
container (str): Container to connect to this network, as either
an ID, name, or :py:class:`~docker.models.containers.Container`
object.
aliases (list): A list of aliases for this endpoint. Names in that
list can be used within the network to reach the container.
Defaults to ``None``.
links (list): A list of links for this endpoint. Containers
declared in this list will be linkedto this container.
Defaults to ``None``.
aliases (:py:class:`list`): A list of aliases for this endpoint.
Names in that list can be used within the network to reach the
container. Defaults to ``None``.
links (:py:class:`list`): A list of links for this endpoint.
Containers declared in this list will be linkedto this
container. Defaults to ``None``.
ipv4_address (str): The IP address of this container on the
network, using the IPv4 protocol. Defaults to ``None``.
ipv6_address (str): The IP address of this container on the
network, using the IPv6 protocol. Defaults to ``None``.
link_local_ips (list): A list of link-local (IPv4/IPv6) addresses.
link_local_ips (:py:class:`list`): A list of link-local (IPv4/IPv6)
addresses.
Raises:
:py:class:`docker.errors.APIError`
......@@ -167,8 +168,8 @@ class NetworkCollection(Collection):
List networks. Similar to the ``docker networks ls`` command.
Args:
names (list): List of names to filter by.
ids (list): List of ids to filter by.
names (:py:class:`list`): List of names to filter by.
ids (:py:class:`list`): List of ids to filter by.
Returns:
(list of :py:class:`Network`) The networks on the server.
......
......@@ -23,6 +23,9 @@ class Model(object):
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))
@property
def id(self):
"""
......
......@@ -42,7 +42,7 @@ class Service(Model):
``label``, and ``desired-state``.
Returns:
(list): List of task dictionaries.
(:py:class:`list`): List of task dictionaries.
Raises:
:py:class:`docker.errors.APIError`
......@@ -92,29 +92,27 @@ class ServiceCollection(Collection):
args (list of str): Arguments to the command.
constraints (list of str): Placement constraints.
container_labels (dict): Labels to apply to the container.
endpoint_spec (dict): Properties that can be configured to
endpoint_spec (EndpointSpec): Properties that can be configured to
access and load balance a service. Default: ``None``.
env (list of str): Environment variables, in the form
``KEY=val``.
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 (string): Scheduling mode for the service (``replicated`` or
mode (str): Scheduling mode for the service (``replicated`` or
``global``). Defaults to ``replicated``.
mounts (list of str): Mounts for the containers, in the form
``source:target:options``, where options is either
``ro`` or ``rw``.
name (str): Name to give to the service.
networks (list): List of network names or IDs to attach the
service to. Default: ``None``.
resources (dict): Resource limits and reservations. For the
format, see the Remote API documentation.
restart_policy (dict): Restart policy for containers. For the
format, see the Remote API documentation.
networks (list of str): List of network names or IDs to attach
the service to. Default: ``None``.
resources (Resources): Resource limits and reservations.
restart_policy (RestartPolicy): Restart policy for containers.
stop_grace_period (int): Amount of time to wait for
containers to terminate before forcefully killing them.
update_config (dict): Specification for the update strategy of the
service. Default: ``None``
update_config (UpdateConfig): Specification for the update strategy
of the service. Default: ``None``
user (str): User to run commands as.
workdir (str): Working directory for commands to run.
......
......@@ -4,6 +4,6 @@ from .healthcheck import Healthcheck
from .networks import EndpointConfig, IPAMConfig, IPAMPool, NetworkingConfig
from .services import (
ContainerSpec, DriverConfig, EndpointSpec, Mount, Resources, RestartPolicy,
TaskTemplate, UpdateConfig
ServiceMode, TaskTemplate, UpdateConfig
)
from .swarm import SwarmSpec, SwarmExternalCA
......@@ -48,7 +48,7 @@ class IPAMConfig(dict):
Args:
driver (str): The IPAM driver to use. Defaults to ``default``.
pool_configs (list): A list of pool configurations
pool_configs (:py:class:`list`): A list of pool configurations
(:py:class:`~docker.types.IPAMPool`). Defaults to empty list.
options (dict): Driver options as a key-value dictionary.
Defaults to `None`.
......
......@@ -20,7 +20,7 @@ class TaskTemplate(dict):
individual container created as part of the service.
restart_policy (RestartPolicy): Specification for the restart policy
which applies to containers created as part of this service.
placement (list): A list of constraints.
placement (:py:class:`list`): A list of constraints.
"""
def __init__(self, container_spec, resources=None, restart_policy=None,
placement=None, log_driver=None):
......@@ -62,16 +62,16 @@ 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 (list): Arguments to the command.
args (:py:class:`list`): Arguments to the command.
env (dict): Environment variables.
dir (string): The working directory for commands to run in.
user (string): The user inside the container.
labels (dict): A map of labels to associate with the service.
mounts (list): A list of specifications for mounts to be added to
containers created as part of the service. See the
:py:class:`~docker.types.Mount` class for details.
mounts (:py:class:`list`): A list of specifications for mounts to be
added to containers created as part of the service. See the
:py:class:`~docker.types.Mount` class for details.
stop_grace_period (int): Amount of time to wait for the container to
terminate before forcefully killing it.
terminate before forcefully killing it.
"""
def __init__(self, image, command=None, args=None, env=None, workdir=None,
user=None, labels=None, mounts=None, stop_grace_period=None):
......@@ -106,7 +106,7 @@ class ContainerSpec(dict):
class Mount(dict):
"""
Describes a mounted folder's configuration inside a container. A list of
``Mount``s would be used as part of a
:py:class:`Mount`s would be used as part of a
:py:class:`~docker.types.ContainerSpec`.
Args:
......@@ -348,3 +348,38 @@ def convert_service_ports(ports):
result.append(port_spec)
return result
class ServiceMode(dict):
"""
Indicate whether a service should be deployed as a replicated or global
service, and associated parameters
Args:
mode (string): Can be either ``replicated`` or ``global``
replicas (int): Number of replicas. For replicated services only.
"""
def __init__(self, mode, replicas=None):
if mode not in ('replicated', 'global'):
raise errors.InvalidArgument(
'mode must be either "replicated" or "global"'
)
if mode != 'replicated' and replicas is not None:
raise errors.InvalidArgument(
'replicas can only be used for replicated mode'
)
self[mode] = {}
if replicas:
self[mode]['Replicas'] = replicas
@property
def mode(self):
if 'global' in self:
return 'global'
return 'replicated'
@property
def replicas(self):
if self.mode != 'replicated':
return None
return self['replicated'].get('Replicas')
version = "2.0.1"
version = "2.0.2"
version_info = tuple([int(d) for d in version.split("-")[0].split(".")])
......@@ -19,8 +19,6 @@ Containers
:members:
:undoc-members:
.. py:module:: docker.api.image
Images
------
......@@ -112,5 +110,6 @@ Configuration types
.. autoclass:: Mount
.. autoclass:: Resources
.. autoclass:: RestartPolicy
.. autoclass:: ServiceMode
.. autoclass:: TaskTemplate
.. autoclass:: UpdateConfig
Change log
==========
2.0.2
-----
[List of PRs / issues for this release](https://github.com/docker/docker-py/milestone/28?closed=1)
### Bugfixes
* Installation of the package now fails if the `docker-py` package is
installed in order to prevent obscure naming conflicts when both
packages co-exist.
* Added missing `filters` parameter to `APIClient.networks`.
* Resource objects generated by the `DockerClient` are now hashable.
* Fixed a bug where retrieving untagged images using `DockerClient`
would raise a `TypeError` exception.
* `mode` parameter in `create_service` is now properly converted to
a valid data type for the Engine API. Use `ServiceMode` for advanced
configurations.
* Fixed a bug where the decoded `APIClient.events` stream would sometimes raise
an exception when a container is stopped or restarted.
2.0.1
-----
......
......@@ -73,13 +73,12 @@ You can manage images:
>>> client.images.list()
[<Image 'ubuntu'>, <Image 'nginx'>, ...]
That's just a taster of what you can do with the Docker SDK for Python. For more, :doc:`take a look at the reference <client>`.
That's just a taste of what you can do with the Docker SDK for Python. For more, :doc:`take a look at the reference <client>`.
.. toctree::
:hidden:
:maxdepth: 2
Home <index>
client
containers
images
......
#!/usr/bin/env python
from __future__ import print_function
import codecs
import os
import sys
import pip
from setuptools import setup, find_packages
if 'docker-py' in [x.project_name for x in pip.get_installed_distributions()]:
print(
'ERROR: "docker-py" needs to be uninstalled before installing this'
' package:\npip uninstall docker-py', file=sys.stderr
)
sys.exit(1)
ROOT_DIR = os.path.dirname(__file__)
SOURCE_DIR = os.path.join(ROOT_DIR)
......
......@@ -251,3 +251,31 @@ class ServiceTest(BaseAPIIntegrationTest):
con_spec = svc_info['Spec']['TaskTemplate']['ContainerSpec']
assert 'Env' in con_spec
assert con_spec['Env'] == ['DOCKER_PY_TEST=1']
def test_create_service_global_mode(self):
container_spec = docker.types.ContainerSpec(
'busybox', ['echo', 'hello']
)
task_tmpl = docker.types.TaskTemplate(container_spec)
name = self.get_service_name()
svc_id = self.client.create_service(
task_tmpl, name=name, mode='global'
)
svc_info = self.client.inspect_service(svc_id)
assert 'Mode' in svc_info['Spec']
assert 'Global' in svc_info['Spec']['Mode']
def test_create_service_replicated_mode(self):
container_spec = docker.types.ContainerSpec(
'busybox', ['echo', 'hello']
)
task_tmpl = docker.types.TaskTemplate(container_spec)
name = self.get_service_name()
svc_id = self.client.create_service(
task_tmpl, name=name,
mode=docker.types.ServiceMode('replicated', 5)
)
svc_info = self.client.inspect_service(svc_id)
assert 'Mode' in svc_info['Spec']
assert 'Replicated' in svc_info['Spec']['Mode']
assert svc_info['Spec']['Mode']['Replicated'] == {'Replicas': 5}
......@@ -7,7 +7,8 @@ import pytest
from docker.constants import DEFAULT_DOCKER_API_VERSION
from docker.errors import InvalidArgument, InvalidVersion
from docker.types import (
EndpointConfig, HostConfig, IPAMConfig, IPAMPool, LogConfig, Mount, Ulimit,
EndpointConfig, HostConfig, IPAMConfig, IPAMPool, LogConfig, Mount,
ServiceMode, Ulimit,
)
try:
......@@ -260,7 +261,35 @@ class IPAMConfigTest(unittest.TestCase):
})
class TestMounts(unittest.TestCase):
class ServiceModeTest(unittest.TestCase):
def test_replicated_simple(self):
mode = ServiceMode('replicated')
assert mode == {'replicated': {}}
assert mode.mode == 'replicated'
assert mode.replicas is None
def test_global_simple(self):
mode = ServiceMode('global')
assert mode == {'global': {}}
assert mode.mode == 'global'
assert mode.replicas is None
def test_global_replicas_error(self):
with pytest.raises(InvalidArgument):
ServiceMode('global', 21)
def test_replicated_replicas(self):
mode = ServiceMode('replicated', 21)
assert mode == {'replicated': {'Replicas': 21}}
assert mode.mode == 'replicated'
assert mode.replicas == 21
def test_invalid_mode(self):
with pytest.raises(InvalidArgument):
ServiceMode('foobar')
class MountTest(unittest.TestCase):
def test_parse_mount_string_ro(self):
mount = Mount.parse_mount_string("/foo/bar:/baz:ro")
assert mount['Source'] == "/foo/bar"
......
......@@ -83,6 +83,11 @@ class ImageTest(unittest.TestCase):
})
assert image.tags == []
image = Image(attrs={
'RepoTags': None
})
assert image.tags == []
def test_history(self):
client = make_fake_client()
image = client.images.get(FAKE_IMAGE_ID)
......
......@@ -12,3 +12,17 @@ class ModelTest(unittest.TestCase):
container.reload()
assert client.api.inspect_container.call_count == 2
assert container.attrs['Name'] == "foobar"
def test_hash(self):
client = make_fake_client()
container1 = client.containers.get(FAKE_CONTAINER_ID)
my_set = set([container1])
assert len(my_set) == 1
container2 = client.containers.get(FAKE_CONTAINER_ID)
my_set.add(container2)
assert len(my_set) == 1
image1 = client.images.get(FAKE_CONTAINER_ID)
my_set.add(image1)
assert len(my_set) == 2
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment