def background(self, command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, as_root=False): try: port_string = '-p {}'.format(self.port) if self.port else '' keyfile_string = '-i {}'.format( self.keyfile) if self.keyfile else '' if as_root and not self.connected_as_root: command = self.sudo_cmd.format(command) options = " ".join([ "-o {}={}".format(key, val) for key, val in self.options.items() ]) command = '{} {} {} {} {}@{} {}'.format(ssh, options, keyfile_string, port_string, self.username, self.host, command) logger.debug(command) if self.password: command, _ = _give_password(self.password, command) return subprocess.Popen(command, stdout=stdout, stderr=stderr, shell=True) except EOF: raise TargetNotRespondingError('Connection lost.')
def _gem5_EOF_handler(self, gem5_simulation, gem5_out_dir, err): # If we have reached the "EOF", it typically means # that gem5 crashed and closed the connection. Let's # check and actually tell the user what happened here, # rather than spewing out pexpect errors. if gem5_simulation.poll(): message = "The gem5 process has crashed with error code {}!\n\tPlease see {} for details." raise TargetNotRespondingError( message.format(gem5_simulation.poll(), gem5_out_dir)) else: # Let's re-throw the exception in this case. raise err
def execute(self, command, timeout=None, check_exit_code=True, as_root=False, strip_colors=True, will_succeed=False): #pylint: disable=unused-argument if command == '': # Empty command is valid but the __devlib_ec stuff below will # produce a syntax error with bash. Treat as a special case. return '' try: with self.lock: _command = '({}); __devlib_ec=$?; echo; echo $__devlib_ec'.format( command) full_output = self._execute_and_wait_for_prompt( _command, timeout, as_root, strip_colors) split_output = full_output.rsplit('\r\n', 2) try: output, exit_code_text, _ = split_output except ValueError as e: raise TargetStableError( "cannot split reply (target misconfiguration?):\n'{}'". format(full_output)) if check_exit_code: try: exit_code = int(exit_code_text) if exit_code: message = 'Got exit code {}\nfrom: {}\nOUTPUT: {}' raise TargetStableError( message.format(exit_code, command, output)) except (ValueError, IndexError): logger.warning( 'Could not get exit code for "{}",\ngot: "{}"'\ .format(command, exit_code_text)) return output except EOF: raise TargetNotRespondingError('Connection lost.') except TargetStableError as e: if will_succeed: raise TargetTransientError(e) else: raise
def background(self, command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, as_root=False): try: port_string = '-p {}'.format(self.port) if self.port else '' keyfile_string = '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ' if as_root and not self.connected_as_root: command = self.sudo_cmd.format(command) command = '{} {} {} {}@{} {}'.format(ssh, keyfile_string, port_string, self.username, self.host, command) logger.debug(command) if self.password: command, _ = _give_password(self.password, command) return subprocess.Popen(command, stdout=stdout, stderr=stderr, shell=True) except EOF: raise TargetNotRespondingError('Connection lost.')
def background(self, command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, as_root=False): try: port_string = '-p {}'.format(self.port) if self.port else '' keyfile_string = '-i {}'.format( self.keyfile) if self.keyfile else '' if as_root: command = self.sudo_cmd.format(command) command = '{} {} {} {}@{} {}'.format(ssh, keyfile_string, port_string, self.username, self.host, command) logger.debug(command) if self.password: command = _give_password(self.password, command) return subprocess.Popen(command, stdout=stdout, stderr=stderr, shell=True) except EOF: raise TargetNotRespondingError('Connection lost.')
def connect_gem5(self, port, gem5_simulation, gem5_interact_dir, gem5_out_dir): """ Connect to the telnet port of the gem5 simulation. We connect, and wait for the prompt to be found. We do not use a timeout for this, and wait for the prompt in a while loop as the gem5 simulation can take many hours to reach a prompt when booting the system. We also inject some newlines periodically to try and force gem5 to show a prompt. Once the prompt has been found, we replace it with a unique prompt to ensure that we are able to match it properly. We also disable the echo as this simplifies parsing the output when executing commands on the device. """ host = socket.gethostname() gem5_logger.info( "Connecting to the gem5 simulation on port {}".format(port)) # Check if there is no on-going connection yet lock_file_name = '{}{}_{}.LOCK'.format(self.lock_directory, host, port) if os.path.isfile(lock_file_name): # There is already a connection to this gem5 simulation raise TargetStableError( 'There is already a connection to the gem5 ' 'simulation using port {} on {}!'.format(port, host)) # Connect to the gem5 telnet port. Use a short timeout here. attempts = 0 while attempts < 10: attempts += 1 try: self.conn = TelnetPxssh(original_prompt=None) self.conn.login(host, self.username, port=port, login_timeout=10, auto_prompt_reset=False) break except pxssh.ExceptionPxssh: pass except EOF as err: self._gem5_EOF_handler(gem5_simulation, gem5_out_dir, err) else: gem5_simulation.kill() raise TargetNotRespondingError( "Failed to connect to the gem5 telnet session.") gem5_logger.info("Connected! Waiting for prompt...") # Create the lock file self.lock_file_name = lock_file_name open(self.lock_file_name, 'w').close() # Similar to touch gem5_logger.info("Created lock file {} to prevent reconnecting to " "same simulation".format(self.lock_file_name)) # We need to find the prompt. It might be different if we are resuming # from a checkpoint. Therefore, we test multiple options here. prompt_found = False while not prompt_found: try: self._login_to_device() except TIMEOUT: pass except EOF as err: self._gem5_EOF_handler(gem5_simulation, gem5_out_dir, err) try: # Try and force a prompt to be shown self.conn.send('\n') self.conn.expect([ r'# ', r'\$ ', self.conn.UNIQUE_PROMPT, r'\[PEXPECT\][\\\$\#]+ ' ], timeout=60) prompt_found = True except TIMEOUT: pass except EOF as err: self._gem5_EOF_handler(gem5_simulation, gem5_out_dir, err) gem5_logger.info("Successfully logged in") gem5_logger.info("Setting unique prompt...") self.conn.set_unique_prompt() self.conn.prompt() gem5_logger.info("Prompt found and replaced with a unique string") # We check that the prompt is what we think it should be. If not, we # need to update the regex we use to match. self._find_prompt() self.conn.setecho(False) self._sync_gem5_shell() # Fully connected to gem5 simulation self.gem5_interact_dir = gem5_interact_dir self.gem5_out_dir = gem5_out_dir self.gem5simulation = gem5_simulation # Ready for interaction now self.ready = True
def check_responsive(self): try: self.conn.execute('ls /', timeout=5) except (TimeoutError, subprocess.CalledProcessError): raise TargetNotRespondingError(self.conn.name)