Unverified Kaydet (Commit) f32c0c17 authored tarafından Ben Firshman's avatar Ben Firshman

Add docstrings to low-level API

Signed-off-by: 's avatarBen Firshman <ben@firshman.co.uk>
üst ed959f21
...@@ -19,6 +19,89 @@ class BuildApiMixin(object): ...@@ -19,6 +19,89 @@ class BuildApiMixin(object):
forcerm=False, dockerfile=None, container_limits=None, forcerm=False, dockerfile=None, container_limits=None,
decode=False, buildargs=None, gzip=False, shmsize=None, decode=False, buildargs=None, gzip=False, shmsize=None,
labels=None): labels=None):
"""
Similar to the ``docker build`` command. Either ``path`` or ``fileobj``
needs to be set. ``path`` can be a local path (to a directory
containing a Dockerfile) or a remote URL. ``fileobj`` must be a
readable file-like object to a Dockerfile.
If you have a tar file for the Docker build context (including a
Dockerfile) already, pass a readable file-like object to ``fileobj``
and also pass ``custom_context=True``. If the stream is compressed
also, set ``encoding`` to the correct value (e.g ``gzip``).
Example:
>>> from io import BytesIO
>>> from docker import Client
>>> dockerfile = '''
... # Shared Volume
... FROM busybox:buildroot-2014.02
... VOLUME /data
... CMD ["/bin/sh"]
... '''
>>> f = BytesIO(dockerfile.encode('utf-8'))
>>> cli = Client(base_url='tcp://127.0.0.1:2375')
>>> response = [line for line in cli.build(
... fileobj=f, rm=True, tag='yourname/volume'
... )]
>>> response
['{"stream":" ---\\u003e a9eb17255234\\n"}',
'{"stream":"Step 1 : VOLUME /data\\n"}',
'{"stream":" ---\\u003e Running in abdc1e6896c6\\n"}',
'{"stream":" ---\\u003e 713bca62012e\\n"}',
'{"stream":"Removing intermediate container abdc1e6896c6\\n"}',
'{"stream":"Step 2 : CMD [\\"/bin/sh\\"]\\n"}',
'{"stream":" ---\\u003e Running in dba30f2a1a7e\\n"}',
'{"stream":" ---\\u003e 032b8b2855fc\\n"}',
'{"stream":"Removing intermediate container dba30f2a1a7e\\n"}',
'{"stream":"Successfully built 032b8b2855fc\\n"}']
Args:
path (str): Path to the directory containing the Dockerfile
fileobj: A file object to use as the Dockerfile. (Or a file-like
object)
tag (str): A tag to add to the final image
quiet (bool): Whether to return the status
nocache (bool): Don't use the cache when set to ``True``
rm (bool): Remove intermediate containers. The ``docker build``
command now defaults to ``--rm=true``, but we have kept the old
default of `False` to preserve backward compatibility
stream (bool): *Deprecated for API version > 1.8 (always True)*.
Return a blocking generator you can iterate over to retrieve
build output as it happens
timeout (int): HTTP timeout
custom_context (bool): Optional if using ``fileobj``
encoding (str): The encoding for a stream. Set to ``gzip`` for
compressing
pull (bool): Downloads any updates to the FROM image in Dockerfiles
forcerm (bool): Always remove intermediate containers, even after
unsuccessful builds
dockerfile (str): path within the build context to the Dockerfile
buildargs (dict): A dictionary of build arguments
container_limits (dict): A dictionary of limits applied to each
container created by the build process. Valid keys:
- memory (int): set memory limit for build
- memswap (int): Total memory (memory + swap), -1 to disable
swap
- cpushares (int): CPU shares (relative weight)
- cpusetcpus (str): CPUs in which to allow execution, e.g.,
``"0-3"``, ``"0,1"``
decode (bool): If set to ``True``, the returned stream will be
decoded into dicts on the fly. Default ``False``.
shmsize (int): Size of `/dev/shm` in bytes. The size must be
greater than 0. If omitted the system uses 64MB.
labels (dict): A dictionary of labels to set on the image.
Returns:
A generator for the build output.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
``TypeError``
If neither ``path`` nor ``fileobj`` is specified.
"""
remote = context = None remote = context = None
headers = {} headers = {}
container_limits = container_limits or {} container_limits = container_limits or {}
......
...@@ -51,8 +51,32 @@ class APIClient( ...@@ -51,8 +51,32 @@ class APIClient(
""" """
A low-level client for the Docker Remote API. A low-level client for the Docker Remote API.
Each method maps one-to-one with a REST API endpoint, so calling each Example:
method results in a single API call.
>>> import docker
>>> client = docker.APIClient(base_url='unix://var/run/docker.sock')
>>> client.version()
{u'ApiVersion': u'1.24',
u'Arch': u'amd64',
u'BuildTime': u'2016-09-27T23:38:15.810178467+00:00',
u'Experimental': True,
u'GitCommit': u'45bed2c',
u'GoVersion': u'go1.6.3',
u'KernelVersion': u'4.4.22-moby',
u'Os': u'linux',
u'Version': u'1.12.2-rc1'}
Args:
base_url (str): URL to the Docker server. For example,
``unix:///var/run/docker.sock`` or ``tcp://127.0.0.1:1234``.
version (str): The version of the API to use. Set to ``auto`` to
automatically detect the server's version. Default: ``1.24``
timeout (int): Default timeout for API calls, in seconds.
tls (bool or :py:class:`~docker.tls.TLSConfig`): Enable TLS. Pass
``True`` to enable it with default options, or pass a
:py:class:`~docker.tls.TLSConfig` object to use custom
configuration.
user_agent (str): Set a custom user agent for requests to the server.
""" """
def __init__(self, base_url=None, version=None, def __init__(self, base_url=None, version=None,
timeout=DEFAULT_TIMEOUT_SECONDS, tls=False, timeout=DEFAULT_TIMEOUT_SECONDS, tls=False,
......
...@@ -11,6 +11,30 @@ class ContainerApiMixin(object): ...@@ -11,6 +11,30 @@ class ContainerApiMixin(object):
@utils.check_resource @utils.check_resource
def attach(self, container, stdout=True, stderr=True, def attach(self, container, stdout=True, stderr=True,
stream=False, logs=False): stream=False, logs=False):
"""
Attach to a container.
The ``.logs()`` function is a wrapper around this method, which you can
use instead if you want to fetch/stream container output without first
retrieving the entire backlog.
Args:
container (str): The container to attach to.
stdout (bool): Include stdout.
stderr (bool): Include stderr.
stream (bool): Return container output progressively as an iterator
of strings, rather than a single string.
logs (bool): Include the container's previous output.
Returns:
By default, the container's output as a single string.
If ``stream=True``, an iterator of output strings.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
params = { params = {
'logs': logs and 1 or 0, 'logs': logs and 1 or 0,
'stdout': stdout and 1 or 0, 'stdout': stdout and 1 or 0,
...@@ -30,6 +54,20 @@ class ContainerApiMixin(object): ...@@ -30,6 +54,20 @@ class ContainerApiMixin(object):
@utils.check_resource @utils.check_resource
def attach_socket(self, container, params=None, ws=False): def attach_socket(self, container, params=None, ws=False):
"""
Like ``attach``, but returns the underlying socket-like object for the
HTTP request.
Args:
container (str): The container to attach to.
params (dict): Dictionary of request parameters (e.g. ``stdout``,
``stderr``, ``stream``).
ws (bool): Use websockets instead of raw HTTP.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
if params is None: if params is None:
params = { params = {
'stdout': 1, 'stdout': 1,
...@@ -56,6 +94,26 @@ class ContainerApiMixin(object): ...@@ -56,6 +94,26 @@ class ContainerApiMixin(object):
@utils.check_resource @utils.check_resource
def commit(self, container, repository=None, tag=None, message=None, def commit(self, container, repository=None, tag=None, message=None,
author=None, changes=None, conf=None): author=None, changes=None, conf=None):
"""
Commit a container to an image. Similar to the ``docker commit``
command.
Args:
container (str): The image hash of the container
repository (str): The repository to push the image to
tag (str): The tag to push
message (str): A commit message
author (str): The name of the author
changes (str): Dockerfile instructions to apply while committing
conf (dict): The configuration for the container. See the
`Remote API documentation
<https://docs.docker.com/reference/api/docker_remote_api/>`_
for full details.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
params = { params = {
'container': container, 'container': container,
'repo': repository, 'repo': repository,
...@@ -71,6 +129,50 @@ class ContainerApiMixin(object): ...@@ -71,6 +129,50 @@ class ContainerApiMixin(object):
def containers(self, quiet=False, all=False, trunc=False, latest=False, def containers(self, quiet=False, all=False, trunc=False, latest=False,
since=None, before=None, limit=-1, size=False, since=None, before=None, limit=-1, size=False,
filters=None): filters=None):
"""
List containers. Similar to the ``docker ps`` command.
Args:
quiet (bool): Only display numeric Ids
all (bool): Show all containers. Only running containers are shown
by default trunc (bool): Truncate output
latest (bool): Show only the latest created container, include
non-running ones.
since (str): Show only containers created since Id or Name, include
non-running ones
before (str): Show only container created before Id or Name,
include non-running ones
limit (int): Show `limit` last created containers, include
non-running ones
size (bool): Display sizes
filters (dict): Filters to be processed on the image list.
Available filters:
- `exited` (int): Only containers with specified exit code
- `status` (str): One of ``restarting``, ``running``,
``paused``, ``exited``
- `label` (str): format either ``"key"`` or ``"key=value"``
- `id` (str): The id of the container.
- `name` (str): The name of the container.
- `ancestor` (str): Filter by container ancestor. Format of
``<image-name>[:tag]``, ``<image-id>``, or
``<image@digest>``.
- `before` (str): Only containers created before a particular
container. Give the container name or id.
- `since` (str): Only containers created after a particular
container. Give container name or id.
A comprehensive list can be found in the documentation for
`docker ps
<https://docs.docker.com/engine/reference/commandline/ps>`_.
Returns:
A list of dicts, one per container
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
params = { params = {
'limit': 1 if latest else limit, 'limit': 1 if latest else limit,
'all': 1 if all else 0, 'all': 1 if all else 0,
...@@ -93,6 +195,24 @@ class ContainerApiMixin(object): ...@@ -93,6 +195,24 @@ class ContainerApiMixin(object):
@utils.check_resource @utils.check_resource
def copy(self, container, resource): def copy(self, container, resource):
"""
Identical to the ``docker cp`` command. Get files/folders from the
container.
**Deprecated for API version >= 1.20.** Use
:py:meth:`~ContainerApiMixin.get_archive` instead.
Args:
container (str): The container to copy from
resource (str): The path within the container
Returns:
The contents of the file as a string
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
if utils.version_gte(self._version, '1.20'): if utils.version_gte(self._version, '1.20'):
warnings.warn( warnings.warn(
'Client.copy() is deprecated for API version >= 1.20, ' 'Client.copy() is deprecated for API version >= 1.20, '
...@@ -117,7 +237,190 @@ class ContainerApiMixin(object): ...@@ -117,7 +237,190 @@ class ContainerApiMixin(object):
mac_address=None, labels=None, volume_driver=None, mac_address=None, labels=None, volume_driver=None,
stop_signal=None, networking_config=None, stop_signal=None, networking_config=None,
healthcheck=None): healthcheck=None):
"""
Creates a container. Parameters are similar to those for the ``docker
run`` command except it doesn't support the attach options (``-a``).
The arguments that are passed directly to this function are
host-independent configuration options. Host-specific configuration
is passed with the `host_config` argument. You'll normally want to
use this method in combination with the :py:meth:`create_host_config`
method to generate ``host_config``.
**Port bindings**
Port binding is done in two parts: first, provide a list of ports to
open inside the container with the ``ports`` parameter, then declare
bindings with the ``host_config`` parameter. For example:
.. code-block:: python
container_id = cli.create_container(
'busybox', 'ls', ports=[1111, 2222],
host_config=cli.create_host_config(port_bindings={
1111: 4567,
2222: None
})
)
You can limit the host address on which the port will be exposed like
such:
.. code-block:: python
cli.create_host_config(port_bindings={1111: ('127.0.0.1', 4567)})
Or without host port assignment:
.. code-block:: python
cli.create_host_config(port_bindings={1111: ('127.0.0.1',)})
If you wish to use UDP instead of TCP (default), you need to declare
ports as such in both the config and host config:
.. code-block:: python
container_id = cli.create_container(
'busybox', 'ls', ports=[(1111, 'udp'), 2222],
host_config=cli.create_host_config(port_bindings={
'1111/udp': 4567, 2222: None
})
)
To bind multiple host ports to a single container port, use the
following syntax:
.. code-block:: python
cli.create_host_config(port_bindings={
1111: [1234, 4567]
})
You can also bind multiple IPs to a single container port:
.. code-block:: python
cli.create_host_config(port_bindings={
1111: [
('192.168.0.100', 1234),
('192.168.0.101', 1234)
]
})
**Using volumes**
Volume declaration is done in two parts. Provide a list of mountpoints
to the with the ``volumes`` parameter, and declare mappings in the
``host_config`` section.
.. code-block:: python
container_id = cli.create_container(
'busybox', 'ls', volumes=['/mnt/vol1', '/mnt/vol2'],
host_config=cli.create_host_config(binds={
'/home/user1/': {
'bind': '/mnt/vol2',
'mode': 'rw',
},
'/var/www': {
'bind': '/mnt/vol1',
'mode': 'ro',
}
})
)
You can alternatively specify binds as a list. This code is equivalent
to the example above:
.. code-block:: python
container_id = cli.create_container(
'busybox', 'ls', volumes=['/mnt/vol1', '/mnt/vol2'],
host_config=cli.create_host_config(binds=[
'/home/user1/:/mnt/vol2',
'/var/www:/mnt/vol1:ro',
])
)
**Networking**
You can specify networks to connect the container to by using the
``networking_config`` parameter. At the time of creation, you can
only connect a container to a single networking, but you
can create more connections by using
:py:meth:`~connect_container_to_network`.
For example:
.. code-block:: python
networking_config = docker_client.create_networking_config({
'network1': docker_client.create_endpoint_config(
ipv4_address='172.28.0.124',
aliases=['foo', 'bar'],
links=['container2']
)
})
ctnr = docker_client.create_container(
img, command, networking_config=networking_config
)
Args:
image (str): The image to run
command (str or list): The command to be run in the container
hostname (str): Optional hostname for the container
user (str or int): Username or UID
detach (bool): Detached mode: run container in the background and
return container ID
stdin_open (bool): Keep STDIN open even if not attached
tty (bool): Allocate a pseudo-TTY
mem_limit (float or str): Memory limit. Accepts float values (which
represent the memory limit of the created container in bytes)
or a string with a units identification char (``100000b``,
``1000k``, ``128m``, ``1g``). If a string is specified without
a units character, bytes are assumed as an intended unit.
ports (list of ints): A list of port numbers
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
volumes (str or list):
volumes_from (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
working_dir (str): Path to the working directory
domainname (str or list): Set custom DNS search domains
memswap_limit (int):
host_config (dict): A dictionary created with
:py:meth:`create_host_config`.
mac_address (str): The Mac Address to assign the container
labels (dict or list): A dictionary of name-value labels (e.g.
``{"label1": "value1", "label2": "value2"}``) or a list of
names of labels to set with empty values (e.g.
``["label1", "label2"]``)
volume_driver (str): The name of a volume driver/plugin.
stop_signal (str): The stop signal to use to stop the container
(e.g. ``SIGINT``).
networking_config (dict): A networking configuration generated
by :py:meth:`create_networking_config`.
Returns:
A dictionary with an image 'Id' key and a 'Warnings' key.
Raises:
:py:class:`docker.errors.ImageNotFound`
If the specified image does not exist.
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
if isinstance(volumes, six.string_types): if isinstance(volumes, six.string_types):
volumes = [volumes, ] volumes = [volumes, ]
...@@ -147,6 +450,130 @@ class ContainerApiMixin(object): ...@@ -147,6 +450,130 @@ class ContainerApiMixin(object):
return self._result(res, True) return self._result(res, True)
def create_host_config(self, *args, **kwargs): def create_host_config(self, *args, **kwargs):
"""
Create a dictionary for the ``host_config`` argument to
:py:meth:`create_container`.
Args:
binds (dict): Volumes to bind. See :py:meth:`create_container`
for more information.
blkio_weight_device: Block IO weight (relative device weight) in
the form of: ``[{"Path": "device_path", "Weight": weight}]``.
blkio_weight: Block IO weight (relative weight), accepts a weight
value between 10 and 1000.
cap_add (list of str): Add kernel capabilities. For example,
``["SYS_ADMIN", "MKNOD"]``.
cap_drop (list of str): Drop kernel capabilities.
cpu_group (int): The length of a CPU period in microseconds.
cpu_period (int): Microseconds of CPU time that the container can
get in a CPU period.
cpu_shares (int): CPU shares (relative weight).
cpuset_cpus (str): CPUs in which to allow execution (``0-3``,
``0,1``).
device_read_bps: Limit read rate (bytes per second) from a device
in the form of: `[{"Path": "device_path", "Rate": rate}]`
device_read_iops: Limit read rate (IO per second) from a device.
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
``<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.
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.
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
to alias or as a list of ``(name, alias)`` tuples.
log_config (dict): Logging configuration, as a dictionary with
keys:
- ``type`` The logging driver name.
- ``config`` A dictionary of configuration for the logging
driver.
lxc_conf (dict): LXC config.
mem_limit (float or str): Memory limit. Accepts float values
(which represent the memory limit of the created container in
bytes) or a string with a units identification char
(``100000b``, ``1000k``, ``128m``, ``1g``). If a string is
specified without a units character, bytes are assumed as an
mem_swappiness (int): Tune a container's memory swappiness
behavior. Accepts number between 0 and 100.
memswap_limit (str or int): Maximum amount of memory + swap a
container is allowed to consume.
network_mode (str): One of:
- ``bridge`` Create a new network stack for the container on
on the bridge network.
- ``none`` No networking for this container.
- ``container:<name|id>`` Reuse another container's network
stack.
- ``host`` Use the host network stack.
oom_kill_disable (bool): Whether to disable OOM killer.
oom_score_adj (int): An integer value containing the score given
to the container in order to tune OOM killer preferences.
pid_mode (str): If set to ``host``, use the host PID namespace
inside the container.
pids_limit (int): Tune a container's pids limit. Set ``-1`` for
unlimited.
port_bindings (dict): See :py:meth:`create_container`
for more information.
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
only.
restart_policy (dict): Restart the container when it exits.
Configured as a dictionary with keys:
- ``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.
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
mapping a path inside the container to options for that path.
For example:
.. code-block:: python
{
'/mnt/vol2': '',
'/mnt/vol1': 'size=3G,uid=1000'
}
ulimits (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.
Returns:
(dict) A dictionary which can be passed to the ``host_config``
argument to :py:meth:`create_container`.
Example:
>>> cli.create_host_config(privileged=True, cap_drop=['MKNOD'],
volumes_from=['nostalgic_newton'])
{'CapDrop': ['MKNOD'], 'LxcConf': None, 'Privileged': True,
'VolumesFrom': ['nostalgic_newton'], 'PublishAllPorts': False}
"""
if not kwargs: if not kwargs:
kwargs = {} kwargs = {}
if 'version' in kwargs: if 'version' in kwargs:
...@@ -158,19 +585,98 @@ class ContainerApiMixin(object): ...@@ -158,19 +585,98 @@ class ContainerApiMixin(object):
return utils.create_host_config(*args, **kwargs) return utils.create_host_config(*args, **kwargs)
def create_networking_config(self, *args, **kwargs): def create_networking_config(self, *args, **kwargs):
"""
Create a networking config dictionary to be used as the
``networking_config`` parameter in :py:meth:`create_container`.
Args:
endpoints_config (dict): A dictionary mapping network names to
endpoint configurations generated by
:py:meth:`create_endpoint_config`.
Returns:
(dict) A networking config.
Example:
>>> docker_client.create_network('network1')
>>> networking_config = docker_client.create_networking_config({
'network1': docker_client.create_endpoint_config()
})
>>> container = docker_client.create_container(
img, command, networking_config=networking_config
)
"""
return create_networking_config(*args, **kwargs) return create_networking_config(*args, **kwargs)
def create_endpoint_config(self, *args, **kwargs): def create_endpoint_config(self, *args, **kwargs):
"""
Create an endpoint config dictionary to be used with
: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
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)
addresses.
Returns:
(dict) An endpoint config.
Example:
>>> endpoint_config = client.create_endpoint_config(
aliases=['web', 'app'],
links=['app_db'],
ipv4_address='132.65.0.123'
)
"""
return create_endpoint_config(self._version, *args, **kwargs) return create_endpoint_config(self._version, *args, **kwargs)
@utils.check_resource @utils.check_resource
def diff(self, container): def diff(self, container):
"""
Inspect changes on a container's filesystem.
Args:
container (str): The container to diff
Returns:
(str)
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
return self._result( return self._result(
self._get(self._url("/containers/{0}/changes", container)), True self._get(self._url("/containers/{0}/changes", container)), True
) )
@utils.check_resource @utils.check_resource
def export(self, container): def export(self, container):
"""
Export the contents of a filesystem as a tar archive.
Args:
container (str): The container to export
Returns:
(str): The filesystem tar archive
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
res = self._get( res = self._get(
self._url("/containers/{0}/export", container), stream=True self._url("/containers/{0}/export", container), stream=True
) )
...@@ -180,6 +686,22 @@ class ContainerApiMixin(object): ...@@ -180,6 +686,22 @@ class ContainerApiMixin(object):
@utils.check_resource @utils.check_resource
@utils.minimum_version('1.20') @utils.minimum_version('1.20')
def get_archive(self, container, path): def get_archive(self, container, path):
"""
Retrieve a file or folder from a container in the form of a tar
archive.
Args:
container (str): The container where the file is located
path (str): Path to the file or folder to retrieve
Returns:
(tuple): First element is a raw tar data stream. Second element is
a dict containing ``stat`` information on the specified ``path``.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
params = { params = {
'path': path 'path': path
} }
...@@ -194,12 +716,37 @@ class ContainerApiMixin(object): ...@@ -194,12 +716,37 @@ class ContainerApiMixin(object):
@utils.check_resource @utils.check_resource
def inspect_container(self, container): def inspect_container(self, container):
"""
Identical to the `docker inspect` command, but only for containers.
Args:
container (str): The container to inspect
Returns:
(dict): Similar to the output of `docker inspect`, but as a
single dict
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
return self._result( return self._result(
self._get(self._url("/containers/{0}/json", container)), True self._get(self._url("/containers/{0}/json", container)), True
) )
@utils.check_resource @utils.check_resource
def kill(self, container, signal=None): def kill(self, container, signal=None):
"""
Kill a container or send a signal to a container.
Args:
container (str): The container to kill
signal (str or int): The signal to send. Defaults to ``SIGKILL``
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
url = self._url("/containers/{0}/kill", container) url = self._url("/containers/{0}/kill", container)
params = {} params = {}
if signal is not None: if signal is not None:
...@@ -213,6 +760,32 @@ class ContainerApiMixin(object): ...@@ -213,6 +760,32 @@ class ContainerApiMixin(object):
@utils.check_resource @utils.check_resource
def logs(self, container, stdout=True, stderr=True, stream=False, 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):
"""
Get logs from a container. Similar to the ``docker logs`` command.
The ``stream`` parameter makes the ``logs`` function return a blocking
generator you can iterate over to retrieve log output as it happens.
Args:
container (str): The container to get logs from
stdout (bool): Get ``STDOUT``
stderr (bool): Get ``STDERR``
stream (bool): Stream the response
timestamps (bool): Show timestamps
tail (str or int): Output specified number of lines at the end of
logs. Either an integer of number of lines or the string
``all``. Default ``all``
since (datetime or int): Show logs since a given datetime or
integer epoch (in seconds)
follow (bool): Follow log output
Returns:
(generator or str)
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
if utils.compare_version('1.11', self._version) >= 0: if utils.compare_version('1.11', self._version) >= 0:
if follow is None: if follow is None:
follow = stream follow = stream
...@@ -249,12 +822,48 @@ class ContainerApiMixin(object): ...@@ -249,12 +822,48 @@ class ContainerApiMixin(object):
@utils.check_resource @utils.check_resource
def pause(self, container): def pause(self, container):
"""
Pauses all processes within a container.
Args:
container (str): The container to pause
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
url = self._url('/containers/{0}/pause', container) url = self._url('/containers/{0}/pause', container)
res = self._post(url) res = self._post(url)
self._raise_for_status(res) self._raise_for_status(res)
@utils.check_resource @utils.check_resource
def port(self, container, private_port): def port(self, container, private_port):
"""
Lookup the public-facing port that is NAT-ed to ``private_port``.
Identical to the ``docker port`` command.
Args:
container (str): The container to look up
private_port (int): The private port to inspect
Returns:
(list of dict): The mapping for the host ports
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
Example:
.. code-block:: bash
$ docker run -d -p 80:80 ubuntu:14.04 /bin/sleep 30
7174d6347063a83f412fad6124c99cffd25ffe1a0807eb4b7f9cec76ac8cb43b
.. code-block:: python
>>> cli.port('7174d6347063', 80)
[{'HostIp': '0.0.0.0', 'HostPort': '80'}]
"""
res = self._get(self._url("/containers/{0}/json", container)) res = self._get(self._url("/containers/{0}/json", container))
self._raise_for_status(res) self._raise_for_status(res)
json_ = res.json() json_ = res.json()
...@@ -279,6 +888,26 @@ class ContainerApiMixin(object): ...@@ -279,6 +888,26 @@ class ContainerApiMixin(object):
@utils.check_resource @utils.check_resource
@utils.minimum_version('1.20') @utils.minimum_version('1.20')
def put_archive(self, container, path, data): def put_archive(self, container, path, data):
"""
Insert a file or folder in an existing container using a tar archive as
source.
Args:
container (str): The container where the file(s) will be extracted
path (str): Path inside the container where the file(s) will be
extracted. Must exist.
data (bytes): tar data to be extracted
Returns:
(bool): True if the call succeeds.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
Raises:
:py:class:`~docker.errors.APIError` If an error occurs.
"""
params = {'path': path} params = {'path': path}
url = self._url('/containers/{0}/archive', container) url = self._url('/containers/{0}/archive', container)
res = self._put(url, params=params, data=data) res = self._put(url, params=params, data=data)
...@@ -287,6 +916,21 @@ class ContainerApiMixin(object): ...@@ -287,6 +916,21 @@ class ContainerApiMixin(object):
@utils.check_resource @utils.check_resource
def remove_container(self, container, v=False, link=False, force=False): def remove_container(self, container, v=False, link=False, force=False):
"""
Remove a container. Similar to the ``docker rm`` command.
Args:
container (str): The container to remove
v (bool): Remove the volumes associated with the container
link (bool): Remove the specified link and not the underlying
container
force (bool): Force the removal of a running container (uses
``SIGKILL``)
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
params = {'v': v, 'link': link, 'force': force} params = {'v': v, 'link': link, 'force': force}
res = self._delete( res = self._delete(
self._url("/containers/{0}", container), params=params self._url("/containers/{0}", container), params=params
...@@ -296,6 +940,17 @@ class ContainerApiMixin(object): ...@@ -296,6 +940,17 @@ class ContainerApiMixin(object):
@utils.minimum_version('1.17') @utils.minimum_version('1.17')
@utils.check_resource @utils.check_resource
def rename(self, container, name): def rename(self, container, name):
"""
Rename a container. Similar to the ``docker rename`` command.
Args:
container (str): ID of the container to rename
name (str): New name for the container
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
url = self._url("/containers/{0}/rename", container) url = self._url("/containers/{0}/rename", container)
params = {'name': name} params = {'name': name}
res = self._post(url, params=params) res = self._post(url, params=params)
...@@ -303,6 +958,18 @@ class ContainerApiMixin(object): ...@@ -303,6 +958,18 @@ class ContainerApiMixin(object):
@utils.check_resource @utils.check_resource
def resize(self, container, height, width): def resize(self, container, height, width):
"""
Resize the tty session.
Args:
container (str or dict): The container to resize
height (int): Height of tty session
width (int): Width of tty session
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
params = {'h': height, 'w': width} params = {'h': height, 'w': width}
url = self._url("/containers/{0}/resize", container) url = self._url("/containers/{0}/resize", container)
res = self._post(url, params=params) res = self._post(url, params=params)
...@@ -310,6 +977,20 @@ class ContainerApiMixin(object): ...@@ -310,6 +977,20 @@ class ContainerApiMixin(object):
@utils.check_resource @utils.check_resource
def restart(self, container, timeout=10): def restart(self, container, timeout=10):
"""
Restart a container. Similar to the ``docker restart`` command.
Args:
container (str or dict): The container to restart. If a dict, the
``Id`` key is used.
timeout (int): Number of seconds to try to stop for before killing
the container. Once killed it will then be restarted. Default
is 10 seconds.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
params = {'t': timeout} params = {'t': timeout}
url = self._url("/containers/{0}/restart", container) url = self._url("/containers/{0}/restart", container)
res = self._post(url, params=params) res = self._post(url, params=params)
...@@ -322,7 +1003,28 @@ class ContainerApiMixin(object): ...@@ -322,7 +1003,28 @@ class ContainerApiMixin(object):
restart_policy=None, cap_add=None, cap_drop=None, devices=None, restart_policy=None, cap_add=None, cap_drop=None, devices=None,
extra_hosts=None, read_only=None, pid_mode=None, ipc_mode=None, extra_hosts=None, read_only=None, pid_mode=None, ipc_mode=None,
security_opt=None, ulimits=None): security_opt=None, ulimits=None):
"""
Start a container. Similar to the ``docker start`` command, but
doesn't support attach options.
**Deprecation warning:** For API version > 1.15, it is highly
recommended to provide host config options in the ``host_config``
parameter of :py:meth:`~ContainerApiMixin.create_container`.
Args:
container (str): The container to start
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
Example:
>>> container = cli.create_container(
... image='busybox:latest',
... command='/bin/sleep 30')
>>> cli.start(container=container.get('Id'))
"""
if utils.compare_version('1.10', self._version) < 0: if utils.compare_version('1.10', self._version) < 0:
if dns is not None: if dns is not None:
raise errors.InvalidVersion( raise errors.InvalidVersion(
...@@ -386,6 +1088,22 @@ class ContainerApiMixin(object): ...@@ -386,6 +1088,22 @@ class ContainerApiMixin(object):
@utils.minimum_version('1.17') @utils.minimum_version('1.17')
@utils.check_resource @utils.check_resource
def stats(self, container, decode=None, stream=True): def stats(self, container, decode=None, stream=True):
"""
Stream statistics for a specific container. Similar to the
``docker stats`` command.
Args:
container (str): The container to stream statistics from
decode (bool): If set to true, stream will be decoded into dicts
on the fly. False by default.
stream (bool): If set to false, only the current stats will be
returned instead of a stream. True by default.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
url = self._url("/containers/{0}/stats", container) url = self._url("/containers/{0}/stats", container)
if stream: if stream:
return self._stream_helper(self._get(url, stream=True), return self._stream_helper(self._get(url, stream=True),
...@@ -396,6 +1114,18 @@ class ContainerApiMixin(object): ...@@ -396,6 +1114,18 @@ class ContainerApiMixin(object):
@utils.check_resource @utils.check_resource
def stop(self, container, timeout=10): def stop(self, container, timeout=10):
"""
Stops a container. Similar to the ``docker stop`` command.
Args:
container (str): The container to stop
timeout (int): Timeout in seconds to wait for the container to
stop before sending a ``SIGKILL``. Default: 10
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
params = {'t': timeout} params = {'t': timeout}
url = self._url("/containers/{0}/stop", container) url = self._url("/containers/{0}/stop", container)
...@@ -405,6 +1135,20 @@ class ContainerApiMixin(object): ...@@ -405,6 +1135,20 @@ class ContainerApiMixin(object):
@utils.check_resource @utils.check_resource
def top(self, container, ps_args=None): def top(self, container, ps_args=None):
"""
Display the running processes of a container.
Args:
container (str): The container to inspect
ps_args (str): An optional arguments passed to ps (e.g. ``aux``)
Returns:
(str): The output of the top
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
u = self._url("/containers/{0}/top", container) u = self._url("/containers/{0}/top", container)
params = {} params = {}
if ps_args is not None: if ps_args is not None:
...@@ -413,6 +1157,12 @@ class ContainerApiMixin(object): ...@@ -413,6 +1157,12 @@ class ContainerApiMixin(object):
@utils.check_resource @utils.check_resource
def unpause(self, container): def unpause(self, container):
"""
Unpause all processes within a container.
Args:
container (str): The container to unpause
"""
url = self._url('/containers/{0}/unpause', container) url = self._url('/containers/{0}/unpause', container)
res = self._post(url) res = self._post(url)
self._raise_for_status(res) self._raise_for_status(res)
...@@ -425,6 +1175,31 @@ class ContainerApiMixin(object): ...@@ -425,6 +1175,31 @@ class ContainerApiMixin(object):
mem_reservation=None, memswap_limit=None, kernel_memory=None, mem_reservation=None, memswap_limit=None, kernel_memory=None,
restart_policy=None restart_policy=None
): ):
"""
Update resource configs of one or more containers.
Args:
container (str): The container to inspect
blkio_weight (int): Block IO (relative weight), between 10 and 1000
cpu_period (int): Limit CPU CFS (Completely Fair Scheduler) period
cpu_quota (int): Limit CPU CFS (Completely Fair Scheduler) quota
cpu_shares (int): CPU shares (relative weight)
cpuset_cpus (str): CPUs in which to allow execution
cpuset_mems (str): MEMs in which to allow execution
mem_limit (int or str): Memory limit
mem_reservation (int or str): Memory soft limit
memswap_limit (int or str): Total memory (memory + swap), -1 to
disable swap
kernel_memory (int or str): Kernel memory limit
restart_policy (dict): Restart policy dictionary
Returns:
(dict): Dictionary containing a ``Warnings`` key.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
url = self._url('/containers/{0}/update', container) url = self._url('/containers/{0}/update', container)
data = {} data = {}
if blkio_weight: if blkio_weight:
...@@ -460,6 +1235,25 @@ class ContainerApiMixin(object): ...@@ -460,6 +1235,25 @@ class ContainerApiMixin(object):
@utils.check_resource @utils.check_resource
def wait(self, container, timeout=None): def wait(self, container, timeout=None):
"""
Block until a container stops, then return its exit code. Similar to
the ``docker wait`` command.
Args:
container (str or dict): The container to wait on. If a dict, the
``Id`` key is used.
timeout (int): Request timeout
Returns:
(int): The exit code of the container. Returns ``-1`` if the API
responds without a ``StatusCode`` attribute.
Raises:
:py:class:`requests.exceptions.ReadTimeout`
If the timeout is exceeded.
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
url = self._url("/containers/{0}/wait", container) url = self._url("/containers/{0}/wait", container)
res = self._post(url, timeout=timeout) res = self._post(url, timeout=timeout)
self._raise_for_status(res) self._raise_for_status(res)
......
...@@ -8,6 +8,36 @@ from ..constants import INSECURE_REGISTRY_DEPRECATION_WARNING ...@@ -8,6 +8,36 @@ from ..constants import INSECURE_REGISTRY_DEPRECATION_WARNING
class DaemonApiMixin(object): class DaemonApiMixin(object):
def events(self, since=None, until=None, filters=None, decode=None): def events(self, since=None, until=None, filters=None, decode=None):
"""
Get real-time events from the server. Similar to the ``docker events``
command.
Args:
since (UTC datetime or int): Get events from this point
until (UTC datetime or int): Get events until this point
filters (dict): Filter the events by event time, container or image
decode (bool): If set to true, stream will be decoded into dicts on
the fly. False by default.
Returns:
(generator): A blocking generator you can iterate over to retrieve
events as they happen.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
Example:
>>> for event in client.events()
... print event
{u'from': u'image/with:tag',
u'id': u'container-id',
u'status': u'start',
u'time': 1423339459}
...
"""
if isinstance(since, datetime): if isinstance(since, datetime):
since = utils.datetime_to_timestamp(since) since = utils.datetime_to_timestamp(since)
...@@ -29,10 +59,42 @@ class DaemonApiMixin(object): ...@@ -29,10 +59,42 @@ class DaemonApiMixin(object):
) )
def info(self): def info(self):
"""
Display system-wide information. Identical to the ``docker info``
command.
Returns:
(dict): The info as a dict
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
return self._result(self._get(self._url("/info")), True) return self._result(self._get(self._url("/info")), True)
def login(self, username, password=None, email=None, registry=None, def login(self, username, password=None, email=None, registry=None,
reauth=False, insecure_registry=False, dockercfg_path=None): reauth=False, insecure_registry=False, dockercfg_path=None):
"""
Authenticate with a registry. Similar to the ``docker login`` command.
Args:
username (str): The registry username
password (str): The plaintext password
email (str): The email for the registry account
registry (str): URL to the registry. E.g.
``https://index.docker.io/v1/``
reauth (bool): Whether refresh existing authentication on the
Docker server.
dockercfg_path (str): Use a custom path for the ``.dockercfg`` file
(default ``$HOME/.dockercfg``)
Returns:
(dict): The response from the login request
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
if insecure_registry: if insecure_registry:
warnings.warn( warnings.warn(
INSECURE_REGISTRY_DEPRECATION_WARNING.format('login()'), INSECURE_REGISTRY_DEPRECATION_WARNING.format('login()'),
...@@ -68,8 +130,30 @@ class DaemonApiMixin(object): ...@@ -68,8 +130,30 @@ class DaemonApiMixin(object):
return self._result(response, json=True) return self._result(response, json=True)
def ping(self): def ping(self):
"""
Checks the server is responsive. An exception will be raised if it
isn't responding.
Returns:
(bool) The response from the server.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
return self._result(self._get(self._url('/_ping'))) == 'OK' return self._result(self._get(self._url('/_ping'))) == 'OK'
def version(self, api_version=True): def version(self, api_version=True):
"""
Returns version information from the server. Similar to the ``docker
version`` command.
Returns:
(dict): The server version information
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
url = self._url("/version", versioned_api=api_version) url = self._url("/version", versioned_api=api_version)
return self._result(self._get(url), json=True) return self._result(self._get(url), json=True)
...@@ -9,6 +9,28 @@ class ExecApiMixin(object): ...@@ -9,6 +9,28 @@ class ExecApiMixin(object):
@utils.check_resource @utils.check_resource
def exec_create(self, container, cmd, stdout=True, stderr=True, def exec_create(self, container, cmd, stdout=True, stderr=True,
stdin=False, tty=False, privileged=False, user=''): stdin=False, tty=False, privileged=False, user=''):
"""
Sets up an exec instance in a running container.
Args:
container (str): Target container where exec instance will be
created
cmd (str or list): Command to be executed
stdout (bool): Attach to stdout. Default: ``True``
stderr (bool): Attach to stderr. Default: ``True``
stdin (bool): Attach to stdin. Default: ``False``
tty (bool): Allocate a pseudo-TTY. Default: False
privileged (bool): Run as privileged.
user (str): User to execute command as. Default: root
Returns:
(dict): A dictionary with an exec ``Id`` key.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
if privileged and utils.compare_version('1.19', self._version) < 0: if privileged and utils.compare_version('1.19', self._version) < 0:
raise errors.InvalidVersion( raise errors.InvalidVersion(
'Privileged exec is not supported in API < 1.19' 'Privileged exec is not supported in API < 1.19'
...@@ -37,6 +59,19 @@ class ExecApiMixin(object): ...@@ -37,6 +59,19 @@ class ExecApiMixin(object):
@utils.minimum_version('1.16') @utils.minimum_version('1.16')
def exec_inspect(self, exec_id): def exec_inspect(self, exec_id):
"""
Return low-level information about an exec command.
Args:
exec_id (str): ID of the exec instance
Returns:
(dict): Dictionary of values returned by the endpoint.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
if isinstance(exec_id, dict): if isinstance(exec_id, dict):
exec_id = exec_id.get('Id') exec_id = exec_id.get('Id')
res = self._get(self._url("/exec/{0}/json", exec_id)) res = self._get(self._url("/exec/{0}/json", exec_id))
...@@ -44,6 +79,15 @@ class ExecApiMixin(object): ...@@ -44,6 +79,15 @@ class ExecApiMixin(object):
@utils.minimum_version('1.15') @utils.minimum_version('1.15')
def exec_resize(self, exec_id, height=None, width=None): def exec_resize(self, exec_id, height=None, width=None):
"""
Resize the tty session used by the specified exec command.
Args:
exec_id (str): ID of the exec instance
height (int): Height of tty session
width (int): Width of tty session
"""
if isinstance(exec_id, dict): if isinstance(exec_id, dict):
exec_id = exec_id.get('Id') exec_id = exec_id.get('Id')
...@@ -55,6 +99,24 @@ class ExecApiMixin(object): ...@@ -55,6 +99,24 @@ class ExecApiMixin(object):
@utils.minimum_version('1.15') @utils.minimum_version('1.15')
def exec_start(self, exec_id, detach=False, tty=False, stream=False, def exec_start(self, exec_id, detach=False, tty=False, stream=False,
socket=False): socket=False):
"""
Start a previously set up exec instance.
Args:
exec_id (str): ID of the exec instance
detach (bool): If true, detach from the exec command.
Default: False
tty (bool): Allocate a pseudo-TTY. Default: False
stream (bool): Stream response data. Default: False
Returns:
(generator or str): If ``stream=True``, a generator yielding
response chunks. A string containing response data otherwise.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
# we want opened socket if socket == True # we want opened socket if socket == True
if isinstance(exec_id, dict): if isinstance(exec_id, dict):
exec_id = exec_id.get('Id') exec_id = exec_id.get('Id')
......
...@@ -14,17 +14,71 @@ class ImageApiMixin(object): ...@@ -14,17 +14,71 @@ class ImageApiMixin(object):
@utils.check_resource @utils.check_resource
def get_image(self, image): def get_image(self, image):
"""
Get a tarball of an image. Similar to the ``docker save`` command.
Args:
image (str): Image name to get
Returns:
(urllib3.response.HTTPResponse object): The response from the
daemon.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
Example:
>>> image = cli.get_image("fedora:latest")
>>> f = open('/tmp/fedora-latest.tar', 'w')
>>> f.write(image.data)
>>> f.close()
"""
res = self._get(self._url("/images/{0}/get", image), stream=True) res = self._get(self._url("/images/{0}/get", image), stream=True)
self._raise_for_status(res) self._raise_for_status(res)
return res.raw return res.raw
@utils.check_resource @utils.check_resource
def history(self, image): def history(self, image):
"""
Show the history of an image.
Args:
image (str): The image to show history for
Returns:
(str): The history of the image
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
res = self._get(self._url("/images/{0}/history", image)) res = self._get(self._url("/images/{0}/history", image))
return self._result(res, True) return self._result(res, True)
def images(self, name=None, quiet=False, all=False, viz=False, def images(self, name=None, quiet=False, all=False, viz=False,
filters=None): filters=None):
"""
List images. Similar to the ``docker images`` command.
Args:
name (str): Only show images belonging to the repository ``name``
quiet (bool): Only return numeric IDs as a list.
all (bool): Show intermediate image layers. By default, these are
filtered out.
filters (dict): Filters to be processed on the image list.
Available filters:
- ``dangling`` (bool)
- ``label`` (str): format either ``key`` or ``key=value``
Returns:
(dict or list): A list if ``quiet=True``, otherwise a dict.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
if viz: if viz:
if utils.compare_version('1.7', self._version) >= 0: if utils.compare_version('1.7', self._version) >= 0:
raise Exception('Viz output is not supported in API >= 1.7!') raise Exception('Viz output is not supported in API >= 1.7!')
...@@ -44,6 +98,25 @@ class ImageApiMixin(object): ...@@ -44,6 +98,25 @@ class ImageApiMixin(object):
def import_image(self, src=None, repository=None, tag=None, image=None, def import_image(self, src=None, repository=None, tag=None, image=None,
changes=None, stream_src=False): changes=None, stream_src=False):
"""
Import an image. Similar to the ``docker import`` command.
If ``src`` is a string or unicode string, it will first be treated as a
path to a tarball on the local system. If there is an error reading
from that file, ``src`` will be treated as a URL instead to fetch the
image from. You can also pass an open file handle as ``src``, in which
case the data will be read from that file.
If ``src`` is unset but ``image`` is set, the ``image`` parameter will
be taken as the name of an existing image to import from.
Args:
src (str or file): Path to tarfile, URL, or file-like object
repository (str): The repository to create
tag (str): The tag to apply
image (str): Use another image like the ``FROM`` Dockerfile
parameter
"""
if not (src or image): if not (src or image):
raise errors.DockerException( raise errors.DockerException(
'Must specify src or image to import from' 'Must specify src or image to import from'
...@@ -77,6 +150,16 @@ class ImageApiMixin(object): ...@@ -77,6 +150,16 @@ class ImageApiMixin(object):
def import_image_from_data(self, data, repository=None, tag=None, def import_image_from_data(self, data, repository=None, tag=None,
changes=None): changes=None):
"""
Like :py:meth:`~docker.api.image.ImageApiMixin.import_image`, but
allows importing in-memory bytes data.
Args:
data (bytes collection): Bytes collection containing valid tar data
repository (str): The repository to create
tag (str): The tag to apply
"""
u = self._url('/images/create') u = self._url('/images/create')
params = _import_image_params( params = _import_image_params(
repository, tag, src='-', changes=changes repository, tag, src='-', changes=changes
...@@ -90,6 +173,19 @@ class ImageApiMixin(object): ...@@ -90,6 +173,19 @@ class ImageApiMixin(object):
def import_image_from_file(self, filename, repository=None, tag=None, def import_image_from_file(self, filename, repository=None, tag=None,
changes=None): changes=None):
"""
Like :py:meth:`~docker.api.image.ImageApiMixin.import_image`, but only
supports importing from a tar file on disk.
Args:
filename (str): Full path to a tar file.
repository (str): The repository to create
tag (str): The tag to apply
Raises:
IOError: File does not exist.
"""
return self.import_image( return self.import_image(
src=filename, repository=repository, tag=tag, changes=changes src=filename, repository=repository, tag=tag, changes=changes
) )
...@@ -103,12 +199,31 @@ class ImageApiMixin(object): ...@@ -103,12 +199,31 @@ class ImageApiMixin(object):
def import_image_from_url(self, url, repository=None, tag=None, def import_image_from_url(self, url, repository=None, tag=None,
changes=None): changes=None):
"""
Like :py:meth:`~docker.api.image.ImageApiMixin.import_image`, but only
supports importing from a URL.
Args:
url (str): A URL pointing to a tar file.
repository (str): The repository to create
tag (str): The tag to apply
"""
return self.import_image( return self.import_image(
src=url, repository=repository, tag=tag, changes=changes src=url, repository=repository, tag=tag, changes=changes
) )
def import_image_from_image(self, image, repository=None, tag=None, def import_image_from_image(self, image, repository=None, tag=None,
changes=None): changes=None):
"""
Like :py:meth:`~docker.api.image.ImageApiMixin.import_image`, but only
supports importing from another image, like the ``FROM`` Dockerfile
parameter.
Args:
image (str): Image name to import from
repository (str): The repository to create
tag (str): The tag to apply
"""
return self.import_image( return self.import_image(
image=image, repository=repository, tag=tag, changes=changes image=image, repository=repository, tag=tag, changes=changes
) )
...@@ -128,16 +243,75 @@ class ImageApiMixin(object): ...@@ -128,16 +243,75 @@ class ImageApiMixin(object):
@utils.check_resource @utils.check_resource
def inspect_image(self, image): def inspect_image(self, image):
"""
Get detailed information about an image. Similar to the ``docker
inspect`` command, but only for containers.
Args:
container (str): The container to inspect
Returns:
(dict): Similar to the output of ``docker inspect``, but as a
single dict
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
return self._result( return self._result(
self._get(self._url("/images/{0}/json", image)), True self._get(self._url("/images/{0}/json", image)), True
) )
def load_image(self, data): def load_image(self, data):
"""
Load an image that was previously saved using
:py:meth:`~docker.api.image.ImageApiMixin.get_image` (or ``docker
save``). Similar to ``docker load``.
Args:
data (binary): Image data to be loaded.
"""
res = self._post(self._url("/images/load"), data=data) res = self._post(self._url("/images/load"), data=data)
self._raise_for_status(res) self._raise_for_status(res)
def pull(self, repository, tag=None, stream=False, def pull(self, repository, tag=None, stream=False,
insecure_registry=False, auth_config=None, decode=False): insecure_registry=False, auth_config=None, decode=False):
"""
Pulls an image. Similar to the ``docker pull`` command.
Args:
repository (str): The repository to pull
tag (str): The tag to pull
stream (bool): Stream the output as a generator
insecure_registry (bool): Use an insecure registry
auth_config (dict): Override the credentials that
:py:meth:`~docker.api.daemon.DaemonApiMixin.login` has set for
this request. ``auth_config`` should contain the ``username``
and ``password`` keys to be valid.
Returns:
(generator or str): The output
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
Example:
>>> for line in cli.pull('busybox', stream=True):
... print(json.dumps(json.loads(line), indent=4))
{
"status": "Pulling image (latest) from busybox",
"progressDetail": {},
"id": "e72ac664f4f0"
}
{
"status": "Pulling image (latest) from busybox, endpoint: ...",
"progressDetail": {},
"id": "e72ac664f4f0"
}
"""
if insecure_registry: if insecure_registry:
warnings.warn( warnings.warn(
INSECURE_REGISTRY_DEPRECATION_WARNING.format('pull()'), INSECURE_REGISTRY_DEPRECATION_WARNING.format('pull()'),
...@@ -177,6 +351,38 @@ class ImageApiMixin(object): ...@@ -177,6 +351,38 @@ class ImageApiMixin(object):
def push(self, repository, tag=None, stream=False, def push(self, repository, tag=None, stream=False,
insecure_registry=False, auth_config=None, decode=False): insecure_registry=False, auth_config=None, decode=False):
"""
Push an image or a repository to the registry. Similar to the ``docker
push`` command.
Args:
repository (str): The repository to push to
tag (str): An optional tag to push
stream (bool): Stream the output as a blocking generator
insecure_registry (bool): Use ``http://`` to connect to the
registry
auth_config (dict): Override the credentials that
:py:meth:`~docker.api.daemon.DaemonApiMixin.login` has set for
this request. ``auth_config`` should contain the ``username``
and ``password`` keys to be valid.
Returns:
(generator or str): The output from the server.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
Example:
>>> for line in cli.push('yourname/app', stream=True):
... print line
{"status":"Pushing repository yourname/app (1 tags)"}
{"status":"Pushing","progressDetail":{},"id":"511136ea3c5a"}
{"status":"Image already pushed, skipping","progressDetail":{},
"id":"511136ea3c5a"}
...
"""
if insecure_registry: if insecure_registry:
warnings.warn( warnings.warn(
INSECURE_REGISTRY_DEPRECATION_WARNING.format('push()'), INSECURE_REGISTRY_DEPRECATION_WARNING.format('push()'),
...@@ -214,11 +420,33 @@ class ImageApiMixin(object): ...@@ -214,11 +420,33 @@ class ImageApiMixin(object):
@utils.check_resource @utils.check_resource
def remove_image(self, image, force=False, noprune=False): def remove_image(self, image, force=False, noprune=False):
"""
Remove an image. Similar to the ``docker rmi`` command.
Args:
image (str): The image to remove
force (bool): Force removal of the image
noprune (bool): Do not delete untagged parents
"""
params = {'force': force, 'noprune': noprune} params = {'force': force, 'noprune': noprune}
res = self._delete(self._url("/images/{0}", image), params=params) res = self._delete(self._url("/images/{0}", image), params=params)
self._raise_for_status(res) self._raise_for_status(res)
def search(self, term): def search(self, term):
"""
Search for images on Docker Hub. Similar to the ``docker search``
command.
Args:
term (str): A term to search for.
Returns:
(list of dicts): The response of the search.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
return self._result( return self._result(
self._get(self._url("/images/search"), params={'term': term}), self._get(self._url("/images/search"), params={'term': term}),
True True
...@@ -226,6 +454,22 @@ class ImageApiMixin(object): ...@@ -226,6 +454,22 @@ class ImageApiMixin(object):
@utils.check_resource @utils.check_resource
def tag(self, image, repository, tag=None, force=False): def tag(self, image, repository, tag=None, force=False):
"""
Tag an image into a repository. Similar to the ``docker tag`` command.
Args:
image (str): The image to tag
repository (str): The repository to set for the tag
tag (str): The tag name
force (bool): Force
Returns:
(bool): ``True`` if successful
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
params = { params = {
'tag': tag, 'tag': tag,
'repo': repository, 'repo': repository,
......
...@@ -8,6 +8,21 @@ from ..utils import version_lt ...@@ -8,6 +8,21 @@ from ..utils import version_lt
class NetworkApiMixin(object): class NetworkApiMixin(object):
@minimum_version('1.21') @minimum_version('1.21')
def networks(self, names=None, ids=None): def networks(self, names=None, ids=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
Returns:
(dict): List of network objects.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
filters = {} filters = {}
if names: if names:
filters['name'] = names filters['name'] = names
...@@ -24,6 +39,51 @@ class NetworkApiMixin(object): ...@@ -24,6 +39,51 @@ class NetworkApiMixin(object):
def create_network(self, name, driver=None, options=None, ipam=None, def create_network(self, name, driver=None, options=None, ipam=None,
check_duplicate=None, internal=False, labels=None, check_duplicate=None, internal=False, labels=None,
enable_ipv6=False): enable_ipv6=False):
"""
Create a network. Similar to the ``docker network create``.
Args:
name (str): Name of the network
driver (str): Name of the driver used to create the network
options (dict): Driver options as a key-value dictionary
ipam (dict): Optional custom IP scheme for the network.
Created with :py:meth:`~docker.utils.create_ipam_config`.
check_duplicate (bool): Request daemon to check for networks with
same name. Default: ``True``.
internal (bool): Restrict external access to the network. Default
``False``.
labels (dict): Map of labels to set on the network. Default
``None``.
enable_ipv6 (bool): Enable IPv6 on the network. Default ``False``.
Returns:
(dict): The created network reference object
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
Example:
A network using the bridge driver:
>>> client.create_network("network1", driver="bridge")
You can also create more advanced networks with custom IPAM
configurations. For example, setting the subnet to
``192.168.52.0/24`` and gateway address to ``192.168.52.254``.
.. code-block:: python
>>> ipam_pool = docker.utils.create_ipam_pool(
subnet='192.168.52.0/24',
gateway='192.168.52.254'
)
>>> ipam_config = docker.utils.create_ipam_config(
pool_configs=[ipam_pool]
)
>>> docker_client.create_network("network1", driver="bridge",
ipam=ipam_config)
"""
if options is not None and not isinstance(options, dict): if options is not None and not isinstance(options, dict):
raise TypeError('options must be a dictionary') raise TypeError('options must be a dictionary')
...@@ -63,12 +123,24 @@ class NetworkApiMixin(object): ...@@ -63,12 +123,24 @@ class NetworkApiMixin(object):
@minimum_version('1.21') @minimum_version('1.21')
def remove_network(self, net_id): def remove_network(self, net_id):
"""
Remove a network. Similar to the ``docker network rm`` command.
Args:
net_id (str): The network's id
"""
url = self._url("/networks/{0}", net_id) url = self._url("/networks/{0}", net_id)
res = self._delete(url) res = self._delete(url)
self._raise_for_status(res) self._raise_for_status(res)
@minimum_version('1.21') @minimum_version('1.21')
def inspect_network(self, net_id): def inspect_network(self, net_id):
"""
Get detailed information about a network.
Args:
net_id (str): ID of network
"""
url = self._url("/networks/{0}", net_id) url = self._url("/networks/{0}", net_id)
res = self._get(url) res = self._get(url)
return self._result(res, json=True) return self._result(res, json=True)
...@@ -79,6 +151,24 @@ class NetworkApiMixin(object): ...@@ -79,6 +151,24 @@ class NetworkApiMixin(object):
ipv4_address=None, ipv6_address=None, ipv4_address=None, ipv6_address=None,
aliases=None, links=None, aliases=None, links=None,
link_local_ips=None): link_local_ips=None):
"""
Connect a container to a network.
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``.
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.
"""
data = { data = {
"Container": container, "Container": container,
"EndpointConfig": self.create_endpoint_config( "EndpointConfig": self.create_endpoint_config(
...@@ -95,6 +185,16 @@ class NetworkApiMixin(object): ...@@ -95,6 +185,16 @@ class NetworkApiMixin(object):
@minimum_version('1.21') @minimum_version('1.21')
def disconnect_container_from_network(self, container, net_id, def disconnect_container_from_network(self, container, net_id,
force=False): force=False):
"""
Disconnect a container from a network.
Args:
container (str): container ID or name to be disconnected from the
network
net_id (str): network ID
force (bool): Force the container to disconnect from a network.
Default: ``False``
"""
data = {"Container": container} data = {"Container": container}
if force: if force:
if version_lt(self._version, '1.22'): if version_lt(self._version, '1.22'):
......
...@@ -9,6 +9,32 @@ class ServiceApiMixin(object): ...@@ -9,6 +9,32 @@ class ServiceApiMixin(object):
update_config=None, networks=None, endpoint_config=None, update_config=None, networks=None, endpoint_config=None,
endpoint_spec=None endpoint_spec=None
): ):
"""
Create a service.
Args:
task_template (dict): 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
access and load balance a service. Default: ``None``.
Returns:
A dictionary containing an ``ID`` key for the newly created
service.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
if endpoint_config is not None: if endpoint_config is not None:
warnings.warn( warnings.warn(
'endpoint_config has been renamed to endpoint_spec.', 'endpoint_config has been renamed to endpoint_spec.',
...@@ -43,18 +69,58 @@ class ServiceApiMixin(object): ...@@ -43,18 +69,58 @@ class ServiceApiMixin(object):
@utils.minimum_version('1.24') @utils.minimum_version('1.24')
@utils.check_resource @utils.check_resource
def inspect_service(self, service): def inspect_service(self, service):
"""
Return information about a service.
Args:
service (str): Service name or ID
Returns:
``True`` if successful.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
url = self._url('/services/{0}', service) url = self._url('/services/{0}', service)
return self._result(self._get(url), True) return self._result(self._get(url), True)
@utils.minimum_version('1.24') @utils.minimum_version('1.24')
@utils.check_resource @utils.check_resource
def inspect_task(self, task): def inspect_task(self, task):
"""
Retrieve information about a task.
Args:
task (str): Task ID
Returns:
(dict): Information about the task.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
url = self._url('/tasks/{0}', task) url = self._url('/tasks/{0}', task)
return self._result(self._get(url), True) return self._result(self._get(url), True)
@utils.minimum_version('1.24') @utils.minimum_version('1.24')
@utils.check_resource @utils.check_resource
def remove_service(self, service): def remove_service(self, service):
"""
Stop and remove a service.
Args:
service (str): Service name or ID
Returns:
``True`` if successful.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
url = self._url('/services/{0}', service) url = self._url('/services/{0}', service)
resp = self._delete(url) resp = self._delete(url)
self._raise_for_status(resp) self._raise_for_status(resp)
...@@ -62,6 +128,20 @@ class ServiceApiMixin(object): ...@@ -62,6 +128,20 @@ class ServiceApiMixin(object):
@utils.minimum_version('1.24') @utils.minimum_version('1.24')
def services(self, filters=None): def services(self, filters=None):
"""
List services.
Args:
filters (dict): Filters to process on the nodes list. Valid
filters: ``id`` and ``name``. Default: ``None``.
Returns:
A list of dictionaries containing data about each service.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
params = { params = {
'filters': utils.convert_filters(filters) if filters else None 'filters': utils.convert_filters(filters) if filters else None
} }
...@@ -70,6 +150,22 @@ class ServiceApiMixin(object): ...@@ -70,6 +150,22 @@ class ServiceApiMixin(object):
@utils.minimum_version('1.24') @utils.minimum_version('1.24')
def tasks(self, filters=None): def tasks(self, filters=None):
"""
Retrieve a list of tasks.
Args:
filters (dict): A map of filters to process on the tasks list.
Valid filters: ``id``, ``name``, ``service``, ``node``,
``label`` and ``desired-state``.
Returns:
(list): List of task dictionaries.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
params = { params = {
'filters': utils.convert_filters(filters) if filters else None 'filters': utils.convert_filters(filters) if filters else None
} }
...@@ -82,7 +178,37 @@ class ServiceApiMixin(object): ...@@ -82,7 +178,37 @@ class ServiceApiMixin(object):
labels=None, mode=None, update_config=None, labels=None, mode=None, update_config=None,
networks=None, endpoint_config=None, networks=None, endpoint_config=None,
endpoint_spec=None): endpoint_spec=None):
"""
Update a service.
Args:
service (string): A service identifier (either its name or service
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.
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
access and load balance a service. Default: ``None``.
Returns:
``True`` if successful.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
if endpoint_config is not None: if endpoint_config is not None:
warnings.warn( warnings.warn(
'endpoint_config has been renamed to endpoint_spec.', 'endpoint_config has been renamed to endpoint_spec.',
......
...@@ -7,11 +7,87 @@ log = logging.getLogger(__name__) ...@@ -7,11 +7,87 @@ log = logging.getLogger(__name__)
class SwarmApiMixin(object): class SwarmApiMixin(object):
def create_swarm_spec(self, *args, **kwargs): def create_swarm_spec(self, *args, **kwargs):
"""
Create a ``docker.types.SwarmSpec`` instance that can be used as the
``swarm_spec`` argument in
:py:meth:`~docker.api.swarm.SwarmApiMixin.init_swarm`.
Args:
task_history_retention_limit (int): Maximum number of tasks
history stored.
snapshot_interval (int): Number of logs entries between snapshot.
keep_old_snapshots (int): Number of snapshots to keep beyond the
current snapshot.
log_entries_for_slow_followers (int): Number of log entries to
keep around to sync up slow followers after a snapshot is
created.
heartbeat_tick (int): Amount of ticks (in seconds) between each
heartbeat.
election_tick (int): Amount of ticks (in seconds) needed without a
leader to trigger a new election.
dispatcher_heartbeat_period (int): The delay for an agent to send
a heartbeat to the dispatcher.
node_cert_expiry (int): Automatic expiry for nodes certificates.
external_ca (dict): Configuration for forwarding signing requests
to an external certificate authority. Use
``docker.types.SwarmExternalCA``.
name (string): Swarm's name
Returns:
``docker.types.SwarmSpec`` instance.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
Example:
>>> spec = client.create_swarm_spec(
snapshot_interval=5000, log_entries_for_slow_followers=1200
)
>>> client.init_swarm(
advertise_addr='eth0', listen_addr='0.0.0.0:5000',
force_new_cluster=False, swarm_spec=spec
)
"""
return utils.SwarmSpec(*args, **kwargs) return utils.SwarmSpec(*args, **kwargs)
@utils.minimum_version('1.24') @utils.minimum_version('1.24')
def init_swarm(self, advertise_addr=None, listen_addr='0.0.0.0:2377', def init_swarm(self, advertise_addr=None, listen_addr='0.0.0.0:2377',
force_new_cluster=False, swarm_spec=None): force_new_cluster=False, swarm_spec=None):
"""
Initialize a new Swarm using the current connected engine as the first
node.
Args:
advertise_addr (string): Externally reachable address advertised
to other nodes. This can either be an address/port combination
in the form ``192.168.1.1:4567``, or an interface followed by a
port number, like ``eth0:4567``. If the port number is omitted,
the port number from the listen address is used. If
``advertise_addr`` is not specified, it will be automatically
detected when possible. Default: None
listen_addr (string): Listen address used for inter-manager
communication, as well as determining the networking interface
used for the VXLAN Tunnel Endpoint (VTEP). This can either be
an address/port combination in the form ``192.168.1.1:4567``,
or an interface followed by a port number, like ``eth0:4567``.
If the port number is omitted, the default swarm listening port
is used. Default: '0.0.0.0:2377'
force_new_cluster (bool): Force creating a new Swarm, even if
already part of one. Default: False
swarm_spec (dict): Configuration settings of the new Swarm. Use
``Client.create_swarm_spec`` to generate a valid
configuration. Default: None
Returns:
``True`` if successful.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
url = self._url('/swarm/init') url = self._url('/swarm/init')
if swarm_spec is not None and not isinstance(swarm_spec, dict): if swarm_spec is not None and not isinstance(swarm_spec, dict):
raise TypeError('swarm_spec must be a dictionary') raise TypeError('swarm_spec must be a dictionary')
...@@ -27,18 +103,67 @@ class SwarmApiMixin(object): ...@@ -27,18 +103,67 @@ class SwarmApiMixin(object):
@utils.minimum_version('1.24') @utils.minimum_version('1.24')
def inspect_swarm(self): def inspect_swarm(self):
"""
Retrieve low-level information about the current swarm.
Returns:
A dictionary containing data about the swarm.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
url = self._url('/swarm') url = self._url('/swarm')
return self._result(self._get(url), True) return self._result(self._get(url), True)
@utils.check_resource @utils.check_resource
@utils.minimum_version('1.24') @utils.minimum_version('1.24')
def inspect_node(self, node_id): def inspect_node(self, node_id):
"""
Retrieve low-level information about a swarm node
Args:
node_id (string): ID of the node to be inspected.
Returns:
A dictionary containing data about this node.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
url = self._url('/nodes/{0}', node_id) url = self._url('/nodes/{0}', node_id)
return self._result(self._get(url), True) return self._result(self._get(url), True)
@utils.minimum_version('1.24') @utils.minimum_version('1.24')
def join_swarm(self, remote_addrs, join_token, listen_addr=None, def join_swarm(self, remote_addrs, join_token, listen_addr=None,
advertise_addr=None): advertise_addr=None):
"""
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.
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
determining the networking interface used for the VXLAN Tunnel
Endpoint (VTEP). Default: ``None``
advertise_addr (string): Externally reachable address advertised
to other nodes. This can either be an address/port combination
in the form ``192.168.1.1:4567``, or an interface followed by a
port number, like ``eth0:4567``. If the port number is omitted,
the port number from the listen address is used. If
AdvertiseAddr is not specified, it will be automatically
detected when possible. Default: ``None``
Returns:
``True`` if the request went through.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
data = { data = {
"RemoteAddrs": remote_addrs, "RemoteAddrs": remote_addrs,
"ListenAddr": listen_addr, "ListenAddr": listen_addr,
...@@ -52,6 +177,20 @@ class SwarmApiMixin(object): ...@@ -52,6 +177,20 @@ class SwarmApiMixin(object):
@utils.minimum_version('1.24') @utils.minimum_version('1.24')
def leave_swarm(self, force=False): def leave_swarm(self, force=False):
"""
Leave a swarm.
Args:
force (bool): Leave the swarm even if this node is a manager.
Default: ``False``
Returns:
``True`` if the request went through.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
url = self._url('/swarm/leave') url = self._url('/swarm/leave')
response = self._post(url, params={'force': force}) response = self._post(url, params={'force': force})
# Ignore "this node is not part of a swarm" error # Ignore "this node is not part of a swarm" error
...@@ -62,6 +201,21 @@ class SwarmApiMixin(object): ...@@ -62,6 +201,21 @@ class SwarmApiMixin(object):
@utils.minimum_version('1.24') @utils.minimum_version('1.24')
def nodes(self, filters=None): def nodes(self, filters=None):
"""
List swarm nodes.
Args:
filters (dict): Filters to process on the nodes list. Valid
filters: ``id``, ``name``, ``membership`` and ``role``.
Default: ``None``
Returns:
A list of dictionaries containing data about each swarm node.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
url = self._url('/nodes') url = self._url('/nodes')
params = {} params = {}
if filters: if filters:
...@@ -71,6 +225,34 @@ class SwarmApiMixin(object): ...@@ -71,6 +225,34 @@ class SwarmApiMixin(object):
@utils.minimum_version('1.24') @utils.minimum_version('1.24')
def update_node(self, node_id, version, node_spec=None): def update_node(self, node_id, version, node_spec=None):
"""
Update the Node's configuration
Args:
version (int): The version number of the node object being
updated. This is required to avoid conflicting writes.
node_spec (dict): Configuration settings to update. Any values
not provided will be removed. Default: ``None``
Returns:
`True` if the request went through.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
Example:
>>> node_spec = {'Availability': 'active',
'Name': 'node-name',
'Role': 'manager',
'Labels': {'foo': 'bar'}
}
>>> client.update_node(node_id='24ifsmvkjbyhk', version=8,
node_spec=node_spec)
"""
url = self._url('/nodes/{0}/update?version={1}', node_id, str(version)) url = self._url('/nodes/{0}/update?version={1}', node_id, str(version))
res = self._post_json(url, data=node_spec) res = self._post_json(url, data=node_spec)
self._raise_for_status(res) self._raise_for_status(res)
...@@ -79,6 +261,28 @@ class SwarmApiMixin(object): ...@@ -79,6 +261,28 @@ class SwarmApiMixin(object):
@utils.minimum_version('1.24') @utils.minimum_version('1.24')
def update_swarm(self, version, swarm_spec=None, rotate_worker_token=False, def update_swarm(self, version, swarm_spec=None, rotate_worker_token=False,
rotate_manager_token=False): rotate_manager_token=False):
"""
Update the Swarm's configuration
Args:
version (int): The version number of the swarm object being
updated. This is required to avoid conflicting writes.
swarm_spec (dict): Configuration settings to update. Use
:py:meth:`~docker.api.swarm.SwarmApiMixin.create_swarm_spec` to
generate a valid configuration. Default: ``None``.
rotate_worker_token (bool): Rotate the worker join token. Default:
``False``.
rotate_manager_token (bool): Rotate the manager join token.
Default: ``False``.
Returns:
``True`` if the request went through.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
"""
url = self._url('/swarm/update') url = self._url('/swarm/update')
response = self._post_json(url, data=swarm_spec, params={ response = self._post_json(url, data=swarm_spec, params={
'rotateWorkerToken': rotate_worker_token, 'rotateWorkerToken': rotate_worker_token,
......
...@@ -5,6 +5,32 @@ from .. import utils ...@@ -5,6 +5,32 @@ from .. import utils
class VolumeApiMixin(object): class VolumeApiMixin(object):
@utils.minimum_version('1.21') @utils.minimum_version('1.21')
def volumes(self, filters=None): def volumes(self, filters=None):
"""
List volumes currently registered by the docker daemon. Similar to the
``docker volume ls`` command.
Args:
filters (dict): Server-side list filtering options.
Returns:
(dict): Dictionary with list of volume objects as value of the
``Volumes`` key.
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
Example:
>>> cli.volumes()
{u'Volumes': [{u'Driver': u'local',
u'Mountpoint': u'/var/lib/docker/volumes/foobar/_data',
u'Name': u'foobar'},
{u'Driver': u'local',
u'Mountpoint': u'/var/lib/docker/volumes/baz/_data',
u'Name': u'baz'}]}
"""
params = { params = {
'filters': utils.convert_filters(filters) if filters else None 'filters': utils.convert_filters(filters) if filters else None
} }
...@@ -13,6 +39,34 @@ class VolumeApiMixin(object): ...@@ -13,6 +39,34 @@ class VolumeApiMixin(object):
@utils.minimum_version('1.21') @utils.minimum_version('1.21')
def create_volume(self, name, driver=None, driver_opts=None, labels=None): def create_volume(self, name, driver=None, driver_opts=None, labels=None):
"""
Create and register a named volume
Args:
name (str): Name of the volume
driver (str): Name of the driver used to create the volume
driver_opts (dict): Driver options as a key-value dictionary
labels (dict): Labels to set on the volume
Returns:
(dict): The created volume reference object
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
Example:
>>> volume = cli.create_volume(name='foobar', driver='local',
driver_opts={'foo': 'bar', 'baz': 'false'},
labels={"key": "value"})
>>> print(volume)
{u'Driver': u'local',
u'Labels': {u'key': u'value'},
u'Mountpoint': u'/var/lib/docker/volumes/foobar/_data',
u'Name': u'foobar'}
"""
url = self._url('/volumes/create') url = self._url('/volumes/create')
if driver_opts is not None and not isinstance(driver_opts, dict): if driver_opts is not None and not isinstance(driver_opts, dict):
raise TypeError('driver_opts must be a dictionary') raise TypeError('driver_opts must be a dictionary')
...@@ -36,11 +90,42 @@ class VolumeApiMixin(object): ...@@ -36,11 +90,42 @@ class VolumeApiMixin(object):
@utils.minimum_version('1.21') @utils.minimum_version('1.21')
def inspect_volume(self, name): def inspect_volume(self, name):
"""
Retrieve volume info by name.
Args:
name (str): volume name
Returns:
(dict): Volume information dictionary
Raises:
:py:class:`docker.errors.APIError`
If the server returns an error.
Example:
>>> cli.inspect_volume('foobar')
{u'Driver': u'local',
u'Mountpoint': u'/var/lib/docker/volumes/foobar/_data',
u'Name': u'foobar'}
"""
url = self._url('/volumes/{0}', name) url = self._url('/volumes/{0}', name)
return self._result(self._get(url), True) return self._result(self._get(url), True)
@utils.minimum_version('1.21') @utils.minimum_version('1.21')
def remove_volume(self, name): def remove_volume(self, name):
"""
Remove a volume. Similar to the ``docker volume rm`` command.
Args:
name (str): The volume's name
Raises:
``docker.errors.APIError``: If volume failed to remove.
"""
url = self._url('/volumes/{0}', name) url = self._url('/volumes/{0}', name)
resp = self._delete(url) resp = self._delete(url)
self._raise_for_status(resp) self._raise_for_status(resp)
...@@ -5,6 +5,20 @@ from . import errors, ssladapter ...@@ -5,6 +5,20 @@ from . import errors, ssladapter
class TLSConfig(object): class TLSConfig(object):
"""
TLS configuration.
Args:
client_cert (tuple of str): Path to client cert, path to client key.
ca_cert (str): Path to CA cert file.
verify (bool or str): This can be ``False`` or a path to a CA cert
file.
ssl_version (int): A valid `SSL version`_.
assert_hostname (bool): Verify the hostname of the server.
.. _`SSL version`:
https://docs.python.org/3.5/library/ssl.html#ssl.PROTOCOL_TLSv1
"""
cert = None cert = None
ca_cert = None ca_cert = None
verify = None verify = None
...@@ -57,6 +71,9 @@ class TLSConfig(object): ...@@ -57,6 +71,9 @@ class TLSConfig(object):
) )
def configure_client(self, client): def configure_client(self, client):
"""
Configure a client with these TLS options.
"""
client.ssl_version = self.ssl_version client.ssl_version = self.ssl_version
if self.verify and self.ca_cert: if self.verify and self.ca_cert:
......
...@@ -39,6 +39,38 @@ BYTE_UNITS = { ...@@ -39,6 +39,38 @@ BYTE_UNITS = {
def create_ipam_pool(subnet=None, iprange=None, gateway=None, def create_ipam_pool(subnet=None, iprange=None, gateway=None,
aux_addresses=None): aux_addresses=None):
"""
Create an IPAM pool config dictionary to be added to the
``pool_configs`` parameter of
:py:meth:`~docker.utils.create_ipam_config`.
Args:
subnet (str): Custom subnet for this IPAM pool using the CIDR
notation. Defaults to ``None``.
iprange (str): Custom IP range for endpoints in this IPAM pool using
the CIDR notation. Defaults to ``None``.
gateway (str): Custom IP address for the pool's gateway.
aux_addresses (dict): A dictionary of ``key -> ip_address``
relationships specifying auxiliary addresses that need to be
allocated by the IPAM driver.
Returns:
(dict) An IPAM pool config
Example:
>>> ipam_pool = docker.utils.create_ipam_pool(
subnet='124.42.0.0/16',
iprange='124.42.0.0/24',
gateway='124.42.0.254',
aux_addresses={
'reserved1': '124.42.1.1'
}
)
>>> ipam_config = docker.utils.create_ipam_config(
pool_configs=[ipam_pool])
"""
return { return {
'Subnet': subnet, 'Subnet': subnet,
'IPRange': iprange, 'IPRange': iprange,
...@@ -48,6 +80,25 @@ def create_ipam_pool(subnet=None, iprange=None, gateway=None, ...@@ -48,6 +80,25 @@ def create_ipam_pool(subnet=None, iprange=None, gateway=None,
def create_ipam_config(driver='default', pool_configs=None): def create_ipam_config(driver='default', pool_configs=None):
"""
Create an IPAM (IP Address Management) config dictionary to be used with
:py:meth:`~docker.api.network.NetworkApiMixin.create_network`.
Args:
driver (str): The IPAM driver to use. Defaults to ``default``.
pool_configs (list): A list of pool configuration dictionaries as
created by :py:meth:`~docker.utils.create_ipam_pool`. Defaults to
empty list.
Returns:
(dict) An IPAM config.
Example:
>>> ipam_config = docker.utils.create_ipam_config(driver='default')
>>> network = client.create_network('network1', ipam=ipam_config)
"""
return { return {
'Driver': driver, 'Driver': driver,
'Config': pool_configs or [] 'Config': pool_configs or []
......
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