|  | @@ -1,860 +0,0 @@
 | 
	
		
			
				|  |  | -# Copyright 2013 dotCloud inc.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#    Licensed under the Apache License, Version 2.0 (the "License");
 | 
	
		
			
				|  |  | -#    you may not use this file except in compliance with the License.
 | 
	
		
			
				|  |  | -#    You may obtain a copy of the License at
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#        http://www.apache.org/licenses/LICENSE-2.0
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#    Unless required by applicable law or agreed to in writing, software
 | 
	
		
			
				|  |  | -#    distributed under the License is distributed on an "AS IS" BASIS,
 | 
	
		
			
				|  |  | -#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
	
		
			
				|  |  | -#    See the License for the specific language governing permissions and
 | 
	
		
			
				|  |  | -#    limitations under the License.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -import json
 | 
	
		
			
				|  |  | -import re
 | 
	
		
			
				|  |  | -import shlex
 | 
	
		
			
				|  |  | -import struct
 | 
	
		
			
				|  |  | -import warnings
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -import requests
 | 
	
		
			
				|  |  | -import requests.exceptions
 | 
	
		
			
				|  |  | -from fig.packages import six
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -from .auth import auth
 | 
	
		
			
				|  |  | -from .unixconn import unixconn
 | 
	
		
			
				|  |  | -from .utils import utils
 | 
	
		
			
				|  |  | -from . import errors
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -if not six.PY3:
 | 
	
		
			
				|  |  | -    import websocket
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -DEFAULT_DOCKER_API_VERSION = '1.12'
 | 
	
		
			
				|  |  | -DEFAULT_TIMEOUT_SECONDS = 60
 | 
	
		
			
				|  |  | -STREAM_HEADER_SIZE_BYTES = 8
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -class Client(requests.Session):
 | 
	
		
			
				|  |  | -    def __init__(self, base_url=None, version=DEFAULT_DOCKER_API_VERSION,
 | 
	
		
			
				|  |  | -                 timeout=DEFAULT_TIMEOUT_SECONDS):
 | 
	
		
			
				|  |  | -        super(Client, self).__init__()
 | 
	
		
			
				|  |  | -        if base_url is None:
 | 
	
		
			
				|  |  | -            base_url = "http+unix://var/run/docker.sock"
 | 
	
		
			
				|  |  | -        if 'unix:///' in base_url:
 | 
	
		
			
				|  |  | -            base_url = base_url.replace('unix:/', 'unix:')
 | 
	
		
			
				|  |  | -        if base_url.startswith('unix:'):
 | 
	
		
			
				|  |  | -            base_url = "http+" + base_url
 | 
	
		
			
				|  |  | -        if base_url.startswith('tcp:'):
 | 
	
		
			
				|  |  | -            base_url = base_url.replace('tcp:', 'http:')
 | 
	
		
			
				|  |  | -        if base_url.endswith('/'):
 | 
	
		
			
				|  |  | -            base_url = base_url[:-1]
 | 
	
		
			
				|  |  | -        self.base_url = base_url
 | 
	
		
			
				|  |  | -        self._version = version
 | 
	
		
			
				|  |  | -        self._timeout = timeout
 | 
	
		
			
				|  |  | -        self._auth_configs = auth.load_config()
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        self.mount('http+unix://', unixconn.UnixAdapter(base_url, timeout))
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def _set_request_timeout(self, kwargs):
 | 
	
		
			
				|  |  | -        """Prepare the kwargs for an HTTP request by inserting the timeout
 | 
	
		
			
				|  |  | -        parameter, if not already present."""
 | 
	
		
			
				|  |  | -        kwargs.setdefault('timeout', self._timeout)
 | 
	
		
			
				|  |  | -        return kwargs
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def _post(self, url, **kwargs):
 | 
	
		
			
				|  |  | -        return self.post(url, **self._set_request_timeout(kwargs))
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def _get(self, url, **kwargs):
 | 
	
		
			
				|  |  | -        return self.get(url, **self._set_request_timeout(kwargs))
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def _delete(self, url, **kwargs):
 | 
	
		
			
				|  |  | -        return self.delete(url, **self._set_request_timeout(kwargs))
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def _url(self, path):
 | 
	
		
			
				|  |  | -        return '{0}/v{1}{2}'.format(self.base_url, self._version, path)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def _raise_for_status(self, response, explanation=None):
 | 
	
		
			
				|  |  | -        """Raises stored :class:`APIError`, if one occurred."""
 | 
	
		
			
				|  |  | -        try:
 | 
	
		
			
				|  |  | -            response.raise_for_status()
 | 
	
		
			
				|  |  | -        except requests.exceptions.HTTPError as e:
 | 
	
		
			
				|  |  | -            raise errors.APIError(e, response, explanation=explanation)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def _result(self, response, json=False, binary=False):
 | 
	
		
			
				|  |  | -        assert not (json and binary)
 | 
	
		
			
				|  |  | -        self._raise_for_status(response)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if json:
 | 
	
		
			
				|  |  | -            return response.json()
 | 
	
		
			
				|  |  | -        if binary:
 | 
	
		
			
				|  |  | -            return response.content
 | 
	
		
			
				|  |  | -        return response.text
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def _container_config(self, image, command, hostname=None, user=None,
 | 
	
		
			
				|  |  | -                          detach=False, stdin_open=False, tty=False,
 | 
	
		
			
				|  |  | -                          mem_limit=0, ports=None, environment=None, dns=None,
 | 
	
		
			
				|  |  | -                          volumes=None, volumes_from=None,
 | 
	
		
			
				|  |  | -                          network_disabled=False, entrypoint=None,
 | 
	
		
			
				|  |  | -                          cpu_shares=None, working_dir=None, domainname=None,
 | 
	
		
			
				|  |  | -                          memswap_limit=0):
 | 
	
		
			
				|  |  | -        if isinstance(command, six.string_types):
 | 
	
		
			
				|  |  | -            command = shlex.split(str(command))
 | 
	
		
			
				|  |  | -        if isinstance(environment, dict):
 | 
	
		
			
				|  |  | -            environment = [
 | 
	
		
			
				|  |  | -                '{0}={1}'.format(k, v) for k, v in environment.items()
 | 
	
		
			
				|  |  | -            ]
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if isinstance(ports, list):
 | 
	
		
			
				|  |  | -            exposed_ports = {}
 | 
	
		
			
				|  |  | -            for port_definition in ports:
 | 
	
		
			
				|  |  | -                port = port_definition
 | 
	
		
			
				|  |  | -                proto = 'tcp'
 | 
	
		
			
				|  |  | -                if isinstance(port_definition, tuple):
 | 
	
		
			
				|  |  | -                    if len(port_definition) == 2:
 | 
	
		
			
				|  |  | -                        proto = port_definition[1]
 | 
	
		
			
				|  |  | -                    port = port_definition[0]
 | 
	
		
			
				|  |  | -                exposed_ports['{0}/{1}'.format(port, proto)] = {}
 | 
	
		
			
				|  |  | -            ports = exposed_ports
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if isinstance(volumes, list):
 | 
	
		
			
				|  |  | -            volumes_dict = {}
 | 
	
		
			
				|  |  | -            for vol in volumes:
 | 
	
		
			
				|  |  | -                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
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        attach_stdin = False
 | 
	
		
			
				|  |  | -        attach_stdout = False
 | 
	
		
			
				|  |  | -        attach_stderr = False
 | 
	
		
			
				|  |  | -        stdin_once = False
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if not detach:
 | 
	
		
			
				|  |  | -            attach_stdout = True
 | 
	
		
			
				|  |  | -            attach_stderr = True
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            if stdin_open:
 | 
	
		
			
				|  |  | -                attach_stdin = True
 | 
	
		
			
				|  |  | -                stdin_once = True
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if utils.compare_version('1.10', self._version) >= 0:
 | 
	
		
			
				|  |  | -            message = ('{0!r} parameter has no effect on create_container().'
 | 
	
		
			
				|  |  | -                       ' It has been moved to start()')
 | 
	
		
			
				|  |  | -            if dns is not None:
 | 
	
		
			
				|  |  | -                raise errors.DockerException(message.format('dns'))
 | 
	
		
			
				|  |  | -            if volumes_from is not None:
 | 
	
		
			
				|  |  | -                raise errors.DockerException(message.format('volumes_from'))
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        return {
 | 
	
		
			
				|  |  | -            'Hostname': hostname,
 | 
	
		
			
				|  |  | -            'Domainname': domainname,
 | 
	
		
			
				|  |  | -            'ExposedPorts': ports,
 | 
	
		
			
				|  |  | -            'User': user,
 | 
	
		
			
				|  |  | -            '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,
 | 
	
		
			
				|  |  | -            'WorkingDir': working_dir,
 | 
	
		
			
				|  |  | -            'MemorySwap': memswap_limit
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def _post_json(self, url, data, **kwargs):
 | 
	
		
			
				|  |  | -        # Go <1.1 can't unserialize null to a string
 | 
	
		
			
				|  |  | -        # so we do this disgusting thing here.
 | 
	
		
			
				|  |  | -        data2 = {}
 | 
	
		
			
				|  |  | -        if data is not None:
 | 
	
		
			
				|  |  | -            for k, v in six.iteritems(data):
 | 
	
		
			
				|  |  | -                if v is not None:
 | 
	
		
			
				|  |  | -                    data2[k] = v
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if 'headers' not in kwargs:
 | 
	
		
			
				|  |  | -            kwargs['headers'] = {}
 | 
	
		
			
				|  |  | -        kwargs['headers']['Content-Type'] = 'application/json'
 | 
	
		
			
				|  |  | -        return self._post(url, data=json.dumps(data2), **kwargs)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def _attach_params(self, override=None):
 | 
	
		
			
				|  |  | -        return override or {
 | 
	
		
			
				|  |  | -            'stdout': 1,
 | 
	
		
			
				|  |  | -            'stderr': 1,
 | 
	
		
			
				|  |  | -            'stream': 1
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def _attach_websocket(self, container, params=None):
 | 
	
		
			
				|  |  | -        if six.PY3:
 | 
	
		
			
				|  |  | -            raise NotImplementedError("This method is not currently supported "
 | 
	
		
			
				|  |  | -                                      "under python 3")
 | 
	
		
			
				|  |  | -        url = self._url("/containers/{0}/attach/ws".format(container))
 | 
	
		
			
				|  |  | -        req = requests.Request("POST", url, params=self._attach_params(params))
 | 
	
		
			
				|  |  | -        full_url = req.prepare().url
 | 
	
		
			
				|  |  | -        full_url = full_url.replace("http://", "ws://", 1)
 | 
	
		
			
				|  |  | -        full_url = full_url.replace("https://", "wss://", 1)
 | 
	
		
			
				|  |  | -        return self._create_websocket_connection(full_url)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def _create_websocket_connection(self, url):
 | 
	
		
			
				|  |  | -        return websocket.create_connection(url)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def _get_raw_response_socket(self, response):
 | 
	
		
			
				|  |  | -        self._raise_for_status(response)
 | 
	
		
			
				|  |  | -        if six.PY3:
 | 
	
		
			
				|  |  | -            return response.raw._fp.fp.raw._sock
 | 
	
		
			
				|  |  | -        else:
 | 
	
		
			
				|  |  | -            return response.raw._fp.fp._sock
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def _stream_helper(self, response):
 | 
	
		
			
				|  |  | -        """Generator for data coming from a chunked-encoded HTTP response."""
 | 
	
		
			
				|  |  | -        socket_fp = self._get_raw_response_socket(response)
 | 
	
		
			
				|  |  | -        socket_fp.setblocking(1)
 | 
	
		
			
				|  |  | -        socket = socket_fp.makefile()
 | 
	
		
			
				|  |  | -        while True:
 | 
	
		
			
				|  |  | -            # Because Docker introduced newlines at the end of chunks in v0.9,
 | 
	
		
			
				|  |  | -            # and only on some API endpoints, we have to cater for both cases.
 | 
	
		
			
				|  |  | -            size_line = socket.readline()
 | 
	
		
			
				|  |  | -            if size_line == '\r\n':
 | 
	
		
			
				|  |  | -                size_line = socket.readline()
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            size = int(size_line, 16)
 | 
	
		
			
				|  |  | -            if size <= 0:
 | 
	
		
			
				|  |  | -                break
 | 
	
		
			
				|  |  | -            data = socket.readline()
 | 
	
		
			
				|  |  | -            if not data:
 | 
	
		
			
				|  |  | -                break
 | 
	
		
			
				|  |  | -            yield data
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def _multiplexed_buffer_helper(self, response):
 | 
	
		
			
				|  |  | -        """A generator of multiplexed data blocks read from a buffered
 | 
	
		
			
				|  |  | -        response."""
 | 
	
		
			
				|  |  | -        buf = self._result(response, binary=True)
 | 
	
		
			
				|  |  | -        walker = 0
 | 
	
		
			
				|  |  | -        while True:
 | 
	
		
			
				|  |  | -            if len(buf[walker:]) < 8:
 | 
	
		
			
				|  |  | -                break
 | 
	
		
			
				|  |  | -            _, length = struct.unpack_from('>BxxxL', buf[walker:])
 | 
	
		
			
				|  |  | -            start = walker + STREAM_HEADER_SIZE_BYTES
 | 
	
		
			
				|  |  | -            end = start + length
 | 
	
		
			
				|  |  | -            walker = end
 | 
	
		
			
				|  |  | -            yield buf[start:end]
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def _multiplexed_socket_stream_helper(self, response):
 | 
	
		
			
				|  |  | -        """A generator of multiplexed data blocks coming from a response
 | 
	
		
			
				|  |  | -        socket."""
 | 
	
		
			
				|  |  | -        socket = self._get_raw_response_socket(response)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        def recvall(socket, size):
 | 
	
		
			
				|  |  | -            blocks = []
 | 
	
		
			
				|  |  | -            while size > 0:
 | 
	
		
			
				|  |  | -                block = socket.recv(size)
 | 
	
		
			
				|  |  | -                if not block:
 | 
	
		
			
				|  |  | -                    return None
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                blocks.append(block)
 | 
	
		
			
				|  |  | -                size -= len(block)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            sep = bytes() if six.PY3 else str()
 | 
	
		
			
				|  |  | -            data = sep.join(blocks)
 | 
	
		
			
				|  |  | -            return data
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        while True:
 | 
	
		
			
				|  |  | -            socket.settimeout(None)
 | 
	
		
			
				|  |  | -            header = recvall(socket, STREAM_HEADER_SIZE_BYTES)
 | 
	
		
			
				|  |  | -            if not header:
 | 
	
		
			
				|  |  | -                break
 | 
	
		
			
				|  |  | -            _, length = struct.unpack('>BxxxL', header)
 | 
	
		
			
				|  |  | -            if not length:
 | 
	
		
			
				|  |  | -                break
 | 
	
		
			
				|  |  | -            data = recvall(socket, length)
 | 
	
		
			
				|  |  | -            if not data:
 | 
	
		
			
				|  |  | -                break
 | 
	
		
			
				|  |  | -            yield data
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def attach(self, container, stdout=True, stderr=True,
 | 
	
		
			
				|  |  | -               stream=False, logs=False):
 | 
	
		
			
				|  |  | -        if isinstance(container, dict):
 | 
	
		
			
				|  |  | -            container = container.get('Id')
 | 
	
		
			
				|  |  | -        params = {
 | 
	
		
			
				|  |  | -            'logs': logs and 1 or 0,
 | 
	
		
			
				|  |  | -            'stdout': stdout and 1 or 0,
 | 
	
		
			
				|  |  | -            'stderr': stderr and 1 or 0,
 | 
	
		
			
				|  |  | -            'stream': stream and 1 or 0,
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        u = self._url("/containers/{0}/attach".format(container))
 | 
	
		
			
				|  |  | -        response = self._post(u, params=params, stream=stream)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        # 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:
 | 
	
		
			
				|  |  | -            def stream_result():
 | 
	
		
			
				|  |  | -                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
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            return stream_result() if stream else \
 | 
	
		
			
				|  |  | -                self._result(response, binary=True)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        sep = bytes() if six.PY3 else str()
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        return stream and self._multiplexed_socket_stream_helper(response) or \
 | 
	
		
			
				|  |  | -            sep.join([x for x in self._multiplexed_buffer_helper(response)])
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def attach_socket(self, container, params=None, ws=False):
 | 
	
		
			
				|  |  | -        if params is None:
 | 
	
		
			
				|  |  | -            params = {
 | 
	
		
			
				|  |  | -                'stdout': 1,
 | 
	
		
			
				|  |  | -                'stderr': 1,
 | 
	
		
			
				|  |  | -                'stream': 1
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if ws:
 | 
	
		
			
				|  |  | -            return self._attach_websocket(container, params)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if isinstance(container, dict):
 | 
	
		
			
				|  |  | -            container = container.get('Id')
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        u = self._url("/containers/{0}/attach".format(container))
 | 
	
		
			
				|  |  | -        return self._get_raw_response_socket(self.post(
 | 
	
		
			
				|  |  | -            u, None, params=self._attach_params(params), stream=True))
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def build(self, path=None, tag=None, quiet=False, fileobj=None,
 | 
	
		
			
				|  |  | -              nocache=False, rm=False, stream=False, timeout=None,
 | 
	
		
			
				|  |  | -              custom_context=False, encoding=None):
 | 
	
		
			
				|  |  | -        remote = context = headers = None
 | 
	
		
			
				|  |  | -        if path is None and fileobj is None:
 | 
	
		
			
				|  |  | -            raise TypeError("Either path or fileobj needs to be provided.")
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if custom_context:
 | 
	
		
			
				|  |  | -            if not fileobj:
 | 
	
		
			
				|  |  | -                raise TypeError("You must specify fileobj with custom_context")
 | 
	
		
			
				|  |  | -            context = fileobj
 | 
	
		
			
				|  |  | -        elif fileobj is not None:
 | 
	
		
			
				|  |  | -            context = utils.mkbuildcontext(fileobj)
 | 
	
		
			
				|  |  | -        elif path.startswith(('http://', 'https://',
 | 
	
		
			
				|  |  | -                              'git://', 'github.com/')):
 | 
	
		
			
				|  |  | -            remote = path
 | 
	
		
			
				|  |  | -        else:
 | 
	
		
			
				|  |  | -            context = utils.tar(path)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if utils.compare_version('1.8', self._version) >= 0:
 | 
	
		
			
				|  |  | -            stream = True
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        u = self._url('/build')
 | 
	
		
			
				|  |  | -        params = {
 | 
	
		
			
				|  |  | -            't': tag,
 | 
	
		
			
				|  |  | -            'remote': remote,
 | 
	
		
			
				|  |  | -            'q': quiet,
 | 
	
		
			
				|  |  | -            'nocache': nocache,
 | 
	
		
			
				|  |  | -            'rm': rm
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if context is not None:
 | 
	
		
			
				|  |  | -            headers = {'Content-Type': 'application/tar'}
 | 
	
		
			
				|  |  | -            if encoding:
 | 
	
		
			
				|  |  | -                headers['Content-Encoding'] = encoding
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if utils.compare_version('1.9', self._version) >= 0:
 | 
	
		
			
				|  |  | -            # If we don't have any auth data so far, try reloading the config
 | 
	
		
			
				|  |  | -            # file one more time in case anything showed up in there.
 | 
	
		
			
				|  |  | -            if not self._auth_configs:
 | 
	
		
			
				|  |  | -                self._auth_configs = auth.load_config()
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            # Send the full auth configuration (if any exists), since the build
 | 
	
		
			
				|  |  | -            # could use any (or all) of the registries.
 | 
	
		
			
				|  |  | -            if self._auth_configs:
 | 
	
		
			
				|  |  | -                headers['X-Registry-Config'] = auth.encode_full_header(
 | 
	
		
			
				|  |  | -                    self._auth_configs
 | 
	
		
			
				|  |  | -                )
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        response = self._post(
 | 
	
		
			
				|  |  | -            u,
 | 
	
		
			
				|  |  | -            data=context,
 | 
	
		
			
				|  |  | -            params=params,
 | 
	
		
			
				|  |  | -            headers=headers,
 | 
	
		
			
				|  |  | -            stream=stream,
 | 
	
		
			
				|  |  | -            timeout=timeout,
 | 
	
		
			
				|  |  | -        )
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if context is not None:
 | 
	
		
			
				|  |  | -            context.close()
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if stream:
 | 
	
		
			
				|  |  | -            return self._stream_helper(response)
 | 
	
		
			
				|  |  | -        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
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def commit(self, container, repository=None, tag=None, message=None,
 | 
	
		
			
				|  |  | -               author=None, conf=None):
 | 
	
		
			
				|  |  | -        params = {
 | 
	
		
			
				|  |  | -            'container': container,
 | 
	
		
			
				|  |  | -            'repo': repository,
 | 
	
		
			
				|  |  | -            'tag': tag,
 | 
	
		
			
				|  |  | -            'comment': message,
 | 
	
		
			
				|  |  | -            'author': author
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        u = self._url("/commit")
 | 
	
		
			
				|  |  | -        return self._result(self._post_json(u, data=conf, params=params),
 | 
	
		
			
				|  |  | -                            json=True)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def containers(self, quiet=False, all=False, trunc=True, latest=False,
 | 
	
		
			
				|  |  | -                   since=None, before=None, limit=-1, size=False):
 | 
	
		
			
				|  |  | -        params = {
 | 
	
		
			
				|  |  | -            'limit': 1 if latest else limit,
 | 
	
		
			
				|  |  | -            'all': 1 if all else 0,
 | 
	
		
			
				|  |  | -            'size': 1 if size else 0,
 | 
	
		
			
				|  |  | -            'trunc_cmd': 1 if trunc else 0,
 | 
	
		
			
				|  |  | -            'since': since,
 | 
	
		
			
				|  |  | -            'before': before
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        u = self._url("/containers/json")
 | 
	
		
			
				|  |  | -        res = self._result(self._get(u, params=params), True)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if quiet:
 | 
	
		
			
				|  |  | -            return [{'Id': x['Id']} for x in res]
 | 
	
		
			
				|  |  | -        return res
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def copy(self, container, resource):
 | 
	
		
			
				|  |  | -        if isinstance(container, dict):
 | 
	
		
			
				|  |  | -            container = container.get('Id')
 | 
	
		
			
				|  |  | -        res = self._post_json(
 | 
	
		
			
				|  |  | -            self._url("/containers/{0}/copy".format(container)),
 | 
	
		
			
				|  |  | -            data={"Resource": resource},
 | 
	
		
			
				|  |  | -            stream=True
 | 
	
		
			
				|  |  | -        )
 | 
	
		
			
				|  |  | -        self._raise_for_status(res)
 | 
	
		
			
				|  |  | -        return res.raw
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def create_container(self, image, command=None, hostname=None, user=None,
 | 
	
		
			
				|  |  | -                         detach=False, stdin_open=False, tty=False,
 | 
	
		
			
				|  |  | -                         mem_limit=0, ports=None, environment=None, dns=None,
 | 
	
		
			
				|  |  | -                         volumes=None, volumes_from=None,
 | 
	
		
			
				|  |  | -                         network_disabled=False, name=None, entrypoint=None,
 | 
	
		
			
				|  |  | -                         cpu_shares=None, working_dir=None, domainname=None,
 | 
	
		
			
				|  |  | -                         memswap_limit=0):
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        config = self._container_config(
 | 
	
		
			
				|  |  | -            image, command, hostname, user, detach, stdin_open, tty, mem_limit,
 | 
	
		
			
				|  |  | -            ports, environment, dns, volumes, volumes_from, network_disabled,
 | 
	
		
			
				|  |  | -            entrypoint, cpu_shares, working_dir, domainname, memswap_limit
 | 
	
		
			
				|  |  | -        )
 | 
	
		
			
				|  |  | -        return self.create_container_from_config(config, name)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def create_container_from_config(self, config, name=None):
 | 
	
		
			
				|  |  | -        u = self._url("/containers/create")
 | 
	
		
			
				|  |  | -        params = {
 | 
	
		
			
				|  |  | -            'name': name
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        res = self._post_json(u, data=config, params=params)
 | 
	
		
			
				|  |  | -        return self._result(res, True)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def diff(self, container):
 | 
	
		
			
				|  |  | -        if isinstance(container, dict):
 | 
	
		
			
				|  |  | -            container = container.get('Id')
 | 
	
		
			
				|  |  | -        return self._result(self._get(self._url("/containers/{0}/changes".
 | 
	
		
			
				|  |  | -                            format(container))), True)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def events(self):
 | 
	
		
			
				|  |  | -        return self._stream_helper(self.get(self._url('/events'), stream=True))
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def export(self, container):
 | 
	
		
			
				|  |  | -        if isinstance(container, dict):
 | 
	
		
			
				|  |  | -            container = container.get('Id')
 | 
	
		
			
				|  |  | -        res = self._get(self._url("/containers/{0}/export".format(container)),
 | 
	
		
			
				|  |  | -                        stream=True)
 | 
	
		
			
				|  |  | -        self._raise_for_status(res)
 | 
	
		
			
				|  |  | -        return res.raw
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def get_image(self, image):
 | 
	
		
			
				|  |  | -        res = self._get(self._url("/images/{0}/get".format(image)),
 | 
	
		
			
				|  |  | -                        stream=True)
 | 
	
		
			
				|  |  | -        self._raise_for_status(res)
 | 
	
		
			
				|  |  | -        return res.raw
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def history(self, image):
 | 
	
		
			
				|  |  | -        res = self._get(self._url("/images/{0}/history".format(image)))
 | 
	
		
			
				|  |  | -        self._raise_for_status(res)
 | 
	
		
			
				|  |  | -        return self._result(res)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def images(self, name=None, quiet=False, all=False, viz=False):
 | 
	
		
			
				|  |  | -        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,
 | 
	
		
			
				|  |  | -            'all': 1 if all else 0,
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        res = self._result(self._get(self._url("/images/json"), params=params),
 | 
	
		
			
				|  |  | -                           True)
 | 
	
		
			
				|  |  | -        if quiet:
 | 
	
		
			
				|  |  | -            return [x['Id'] for x in res]
 | 
	
		
			
				|  |  | -        return res
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def import_image(self, src=None, repository=None, tag=None, image=None):
 | 
	
		
			
				|  |  | -        u = self._url("/images/create")
 | 
	
		
			
				|  |  | -        params = {
 | 
	
		
			
				|  |  | -            'repo': repository,
 | 
	
		
			
				|  |  | -            'tag': tag
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if src:
 | 
	
		
			
				|  |  | -            try:
 | 
	
		
			
				|  |  | -                # XXX: this is ways not optimal but the only way
 | 
	
		
			
				|  |  | -                # for now to import tarballs through the API
 | 
	
		
			
				|  |  | -                fic = open(src)
 | 
	
		
			
				|  |  | -                data = fic.read()
 | 
	
		
			
				|  |  | -                fic.close()
 | 
	
		
			
				|  |  | -                src = "-"
 | 
	
		
			
				|  |  | -            except IOError:
 | 
	
		
			
				|  |  | -                # file does not exists or not a file (URL)
 | 
	
		
			
				|  |  | -                data = None
 | 
	
		
			
				|  |  | -            if isinstance(src, six.string_types):
 | 
	
		
			
				|  |  | -                params['fromSrc'] = src
 | 
	
		
			
				|  |  | -                return self._result(self._post(u, data=data, params=params))
 | 
	
		
			
				|  |  | -            return self._result(self._post(u, data=src, params=params))
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if image:
 | 
	
		
			
				|  |  | -            params['fromImage'] = image
 | 
	
		
			
				|  |  | -            return self._result(self._post(u, data=None, params=params))
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        raise Exception("Must specify a src or image")
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def info(self):
 | 
	
		
			
				|  |  | -        return self._result(self._get(self._url("/info")),
 | 
	
		
			
				|  |  | -                            True)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    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/" + image + "/insert")
 | 
	
		
			
				|  |  | -        params = {
 | 
	
		
			
				|  |  | -            'url': url,
 | 
	
		
			
				|  |  | -            'path': path
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        return self._result(self._post(api_url, params=params))
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def inspect_container(self, container):
 | 
	
		
			
				|  |  | -        if isinstance(container, dict):
 | 
	
		
			
				|  |  | -            container = container.get('Id')
 | 
	
		
			
				|  |  | -        return self._result(
 | 
	
		
			
				|  |  | -            self._get(self._url("/containers/{0}/json".format(container))),
 | 
	
		
			
				|  |  | -            True)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def inspect_image(self, image_id):
 | 
	
		
			
				|  |  | -        return self._result(
 | 
	
		
			
				|  |  | -            self._get(self._url("/images/{0}/json".format(image_id))),
 | 
	
		
			
				|  |  | -            True
 | 
	
		
			
				|  |  | -        )
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def kill(self, container, signal=None):
 | 
	
		
			
				|  |  | -        if isinstance(container, dict):
 | 
	
		
			
				|  |  | -            container = container.get('Id')
 | 
	
		
			
				|  |  | -        url = self._url("/containers/{0}/kill".format(container))
 | 
	
		
			
				|  |  | -        params = {}
 | 
	
		
			
				|  |  | -        if signal is not None:
 | 
	
		
			
				|  |  | -            params['signal'] = signal
 | 
	
		
			
				|  |  | -        res = self._post(url, params=params)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        self._raise_for_status(res)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def load_image(self, data):
 | 
	
		
			
				|  |  | -        res = self._post(self._url("/images/load"), data=data)
 | 
	
		
			
				|  |  | -        self._raise_for_status(res)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def login(self, username, password=None, email=None, registry=None,
 | 
	
		
			
				|  |  | -              reauth=False):
 | 
	
		
			
				|  |  | -        # If we don't have any auth data so far, try reloading the config file
 | 
	
		
			
				|  |  | -        # one more time in case anything showed up in there.
 | 
	
		
			
				|  |  | -        if not self._auth_configs:
 | 
	
		
			
				|  |  | -            self._auth_configs = auth.load_config()
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        registry = registry or auth.INDEX_URL
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        authcfg = auth.resolve_authconfig(self._auth_configs, registry)
 | 
	
		
			
				|  |  | -        # If we found an existing auth config for this registry and username
 | 
	
		
			
				|  |  | -        # combination, we can return it immediately unless reauth is requested.
 | 
	
		
			
				|  |  | -        if authcfg and authcfg.get('username', None) == username \
 | 
	
		
			
				|  |  | -                and not reauth:
 | 
	
		
			
				|  |  | -            return authcfg
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        req_data = {
 | 
	
		
			
				|  |  | -            'username': username,
 | 
	
		
			
				|  |  | -            'password': password,
 | 
	
		
			
				|  |  | -            'email': email,
 | 
	
		
			
				|  |  | -            'serveraddress': registry,
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        response = self._post_json(self._url('/auth'), data=req_data)
 | 
	
		
			
				|  |  | -        if response.status_code == 200:
 | 
	
		
			
				|  |  | -            self._auth_configs[registry] = req_data
 | 
	
		
			
				|  |  | -        return self._result(response, json=True)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def logs(self, container, stdout=True, stderr=True, stream=False,
 | 
	
		
			
				|  |  | -             timestamps=False):
 | 
	
		
			
				|  |  | -        if isinstance(container, dict):
 | 
	
		
			
				|  |  | -            container = container.get('Id')
 | 
	
		
			
				|  |  | -        if utils.compare_version('1.11', self._version) >= 0:
 | 
	
		
			
				|  |  | -            params = {'stderr': stderr and 1 or 0,
 | 
	
		
			
				|  |  | -                      'stdout': stdout and 1 or 0,
 | 
	
		
			
				|  |  | -                      'timestamps': timestamps and 1 or 0,
 | 
	
		
			
				|  |  | -                      'follow': stream and 1 or 0}
 | 
	
		
			
				|  |  | -            url = self._url("/containers/{0}/logs".format(container))
 | 
	
		
			
				|  |  | -            res = self._get(url, params=params, stream=stream)
 | 
	
		
			
				|  |  | -            if stream:
 | 
	
		
			
				|  |  | -                return self._multiplexed_socket_stream_helper(res)
 | 
	
		
			
				|  |  | -            elif six.PY3:
 | 
	
		
			
				|  |  | -                return bytes().join(
 | 
	
		
			
				|  |  | -                    [x for x in self._multiplexed_buffer_helper(res)]
 | 
	
		
			
				|  |  | -                )
 | 
	
		
			
				|  |  | -            else:
 | 
	
		
			
				|  |  | -                return str().join(
 | 
	
		
			
				|  |  | -                    [x for x in self._multiplexed_buffer_helper(res)]
 | 
	
		
			
				|  |  | -                )
 | 
	
		
			
				|  |  | -        return self.attach(
 | 
	
		
			
				|  |  | -            container,
 | 
	
		
			
				|  |  | -            stdout=stdout,
 | 
	
		
			
				|  |  | -            stderr=stderr,
 | 
	
		
			
				|  |  | -            stream=stream,
 | 
	
		
			
				|  |  | -            logs=True
 | 
	
		
			
				|  |  | -        )
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def ping(self):
 | 
	
		
			
				|  |  | -        return self._result(self._get(self._url('/_ping')))
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def port(self, container, private_port):
 | 
	
		
			
				|  |  | -        if isinstance(container, dict):
 | 
	
		
			
				|  |  | -            container = container.get('Id')
 | 
	
		
			
				|  |  | -        res = self._get(self._url("/containers/{0}/json".format(container)))
 | 
	
		
			
				|  |  | -        self._raise_for_status(res)
 | 
	
		
			
				|  |  | -        json_ = res.json()
 | 
	
		
			
				|  |  | -        s_port = str(private_port)
 | 
	
		
			
				|  |  | -        h_ports = None
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        h_ports = json_['NetworkSettings']['Ports'].get(s_port + '/udp')
 | 
	
		
			
				|  |  | -        if h_ports is None:
 | 
	
		
			
				|  |  | -            h_ports = json_['NetworkSettings']['Ports'].get(s_port + '/tcp')
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        return h_ports
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def pull(self, repository, tag=None, stream=False):
 | 
	
		
			
				|  |  | -        if not tag:
 | 
	
		
			
				|  |  | -            repository, tag = utils.parse_repository_tag(repository)
 | 
	
		
			
				|  |  | -        registry, repo_name = auth.resolve_repository_name(repository)
 | 
	
		
			
				|  |  | -        if repo_name.count(":") == 1:
 | 
	
		
			
				|  |  | -            repository, tag = repository.rsplit(":", 1)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        params = {
 | 
	
		
			
				|  |  | -            'tag': tag,
 | 
	
		
			
				|  |  | -            'fromImage': repository
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        headers = {}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if utils.compare_version('1.5', self._version) >= 0:
 | 
	
		
			
				|  |  | -            # If we don't have any auth data so far, try reloading the config
 | 
	
		
			
				|  |  | -            # file one more time in case anything showed up in there.
 | 
	
		
			
				|  |  | -            if not self._auth_configs:
 | 
	
		
			
				|  |  | -                self._auth_configs = auth.load_config()
 | 
	
		
			
				|  |  | -            authcfg = auth.resolve_authconfig(self._auth_configs, registry)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            # Do not fail here if no authentication exists for this specific
 | 
	
		
			
				|  |  | -            # registry as we can have a readonly pull. Just put the header if
 | 
	
		
			
				|  |  | -            # we can.
 | 
	
		
			
				|  |  | -            if authcfg:
 | 
	
		
			
				|  |  | -                headers['X-Registry-Auth'] = auth.encode_header(authcfg)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        response = self._post(self._url('/images/create'), params=params,
 | 
	
		
			
				|  |  | -                              headers=headers, stream=stream, timeout=None)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if stream:
 | 
	
		
			
				|  |  | -            return self._stream_helper(response)
 | 
	
		
			
				|  |  | -        else:
 | 
	
		
			
				|  |  | -            return self._result(response)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def push(self, repository, stream=False):
 | 
	
		
			
				|  |  | -        registry, repo_name = auth.resolve_repository_name(repository)
 | 
	
		
			
				|  |  | -        u = self._url("/images/{0}/push".format(repository))
 | 
	
		
			
				|  |  | -        headers = {}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if utils.compare_version('1.5', self._version) >= 0:
 | 
	
		
			
				|  |  | -            # If we don't have any auth data so far, try reloading the config
 | 
	
		
			
				|  |  | -            # file one more time in case anything showed up in there.
 | 
	
		
			
				|  |  | -            if not self._auth_configs:
 | 
	
		
			
				|  |  | -                self._auth_configs = auth.load_config()
 | 
	
		
			
				|  |  | -            authcfg = auth.resolve_authconfig(self._auth_configs, registry)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            # Do not fail here if no authentication exists for this specific
 | 
	
		
			
				|  |  | -            # registry as we can have a readonly pull. Just put the header if
 | 
	
		
			
				|  |  | -            # we can.
 | 
	
		
			
				|  |  | -            if authcfg:
 | 
	
		
			
				|  |  | -                headers['X-Registry-Auth'] = auth.encode_header(authcfg)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            response = self._post_json(u, None, headers=headers, stream=stream)
 | 
	
		
			
				|  |  | -        else:
 | 
	
		
			
				|  |  | -            response = self._post_json(u, None, stream=stream)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        return stream and self._stream_helper(response) \
 | 
	
		
			
				|  |  | -            or self._result(response)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def remove_container(self, container, v=False, link=False, force=False):
 | 
	
		
			
				|  |  | -        if isinstance(container, dict):
 | 
	
		
			
				|  |  | -            container = container.get('Id')
 | 
	
		
			
				|  |  | -        params = {'v': v, 'link': link, 'force': force}
 | 
	
		
			
				|  |  | -        res = self._delete(self._url("/containers/" + container),
 | 
	
		
			
				|  |  | -                           params=params)
 | 
	
		
			
				|  |  | -        self._raise_for_status(res)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def remove_image(self, image, force=False, noprune=False):
 | 
	
		
			
				|  |  | -        params = {'force': force, 'noprune': noprune}
 | 
	
		
			
				|  |  | -        res = self._delete(self._url("/images/" + image), params=params)
 | 
	
		
			
				|  |  | -        self._raise_for_status(res)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def restart(self, container, timeout=10):
 | 
	
		
			
				|  |  | -        if isinstance(container, dict):
 | 
	
		
			
				|  |  | -            container = container.get('Id')
 | 
	
		
			
				|  |  | -        params = {'t': timeout}
 | 
	
		
			
				|  |  | -        url = self._url("/containers/{0}/restart".format(container))
 | 
	
		
			
				|  |  | -        res = self._post(url, params=params)
 | 
	
		
			
				|  |  | -        self._raise_for_status(res)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def search(self, term):
 | 
	
		
			
				|  |  | -        return self._result(self._get(self._url("/images/search"),
 | 
	
		
			
				|  |  | -                                      params={'term': term}),
 | 
	
		
			
				|  |  | -                            True)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def start(self, container, binds=None, port_bindings=None, lxc_conf=None,
 | 
	
		
			
				|  |  | -              publish_all_ports=False, links=None, privileged=False,
 | 
	
		
			
				|  |  | -              dns=None, dns_search=None, volumes_from=None, network_mode=None):
 | 
	
		
			
				|  |  | -        if isinstance(container, dict):
 | 
	
		
			
				|  |  | -            container = container.get('Id')
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if isinstance(lxc_conf, dict):
 | 
	
		
			
				|  |  | -            formatted = []
 | 
	
		
			
				|  |  | -            for k, v in six.iteritems(lxc_conf):
 | 
	
		
			
				|  |  | -                formatted.append({'Key': k, 'Value': str(v)})
 | 
	
		
			
				|  |  | -            lxc_conf = formatted
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        start_config = {
 | 
	
		
			
				|  |  | -            'LxcConf': lxc_conf
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if binds:
 | 
	
		
			
				|  |  | -            start_config['Binds'] = utils.convert_volume_binds(binds)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if port_bindings:
 | 
	
		
			
				|  |  | -            start_config['PortBindings'] = utils.convert_port_bindings(
 | 
	
		
			
				|  |  | -                port_bindings
 | 
	
		
			
				|  |  | -            )
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        start_config['PublishAllPorts'] = publish_all_ports
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if links:
 | 
	
		
			
				|  |  | -            if isinstance(links, dict):
 | 
	
		
			
				|  |  | -                links = six.iteritems(links)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            formatted_links = [
 | 
	
		
			
				|  |  | -                '{0}:{1}'.format(k, v) for k, v in sorted(links)
 | 
	
		
			
				|  |  | -            ]
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            start_config['Links'] = formatted_links
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        start_config['Privileged'] = privileged
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if utils.compare_version('1.10', self._version) >= 0:
 | 
	
		
			
				|  |  | -            if dns is not None:
 | 
	
		
			
				|  |  | -                start_config['Dns'] = dns
 | 
	
		
			
				|  |  | -            if volumes_from is not None:
 | 
	
		
			
				|  |  | -                if isinstance(volumes_from, six.string_types):
 | 
	
		
			
				|  |  | -                    volumes_from = volumes_from.split(',')
 | 
	
		
			
				|  |  | -                start_config['VolumesFrom'] = volumes_from
 | 
	
		
			
				|  |  | -        else:
 | 
	
		
			
				|  |  | -            warning_message = ('{0!r} parameter is discarded. It is only'
 | 
	
		
			
				|  |  | -                               ' available for API version greater or equal'
 | 
	
		
			
				|  |  | -                               ' than 1.10')
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            if dns is not None:
 | 
	
		
			
				|  |  | -                warnings.warn(warning_message.format('dns'),
 | 
	
		
			
				|  |  | -                              DeprecationWarning)
 | 
	
		
			
				|  |  | -            if volumes_from is not None:
 | 
	
		
			
				|  |  | -                warnings.warn(warning_message.format('volumes_from'),
 | 
	
		
			
				|  |  | -                              DeprecationWarning)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if dns_search:
 | 
	
		
			
				|  |  | -            start_config['DnsSearch'] = dns_search
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if network_mode:
 | 
	
		
			
				|  |  | -            start_config['NetworkMode'] = network_mode
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        url = self._url("/containers/{0}/start".format(container))
 | 
	
		
			
				|  |  | -        res = self._post_json(url, data=start_config)
 | 
	
		
			
				|  |  | -        self._raise_for_status(res)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def resize(self, container, height, width):
 | 
	
		
			
				|  |  | -        if isinstance(container, dict):
 | 
	
		
			
				|  |  | -            container = container.get('Id')
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        params = {'h': height, 'w': width}
 | 
	
		
			
				|  |  | -        url = self._url("/containers/{0}/resize".format(container))
 | 
	
		
			
				|  |  | -        res = self._post(url, params=params)
 | 
	
		
			
				|  |  | -        self._raise_for_status(res)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def stop(self, container, timeout=10):
 | 
	
		
			
				|  |  | -        if isinstance(container, dict):
 | 
	
		
			
				|  |  | -            container = container.get('Id')
 | 
	
		
			
				|  |  | -        params = {'t': timeout}
 | 
	
		
			
				|  |  | -        url = self._url("/containers/{0}/stop".format(container))
 | 
	
		
			
				|  |  | -        res = self._post(url, params=params,
 | 
	
		
			
				|  |  | -                         timeout=max(timeout, self._timeout))
 | 
	
		
			
				|  |  | -        self._raise_for_status(res)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def tag(self, image, repository, tag=None, force=False):
 | 
	
		
			
				|  |  | -        params = {
 | 
	
		
			
				|  |  | -            'tag': tag,
 | 
	
		
			
				|  |  | -            'repo': repository,
 | 
	
		
			
				|  |  | -            'force': 1 if force else 0
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        url = self._url("/images/{0}/tag".format(image))
 | 
	
		
			
				|  |  | -        res = self._post(url, params=params)
 | 
	
		
			
				|  |  | -        self._raise_for_status(res)
 | 
	
		
			
				|  |  | -        return res.status_code == 201
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def top(self, container):
 | 
	
		
			
				|  |  | -        u = self._url("/containers/{0}/top".format(container))
 | 
	
		
			
				|  |  | -        return self._result(self._get(u), True)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def version(self):
 | 
	
		
			
				|  |  | -        return self._result(self._get(self._url("/version")), True)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    def wait(self, container):
 | 
	
		
			
				|  |  | -        if isinstance(container, dict):
 | 
	
		
			
				|  |  | -            container = container.get('Id')
 | 
	
		
			
				|  |  | -        url = self._url("/containers/{0}/wait".format(container))
 | 
	
		
			
				|  |  | -        res = self._post(url, timeout=None)
 | 
	
		
			
				|  |  | -        self._raise_for_status(res)
 | 
	
		
			
				|  |  | -        json_ = res.json()
 | 
	
		
			
				|  |  | -        if 'StatusCode' in json_:
 | 
	
		
			
				|  |  | -            return json_['StatusCode']
 | 
	
		
			
				|  |  | -        return -1
 |