def test_run_cmd():
    ret = run_cmd(
        ["sh", "-c", "for x in `seq 1 5`; do echo $x; sleep 0.01; done"])
    assert not ret

    ret = run_cmd(
        ["sh", "-c", "for x in `seq 1 5`; do echo $x; sleep 0.01; done"],
        return_output=True)
    assert ret == '1\n2\n3\n4\n5\n'

    with pytest.raises(subprocess.CalledProcessError) as excinfo:
        ret = run_cmd(["sh", "-c", "exit 5"])
        assert not ret
    assert excinfo.value.returncode == 5

    ret = run_cmd(["sh", "-c", "exit 5"], ignore_status=True)
    assert ret == 5
Example #2
0
 def __enter__(self):
     # TODO RFE: use libguestfs if possible
     # TODO: allow pass partition number to mount exact partition of disc
     self.loopdevice = run_cmd(
         ["losetup", "--show", "-f", self.image.local_location],
         return_output=True).strip()
     run_cmd(["partprobe", self.loopdevice])
     partitions = glob.glob("{}*".format(self.loopdevice))
     for part in partitions:
         try:
             run_cmd(["mount", part, self.mount_point])
             return super(NspawnImageFS, self).__enter__()
         except Exception as e:
             logger.debug(
                 ConuException(
                     "unable to mount partition {}".format(part),
                     e))
Example #3
0
    def machined_restart():
        """
        Workaround for systemd when machined is blocked on D-bus

        :return: int: return code
        """
        logger.debug("restart systemd-machined")
        return run_cmd("systemctl restart systemd-machined", ignore_status=True)
Example #4
0
File: image.py Project: pingf/conu
    def rmi(self, force=False, via_name=False):
        """
        remove this image

        :param force: bool, force removal of the image
        :param via_name: bool, refer to the image via name, if false, refer via ID, not used now
        :return: None
        """
        return run_cmd(["machinectl", "--no-pager", "remove", self.get_id()])
Example #5
0
    def mount(self, mount_point=None):
        """
        mount container filesystem

        :return: str, the location of the mounted file system
        """
        cmd = ["podman", "mount", self._id or self.get_id()]
        output = run_cmd(cmd, return_output=True).rstrip("\n\r")
        return output
Example #6
0
 def _list_all_podman_images():
     """
     Finds all podman containers
     :return: list of dicts with image info
     """
     cmdline = ["podman", "images", "--format", "json"]
     output = run_cmd(cmdline, return_output=True)
     images = json.loads(output)
     return images
Example #7
0
    def extend(self, source, new_image_name, s2i_args=None):
        """
        extend this s2i-enabled image using provided source, raises ConuException if
        `s2i build` fails

        :param source: str, source used to extend the image, can be path or url
        :param new_image_name: str, name of the new, extended image
        :param s2i_args: list of str, additional options and arguments provided to `s2i build`
        :return: S2Image instance
        """
        s2i_args = s2i_args or []
        c = self._s2i_command(["build"] + s2i_args + [source, self.get_full_name()])
        if new_image_name:
            c.append(new_image_name)
        try:
            run_cmd(c)
        except subprocess.CalledProcessError as ex:
            raise ConuException("s2i build failed: %s" % ex)
        return S2IDockerImage(new_image_name)
Example #8
0
 def _list_podman_containers(filter=None):
     """
     Finds podman containers by filter or all containers
     :return: list of dicts with containers info
     """
     option = ["--filter", filter] if filter else ["-a"]
     cmdline = ["podman", "ps"] + option + ["--format", "json"]
     output = run_cmd(cmdline, return_output=True)
     containers = json.loads(output)
     return containers
Example #9
0
    def mount(self, mount_point=None):
        """
        mount container filesystem

        :return: str, the location of the mounted file system
        """
        # TODO: In rootless mode you must use buildah unshare first.
        cmd = ["buildah", "mount", self._id or self.get_id()]
        output = run_cmd(cmd, return_output=True).rstrip("\n\r")
        return output
