Beispiel #1
0
def wait_input_ready(
    debug_process: pexpect.spawn, lang: str, timeout: Optional[float] = None
):
    if lang == "python3":
        debug_process.expect("\(Pdb\)", timeout=timeout)
    else:
        debug_process.expect("\(gdb\)", timeout=timeout)
Beispiel #2
0
 def _run_expect(self, child: pexpect.spawn) -> Optional[str]:
     if self._database.has_password():
         child.expect('Enter password to unlock {}: '.format(
             self._database.get_path()))
         child.sendline(self._database.get_password())
     child.expect(pexpect.EOF)
     return child.before
Beispiel #3
0
def debug_kernel_panic(qemu: pexpect.spawn):
    # wait up to 10 seconds for a db prompt
    i = qemu.expect([pexpect.TIMEOUT, "db> "], timeout=10)
    if i == 1:
        qemu.sendline("bt")
    # wait for the backtrace
    qemu.expect([pexpect.TIMEOUT, "db> "], timeout=30)
    failure("GOT KERNEL PANIC!", exit=False)
Beispiel #4
0
def worker_run_task_in_subprocess(sp: pexpect.spawn, *args, **kwargs):
    # TODO check the buffer size rules for stdin and stdout and directly
    # stream bytes instead of saving them to the file system. See 'encoding='
    # argument in pexpect.spawn constructor

    # Serialize args and kwargs to a file
    path_to_args = os.path.join(tempfile.gettempdir(), f'{uuid.uuid4()}.pkl')
    with open(path_to_args, 'wb') as args_file:
        cloudpickle.dump([args, kwargs], args_file)

    # Prepare result and error files
    path_to_result = os.path.join(tempfile.gettempdir(), f'{uuid.uuid4()}.pkl')
    path_to_error = os.path.join(tempfile.gettempdir(), f'{uuid.uuid4()}.pkl')

    # Communicate to the subprocess
    sp.expect('Ready for next task.')  # Printed in the subprocess loop
    sp.sendline(path_to_args)
    sp.sendline(path_to_result)
    sp.sendline(path_to_error)

    # Wait for the subprocess to complete
    sp.expect('Task complete.')  # Printed in the subprocess loop

    # Check for an exception to be reraised
    error: SerializableException = None
    try:
        with open(path_to_error, 'rb') as error_file:
            error: SerializableException = cloudpickle.load(error_file)
    except FileNotFoundError:
        pass

    # Check for a result to be returned
    result = None
    try:
        with open(path_to_result, 'rb') as result_file:
            result = cloudpickle.load(result_file)
    except FileNotFoundError as e:
        pass

    # Remove the args, result and error files
    try:
        os.remove(path_to_args)
    except (FileNotFoundError, NameError):
        pass
    try:
        os.remove(path_to_result)
    except (FileNotFoundError, NameError):
        pass
    try:
        os.remove(path_to_error)
    except (FileNotFoundError, NameError):
        pass

    # Finish up (reraise error or return result)
    if error is not None:
        error.reraise()
    return result
Beispiel #5
0
def expect_ftcs_command_finished(zsh: pexpect.spawn) -> typing.Optional[int]:
    """Match a FinalTerm FTCS_COMMAND_FINISHED escape sequence.
    """
    zsh.expect(
        b"\x1b]133;D(?:;(?P<exit_status>[0-9]+))?" + ftcs_extra_arguments_re + b"\x07"
    )
    exit_status = zsh.match.group("exit_status")
    if not exit_status:
        return None
    return int(exit_status)
Beispiel #6
0
def run_cheribsd_command_or_die(qemu: pexpect.spawn, cmd: str, timeout=600):
    qemu.sendline(
        test_command +
        " ;if test $? -eq 0; then echo 'COMMAND' 'SUCCESSFUL'; else echo 'COMMAND' 'FAILED'; fi"
    )
    i = qemu.expect([
        pexpect.TIMEOUT, "COMMAND SUCCESSFUL", "COMMAND FAILED", PANIC,
        CHERI_TRAP, STOPPED
    ],
                    timeout=timeout)
    testtime = datetime.datetime.now() - run_tests_starttime
    if i == 0:  # Timeout
        return failure("timeout after",
                       testtime,
                       "waiting for tests: ",
                       str(qemu),
                       exit=False)
    elif i == 1:
        success("===> Tests completed!")
        success("Running tests took ", testtime)
        return True
    else:
        return failure("error after ",
                       testtime,
                       "while running tests : ",
                       str(qemu),
                       exit=False)
Beispiel #7
0
 def spawnAction(self, sp: spawn):
     keys = list(self.keys())
     r = sp.expect(keys)
     yield r
     matched = keys[r]
     print('received {} ({})'.format(matched, r))
     yield from self.get(matched).spawnAction(sp)
