Exemple #1
0
    def run(self, connection, max_end_time, args=None):
        # substitutions
        substitutions = {'{emptyimage}': self.get_namespace_data(action='prepare-empty-image', label='prepare-empty-image', key='output')}
        sub_command = self.get_namespace_data(action='prepare-qemu-commands', label='prepare-qemu-commands', key='sub_command')
        sub_command = substitute(sub_command, substitutions)
        command_line = ' '.join(sub_command)

        commands = []
        # get the download args in run()
        image_arg = self.get_namespace_data(action='download-action', label='iso', key='image_arg')
        action_arg = self.get_namespace_data(action='download-action', label='iso', key='file')
        substitutions["{%s}" % 'iso'] = action_arg
        commands.append(image_arg)
        command_line += ' '.join(substitute(commands, substitutions))

        preseed_file = self.get_namespace_data(action='download-action', label='file', key='preseed')
        if not preseed_file:
            raise JobError("Unable to identify downloaded preseed filename.")
        substitutions = {'{preseed}': preseed_file}
        append_args = self.get_namespace_data(action='prepare-qemu-commands', label='prepare-qemu-commands', key='append')
        append_args = substitute([append_args], substitutions)
        command_line += ' '.join(append_args)

        self.logger.info(command_line)
        shell = ShellCommand(command_line, self.timeout, logger=self.logger)
        if shell.exitstatus:
            raise JobError("%s command exited %d: %s" % (sub_command[0], shell.exitstatus, shell.readlines()))
        self.logger.debug("started a shell command")

        shell_connection = ShellSession(self.job, shell)
        shell_connection.prompt_str = self.get_namespace_data(
            action='prepare-qemu-commands', label='prepare-qemu-commands', key='prompts')
        shell_connection = super(IsoCommandLine, self).run(shell_connection, max_end_time, args)
        return shell_connection
Exemple #2
0
    def run(self, connection, max_end_time):
        start = time.time()

        if not self.local_docker_image:
            self.logger.debug("Pulling image %s", self.docker_image)
            self.run_cmd(["docker", "pull", self.docker_image])

        fvp_arguments = self.parameters.get("version_args", "--version")

        # Build the command line
        # The docker image is safe to be included in the command line
        cmd = self.construct_docker_fvp_command(self.docker_image, fvp_arguments)

        self.logger.debug("Boot command: %s", cmd)
        shell = ShellCommand(cmd, self.timeout, logger=self.logger)

        shell_connection = ShellSession(self.job, shell)
        shell_connection = super().run(shell_connection, max_end_time)

        # Wait for the version
        shell_connection.prompt_str = self.fvp_version_string
        self.wait(shell_connection)
        matched_version_string = shell_connection.raw_connection.match.group()
        result = {
            "definition": "lava",
            "case": "fvp-version",
            "level": self.level,
            "extra": {"fvp-version": matched_version_string},
            "result": "pass",
            "duration": "%.02f" % (time.time() - start),
        }
        self.logger.results(result)

        return shell_connection
Exemple #3
0
    def run(self, connection, max_end_time, args=None):
        """
        qemu needs help to reboot after running the debian installer
        and typically the boot is quiet, so there is almost nothing to log.
        """
        base_image = self.get_namespace_data(action='prepare-empty-image', label='prepare-empty-image', key='output')
        self.sub_command.append('-drive format=raw,file=%s' % base_image)
        guest = self.get_namespace_data(action='apply-overlay-guest', label='guest', key='filename')
        if guest:
            self.logger.info("Extending command line for qcow2 test overlay")
            self.sub_command.append('-drive format=qcow2,file=%s,media=disk' % (os.path.realpath(guest)))
            # push the mount operation to the test shell pre-command to be run
            # before the test shell tries to execute.
            shell_precommand_list = []
            mountpoint = self.get_namespace_data(action='test', label='results', key='lava_test_results_dir')
            shell_precommand_list.append('mkdir %s' % mountpoint)
            shell_precommand_list.append('mount -L LAVA %s' % mountpoint)
            self.set_namespace_data(action='test', label='lava-test-shell', key='pre-command-list', value=shell_precommand_list)

        self.logger.info("Boot command: %s", ' '.join(self.sub_command))
        shell = ShellCommand(' '.join(self.sub_command), self.timeout, logger=self.logger)
        if shell.exitstatus:
            raise JobError("%s command exited %d: %s" % (self.sub_command, shell.exitstatus, shell.readlines()))
        self.logger.debug("started a shell command")

        shell_connection = ShellSession(self.job, shell)
        shell_connection = super(IsoRebootAction, self).run(shell_connection, max_end_time, args)
        shell_connection.prompt_str = [INSTALLER_QUIET_MSG]
        self.wait(shell_connection)
        self.set_namespace_data(action='shared', label='shared', key='connection', value=shell_connection)
        return shell_connection
