def ftd_install(self): """Perform ping test and verify the network connectivity to http server Install SFR pkg image Enter device network info, hostname. :return: None """ self.spawn_id.sendline('') self.spawn_id.expect('-boot>', timeout=20) for i in range(20): self.spawn_id.sendline('ping -c 1 {}'.format(self.http_server)) try: self.spawn_id.expect('64 bytes from', timeout=5) except TimeoutError: continue else: break else: raise RuntimeError(">>>>>> Ping not working") d1 = Dialog([ [ '-boot>', 'sendline(system install {})'.format(self.pkg_image), None, True, False ], ['Do you want to continue?', 'sendline(y)', None, True, False], ['Upgrade aborted', 'sendline()', None, False, False], ]) count = 0 while count < self.retry_count: try: d1.process(self.spawn_id, timeout=300) count += 1 logger.info( 'captured "Upgrade aborted": {} times'.format(count)) time.sleep(5) except: logger.info('did not capture Upgrade aborted within 5 minutes') break assert count < self.retry_count, 'ftd installation failed' \ ', please check ftd package url: "{}"'.format(self.pkg_image) d2 = Dialog([ [ 'Do you want to continue with upgrade?', 'sendline(y)', None, True, True ], [ "Press 'Enter' to reboot the system.", 'sendline()', None, True, True ], [ 'The system is going down for reboot NOW', 'sendline()', None, False, True ], #['{}# '.format(self.hostname), 'sendline()', None, False, True], ]) d2.process(self.spawn_id, timeout=2400)
def _reload_expect_prompt(self, timeout=300): """Wait for ASA to be back online after reload :param timeout: timeout for reload :return: None """ if 'telnet' in self.type: disable_prompt = self.sm.patterns.prompt.disable_prompt dialog = Dialog([ ['Process shutdown finished', None, None, True, False], ['The system is restarting', None, None, True, False], ['Configuring network interfaces... done', None, None, True, False], ['Compiled on', None, None, True, False], ['The digital signature of the running image verified successfully', \ None, None, True, False], ['Compiled on', None, None, True, False], ['Cisco Adaptive Security Appliance Software Version', None, None, True, False], [disable_prompt, 'sendline()', None, False, False], ]) dialog.process(self.spawn_id, timeout=timeout) self.go_to('any') elif 'ssh' in self.type: pass
def rommon_boot(self, timeout=600): """Perform TFTP Boot from ROMMON. :return: None """ time.sleep(10) logger.info('=== Performing TFTP Boot from ROMMON') logger.info('=== Wait for installation to complete, timeout = {}' ' seconds ...'.format(str(timeout))) self.spawn_id.sendline('tftpdnld') d1 = Dialog([ ['rommon.*> ', 'sendline(tftpdnld)', None, True, False], ['Use SPACE to launch Cisco FTD immediately.', 'sendline({})'.format(chr(27)), None, True, False], ['-boot>', 'sendline()', None, False, False], [self.sm.patterns.prompt.enable_prompt, 'sendline()', None, False, False], [self.sm.patterns.prompt.disable_prompt, 'sendline()', None, False, False], ]) try: d1.process(self.spawn_id, timeout=timeout) self.spawn_id.sendline() logger.info("=== Rommon file was installed successfully.") except: logger.info("=== Rommon file download failed, raise runtime error. ") raise RuntimeError( ">>>>>> Download failed. Please check details - " "tftp_server: {}, image file: {}".format(self.rommon_tftp_server, self.rommon_image)) logger.info('In boot CLI mode') logger.info("=== Rommon file was installed successfully.")
def ssh_vty(self, ip, port='22'): """Setup ssh connection to the server. :param ip: ssh host/ip :param port: ssh port :return: ssh_line """ from .constants import WebserverConstants spawn = Spawn( 'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no ' '-l {} -p {} {} \n'.format(WebserverConstants.username, port, ip)) d1 = Dialog([ [ 'continue connecting (yes/no)?', 'sendline(yes)', None, True, False ], [ '(p|P)assword:', 'sendline({})'.format(WebserverConstants.login_password), None, False, False ], ]) try: d1.process(spawn, timeout=60) spawn.sendline() except TimeoutError: pass ssh_line = WebserverLine(spawn, self.sm, 'ssh_ftd') return ssh_line
def config_transition(statemachine, spawn, context): # Config may be locked, retry until max attempts or config state reached wait_time = spawn.settings.CONFIG_LOCK_RETRY_SLEEP max_attempts = spawn.settings.CONFIG_LOCK_RETRIES dialog = Dialog([Statement(pattern=statemachine.get_state('enable').pattern, loop_continue=False, trim_buffer=True), Statement(pattern=statemachine.get_state('config').pattern, loop_continue=False, trim_buffer=False), ]) if hasattr(statemachine, 'config_transition_statement_list'): dialog += Dialog(statemachine.config_transition_statement_list) for attempt in range(max_attempts + 1): spawn.sendline(statemachine.config_command) dialog.process(spawn, timeout=spawn.settings.CONFIG_TIMEOUT, context=context) statemachine.detect_state(spawn) if statemachine.current_state == 'config': return if attempt < max_attempts: spawn.log.warning('*** Could not enter config mode, waiting {} seconds. Retry attempt {}/{} ***'.format( wait_time, attempt + 1, max_attempts)) sleep(wait_time) raise StateMachineError('Unable to transition to config mode')
def _set_password(line, username, new_password): """ Change password for user 'username' :param line: BasicLine object :param username: username for the password is changing :param new_password: new password to be set :return: """ line.sendline('expert') line.sendline('sudo su') line.spawn_id.expect('[p|P]assword:') line.sendline('{}'.format(KickConsts.DUMMY_PASSWORD)) logger.info('\nChanging back the password to {}'.format(new_password)) line.sendline('passwd {}'.format(username)) d_set_password = Dialog([ ['[N|n]ew UNIX password', 'sendline({})'.format(new_password), None, True, False], ['Retype new UNIX password', 'sendline({})'.format(new_password), None, True, False], ['passwd: password updated successfully', None, None, False, False], ]) try: d_set_password.process(line.spawn_id, timeout=120) line.sm.update_cur_state('sudo_state') logger.info('Changing password successfully') except uniconTimeoutError: logger.error('Changing password for {} user has failed'.format(username)) line.spawn_id.close() raise Exception('Error while changing default password for {} user'.format(username))
def rommon_boot(self, timeout=600): """Perform TFTP Boot from ROMMON. :return: None """ time.sleep(10) logger.info('=== Performing TFTP Boot from ROMMON') logger.info('=== Wait for installation to complete, timeout = {}' ' seconds ...'.format(str(timeout))) self.spawn_id.sendline('tftpdnld') d1 = Dialog([ ['rommon.*> ', 'sendline(tftpdnld)', None, True, False], ['Overwrite \(y/n\)', 'sendline(y)', None, True, False], ['login:'******'sendline()', None, False, False], ]) try: d1.process(self.spawn_id, timeout=timeout) self.spawn_id.sendline() except: logger.info("=== Rommon file download failed, raise runtime error. ") raise RuntimeError( ">>>>>> Download failed. Please check details - " "tftp_server: {}, image file: {}".format(self.rommon_tftp_server, self.rommon_image)) logger.info("=== Rommon file was installed successfully.")
def install_activate(self, steps, device, install_timeout=INSTALL_TIMEOUT): with steps.start("Activating operation ID {}".format( self.operation_id)) as step: cmd = 'install activate id {id}'.format(id=self.operation_id) install_activate_dialog = Dialog([ Statement(pattern='.*This install operation will reload the ' 'system\, continue\?.*\[yes[:\/]no\]\:\[yes\].*', action='sendline(yes)', loop_continue=False, continue_timer=False) ]) try: # send the install cmd device.sendline(cmd) # Process the dialog that appears install_activate_dialog.process(device.spawn, timeout=install_timeout) # Wait for successful output device.expect([self.successful_operation_string], timeout=install_timeout) except Exception as e: step.failed("Attempting to activate install id '{id}' " "failed. Error: {e}".format(id=self.operation_id, e=str(e)))
def _first_login(self): d0 = Dialog([ ['\(current\) UNIX password', 'sendline({})'.format(self.sm.patterns.default_password), None, True, False], ['New UNIX password', 'sendline({})'.format(self.sm.patterns.login_password), None, True, False], ['Retype new UNIX password', 'sendline({})'.format(self.sm.patterns.login_password), None, False, False], ['Press <ENTER> to display the EULA: ', 'sendline()', None, True, False], ['--More--', 'send(\x20)', None, True, False], ["Please enter 'YES' or press <ENTER> to AGREE to the EULA: ", 'sendline()', None, False, False], ]) accept_eula_dialog = Dialog([ ['Press <ENTER> to display the EULA: ', 'sendline()', None, True, False], ['--More--', 'send(\x20)', None, True, False], ["Please enter 'YES' or press <ENTER> to AGREE to the EULA: ", 'sendline()', None, False, False], ['Enter new password', 'sendline({})'.format(self.sm.patterns.login_password), None, True, False], ['Confirm new password', 'sendline({})'.format(self.sm.patterns.login_password), None, False, False], ]) try: d0.process(self.spawn_id, timeout=90) try: accept_eula_dialog.process(self.spawn_id, timeout=90) except TimeoutError: logger.info("=== EULA was not displayed") logger.info("=== Successfully completed the first login for fmc") except TimeoutError: logger.warning('Changing password for {} user was not required at this step'. format(self.sm.patterns.login_username)) self.spawn_id.sendline()
def enable_failover(self, unit, check_status=False, timeout=300): """Enable failover :param unit: asa instance where failover will be enabled :param check_status: option to check failover status. False by default :return: None """ unit.config('failover') if check_status: dialog = Dialog([ [ 'Beginning configuration replication', None, None, True, False ], [ 'End Configuration Replication to mate', 'sendline()', None, False, False ], ]) dialog.process(unit.asa_conn.spawn_id, timeout=timeout) start_time = time.time() while time.time() - start_time < timeout: if self.is_failover_formed(): break time.sleep(10) else: raise RuntimeError( 'HA pair not formed in {} sec'.format(timeout))
def __wait_for_rommon(spawn_id, timeout): # The system will reboot, wait for the following prompts d = Dialog([['Use BREAK or ESC to interrupt boot', 'sendline({})'.format(chr(27)), None, True, False], ]) for prompt in VALID_PROMPTS: d.append([prompt, None, None, False, False], ) d.process(spawn_id, timeout=timeout)
def ssh_vty(self, ip, port, username='******', password='******', timeout=None, line_type='ssh', rsa_key=None): """Set up an ssh connection to device's interface. This goes into device's ip address, not console. :param ip: ip address of terminal server :param port: port of device on terminal server :param username: usually "admin" :param password: usually "Admin123" :param line_type: ssh line type :param timeout: in seconds :param rsa_key: identity file (full path) :return: a line object (where users can call execute(), for example) """ graphite.publish_kick_metric('device.basic.ssh_vty', 1) if not timeout: timeout = self.default_timeout if rsa_key: resp = subprocess.getoutput('chmod 400 {}'.format(rsa_key)) if 'No such file or directory' in resp: raise RuntimeError( 'The identity file {} you provided does not exist'.format( rsa_key)) spawn_id = NewSpawn( 'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no ' '-i {} -l {} -p {} {} \n'.format(rsa_key, username, port, ip)) else: spawn_id = NewSpawn( 'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no ' '-l {} -p {} {} \n'.format(username, port, ip)) ctx = AttributeDict({'password': password}) d = Dialog([ [ 'continue connecting (yes/no)?', 'sendline(yes)', None, True, False ], ['(p|P)assword:', 'sendline_ctx(password)', None, True, False], ['Password OK', 'sendline()', None, False, False], ['[.*>#$]+.*\s', 'sendline()', None, False, False], ]) d.process(spawn_id, context=ctx, timeout=timeout) ssh_line = self.line_class(spawn_id, self.sm, line_type, timeout) logger.debug('ssh_vty() finished successfully') return ssh_line
def wait_for_launch_complete(self, initial_discovery_wait_sec, initial_wait_sec, post_prompt_wait_sec, connection, log, hostname, checkpoint_pattern, learn_hostname=False): con = connection # Checking if a device is launching or not log.info('Trying to connect to prompt on device {} ...'.\ format(hostname)) spawn = connection.spawn initial_prompts = [ patterns.enable_prompt.replace( '%N', con.settings.DEFAULT_LEARNED_HOSTNAME if learn_hostname else hostname), patterns.config_prompt.replace( '%N', con.settings.DEFAULT_LEARNED_HOSTNAME if learn_hostname else hostname), patterns.secret_password_prompt, patterns.username_prompt, patterns.password_prompt, patterns.standby_prompt, patterns.logout_prompt ] result = False dialog = Dialog([[p, None, None, False, False] for p in initial_prompts]) for x in range(connection.settings.INITIAL_DISCOVERY_RETRIES): try: spawn.sendline() result = dialog.process(spawn, timeout=initial_discovery_wait_sec) if result: break except TimeoutError: pass if result is False: log.info("Can not access prompt on device {} so assuming " " virtual launch is in progress ...".\ format(hostname)) dialog += Dialog([[p, None, None, False, False] \ for p in [checkpoint_pattern, patterns.standby_prompt]]) result = dialog.process(spawn, timeout=initial_wait_sec) log.info("Final steps in launching virtual device {} detected: " "will attempt to access prompt in ~{} seconds.".\ format(hostname, post_prompt_wait_sec)) # Random timer to display prompts from different routers with a # slight delay from each other time.sleep(post_prompt_wait_sec - 10 + randint(10, 30))
def boot_fxos(statemachine, spawn, context): spawn.sendline('boot') boot_wait(spawn, timeout=spawn.settings.BOOT_TIMEOUT) spawn.sendline() dialog = Dialog([ generic_statements.login_stmt, generic_statements.password_stmt, Statement(patterns.fxos_prompt) ]) dialog.process(spawn, context=context) spawn.sendline()
def set_boot_image(self, tftp_server, boot_image, timeout=20): """Function for setting the new boot system image :param tftp_server: tftp server ip e.g: '192.168.0.50' :param boot_image: the name of the boot image given with its absolute path e.g. asa/asa952-2-smp-k8.bin for saleen or asa/asa962-21-lfbff-k8.SPA for Kenton asa962-21-lfbff-k8.SPA :param timeout: defaulted to 20s :return: None """ self.go_to('config_state') # remove previous images output = self.execute('show running-config boot system') if output: images = re.findall(r'disk0:/.*', output) logger.info('Removing previous boot system images') if images: for i in images: self.execute('no boot system {}'.format(i), timeout) logger.info('Copying the new ASA image to the ASA, placing the image in disk0') asa_boot_image = PurePosixPath(boot_image).name or boot_image command = 'copy /noconfirm tftp://{}/{} disk0:{}'.format(tftp_server, boot_image, asa_boot_image) self.spawn_id.sendline(command) d1 = Dialog([ ['Do you want to over write?', 'sendline()', None, True, False], ['Accessing tftp', None, None, True, True], ['Digital signature successfully validated', None, None, True, False], ['bytes copied in .* secs', 'sendline()', None, False, False], ['Error', None, None, False, False], [self.sm.patterns.prompt.config_prompt, 'sendline()', None, False, False], ]) resp = d1.process(self.spawn_id, timeout=1200) if isinstance(resp, ExpectMatch): if 'Error' in resp.match_output: logger.error('An error appeared while downloading the image, ' 'please check the name of the boot image and its path') raise RuntimeError('An error appeared while downloading the boot image, ' 'please check your file path') logger.info('Setting new boot system image') self.execute('boot system disk0:/{}'.format(asa_boot_image, timeout)) self.spawn_id.sendline('write memory') d2 = Dialog([ #[self.sm.patterns.prompt.config_prompt, 'sendline(write memory)', None, True, False], ['Building configuration', None, None, True, False], ['[OK]', 'sendline()', None, True, False], [self.sm.patterns.prompt.config_prompt, None, None, False, False], ]) d2.process(self.spawn_id, timeout=60)
def _boot_selection(self, spawn, prompt): spawn.send("\t") spawn.expect('boot:') spawn.send("\t") spawn.expect('boot:') spawn.send("System_Restore\r") d1 = Dialog([ ['1. Load with serial console', None, None, True, False], ['boot:', 'sendline({})'.format('1'), None, True, False], [prompt, None, None, False, False], ]) d1.process(spawn, timeout=300)
def configure_ssh_v2(self, gateway, netmask, user, passwd, activation_key=''): """Function to configure ssh version 2 :param gateway: :param netmask: the ip netmask to apply to the ip :param user: username of the user :param passwd: the password for user :param activation_key: string containing a Encryption-3DES-AES activation key e.g.: '7717d15c 7451cf52 b81171b4 979c3404 c51501b3' :return: None """ self.go_to('config_state') self.spawn_id.sendline('crypto key generate rsa modulus 1024') d = Dialog([ [ 'Keypair generation process begin. Please wait', None, None, True, False ], [ 'Do you really want to replace them?', 'sendline(no)', None, True, False ], [self.sm.patterns.prompt.config_prompt, None, None, False, False], ]) d.process(self.spawn_id, 30) cmd_lines1 = 'ssh {} {} diagnostic\n' \ 'ssh timeout 60\n' \ 'route diagnostic 0 0 {} 1\n' \ 'username {} password {}\n' \ 'aaa authentication ssh console LOCAL'.format(gateway, netmask, gateway, user, passwd) logger.info("Configure ssh") self.config(cmd_lines1) if activation_key: logger.info("Apply ssh activation key") self.config('activation-key {}'.format(activation_key), 300, True) try: self.config('ssh version 2', None, True) except Exception as e: logger.info('SSH version2 could not be activated') raise e
def firepower_boot_configure(self): """In boot CLI mode, set device network info, DNS server and domain. :return: None """ d1 = Dialog([ ['login:'******'sendline(admin)', None, True, False], ['Password: '******'sendline({})'.format(self.sm.patterns.default_password), None, True, False], ['-boot>', 'sendline(setup)', None, False, False], ]) d1.process(self.spawn_id, timeout=30) set_ntp_server = 'n' if self.ntp_server == None else 'y' d2 = Dialog([ ['Enter a hostname ', 'sendline(firepower)', None, True, False], ['Do you want to configure IPv4 address on management interface', 'sendline(y)', None, True, False], ['Do you want to enable DHCP for IPv4 address assignment on ' 'management interface', 'sendline(n)', None, True, False], ['Enter an IPv4 address', 'sendline({})'.format(self.uut_ip), None, True, False], ['Enter the netmask', 'sendline({})'.format(self.uut_netmask), None, True, False], ['Enter the gateway', 'sendline({})'.format(self.uut_gateway), None, True, False], ['Do you want to configure static IPv6 address on management ' 'interface', 'sendline(n)', None, True, False], ['Enter the primary DNS server IP address', 'sendline({})'.format(self.dns_server.split(',')[0]), None, True, False], ['Do you want to configure Secondary DNS Server', 'sendline(n)', None, True, False], ['Do you want to configure Local Domain Name', 'sendline(n)', None, True, False], ['Do you want to configure Search domains', 'sendline(y)', None, True, False], ['Enter the comma separated list for search domains', 'sendline({})'.format(self.search_domains), None, True, False], ['Do you want to enable the NTP service', 'sendline({})'.format(set_ntp_server), None, True, False], ['Enter the NTP servers separated by commas', 'sendline({})'.format(self.ntp_server), None, True, False], ['Do you want to enable the NTP symmetric key authentication', 'sendline(n)', None, True, False], ['Apply the changes', 'sendline(y)', None, True, False], ['Press ENTER to continue...', 'sendline()', None, True, False], ['-boot>', 'sendline()', None, False, False], ]) d2.process(self.spawn_id, timeout=120)
def config_transition(statemachine, spawn, context): # Config may be locked, retry until max attempts or config state reached wait_time = spawn.settings.CONFIG_LOCK_RETRY_SLEEP max_attempts = spawn.settings.CONFIG_LOCK_RETRIES dialog = Dialog([ Statement(pattern=patterns.config_locked, action=update_context, args={'config_locked': True}, loop_continue=False, trim_buffer=True), Statement(pattern=statemachine.get_state('enable').pattern, action=update_context, args={'config_locked': False}, loop_continue=False, trim_buffer=False), Statement(pattern=statemachine.get_state('config').pattern, action=update_context, args={'config_locked': False}, loop_continue=False, trim_buffer=False) ]) for attempts in range(max_attempts + 1): spawn.sendline(statemachine.config_command) try: dialog.process(spawn, timeout=spawn.settings.CONFIG_TIMEOUT, context=context) except UniconTimeoutError: pass if context.get('config_locked'): if attempts < max_attempts: spawn.log.warning( '*** Config lock detected, waiting {} seconds. Retry attempt {}/{} ***' .format(wait_time, attempts + 1, max_attempts)) sleep(wait_time) else: statemachine.detect_state(spawn) if statemachine.current_state == 'config': return else: spawn.log.warning( "Could not enter config mode, sending clear line command and trying again.." ) spawn.send(spawn.settings.CLEAR_LINE_CMD) if context.get('config_locked'): raise StateMachineError('Config locked, unable to configure device') else: raise StateMachineError('Unable to transition to config mode')
def connect_from_ssp(self, ssp_line, slot, timeout=None, ld_name=''): """Connect through SSP telnet console :param ssp_line: SSP connection instance :param slot: module # that ASA is installed on :param timeout: timeout to wait for asa connection to be ready in seconds :param ld_name: logical device name for multi instance only :return: line object of ASA device To connect to ASA console from SSP MIO (BS-FPR9300/QP-FPR4100), following sequence of commands are needed: - connect module 1(2,3) console * we now enter Firepower mode, with prompts such as "Firepower-module1>","Firepower-module2>" or "Firepower-module3>" - connect asa * this brings us to asa mode with promps such as "ciscoasa>", "ciscoasa#" etc After this cli is entered, console messages from previous sessions will roll up. Sometimes these messages are not ended w/ newline thus not able to bring up asa prompt. For this kind of scenarios, we need to send a newline to bring up asa prompt. """ if not timeout: timeout = DEFAULT_TIMEOUT ssp_line.go_to('mio_state') # connect to module ssp_line.spawn_id.sendline('connect module {} console'.format(slot)) time.sleep(0.5) ssp_line.spawn_id.sendline() ssp_line.spawn_id.sendline() # pylint: disable=anomalous-backslash-in-string asa_prompt = '[\r\n]({}|ciscoasa|asa)[/\w\(\)-]*[>#] '.format( self.patterns.hostname) dialog = Dialog([[ 'Firepower-module{}>'.format(slot), 'sendline(connect asa {})'.format(ld_name), None, True, False ], ['Connecting to ', 'sendline()', None, True, False], [asa_prompt, 'sendline()', None, False, False]]) dialog.process(ssp_line.spawn_id, timeout=timeout) asa_line = self.line_class(ssp_line.spawn_id, self.sm, 'telnet', carrier='ssp', timeout=timeout) return asa_line
def rommon_go_to(self, timeout=180): """Go to rommon mode. :return: None """ # break into rommon d1 = Dialog([ ['Use SPACE to begin boot immediately.', 'sendline({})'.format(chr(27)), None, False, False], ]) d1.process(self.spawn_id, timeout=timeout) time.sleep(10) logger.info('In rommon mode')
def return_to_cli_root(self, state): handle = self.get_handle() state = handle.state_machine.get_state(state) statement = Statement(pattern=state.pattern, action=None, args=None, loop_continue=False, continue_timer=False, trim_buffer=True) dialog = Dialog([sros_statements.discard_uncommitted, statement]) handle.spawn.send(KEY_RETURN_ROOT) try: dialog.process(handle.spawn) except Exception as err: raise SubCommandFailure('Return to cli root failed', err) from err
def reboot_cimc(self, ip, port, cimc_username='******', cimc_password='******', retries=10, interval=120): """This is the method to reboot cimc :param ip: FMC CIMC IP :param port: ssh port for FMC CIMC :param cimc_username: ssh username for FMC CIMC :param cimc_password: ssh password for FMC CIMC :param retries: polling attempts to check if CIMC is back :param interval: polling interval :return: True/False to indicate sucess """ self.ssh_cimc(ip, port, cimc_username, cimc_password) self.spawn_id.sendline("top") self.spawn_id.sendline("scope cimc") d1 = Dialog([ ['/cimc.*#', 'sendline(reboot)', None, True, False], ['Continue?.*', 'sendline(y)', None, False, False], ]) d1.process(self.spawn_id, timeout=30) self.spawn_id.sendline() self.spawn_id.sendline() logger.info("Sleeping for 60 secs..") time.sleep(60) while retries > 0: logger.info( "Wait for CIMC to be back. Attempt: {}".format(retries)) try: line = self.ssh_cimc(ip, port, cimc_username, cimc_password) if line is not None: line.disconnect() break except: logger.info("CIMC did not respond") time.sleep(interval) retries -= 1 if retries == 0: logger.error("CIMC did not come back after reboot") return False else: return True
def _cli(device, cmd, timeout, prompt): """ Send command to device and get the output Args: device (`obj`): Device object cmd (`str`): Command timeout (`int`): Timeout in second prompt (`obj`): Unicon statement Returns: output (`obj`): Output """ # Create a dialog state = device.state_machine.current_state pattern = device.state_machine.get_state(state).pattern device.send(cmd) statements = [] statements.append(prompt) statements.append(Statement(pattern=pattern)) statements.extend(device.state_machine.default_dialog) statements.extend(default_statement_list) dialog = Dialog(statements) output = dialog.process(device.spawn, timeout=timeout) return output
def ssh_cimc(self, ip, port, cimc_username='******', cimc_password='******', timeout=None): """This is the method to login to FMC via CIMC Interface. :param ip: FMC CIMC IP :param port: ssh port for FMC CIMC :param cimc_username: ssh username for FMC CIMC :param cimc_password: ssh password for FMC CIMC :param timeout: timeout for ssh login :return: ssh_line """ publish_kick_metric('device.m4.ssh', 1) if not timeout: timeout = self.default_timeout self.spawn_id = Spawn('ssh -o UserKnownHostsFile=/dev/null' ' -o StrictHostKeyChecking=no ' '-l {} -p {} {}'.format(cimc_username, port, ip)) d1 = Dialog([ [ 'continue connecting (yes/no)?', 'sendline(yes)', None, True, False ], [ '[Pp]assword:', 'sendline({})'.format(cimc_password), None, True, False ], [self.sm.get_state('mio_state').pattern, None, None, False, False], ]) try: d1.process(self.spawn_id, timeout=60) self.spawn_id.sendline() self.spawn_id.sendline() except TimeoutError: pass ssh_line = self.line_class(self.spawn_id, self.sm, 'ssh_cimc', timeout=timeout) logger.debug("Done: connection created by ssh {} {}".format(ip, port)) return ssh_line
def boot_wait(spawn, timeout=600): def count(spawn, context, session): m = re.findall(patterns.boot_wait_msg, spawn.buffer, re.M) session['matches'] = session.get('matches', len(m)) + len(m) matches = session['matches'] if matches >= spawn.settings.BOOT_WAIT_PATTERN_COUNT: raise ValueError wait_dialog = Dialog([Statement(patterns.boot_wait_msg, action=count, loop_continue=True, continue_timer=True)]) while True: try: wait_dialog.process(spawn, timeout=timeout) except ValueError: break # Wait a bit until the terminal is finished logging the interfaces messages chatty_term_wait(spawn)
def wait_until_device_on(self, timeout=600): """ Wait a given period of time for device to be on :param timeout: wait time for the device to boot up :return: None """ # The system will reboot, wait for the following prompts d1 = Dialog([ ['SW-DRBG health test passed', None, None, False, False], ]) d1.process(self.spawn_id, timeout=timeout) # sleep 60 seconds to avoid errors time.sleep(60) self.sm.go_to('any', self.spawn_id)
def _accept_configuration_and_change_password(self, spawn_id, line_type, username, password, timeout): """ Confirm device properties and change password to a dummy one and then back to the one provided by the user :param spawn_id: NewSpawn object :param line_type: 'ssh' or 'ssh_vty' :param username: usually 'admin' :param password: password for ssh access :param timeout: timeout for ssh connection :return: """ ssh_line = None d_change_password = Dialog( [['Password OK', 'sendline()', None, False, False], ['[.*># $] ', 'sendline()', None, False, False], [ 'You are required to change your password immediately', None, None, True, False ], [ '\(current\) UNIX password', 'sendline({})'.format(password), None, True, False ], [ 'New UNIX password', 'sendline({})'.format(KickConsts.DUMMY_PASSWORD), None, True, False ], [ 'Retype new UNIX password', 'sendline({})'.format(KickConsts.DUMMY_PASSWORD), None, True, False ], ['Password unchanged', None, None, False, False]]) response = d_change_password.process(spawn_id, timeout=60) if response and 'Password unchanged' in response.match_output: logger.error( 'Changing password for {} user has failed'.format(username)) spawn_id.close() raise Exception( 'Error while changing {} password to the temporary one'.format( username)) CONFIGURATION_DIALOG.process(spawn_id, timeout=300) if response and 'You are required to change your password immediately' in response.match_output: logger.info( "Change back dummy password: '******' to the one provided by the user" .format(KickConsts.DUMMY_PASSWORD)) ssh_line = self.line_class(spawn_id, self.sm, line_type, timeout=timeout) _set_password(ssh_line, username, password) return ssh_line
def call_service(self, command, reply=Dialog([]), timeout=None, error_pattern=None, *args, **kwargs): con = self.connection timeout = timeout or self.timeout if error_pattern is None: self.error_pattern = con.settings.ERROR_PATTERN else: self.error_pattern = error_pattern if not isinstance(command, str): raise SubCommandFailure('Command is not a string: %s' % type(command)) if not isinstance(reply, Dialog): raise SubCommandFailure( "dialog passed via 'reply' must be an instance of Dialog") sm = self.get_sm() self.start_state = sm.current_state con.log.debug("+++ command '%s' +++" % command) timeout = timeout or con.settings.EXEC_TIMEOUT if 'service_dialog' in kwargs: service_dialog = kwargs['service_dialog'] if service_dialog is None: service_dialog = Dialog([]) elif not isinstance(service_dialog, Dialog): raise SubCommandFailure( "dialog passed via 'service_dialog' must be an instance of Dialog" ) dialog = self.service_dialog(service_dialog=service_dialog + reply) else: dialog = Dialog(execution_statement_list) dialog += self.service_dialog(service_dialog=reply) for state in sm.states: dialog.append(Statement(pattern=state.pattern)) con.sendline(command) try: self.result = dialog.process(con.spawn, timeout=timeout) except Exception as err: raise SubCommandFailure("Command execution failed", err) if self.result: self.result = self.result.match_output sm.detect_state(con.spawn) self.end_state = sm.current_state
def enable_configure(self, timeout=20): """Used to enable configure terminal :param timeout: time to wait for the output of a command; default is 30s :return: None """ d = Dialog([ ['-boot>', 'sendline()', None, False, False], [self.sm.patterns.prompt.enable_prompt, 'sendline()', None, False, False], [self.sm.patterns.prompt.disable_prompt, 'sendline()', None, False, False], ['login', 'sendline({})'.format(self.sm.patterns.username), None, True, False], ['(p|P)assword:', 'sendline({})'.format(self.sm.patterns.login_password), None, False, False], ]) d1 = Dialog([ ['Would you like to enable anonymous error reporting to help improve', 'sendline(N)', None, True, False], [self.sm.patterns.prompt.config_prompt, 'sendline()', None, False, False], ]) try: self.go_to('any') except: logger.info("Device is rebooting") d.process(self.spawn_id, timeout=600) self.go_to('any') self.go_to('enable_state') time.sleep(0.5) logger.info("=== Configure terminal ") self.spawn_id.sendline('conf t') time.sleep(0.5) if 'Invalid input detected' in self.spawn_id.read(): self.spawn_id.sendline() time.sleep(0.5) self.spawn_id.expect(self.sm.patterns.prompt.enable_prompt) output = self.execute('show running-config | grep Serial Number', 15) sn = re.findall(r'Serial Number:\s(\w+)', output)[0] new_sn = '1111222233334444' + sn self.sudo_execute('echo -n {}| md5sum > /mnt/disk0/enable_configure'.format(new_sn), timeout) self.go_to('config_state') d1.process(self.spawn_id, timeout=30)