Example #1
0
def buildah_common_inspect_to_metadata(metadata_object, inspect_data):
    """
    :param metadata_object: instance of conu.Metadata object
    :param inspect_data: dict with the inspect metadata
    """
    ociv1 = inspect_data.get("OCIv1")
    if not ociv1:
        raise ConuException(
            "inspect metadata are invalid: don't have OCIv1 section")
    raw_env_vars = graceful_get(ociv1, "config", "Env") or []
    if raw_env_vars:
        metadata_object.env_variables = {}
        for env_variable in raw_env_vars:
            splits = env_variable.split("=", 1)
            name = splits[0]
            value = splits[1] if len(splits) > 1 else None
            if value is not None:
                metadata_object.env_variables.update({name: value})

    metadata_object.labels = graceful_get(ociv1,
                                          "config",
                                          "Labels",
                                          default={})
    metadata_object.command = graceful_get(ociv1, 'config', 'Cmd')
    metadata_object.creation_timestamp = graceful_get(ociv1, "created")
Example #2
0
    def push(self, repository=None, tag=None):
        """
        Push image to registry. Raise exception when push fail.
        :param repository: str, see constructor
        :param tag: str, see constructor
        :return: None
        """

        image = self

        if repository or tag:
            image = self.tag_image(repository, tag)

        for json_e in self.d.push(repository=image.name, tag=image.tag, stream=True, decode=True):
            logger.debug(json_e)
            status = graceful_get(json_e, "status")
            if status:
                logger.info(status)
            else:
                error = graceful_get(json_e, "error")
                if error is not None:
                    logger.error(status)
                    raise ConuException("There was an error while pushing the image %s: %s",
                                        self.name, error)
        return image
Example #3
0
def buildah_image_inspect_to_metadata(inspect_data):
    """
    process data from `buildah inspect -t image` and return ImageMetadata

    :param inspect_data: dict, metadata from `buildah inspect -t image`
    :return: instance of ImageMetadata
    """
    im = ImageMetadata()
    im.name = graceful_get(inspect_data, "FromImage")
    im.identifier = graceful_get(inspect_data, "FromImageID")
    buildah_common_inspect_to_metadata(im, inspect_data)
    return im
Example #4
0
def buildah_container_inspect_to_metadata(inspect_data):
    """
    process data from `buildah inspect -t container` and return ContainerMetadata

    :param inspect_data: dict, metadata from `buildah inspect -t container`
    :return: instance of ContainerMetadata
    """
    cm = ContainerMetadata()
    cm.name = graceful_get(inspect_data, 'Container')
    cm.identifier = graceful_get(inspect_data, 'ContainerID')
    buildah_common_inspect_to_metadata(cm, inspect_data)
    return cm
Example #5
0
    def exit_code(self):
        """
        get exit code of container. Return value is 0 for running and created containers

        :return: int
        """
        return graceful_get(self.inspect(refresh=True), "State", "ExitCode")
Example #6
0
    def get_status(self):
        """
        Get status of container

        :return: one of: 'created', 'restarting', 'running', 'paused', 'exited', 'dead'
        """
        return graceful_get(self.inspect(refresh=True), "State", "Status")
Example #7
0
    def get_image_name(self):
        """
        return name of the container image

        :return: str
        """
        return graceful_get(self.inspect(refresh=False), "FromImage")
Example #8
0
    def get_name(self):
        """
        Returns name of the container

        :return: str
        """
        self.name = self.name or graceful_get(self.inspect(refresh=False), "Container")
        return self.name