Exemple #4
0
    def run(self, connection, max_end_time):
        connection = super().run(connection, max_end_time)

        # Build the substitutions dictionary
        substitutions = {}
        paths = set()
        for action in self.get_namespace_keys("download-action"):
            filename = self.get_namespace_data(action="download-action",
                                               label=action,
                                               key="file")
            if filename is None:
                self.logger.warning(
                    "Empty value for action='download-action' label='%s' key='file'",
                    action,
                )
                continue
            substitutions["{%s}" % action.upper()] = filename
            paths.add(os.path.dirname(filename))

        # If needed, prepend with docker
        if self.container is None:
            cmd = self.gdb
        else:
            cmd = "docker run --rm -it --name lava-%s-%s" % (
                self.job.job_id,
                self.level,
            )
            for path in paths:
                cmd += " --volume %s:%s" % (path, path)
            for device in self.devices:
                cmd += " --device %s:%s:rw" % (device, device)
            cmd += " %s %s" % (self.container, self.gdb)

        for arg in substitute(self.arguments, substitutions):
            cmd += " " + arg

        # Start gdb
        self.logger.info("Starting gdb: %s", cmd)
        shell = ShellCommand(cmd, self.timeout, logger=self.logger)
        gdb = ShellSession(self.job, shell)
        gdb.prompt_str = "\\(gdb\\) "
        self.gdb_connection = gdb
        self.gdb_connection.wait()

        # Send all gdb commands
        for cmd in substitute(self.commands, substitutions):
            self.gdb_connection.sendline(cmd)
            self.gdb_connection.wait()

        # "continue" is send last
        if self.wait_before_continue:
            self.logger.debug("Sleeping %ss before sending 'continue'",
                              self.wait_before_continue)
            time.sleep(self.wait_before_continue)
        self.gdb_connection.sendline("continue")

        return connection
Exemple #5
0
    def run(self, connection, max_end_time):
        # substitutions
        substitutions = {
            "{emptyimage}":
            self.get_namespace_data(action="prepare-empty-image",
                                    label="prepare-empty-image",
                                    key="output")
        }
        sub_command = self.get_namespace_data(
            action="prepare-qemu-commands",
            label="prepare-qemu-commands",
            key="sub_command",
        )
        sub_command = substitute(sub_command, substitutions)
        command_line = " ".join(sub_command)

        commands = []
        # get the download args in run()
        image_arg = self.get_namespace_data(action="download-action",
                                            label="iso",
                                            key="image_arg")
        action_arg = self.get_namespace_data(action="download-action",
                                             label="iso",
                                             key="file")
        substitutions["{%s}" % "iso"] = action_arg
        commands.append(image_arg)
        command_line += " ".join(substitute(commands, substitutions))

        preseed_file = self.get_namespace_data(action="download-action",
                                               label="file",
                                               key="preseed")
        if not preseed_file:
            raise JobError("Unable to identify downloaded preseed filename.")
        substitutions = {"{preseed}": preseed_file}
        append_args = self.get_namespace_data(action="prepare-qemu-commands",
                                              label="prepare-qemu-commands",
                                              key="append")
        append_args = substitute([append_args], substitutions)
        command_line += " ".join(append_args)

        self.logger.info(command_line)
        shell = ShellCommand(command_line, self.timeout, logger=self.logger)
        if shell.exitstatus:
            raise JobError(
                "%s command exited %d: %s" %
                (sub_command[0], shell.exitstatus, shell.readlines()))
        self.logger.debug("started a shell command")

        shell_connection = ShellSession(self.job, shell)
        shell_connection.prompt_str = self.get_namespace_data(
            action="prepare-qemu-commands",
            label="prepare-qemu-commands",
            key="prompts")
        shell_connection = super().run(shell_connection, max_end_time)
        return shell_connection