def assert_bash_exec(
        bash: pexpect.spawn, cmd: str, want_output: bool = False) -> str:

    # Send command
    bash.sendline(cmd)
    bash.expect_exact(cmd)

    # Find prompt, output is before it
    bash.expect_exact("\r\n" + PS1)
    output = bash.before

    # Retrieve exit status
    echo = "echo $?"
    bash.sendline(echo)
    got = bash.expect([
        r"^%s\r\n(\d+)\r\n%s" % (re.escape(echo), re.escape(PS1)),
        PS1,
        pexpect.EOF,
        pexpect.TIMEOUT,
    ])
    status = bash.match.group(1) if got == 0 else "unknown"

    assert status == "0", \
        'Error running "%s": exit status=%s, output="%s"' % \
        (cmd, status, output)
    if output:
        assert want_output, \
            'Unexpected output from "%s": exit status=%s, output="%s"' % \
            (cmd, status, output)
    else:
        assert not want_output, \
            'Expected output from "%s": exit status=%s, output="%s"' % \
            (cmd, status, output)

    return output
Beispiel #9
0
def run_noop_test(qemu: pexpect.spawn, args: argparse.Namespace):
    import boot_cheribsd
    boot_cheribsd.success("Booted successfully")
    boot_cheribsd.run_cheribsd_command(qemu, "mount_smbfs --help", cheri_trap_fatal=False)
    boot_cheribsd.run_cheribsd_command(qemu, "/libexec/ld-cheri-elf.so.1 --help")
    poweroff_start = datetime.datetime.now()
    qemu.sendline("poweroff")
    i = qemu.expect(["Uptime:", pexpect.TIMEOUT, pexpect.EOF] + boot_cheribsd.FATAL_ERROR_MESSAGES, timeout=20)
    if i != 0:
        boot_cheribsd.failure("Poweroff " + ("timed out" if i == 1 else "failed"))
        return False
    i = qemu.expect([pexpect.TIMEOUT, pexpect.EOF], timeout=20)
    if i == 0:
        boot_cheribsd.failure("QEMU didn't exit after shutdown!")
        return False
    boot_cheribsd.success("Poweroff took: ", datetime.datetime.now() - poweroff_start)
    return True
Beispiel #10
0
def run_cheribsd_command(qemu: pexpect.spawn,
                         cmd: str,
                         expected_output=None,
                         error_output=None,
                         timeout=60):
    qemu.sendline(cmd)
    if expected_output:
        qemu.expect(expected_output)
    results = [
        pexpect.TIMEOUT, PROMPT, "/bin/sh: [\\w\\d_-]+: not found", CHERI_TRAP
    ]
    if error_output:
        results.append(error_output)
    i = qemu.expect(results, timeout=timeout)
    if i == 0:
        failure("timeout running ", cmd)
    elif i == 2:
        failure("Command not found!")
    elif i == 3:
        # wait up to 20 seconds for a prompt to ensure the dump output has been printed
        qemu.expect([pexpect.TIMEOUT, PROMPT], timeout=20)
        qemu.flush()
        failure("Got CHERI TRAP!")
    elif i == 4:
        # wait up to 5 seconds for a prompt to ensure the full output has been printed
        qemu.expect([pexpect.TIMEOUT, PROMPT], timeout=5)
        qemu.flush()
        failure("Matched error output ", error_output)
Beispiel #11
0
def assert_complete(bash: pexpect.spawn, cmd: str,
                    **kwargs) -> CompletionResult:
    skipif = kwargs.get("skipif")
    if skipif:
        try:
            assert_bash_exec(bash, skipif, want_output=None)
        except AssertionError:
            pass
        else:
            pytest.skip(skipif)
    xfail = kwargs.get("xfail")
    if xfail:
        try:
            assert_bash_exec(bash, xfail, want_output=None)
        except AssertionError:
            pass
        else:
            pytest.xfail(xfail)

    with bash_env_saved(bash, sendintr=True) as bash_env:

        cwd = kwargs.get("cwd")
        if cwd:
            bash_env.chdir(str(cwd))

        for k, v in kwargs.get("env", {}).items():
            bash_env.write_env(k, v, quote=False)

        for k, v in kwargs.get("shopt", {}).items():
            bash_env.shopt(k, v)

        bash.send(cmd + "\t")
        # Sleep a bit if requested, to avoid `.*` matching too early
        time.sleep(kwargs.get("sleep_after_tab", 0))
        bash.expect_exact(kwargs.get("rendered_cmd", cmd))
        bash.send(MAGIC_MARK)
        got = bash.expect([
            # 0: multiple lines, result in .before
            r"\r\n" + re.escape(PS1 + cmd) + ".*" + re.escape(MAGIC_MARK),
            # 1: no completion
            r"^" + re.escape(MAGIC_MARK),
            # 2: on same line, result in .match
            r"^([^\r]+)%s$" % re.escape(MAGIC_MARK),
            pexpect.EOF,
            pexpect.TIMEOUT,
        ])
        if got == 0:
            output = bash.before
            if output.endswith(MAGIC_MARK):
                output = bash.before[:-len(MAGIC_MARK)]
            return CompletionResult(output)
        elif got == 2:
            output = bash.match.group(1)
            return CompletionResult(output)
        else:
            # TODO: warn about EOF/TIMEOUT?
            return CompletionResult()