Example #9
0
def inspect_to_metadata(metadata_object, inspect_data):
    """
    process data from `podman inspect` and update provided metadata object

    :param metadata_object: instance of Metadata
    :param inspect_data: dict, metadata from `podman inspect`
    :return: instance of Metadata
    """
    identifier = graceful_get(inspect_data, 'Id') or graceful_get(
        inspect_data, 'ID')
    if identifier:
        if ":" in identifier:
            # if format of image name from podman inspect:
            # sha256:8f0e66c924c0c169352de487a3c2463d82da24e9442fc097dddaa5f800df7129
            metadata_object.identifier = identifier.split(':')[1]
        else:
            # container
            metadata_object.identifier = identifier

    # format of Environment Variables from podman inspect:
    # ['DISTTAG=f26container', 'FGC=f26']
    raw_env_vars = graceful_get(inspect_data, "Config", "Env") or []
    if raw_env_vars:
        metadata_object.env_variables = {}
        for env_variable in raw_env_vars:
            splits = env_variable.split("=", 1)
            name = splits[0]
            value = splits[1] if len(splits) > 1 else None
            if value is not None:
                metadata_object.env_variables.update({name: value})

    raw_exposed_ports = graceful_get(inspect_data, "NetworkSettings", "Ports")
    if raw_exposed_ports:
        metadata_object.exposed_ports = list(
            set([d["containerPort"] for d in raw_exposed_ports]))

    # specific to images
    if "RepoTags" in inspect_data:
        repo_tags = graceful_get(inspect_data, 'RepoTags')
        # podman sets it to None if the image is not tagged
        if not repo_tags:
            repo_tags = [None]
        metadata_object.name = repo_tags[0]
        metadata_object.image_names = repo_tags
    else:
        metadata_object.name = graceful_get(inspect_data, 'ImageName')
    metadata_object.labels = graceful_get(inspect_data, 'Config', 'Labels')
    metadata_object.command = graceful_get(inspect_data, 'Config', 'Cmd')
    metadata_object.creation_timestamp = inspect_data.get('Created', None)
    # specific to images
    digests = inspect_data.get("RepoDigests", None)
    if digests:
        metadata_object.repo_digests = digests
        metadata_object.digest = digests[0]
    return metadata_object
Example #10
0
    def pull(self):
        """
        Pull this image from registry. Raises an exception if the image is not found in
        the registry.

        :return: None
        """
        for json_e in self.d.pull(repository=self.name, tag=self.tag, stream=True, decode=True):
            logger.debug(json_e)
            status = graceful_get(json_e, "status")
            if status:
                logger.info(status)
            else:
                error = graceful_get(json_e, "error")
                logger.error(status)
                raise ConuException("There was an error while pulling the image %s: %s",
                                    self.name, error)
        self.using_transport(SkopeoTransport.DOCKER_DAEMON)
Example #11
0
    def pull(self):
        """
        Pull this image from registry. Raises an exception if the image is not found in
        the registry.

        :return: None
        """
        for json_s in self.d.pull(repository=self.name, tag=self.tag, stream=True):
            logger.debug(json_s)
            json_e = json.loads(json_s)
            status = graceful_get(json_e, "status")
            if status:
                logger.info(status)
            else:
                error = graceful_get(json_e, "error")
                logger.error(status)
                raise ConuException("There was an error while pulling the image %s: %s",
                                    self.name, error)
Example #12
0
    def get_id(self):
        """
        get unique identifier of this container

        :return: str
        """
        if self._id is None:
            self._id = graceful_get(self.inspect(refresh=False), "ContainerID")
        return self._id
Example #13
0
File: image.py Project: r00ta/conu
    def get_id(self):
        """
        get unique identifier of this image

        :return: str
        """
        if self._id is None:
            self._id = graceful_get(self.inspect(refresh=False), "Id")
        return self._id
Example #14
0
    def get_metadata(self):
        """
        Convert dictionary returned after podman inspect command into instance of ContainerMetadata class
        :return: ContainerMetadata, container metadata instance
        """
        if self._metadata is None:
            inspect_data = self.inspect(refresh=True)
            self._metadata = buildah_container_inspect_to_metadata(inspect_data)

            # this is a hack to avoid circular imports: feel free to fix it
            if self.ImageClass:
                image_id = graceful_get(inspect_data, "FromImageID")
                image_name = graceful_get(inspect_data, "FromImage")
                if image_name:
                    image_repo, tag = parse_reference(image_name)
                else:
                    image_repo, tag = None, None
                self._metadata.image = self.ImageClass(image_repo, tag=tag, identifier=image_id)
        return self._metadata
