Exemplo n.º 1
0
    def copy_from(self, src, dst=".", recursive=False, nonzero_e=tc.error_e):
        """
        Copy a file or tree with *SCP* from the target to the client

        :param str src: remote file or directory to copy
        :param str dst: (optional) destination file or directory
          (defaults to current working directory)
        :param bool recursive: (optional) copy recursively (needed for
          directories)

        :param tcfl.tc.exception nonzero_e: exception to raise in case of 
          non zero exit code.  Must be a subclass of :class:`tcfl.tc.exception`
          (i.e.: :class:`tcfl.tc.failed_e`,  :class:`tcfl.tc.error_e`,
          :class:`tcfl.tc.skip_e`, :class:`tcfl.tc.blocked_e`) or
          *None* (default) to not raise anything and just return the
          exit code.

        """
        self._tunnel()
        self.target.report_info("running SCP target:%s -> local:%s" %
                                (src, dst),
                                dlevel=1)
        options = "-v"
        if recursive:
            options += "r"
        try:
            env = dict(os.environ)
            if self.password:
                cmdline = ['sshpass', "-e"]
                env['SSHPASS'] = self.password
            else:
                cmdline = []
                options += "B"
            cmdline += \
                [ "scp", options, "-P", str(self._ssh_port) ] \
                + self._ssh_cmdline_options \
                + [ self.login + "@" + self._ssh_host + ":" + src, dst ]
            self.target.report_info("running SCP command: %s" %
                                    " ".join(cmdline),
                                    dlevel=2)
            self._known_hosts_wipe()
            s = subprocess.check_output(cmdline,
                                        stderr=subprocess.STDOUT,
                                        shell=False,
                                        env=env,
                                        encoding='utf-8')
        except subprocess.CalledProcessError as e:
            self._returncode_eval(e.returncode)
            commonl.raise_from(
                nonzero_e(
                    "failed SCP local:%s -> target:%s" % (src, dst),
                    dict(returncode=e.returncode,
                         output=e.output,
                         src=src,
                         dst=dst,
                         recursive=recursive,
                         ssh_cmd=" ".join(e.cmd),
                         target=self.target)), e)
        self.target.report_info("ran SCP target:%s -> local:%s" % (src, dst),
                                attachments=dict(output=s))
Exemplo n.º 2
0
    def copy_to(self, src, dst="", recursive=False, result_on_failure="error"):
        """
        Copy a file or tree with *SCP* to the target from the client

        :param str src: local file or directory to copy
        :param str dst: (optional) destination file or directoy
          (defaults to root's home directory)
        :param bool recursive: (optional) copy recursively (needed for
          directories)
        :param str result_on_failure: (optional) how shall a failure
          considered to be (errr|fail|blck|skip).
        """
        exc = self._result_e(result_on_failure)
        self._tunnel()
        self.target.report_info("running SCP %s %s" % (src, dst), dlevel=2)
        options = "-vB"
        if recursive:
            options += "r"
        try:
            s = subprocess.check_output(
                ["/usr/bin/scp", options, "-P",
                 "%s" % self._ssh_port] + self._ssh_cmdline_options +
                [src, self.login + "@" + self._ssh_host + ":" + dst],
                stderr=subprocess.STDOUT)
        except subprocess.CalledProcessError as e:
            commonl.raise_from(
                exc(
                    "scp to '%s' -> '%s' failed" % (src, dst),
                    dict(output=e.output,
                         src=src,
                         dst=dst,
                         recursive=recursive,
                         ssh_cmd=" ".join(e.cmd))), e)
        self.target.report_info("ran SCP %s %s" % (src, dst), dlevel=1)
        return s
Exemplo n.º 3
0
    def check_output(self, cmd, result_on_failure="error"):
        """
        Run a shell command over SSH, substituting any %(KEYWORD)[ds]
        field from the target's keywords in
        :attr:`tcfl.tc.target_c.kws`

        Similar to :func:`subprocess.check_output`

        :param str cmd: shell command to execute via SSH
        :param str result_on_failure: (optional) how shall a failure
          considered to be (errr|fail|blck|skip).
        :returns: exitcode
        """
        exc = self._result_e(result_on_failure)
        self._tunnel()
        _cmd = cmd % self.target.kws
        self.target.report_info("running SSH command '%s'" % _cmd, dlevel=2)
        try:
            s = subprocess.check_output(
                ["/usr/bin/ssh", "-p",
                 "%s" % self._ssh_port] + self._ssh_cmdline_options +
                [self.login + "@" + self._ssh_host, "-t", _cmd],
                stderr=subprocess.STDOUT)
        except subprocess.CalledProcessError as e:
            commonl.raise_from(
                exc("ssh command failed: %s" % cmd,
                    dict(output=e.output, ssh_cmd=" ".join(e.cmd), cmd=cmd)),
                e)
        self.target.report_info("ran SSH command '%s': %s" % (_cmd, s),
                                dlevel=1)
        return s