Beispiel #12
0
    def connect(self, connection=None):
        """
        See :meth:`BaseShell.connect` for more information.
        """
        connection = connection or self._default_connection or '0'

        if connection in self._connections and self.is_connected(connection):
            raise AlreadyConnectedError(connection)

        # Create a child process
        spawn = Spawn(
            self._get_connect_command().strip(),
            **self._spawn_args
        )
        self._connections[connection] = spawn

        try:
            # If connection is via user
            if self._user is not None:
                spawn.expect(
                    [self._user_match], timeout=self._timeout
                )
                spawn.sendline(self._user)

            # If connection is via password
            if self._password is not None:
                spawn.expect(
                    [self._password_match], timeout=self._timeout
                )
                spawn.sendline(self._password)

            # Setup shell before using it
            self._setup_shell(connection)

            # Execute initial command if required
            if self._initial_command is not None:
                spawn.expect(
                    self._prompt, timeout=self._timeout
                )
                spawn.sendline(self._initial_command)

            # Wait for command response to match the prompt
            spawn.expect(
                self._prompt, timeout=self._timeout
            )

        except:
            # Always remove bad connections if it failed
            del self._connections[connection]
            raise

        # Set connection as default connection if required
        if self.default_connection is None:
            self.default_connection = connection
Beispiel #13
0
def assert_complete_at_point(
    bash: pexpect.spawn, cmd: str, trail: str
) -> CompletionResult:
    # TODO: merge to assert_complete
    fullcmd = "%s%s%s" % (
        cmd,
        trail,
        "\002" * len(trail),
    )  # \002 = ^B = cursor left
    bash.send(fullcmd + "\t")
    bash.send(MAGIC_MARK)
    bash.expect_exact(fullcmd.replace("\002", "\b"))

    got = bash.expect_exact(
        [
            # 0: multiple lines, result in .before
            PS1 + fullcmd.replace("\002", "\b"),
            # 1: no completion
            MAGIC_MARK,
            pexpect.EOF,
            pexpect.TIMEOUT,
        ]
    )
    if got == 0:
        output = bash.before
        result = CompletionResult(output)

        # At this point, something weird happens. For most test setups, as
        # expected (pun intended!), MAGIC_MARK follows as is. But for some
        # others (e.g. CentOS 6, Ubuntu 14 test containers), we get MAGIC_MARK
        # one character a time, followed each time by trail and the corresponding
        # number of \b's. Don't know why, but accept it until/if someone finds out.
        # Or just be fine with it indefinitely, the visible and practical end
        # result on a terminal is the same anyway.
        repeat = "(%s%s)?" % (re.escape(trail), "\b" * len(trail))
        fullexpected = "".join(
            "%s%s" % (re.escape(x), repeat) for x in MAGIC_MARK
        )
        bash.expect(fullexpected)
    else:
        # TODO: warn about EOF/TIMEOUT?
        result = CompletionResult()

    return result
Beispiel #14
0
def assert_bash_exec(
    bash: pexpect.spawn,
    cmd: str,
    want_output: Optional[bool] = False,
    want_newline=True,
) -> str:
    """
    :param want_output: if None, don't care if got output or not
    """

    # Send command
    bash.sendline(cmd)
    bash.expect_exact(cmd)

    # Find prompt, output is before it
    bash.expect_exact("%s%s" % ("\r\n" if want_newline else "", PS1))
    output = bash.before

    # Retrieve exit status
    echo = "echo $?"
    bash.sendline(echo)
    got = bash.expect(
        [
            r"^%s\r\n(\d+)\r\n%s" % (re.escape(echo), re.escape(PS1)),
            PS1,
            pexpect.EOF,
            pexpect.TIMEOUT,
        ]
    )
    status = bash.match.group(1) if got == 0 else "unknown"

    assert status == "0", 'Error running "%s": exit status=%s, output="%s"' % (
        cmd,
        status,
        output,
    )
    if want_output is not None:
        if output:
            assert (
                want_output
            ), 'Unexpected output from "%s": exit status=%s, output="%s"' % (
                cmd,
                status,
                output,
            )
        else:
            assert (
                not want_output
            ), 'Expected output from "%s": exit status=%s, output="%s"' % (
                cmd,
                status,
                output,
            )

    return output
