Esempio n. 1
0
    def export(self,
               chunk_size: int = api.DEFAULT_CHUNK_SIZE) -> Iterator[bytes]:
        """Download container's filesystem contents as a tar archive.

        Args:
            chunk_size: <= number of bytes to return for each iteration of the generator.

        Yields:
            tarball in size/chunk_size chunks

        Raises:
            NotFound when container has been removed from service
            APIError when service reports an error
        """
        response = self.client.get(f"/containers/{self.id}/export",
                                   stream=True)

        if response.status_code != 200:
            body = response.json()
            if response.status_code == 404:
                raise NotFound(body["cause"],
                               response=response,
                               explanation=body["message"])
            raise APIError(body["cause"],
                           response=response,
                           explanation=body["message"])

        for out in response.iter_content(chunk_size=chunk_size):
            yield out
Esempio n. 2
0
    def remove(self,
               name: Union[Volume, str],
               force: Optional[bool] = None) -> None:
        """Delete a volume.

        Args:
            name: Identifier for Volume to be deleted.
            force: When true, force deletion of in-use volume

        Raises:
            APIError: when service reports an error

        Notes:
            Podman only.
        """
        if isinstance(name, Volume):
            name = name.name
        response = self.client.delete(f"/volumes/{name}",
                                      params={"force": force})

        if response.status_code == requests.codes.no_content:
            return

        data = response.json()
        if response.status_code == requests.codes.not_found:
            raise NotFound(data["cause"],
                           response=response,
                           explanation=data["message"])
        raise APIError(data["cause"],
                       response=response,
                       explanation=data["message"])
Esempio n. 3
0
    def top(self, **kwargs) -> Union[Iterator[Dict[str, Any]], Dict[str, Any]]:
        """Report on running processes in the container.

        Keyword Args:
            ps_args (str): When given, arguments will be passed to ps
            stream (bool): When True, repeatedly return results. Default: False

        Raises:
            NotFound: when the container no longer exists
            APIError: when the service reports an error
        """
        params = {
            "ps_args": kwargs.get("ps_args"),
            "stream": kwargs.get("stream", False),
        }
        response = self.client.get(f"/containers/{self.id}/top", params=params)

        if response.status_code != requests.codes.okay:
            body = response.json()

            if response.status_code == requests.codes.not_found:
                raise NotFound(body["cause"], response=response, explanation=body["message"])
            raise APIError(body["cause"], response=response, explanation=body["message"])

        if params["stream"]:
            self._top_helper(response)

        return response.json()
Esempio n. 4
0
    def wait(self, **kwargs) -> Dict[str, Any]:
        """Block until the container enters given state.

        Keyword Args:
            condition (str): Container state on which to release, values:
                not-running (default), next-exit or removed.
            timeout (int): Number of seconds to wait for the container to stop.

        Returns:
              Keys:
                - StatusCode (int): Container's exit code
                - Error["Message"] (str): Error message from container

        Raises:
              NotFound: When Container not found
              ReadTimeoutError: When timeout is exceeded
              APIError: When service returns an error
        """
        condition = kwargs.get("condition")
        if isinstance(condition, str):
            condition = [condition]

        response = self.client.post(f"/containers/{self.id}/wait", params={"condition": condition})
        body = response.json()

        if response.status_code == requests.codes.okay:
            return body

        if response.status_code == requests.codes.not_found:
            raise NotFound(body["cause"], response=response, explanation=body["message"])
        raise APIError(body["cause"], response=response, explanation=body["message"])