Exemplo n.º 4
0
    def copy_to(self, src, dst="", recursive=False, nonzero_e=tc.error_e):
        """Copy a file or tree with *SCP* to the target from the client

        :param str src: local file or directory to copy

          Note a relative path will be made relative to the location
          of the testscript, see :func:`testcase.relpath_to_abs
          <tcfl.tc.tc_c.relpath_to_abs>`.

        :param str dst: (optional) destination file or directoy
          (defaults to root's home directory)
        :param bool recursive: (optional) copy recursively (needed for
          directories)

        :param tcfl.tc.exception nonzero_e: exception to raise in case of 
          non zero exit code.  Must be a subclass of :class:`tcfl.tc.exception`
          (i.e.: :class:`tcfl.tc.failed_e`,  :class:`tcfl.tc.error_e`,
          :class:`tcfl.tc.skip_e`, :class:`tcfl.tc.blocked_e`) or
          *None* (default) to not raise anything and just return the
          exit code.

        """
        self._tunnel()
        self.target.report_info("running SCP local:%s -> target:%s" %
                                (src, dst),
                                dlevel=1)
        src = self.target.testcase.relpath_to_abs(src)
        options = "-vB"
        if recursive:
            options += "r"
        try:
            cmdline = \
                [ "/usr/bin/scp", options, "-P", "%s" % self._ssh_port] \
                + self._ssh_cmdline_options \
                + [ src, self.login + "@" + self._ssh_host + ":" + dst ]
            self.target.report_info("running SCP command: %s" %
                                    " ".join(cmdline),
                                    dlevel=2)
            s = subprocess.check_output(cmdline,
                                        stderr=subprocess.STDOUT,
                                        shell=False)
        except subprocess.CalledProcessError as e:
            self._returncode_eval(e.returncode)
            commonl.raise_from(
                nonzero_e(
                    "failed SCP local:%s -> target:%s" % (src, dst),
                    dict(returncode=e.returncode,
                         output=e.output,
                         src=src,
                         dst=dst,
                         recursive=recursive,
                         ssh_cmd=" ".join(e.cmd),
                         target=self.target)), e)
        self.target.report_info("ran SCP local:%s -> target:%s" % (src, dst),
                                attachments=dict(output=s))
Exemplo n.º 5
0
    def copy_from(self, src, dst = ".", recursive = False,
                  nonzero_e = tc.error_e):
        """
        Copy a file or tree with *SCP* from the target to the client

        :param str src: remote file or directory to copy
        :param str dst: (optional) destination file or directory
          (defaults to current working directory)
        :param bool recursive: (optional) copy recursively (needed for
          directories)

        :param tcfl.tc.exception nonzero_e: exception to raise in case of 
          non zero exit code.  Must be a subclass of :class:`tcfl.tc.exception`
          (i.e.: :class:`tcfl.tc.failed_e`,  :class:`tcfl.tc.error_e`,
          :class:`tcfl.tc.skip_e`, :class:`tcfl.tc.blocked_e`) or
          *None* (default) to not raise anything and just return the
          exit code.

        """
        self._tunnel()
        self.target.report_info("running SCP target:%s -> local:%s"
                                % (src, dst), dlevel = 1)
        options = "-vB"
        if recursive:
            options += "r"
        try:
            cmdline = \
                [ "/usr/bin/scp", options, "-P", "%s" % self._ssh_port] \
                + self._ssh_cmdline_options \
                + [self.login + "@" + self._ssh_host + ":" + src, dst ]
            self.target.report_info("running SCP command: %s"
                                    % " ".join(cmdline), dlevel = 2)
            s = subprocess.check_output(cmdline, stderr = subprocess.STDOUT)
        except subprocess.CalledProcessError as e:
            self._returncode_eval(e.returncode)
            commonl.raise_from(nonzero_e(
                "failed SCP local:%s -> target:%s" % (src, dst),
                dict(returncode = e.returncode,
                     output = e.output,
                     src = src, dst = dst, recursive = recursive,
                     ssh_cmd = " ".join(e.cmd),
                     target = self.target
                )), e)
        self.target.report_info("ran SCP target:%s -> local:%s" % (src, dst),
                                attachments = dict(output = s))