Beispiel #15
0
    def _wait_connect(self, p: pexpect.spawn,
                      password_manager: PasswordManager,
                      azure_ad_config: AuthConfig):
        i = p.expect([
            pexpect.EOF,
            re.compile(r"continue connecting \(yes/no(/\[fingerprint])?\)\? "),
            re.compile(r"authenticate\.")
        ])

        if i == 0:
            if self.is_connected():
                return
            else:
                raise GProxyError(f"Error when initializing SSH: {p.before}")
        elif i == 1:
            host_key_fingerprint = self._extract_host_key_fingerprint(p.before)
            if host_key_fingerprint != GPROXY_FINGERPRINT:
                raise GProxyError(
                    f"!!!SEVERE!!! Host fingerprint is not matching expected!!! Report to CCOE!:"
                    f"Actual:{host_key_fingerprint} != Expected:{GPROXY_FINGERPRINT}"
                )
            LOG.info("Confirming host! Fingerprint is matching expected.")
            p.send("yes\r")
            self._wait_connect(p, password_manager, azure_ad_config)
            return

        p.send("\r")
        code = self._extract_code(p.before)
        url = self._extract_url(p.before)
        LOG.info(f"GProxy OTC Code: {code}, Url: {url}")

        if url != GProxyAdLogin.URL:
            raise GProxyError(
                f"Url does not match expected login-url. !={GProxyAdLogin.URL}"
            )

        GProxyAdLogin(code=code,
                      password_manager=password_manager,
                      config=azure_ad_config).login_sync()

        p.expect(pexpect.EOF, timeout=30)
def flush_thread(f, qemu: pexpect.spawn):
    while True:
        if f:
            f.flush()
        i = qemu.expect([pexpect.TIMEOUT, "KDB: enter:"], timeout=30)
        if boot_cheribsd.PRETEND:
            time.sleep(1)
        elif i == 1:
            boot_cheribsd.failure("GOT KERNEL PANIC!", exit=False)
            boot_cheribsd.debug_kernel_panic(qemu)
            global KERNEL_PANIC
            KERNEL_PANIC = True
Beispiel #17
0
def setup_ssh(qemu: pexpect.spawn, pubkey: Path):
    run_cheribsd_command(qemu, "mkdir -p /root/.ssh")
    contents = pubkey.read_text(encoding="utf-8").strip()
    run_cheribsd_command(
        qemu,
        "echo " + shlex.quote(contents) + " >> /root/.ssh/authorized_keys")
    run_cheribsd_command(qemu, "chmod 600 /root/.ssh/authorized_keys")
    run_cheribsd_command(
        qemu,
        "echo 'PermitRootLogin without-password' >> /etc/ssh/sshd_config")
    # TODO: check for bluehive images without /sbin/service
    run_cheribsd_command(qemu,
                         "cat /root/.ssh/authorized_keys",
                         expected_output="ssh-")
    run_cheribsd_command(qemu, "grep -n PermitRootLogin /etc/ssh/sshd_config")
    qemu.sendline("service sshd restart")
    i = qemu.expect([pexpect.TIMEOUT, "service: not found", "Starting sshd."],
                    timeout=120)
    if i == 0:
        failure("Timed out setting up SSH keys")
    qemu.expect(PROMPT)
    time.sleep(2)  # sleep for two seconds to avoid a rejection
    success("===> SSH authorized_keys set up")
Beispiel #18
0
 def _run_expect(self, child: pexpect.spawn) -> Optional[str]:
     if self._database.has_password():
         child.expect('Enter password to unlock {}: '.format(
             self._database.get_path()))
         child.sendline(self._database.get_password())
     if self._database_from.has_password():
         child.expect('Enter password to unlock {}: '.format(
             self._database_from.get_path()))
         child.sendline(self._database_from.get_password())
     child.expect('Database was not modified by merge operation.')
     return child.before
Beispiel #19
0
def wait_for(child: pexpect.spawn, pattern: str, answer: str):
    countdown = 1024
    while True:
        hit = child.expect([pattern, pexpect.TIMEOUT, pexpect.EOF], timeout=15)
        if hit == 0:
            if answer and len(answer):
                child.sendline(answer)
            return 0
        if hit == 1:
            print('timeout on pattern : ', pattern)
            sigterm(signal.SIGTERM, None)
            return 1
        if hit == 2:
            countdown -= 1
            if countdown == 0:
                print('too much EOF on pattern : ', pattern)
                return 2
Beispiel #20
0
    def connect(self, connection=None):
        """
        See :meth:`BaseShell.connect` for more information.
        """
        connection = connection or self._default_connection or '0'

        if connection in self._connections and self.is_connected(connection):
            raise AlreadyConnectedError(connection)

        # Create a child process
        spawn = Spawn(self._get_connect_command().strip(), **self._spawn_args)
        self._connections[connection] = spawn

        try:
            # If connection is via user
            if self._user is not None:
                spawn.expect([self._user_match], timeout=self._timeout)
                spawn.sendline(self._user)

            # If connection is via password
            if self._password is not None:
                spawn.expect([self._password_match], timeout=self._timeout)
                spawn.sendline(self._password)

            # Setup shell before using it
            self._setup_shell(connection)

            # Execute initial command if required
            if self._initial_command is not None:
                spawn.expect(self._prompt, timeout=self._timeout)
                spawn.sendline(self._initial_command)

            # Wait for command response to match the prompt
            spawn.expect(self._prompt, timeout=self._timeout)

        except:
            # Always remove bad connections if it failed
            del self._connections[connection]
            raise

        # Set connection as default connection if required
        if self.default_connection is None:
            self.default_connection = connection