Example #15
0
    def is_running(self):
        """
        returns True if the container is running

        :return: bool
        """
        try:
            return graceful_get(self.inspect(refresh=True), "State", "Running")
        except subprocess.CalledProcessError:
            return False
Example #16
0
    def get_ports(self):
        """
        get ports specified in container metadata

        :return: list of str
        """
        ports = []
        container_ports = graceful_get(self.inspect(refresh=True),
                                       "NetworkSettings", "Ports")
        if not container_ports:
            return ports
        for p in container_ports:
            # TODO: gracefullness, error handling
            ports.append(p.split("/")[0])
        return ports
def inspect_to_metadata(metadata_object, inspect_data):
    """
    process data from `docker inspect` and update provided metadata object

    :param metadata_object: instance of Metadata
    :param inspect_data: dict, metadata from `docker inspect` or `dockert_client.images()`
    :return: instance of Metadata
    """
    identifier = graceful_get(inspect_data, 'Id')
    if identifier:
        if ":" in identifier:
            # format of image name from docker inspect:
            # sha256:8f0e66c924c0c169352de487a3c2463d82da24e9442fc097dddaa5f800df7129
            metadata_object.identifier = identifier.split(':')[1]
        else:
            # container
            metadata_object.identifier = identifier

    # format of Environment Variables from docker inspect:
    # ['DISTTAG=f26container', 'FGC=f26']
    raw_env_vars = graceful_get(inspect_data, "Config", "Env") or []
    if raw_env_vars:
        metadata_object.env_variables = {}
        for env_variable in raw_env_vars:
            splits = env_variable.split("=", 1)
            name = splits[0]
            value = splits[1] if len(splits) > 1 else None
            if value is not None:
                metadata_object.env_variables.update({name: value})

    raw_exposed_ports = graceful_get(inspect_data, "Config", "ExposedPorts")
    if raw_exposed_ports:
        metadata_object.exposed_ports = list(raw_exposed_ports.keys())

    # specific to images
    raw_repo_tags = graceful_get(inspect_data, 'RepoTags')
    if raw_repo_tags:
        metadata_object.name = raw_repo_tags[0]
    metadata_object.labels = graceful_get(inspect_data, 'Config', 'Labels')
    metadata_object.command = graceful_get(inspect_data, 'Config', 'Cmd')
    metadata_object.creation_timestamp = inspect_data.get('Created', None)
    # specific to images
    metadata_object.image_names = inspect_data.get('RepoTags', None)
    # specific to images
    digests = inspect_data.get("RepoDigests", None)
    if digests:
        metadata_object.repo_digests = digests
        metadata_object.digest = digests[0]

    return metadata_object
Example #18
0
    def get_port_mappings(self, port=None):
        """
        Get list of port mappings between container and host. The format of dicts is:

            {"HostIp": XX, "HostPort": YY};

        When port is None - return all port mappings. The container needs
        to be running, otherwise this returns an empty list.

        :param port: int or None, container port
        :return: list of dict or None; dict when port=None
        """
        port_mappings = graceful_get(self.inspect(refresh=True),
                                     "NetworkSettings", "Ports")

        if not port:
            return port_mappings

        if str(port) not in self.get_ports():
            return []

        for p in port_mappings:
            if p.split("/")[0] == str(port):
                return port_mappings[p]
