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)
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
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)
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
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)
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)
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
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
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)
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()
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
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
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
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
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")
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
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
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
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
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
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")
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
def send_cmd(child: pexpect.spawn, cmd): prompt = ['# ', '>>> ', '> ', '\$ '] child.sendline(cmd) child.expect(prompt) print(child.before.decode())
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
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
def spawnAction(self, sp: spawn): print("expecting {}".format(self)) yield sp.expect(self)
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
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)
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")
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")
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")
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))
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
def get_dumped_input_buffer(zsh: pexpect.spawn) -> None: zsh.expect(b"\[\[\[(?P<input_buffer>.*)\]\]\]") return zsh.match.group("input_buffer")