Beispiel #21
0
    def execute(self, sp: spawn, outputhook=print):
        gen = self.seq.spawnAction(sp)
        try:
            self.last = next(gen)
            while True:
                args = self.log(sp, outputhook)
                self.last = gen.send(args)
        except StopIteration:
            r = sp.expect([EOF, TIMEOUT])
            self.log(sp, outputhook)
            if r:
                self.error(sp.command)
        except (TIMEOUT, EOF) as e:
            self.log(sp, outputhook)
            self.error(sp.command)
            raise e

        return self
Beispiel #22
0
def assert_bash_exec(bash: pexpect.spawn,
                     cmd: str,
                     want_output: bool = False) -> str:

    # Send command
    bash.sendline(cmd)
    bash.expect_exact(cmd)

    # Find prompt, output is before it
    bash.expect_exact("\r\n" + PS1)
    output = bash.before

    # Retrieve exit status
    echo = "echo $?"
    bash.sendline(echo)
    got = bash.expect([
        r"^%s\r\n(\d+)\r\n%s" % (re.escape(echo), re.escape(PS1)),
        PS1,
        pexpect.EOF,
        pexpect.TIMEOUT,
    ])
    status = bash.match.group(1) if got == 0 else "unknown"

    assert status == "0", 'Error running "%s": exit status=%s, output="%s"' % (
        cmd,
        status,
        output,
    )
    if output:
        assert want_output, (
            'Unexpected output from "%s": exit status=%s, output="%s"' %
            (cmd, status, output))
    else:
        assert not want_output, (
            'Expected output from "%s": exit status=%s, output="%s"' %
            (cmd, status, output))

    return output
Beispiel #23
0
def expect_iterm_current_dir(zsh: pexpect.spawn) -> bytes:
    """Match a iTerm CurrentDir escape sequence.
    """
    zsh.expect(b"\x1b](?:1337|50);CurrentDir=(?P<iterm_current_dir_path>.*?)\x07")
    return zsh.match.group("iterm_current_dir_path")
Beispiel #24
0
def assert_complete(bash: pexpect.spawn, cmd: str,
                    **kwargs) -> CompletionResult:
    skipif = kwargs.get("skipif")
    if skipif:
        try:
            assert_bash_exec(bash, skipif)
        except AssertionError:
            pass
        else:
            pytest.skip(skipif)
    xfail = kwargs.get("xfail")
    if xfail:
        try:
            assert_bash_exec(bash, xfail)
        except AssertionError:
            pass
        else:
            pytest.xfail(xfail)
    cwd = kwargs.get("cwd")
    if cwd:
        assert_bash_exec(bash, "cd '%s'" % cwd)
    env_prefix = "_BASHCOMP_TEST_"
    env = kwargs.get("env", {})
    if env:
        # Back up environment and apply new one
        assert_bash_exec(
            bash,
            " ".join('%s%s="$%s"' % (env_prefix, k, k) for k in env.keys()),
        )
        assert_bash_exec(
            bash,
            "export %s" % " ".join("%s=%s" % (k, v) for k, v in env.items()),
        )
    bash.send(cmd + "\t")
    bash.expect_exact(cmd)
    bash.send(MAGIC_MARK)
    got = bash.expect([
        # 0: multiple lines, result in .before
        r"\r\n" + re.escape(PS1 + cmd) + ".*" + MAGIC_MARK,
        # 1: no completion
        r"^" + MAGIC_MARK,
        # 2: on same line, result in .match
        r"^([^\r]+)%s$" % MAGIC_MARK,
        pexpect.EOF,
        pexpect.TIMEOUT,
    ])
    if got == 0:
        output = bash.before
        if output.endswith(MAGIC_MARK):
            output = bash.before[:-len(MAGIC_MARK)]
        result = CompletionResult(output)
    elif got == 2:
        output = bash.match.group(1)
        result = CompletionResult(output, [shlex.split(cmd + output)[-1]])
    else:
        # TODO: warn about EOF/TIMEOUT?
        result = CompletionResult("", [])
    bash.sendintr()
    bash.expect_exact(PS1)
    if env:
        # Restore environment, and clean up backup
        # TODO: Test with declare -p if a var was set, backup only if yes, and
        #       similarly restore only backed up vars. Should remove some need
        #       for ignore_env.
        assert_bash_exec(
            bash,
            "export %s" % " ".join('%s="$%s%s"' % (k, env_prefix, k)
                                   for k in env.keys()),
        )
        assert_bash_exec(
            bash,
            "unset -v %s" % " ".join("%s%s" % (env_prefix, k)
                                     for k in env.keys()),
        )
    if cwd:
        assert_bash_exec(bash, "cd - >/dev/null")
    return result