Example #19
0
File: image.py Project: r00ta/conu
    def run_via_binary_in_foreground(self,
                                     run_command_instance=None,
                                     command=None,
                                     volumes=None,
                                     additional_opts=None,
                                     popen_params=None,
                                     container_name=None):
        """
        Create a container using this image and run it in foreground;
        this method is useful to test real user scenarios when users invoke containers using
        binary and pass input into the container via STDIN. You are also responsible for:

         * redirecting STDIN when intending to use container.write_to_stdin afterwards by setting
              popen_params={"stdin": subprocess.PIPE} during run_via_binary_in_foreground

         * checking whether the container exited successfully via:
              container.popen_instance.returncode

        Please consult the documentation for subprocess python module for best practices on
        how you should work with instance of Popen

        :param run_command_instance: instance of PodmanRunBuilder
        :param command: list of str, command to run in the container, examples:
            - ["ls", "/"]
            - ["bash", "-c", "ls / | grep bin"]
        :param volumes: tuple or list of tuples in the form:

            * `("/path/to/directory", )`
            * `("/host/path", "/container/path")`
            * `("/host/path", "/container/path", "mode")`
            * `(conu.Directory('/host/path'), "/container/path")` (source can be also
                Directory instance)

        :param additional_opts: list of str, additional options for `docker run`
        :param popen_params: dict, keyword arguments passed to Popen constructor
        :param container_name: str, pretty container identifier
        :return: instance of PodmanContainer
        """
        logger.info("run container via binary in foreground")

        if (command is not None or additional_opts is not None) \
                and run_command_instance is not None:
            raise ConuException(
                "run_command_instance and command parameters cannot be "
                "passed into method at same time")

        if run_command_instance is None:
            command = command or []
            additional_opts = additional_opts or []

            if (isinstance(command, list) or isinstance(command, tuple)
                    and isinstance(additional_opts, list)
                    or isinstance(additional_opts, tuple)):
                run_command_instance = PodmanRunBuilder(
                    command=command, additional_opts=additional_opts)
            else:
                raise ConuException(
                    "command and additional_opts needs to be list of str or None"
                )
        else:
            run_command_instance = run_command_instance or PodmanRunBuilder()
            if not isinstance(run_command_instance, PodmanRunBuilder):
                raise ConuException("run_command_instance needs to be an "
                                    "instance of PodmanRunBuilder")

        popen_params = popen_params or {}

        run_command_instance.image_name = self.get_id()
        if container_name:
            run_command_instance.options += ["--name", container_name]

        if volumes:
            run_command_instance.options += self.get_volume_options(
                volumes=volumes)

        def callback():
            return subprocess.Popen(run_command_instance.build(),
                                    **popen_params)

        container_id, popen_instance = self._run_container(
            run_command_instance, callback)

        actual_name = graceful_get(self._inspect(container_id), "Name")

        if container_name and container_name != actual_name:
            raise ConuException(
                "Unexpected container name value. Expected = " +
                str(container_name) + " Actual = " + str(actual_name))
        if not container_name:
            container_name = actual_name
        return PodmanContainer(self,
                               container_id,
                               popen_instance=popen_instance,
                               name=container_name)
Example #20
0
File: image.py Project: r00ta/conu
    def run_via_binary(self,
                       run_command_instance=None,
                       command=None,
                       volumes=None,
                       additional_opts=None,
                       **kwargs):
        """
        create a container using this image and run it in background;
        this method is useful to test real user scenarios when users invoke containers using
        binary

        :param run_command_instance: instance of PodmanRunBuilder
        :param command: list of str, command to run in the container, examples:
            - ["ls", "/"]
            - ["bash", "-c", "ls / | grep bin"]
        :param volumes: tuple or list of tuples in the form:

            * `("/path/to/directory", )`
            * `("/host/path", "/container/path")`
            * `("/host/path", "/container/path", "mode")`
            * `(conu.Directory('/host/path'), "/container/path")` (source can be also
                Directory instance)

        :param additional_opts: list of str, additional options for `podman run`
        :return: instance of PodmanContainer
        """

        logger.info("run container via binary in background")

        if (command is not None or additional_opts is not None) \
                and run_command_instance is not None:
            raise ConuException(
                "run_command_instance and command parameters cannot be passed "
                "into method at same time")

        if run_command_instance is None:
            command = command or []
            additional_opts = additional_opts or []

            if (isinstance(command, list) or isinstance(command, tuple)
                    and isinstance(additional_opts, list)
                    or isinstance(additional_opts, tuple)):
                run_command_instance = PodmanRunBuilder(
                    command=command, additional_opts=additional_opts)
            else:
                raise ConuException(
                    "command and additional_opts needs to be list of str or None"
                )
        else:
            run_command_instance = run_command_instance or PodmanRunBuilder()
            if not isinstance(run_command_instance, PodmanRunBuilder):
                raise ConuException(
                    "run_command_instance needs to be an instance of PodmanRunBuilder"
                )

        run_command_instance.image_name = self.get_id()
        run_command_instance.options += ["-d"]

        if volumes:
            run_command_instance.options += self.get_volume_options(
                volumes=volumes)

        def callback():
            try:
                # FIXME: catch std{out,err}, print stdout to logger.debug, stderr to logger.error
                run_cmd(run_command_instance.build())
            except subprocess.CalledProcessError as ex:
                raise ConuException("Container exited with an error: %s" %
                                    ex.returncode)

        container_id, _ = self._run_container(run_command_instance, callback)
        container_name = graceful_get(self._inspect(container_id), "Name")

        return PodmanContainer(self, container_id, name=container_name)
