def setup_term(self, system, my_term, ssh_obj=None, block=0): # Login and/or setup any terminal # my_term needs to be the opexpect object # This will behave correctly even if already logged in # Petitboot Menu is special case to NOT participate in this setup, conditionally checks if system state is PETITBOOT and skips # CANNOT CALL GET_CONSOLE OR CONNECT from here since get_console and connect call into setup_term if block == 1: return if ssh_obj is not None: track_obj = ssh_obj term_obj = ssh_obj system_obj = ssh_obj.system else: track_obj = system term_obj = system.console system_obj = system my_term.sendline() rc = my_term.expect(['login: $', ".*#$", ".*# $", ".*\$", 'Petitboot', pexpect.TIMEOUT, pexpect.EOF], timeout=10) if rc == 0: track_obj.PS1_set, track_obj.LOGIN_set = self.get_login(system_obj.cv_HOST, term_obj, my_term, self.build_prompt(system_obj.prompt)) track_obj.PS1_set, track_obj.SUDO_set = self.get_sudo(system_obj.cv_HOST, term_obj, my_term, self.build_prompt(system_obj.prompt)) return if rc in [1,2,3]: track_obj.PS1_set = self.set_PS1(term_obj, my_term, self.build_prompt(system_obj.prompt)) track_obj.LOGIN_set = 1 # ssh port 22 can get in which uses sshpass or Petitboot, do this after set_PS1 to make sure we have something track_obj.PS1_set, track_obj.SUDO_set = self.get_sudo(system_obj.cv_HOST, term_obj, my_term, self.build_prompt(system_obj.prompt)) return if rc == 4: return # Petitboot so nothing to do if rc == 6: # EOF term_obj.close() # mark as bad raise ConsoleSettings(before=my_term.before, after=my_term.after, msg="Getting login and sudo not successful, probably connection or credential issue, retry") # now just timeout my_term.sendline() rc = my_term.expect(['login: $', ".*#$", ".*# $", ".*\$", 'Petitboot', pexpect.TIMEOUT, pexpect.EOF], timeout=10) if rc == 0: track_obj.PS1_set, track_obj.LOGIN_set = self.get_login(system_obj.cv_HOST, term_obj, my_term, self.build_prompt(system_obj.prompt)) track_obj.PS1_set, track_obj.SUDO_set = self.get_sudo(system_obj.cv_HOST, term_obj, my_term, self.build_prompt(system_obj.prompt)) return if rc in [1,2,3]: track_obj.LOGIN_set = track_obj.PS1_set = self.set_PS1(term_obj, my_term, self.build_prompt(system_obj.prompt)) track_obj.PS1_set, track_obj.SUDO_set = self.get_sudo(system_obj.cv_HOST, term_obj, my_term, self.build_prompt(system_obj.prompt)) return if rc == 4: return # Petitboot do nothing else: if term_obj.setup_term_quiet == 0: term_obj.close() # mark as bad raise ConsoleSettings(before=my_term.before, after=my_term.after, msg="Getting login and sudo not successful, probably connection issue, retry") else: # this case happens when detect_target sets the quiet flag and we are timing out print "OpTestSystem detected something, checking if your system is powered off, will retry"
def retry_password(self, term_obj, my_term, command): retry_list_output = [] a = 0 while a < 3: a += 1 my_term.sendline(term_obj.system.cv_HOST.password()) rc = my_term.expect([".*#", "try again.", pexpect.TIMEOUT, pexpect.EOF]) if (rc == 0) or (rc == 1): combo_io = my_term.before + my_term.after retry_list_output += combo_io.splitlines() matching = [xs for xs in sudo_responses if any(xs in xa for xa in my_term.after.splitlines())] if len(matching): echo_rc = 1 rc = -1 # use to flag the failure next if rc == 0: retry_list_output += self.set_env(term_obj, my_term) echo_rc = 0 break elif a == 2: echo_rc = 1 break elif (rc == 2): raise CommandFailed(command, 'Retry Password TIMEOUT ' + ''.join(retry_list_output), -1) elif (rc == 3): term_obj.close() raise ConsoleSettings(before=my_term.before, after=my_term.after, msg='SSH session/console issue, probably connection issue, retry') return retry_list_output, echo_rc
def get_sudo(self, host, term_obj, my_term, prompt): # prompt comes in as the string desired, needs to be pre-built # must have PS1 expect_prompt already set # must be already logged in if term_obj.setup_term_disable == 1: return -1, -1 my_term.sendline() expect_prompt = prompt + "$" my_user = host.username() my_pwd = host.password() my_term.sendline("which sudo && sudo -s") rc = my_term.expect([r"[Pp]assword for", "#", pexpect.TIMEOUT, pexpect.EOF], timeout=10) if rc == 0: my_term.sendline(my_pwd) time.sleep(0.5) # delays for next call my_PS1_set = self.set_PS1(term_obj, my_term, prompt) self.check_root(my_term, prompt) my_SUDO_set = 1 return my_PS1_set, my_SUDO_set # caller needs to save state elif rc in [1,2]: # we must have been root, we first filter out password prompt above my_PS1_set = self.set_PS1(term_obj, my_term, prompt) self.check_root(my_term, prompt) my_SUDO_set = 1 return my_PS1_set, my_SUDO_set # caller needs to save state else: if term_obj.setup_term_quiet == 0: print ("OpTestSystem Unable to setup root access, probably a connection issue," " raised Exception ConsoleSettings but continuing") raise ConsoleSettings(before=my_term.before, after=my_term.after, msg='Unable to setup root access, probably a connection issue, retry') else: term_obj.setup_term_disable = 1 return -1, -1
def check_root(self, my_term, prompt): # we do the best we can to verify, but if not oh well expect_prompt = prompt + "$" my_term.sendline("date") # buffer kicker needed my_term.sendline("which whoami && whoami") time.sleep(1) rc = my_term.expect([expect_prompt, pexpect.TIMEOUT, pexpect.EOF], timeout=10) if rc == 0: try: whoami = my_term.before.splitlines()[-1] except Exception as e: pass my_term.sendline("echo $?") time.sleep(1) rc = my_term.expect([expect_prompt, pexpect.TIMEOUT, pexpect.EOF], timeout=10) if rc == 0: try: echo_rc = int(my_term.before.splitlines()[-1]) except Exception as e: echo_rc = -1 if echo_rc == 0: if whoami in "root": print "OpTestSystem now running as root" else: raise ConsoleSettings(before=my_term.before, after=my_term.after, msg="Unable to confirm root access setting up terminal, check that you provided" " root credentials or a properly enabled sudo user, retry") else: print "OpTestSystem should be running as root, unable to verify"
def set_env(self, term_obj, my_term): set_env_list = [] my_term.sendline("which bash && exec bash --norc --noprofile") expect_prompt = self.build_prompt(term_obj.prompt) + "$" my_term.sendline('PS1=' + self.build_prompt(term_obj.prompt)) rc = my_term.expect([expect_prompt, pexpect.TIMEOUT, pexpect.EOF], timeout=10) if rc == 0: combo_io = (my_term.before + my_term.after).lstrip() set_env_list += combo_io.splitlines() # remove the expect prompt since matched generic # del set_env_list[-1] return set_env_list else: raise ConsoleSettings(before=my_term.before, after=my_term.after, msg="Setting environment for sudo command not successful, probably connection issue, retry")
def get_sudo(self, host, term_obj, my_term, prompt): # prompt comes in as the string desired, needs to be pre-built # must have PS1 expect_prompt already set # must be already logged in if term_obj.setup_term_disable == 1: return -1, -1 my_term.sendline() expect_prompt = prompt + "$" my_user = host.username() my_pwd = host.password() my_term.sendline("which sudo && sudo -s") rc = my_term.expect([r"[Pp]assword for", pexpect.TIMEOUT, pexpect.EOF], timeout=5) # we must not add # prompt to the expect, we get false hit when complicated user login prompt and control chars, # we need to cleanly ignore everything but password and then we blindly next do PS1 setup, ignoring who knows what if rc == 0: my_term.sendline(my_pwd) time.sleep(0.5) # delays for next call my_PS1_set = self.set_PS1(term_obj, my_term, prompt) self.check_root(my_term, prompt) my_SUDO_set = 1 return my_PS1_set, my_SUDO_set # caller needs to save state elif rc == 1: # we must have been root, we first filter out password prompt above my_PS1_set = self.set_PS1(term_obj, my_term, prompt) self.check_root(my_term, prompt) my_SUDO_set = 1 return my_PS1_set, my_SUDO_set # caller needs to save state else: if term_obj.setup_term_quiet == 0: log.warning( "OpTestSystem Unable to setup root access, probably a connection issue," " raised Exception ConsoleSettings but continuing") raise ConsoleSettings( before=my_term.before, after=my_term.after, msg= 'Unable to setup root access, probably a connection issue, retry' ) else: term_obj.setup_term_disable = 1 return -1, -1
def get_login(self, host, term_obj, my_term, prompt): # prompt comes in as the string desired, needs to be pre-built if term_obj.setup_term_disable == 1: return -1, -1 my_user = host.username() my_pwd = host.password() my_term.sendline() rc = my_term.expect(['login: '******'login: $', ".*#$", ".*# $", ".*\$", 'Petitboot', pexpect.TIMEOUT, pexpect.EOF ], timeout=10) if rc not in [1, 2, 3]: if term_obj.setup_term_quiet == 0: log.warning( "OpTestSystem Problem with the login and/or password prompt," " raised Exception ConsoleSettings but continuing") raise ConsoleSettings( before=my_term.before, after=my_term.after, msg= "Problem with the login and/or password prompt, probably a connection or credential issue, retry" ) else: term_obj.setup_term_disable = 1 return -1, -1 else: if term_obj.setup_term_quiet == 0: log.warning( "OpTestSystem Problem with the login and/or password prompt, raised Exception ConsoleSettings but continuing" ) raise ConsoleSettings( before=my_term.before, after=my_term.after, msg= "Problem with the login and/or password prompt, probably a connection or credential issue, retry" ) else: term_obj.setup_term_disable = 1 return -1, -1 my_PS1_set = self.set_PS1(term_obj, my_term, prompt) my_LOGIN_set = 1 else: # timeout eof my_term.sendline() rc = my_term.expect(['login: '******'login: $', ".*#$", ".*# $", ".*\$", 'Petitboot', pexpect.TIMEOUT, pexpect.EOF ], timeout=10) if rc not in [1, 2, 3]: if term_obj.setup_term_quiet == 0: log.warning( "OpTestSystem Problem with the login and/or password prompt," " raised Exception ConsoleSettings but continuing" ) raise ConsoleSettings( before=my_term.before, after=my_term.after, msg= "Problem with the login and/or password prompt, probably a connection or credential issue, retry" ) else: term_obj.setup_term_disable = 1 return -1, -1 else: if term_obj.setup_term_quiet == 0: log.warning( "OpTestSystem Problem with the login and/or password prompt after a secondary connection issue," " raised Exception ConsoleSettings but continuing") raise ConsoleSettings( before=my_term.before, after=my_term.after, msg= "Problem with the login and/or password prompt after a secondary connection or credential issue, retry" ) else: term_obj.setup_term_disable = 1 return -1, -1 my_PS1_set = self.set_PS1(term_obj, my_term, prompt) my_LOGIN_set = 1 else: # timeout eof if term_obj.setup_term_quiet == 0: log.warning( "OpTestSystem Problem with the login and/or password prompt after a previous connection issue," " raised Exception ConsoleSettings but continuing") raise ConsoleSettings( before=my_term.before, after=my_term.after, msg= "Problem with the login and/or password prompt last try, probably a connection or credential issue, retry" ) else: term_obj.setup_term_disable = 1 return -1, -1 return my_PS1_set, my_LOGIN_set # caller needs to save state
def set_PS1(self, term_obj, my_term, prompt): # prompt comes in as the string desired, needs to be pre-built # on success caller is returned 1, otherwise exception thrown # order of execution and commands are sensitive here to provide reliability if term_obj.setup_term_disable == 1: return -1 expect_prompt = prompt + "$" my_term.sendline("which bash && exec bash --norc --noprofile") time.sleep(0.2) my_term.sendline('PS1=' + prompt) time.sleep(0.2) my_term.sendline( "which stty && stty cols 300;which stty && stty rows 30") time.sleep(0.2) my_term.sendline("export LANG=C") time.sleep(0.2) my_term.sendline() # needed to sync buffers later on time.sleep( 0.2 ) # pause for first time setup, buffers you know, more sensitive in petitboot shell, pexpect or console buffer not sure rc = my_term.expect([expect_prompt, pexpect.TIMEOUT, pexpect.EOF], timeout=10) if rc == 0: log.debug("Shell prompt changed") return 1 # caller needs to save state else: # we don't seem to have anything so try to get something term_obj.close() try: # special case to allow calls back to connect which is where we probably came from self.orig_system_setup_term = term_obj.get_system_setup_term() self.orig_block_setup_term = term_obj.get_block_setup_term() term_obj.set_system_setup_term( 1 ) # block so the new connect will not try to come back here term_obj.set_block_setup_term( 1 ) # block so the new connect will not try to come back here self.try_recover( term_obj, counter=3 ) # if try_recover bails we leave things blocked, they'll get reset # if we get back here we have a new prompt and unknown console # in future if state can change or block flags can change this needs revisted my_term = term_obj.connect( ) # need a new my_term since we recovered term_obj.set_system_setup_term = self.orig_system_setup_term term_obj.set_block_setup_term = self.orig_block_setup_term my_term.sendline("which bash && exec bash --norc --noprofile") time.sleep(0.2) my_term.sendline('PS1=' + prompt) time.sleep(0.2) my_term.sendline( "which stty && stty cols 300;which stty && stty rows 30") time.sleep(0.2) my_term.sendline("export LANG=C") time.sleep(0.2) my_term.sendline() # needed to sync buffers later on time.sleep( 0.2 ) # pause for first time setup, buffers you know, more sensitive in petitboot shell, pexpect or console buffer not sure rc = my_term.expect( [expect_prompt, pexpect.TIMEOUT, pexpect.EOF], timeout=10) if rc == 0: log.debug("Shell prompt changed") return 1 # caller needs to save state else: if term_obj.setup_term_quiet == 0: log.warning( "OpTestSystem Change of shell prompt not completed after last final retry," " probably a connection issue, raised Exception ConsoleSettings but continuing" ) raise ConsoleSettings( before=my_term.before, after=my_term.after, msg= "Change of shell prompt not completed after last final retry, probably a connection issue, retry" ) else: term_obj.setup_term_disable = 1 return -1 except RecoverFailed as e: if term_obj.setup_term_quiet == 0: log.warning( "OpTestSystem Change of shell prompt not completed after last retry," " probably a connection issue, raised Exception ConsoleSettings but continuing" ) raise ConsoleSettings( before=my_term.before, after=my_term.after, msg= "Change of shell prompt not completed after last retry, probably a connection issue, retry" ) else: term_obj.setup_term_disable = 1 return -1