Esempio n. 5
0
    def get(self, network_id: str, *_, **kwargs) -> Network:  # pylint: disable=arguments-differ
        """Return information for network network_id.

        Args:
            network_id: Network name or id.

        Keyword Args:
            compatible (bool): Should compatible API be used. Default: True

        Raises:
            NotFound: Network does not exist.
            APIError: Error returned by service.

        Note:
            The compatible API is used, this allows the server to provide dynamic fields.
                id is the most important example.
        """
        compatible = kwargs.get("compatible", True)

        path = f"/networks/{network_id}" + ("" if compatible else "/json")

        response = self.client.get(path, compatible=compatible)
        body = response.json()

        if response.status_code != 200:
            if response.status_code == 404:
                raise NotFound(body["cause"], response=response, explanation=body["message"])
            raise APIError(body["cause"], response=response, explanation=body["message"])

        if not compatible:
            body = body[0]

        return self.prepare_model(body)
Esempio n. 6
0
    def stats(self, **kwargs) -> Union[Sequence[Dict[str, bytes]], bytes]:
        """Return statistics for container.

        Keyword Args:
            decode (bool): If True and stream is True, stream will be decoded into dict's.
                Default: False.
            stream (bool): Stream statistics until cancelled. Default: True.

        Raises:
            APIError when service reports an error
        """
        # FIXME Errors in stream are not handled, need content and json to read Errors.
        stream = kwargs.get("stream", True)
        decode = kwargs.get("decode", False)

        params = {
            "containers": self.id,
            "stream": stream,
        }

        response = self.client.get("/containers/stats", params=params)

        if response.status_code != requests.codes.okay:
            body = response.json()
            if response.status_code == requests.codes.not_found:
                raise NotFound(body["cause"], response=response, explanation=body["message"])
            raise APIError(body["cause"], response=response, explanation=body["message"])

        if stream:
            return self._stats_helper(decode, response.iter_lines())

        with io.StringIO() as buffer:
            for entry in response.text:
                buffer.writer(json.dumps(entry) + "\n")
            return buffer.getvalue()
Esempio n. 7
0
    def get_archive(
        self,
        path: str,
        chunk_size: int = api.DEFAULT_CHUNK_SIZE
    ) -> Tuple[Iterable, Dict[str, Any]]:
        """Download a file or folder from the container's filesystem.

        Args:
            path: Path to file or folder.
            chunk_size: <= number of bytes to return for each iteration of the generator.

        Returns:
            First item is a raw tar data stream.
            Second item is a dict containing stat information on the specified path.
        """
        response = self.client.get(f"/containers/{self.id}/archive",
                                   params={"path": [path]})
        if response.status_code != 200:
            body = response.json()
            if response.status_code == 404:
                raise NotFound(body["cause"],
                               response=response,
                               explanation=body["message"])
            raise APIError(body["cause"],
                           response=response,
                           explanation=body["message"])

        stat = response.headers.get('x-docker-container-path-stat', None)
        stat = api.decode_header(stat)
        return response.iter_content(chunk_size=chunk_size), stat
Esempio n. 8
0
    def stats(self, **kwargs) -> Dict[str, Any]:
        """Resource usage statistics for the containers in pods.

        Keyword Args:
            all (bool): Provide statistics for all running pods.
            name (Union[str, List[str]]): Pods to include in report.

        Raises:
            NotFound when pod not found.
            APIError when service reports an error.
        """
        if "all" in kwargs and "name" in kwargs:
            raise ValueError(
                "Keywords 'all' and 'name' are mutually exclusive.")

        params = {
            "all": kwargs.get("all"),
            "namesOrIDs": kwargs.get("name"),
        }
        response = self.client.get("/pods/stats", params=params)
        body = response.json()

        if response.status_code == requests.codes.okay:
            return body

        if response.status_code == requests.codes.not_found:
            raise NotFound(body["cause"],
                           response=response,
                           explanation=body["message"])
        raise APIError(body["cause"],
                       response=response,
                       explanation=body["message"])
Esempio n. 9
0
    def pause(self) -> None:
        """Pause processes within the container."""
        response = self.client.post(f"/containers/{self.id}/pause")
        if response.status_code == requests.codes.no_content:
            return

        body = response.json()
        if response.status_code == requests.codes.not_found:
            raise NotFound(body["cause"], response=response, explanation=body["message"])
        raise APIError(body["cause"], response=response, explanation=body["message"])