Beispiel #25
0
def send_cmd(child: pexpect.spawn, cmd):
    prompt = ['# ', '>>> ', '> ', '\$ ']
    child.sendline(cmd)
    child.expect(prompt)
    print(child.before.decode())
Beispiel #26
0
def assert_complete(
        bash: pexpect.spawn, cmd: str, **kwargs) -> CompletionResult:
    skipif = kwargs.get("skipif")
    if skipif:
        try:
            assert_bash_exec(bash, skipif)
        except AssertionError:
            pass
        else:
            pytest.skip(skipif)
            return CompletionResult("", [])
    cwd = kwargs.get("cwd")
    if cwd:
        assert_bash_exec(bash, "cd '%s'" % cwd)
    env_prefix = "_BASHCOMP_TEST_"
    env = kwargs.get("env", {})
    if env:
        # Back up environment and apply new one
        assert_bash_exec(bash, " ".join(
            '%s%s="$%s"' % (env_prefix, k, k) for k in env.keys()
        ))
        assert_bash_exec(bash, "export %s" % " ".join(
            "%s=%s" % (k, v) for k, v in env.items()
        ))
    bash.send(cmd + "\t")
    bash.expect_exact(cmd)
    bash.send(MAGIC_MARK)
    got = bash.expect([
        r"\r\n" + re.escape(PS1 + cmd),  # 0: multiple lines, result in .before
        r"^" + MAGIC_MARK,               # 1: no completion
        r"^[^\r]+",                      # 2: on same line, result in .after
        pexpect.EOF,
        pexpect.TIMEOUT,
    ])
    if got == 0:
        line = bash.before
        if line.endswith(MAGIC_MARK):
            line = bash.before[:-len(MAGIC_MARK)]
        result = CompletionResult(
            line,
            sorted(x for x in re.split(r" {2,}|\r\n", line) if x),
        )
    elif got == 2:
        line = bash.after
        if line.endswith(MAGIC_MARK):
            line = bash.after[:-len(MAGIC_MARK)]
        result = CompletionResult(
            line,
            [shlex.split(cmd + line)[-1]],
        )
    else:
        # TODO: warn about EOF/TIMEOUT?
        result = CompletionResult("", [])
    bash.sendintr()
    bash.expect_exact(PS1)
    if env:
        # Restore environment, and clean up backup
        # TODO: Test with declare -p if a var was set, backup only if yes, and
        #       similarly restore only backed up vars. Should remove some need
        #       for ignore_env.
        assert_bash_exec(bash, "export %s" % " ".join(
            '%s="$%s%s"' % (k, env_prefix, k) for k in env.keys()
        ))
        assert_bash_exec(bash, "unset -v %s" % " ".join(
            "%s%s" % (env_prefix, k) for k in env.keys()
        ))
    if cwd:
        assert_bash_exec(bash, "cd - >/dev/null")
    return result
Beispiel #27
0
    def connect(self, connection=None):
        """
        See :meth:`BaseShell.connect` for more information.
        """
        connection = connection or self._default_connection or '0'

        if connection in self._connections and self.is_connected(connection):
            raise AlreadyConnectedError(connection)

        # Inject framework logger to the spawn object
        spawn_args = {
            'logfile':
            get_logger(OrderedDict([('node_identifier', self._node_identifier),
                                    ('shell_name', self._shell_name),
                                    ('connection', connection)]),
                       category='pexpect'),
        }

        # Create a child process
        spawn_args.update(self._spawn_args)

        spawn = Spawn(self._get_connect_command().strip(), **spawn_args)

        # Add a connection logger
        # Note: self._node and self._name were added to this shell in the
        #       node's call to its _register_shell method.
        spawn._connection_logger = get_logger(OrderedDict([
            ('node_identifier', self._node_identifier),
            ('shell_name', self._shell_name), ('connection', connection)
        ]),
                                              category='connection')

        self._connections[connection] = spawn

        try:

            def expect_sendline(prompt, command):
                if command is not None:
                    spawn.expect(prompt, timeout=self._timeout)
                    spawn.sendline(command)

            # If connection is via user
            expect_sendline(self._user_match, self._user)

            # If connection is via password
            expect_sendline(self._password_match, self._password)

            # If connection is via initial command
            expect_sendline(self._initial_prompt, self._initial_command)

            # Setup shell before using it
            self._setup_shell(connection)

            # Wait for command response to match the prompt
            spawn.expect(self._prompt, timeout=self._timeout)

        except:
            # Always remove a bad connection if it failed
            del self._connections[connection]
            raise

        # Set connection as default connection if required
        if self.default_connection is None:
            self.default_connection = connection