Example #10
0
    def copy(self,
             repository=None,
             tag=None,
             source_transport=None,
             target_transport=SkopeoTransport.DOCKER,
             source_path=None,
             target_path=None,
             logs=True):
        """ Copy this image

        :param repository to be copied to
        :param tag
        :param source_transport Transport
        :param target_transport Transport
        :param source_path needed to specify for dir, docker-archive or oci transport
        :param target_path needed to specify for dir, docker-archive or oci transport
        :param logs enable/disable logs
        :return: the new DockerImage
        """
        if not repository:
            repository = self.name
        if not tag:
            tag = self.tag if self.tag else "latest"
        if target_transport == SkopeoTransport.OSTREE and tag and logs:
            logging.warning("tag was ignored")
        target = (DockerImage(
            repository, tag,
            pull_policy=DockerImagePullPolicy.NEVER).using_transport(
                target_transport, target_path))
        self.using_transport(source_transport, source_path)

        try:
            run_cmd([
                "skopeo", "copy",
                transport_param(self),
                transport_param(target)
            ])
        except subprocess.CalledProcessError:
            raise ConuException("There was an error while copying repository",
                                self.name)

        return target
Example #11
0
    def wait(self, timeout=None):
        """
        Block until the container stops, then return its exit code. Similar to
        the ``podman wait`` command.

        :param timeout: int, microseconds to wait before polling for completion
        :return: int, exit code
        """
        timeout = ["--interval=%s" % timeout] if timeout else []
        cmdline = ["podman", "wait"] + timeout + [self._id or self.get_id()]
        return run_cmd(cmdline, return_output=True)
Example #12
0
    def execute(self, command):
        """
        Execute a command in this container -- the container needs to be running.

        :param command: list of str, command to execute in the container
        :return: str
        """
        logger.info("running command %s", command)
        cmd = ["podman", "exec", self.get_id()] + command
        output = run_cmd(cmd, return_output=True)
        return output
Example #13
0
    def get_layer_ids(self, rev=True):
        """
        Get IDs of image layers

        :param rev: get layers reversed
        :return: list of strings
        """
        cmdline = ["podman", "history", "--format", "{{.ID}}", self._id or self.get_id()]
        layers = [layer for layer in run_cmd(cmdline, return_output=True)]
        if not rev:
            layers = layers.reverse()
        return layers
Example #14
0
    def _systemctl_wait_until_finish(self, machine, unit):
        """
        Internal method
        workaround for systemd-run without --wait option
        see  _run_systemdrun_decide method

        :param machine:
        :param unit:
        :return:
        """
        while True:
            metadata = convert_kv_to_dict(
                run_cmd(
                    ["systemctl", "--no-pager", "show", "-M", machine, unit],
                    return_output=True))
            if not metadata["SubState"] in ["exited", "failed"]:
                time.sleep(0.1)
            else:
                break
        run_cmd(["systemctl", "--no-pager", "-M", machine, "stop", unit], ignore_status=True)
        return metadata["ExecMainStatus"]
Example #15
0
    def _run_systemdrun_decide(self):
        """
        Internal method
        decide if it is possible to use --wait option to systemd
        for example RHEL7 does not support --wait option

        :return: bool
        """
        if self.systemd_wait_support is None:
            self.systemd_wait_support = "--wait" in run_cmd(
                ["systemd-run", "--help"], return_output=True)
        return self.systemd_wait_support
Example #16
0
    def _set_selinux_context(self):
        """
        set SELinux context or fields using chcon program

        :return: None
        """
        # FIXME: do this using python API if possible
        if self.selinux_context:
            logger.debug("setting SELinux context of %s to %s", self.path, self.selinux_context)
            run_cmd(["chcon", self.selinux_context, self.path])
        if any([self.selinux_user, self.selinux_role, self.selinux_type, self.selinux_range]):
            logger.debug("setting SELinux fields of %s", self.path, self.selinux_context)
            # chcon [OPTION]... [-u USER] [-r ROLE] [-l RANGE] [-t TYPE] FILE...
            pairs = [("-u", self.selinux_user), ("-r", self.selinux_role),
                     ("-l", self.selinux_range), ("-t", self.selinux_type)]
            c = ["chcon"]
            for p in pairs:
                if p[1]:
                    c += p
            c += [self.path]
            run_cmd(c)