Exemple #6
0
    def run(self, connection, max_end_time, args=None):
        # substitutions
        substitutions = {
            '{emptyimage}':
            self.get_namespace_data(action='prepare-empty-image',
                                    label='prepare-empty-image',
                                    key='output')
        }
        sub_command = self.get_namespace_data(action='prepare-qemu-commands',
                                              label='prepare-qemu-commands',
                                              key='sub_command')
        sub_command = substitute(sub_command, substitutions)
        command_line = ' '.join(sub_command)

        commands = []
        # get the download args in run()
        image_arg = self.get_namespace_data(action='download-action',
                                            label='iso',
                                            key='image_arg')
        action_arg = self.get_namespace_data(action='download-action',
                                             label='iso',
                                             key='file')
        substitutions["{%s}" % 'iso'] = action_arg
        commands.append(image_arg)
        command_line += ' '.join(substitute(commands, substitutions))

        preseed_file = self.get_namespace_data(action='download-action',
                                               label='file',
                                               key='preseed')
        if not preseed_file:
            raise JobError("Unable to identify downloaded preseed filename.")
        substitutions = {'{preseed}': preseed_file}
        append_args = self.get_namespace_data(action='prepare-qemu-commands',
                                              label='prepare-qemu-commands',
                                              key='append')
        append_args = substitute([append_args], substitutions)
        command_line += ' '.join(append_args)

        self.logger.info(command_line)
        shell = ShellCommand(command_line, self.timeout, logger=self.logger)
        if shell.exitstatus:
            raise JobError(
                "%s command exited %d: %s" %
                (sub_command[0], shell.exitstatus, shell.readlines()))
        self.logger.debug("started a shell command")

        shell_connection = ShellSession(self.job, shell)
        shell_connection.prompt_str = self.get_namespace_data(
            action='prepare-qemu-commands',
            label='prepare-qemu-commands',
            key='prompts')
        shell_connection = super(IsoCommandLine,
                                 self).run(shell_connection, max_end_time,
                                           args)
        return shell_connection
Exemple #7
0
    def run(self, connection, max_end_time):
        # obtain lava overlay
        # start container
        # create USB device mapping to container
        # connect to container, and run lava-test-shell over it
        location = self.get_namespace_data(action="test",
                                           label="shared",
                                           key="location")
        overlay = self.get_namespace_data(
            action="test", label="results",
            key="lava_test_results_dir").strip("/")

        image = self.parameters["docker"]["image"]
        container = "lava-docker-test-shell-%s-%s" % (self.job.job_id,
                                                      self.level)

        board_id = self.get_board_id()
        device_info = {"board_id": board_id}
        add_device_container_mapping(
            job_id=self.job.job_id,
            device_info=device_info,
            container=container,
            container_type="docker",
            logging_info=self.get_logging_info(),
        )

        docker = DockerRun(image)
        docker.bind_mount(os.path.join(location, overlay), "/" + overlay)
        docker.interactive()
        docker.hostname("lava")
        docker.name(container)
        docker.environment("PS1", "docker-test-shell:$ ")
        if self.wait_for_device:
            devices = get_udev_devices(device_info=[device_info])
            for dev in devices:
                docker.add_device(dev)

        docker_cmd = docker.cmdline("bash", "--norc", "-i")

        cmd = " ".join([shlex.quote(s) for s in docker_cmd])
        self.logger.debug("Starting docker test shell container: %s" % cmd)
        shell = ShellCommand(cmd, self.timeout, logger=self.logger)

        shell_connection = ShellSession(self.job, shell)
        shell_connection.prompt_str = "docker-test-shell:"

        self.__set_connection__(shell_connection)
        super().run(shell_connection, max_end_time)

        # finish the container
        shell_connection.finalise()

        # return the original connection untouched
        self.__set_connection__(connection)
        return connection