Beispiel #28
0
 def spawnAction(self, sp: spawn):
     print("expecting {}".format(self))
     yield sp.expect(self)
Beispiel #29
0
    def connect(self, connection=None):
        """
        See :meth:`BaseShell.connect` for more information.
        """
        connection = connection or self._default_connection or '0'

        if connection in self._connections and self.is_connected(connection):
            raise AlreadyConnectedError(connection)

        # Inject framework logger to the spawn object
        spawn_args = {
            'logfile': get_logger(
                OrderedDict([
                    ('node_identifier', self._node_identifier),
                    ('shell_name', self._shell_name),
                    ('connection', connection)
                ]),
                category='pexpect'
            ),
        }

        # Create a child process
        spawn_args.update(self._spawn_args)

        spawn = Spawn(
            self._get_connect_command().strip(),
            **spawn_args
        )

        # Add a connection logger
        # Note: self._node and self._name were added to this shell in the
        #       node's call to its _register_shell method.
        spawn._connection_logger = get_logger(
            OrderedDict([
                ('node_identifier', self._node_identifier),
                ('shell_name', self._shell_name),
                ('connection', connection)
            ]),
            category='connection'
        )

        self._connections[connection] = spawn

        try:
            # If connection is via user
            if self._user is not None:
                spawn.expect(
                    [self._user_match], timeout=self._timeout
                )
                spawn.sendline(self._user)

            # If connection is via password
            if self._password is not None:
                spawn.expect(
                    [self._password_match], timeout=self._timeout
                )
                spawn.sendline(self._password)

            # Setup shell before using it
            self._setup_shell(connection)

            # Execute initial command if required
            if self._initial_command is not None:
                spawn.expect(
                    self._prompt, timeout=self._timeout
                )
                spawn.sendline(self._initial_command)

            # Wait for command response to match the prompt
            spawn.expect(
                self._prompt, timeout=self._timeout
            )

        except:
            # Always remove bad connections if it failed
            del self._connections[connection]
            raise

        # Set connection as default connection if required
        if self.default_connection is None:
            self.default_connection = connection
Beispiel #30
0
def runtests(
    qemu: pexpect.spawn,
    test_archives: list,
    test_command: str,
    smb_dir: typing.Optional[Path],
    ssh_keyfile: typing.Optional[str],
    ssh_port: typing.Optional[int],
    timeout: int,
    test_function: "typing.Callable[[pexpect.spawn, ...], bool]" = None
) -> bool:
    setup_tests_starttime = datetime.datetime.now()
    # disable coredumps, otherwise we get no space left on device errors
    run_cheribsd_command(qemu, "sysctl kern.coredump=0")
    # create tmpfs on opt
    run_cheribsd_command(
        qemu, "mkdir -p /opt && mount -t tmpfs -o size=500m tmpfs /opt")
    # ensure that /usr/local exists and if not create it as a tmpfs (happens in the minimal image)
    run_cheribsd_command(
        qemu,
        "mkdir -p /usr/local && mount -t tmpfs -o size=300m tmpfs /usr/local")
    run_cheribsd_command(qemu, "df -h", expected_output="/opt")
    info("\nWill transfer the following archives: ", test_archives)
    # strip the .pub from the key file
    for archive in test_archives:
        if smb_dir:
            run_host_command(["tar", "xJf", str(archive), "-C", str(smb_dir)])
        else:
            # Extract to temporary directory and scp over
            with tempfile.TemporaryDirectory(dir=os.getcwd(),
                                             prefix="test_files_") as tmp:
                run_host_command(["tar", "xJf", str(archive), "-C", tmp])
                private_key = str(Path(ssh_keyfile).with_suffix(""))
                scp_cmd = [
                    "scp", "-B", "-r", "-P",
                    str(ssh_port), "-o", "StrictHostKeyChecking=no", "-o",
                    "UserKnownHostsFile=/dev/null", "-i",
                    shlex.quote(private_key), ".", "root@localhost:/"
                ]
                # use script for a fake tty to get progress output from scp
                if sys.platform.startswith("linux"):
                    scp_cmd = [
                        "script", "--quiet", "--return", "--command",
                        " ".join(scp_cmd), "/dev/null"
                    ]
                run_host_command(["ls", "-la"], cwd=tmp)
                run_host_command(scp_cmd, cwd=tmp)
    if test_archives:
        time.sleep(5)  # wait 5 seconds to make sure the disks have synced
    # See how much space we have after running scp
    run_cheribsd_command(qemu, "df -h", expected_output="/opt")
    success("Preparing test enviroment took ",
            datetime.datetime.now() - setup_tests_starttime)

    run_tests_starttime = datetime.datetime.now()
    # Run the tests (allowing custom test functions)
    if test_function:
        return test_function(qemu, ssh_keyfile=ssh_keyfile, ssh_port=ssh_port)

    qemu.sendline(
        test_command +
        " ;if test $? -eq 0; then echo 'TESTS' 'COMPLETED'; else echo 'TESTS' 'FAILED'; fi"
    )
    i = qemu.expect(
        [pexpect.TIMEOUT, "TESTS COMPLETED", "TESTS FAILED", PANIC, STOPPED],
        timeout=timeout)
    testtime = datetime.datetime.now() - run_tests_starttime
    if i == 0:  # Timeout
        return failure("timeout after",
                       testtime,
                       "waiting for tests: ",
                       str(qemu),
                       exit=False)
    elif i == 1:
        success("===> Tests completed!")
        success("Running tests took ", testtime)
        run_cheribsd_command(
            qemu, "df -h",
            expected_output="/opt")  # see how much space we have now
        return True
    else:
        return failure("error after ",
                       testtime,
                       "while running tests : ",
                       str(qemu),
                       exit=False)