Example #17
0
    def execute(self, command, options=None, **kwargs):
        """
        Execute a command in this container

        :param command: list of str, command to execute in the container
        :param options: list of str, additional options to run command
        :return: str
        """
        options = options or []
        logger.info("running command %s", command)
        cmd = ["buildah", "run"] + options + [self.get_id()] + command
        output = run_cmd(cmd, return_output=True)
        return output
Example #18
0
    def pull(self):
        """
        Pull this image from URL.

        :return: None
        """
        if not os.path.exists(CONU_IMAGES_STORE):
            os.makedirs(CONU_IMAGES_STORE)
        logger.debug(
            "Try to pull: {} -> {}".format(self.location, self.local_location))

        if not self._is_local():
            compressed_location = self.local_location + ".xz"
            run_cmd(["curl", "-f", "-L", "-o", compressed_location, self.location])
            run_cmd(["xz", "-d", compressed_location])
        else:
            if self.location.endswith("xz"):
                compressed_location = self.local_location + ".xz"
                run_cmd(["cp", self.location, compressed_location])
                run_cmd(["xz", "-d", compressed_location])
            else:
                run_cmd(["cp", self.location, self.local_location])
Example #19
0
 def get_status(self):
     """
     Get status of OpenShift cluster, similar to `oc status`
     :return: str
     """
     try:
         c = self._oc_command(["status"])
         o = run_cmd(c, return_output=True)
         for line in o.split('\n'):
             logger.debug(line)
         return o
     except subprocess.CalledProcessError as ex:
         raise ConuException("Cannot obtain OpenShift cluster status: %s" % ex)
Example #20
0
    def get_version(self):
        """
        return 3-tuple of version info or None

        :return: (str, str, str)
        """
        raw_version = run_cmd(["buildah", "version"], return_output=True)
        regex = re.compile(r"Version:\s*(\d+)\.(\d+)\.(\d+)")
        match = regex.findall(raw_version)
        try:
            return match[0]
        except IndexError:
            logger.error("unable to parse version from `buildah version`")
            return
Example #21
0
    def umount(self, all=False):
        """
        unmount container filesystem

        :param all: bool, option to unmount all mounted containers
        :return: str, the output from cmd
        """
        options = []
        if all:
            options.append('--all')
        cmd = ["buildah", "umount"] + options
        if not all:
            cmd += [self.get_id()]
        return run_cmd(cmd, return_output=True)
Example #22
0
    def create_app_from_template(self,
                                 image_name,
                                 name,
                                 template,
                                 name_in_template,
                                 other_images=None,
                                 oc_new_app_args=None,
                                 project=None):
        """Helper function to create app from template

        :param image_name: image to be used as builder image
        :param name: name of app from template
        :param template: str, url or local path to a template to use
        :param name_in_template: dict, {repository:tag} image name used in the template
        :param other_images: list of dict, some templates need other image to be pushed into the
               OpenShift registry, specify them in this parameter as list of dict [{<image>:<tag>}],
               where "<image>" is image name with tag and "<tag>" is a tag under which the image
               should be available in the OpenShift registry.
        :param oc_new_app_args: additional parameters for the `oc new-app`
        :param project: project where app should be created, default: current project
        :return: None
        """
        self.project = project or self.get_current_project()
        oc_new_app_args = oc_new_app_args or []

        # push images to registry
        repository, tag = list(name_in_template.items())[0]
        self.import_image(repository + ":" + tag, image_name)

        other_images = other_images or []

        for o in other_images:
            image, tag = list(o.items())[0]
            self.import_image(
                tag.split(':')[0] + ":" + tag.split(':')[1], image)

        c = self._oc_command(["new-app"] + [template] + oc_new_app_args +
                             ["-n"] + [project] + ["--name=%s" % name])

        logger.info("Creating new app in project %s", project)

        try:
            # ignore status because sometimes oc new-app can fail when image
            # is already pushed in register
            o = run_cmd(c, return_output=True, ignore_status=True)
            logger.debug(o)
        except subprocess.CalledProcessError as ex:
            raise ConuException("oc new-app failed: %s" % ex)

        return name
Example #23
0
 def clean_project(self, app_name):
     """
     Delete all objects in current project in OpenShift cluster
     :return: None
     """
     logger.info('Deleting app')
     try:
         o = run_cmd(self._oc_command(
             ["delete", "all", "-l app=%s" % app_name]),
                     return_output=True)
         o_lines = o.split('\n')
         for line in o_lines:
             logger.info(line)
     except subprocess.CalledProcessError as ex:
         raise ConuException("Cleanup failed: %s" % ex)