Exemple #8
0
    def run(self, connection, max_end_time):
        """
        qemu needs help to reboot after running the debian installer
        and typically the boot is quiet, so there is almost nothing to log.
        """
        base_image = self.get_namespace_data(
            action="prepare-empty-image", label="prepare-empty-image", key="output"
        )
        self.sub_command.append("-drive format=raw,file=%s" % base_image)
        guest = self.get_namespace_data(
            action="apply-overlay-guest", label="guest", key="filename"
        )
        if guest:
            self.logger.info("Extending command line for qcow2 test overlay")
            self.sub_command.append(
                "-drive format=qcow2,file=%s,media=disk" % (os.path.realpath(guest))
            )
            # push the mount operation to the test shell pre-command to be run
            # before the test shell tries to execute.
            shell_precommand_list = []
            mountpoint = self.get_namespace_data(
                action="test", label="results", key="lava_test_results_dir"
            )
            shell_precommand_list.append("mkdir %s" % mountpoint)
            shell_precommand_list.append("mount -L LAVA %s" % mountpoint)
            self.set_namespace_data(
                action="test",
                label="lava-test-shell",
                key="pre-command-list",
                value=shell_precommand_list,
            )

        self.logger.info("Boot command: %s", " ".join(self.sub_command))
        shell = ShellCommand(
            " ".join(self.sub_command), self.timeout, logger=self.logger
        )
        if shell.exitstatus:
            raise JobError(
                "%s command exited %d: %s"
                % (self.sub_command, shell.exitstatus, shell.readlines())
            )
        self.logger.debug("started a shell command")

        shell_connection = ShellSession(self.job, shell)
        shell_connection = super().run(shell_connection, max_end_time)
        shell_connection.prompt_str = [INSTALLER_QUIET_MSG]
        self.wait(shell_connection)
        self.set_namespace_data(
            action="shared", label="shared", key="connection", value=shell_connection
        )
        return shell_connection
Exemple #9
0
    def run(self, connection, max_end_time):
        fvp_arguments = " ".join(self.parameters.get("arguments"))

        # Build the command line
        # The docker image is safe to be included in the command line
        cmd = self.construct_docker_fvp_command(self.docker_image,
                                                fvp_arguments)

        self.logger.debug("Boot command: %s", cmd)
        shell = ShellCommand(cmd, self.timeout, logger=self.logger)

        shell_connection = ShellSession(self.job, shell)
        shell_connection = super().run(shell_connection, max_end_time)

        # Wait for the console string
        shell_connection.prompt_str = self.fvp_console_string
        self.wait(shell_connection)
        # We should now have the matched output
        if "PORT" not in shell_connection.raw_connection.match.groupdict():
            raise JobError(
                "'console_string' should contain a regular expression section, such as '(?P<PORT>\\d+)' to extract the serial port of the FVP. Group name must be 'PORT'"
            )

        serial_port = shell_connection.raw_connection.match.groupdict()["PORT"]
        self.set_namespace_data(
            action=StartFVPAction.name,
            label="fvp",
            key="serial_port",
            value=serial_port,
        )
        self.logger.info("Found FVP port %s", serial_port)
        self.set_namespace_data(
            action=StartFVPAction.name,
            label="fvp",
            key="container",
            value=self.container,
        )
        # Although we don't require any more output on this connection,
        # discarding this may cause SIGHUPs to be sent to the model
        # which will terminate the model.
        self.shell = shell
        return shell_connection
Exemple #10
0
    def run(self, connection, max_end_time):
        # obtain lava overlay
        # start container
        # create USB device mapping to container
        # connect to container, and run lava-test-shell over it
        location = self.get_namespace_data(action="test",
                                           label="shared",
                                           key="location")
        overlay = self.get_namespace_data(
            action="test", label="results",
            key="lava_test_results_dir").strip("/")

        container = "lava-docker-test-shell-%s-%s" % (self.job.job_id,
                                                      self.level)

        docker = DockerRun.from_parameters(self.parameters["docker"])
        docker.prepare()
        docker.bind_mount(os.path.join(location, overlay), "/" + overlay)

        namespace = self.parameters.get("downloads-namespace",
                                        self.parameters.get("namespace"))
        if namespace:
            downloads_dir = pathlib.Path(
                self.job.tmp_dir) / "downloads" / namespace
            if downloads_dir.exists():
                docker.bind_mount(downloads_dir, LAVA_DOWNLOADS)

        for bind_mount in self.test_docker_bind_mounts:
            read_only = True if len(bind_mount) == 2 else False
            docker.bind_mount(bind_mount[0], bind_mount[1], read_only)

        docker.interactive()
        docker.tty()
        docker.hostname("lava")
        docker.name(container)
        docker.environment("PS1", "docker-test-shell:$ ")

        docker_cmd = docker.cmdline("bash", "--norc", "-i")

        cmd = " ".join([shlex.quote(s) for s in docker_cmd])
        self.logger.debug("Starting docker test shell container: %s" % cmd)
        shell = ShellCommand(cmd, self.timeout, logger=self.logger)

        shell_connection = ShellSession(self.job, shell)
        shell_connection.prompt_str = "docker-test-shell:"
        self.__set_connection__(shell_connection)

        self.add_device_container_mappings(container, "docker")

        devices = get_udev_devices(device_info=self.device_info,
                                   logger=self.logger,
                                   required=False)

        docker.wait()

        # share all the devices as there isn't a 1:1 relationship between
        # the trigger and actual sharing of the devices
        for dev in devices:
            if not os.path.islink(dev):
                self.trigger_share_device_with_container(dev)

        for dev in devices:
            docker.wait_file(dev)

        try:
            super().run(shell_connection, max_end_time)
        finally:
            # finish the container
            shell_connection.finalise()
            docker.destroy()

        # return the original connection untouched
        self.__set_connection__(connection)
        return connection