Esempio n. 10
0
    def diff(self) -> List[Dict[str, int]]:
        """Report changes of a container's filesystem.

        Raises:
            APIError: when service reports error
        """
        response = self.client.get(f"/containers/{self.id}/changes")
        body = response.json()

        if response.status_code == requests.codes.okay:
            return body

        if response.status_code == requests.codes.not_found:
            raise NotFound(body["cause"], response=response, explanation=body["message"])
        raise APIError(body["cause"], response=response, explanation=body["message"])
Esempio n. 11
0
    def commit(self,
               repository: str = None,
               tag: str = None,
               **kwargs) -> Image:
        """Save container to given repository using given parameters.

        Args:
            repository: Where to save Image
            tag: Tag to push with Image

        Keyword Args:
            author (str): Name of commit author
            changes (List[str]): Instructions to apply during commit
            comment (List[str]): Instructions to apply while committing in Dockerfile format
            conf (Dict[str, Any]): Ignored
            format (str): Format of the image manifest and metadata
            message (str): Commit message to include with Image
            pause (bool): Pause the container before committing it

            See https://docs.podman.io/en/latest/_static/api.html#operation/libpodCommitContainer
        """
        params = {
            "author": kwargs.get("author", None),
            "changes": kwargs.get("changes", None),
            "comment": kwargs.get("comment", None),
            "container": self.id,
            "format": kwargs.get("format", None),
            "pause": kwargs.get("pause", None),
            "repo": repository,
            "tag": tag,
        }
        response = self.client.post("/commit", params=params)
        body = response.json()

        if response.status_code != 201:
            if response.status_code == 404:
                raise NotFound(body["cause"],
                               response=response,
                               explanation=body["message"])
            raise APIError(body["cause"],
                           response=response,
                           explanation=body["message"])

        return ImagesManager(client=self.client).get(body["ID"])
Esempio n. 12
0
    def resize(self, height: int = None, width: int = None) -> None:
        """Resize the tty session.

        Args:
            height: New height of tty session.
            width: New width of tty session.
        """
        params = {
            "h": height,
            "w": width,
        }
        response = self.client.post(f"/containers/{self.id}/resize", params=params)
        if response.status_code == requests.codes.okay:
            return

        body = response.json()
        if response.status_code == requests.codes.not_found:
            raise NotFound(body["cause"], response=response, explanation=body["message"])
        raise APIError(body["cause"], response=response, explanation=body["message"])
Esempio n. 13
0
    def get(self, container_id: str) -> Container:  # pylint: disable=arguments-differ
        """Get container by name or id.

        Args:
            container_id: Container name or id.

        Raises:
            NotFound: Container does not exist.
            APIError: Error return by service.
        """
        container_id = urllib.parse.quote_plus(container_id)
        response = self.client.get(f"/containers/{container_id}/json")
        body = response.json()

        if response.status_code == 200:
            return self.prepare_model(body)

        if response.status_code == 404:
            raise NotFound(body["cause"], response=response, explanation=body["message"])
        raise APIError(body["cause"], response=response, explanation=body["message"])
Esempio n. 14
0
    def remove(self, force: bool = None):
        """Delete this volume.

        Args:
            force: When true, force deletion of volume

        Raises:
            APIError when service reports an error
        """
        params = {"force": force}
        response = self.client.delete(f"/volumes/{self.name}", params=params)

        if response.status_code == 204:
            return

        data = response.json()
        if response.status_code == 404:
            raise NotFound(data["cause"], response=response, explanation=data["message"])

        raise APIError(data["cause"], response=response, explanation=data["message"])