Exemplo n.º 6
0
    def _qemu_launch(self, bsp, kws):
        gdb_tcp_port = commonl.tcp_port_assigner(
            1, port_range=ttbl.config.tcp_port_range)
        self.fsdb.set("debug-%s-gdb-tcp-port" % bsp, "%s" % gdb_tcp_port)
        console_out_fname = os.path.join(self.state_dir,
                                         "console-%s.log" % bsp)
        errfname = os.path.join(self.state_dir, "%s-stderr.log" % bsp)
        try:
            # Make sure we wipe the PID file -- sometimes a pidfile is
            # left over and it seems to override it, so the reading
            # becomes corrupt
            commonl.rm_f(self.pidfile[bsp])
            qemu_cmdline = \
                (self.qemu_cmdlines[bsp] % kws).split() \
                + [
                    # Don't add -daemonize! This way this is part of
                    # the process tree and killed when we kill the
                    # parent process
                    # We use QMP to find the PTY assigned
                    "-qmp", "unix:%s.qmp,server,nowait" % self.pidfile[bsp],
                    # Always start in debug mode -- this way the
                    # whole thing is stopped until we unleash it
                    # with QMP; this allows us to first start
                    # daemons that we might need to start
                    "-S",
                    "-pidfile", self.pidfile[bsp],
                    "-gdb", "tcp:0.0.0.0:%d" % gdb_tcp_port,
                ]
            self.fsdb.set("qemu-cmdline-%s" % bsp, qemu_cmdline[0])
        except KeyError as e:
            msg = "bad QEMU command line specification: " \
                  "uninitialized key %s" % e
            self.log.error(msg)
            commonl.raise_from(RuntimeError(msg), e)
        self.log.debug("QEMU cmdline %s" % " ".join(qemu_cmdline))
        self.tags['bsps'][bsp]['cmdline'] = " ".join(qemu_cmdline)
        try:
            _preexec_fn = getattr(self, "qemu_preexec_fn", None)

            def _local_preexec_fn():
                if _preexec_fn:
                    _preexec_fn()
                    # Open file descriptors for stdout/stderr to a
                    # logfile, because -D is not really working. We
                    # need it to check startup errors for things that
                    # need a retry.
                commonl.rm_f(errfname)
                logfd = os.open(
                    errfname,
                    # O_CREAT: Always a new file, so
                    # we can check for errors and not
                    # get confused with previous runs
                    os.O_WRONLY | os.O_EXCL | os.O_CREAT,
                    0o0644)
                os.dup2(logfd, 1)
                os.dup2(logfd, 2)
                os.close(logfd)

            p = subprocess.Popen(qemu_cmdline,
                                 shell=False,
                                 cwd=self.state_dir,
                                 close_fds=True,
                                 preexec_fn=_local_preexec_fn)
            self.log.debug("QEMU %s: console @ %s" % (bsp, console_out_fname))
            # Give it a few secs to start, the pidfile has been
            # deleted before starting -- note 4 was found by
            # ad-hoc experimentation, sometimes depending on system load it
            # takes more or less.
            timeout = 10
            ts0 = time.time()
            while True:
                if time.time() - ts0 > timeout:
                    lines = []
                    with open(errfname) as f:
                        count = 0
                        for line in f:
                            lines.append("log: " + line)
                            if count > 5:
                                lines.append("log: ...")
                                break
                    raise RuntimeError("QEMU %s: did not start after %.0fs\n"
                                       "%s" % (bsp, timeout, "\n".join(lines)))
                try:
                    if self._qmp_running(bsp):
                        # FIXME: race condition
                        ttbl.daemon_pid_add(p.pid)
                        return True
                except RuntimeError as e:
                    self.log.warning("QEMU %s: can't read QMP: %s" %
                                     (bsp, str(e)))
                    # fall through, let it retry
                # Check errors during startup
                with open(errfname, "r") as logf:
                    causes_for_retry = [
                        # bah, race condition: since we chose the
                        # port we wanted to use and until we
                        # started using it someone took it. Retry
                        'Failed to bind socket: Address already in use',
                    ]
                    for line in logf:
                        for cause in causes_for_retry:
                            if cause in line:
                                self.log.info(
                                    "QEMU %s: retrying because found in "
                                    "logfile: %s", bsp, cause)
                                return False
                time.sleep(0.25)
                # nothing runs after this, either it returns or raises
        except (OSError, ValueError) as e:
            self.log.debug("QEMU %s: launch failure: %s", bsp, e)
            raise