Example #24
0
 def umount(self, all=False, force=True):
     """
     unmount container filesystem
     :param all: bool, option to unmount all mounted containers
     :param force: bool, force the unmounting of specified containers' root file system
     :return: str, the output from cmd
     """
     # FIXME: handle error if unmount didn't work
     options = []
     if force:
         options.append('--force')
     if all:
         options.append('--all')
     cmd = ["podman", "umount"
            ] + options + [self.get_id() if not all else ""]
     return run_cmd(cmd, return_output=True)
Example #25
0
File: image.py Project: pingf/conu
 def _wait_for_machine_finish(self, name):
     """
     Interna method
     wait until machine is really destroyed, machine does not exist.
     :param name: str machine name
     :return: True or exception
     """
     # TODO: rewrite it using probes module in utils
     for foo in range(constants.DEFAULT_RETRYTIMEOUT):
         time.sleep(constants.DEFAULT_SLEEP)
         out = run_cmd(["machinectl", "--no-pager", "status", name],
                       ignore_status=True,
                       return_output=True)
         if out != 0:
             return True
     raise ConuException("Unable to stop machine %s within %d" %
                         (name, constants.DEFAULT_RETRYTIMEOUT))
Example #26
0
    def list_containers(self):
        """
        list all available nspawn containers

        :return: collection of instances of :class:`conu.backend.nspawn.container.NspawnContainer`
        """
        data = run_cmd(["machinectl", "list", "--no-legend", "--no-pager"],
                       return_output=True)
        output = []
        reg = re.compile(r"\s+")
        for line in data.split("\n"):
            stripped = line.strip()
            if stripped:
                parts = reg.split(stripped)
                name = parts[0]
                output.append(self.ContainerClass(None, None, name=name))
        return output
Example #27
0
    def get_current_project(self):
        """
        Get name of current project using `oc project` command.
        Raise ConuException in case of an error.
        :return: str, project name
        """

        try:
            command = self._oc_command(["project", "-q"])
            output = run_cmd(command, return_output=True)
        except subprocess.CalledProcessError as ex:
            raise ConuException("Failed to obtain current project name : %s" % ex)

        try:
            return output.rstrip()  # remove '\n'
        except IndexError:
            raise ConuException("Failed to obtain project name")
Example #28
0
    def _list_all_buildah_images():
        """
        List all buildah images

        sample image:
        "id": "9754ce14641df7f1f3751d21e14b3037dce7dca2472cf4cdff38d96891703453",
        "names": [
            "docker.io/library/fedora:30"
        ]

        :return: list of dicts with image info
        """
        cmdline = ["buildah", "images", "--json"]
        output = run_cmd(cmdline, return_output=True)
        images = json.loads(output)
        if not images:
            return []
        return images
Example #29
0
    def get_metadata(self, refresh=True):
        """
        return cached metadata by default

        :param refresh: bool, returns up to date metadata if set to True
        :return: dict
        """
        if refresh or not self._metadata:
            ident = self._id or self.name
            if not ident:
                raise ConuException(
                    "This container does not have a valid identifier.")
            out = run_cmd(["machinectl", "--no-pager", "show", ident], return_output=True, ignore_status=True)
            if "Could not get path to machine" in out:
                self._metadata = {}
            else:
                self._metadata = convert_kv_to_dict(out)
        return self._metadata
Example #30
0
    def system_requirements():
        """
        Check if all necessary packages are installed on system

        :return: None or raise exception if some tooling is missing
        """
        command_exists("systemd-nspawn",
            ["systemd-nspawn", "--version"],
            "Command systemd-nspawn does not seems to be present on your system"
            "Do you have system with systemd")
        command_exists(
            "machinectl",
            ["machinectl", "--no-pager", "--help"],
            "Command machinectl does not seems to be present on your system"
            "Do you have system with systemd")
        if "Enforcing" in run_cmd(["getenforce"], return_output=True, ignore_status=True):
            logger.error("Please disable selinux (setenforce 0), selinux blocks some nspawn operations"
                         "This may lead to strange behaviour")