Exemple #1
0
    async def http_query(self, method, path, data={}, params={}, timeout=300):
        """
        Makes a query to the docker daemon

        :param method: HTTP method
        :param path: Endpoint in API
        :param data: Dictionnary with the body. Will be transformed to a JSON
        :param params: Parameters added as a query arg
        :param timeout: Timeout
        :returns: HTTP response
        """

        data = json.dumps(data)
        if timeout is None:
            timeout = 60 * 60 * 24 * 31  # One month timeout

        if path == 'version':
            url = "http://docker/v1.12/" + path  # API of docker v1.0
        else:
            url = "http://docker/v" + DOCKER_MINIMUM_API_VERSION + "/" + path
        try:
            if path != "version":  # version is use by check connection
                await self._check_connection()
            if self._session is None or self._session.closed:
                connector = self.connector()
                self._session = aiohttp.ClientSession(connector=connector)
            response = await self._session.request(method,
                                                   url,
                                                   params=params,
                                                   data=data,
                                                   headers={
                                                       "content-type":
                                                       "application/json",
                                                   },
                                                   timeout=timeout)
        except (aiohttp.ClientResponseError, aiohttp.ClientOSError) as e:
            raise DockerError("Docker has returned an error: {}".format(
                str(e)))
        except (asyncio.TimeoutError):
            raise DockerError("Docker timeout " + method + " " + path)
        if response.status >= 300:
            body = await response.read()
            try:
                body = json.loads(body.decode("utf-8"))["message"]
            except ValueError:
                pass
            log.debug("Query Docker %s %s params=%s data=%s Response: %s",
                      method, path, params, data, body)
            if response.status == 304:
                raise DockerHttp304Error(
                    "Docker has returned an error: {} {}".format(
                        response.status, body))
            elif response.status == 404:
                raise DockerHttp404Error(
                    "Docker has returned an error: {} {}".format(
                        response.status, body))
            else:
                raise DockerError("Docker has returned an error: {} {}".format(
                    response.status, body))
        return response
Exemple #2
0
 def connector(self):
     if self._connector is None or self._connector.closed:
         if not sys.platform.startswith("linux"):
             raise DockerError("Docker is supported only on Linux")
         try:
             self._connector = aiohttp.connector.UnixConnector(
                 self._server_url, conn_timeout=2, limit=None)
         except (aiohttp.errors.ClientOSError, FileNotFoundError):
             raise DockerError("Can't connect to docker daemon")
     return self._connector
Exemple #3
0
    async def pull_image(self, image, progress_callback=None):
        """
        Pulls an image from the Docker repository

        :params image: Image name
        :params progress_callback: A function that receive a log message about image download progress
        """

        try:
            await self.query("GET", "images/{}/json".format(image))
            return  # We already have the image skip the download
        except DockerHttp404Error:
            pass

        if progress_callback:
            progress_callback("Pulling '{}' from docker hub".format(image))
        try:
            response = await self.http_query("POST",
                                             "images/create",
                                             params={"fromImage": image},
                                             timeout=None)
        except DockerError as e:
            raise DockerError(
                "Could not pull the '{}' image from Docker Hub, please check your Internet connection (original error: {})"
                .format(image, e))
        # The pull api will stream status via an HTTP JSON stream
        content = ""
        while True:
            try:
                chunk = await response.content.read(CHUNK_SIZE)
            except aiohttp.ServerDisconnectedError:
                log.error(
                    "Disconnected from server while pulling Docker image '{}' from docker hub"
                    .format(image))
                break
            except asyncio.TimeoutError:
                log.error(
                    "Timeout while pulling Docker image '{}' from docker hub".
                    format(image))
                break
            if not chunk:
                break
            content += chunk.decode("utf-8")

            try:
                while True:
                    content = content.lstrip(" \r\n\t")
                    answer, index = json.JSONDecoder().raw_decode(content)
                    if "progress" in answer and progress_callback:
                        progress_callback("Pulling image {}:{}: {}".format(
                            image, answer["id"], answer["progress"]))
                    content = content[index:]
            except ValueError:  # Partial JSON
                pass
        response.close()
        if progress_callback:
            progress_callback("Success pulling image {}".format(image))
Exemple #4
0
    def _check_connection(self):
        if not self._connected:
            try:
                self._connected = True
                connector = self.connector()
                version = yield from self.query("GET", "version")
            except (aiohttp.errors.ClientOSError, FileNotFoundError):
                self._connected = False
                raise DockerError("Can't connect to docker daemon")

            docker_version = parse_version(version['ApiVersion'])

            if docker_version < parse_version(DOCKER_MINIMUM_API_VERSION):
                raise DockerError(
                    "Docker version is {}. GNS3 requires a minimum version of {}"
                    .format(version["Version"], DOCKER_MINIMUM_VERSION))

            preferred_api_version = parse_version(DOCKER_PREFERRED_API_VERSION)
            if docker_version >= preferred_api_version:
                self._api_version = DOCKER_PREFERRED_API_VERSION