Exemplo n.º 7
0
Arquivo: tt_qemu.py Projeto: intel/tcf
    def _qemu_launch(self, bsp, kws):
        gdb_tcp_port = commonl.tcp_port_assigner(
            1, port_range = ttbl.config.tcp_port_range)
        self.fsdb.set("debug-%s-gdb-tcp-port" % bsp, "%s" % gdb_tcp_port)
        console_out_fname = os.path.join(
            self.state_dir, "console-%s.log" % bsp)
        errfname = os.path.join(
            self.state_dir, "%s-stderr.log" % bsp)
        try:
            # Make sure we wipe the PID file -- sometimes a pidfile is
            # left over and it seems to override it, so the reading
            # becomes corrupt
            commonl.rm_f(self.pidfile[bsp])
            qemu_cmdline = \
                (self.qemu_cmdlines[bsp] % kws).split() \
                + [
                    # Don't add -daemonize! This way this is part of
                    # the process tree and killed when we kill the
                    # parent process
                    # We use QMP to find the PTY assigned
                    "-qmp", "unix:%s.qmp,server,nowait" % self.pidfile[bsp],
                    # Always start in debug mode -- this way the
                    # whole thing is stopped until we unleash it
                    # with QMP; this allows us to first start
                    # daemons that we might need to start
                    "-S",
                    "-pidfile", self.pidfile[bsp],
                    "-gdb", "tcp:0.0.0.0:%d" % gdb_tcp_port,
                ]
            self.fsdb.set("qemu-cmdline-%s" % bsp, qemu_cmdline[0])
        except KeyError as e:
            msg = "bad QEMU command line specification: " \
                  "uninitialized key %s" % e
            self.log.error(msg)
            commonl.raise_from(RuntimeError(msg), e)
        self.log.debug("QEMU cmdline %s" % " ".join(qemu_cmdline))
        self.tags['bsps'][bsp]['cmdline'] = " ".join(qemu_cmdline)
        try:
            _preexec_fn = getattr(self, "qemu_preexec_fn", None)
            def _local_preexec_fn():
                if _preexec_fn:
                    _preexec_fn()
                    # Open file descriptors for stdout/stderr to a
                    # logfile, because -D is not really working. We
                    # need it to check startup errors for things that
                    # need a retry.
                commonl.rm_f(errfname)
                logfd = os.open(errfname,
                                # O_CREAT: Always a new file, so
                                # we can check for errors and not
                                # get confused with previous runs
                                os.O_WRONLY | os.O_EXCL |os.O_CREAT, 0o0644)
                os.dup2(logfd, 1)
                os.dup2(logfd, 2)
                os.close(logfd)

            p = subprocess.Popen(qemu_cmdline,
                                 shell = False, cwd = self.state_dir,
                                 close_fds = True,
                                 preexec_fn = _local_preexec_fn)
            self.log.debug("QEMU %s: console @ %s" % (bsp, console_out_fname))
            # Give it a few secs to start, the pidfile has been
            # deleted before starting -- note 4 was found by
            # ad-hoc experimentation, sometimes depending on system load it
            # takes more or less.
            timeout = 10
            ts0 = time.time()
            while True:
                if time.time() - ts0 > timeout:
                    lines = []
                    with open(errfname) as f:
                        count = 0
                        for line in f:
                            lines.append("log: " + line)
                            if count > 5:
                                lines.append("log: ...")
                                break
                    raise RuntimeError("QEMU %s: did not start after %.0fs\n"
                                       "%s" % (bsp, timeout, "\n".join(lines)))
                try:
                    if self._qmp_running(bsp):
                        # FIXME: race condition
                        ttbl.daemon_pid_add(p.pid)
                        return True
                except RuntimeError as e:
                    self.log.warning("QEMU %s: can't read QMP: %s"
                                     % (bsp, str(e)))
                    # fall through, let it retry
                # Check errors during startup
                with open(errfname, "r") as logf:
                    causes_for_retry = [
                        # bah, race condition: since we chose the
                        # port we wanted to use and until we
                        # started using it someone took it. Retry
                        'Failed to bind socket: Address already in use',
                    ]
                    for line in logf:
                        for cause in causes_for_retry:
                            if cause in line:
                                self.log.info(
                                    "QEMU %s: retrying because found in "
                                    "logfile: %s", bsp, cause)
                                return False
                time.sleep(0.25)
                # nothing runs after this, either it returns or raises
        except (OSError, ValueError) as e:
            self.log.debug("QEMU %s: launch failure: %s", bsp, e)
            raise