Example #21
0
def inspect_to_container_metadata(c_metadata_object, inspect_data,
                                  image_instance):
    """
    process data from `podman container inspect` and update provided container metadata object

    :param c_metadata_object: instance of ContainerMetadata
    :param inspect_data: dict, metadata from `podman inspect`
    :param image_instance: instance of PodmanImage
    :return: instance of ContainerMetadata
    """
    inspect_to_metadata(c_metadata_object, inspect_data)

    # FIXME: Rename this function to be universal?
    status = ContainerStatus.get_from_docker(
        graceful_get(inspect_data, "State", "Status"),
        graceful_get(inspect_data, "State", "ExitCode"),
    )

    image_id = graceful_get(inspect_data, "Image")
    if image_id:
        if ":" in image_id:
            # format of image name from podman inspect:
            # sha256:8f0e66c924c0c169352de487a3c2463d82da24e9442fc097dddaa5f800df7129
            image_instance.identifier = image_id.split(':')[1]
        else:
            # container
            image_instance.identifier = image_id

    # format of Port mappings from docker inspect:
    # {'12345/tcp': [
    #   {'HostIp': '0.0.0.0', 'HostPort': '123'},
    #   {'HostIp': '0.0.0.0', 'HostPort': '1234'}]}
    port_mappings = dict()

    raw_port_mappings = graceful_get(inspect_data, 'HostConfig',
                                     'PortBindings') or {}

    for key, value in raw_port_mappings.items():
        for item in value:
            logger.debug("parsing ports: key = %s, item = %s", key, item)
            li = port_mappings.get(key, [])
            raw_host_port = item['HostPort']
            if raw_host_port == "":
                int_port = None
            else:
                try:
                    int_port = int(raw_host_port)
                except ValueError as ex:
                    logger.error("could not parse port: %s", ex)
                    continue
            li.append(int_port)
            port_mappings.update({key: li})

    raw_port_mappings = graceful_get(inspect_data, "NetworkSettings", "Ports")
    c_metadata_object.port_mappings = {
        d["containerPort"]: [
            p["hostPort"] for p in raw_port_mappings
            if p["containerPort"] == d["containerPort"]
        ]
        for d in raw_port_mappings
    }

    c_metadata_object.status = status
    c_metadata_object.hostname = graceful_get(inspect_data, 'Config',
                                              'Hostname')

    # TODO: Make it work not only with one IP address
    c_metadata_object.ipv4_addresses = [
        graceful_get(inspect_data, "NetworkSettings", "IPAddress")
    ]
    c_metadata_object.ipv6_addresses = [
        graceful_get(inspect_data, "NetworkSettings", "GlobalIPv6Address")
    ]

    c_metadata_object.image = image_instance
    name = graceful_get(inspect_data, "Name")
    if name:
        name = name[1:] if name.startswith(
            "/") else name  # remove / at the beginning
        c_metadata_object.name = name
    return c_metadata_object
Example #22
0
def test_graceful_get():
    assert graceful_get({"a": [{1: 2}, {"b": "c"}]}, "a", 1, "b") == "c"