Exemple #11
0
    def run(self, connection, max_end_time):
        # obtain lava overlay
        # start container
        # create USB device mapping to container
        # connect to container, and run lava-test-shell over it
        location = self.get_namespace_data(action="test",
                                           label="shared",
                                           key="location")
        overlay = self.get_namespace_data(
            action="test", label="results",
            key="lava_test_results_dir").strip("/")

        container = "lava-docker-test-shell-%s-%s" % (self.job.job_id,
                                                      self.level)

        docker = DockerRun.from_parameters(self.parameters["docker"], self.job)
        docker.prepare()
        docker.bind_mount(os.path.join(location, overlay), "/" + overlay)

        docker_method_conf = (self.job.device["actions"].get("test", {}).get(
            "methods", {}).get("docker", {}))

        # Preprocess docker option list, to better support partial
        # overriding of them via device dict:
        # 1. Filter out None, to make it easier to template
        # YAML syntactic lists with Jinja2:
        # '- {{ some_opt_from_device_dict }}'
        # (if not default, will be set to None).
        # 2. Flatten sublists, `- ['--opt1', '--opt2']`.
        def preproc_opts(opts):
            res = []
            for o in opts:
                if o is None:
                    continue
                elif isinstance(o, list):
                    res += o
                else:
                    res.append(o)
            return res

        if "global_options" in docker_method_conf:
            docker.add_docker_options(
                *preproc_opts(docker_method_conf["global_options"]))
        if "options" in docker_method_conf:
            docker.add_docker_run_options(
                *preproc_opts(docker_method_conf["options"]))

        namespace = self.parameters.get("downloads-namespace",
                                        self.parameters.get("namespace"))
        if namespace:
            downloads_dir = pathlib.Path(
                self.job.tmp_dir) / "downloads" / namespace
            if downloads_dir.exists():
                docker.bind_mount(downloads_dir, LAVA_DOWNLOADS)

        for bind_mount in self.test_docker_bind_mounts:
            read_only = True if len(bind_mount) == 2 else False
            docker.bind_mount(bind_mount[0], bind_mount[1], read_only)

        docker.interactive()
        docker.tty()
        docker.name(container)
        docker.environment("PS1", "docker-test-shell:$ ")

        docker_cmd = docker.cmdline("bash", "--norc", "-i")

        cmd = " ".join([shlex.quote(s) for s in docker_cmd])
        self.logger.debug("Starting docker test shell container: %s" % cmd)
        shell = ShellCommand(cmd, self.timeout, logger=self.logger)

        shell_connection = ShellSession(self.job, shell)
        shell_connection.prompt_str = "docker-test-shell:"
        self.__set_connection__(shell_connection)

        self.add_device_container_mappings(container, "docker")

        devices = get_udev_devices(device_info=self.device_info,
                                   logger=self.logger,
                                   required=False)

        docker.wait(shell)

        # share all the devices as there isn't a 1:1 relationship between
        # the trigger and actual sharing of the devices
        for dev in devices:
            if not os.path.islink(dev):
                self.trigger_share_device_with_container(dev)

        for dev in devices:
            docker.wait_file(dev)

        try:
            super().run(shell_connection, max_end_time)
        finally:
            # finish the container
            shell_connection.finalise()
            docker.destroy()

        # return the original connection untouched
        self.__set_connection__(connection)
        return connection