mirror of https://github.com/docker/docker-py.git
Refuse API version < 1.21 ; Remove associated code paths
Signed-off-by: Joffrey F <joffrey@docker.com>
This commit is contained in:
parent
b180b8770a
commit
df8422d079
|
@ -1,7 +1,6 @@
|
|||
import json
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
|
||||
from .. import auth
|
||||
from .. import constants
|
||||
|
@ -14,7 +13,7 @@ log = logging.getLogger(__name__)
|
|||
|
||||
class BuildApiMixin(object):
|
||||
def build(self, path=None, tag=None, quiet=False, fileobj=None,
|
||||
nocache=False, rm=False, stream=False, timeout=None,
|
||||
nocache=False, rm=False, timeout=None,
|
||||
custom_context=False, encoding=None, pull=False,
|
||||
forcerm=False, dockerfile=None, container_limits=None,
|
||||
decode=False, buildargs=None, gzip=False, shmsize=None,
|
||||
|
@ -67,9 +66,6 @@ class BuildApiMixin(object):
|
|||
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
|
||||
|
@ -154,17 +150,6 @@ class BuildApiMixin(object):
|
|||
)
|
||||
encoding = 'gzip' if gzip else encoding
|
||||
|
||||
if utils.compare_version('1.8', self._version) >= 0:
|
||||
stream = True
|
||||
|
||||
if dockerfile and utils.compare_version('1.17', self._version) < 0:
|
||||
raise errors.InvalidVersion(
|
||||
'dockerfile was only introduced in API version 1.17'
|
||||
)
|
||||
|
||||
if utils.compare_version('1.19', self._version) < 0:
|
||||
pull = 1 if pull else 0
|
||||
|
||||
u = self._url('/build')
|
||||
params = {
|
||||
't': tag,
|
||||
|
@ -179,12 +164,7 @@ class BuildApiMixin(object):
|
|||
params.update(container_limits)
|
||||
|
||||
if buildargs:
|
||||
if utils.version_gte(self._version, '1.21'):
|
||||
params.update({'buildargs': json.dumps(buildargs)})
|
||||
else:
|
||||
raise errors.InvalidVersion(
|
||||
'buildargs was only introduced in API version 1.21'
|
||||
)
|
||||
params.update({'buildargs': json.dumps(buildargs)})
|
||||
|
||||
if shmsize:
|
||||
if utils.version_gte(self._version, '1.22'):
|
||||
|
@ -256,30 +236,21 @@ class BuildApiMixin(object):
|
|||
if encoding:
|
||||
headers['Content-Encoding'] = encoding
|
||||
|
||||
if utils.compare_version('1.9', self._version) >= 0:
|
||||
self._set_auth_headers(headers)
|
||||
self._set_auth_headers(headers)
|
||||
|
||||
response = self._post(
|
||||
u,
|
||||
data=context,
|
||||
params=params,
|
||||
headers=headers,
|
||||
stream=stream,
|
||||
stream=True,
|
||||
timeout=timeout,
|
||||
)
|
||||
|
||||
if context is not None and not custom_context:
|
||||
context.close()
|
||||
|
||||
if stream:
|
||||
return self._stream_helper(response, decode=decode)
|
||||
else:
|
||||
output = self._result(response)
|
||||
srch = r'Successfully built ([0-9a-f]+)'
|
||||
match = re.search(srch, output)
|
||||
if not match:
|
||||
return None, output
|
||||
return match.group(1), output
|
||||
return self._stream_helper(response, decode=decode)
|
||||
|
||||
def _set_auth_headers(self, headers):
|
||||
log.debug('Looking for auth config')
|
||||
|
@ -316,13 +287,8 @@ class BuildApiMixin(object):
|
|||
)
|
||||
)
|
||||
|
||||
if utils.compare_version('1.19', self._version) >= 0:
|
||||
headers['X-Registry-Config'] = auth.encode_header(
|
||||
auth_data
|
||||
)
|
||||
else:
|
||||
headers['X-Registry-Config'] = auth.encode_header({
|
||||
'configs': auth_data
|
||||
})
|
||||
headers['X-Registry-Config'] = auth.encode_header(
|
||||
auth_data
|
||||
)
|
||||
else:
|
||||
log.debug('No auth config found')
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import json
|
||||
import struct
|
||||
import warnings
|
||||
from functools import partial
|
||||
|
||||
import requests
|
||||
|
@ -27,7 +26,7 @@ from ..constants import (
|
|||
MINIMUM_DOCKER_API_VERSION
|
||||
)
|
||||
from ..errors import (
|
||||
DockerException, TLSParameterError,
|
||||
DockerException, InvalidVersion, TLSParameterError,
|
||||
create_api_error_from_http_exception
|
||||
)
|
||||
from ..tls import TLSConfig
|
||||
|
@ -160,11 +159,9 @@ class APIClient(
|
|||
)
|
||||
)
|
||||
if utils.version_lt(self._version, MINIMUM_DOCKER_API_VERSION):
|
||||
warnings.warn(
|
||||
'The minimum API version supported is {}, but you are using '
|
||||
'version {}. It is recommended you either upgrade Docker '
|
||||
'Engine or use an older version of Docker SDK for '
|
||||
'Python.'.format(MINIMUM_DOCKER_API_VERSION, self._version)
|
||||
raise InvalidVersion(
|
||||
'API versions below {} are no longer supported by this '
|
||||
'library.'.format(MINIMUM_DOCKER_API_VERSION)
|
||||
)
|
||||
|
||||
def _retrieve_server_version(self):
|
||||
|
@ -353,17 +350,8 @@ class APIClient(
|
|||
break
|
||||
yield data
|
||||
|
||||
def _stream_raw_result_old(self, response):
|
||||
''' Stream raw output for API versions below 1.6 '''
|
||||
self._raise_for_status(response)
|
||||
for line in response.iter_lines(chunk_size=1,
|
||||
decode_unicode=True):
|
||||
# filter out keep-alive new lines
|
||||
if line:
|
||||
yield line
|
||||
|
||||
def _stream_raw_result(self, response):
|
||||
''' Stream result for TTY-enabled container above API 1.6 '''
|
||||
''' Stream result for TTY-enabled container '''
|
||||
self._raise_for_status(response)
|
||||
for out in response.iter_content(chunk_size=1, decode_unicode=True):
|
||||
yield out
|
||||
|
@ -419,11 +407,6 @@ class APIClient(
|
|||
return self._get_result_tty(stream, res, self._check_is_tty(container))
|
||||
|
||||
def _get_result_tty(self, stream, res, is_tty):
|
||||
# Stream multi-plexing was only introduced in API v1.6. Anything
|
||||
# before that needs old-style streaming.
|
||||
if utils.compare_version('1.6', self._version) < 0:
|
||||
return self._stream_raw_result_old(res)
|
||||
|
||||
# We should also use raw streaming (without keep-alives)
|
||||
# if we're dealing with a tty-enabled container.
|
||||
if is_tty:
|
||||
|
|
|
@ -204,15 +204,13 @@ class ContainerApiMixin(object):
|
|||
return res
|
||||
|
||||
def create_container(self, image, command=None, hostname=None, user=None,
|
||||
detach=False, stdin_open=False, tty=False,
|
||||
mem_limit=None, ports=None, environment=None,
|
||||
dns=None, volumes=None, volumes_from=None,
|
||||
detach=False, stdin_open=False, tty=False, ports=None,
|
||||
environment=None, volumes=None,
|
||||
network_disabled=False, name=None, entrypoint=None,
|
||||
cpu_shares=None, working_dir=None, domainname=None,
|
||||
memswap_limit=None, cpuset=None, host_config=None,
|
||||
mac_address=None, labels=None, volume_driver=None,
|
||||
stop_signal=None, networking_config=None,
|
||||
healthcheck=None, stop_timeout=None, runtime=None):
|
||||
working_dir=None, domainname=None, host_config=None,
|
||||
mac_address=None, labels=None, stop_signal=None,
|
||||
networking_config=None, healthcheck=None,
|
||||
stop_timeout=None, runtime=None):
|
||||
"""
|
||||
Creates a container. Parameters are similar to those for the ``docker
|
||||
run`` command except it doesn't support the attach options (``-a``).
|
||||
|
@ -354,27 +352,17 @@ class ContainerApiMixin(object):
|
|||
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 (:py:class:`list`): DNS name servers. Deprecated since API
|
||||
version 1.10. Use ``host_config`` instead.
|
||||
volumes (str or list): List of paths inside the container to use
|
||||
as volumes.
|
||||
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
|
||||
working_dir (str): Path to the working directory
|
||||
domainname (str): The domain name to use for the container
|
||||
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
|
||||
|
@ -382,7 +370,6 @@ class ContainerApiMixin(object):
|
|||
``{"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``).
|
||||
stop_timeout (int): Timeout to stop the container, in seconds.
|
||||
|
@ -405,17 +392,12 @@ class ContainerApiMixin(object):
|
|||
if isinstance(volumes, six.string_types):
|
||||
volumes = [volumes, ]
|
||||
|
||||
if host_config and utils.compare_version('1.15', self._version) < 0:
|
||||
raise errors.InvalidVersion(
|
||||
'host_config is not supported in API < 1.15'
|
||||
)
|
||||
|
||||
config = self.create_container_config(
|
||||
image, command, hostname, user, detach, stdin_open, tty, mem_limit,
|
||||
ports, dns, environment, volumes, volumes_from,
|
||||
network_disabled, entrypoint, cpu_shares, working_dir, domainname,
|
||||
memswap_limit, cpuset, host_config, mac_address, labels,
|
||||
volume_driver, stop_signal, networking_config, healthcheck,
|
||||
image, command, hostname, user, detach, stdin_open, tty,
|
||||
ports, environment, volumes,
|
||||
network_disabled, entrypoint, working_dir, domainname,
|
||||
host_config, mac_address, labels,
|
||||
stop_signal, networking_config, healthcheck,
|
||||
stop_timeout, runtime
|
||||
)
|
||||
return self.create_container_from_config(config, name)
|
||||
|
@ -681,7 +663,6 @@ class ContainerApiMixin(object):
|
|||
return self._stream_raw_result(res)
|
||||
|
||||
@utils.check_resource('container')
|
||||
@utils.minimum_version('1.20')
|
||||
def get_archive(self, container, path):
|
||||
"""
|
||||
Retrieve a file or folder from a container in the form of a tar
|
||||
|
@ -786,59 +767,46 @@ class ContainerApiMixin(object):
|
|||
:py:class:`docker.errors.APIError`
|
||||
If the server returns an error.
|
||||
"""
|
||||
if utils.compare_version('1.11', self._version) >= 0:
|
||||
if follow is None:
|
||||
follow = stream
|
||||
params = {'stderr': stderr and 1 or 0,
|
||||
'stdout': stdout and 1 or 0,
|
||||
'timestamps': timestamps and 1 or 0,
|
||||
'follow': follow and 1 or 0,
|
||||
}
|
||||
if utils.compare_version('1.13', self._version) >= 0:
|
||||
if tail != 'all' and (not isinstance(tail, int) or tail < 0):
|
||||
tail = 'all'
|
||||
params['tail'] = tail
|
||||
if follow is None:
|
||||
follow = stream
|
||||
params = {'stderr': stderr and 1 or 0,
|
||||
'stdout': stdout and 1 or 0,
|
||||
'timestamps': timestamps and 1 or 0,
|
||||
'follow': follow and 1 or 0,
|
||||
}
|
||||
if tail != 'all' and (not isinstance(tail, int) or tail < 0):
|
||||
tail = 'all'
|
||||
params['tail'] = tail
|
||||
|
||||
if since is not None:
|
||||
if utils.version_lt(self._version, '1.19'):
|
||||
raise errors.InvalidVersion(
|
||||
'since is not supported for API version < 1.19'
|
||||
)
|
||||
if isinstance(since, datetime):
|
||||
params['since'] = utils.datetime_to_timestamp(since)
|
||||
elif (isinstance(since, int) and since > 0):
|
||||
params['since'] = since
|
||||
else:
|
||||
raise errors.InvalidArgument(
|
||||
'since value should be datetime or positive int, '
|
||||
'not {}'.format(type(since))
|
||||
)
|
||||
if since is not None:
|
||||
if isinstance(since, datetime):
|
||||
params['since'] = utils.datetime_to_timestamp(since)
|
||||
elif (isinstance(since, int) and since > 0):
|
||||
params['since'] = since
|
||||
else:
|
||||
raise errors.InvalidArgument(
|
||||
'since value should be datetime or positive int, '
|
||||
'not {}'.format(type(since))
|
||||
)
|
||||
|
||||
if until is not None:
|
||||
if utils.version_lt(self._version, '1.35'):
|
||||
raise errors.InvalidVersion(
|
||||
'until is not supported for API version < 1.35'
|
||||
)
|
||||
if isinstance(until, datetime):
|
||||
params['until'] = utils.datetime_to_timestamp(until)
|
||||
elif (isinstance(until, int) and until > 0):
|
||||
params['until'] = until
|
||||
else:
|
||||
raise errors.InvalidArgument(
|
||||
'until value should be datetime or positive int, '
|
||||
'not {}'.format(type(until))
|
||||
)
|
||||
if until is not None:
|
||||
if utils.version_lt(self._version, '1.35'):
|
||||
raise errors.InvalidVersion(
|
||||
'until is not supported for API version < 1.35'
|
||||
)
|
||||
if isinstance(until, datetime):
|
||||
params['until'] = utils.datetime_to_timestamp(until)
|
||||
elif (isinstance(until, int) and until > 0):
|
||||
params['until'] = until
|
||||
else:
|
||||
raise errors.InvalidArgument(
|
||||
'until value should be datetime or positive int, '
|
||||
'not {}'.format(type(until))
|
||||
)
|
||||
|
||||
url = self._url("/containers/{0}/logs", container)
|
||||
res = self._get(url, params=params, stream=stream)
|
||||
return self._get_result(container, stream, res)
|
||||
return self.attach(
|
||||
container,
|
||||
stdout=stdout,
|
||||
stderr=stderr,
|
||||
stream=stream,
|
||||
logs=True
|
||||
)
|
||||
url = self._url("/containers/{0}/logs", container)
|
||||
res = self._get(url, params=params, stream=stream)
|
||||
return self._get_result(container, stream, res)
|
||||
|
||||
@utils.check_resource('container')
|
||||
def pause(self, container):
|
||||
|
@ -906,7 +874,6 @@ class ContainerApiMixin(object):
|
|||
return h_ports
|
||||
|
||||
@utils.check_resource('container')
|
||||
@utils.minimum_version('1.20')
|
||||
def put_archive(self, container, path, data):
|
||||
"""
|
||||
Insert a file or folder in an existing container using a tar archive as
|
||||
|
@ -976,7 +943,6 @@ class ContainerApiMixin(object):
|
|||
)
|
||||
self._raise_for_status(res)
|
||||
|
||||
@utils.minimum_version('1.17')
|
||||
@utils.check_resource('container')
|
||||
def rename(self, container, name):
|
||||
"""
|
||||
|
@ -1073,7 +1039,6 @@ class ContainerApiMixin(object):
|
|||
res = self._post(url)
|
||||
self._raise_for_status(res)
|
||||
|
||||
@utils.minimum_version('1.17')
|
||||
@utils.check_resource('container')
|
||||
def stats(self, container, decode=None, stream=True):
|
||||
"""
|
||||
|
|
|
@ -5,7 +5,6 @@ from .. import utils
|
|||
|
||||
|
||||
class ExecApiMixin(object):
|
||||
@utils.minimum_version('1.15')
|
||||
@utils.check_resource('container')
|
||||
def exec_create(self, container, cmd, stdout=True, stderr=True,
|
||||
stdin=False, tty=False, privileged=False, user='',
|
||||
|
@ -41,14 +40,6 @@ class ExecApiMixin(object):
|
|||
If the server returns an error.
|
||||
"""
|
||||
|
||||
if privileged and utils.version_lt(self._version, '1.19'):
|
||||
raise errors.InvalidVersion(
|
||||
'Privileged exec is not supported in API < 1.19'
|
||||
)
|
||||
if user and utils.version_lt(self._version, '1.19'):
|
||||
raise errors.InvalidVersion(
|
||||
'User-specific exec is not supported in API < 1.19'
|
||||
)
|
||||
if environment is not None and utils.version_lt(self._version, '1.25'):
|
||||
raise errors.InvalidVersion(
|
||||
'Setting environment for exec is not supported in API < 1.25'
|
||||
|
@ -88,7 +79,6 @@ class ExecApiMixin(object):
|
|||
res = self._post_json(url, data=data)
|
||||
return self._result(res, True)
|
||||
|
||||
@utils.minimum_version('1.16')
|
||||
def exec_inspect(self, exec_id):
|
||||
"""
|
||||
Return low-level information about an exec command.
|
||||
|
@ -108,7 +98,6 @@ class ExecApiMixin(object):
|
|||
res = self._get(self._url("/exec/{0}/json", exec_id))
|
||||
return self._result(res, True)
|
||||
|
||||
@utils.minimum_version('1.15')
|
||||
def exec_resize(self, exec_id, height=None, width=None):
|
||||
"""
|
||||
Resize the tty session used by the specified exec command.
|
||||
|
@ -127,7 +116,6 @@ class ExecApiMixin(object):
|
|||
res = self._post(url, params=params)
|
||||
self._raise_for_status(res)
|
||||
|
||||
@utils.minimum_version('1.15')
|
||||
@utils.check_resource('exec_id')
|
||||
def exec_start(self, exec_id, detach=False, tty=False, stream=False,
|
||||
socket=False):
|
||||
|
|
|
@ -54,8 +54,7 @@ class ImageApiMixin(object):
|
|||
res = self._get(self._url("/images/{0}/history", image))
|
||||
return self._result(res, True)
|
||||
|
||||
def images(self, name=None, quiet=False, all=False, viz=False,
|
||||
filters=None):
|
||||
def images(self, name=None, quiet=False, all=False, filters=None):
|
||||
"""
|
||||
List images. Similar to the ``docker images`` command.
|
||||
|
||||
|
@ -76,10 +75,6 @@ class ImageApiMixin(object):
|
|||
:py:class:`docker.errors.APIError`
|
||||
If the server returns an error.
|
||||
"""
|
||||
if viz:
|
||||
if utils.compare_version('1.7', self._version) >= 0:
|
||||
raise Exception('Viz output is not supported in API >= 1.7!')
|
||||
return self._result(self._get(self._url("images/viz")))
|
||||
params = {
|
||||
'filter': name,
|
||||
'only_ids': 1 if quiet else 0,
|
||||
|
@ -225,19 +220,6 @@ class ImageApiMixin(object):
|
|||
image=image, repository=repository, tag=tag, changes=changes
|
||||
)
|
||||
|
||||
@utils.check_resource('image')
|
||||
def insert(self, image, url, path):
|
||||
if utils.compare_version('1.12', self._version) >= 0:
|
||||
raise errors.DeprecatedMethod(
|
||||
'insert is not available for API version >=1.12'
|
||||
)
|
||||
api_url = self._url("/images/{0}/insert", image)
|
||||
params = {
|
||||
'url': url,
|
||||
'path': path
|
||||
}
|
||||
return self._result(self._post(api_url, params=params))
|
||||
|
||||
@utils.check_resource('image')
|
||||
def inspect_image(self, image):
|
||||
"""
|
||||
|
@ -369,14 +351,13 @@ class ImageApiMixin(object):
|
|||
}
|
||||
headers = {}
|
||||
|
||||
if utils.version_gte(self._version, '1.5'):
|
||||
if auth_config is None:
|
||||
header = auth.get_config_header(self, registry)
|
||||
if header:
|
||||
headers['X-Registry-Auth'] = header
|
||||
else:
|
||||
log.debug('Sending supplied auth config')
|
||||
headers['X-Registry-Auth'] = auth.encode_header(auth_config)
|
||||
if auth_config is None:
|
||||
header = auth.get_config_header(self, registry)
|
||||
if header:
|
||||
headers['X-Registry-Auth'] = header
|
||||
else:
|
||||
log.debug('Sending supplied auth config')
|
||||
headers['X-Registry-Auth'] = auth.encode_header(auth_config)
|
||||
|
||||
if platform is not None:
|
||||
if utils.version_lt(self._version, '1.32'):
|
||||
|
@ -440,14 +421,13 @@ class ImageApiMixin(object):
|
|||
}
|
||||
headers = {}
|
||||
|
||||
if utils.compare_version('1.5', self._version) >= 0:
|
||||
if auth_config is None:
|
||||
header = auth.get_config_header(self, registry)
|
||||
if header:
|
||||
headers['X-Registry-Auth'] = header
|
||||
else:
|
||||
log.debug('Sending supplied auth config')
|
||||
headers['X-Registry-Auth'] = auth.encode_header(auth_config)
|
||||
if auth_config is None:
|
||||
header = auth.get_config_header(self, registry)
|
||||
if header:
|
||||
headers['X-Registry-Auth'] = header
|
||||
else:
|
||||
log.debug('Sending supplied auth config')
|
||||
headers['X-Registry-Auth'] = auth.encode_header(auth_config)
|
||||
|
||||
response = self._post_json(
|
||||
u, None, headers=headers, stream=stream, params=params
|
||||
|
|
|
@ -5,7 +5,6 @@ from .. import utils
|
|||
|
||||
|
||||
class NetworkApiMixin(object):
|
||||
@minimum_version('1.21')
|
||||
def networks(self, names=None, ids=None, filters=None):
|
||||
"""
|
||||
List networks. Similar to the ``docker networks ls`` command.
|
||||
|
@ -38,7 +37,6 @@ class NetworkApiMixin(object):
|
|||
res = self._get(url, params=params)
|
||||
return self._result(res, json=True)
|
||||
|
||||
@minimum_version('1.21')
|
||||
def create_network(self, name, driver=None, options=None, ipam=None,
|
||||
check_duplicate=None, internal=False, labels=None,
|
||||
enable_ipv6=False, attachable=None, scope=None,
|
||||
|
@ -175,7 +173,6 @@ class NetworkApiMixin(object):
|
|||
url = self._url('/networks/prune')
|
||||
return self._result(self._post(url, params=params), True)
|
||||
|
||||
@minimum_version('1.21')
|
||||
@check_resource('net_id')
|
||||
def remove_network(self, net_id):
|
||||
"""
|
||||
|
@ -188,7 +185,6 @@ class NetworkApiMixin(object):
|
|||
res = self._delete(url)
|
||||
self._raise_for_status(res)
|
||||
|
||||
@minimum_version('1.21')
|
||||
@check_resource('net_id')
|
||||
def inspect_network(self, net_id, verbose=None, scope=None):
|
||||
"""
|
||||
|
@ -216,7 +212,6 @@ class NetworkApiMixin(object):
|
|||
return self._result(res, json=True)
|
||||
|
||||
@check_resource('container')
|
||||
@minimum_version('1.21')
|
||||
def connect_container_to_network(self, container, net_id,
|
||||
ipv4_address=None, ipv6_address=None,
|
||||
aliases=None, links=None,
|
||||
|
@ -253,7 +248,6 @@ class NetworkApiMixin(object):
|
|||
self._raise_for_status(res)
|
||||
|
||||
@check_resource('container')
|
||||
@minimum_version('1.21')
|
||||
def disconnect_container_from_network(self, container, net_id,
|
||||
force=False):
|
||||
"""
|
||||
|
|
|
@ -3,7 +3,6 @@ from .. import utils
|
|||
|
||||
|
||||
class VolumeApiMixin(object):
|
||||
@utils.minimum_version('1.21')
|
||||
def volumes(self, filters=None):
|
||||
"""
|
||||
List volumes currently registered by the docker daemon. Similar to the
|
||||
|
@ -37,7 +36,6 @@ class VolumeApiMixin(object):
|
|||
url = self._url('/volumes')
|
||||
return self._result(self._get(url, params=params), True)
|
||||
|
||||
@utils.minimum_version('1.21')
|
||||
def create_volume(self, name=None, driver=None, driver_opts=None,
|
||||
labels=None):
|
||||
"""
|
||||
|
@ -90,7 +88,6 @@ class VolumeApiMixin(object):
|
|||
|
||||
return self._result(self._post_json(url, data=data), True)
|
||||
|
||||
@utils.minimum_version('1.21')
|
||||
def inspect_volume(self, name):
|
||||
"""
|
||||
Retrieve volume info by name.
|
||||
|
@ -138,7 +135,6 @@ class VolumeApiMixin(object):
|
|||
url = self._url('/volumes/prune')
|
||||
return self._result(self._post(url, params=params), True)
|
||||
|
||||
@utils.minimum_version('1.21')
|
||||
def remove_volume(self, name, force=False):
|
||||
"""
|
||||
Remove a volume. Similar to the ``docker volume rm`` command.
|
||||
|
|
|
@ -129,20 +129,12 @@ class HostConfig(dict):
|
|||
self['MemorySwap'] = parse_bytes(memswap_limit)
|
||||
|
||||
if mem_reservation:
|
||||
if version_lt(version, '1.21'):
|
||||
raise host_config_version_error('mem_reservation', '1.21')
|
||||
|
||||
self['MemoryReservation'] = parse_bytes(mem_reservation)
|
||||
|
||||
if kernel_memory:
|
||||
if version_lt(version, '1.21'):
|
||||
raise host_config_version_error('kernel_memory', '1.21')
|
||||
|
||||
self['KernelMemory'] = parse_bytes(kernel_memory)
|
||||
|
||||
if mem_swappiness is not None:
|
||||
if version_lt(version, '1.20'):
|
||||
raise host_config_version_error('mem_swappiness', '1.20')
|
||||
if not isinstance(mem_swappiness, int):
|
||||
raise host_config_type_error(
|
||||
'mem_swappiness', mem_swappiness, 'int'
|
||||
|
@ -168,9 +160,6 @@ class HostConfig(dict):
|
|||
self['Privileged'] = privileged
|
||||
|
||||
if oom_kill_disable:
|
||||
if version_lt(version, '1.20'):
|
||||
raise host_config_version_error('oom_kill_disable', '1.19')
|
||||
|
||||
self['OomKillDisable'] = oom_kill_disable
|
||||
|
||||
if oom_score_adj:
|
||||
|
@ -193,7 +182,7 @@ class HostConfig(dict):
|
|||
|
||||
if network_mode:
|
||||
self['NetworkMode'] = network_mode
|
||||
elif network_mode is None and version_gte(version, '1.20'):
|
||||
elif network_mode is None:
|
||||
self['NetworkMode'] = 'default'
|
||||
|
||||
if restart_policy:
|
||||
|
@ -214,18 +203,12 @@ class HostConfig(dict):
|
|||
self['Devices'] = parse_devices(devices)
|
||||
|
||||
if group_add:
|
||||
if version_lt(version, '1.20'):
|
||||
raise host_config_version_error('group_add', '1.20')
|
||||
|
||||
self['GroupAdd'] = [six.text_type(grp) for grp in group_add]
|
||||
|
||||
if dns is not None:
|
||||
self['Dns'] = dns
|
||||
|
||||
if dns_opt is not None:
|
||||
if version_lt(version, '1.21'):
|
||||
raise host_config_version_error('dns_opt', '1.21')
|
||||
|
||||
self['DnsOptions'] = dns_opt
|
||||
|
||||
if security_opt is not None:
|
||||
|
@ -298,38 +281,23 @@ class HostConfig(dict):
|
|||
if cpu_quota:
|
||||
if not isinstance(cpu_quota, int):
|
||||
raise host_config_type_error('cpu_quota', cpu_quota, 'int')
|
||||
if version_lt(version, '1.19'):
|
||||
raise host_config_version_error('cpu_quota', '1.19')
|
||||
|
||||
self['CpuQuota'] = cpu_quota
|
||||
|
||||
if cpu_period:
|
||||
if not isinstance(cpu_period, int):
|
||||
raise host_config_type_error('cpu_period', cpu_period, 'int')
|
||||
if version_lt(version, '1.19'):
|
||||
raise host_config_version_error('cpu_period', '1.19')
|
||||
|
||||
self['CpuPeriod'] = cpu_period
|
||||
|
||||
if cpu_shares:
|
||||
if version_lt(version, '1.18'):
|
||||
raise host_config_version_error('cpu_shares', '1.18')
|
||||
|
||||
if not isinstance(cpu_shares, int):
|
||||
raise host_config_type_error('cpu_shares', cpu_shares, 'int')
|
||||
|
||||
self['CpuShares'] = cpu_shares
|
||||
|
||||
if cpuset_cpus:
|
||||
if version_lt(version, '1.18'):
|
||||
raise host_config_version_error('cpuset_cpus', '1.18')
|
||||
|
||||
self['CpusetCpus'] = cpuset_cpus
|
||||
|
||||
if cpuset_mems:
|
||||
if version_lt(version, '1.19'):
|
||||
raise host_config_version_error('cpuset_mems', '1.19')
|
||||
|
||||
if not isinstance(cpuset_mems, str):
|
||||
raise host_config_type_error(
|
||||
'cpuset_mems', cpuset_mems, 'str'
|
||||
|
@ -462,8 +430,6 @@ class HostConfig(dict):
|
|||
self['InitPath'] = init_path
|
||||
|
||||
if volume_driver is not None:
|
||||
if version_lt(version, '1.21'):
|
||||
raise host_config_version_error('volume_driver', '1.21')
|
||||
self['VolumeDriver'] = volume_driver
|
||||
|
||||
if cpu_count:
|
||||
|
@ -520,53 +486,12 @@ def host_config_value_error(param, param_value):
|
|||
class ContainerConfig(dict):
|
||||
def __init__(
|
||||
self, version, image, command, hostname=None, user=None, detach=False,
|
||||
stdin_open=False, tty=False, mem_limit=None, ports=None, dns=None,
|
||||
environment=None, volumes=None, volumes_from=None,
|
||||
network_disabled=False, entrypoint=None, cpu_shares=None,
|
||||
working_dir=None, domainname=None, memswap_limit=None, cpuset=None,
|
||||
host_config=None, mac_address=None, labels=None, volume_driver=None,
|
||||
stop_signal=None, networking_config=None, healthcheck=None,
|
||||
stop_timeout=None, runtime=None
|
||||
stdin_open=False, tty=False, ports=None, environment=None,
|
||||
volumes=None, network_disabled=False, entrypoint=None,
|
||||
working_dir=None, domainname=None, host_config=None, mac_address=None,
|
||||
labels=None, stop_signal=None, networking_config=None,
|
||||
healthcheck=None, stop_timeout=None, runtime=None
|
||||
):
|
||||
if version_gte(version, '1.10'):
|
||||
message = ('{0!r} parameter has no effect on create_container().'
|
||||
' It has been moved to host_config')
|
||||
if dns is not None:
|
||||
raise errors.InvalidVersion(message.format('dns'))
|
||||
if volumes_from is not None:
|
||||
raise errors.InvalidVersion(message.format('volumes_from'))
|
||||
|
||||
if version_lt(version, '1.18'):
|
||||
if labels is not None:
|
||||
raise errors.InvalidVersion(
|
||||
'labels were only introduced in API version 1.18'
|
||||
)
|
||||
|
||||
if version_lt(version, '1.19'):
|
||||
if volume_driver is not None:
|
||||
raise errors.InvalidVersion(
|
||||
'Volume drivers were only introduced in API version 1.19'
|
||||
)
|
||||
mem_limit = mem_limit if mem_limit is not None else 0
|
||||
memswap_limit = memswap_limit if memswap_limit is not None else 0
|
||||
else:
|
||||
if mem_limit is not None:
|
||||
raise errors.InvalidVersion(
|
||||
'mem_limit has been moved to host_config in API version'
|
||||
' 1.19'
|
||||
)
|
||||
|
||||
if memswap_limit is not None:
|
||||
raise errors.InvalidVersion(
|
||||
'memswap_limit has been moved to host_config in API '
|
||||
'version 1.19'
|
||||
)
|
||||
|
||||
if version_lt(version, '1.21'):
|
||||
if stop_signal is not None:
|
||||
raise errors.InvalidVersion(
|
||||
'stop_signal was only introduced in API version 1.21'
|
||||
)
|
||||
|
||||
if stop_timeout is not None and version_lt(version, '1.25'):
|
||||
raise errors.InvalidVersion(
|
||||
|
@ -597,12 +522,6 @@ class ContainerConfig(dict):
|
|||
if isinstance(labels, list):
|
||||
labels = dict((lbl, six.text_type('')) for lbl in labels)
|
||||
|
||||
if mem_limit is not None:
|
||||
mem_limit = parse_bytes(mem_limit)
|
||||
|
||||
if memswap_limit is not None:
|
||||
memswap_limit = parse_bytes(memswap_limit)
|
||||
|
||||
if isinstance(ports, list):
|
||||
exposed_ports = {}
|
||||
for port_definition in ports:
|
||||
|
@ -624,13 +543,6 @@ class ContainerConfig(dict):
|
|||
volumes_dict[vol] = {}
|
||||
volumes = volumes_dict
|
||||
|
||||
if volumes_from:
|
||||
if not isinstance(volumes_from, six.string_types):
|
||||
volumes_from = ','.join(volumes_from)
|
||||
else:
|
||||
# Force None, an empty list or dict causes client.start to fail
|
||||
volumes_from = None
|
||||
|
||||
if healthcheck and isinstance(healthcheck, dict):
|
||||
healthcheck = Healthcheck(**healthcheck)
|
||||
|
||||
|
@ -655,28 +567,20 @@ class ContainerConfig(dict):
|
|||
'Tty': tty,
|
||||
'OpenStdin': stdin_open,
|
||||
'StdinOnce': stdin_once,
|
||||
'Memory': mem_limit,
|
||||
'AttachStdin': attach_stdin,
|
||||
'AttachStdout': attach_stdout,
|
||||
'AttachStderr': attach_stderr,
|
||||
'Env': environment,
|
||||
'Cmd': command,
|
||||
'Dns': dns,
|
||||
'Image': image,
|
||||
'Volumes': volumes,
|
||||
'VolumesFrom': volumes_from,
|
||||
'NetworkDisabled': network_disabled,
|
||||
'Entrypoint': entrypoint,
|
||||
'CpuShares': cpu_shares,
|
||||
'Cpuset': cpuset,
|
||||
'CpusetCpus': cpuset,
|
||||
'WorkingDir': working_dir,
|
||||
'MemorySwap': memswap_limit,
|
||||
'HostConfig': host_config,
|
||||
'NetworkingConfig': networking_config,
|
||||
'MacAddress': mac_address,
|
||||
'Labels': labels,
|
||||
'VolumeDriver': volume_driver,
|
||||
'StopSignal': stop_signal,
|
||||
'Healthcheck': healthcheck,
|
||||
'StopTimeout': stop_timeout,
|
||||
|
|
|
@ -21,7 +21,7 @@ class BuildTest(BaseAPIIntegrationTest):
|
|||
'ADD https://dl.dropboxusercontent.com/u/20637798/silence.tar.gz'
|
||||
' /tmp/silence.tar.gz'
|
||||
]).encode('ascii'))
|
||||
stream = self.client.build(fileobj=script, stream=True, decode=True)
|
||||
stream = self.client.build(fileobj=script, decode=True)
|
||||
logs = []
|
||||
for chunk in stream:
|
||||
logs.append(chunk)
|
||||
|
@ -37,7 +37,7 @@ class BuildTest(BaseAPIIntegrationTest):
|
|||
'ADD https://dl.dropboxusercontent.com/u/20637798/silence.tar.gz'
|
||||
' /tmp/silence.tar.gz'
|
||||
]))
|
||||
stream = self.client.build(fileobj=script, stream=True)
|
||||
stream = self.client.build(fileobj=script)
|
||||
logs = ''
|
||||
for chunk in stream:
|
||||
if six.PY3:
|
||||
|
@ -45,7 +45,6 @@ class BuildTest(BaseAPIIntegrationTest):
|
|||
logs += chunk
|
||||
assert logs != ''
|
||||
|
||||
@requires_api_version('1.8')
|
||||
def test_build_with_dockerignore(self):
|
||||
base_dir = tempfile.mkdtemp()
|
||||
self.addCleanup(shutil.rmtree, base_dir)
|
||||
|
@ -97,7 +96,6 @@ class BuildTest(BaseAPIIntegrationTest):
|
|||
'/test/not-ignored'
|
||||
])
|
||||
|
||||
@requires_api_version('1.21')
|
||||
def test_build_with_buildargs(self):
|
||||
script = io.BytesIO('\n'.join([
|
||||
'FROM scratch',
|
||||
|
@ -320,7 +318,7 @@ class BuildTest(BaseAPIIntegrationTest):
|
|||
]))
|
||||
|
||||
stream = self.client.build(
|
||||
fileobj=script, stream=True, decode=True, nocache=True
|
||||
fileobj=script, decode=True, nocache=True
|
||||
)
|
||||
lines = []
|
||||
for chunk in stream:
|
||||
|
@ -341,7 +339,7 @@ class BuildTest(BaseAPIIntegrationTest):
|
|||
]))
|
||||
|
||||
stream = self.client.build(
|
||||
path=base_dir, stream=True, decode=True, nocache=True,
|
||||
path=base_dir, decode=True, nocache=True,
|
||||
gzip=True
|
||||
)
|
||||
|
||||
|
@ -365,7 +363,7 @@ class BuildTest(BaseAPIIntegrationTest):
|
|||
]))
|
||||
|
||||
stream = self.client.build(
|
||||
path=base_dir, stream=True, decode=True, nocache=True
|
||||
path=base_dir, decode=True, nocache=True
|
||||
)
|
||||
|
||||
lines = []
|
||||
|
@ -383,9 +381,7 @@ class BuildTest(BaseAPIIntegrationTest):
|
|||
script = io.BytesIO('FROM busybox\n'.encode('ascii'))
|
||||
|
||||
with pytest.raises(errors.APIError) as excinfo:
|
||||
stream = self.client.build(
|
||||
fileobj=script, stream=True, platform='foobar'
|
||||
)
|
||||
stream = self.client.build(fileobj=script, platform='foobar')
|
||||
for _ in stream:
|
||||
pass
|
||||
|
||||
|
|
|
@ -145,22 +145,18 @@ class CreateContainerTest(BaseAPIIntegrationTest):
|
|||
container2_id = res1['Id']
|
||||
self.tmp_containers.append(container2_id)
|
||||
self.client.start(container2_id)
|
||||
with pytest.raises(docker.errors.DockerException):
|
||||
self.client.create_container(
|
||||
BUSYBOX, 'cat', detach=True, stdin_open=True,
|
||||
volumes_from=vol_names
|
||||
)
|
||||
res2 = self.client.create_container(
|
||||
|
||||
res = self.client.create_container(
|
||||
BUSYBOX, 'cat', detach=True, stdin_open=True,
|
||||
host_config=self.client.create_host_config(
|
||||
volumes_from=vol_names, network_mode='none'
|
||||
)
|
||||
)
|
||||
container3_id = res2['Id']
|
||||
container3_id = res['Id']
|
||||
self.tmp_containers.append(container3_id)
|
||||
self.client.start(container3_id)
|
||||
|
||||
info = self.client.inspect_container(res2['Id'])
|
||||
info = self.client.inspect_container(res['Id'])
|
||||
assert len(info['HostConfig']['VolumesFrom']) == len(vol_names)
|
||||
|
||||
def create_container_readonly_fs(self):
|
||||
|
@ -222,7 +218,6 @@ class CreateContainerTest(BaseAPIIntegrationTest):
|
|||
|
||||
self.client.kill(id)
|
||||
|
||||
@requires_api_version('1.20')
|
||||
def test_group_id_ints(self):
|
||||
container = self.client.create_container(
|
||||
BUSYBOX, 'id -G',
|
||||
|
@ -239,7 +234,6 @@ class CreateContainerTest(BaseAPIIntegrationTest):
|
|||
assert '1000' in groups
|
||||
assert '1001' in groups
|
||||
|
||||
@requires_api_version('1.20')
|
||||
def test_group_id_strings(self):
|
||||
container = self.client.create_container(
|
||||
BUSYBOX, 'id -G', host_config=self.client.create_host_config(
|
||||
|
@ -604,24 +598,15 @@ class VolumeBindTest(BaseAPIIntegrationTest):
|
|||
assert mount_data['RW'] is True
|
||||
|
||||
def check_container_data(self, inspect_data, rw):
|
||||
if docker.utils.compare_version('1.20', self.client._version) < 0:
|
||||
assert 'Volumes' in inspect_data
|
||||
assert self.mount_dest in inspect_data['Volumes']
|
||||
assert (
|
||||
self.mount_origin == inspect_data['Volumes'][self.mount_dest]
|
||||
)
|
||||
assert self.mount_dest in inspect_data['VolumesRW']
|
||||
assert not inspect_data['VolumesRW'][self.mount_dest]
|
||||
else:
|
||||
assert 'Mounts' in inspect_data
|
||||
filtered = list(filter(
|
||||
lambda x: x['Destination'] == self.mount_dest,
|
||||
inspect_data['Mounts']
|
||||
))
|
||||
assert len(filtered) == 1
|
||||
mount_data = filtered[0]
|
||||
assert mount_data['Source'] == self.mount_origin
|
||||
assert mount_data['RW'] == rw
|
||||
assert 'Mounts' in inspect_data
|
||||
filtered = list(filter(
|
||||
lambda x: x['Destination'] == self.mount_dest,
|
||||
inspect_data['Mounts']
|
||||
))
|
||||
assert len(filtered) == 1
|
||||
mount_data = filtered[0]
|
||||
assert mount_data['Source'] == self.mount_origin
|
||||
assert mount_data['RW'] == rw
|
||||
|
||||
def run_with_volume(self, ro, *args, **kwargs):
|
||||
return self.run_container(
|
||||
|
@ -640,7 +625,6 @@ class VolumeBindTest(BaseAPIIntegrationTest):
|
|||
)
|
||||
|
||||
|
||||
@requires_api_version('1.20')
|
||||
class ArchiveTest(BaseAPIIntegrationTest):
|
||||
def test_get_file_archive_from_container(self):
|
||||
data = 'The Maid and the Pocket Watch of Blood'
|
||||
|
@ -1323,7 +1307,6 @@ class PruneTest(BaseAPIIntegrationTest):
|
|||
|
||||
|
||||
class GetContainerStatsTest(BaseAPIIntegrationTest):
|
||||
@requires_api_version('1.19')
|
||||
def test_get_container_stats_no_stream(self):
|
||||
container = self.client.create_container(
|
||||
BUSYBOX, ['sleep', '60'],
|
||||
|
@ -1338,7 +1321,6 @@ class GetContainerStatsTest(BaseAPIIntegrationTest):
|
|||
'memory_stats', 'blkio_stats']:
|
||||
assert key in response
|
||||
|
||||
@requires_api_version('1.17')
|
||||
def test_get_container_stats_stream(self):
|
||||
container = self.client.create_container(
|
||||
BUSYBOX, ['sleep', '60'],
|
||||
|
@ -1401,7 +1383,6 @@ class ContainerUpdateTest(BaseAPIIntegrationTest):
|
|||
|
||||
|
||||
class ContainerCPUTest(BaseAPIIntegrationTest):
|
||||
@requires_api_version('1.18')
|
||||
def test_container_cpu_shares(self):
|
||||
cpu_shares = 512
|
||||
container = self.client.create_container(
|
||||
|
@ -1414,7 +1395,6 @@ class ContainerCPUTest(BaseAPIIntegrationTest):
|
|||
inspect_data = self.client.inspect_container(container)
|
||||
assert inspect_data['HostConfig']['CpuShares'] == 512
|
||||
|
||||
@requires_api_version('1.18')
|
||||
def test_container_cpuset(self):
|
||||
cpuset_cpus = "0,1"
|
||||
container = self.client.create_container(
|
||||
|
|
|
@ -17,7 +17,6 @@ class TestNetworks(BaseAPIIntegrationTest):
|
|||
self.tmp_networks.append(net_id)
|
||||
return (net_name, net_id)
|
||||
|
||||
@requires_api_version('1.21')
|
||||
def test_list_networks(self):
|
||||
networks = self.client.networks()
|
||||
|
||||
|
@ -32,7 +31,6 @@ class TestNetworks(BaseAPIIntegrationTest):
|
|||
networks_by_partial_id = self.client.networks(ids=[net_id[:8]])
|
||||
assert [n['Id'] for n in networks_by_partial_id] == [net_id]
|
||||
|
||||
@requires_api_version('1.21')
|
||||
def test_inspect_network(self):
|
||||
net_name, net_id = self.create_network()
|
||||
|
||||
|
@ -43,7 +41,6 @@ class TestNetworks(BaseAPIIntegrationTest):
|
|||
assert net['Scope'] == 'local'
|
||||
assert net['IPAM']['Driver'] == 'default'
|
||||
|
||||
@requires_api_version('1.21')
|
||||
def test_create_network_with_ipam_config(self):
|
||||
_, net_id = self.create_network(
|
||||
ipam=IPAMConfig(
|
||||
|
@ -81,12 +78,10 @@ class TestNetworks(BaseAPIIntegrationTest):
|
|||
},
|
||||
}]
|
||||
|
||||
@requires_api_version('1.21')
|
||||
def test_create_network_with_host_driver_fails(self):
|
||||
with pytest.raises(docker.errors.APIError):
|
||||
self.client.create_network(random_name(), driver='host')
|
||||
|
||||
@requires_api_version('1.21')
|
||||
def test_remove_network(self):
|
||||
net_name, net_id = self.create_network()
|
||||
assert net_name in [n['Name'] for n in self.client.networks()]
|
||||
|
@ -94,7 +89,6 @@ class TestNetworks(BaseAPIIntegrationTest):
|
|||
self.client.remove_network(net_id)
|
||||
assert net_name not in [n['Name'] for n in self.client.networks()]
|
||||
|
||||
@requires_api_version('1.21')
|
||||
def test_connect_and_disconnect_container(self):
|
||||
net_name, net_id = self.create_network()
|
||||
|
||||
|
@ -163,7 +157,6 @@ class TestNetworks(BaseAPIIntegrationTest):
|
|||
assert 'foo' in aliases
|
||||
assert 'bar' in aliases
|
||||
|
||||
@requires_api_version('1.21')
|
||||
def test_connect_on_container_create(self):
|
||||
net_name, net_id = self.create_network()
|
||||
|
||||
|
@ -309,7 +302,6 @@ class TestNetworks(BaseAPIIntegrationTest):
|
|||
|
||||
self.execute(container, ['nslookup', 'bar'])
|
||||
|
||||
@requires_api_version('1.21')
|
||||
def test_create_check_duplicate(self):
|
||||
net_name, net_id = self.create_network()
|
||||
with pytest.raises(docker.errors.APIError):
|
||||
|
@ -475,7 +467,6 @@ class TestNetworks(BaseAPIIntegrationTest):
|
|||
with pytest.raises(docker.errors.NotFound):
|
||||
self.client.inspect_network(net_name_swarm, scope='local')
|
||||
|
||||
@requires_api_version('1.21')
|
||||
def test_create_remove_network_with_space_in_name(self):
|
||||
net_id = self.client.create_network('test 01')
|
||||
self.tmp_networks.append(net_id)
|
||||
|
|
|
@ -5,7 +5,6 @@ from ..helpers import requires_api_version
|
|||
from .base import BaseAPIIntegrationTest
|
||||
|
||||
|
||||
@requires_api_version('1.21')
|
||||
class TestVolumes(BaseAPIIntegrationTest):
|
||||
def test_create_volume(self):
|
||||
name = 'perfectcherryblossom'
|
||||
|
|
|
@ -31,17 +31,6 @@ class BuildTest(BaseAPIClientTest):
|
|||
|
||||
self.client.build(fileobj=script, pull=True)
|
||||
|
||||
def test_build_container_stream(self):
|
||||
script = io.BytesIO('\n'.join([
|
||||
'FROM busybox',
|
||||
'RUN mkdir -p /tmp/test',
|
||||
'EXPOSE 8080',
|
||||
'ADD https://dl.dropboxusercontent.com/u/20637798/silence.tar.gz'
|
||||
' /tmp/silence.tar.gz'
|
||||
]).encode('ascii'))
|
||||
|
||||
self.client.build(fileobj=script, stream=True)
|
||||
|
||||
def test_build_container_custom_context(self):
|
||||
script = io.BytesIO('\n'.join([
|
||||
'FROM busybox',
|
||||
|
|
|
@ -219,24 +219,6 @@ class CreateContainerTest(BaseAPIClientTest):
|
|||
''')
|
||||
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
||||
|
||||
def test_create_container_with_cpu_shares(self):
|
||||
with pytest.deprecated_call():
|
||||
self.client.create_container('busybox', 'ls', cpu_shares=5)
|
||||
|
||||
args = fake_request.call_args
|
||||
assert args[0][1] == url_prefix + 'containers/create'
|
||||
assert json.loads(args[1]['data']) == json.loads('''
|
||||
{"Tty": false, "Image": "busybox",
|
||||
"Cmd": ["ls"], "AttachStdin": false,
|
||||
"AttachStderr": true,
|
||||
"AttachStdout": true, "OpenStdin": false,
|
||||
"StdinOnce": false,
|
||||
"NetworkDisabled": false,
|
||||
"CpuShares": 5}
|
||||
''')
|
||||
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
||||
|
||||
@requires_api_version('1.18')
|
||||
def test_create_container_with_host_config_cpu_shares(self):
|
||||
self.client.create_container(
|
||||
'busybox', 'ls', host_config=self.client.create_host_config(
|
||||
|
@ -261,25 +243,6 @@ class CreateContainerTest(BaseAPIClientTest):
|
|||
''')
|
||||
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
||||
|
||||
def test_create_container_with_cpuset(self):
|
||||
with pytest.deprecated_call():
|
||||
self.client.create_container('busybox', 'ls', cpuset='0,1')
|
||||
|
||||
args = fake_request.call_args
|
||||
assert args[0][1] == url_prefix + 'containers/create'
|
||||
assert json.loads(args[1]['data']) == json.loads('''
|
||||
{"Tty": false, "Image": "busybox",
|
||||
"Cmd": ["ls"], "AttachStdin": false,
|
||||
"AttachStderr": true,
|
||||
"AttachStdout": true, "OpenStdin": false,
|
||||
"StdinOnce": false,
|
||||
"NetworkDisabled": false,
|
||||
"Cpuset": "0,1",
|
||||
"CpusetCpus": "0,1"}
|
||||
''')
|
||||
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
||||
|
||||
@requires_api_version('1.18')
|
||||
def test_create_container_with_host_config_cpuset(self):
|
||||
self.client.create_container(
|
||||
'busybox', 'ls', host_config=self.client.create_host_config(
|
||||
|
@ -304,7 +267,6 @@ class CreateContainerTest(BaseAPIClientTest):
|
|||
''')
|
||||
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
||||
|
||||
@requires_api_version('1.19')
|
||||
def test_create_container_with_host_config_cpuset_mems(self):
|
||||
self.client.create_container(
|
||||
'busybox', 'ls', host_config=self.client.create_host_config(
|
||||
|
@ -374,28 +336,6 @@ class CreateContainerTest(BaseAPIClientTest):
|
|||
''')
|
||||
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
||||
|
||||
def test_create_container_with_volumes_from(self):
|
||||
vol_names = ['foo', 'bar']
|
||||
try:
|
||||
self.client.create_container('busybox', 'true',
|
||||
volumes_from=vol_names)
|
||||
except docker.errors.DockerException:
|
||||
assert docker.utils.compare_version(
|
||||
'1.10', self.client._version
|
||||
) >= 0
|
||||
return
|
||||
|
||||
args = fake_request.call_args
|
||||
assert args[0][1] == url_prefix + 'containers/create'
|
||||
assert json.loads(args[1]['data'])['VolumesFrom'] == ','.join(
|
||||
vol_names
|
||||
)
|
||||
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
||||
|
||||
def test_create_container_empty_volumes_from(self):
|
||||
with pytest.raises(docker.errors.InvalidVersion):
|
||||
self.client.create_container('busybox', 'true', volumes_from=[])
|
||||
|
||||
def test_create_named_container(self):
|
||||
self.client.create_container('busybox', 'true',
|
||||
name='marisa-kirisame')
|
||||
|
|
|
@ -197,26 +197,6 @@ class ImageTest(BaseAPIClientTest):
|
|||
|
||||
assert excinfo.value.args[0] == 'Resource ID was not provided'
|
||||
|
||||
def test_insert_image(self):
|
||||
try:
|
||||
self.client.insert(fake_api.FAKE_IMAGE_NAME,
|
||||
fake_api.FAKE_URL, fake_api.FAKE_PATH)
|
||||
except docker.errors.DeprecatedMethod:
|
||||
assert docker.utils.compare_version(
|
||||
'1.12', self.client._version
|
||||
) >= 0
|
||||
return
|
||||
|
||||
fake_request.assert_called_with(
|
||||
'POST',
|
||||
url_prefix + 'images/test_image/insert',
|
||||
params={
|
||||
'url': fake_api.FAKE_URL,
|
||||
'path': fake_api.FAKE_PATH
|
||||
},
|
||||
timeout=DEFAULT_TIMEOUT_SECONDS
|
||||
)
|
||||
|
||||
def test_push_image(self):
|
||||
with mock.patch('docker.auth.resolve_authconfig',
|
||||
fake_resolve_authconfig):
|
||||
|
|
|
@ -3,7 +3,6 @@ import json
|
|||
import six
|
||||
|
||||
from .api_test import BaseAPIClientTest, url_prefix, response
|
||||
from ..helpers import requires_api_version
|
||||
from docker.types import IPAMConfig, IPAMPool
|
||||
|
||||
try:
|
||||
|
@ -13,7 +12,6 @@ except ImportError:
|
|||
|
||||
|
||||
class NetworkTest(BaseAPIClientTest):
|
||||
@requires_api_version('1.21')
|
||||
def test_list_networks(self):
|
||||
networks = [
|
||||
{
|
||||
|
@ -49,7 +47,6 @@ class NetworkTest(BaseAPIClientTest):
|
|||
filters = json.loads(get.call_args[1]['params']['filters'])
|
||||
assert filters == {'id': ['123']}
|
||||
|
||||
@requires_api_version('1.21')
|
||||
def test_create_network(self):
|
||||
network_data = {
|
||||
"id": 'abc12345',
|
||||
|
@ -98,7 +95,6 @@ class NetworkTest(BaseAPIClientTest):
|
|||
}
|
||||
}
|
||||
|
||||
@requires_api_version('1.21')
|
||||
def test_remove_network(self):
|
||||
network_id = 'abc12345'
|
||||
delete = mock.Mock(return_value=response(status_code=200))
|
||||
|
@ -109,7 +105,6 @@ class NetworkTest(BaseAPIClientTest):
|
|||
args = delete.call_args
|
||||
assert args[0][0] == url_prefix + 'networks/{0}'.format(network_id)
|
||||
|
||||
@requires_api_version('1.21')
|
||||
def test_inspect_network(self):
|
||||
network_id = 'abc12345'
|
||||
network_name = 'foo'
|
||||
|
@ -130,7 +125,6 @@ class NetworkTest(BaseAPIClientTest):
|
|||
args = get.call_args
|
||||
assert args[0][0] == url_prefix + 'networks/{0}'.format(network_id)
|
||||
|
||||
@requires_api_version('1.21')
|
||||
def test_connect_container_to_network(self):
|
||||
network_id = 'abc12345'
|
||||
container_id = 'def45678'
|
||||
|
@ -157,7 +151,6 @@ class NetworkTest(BaseAPIClientTest):
|
|||
},
|
||||
}
|
||||
|
||||
@requires_api_version('1.21')
|
||||
def test_disconnect_container_from_network(self):
|
||||
network_id = 'abc12345'
|
||||
container_id = 'def45678'
|
||||
|
|
|
@ -437,7 +437,6 @@ class StreamTest(unittest.TestCase):
|
|||
try:
|
||||
stream = client.build(
|
||||
path=self.build_context,
|
||||
stream=True
|
||||
)
|
||||
break
|
||||
except requests.ConnectionError as e:
|
||||
|
|
|
@ -7,7 +7,6 @@ from .api_test import BaseAPIClientTest, url_prefix, fake_request
|
|||
|
||||
|
||||
class VolumeTest(BaseAPIClientTest):
|
||||
@requires_api_version('1.21')
|
||||
def test_list_volumes(self):
|
||||
volumes = self.client.volumes()
|
||||
assert 'Volumes' in volumes
|
||||
|
@ -17,7 +16,6 @@ class VolumeTest(BaseAPIClientTest):
|
|||
assert args[0][0] == 'GET'
|
||||
assert args[0][1] == url_prefix + 'volumes'
|
||||
|
||||
@requires_api_version('1.21')
|
||||
def test_list_volumes_and_filters(self):
|
||||
volumes = self.client.volumes(filters={'dangling': True})
|
||||
assert 'Volumes' in volumes
|
||||
|
@ -29,7 +27,6 @@ class VolumeTest(BaseAPIClientTest):
|
|||
assert args[1] == {'params': {'filters': '{"dangling": ["true"]}'},
|
||||
'timeout': 60}
|
||||
|
||||
@requires_api_version('1.21')
|
||||
def test_create_volume(self):
|
||||
name = 'perfectcherryblossom'
|
||||
result = self.client.create_volume(name)
|
||||
|
@ -59,7 +56,6 @@ class VolumeTest(BaseAPIClientTest):
|
|||
with pytest.raises(TypeError):
|
||||
self.client.create_volume(name, labels=1)
|
||||
|
||||
@requires_api_version('1.21')
|
||||
def test_create_volume_with_driver(self):
|
||||
name = 'perfectcherryblossom'
|
||||
driver_name = 'sshfs'
|
||||
|
@ -72,7 +68,6 @@ class VolumeTest(BaseAPIClientTest):
|
|||
assert 'Driver' in data
|
||||
assert data['Driver'] == driver_name
|
||||
|
||||
@requires_api_version('1.21')
|
||||
def test_create_volume_invalid_opts_type(self):
|
||||
with pytest.raises(TypeError):
|
||||
self.client.create_volume(
|
||||
|
@ -99,7 +94,6 @@ class VolumeTest(BaseAPIClientTest):
|
|||
assert 'Scope' in result
|
||||
assert result['Scope'] == 'local'
|
||||
|
||||
@requires_api_version('1.21')
|
||||
def test_inspect_volume(self):
|
||||
name = 'perfectcherryblossom'
|
||||
result = self.client.inspect_volume(name)
|
||||
|
@ -112,7 +106,6 @@ class VolumeTest(BaseAPIClientTest):
|
|||
assert args[0][0] == 'GET'
|
||||
assert args[0][1] == '{0}volumes/{1}'.format(url_prefix, name)
|
||||
|
||||
@requires_api_version('1.21')
|
||||
def test_remove_volume(self):
|
||||
name = 'perfectcherryblossom'
|
||||
self.client.remove_volume(name)
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import unittest
|
||||
import warnings
|
||||
|
||||
import pytest
|
||||
|
||||
from docker.constants import DEFAULT_DOCKER_API_VERSION
|
||||
from docker.errors import InvalidArgument, InvalidVersion
|
||||
from docker.types import (
|
||||
ContainerConfig, ContainerSpec, EndpointConfig, HostConfig, IPAMConfig,
|
||||
ContainerSpec, EndpointConfig, HostConfig, IPAMConfig,
|
||||
IPAMPool, LogConfig, Mount, ServiceMode, Ulimit,
|
||||
)
|
||||
from docker.types.services import convert_service_ports
|
||||
|
@ -24,33 +23,29 @@ def create_host_config(*args, **kwargs):
|
|||
|
||||
|
||||
class HostConfigTest(unittest.TestCase):
|
||||
def test_create_host_config_no_options(self):
|
||||
config = create_host_config(version='1.19')
|
||||
assert not ('NetworkMode' in config)
|
||||
|
||||
def test_create_host_config_no_options_newer_api_version(self):
|
||||
config = create_host_config(version='1.20')
|
||||
config = create_host_config(version='1.21')
|
||||
assert config['NetworkMode'] == 'default'
|
||||
|
||||
def test_create_host_config_invalid_cpu_cfs_types(self):
|
||||
with pytest.raises(TypeError):
|
||||
create_host_config(version='1.20', cpu_quota='0')
|
||||
create_host_config(version='1.21', cpu_quota='0')
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
create_host_config(version='1.20', cpu_period='0')
|
||||
create_host_config(version='1.21', cpu_period='0')
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
create_host_config(version='1.20', cpu_quota=23.11)
|
||||
create_host_config(version='1.21', cpu_quota=23.11)
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
create_host_config(version='1.20', cpu_period=1999.0)
|
||||
create_host_config(version='1.21', cpu_period=1999.0)
|
||||
|
||||
def test_create_host_config_with_cpu_quota(self):
|
||||
config = create_host_config(version='1.20', cpu_quota=1999)
|
||||
config = create_host_config(version='1.21', cpu_quota=1999)
|
||||
assert config.get('CpuQuota') == 1999
|
||||
|
||||
def test_create_host_config_with_cpu_period(self):
|
||||
config = create_host_config(version='1.20', cpu_period=1999)
|
||||
config = create_host_config(version='1.21', cpu_period=1999)
|
||||
assert config.get('CpuPeriod') == 1999
|
||||
|
||||
def test_create_host_config_with_blkio_constraints(self):
|
||||
|
@ -79,10 +74,8 @@ class HostConfigTest(unittest.TestCase):
|
|||
assert config.get('ShmSize') == 67108864
|
||||
|
||||
def test_create_host_config_with_oom_kill_disable(self):
|
||||
config = create_host_config(version='1.20', oom_kill_disable=True)
|
||||
config = create_host_config(version='1.21', oom_kill_disable=True)
|
||||
assert config.get('OomKillDisable') is True
|
||||
with pytest.raises(InvalidVersion):
|
||||
create_host_config(version='1.18.3', oom_kill_disable=True)
|
||||
|
||||
def test_create_host_config_with_userns_mode(self):
|
||||
config = create_host_config(version='1.23', userns_mode='host')
|
||||
|
@ -109,20 +102,13 @@ class HostConfigTest(unittest.TestCase):
|
|||
assert 'use-vc' in dns_opts
|
||||
assert 'no-tld-query' in dns_opts
|
||||
|
||||
with pytest.raises(InvalidVersion):
|
||||
create_host_config(version='1.20', dns_opt=tested_opts)
|
||||
|
||||
def test_create_host_config_with_mem_reservation(self):
|
||||
config = create_host_config(version='1.21', mem_reservation=67108864)
|
||||
assert config.get('MemoryReservation') == 67108864
|
||||
with pytest.raises(InvalidVersion):
|
||||
create_host_config(version='1.20', mem_reservation=67108864)
|
||||
|
||||
def test_create_host_config_with_kernel_memory(self):
|
||||
config = create_host_config(version='1.21', kernel_memory=67108864)
|
||||
assert config.get('KernelMemory') == 67108864
|
||||
with pytest.raises(InvalidVersion):
|
||||
create_host_config(version='1.20', kernel_memory=67108864)
|
||||
|
||||
def test_create_host_config_with_pids_limit(self):
|
||||
config = create_host_config(version='1.23', pids_limit=1024)
|
||||
|
@ -158,9 +144,6 @@ class HostConfigTest(unittest.TestCase):
|
|||
create_host_config(version='1.24', mem_swappiness='40')
|
||||
|
||||
def test_create_host_config_with_volume_driver(self):
|
||||
with pytest.raises(InvalidVersion):
|
||||
create_host_config(version='1.20', volume_driver='local')
|
||||
|
||||
config = create_host_config(version='1.21', volume_driver='local')
|
||||
assert config.get('VolumeDriver') == 'local'
|
||||
|
||||
|
@ -215,19 +198,6 @@ class HostConfigTest(unittest.TestCase):
|
|||
create_host_config(version='1.24', cpu_rt_runtime=1000)
|
||||
|
||||
|
||||
class ContainerConfigTest(unittest.TestCase):
|
||||
def test_create_container_config_volume_driver_warning(self):
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter('always')
|
||||
ContainerConfig(
|
||||
version='1.21', image='scratch', command=None,
|
||||
volume_driver='local'
|
||||
)
|
||||
|
||||
assert len(w) == 1
|
||||
assert 'The volume_driver option has been moved' in str(w[0].message)
|
||||
|
||||
|
||||
class ContainerSpecTest(unittest.TestCase):
|
||||
def test_parse_mounts(self):
|
||||
spec = ContainerSpec(
|
||||
|
|
|
@ -21,21 +21,36 @@ FAKE_NODE_ID = '24ifsmvkjbyhk'
|
|||
# for clarity and readability
|
||||
|
||||
|
||||
def get_fake_raw_version():
|
||||
status_code = 200
|
||||
response = {
|
||||
"ApiVersion": "1.18",
|
||||
"GitCommit": "fake-commit",
|
||||
"GoVersion": "go1.3.3",
|
||||
"Version": "1.5.0"
|
||||
}
|
||||
return status_code, response
|
||||
|
||||
|
||||
def get_fake_version():
|
||||
status_code = 200
|
||||
response = {'GoVersion': '1', 'Version': '1.1.1',
|
||||
'GitCommit': 'deadbeef+CHANGES'}
|
||||
response = {
|
||||
'ApiVersion': '1.35',
|
||||
'Arch': 'amd64',
|
||||
'BuildTime': '2018-01-10T20:09:37.000000000+00:00',
|
||||
'Components': [{
|
||||
'Details': {
|
||||
'ApiVersion': '1.35',
|
||||
'Arch': 'amd64',
|
||||
'BuildTime': '2018-01-10T20:09:37.000000000+00:00',
|
||||
'Experimental': 'false',
|
||||
'GitCommit': '03596f5',
|
||||
'GoVersion': 'go1.9.2',
|
||||
'KernelVersion': '4.4.0-112-generic',
|
||||
'MinAPIVersion': '1.12',
|
||||
'Os': 'linux'
|
||||
},
|
||||
'Name': 'Engine',
|
||||
'Version': '18.01.0-ce'
|
||||
}],
|
||||
'GitCommit': '03596f5',
|
||||
'GoVersion': 'go1.9.2',
|
||||
'KernelVersion': '4.4.0-112-generic',
|
||||
'MinAPIVersion': '1.12',
|
||||
'Os': 'linux',
|
||||
'Platform': {'Name': ''},
|
||||
'Version': '18.01.0-ce'
|
||||
}
|
||||
|
||||
return status_code, response
|
||||
|
||||
|
||||
|
@ -503,7 +518,7 @@ if constants.IS_WINDOWS_PLATFORM:
|
|||
|
||||
fake_responses = {
|
||||
'{0}/version'.format(prefix):
|
||||
get_fake_raw_version,
|
||||
get_fake_version,
|
||||
'{1}/{0}/version'.format(CURRENT_VERSION, prefix):
|
||||
get_fake_version,
|
||||
'{1}/{0}/info'.format(CURRENT_VERSION, prefix):
|
||||
|
|
Loading…
Reference in New Issue