def _execute_and_wait_for_prompt(self, command, timeout=None, as_root=False, strip_colors=True, log=True): self.conn.prompt(0.1) # clear an existing prompt if there is one. if as_root: command = "sudo -- sh -c '{}'".format( escape_single_quotes(command)) if log: logger.debug(command) self.conn.sendline(command) if self.password: index = self.conn.expect_exact([self.password_prompt, TIMEOUT], timeout=0.5) if index == 0: self.conn.sendline(self.password) else: # not as_root if log: logger.debug(command) self.conn.sendline(command) timed_out = self._wait_for_prompt(timeout) # the regex removes line breaks potential introduced when writing # command to shell. output = process_backspaces(self.conn.before) output = re.sub(r'\r([^\n])', r'\1', output) if '\r\n' in output: # strip the echoed command output = output.split('\r\n', 1)[1] if timed_out: self.cancel_running_command() raise TimeoutError(command, output) if strip_colors: output = strip_bash_colors(output) return output
def _scp(self, source, dest, timeout=30): # NOTE: the version of scp in Ubuntu 12.04 occasionally (and bizarrely) # fails to connect to a device if port is explicitly specified using -P # option, even if it is the default port, 22. To minimize this problem, # only specify -P for scp if the port is *not* the default. port_string = '-P {}'.format(quote(str( self.port))) if (self.port and self.port != 22) else '' keyfile_string = '-i {}'.format(quote( self.keyfile)) if self.keyfile else '' options = " ".join( ["-o{}={}".format(key, val) for key, val in self.options.items()]) command = '{} {} -r {} {} {} {}'.format(scp, options, keyfile_string, port_string, quote(source), quote(dest)) command_redacted = command logger.debug(command) if self.password: command, command_redacted = _give_password(self.password, command) try: check_output(command, timeout=timeout, shell=True) except subprocess.CalledProcessError as e: raise_from( HostError("Failed to copy file with '{}'. Output:\n{}".format( command_redacted, e.output)), None) except TimeoutError as e: raise TimeoutError(command_redacted, e.output)
def wait_for_device(self, timeout=30): """ Wait for Gem5 to be ready for interation with a timeout. """ for _ in attempts(timeout): if self.ready: return time.sleep(1) raise TimeoutError('Gem5 is not ready for interaction')
def check_output(command, timeout=None, ignore=None, inputtext=None, **kwargs): """This is a version of subprocess.check_output that adds a timeout parameter to kill the subprocess if it does not return within the specified time.""" # pylint: disable=too-many-branches if ignore is None: ignore = [] elif isinstance(ignore, int): ignore = [ignore] elif not isinstance(ignore, list) and ignore != 'all': message = 'Invalid value for ignore parameter: "{}"; must be an int or a list' raise ValueError(message.format(ignore)) if 'stdout' in kwargs: raise ValueError('stdout argument not allowed, it will be overridden.') def callback(pid): try: check_output_logger.debug( '{} timed out; sending SIGKILL'.format(pid)) os.killpg(pid, signal.SIGKILL) except OSError: pass # process may have already terminated. with check_output_lock: process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, preexec_fn=preexec_function, **kwargs) if timeout: timer = threading.Timer(timeout, callback, [ process.pid, ]) timer.start() try: output, error = process.communicate(inputtext) if sys.version_info[0] == 3: # Currently errors=replace is needed as 0x8c throws an error output = output.decode(sys.stdout.encoding, "replace") error = error.decode(sys.stderr.encoding, "replace") finally: if timeout: timer.cancel() retcode = process.poll() if retcode: if retcode == -9: # killed, assume due to timeout callback raise TimeoutError(command, output='\n'.join([output, error])) elif ignore != 'all' and retcode not in ignore: raise subprocess.CalledProcessError(retcode, command, output='\n'.join( [str(output), str(error)])) return output, error
def check_output(command, timeout=None, ignore=None, inputtext=None, combined_output=False, **kwargs): """This is a version of subprocess.check_output that adds a timeout parameter to kill the subprocess if it does not return within the specified time.""" # pylint: disable=too-many-branches if ignore is None: ignore = [] elif isinstance(ignore, int): ignore = [ignore] elif not isinstance(ignore, list) and ignore != 'all': message = 'Invalid value for ignore parameter: "{}"; must be an int or a list' raise ValueError(message.format(ignore)) if 'stdout' in kwargs: raise ValueError('stdout argument not allowed, it will be overridden.') with check_output_lock: stderr = subprocess.STDOUT if combined_output else subprocess.PIPE process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=stderr, stdin=subprocess.PIPE, preexec_fn=preexec_function, **kwargs) try: output, error = process.communicate(inputtext, timeout=timeout) except subprocess.TimeoutExpired as e: timeout_expired = e else: timeout_expired = None # Currently errors=replace is needed as 0x8c throws an error output = output.decode(sys.stdout.encoding or 'utf-8', "replace") if error: error = error.decode(sys.stderr.encoding or 'utf-8', "replace") if timeout_expired: raise TimeoutError(command, output='\n'.join([output or '', error or ''])) retcode = process.poll() if retcode and ignore != 'all' and retcode not in ignore: raise subprocess.CalledProcessError(retcode, command, output='\n'.join( [output or '', error or ''])) return output, error
def _scp(self, source, dest, timeout=30): # NOTE: the version of scp in Ubuntu 12.04 occasionally (and bizarrely) # fails to connect to a device if port is explicitly specified using -P # option, even if it is the default port, 22. To minimize this problem, # only specify -P for scp if the port is *not* the default. port_string = '-P {}'.format(self.port) if (self.port and self.port != 22) else '' keyfile_string = '-i {}'.format(self.keyfile) if self.keyfile else '' command = '{} -r {} {} {} {}'.format(scp, keyfile_string, port_string, source, dest) pass_string = '' logger.debug(command) if self.password: command = _give_password(self.password, command) try: check_output(command, timeout=timeout, shell=True) except subprocess.CalledProcessError as e: raise subprocess.CalledProcessError(e.returncode, e.cmd.replace(pass_string, ''), e.output) except TimeoutError as e: raise TimeoutError(e.command.replace(pass_string, ''), e.output)
def _execute_and_wait_for_prompt(self, command, timeout=None, as_root=False, strip_colors=True, log=True): self.conn.prompt(0.1) # clear an existing prompt if there is one. if self.username == 'root': # As we're already root, there is no need to use sudo. as_root = False if as_root: command = self.sudo_cmd.format(escape_single_quotes(command)) if log: logger.debug(command) self.conn.sendline(command) if self.password: index = self.conn.expect_exact([self.password_prompt, TIMEOUT], timeout=0.5) if index == 0: self.conn.sendline(self.password) else: # not as_root if log: logger.debug(command) self.conn.sendline(command) timed_out = self._wait_for_prompt(timeout) # the regex removes line breaks potential introduced when writing # command to shell. if sys.version_info[0] == 3: output = process_backspaces( self.conn.before.decode(sys.stdout.encoding, 'replace')) else: output = process_backspaces(self.conn.before) output = re.sub(r'\r([^\n])', r'\1', output) if '\r\n' in output: # strip the echoed command output = output.split('\r\n', 1)[1] if timed_out: self.cancel_running_command() raise TimeoutError(command, output) if strip_colors: output = strip_bash_colors(output) return output
def _execute_and_wait_for_prompt(self, command, timeout=None, as_root=False, strip_colors=True, log=True): self.conn.prompt(0.1) # clear an existing prompt if there is one. if as_root and self.connected_as_root: # As we're already root, there is no need to use sudo. as_root = False if as_root: command = self.sudo_cmd.format(quote(command)) if log: logger.debug(command) self._sendline(command) if self.password: index = self.conn.expect_exact([self.password_prompt, TIMEOUT], timeout=0.5) if index == 0: self._sendline(self.password) else: # not as_root if log: logger.debug(command) self._sendline(command) timed_out = self._wait_for_prompt(timeout) if sys.version_info[0] == 3: output = process_backspaces( self.conn.before.decode(sys.stdout.encoding or 'utf-8', 'replace')) else: output = process_backspaces(self.conn.before) if timed_out: self.cancel_running_command() raise TimeoutError(command, output) if strip_colors: output = strip_bash_colors(output) return output
def check_subprocess_output(process, timeout=None, ignore=None, inputtext=None): output = None error = None # pylint: disable=too-many-branches if ignore is None: ignore = [] elif isinstance(ignore, int): ignore = [ignore] elif not isinstance(ignore, list) and ignore != 'all': message = 'Invalid value for ignore parameter: "{}"; must be an int or a list' raise ValueError(message.format(ignore)) try: output, error = process.communicate(inputtext, timeout=timeout) except subprocess.TimeoutExpired as e: timeout_expired = e else: timeout_expired = None # Currently errors=replace is needed as 0x8c throws an error output = output.decode(sys.stdout.encoding or 'utf-8', "replace") if output else '' error = error.decode(sys.stderr.encoding or 'utf-8', "replace") if error else '' if timeout_expired: raise TimeoutError(process.args, output='\n'.join([output, error])) retcode = process.poll() if retcode and ignore != 'all' and retcode not in ignore: raise subprocess.CalledProcessError(retcode, process.args, output='\n'.join([output, error])) return output, error