Beispiel #31
0
def expect_ftcs_prompt(zsh: pexpect.spawn) -> None:
    """Match a FinalTerm FTCS_PROMPT escape sequence.
    """
    zsh.expect(b"\x1b]133;A" + ftcs_extra_arguments_re + b"\x07")
Beispiel #32
0
def expect_ftcs_command_start(zsh: pexpect.spawn) -> None:
    """Match a FinalTerm FTCS_COMMAND_START escape sequence.
    """
    zsh.expect(b"\x1b]133;B" + ftcs_extra_arguments_re + b"\x07")
Beispiel #33
0
def expect_ftcs_command_executed(zsh: pexpect.spawn) -> None:
    """Match a FinalTerm FTCS_COMMAND_EXECUTED escape sequence.
    """
    zsh.expect(b"\x1b]133;C" + ftcs_extra_arguments_re + b"\x07")
Beispiel #34
0
def send_and_expect_byte_by_byte(zsh: pexpect.spawn, input: bytes) -> bytes:
    for byte in input:
        current_input = bytes([byte])
        zsh.send(current_input)
        zsh.expect(string_ignoring_escape_sequences_re(current_input))
Beispiel #35
0
    def connect(self, *args, connection=None, **kwargs):
        """
        See :meth:`BaseShell.connect` for more information.
        """
        connection = connection or self._default_connection or '0'

        connection_is_present = connection in self._connections

        if connection_is_present and self.is_connected(connection=connection):
            raise AlreadyConnectedError(connection)

        spawn = Spawn(
            self._get_connect_command().strip(),
            **self._spawn_args
        )

        # If the disconnect is called on a connection and then connect is
        # called again on the same connection, this will be called twice,
        # making each message from that connection to be logged twice.
        if connection_is_present:
            present_connection = self._connections[connection]

            spawn.logfile_read = present_connection.logfile_read
            spawn.logfile_send = present_connection.logfile_send
            spawn._connection_logger = present_connection._connection_logger

        else:
            spawn.logfile_read = get_logger(
                OrderedDict([
                    ('node_identifier', self._node_identifier),
                    ('shell_name', self._shell_name),
                    ('connection', connection)
                ]),
                category='pexpect_read',
            )

            spawn.logfile_send = get_logger(
                OrderedDict([
                    ('node_identifier', self._node_identifier),
                    ('shell_name', self._shell_name),
                    ('connection', connection)
                ]),
                category='pexpect_send',
            )

            # Add a connection logger
            # Note: self._node and self._name were added to this shell in the
            #       node's call to its _register_shell method.
            spawn._connection_logger = get_logger(
                OrderedDict([
                    ('node_identifier', self._node_identifier),
                    ('shell_name', self._shell_name),
                    ('connection', connection)
                ]),
                category='connection'
            )
        # Set larger PTTY so there are less unnecessary line
        # changes on the stream
        spawn.setwinsize(30, 150)

        self._connections[connection] = spawn

        try:
            def expect_sendline(prompt, command):
                if command is not None:
                    spawn.expect(
                        prompt, timeout=self._timeout
                    )
                    spawn.sendline(command)

            # If connection is via user
            expect_sendline(self._user_match, self._user)

            # If connection is via password
            expect_sendline(self._password_match, self._password)

            # If connection is via initial command
            expect_sendline(self._initial_prompt, self._initial_command)

            # Setup shell before using it
            self._setup_shell(*args, connection=connection, **kwargs)

            # Wait for command response to match the prompt
            spawn.expect(
                self._prompt, timeout=self._timeout
            )

        except Exception:
            # Always remove a bad connection if it failed
            del self._connections[connection]
            raise

        # Set connection as default connection if required
        if self.default_connection is None:
            self.default_connection = connection
Beispiel #36
0
def get_dumped_input_buffer(zsh: pexpect.spawn) -> None:
    zsh.expect(b"\[\[\[(?P<input_buffer>.*)\]\]\]")
    return zsh.match.group("input_buffer")