import logging import os import six import warnings from ..auth import auth from ..constants import INSECURE_REGISTRY_DEPRECATION_WARNING from .. import utils from .. import errors log = logging.getLogger(__name__) class ImageApiMixin(object): @utils.check_resource def get_image(self, image): res = self._get(self._url("/images/{0}/get", image), stream=True) self._raise_for_status(res) return res.raw @utils.check_resource def history(self, image): 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): 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, } if filters: params['filters'] = utils.convert_filters(filters) 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, changes=None, stream_src=False): if not (src or image): raise errors.DockerException( 'Must specify src or image to import from' ) u = self._url('/images/create') params = _import_image_params( repository, tag, image, src=(src if isinstance(src, six.string_types) else None), changes=changes ) headers = {'Content-Type': 'application/tar'} if image or params.get('fromSrc') != '-': # from image or URL return self._result( self._post(u, data=None, params=params) ) elif isinstance(src, six.string_types): # from file path with open(src, 'rb') as f: return self._result( self._post( u, data=f, params=params, headers=headers, timeout=None ) ) else: # from raw data if stream_src: headers['Transfer-Encoding'] = 'chunked' return self._result( self._post(u, data=src, params=params, headers=headers) ) def import_image_from_data(self, data, repository=None, tag=None, changes=None): u = self._url('/images/create') params = _import_image_params( repository, tag, src='-', changes=changes ) headers = {'Content-Type': 'application/tar'} return self._result( self._post( u, data=data, params=params, headers=headers, timeout=None ) ) return self.import_image( src=data, repository=repository, tag=tag, changes=changes ) def import_image_from_file(self, filename, repository=None, tag=None, changes=None): return self.import_image( src=filename, repository=repository, tag=tag, changes=changes ) def import_image_from_stream(self, stream, repository=None, tag=None, changes=None): return self.import_image( src=stream, stream_src=True, repository=repository, tag=tag, changes=changes ) def import_image_from_url(self, url, repository=None, tag=None, changes=None): return self.import_image( src=url, repository=repository, tag=tag, changes=changes ) def import_image_from_image(self, image, repository=None, tag=None, changes=None): return self.import_image( image=image, repository=repository, tag=tag, changes=changes ) @utils.check_resource 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 def inspect_image(self, image): return self._result( self._get(self._url("/images/{0}/json", image)), True ) def load_image(self, data): res = self._post(self._url("/images/load"), data=data) self._raise_for_status(res) def pull(self, repository, tag=None, stream=False, insecure_registry=False, auth_config=None, decode=False): if insecure_registry: warnings.warn( INSECURE_REGISTRY_DEPRECATION_WARNING.format('pull()'), DeprecationWarning ) if not tag: repository, tag = utils.parse_repository_tag(repository) registry, repo_name = auth.resolve_repository_name(repository) params = { 'tag': tag, 'fromImage': repository } 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) response = self._post( self._url('/images/create'), params=params, headers=headers, stream=stream, timeout=None ) self._raise_for_status(response) if stream: return self._stream_helper(response, decode=decode) return self._result(response) def push(self, repository, tag=None, stream=False, insecure_registry=False, auth_config=None, decode=False): if insecure_registry: warnings.warn( INSECURE_REGISTRY_DEPRECATION_WARNING.format('push()'), DeprecationWarning ) if not tag: repository, tag = utils.parse_repository_tag(repository) registry, repo_name = auth.resolve_repository_name(repository) u = self._url("/images/{0}/push", repository) params = { 'tag': tag } 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) response = self._post_json( u, None, headers=headers, stream=stream, params=params ) self._raise_for_status(response) if stream: return self._stream_helper(response, decode=decode) return self._result(response) @utils.check_resource def remove_image(self, image, force=False, noprune=False): params = {'force': force, 'noprune': noprune} res = self._delete(self._url("/images/{0}", image), params=params) self._raise_for_status(res) def search(self, term): return self._result( self._get(self._url("/images/search"), params={'term': term}), True ) @utils.check_resource 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", image) res = self._post(url, params=params) self._raise_for_status(res) return res.status_code == 201 def is_file(src): try: return ( isinstance(src, six.string_types) and os.path.isfile(src) ) except TypeError: # a data string will make isfile() raise a TypeError return False def _import_image_params(repo, tag, image=None, src=None, changes=None): params = { 'repo': repo, 'tag': tag, } if image: params['fromImage'] = image elif src and not is_file(src): params['fromSrc'] = src else: params['fromSrc'] = '-' if changes: params['changes'] = changes return params