Esempio n. 15
0
    def get(self, volume_id: str) -> Volume:  # pylint: disable=arguments-differ
        """Returns and volume by name or id.

        Args:
            volume_id: Volume id or name for which to search

        Raises:
            NotFound if volume could not be found
            APIError when service reports an error
        """
        response = self.client.get(f"/volumes/{volume_id}")

        if response.status_code == 404:
            raise NotFound(
                response.text, response=response, explanation=f"Failed to find volume '{volume_id}'"
            )

        data = response.json()
        if response.status_code == 200:
            return self.prepare_model(data)

        raise APIError(data["cause"], response=response, explanation=data["message"])
Esempio n. 16
0
    def logs(self, **kwargs) -> Union[bytes, Iterator[bytes]]:
        """Get logs from the container.

        Keyword Args:
            stdout (bool): Include stdout. Default: True
            stderr (bool): Include stderr. Default: True
            stream (bool): Return generator of strings as the response. Default: False
            timestamps (bool): Show timestamps in output. Default: False
            tail (Union[str, int]): Output specified number of lines at the end of
                logs.  Integer representing the number of lines to display, or the string all.
                Default: all
            since (Union[datetime, int]): Show logs since a given datetime or
                integer epoch (in seconds)
            follow (bool): Follow log output. Default: False
            until (Union[datetime, int]): Show logs that occurred before the given
                datetime or integer epoch (in seconds)
        """
        params = {
            "follow": kwargs.get("follow", kwargs.get("stream", None)),
            "since": api.prepare_timestamp(kwargs.get("since")),
            "stderr": kwargs.get("stderr", None),
            "stdout": kwargs.get("stdout", True),
            "tail": kwargs.get("tail"),
            "timestamps": kwargs.get("timestamps"),
            "until": api.prepare_timestamp(kwargs.get("until")),
        }

        response = self.client.get(f"/containers/{self.id}/logs", params=params)

        if response.status_code != requests.codes.okay:
            body = response.json()
            if response.status_code == requests.codes.not_found:
                raise NotFound(body["cause"], response=response, explanation=body["message"])
            raise APIError(body["cause"], response=response, explanation=body["message"])

        if bool(kwargs.get("stream", False)):
            return api.stream_frames(response)
        return api.frames(response)
Esempio n. 17
0
    def remove(self, force: Optional[bool] = None) -> None:
        """Delete this volume.

        Args:
            force: When true, force deletion of in-use volume

        Raises:
            APIError when service reports an error
        """
        response = self.client.delete(f"/volumes/{self.name}",
                                      params={"force": force})

        if response.status_code == requests.codes.no_content:
            return

        data = response.json()
        if response.status_code == requests.codes.not_found:
            raise NotFound(data["cause"],
                           response=response,
                           explanation=data["message"])
        raise APIError(data["cause"],
                       response=response,
                       explanation=data["message"])
Esempio n. 18
0
    def get(self, pod_id: str) -> Pod:  # pylint: disable=arguments-differ
        """Return information for Pod by name or id.

        Args:
            pod_id: Pod name or id.

        Raises:
            NotFound: When network does not exist.
            APIError: When error returned by service.
        """
        response = self.client.get(f"/pods/{pod_id}/json")
        body = response.json()

        if response.status_code == requests.codes.okay:
            return self.prepare_model(attrs=body)

        if response.status_code == requests.codes.not_found:
            raise NotFound(body["cause"],
                           response=response,
                           explanation=body["message"])
        raise APIError(body["cause"],
                       response=response,
                       explanation=body["message"])
Esempio n. 19
0
    def top(self, **kwargs) -> Dict[str, Any]:
        """Report on running processes in container.

        Keyword Args:
            ps_args (str): Optional arguments passed to ps
        """
        params = {
            "ps_args": kwargs.get("ps_args", None),
            "stream": kwargs.get("stream", None),
        }
        response = self.client.get(f"/containers/{self.id}/top", params=params)
        body = response.json()

        if response.status_code != 200:
            if response.status_code == 404:
                raise NotFound(body["cause"],
                               response=response,
                               explanation=body["message"])
            raise APIError(body["cause"],
                           response=response,
                           explanation=body["message"])

        return body