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 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 call_service(self, addr, command="ping", **kwargs): if not addr: raise SubCommandFailure("Address is not specified") if 'error_pattern' in kwargs: self.error_pattern = kwargs['error_pattern'] if self.error_pattern is None: self.error_pattern = [] if not isinstance(self.error_pattern, list): raise ValueError('error pattern must be a list') kwargs.pop('error_pattern') else: self.error_pattern = self.default_error_pattern con = self.connection # Default value setting timeout = self.timeout ping_options = AttributeDict({}) ping_options['c'] = '5' # default to 5 packets # Read input values passed # Convert to string in case users passes non-string types for key in kwargs.copy(): if key in self._ping_option_long_to_short: new_key = self._ping_option_long_to_short[key] kwargs[new_key] = kwargs[key] kwargs.pop(key) key = new_key if key == 'options': for o in str(kwargs['options']): if o in self.ping_boolean_options: ping_options[o] = "" # Boolean options else: log.warning('Uknown ping option - %s, ignoring' % o) elif key in self.ping_arg_options: ping_options[key] = str(kwargs[key]) else: log.warning('Uknown ping option - %s, ignoring' % key) if not 'options' in kwargs: ping_options['A'] = "" # Default to adaptive ping ipaddr = ipaddress.ip_address(addr) if isinstance(ipaddr, ipaddress.IPv6Address): ping_str = 'ping6' elif isinstance(ipaddr, ipaddress.IPv4Address): ping_str = 'ping' else: # Stringify the command in case it is an object. ping_str = str(command) for ping_option in sorted(ping_options): ping_str += ' -%s%s' % (ping_option, ping_options[ping_option]) ping_str += ' %s' % addr p = LinuxPatterns() dialog = Dialog() dialog.append(Statement(pattern=p.prompt)) spawn = con.spawn spawn.sendline(ping_str) try: self.result = dialog.process(spawn, timeout=timeout) except Exception as err: raise SubCommandFailure("Ping failed", err) # Remove command and hostname from output. if self.result: output = utils.truncate_trailing_prompt( con.state_machine.get_state(con.state_machine.current_state), self.result.match_output, self.connection.hostname) output = re.sub(re.escape(ping_str), "", output, 1) self.result = output.strip() # Error checking is not part of the linux base infra, adding it here for now # TODO: update linux infra self.match_flag = False self.match_list = [] for pat in self.error_pattern: m = re.search(pat, self.result) if m: self.match_list.append(m.group()) self.match_flag = True if self.match_flag: raise SubCommandFailure(self.result, self.match_list)
class Reload(BaseService): """Service to reload the device. Arguments: reload_command: reload command to be issued on device. default reload_command is "reload" dialog: Dialog which include list of Statements for additional dialogs prompted by reload command, in-case it is not in the current list. timeout: Timeout value in sec, Default Value is 400 sec image_to_boot: image to be used if the device stops in rommon mode Returns: bool: True on success False otherwise Raises: SubCommandFailure: on failure. Example: .. code-block:: python uut.reload() uut.reload(image_to_boot=""tftp://172.18.200.210/image.bin"") """ def __init__(self, connection, context, **kwargs): super().__init__(connection, context, **kwargs) self.start_state = 'enable' self.end_state = 'enable' self.service_name = 'reload' self.timeout = connection.settings.RELOAD_TIMEOUT self.dialog = Dialog(reload_statement_list) self.dialog.append(boot_reached) def call_service(self, reload_command='reload', dialog=Dialog([]), timeout=None, return_output=False, *args, **kwargs): con = self.connection timeout = timeout or self.timeout assert isinstance(dialog, Dialog), "dialog passed must be an instance of Dialog" dialog += self.dialog con.log.debug( "+++ reloading {} with reload_command {} and timeout is {} +++" .format(self.connection.hostname, reload_command, timeout)) context = AttributeDict(self.context) if "image_to_boot" in kwargs: context["image_to_boot"] = kwargs["image_to_boot"] con.state_machine.go_to(self.start_state, con.spawn, context=context) dialog = self.service_dialog(service_dialog=dialog) con.spawn.sendline(reload_command) try: reload_op=dialog.process(con.spawn, context=context, timeout=timeout, prompt_recovery=self.prompt_recovery) con.state_machine.go_to(['disable', 'enable'], con.spawn, context=context, timeout=con.connection_timeout, prompt_recovery=self.prompt_recovery) except Exception as err: raise SubCommandFailure("Reload failed : {}".format(err)) # Issue init commands to disable console logging and perform # initial configuration (in case "write erase" was done before reload). # # This logic is shared with the generic plugin's HAReloadService. exec_commands = self.connection.settings.HA_INIT_EXEC_COMMANDS for command in exec_commands: con.execute(command, prompt_recovery=self.prompt_recovery) config_commands = self.connection.settings.HA_INIT_CONFIG_COMMANDS config_retry = 0 while config_retry < \ self.connection.settings.CONFIG_POST_RELOAD_MAX_RETRIES: try: con.configure(config_commands, timeout=60, prompt_recovery=self.prompt_recovery) except Exception as err: if re.search("Config mode locked out", str(err)): sleep(self.connection.settings.\ CONFIG_POST_RELOAD_RETRY_DELAY_SEC) con.spawn.sendline() config_retry += 1 else: break con.log.debug("+++ Reload Completed Successfully +++") self.result = True if return_output: self.result = ReloadResult(self.result, reload_op.match_output.replace(reload_command, '', 1))
def firepower_install(self): """Perform ping test and verify the network connectivity to TFTP server. Install FTD pkg image Enter device network info, hostname, and firewall mode. :return: None """ for i in range(40): self.spawn_id.sendline('ping -c 1 {}'.format(self.rommon_tftp_server)) try: self.spawn_id.expect('64 bytes from', timeout=5) except TimeoutError: time.sleep(60) continue else: break else: raise RuntimeError(">>>>>> Ping not working") d0 = Dialog([ ['-boot>', 'sendline(system install {})'.format(self.pkg_image), None, False, False] ]) d1 = Dialog([ ['Do you want to continue\?', 'sendline(y)', None, True, False], ['Upgrade aborted', 'sendline()', None, False, False], ['Installation aborted', 'sendline()', None, False, False], ['Package Detail', None, None, False, False] ]) count = 0 while count < self.retry_count: d0.process(self.spawn_id, timeout=20) match = d1.process(self.spawn_id, timeout=600) if self._last_match_index(match) == 3: break count += 1 time.sleep(5) else: # didn't break out raise RuntimeError('ftd installation failed, please check ' 'ftd package url: "{}"'.format(self.pkg_image)) d2 = Dialog([ ['Do you want to continue with upgrade\?', 'sendline(y)', None, False, False], ]) # used to take 2 minutes d2.process(self.spawn_id, timeout=1200) # Handle the case "Press 'Enter' to reboot the system." was never displayed # Script stuck if message above is not displayed but the device is waiting for 'enter' count = 0 waittime = 60 total = 60 d2_2 = Dialog([ ["Press 'Enter' to reboot the system.", 'sendline()', None, True, False], ['Use SPACE to begin boot immediately.', 'send(" ")', None, True, False], ['Use SPACE to launch Cisco FTD immediately.', 'send(" ")', None, True, False], ['firepower login: '******'sendline()', None, False, False], ]) while count < total: self.spawn_id.sendline() try: d2_2.process(self.spawn_id, timeout=waittime) break except: logger.info('=== Wait for firepower login: ({})'.format(count)) count += 1 time.sleep(5) continue # Allow install processes to finish # Sleep was extended to 5 minutes as part of CSCvi89671 # TODO: This sleep should be removed once CSCvi89616 is resolved time.sleep(300) d3 = Dialog([ ['firepower login: '******'sendline(admin)', None, True, False], ['Password: '******'sendline({})'.format(self.sm.patterns.default_password), None, True, False], ['Press <ENTER> to display the EULA: ', 'sendline()', None, True, False], ['--More--', 'send(q)', None, True, False], ["Please enter 'YES' or press <ENTER> to AGREE to the EULA: ", 'sendline(YES)', None, False, False], ]) d3.process(self.spawn_id, timeout=600) d4 = Dialog([ ['firepower login: '******'sendline(admin)', None, True, False], ['Password: '******'sendline({})'.format(self.sm.patterns.login_password), None, True, False], ['Enter new password:'******'sendline({})'.format(self.sm.patterns.login_password), None, True, True], ['Confirm new password:'******'sendline({})'.format(self.sm.patterns.login_password), None, True, False], ['Do you want to configure IPv4', 'sendline(y)', None, True, False], ]) if self.uut_ip6 is None: d4.append(['Do you want to configure IPv6', 'sendline(n)', None, True, False]) else: d4.append(['Do you want to configure IPv6', 'sendline(y)', None, True, False]) d4.append(['Configure IPv4 via DHCP or manually', 'sendline(manual)', None, True, False]) d4.append(['Enter an IPv4 address for the management interface', 'sendline({})'.format(self.uut_ip), None, True, False]) d4.append(['Enter an IPv4 netmask for the management interface', 'sendline({})'.format(self.uut_netmask), None, True, False]) d4.append(['Enter the IPv4 default gateway for the management interface', 'sendline({})'.format(self.uut_gateway), None, True, False]) if self.uut_ip6 is not None: d4.append(['Configure IPv6 via DHCP, router, or manually', 'sendline(manual)', None, True, False]) d4.append(['Enter the IPv6 address for the management interface', 'sendline({})'.format(self.uut_ip6), None, True, False]) d4.append(['Enter the IPv6 address prefix for the management interface', 'sendline({})'.format(self.uut_prefix), None, True, False]) d4.append(['Enter the IPv6 gateway for the management interface', 'sendline({})'.format(self.uut_gateway6), None, True, False]) d4.append(['Enter a fully qualified hostname for this system', 'sendline({})'.format(self.hostname), None, True, False]) d4.append(['Enter a comma-separated list of DNS servers or', 'sendline({})'.format(self.dns_server), None, True, False]) d4.append(['Enter a comma-separated list of search domains or', 'sendline({})'.format(self.search_domains), None, False, False]) d4.process(self.spawn_id, timeout=900) d5 = Dialog([ ['Configure (firewall|deployment) mode', 'sendline({})'.format(self.firewall_mode), None, True, False] ]) if self.mode == 'local': d5.append(['Manage the device locally?', 'sendline(yes)', None, True, False]) else: d5.append(['Manage the device locally?', 'sendline(no)', None, True, False]) d5.append(['Successfully performed firstboot initial configuration steps', 'sendline()', None, True, False]) d5.append(['> ', 'sendline()', None, False, False]) d5.process(self.spawn_id, timeout=600) logger.info('fully installed.')
def ftd_configure(self): """Accept EULA, enter new password and configure network for ftd. :return: None """ time.sleep(10) for i in range(20): self.spawn_id.sendline('') try: self.go_to('any') except: continue else: break else: raise RuntimeError(">>>>>> Switching back to enable mode failed") self.execute_and_verify(cmd='show module sfr details | grep ^Status', expected_str='Up', timeout=360, interval=10, timeout_total=7200, retry_count=360) self.spawn_id.sendline('session sfr console\n') d1 = Dialog([ [ 'firepower login: '******'sendline({})'.format(self.sm.patterns.username), None, True, False ], [ 'Password: '******'sendline({})'.format(self.sm.patterns.default_password), None, True, False ], [ 'Press <ENTER> to display the EULA: ', 'sendline()', None, True, False ], ['--More--', 'send(q)', None, True, False], [ "Please enter 'YES' or press <ENTER> to AGREE to the EULA: ", 'sendline(YES)', None, False, False ], ]) d1.process(self.spawn_id, timeout=600) d2 = Dialog([[ 'Enter new password:'******'sendline({})'.format(self.sm.patterns.login_password), None, True, True ], [ 'Confirm new password:'******'sendline({})'.format( self.sm.patterns.login_password), None, True, False ], [ 'Do you want to configure IPv4', 'sendline(y)', None, True, False ]]) if self.uut_ip6 is None: d2.append([ 'Do you want to configure IPv6', 'sendline(n)', None, True, False ]) else: d2.append([ 'Do you want to configure IPv6', 'sendline(y)', None, True, False ]) d2.append([ 'Configure IPv4 via DHCP or manually', 'sendline(manual)', None, True, False ]) d2.append([ 'Enter an IPv4 address for the management interface', 'sendline({})'.format(self.uut_ip), None, True, False ]) d2.append([ 'Enter an IPv4 netmask for the management interface', 'sendline({})'.format(self.uut_netmask), None, True, False ]) d2.append([ 'Enter the IPv4 default gateway for the management interface', 'sendline({})'.format(self.uut_gateway), None, True, False ]) if self.uut_ip6 is not None: d2.append([ 'Configure IPv6 via DHCP, router, or manually', 'sendline(manual)', None, True, False ]) d2.append([ 'Enter the IPv6 address for the management interface', 'sendline({})'.format(self.uut_ip6), None, True, False ]) d2.append([ 'Enter the IPv6 address prefix for the management interface', 'sendline({})'.format(self.uut_prefix), None, True, False ]) d2.append([ 'Enter the IPv6 gateway for the management interface', 'sendline({})'.format(self.uut_gateway6), None, True, False ]) d2.append([ 'Enter a fully qualified hostname for this system ', 'sendline({})'.format(self.hostname), None, True, False ]) d2.append([ 'Enter a comma-separated list of DNS servers or', 'sendline({})'.format(self.dns_server), None, True, False ]) d2.append([ 'Enter a comma-separated list of search domains or', 'sendline({})'.format(self.search_domains), None, True, False ]) d2.append(['> ', 'sendline()', None, False, False]) d2.process(self.spawn_id, timeout=900) logger.info('fully installed.')
def firepower_install(self): """Perform ping test and verify the network connectivity to TFTP server. Install Elektra pkg image Enter device network info, hostname, and firewall mode. :return: None """ for i in range(20): self.spawn_id.sendline('ping -c 1 {}'.format(self.rommon_tftp_server)) try: self.spawn_id.expect('64 bytes from', timeout=5) except TimeoutError: time.sleep(60) continue else: break else: raise RuntimeError(">>>>>> Ping not working") d0 = Dialog([ ['-boot>', 'sendline(system install {})'.format(self.pkg_image), None, False, False] ]) d1 = Dialog([ ['Do you want to continue?', 'sendline(y)', None, True, False], ['Upgrade aborted', 'sendline()', None, False, False], ['Installation aborted', 'sendline()', None, False, False] ]) count = 0 while count < self.retry_count: try: d0.process(self.spawn_id, timeout=20) d1.process(self.spawn_id, timeout=60) count += 1 time.sleep(5) except: break assert count < self.retry_count, 'elektra installation failed' \ ', please check elektra 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], ['Use SPACE to begin boot immediately.', 'send(" ")', None, True, True], ['firepower login: '******'sendline()', None, False, False], ]) d2.process(self.spawn_id, timeout=3900) # Allow install processes to finish time.sleep(180) d3 = Dialog([ ['firepower login: '******'sendline(admin)', None, True, False], ['Password: '******'sendline({})'.format(self.sm.patterns.default_password), None, True, False], ['Press <ENTER> to display the EULA: ', 'sendline()', None, True, False], ['--More--', 'send(q)', None, True, False], ["Please enter 'YES' or press <ENTER> to AGREE to the EULA: ", 'sendline(YES)', None, False, False], ]) d3.process(self.spawn_id, timeout=600) d4 = Dialog([ ['firepower login: '******'sendline(admin)', None, True, False], ['Password: '******'sendline({})'.format(self.sm.patterns.login_password), None, True, False], ['Enter new password:'******'sendline({})'.format(self.sm.patterns.login_password), None, True, True], ['Confirm new password:'******'sendline({})'.format(self.sm.patterns.login_password), None, True, False], ['Do you want to configure IPv4', 'sendline(y)', None, True, False], ]) if self.uut_ip6 is None: d4.append(['Do you want to configure IPv6', 'sendline(n)', None, True, False]) else: d4.append(['Do you want to configure IPv6', 'sendline(y)', None, True, False]) d4.append(['Configure IPv4 via DHCP or manually', 'sendline(manual)', None, True, False]) d4.append(['Enter an IPv4 address for the management interface', 'sendline({})'.format(self.uut_ip), None, True, False]) d4.append(['Enter an IPv4 netmask for the management interface', 'sendline({})'.format(self.uut_netmask), None, True, False]) d4.append(['Enter the IPv4 default gateway for the management interface', 'sendline({})'.format(self.uut_gateway), None, True, False]) if self.uut_ip6 is not None: d4.append(['Configure IPv6 via DHCP, router, or manually', 'sendline(manual)', None, True, False]) d4.append(['Enter the IPv6 address for the management interface', 'sendline({})'.format(self.uut_ip6), None, True, False]) d4.append(['Enter the IPv6 address prefix for the management interface', 'sendline({})'.format(self.uut_prefix), None, True, False]) d4.append(['Enter the IPv6 gateway for the management interface', 'sendline({})'.format(self.uut_gateway6), None, True, False]) d4.append(['Enter a fully qualified hostname for this system ', 'sendline({})'.format(self.hostname), None, True, False]) d4.append(['Enter a comma-separated list of DNS servers or', 'sendline({})'.format(self.dns_server), None, True, False]) d4.append(['Enter a comma-separated list of search domains or', 'sendline({})'.format(self.search_domains), None, True, False]) d4.append(['> ', 'sendline()', None, False, False]) d4.process(self.spawn_id, timeout=900) logger.info('fully installed.')
def configuration_wizard(self, ipv4_mode, ipv6_mode, ipv4, ipv4_netmask, ipv4_gateway, ipv6, ipv6_prefix, ipv6_gateway, dns_servers, search_domains, ntp_servers): """ Handle FMC configuration wizard :param ipv4_mode: IPv4 configuration mode - 'static' ('manual') or 'dhcp' :param ipv4: IPv4 address of the management interface :param ipv4_netmask: IPv4 netmask of the management interface :param ipv4_gateway: IPv4 gateway of the management interface :param ipv6: IPv6 address of the management interface :param ipv6_prefix: IPv6 prefix of the management interface :param ipv6_gateway: IPv6 gateway of the management interface :param ipv6_mode: IPv6 configuration mode - 'dhcp', 'router' or 'manual' :param dns_servers: a comma-separated string of DNS servers :param search_domains: a comma-separated string of search domains :param ntp_servers: a comma-separated string of NTP servers :return: True if network configuration was done, False otherwise """ if ipv4_mode in ["static", "manual"]: ipv4_mode_new = "manual" ipv4_mode_old = "static" else: ipv4_mode_old = "dhcp" ipv4_mode_new = "dhcp" config_dialog = Dialog([ [self.sm.patterns.prompt.fireos_prompt, 'sendline()', None, False, False], [self.sm.patterns.prompt.admin_prompt, 'sendline()', None, False, False], [self.sm.patterns.prompt.sudo_prompt, 'sendline()', None, False, False], ['Enter a hostname or fully qualified domain name for this system ', 'sendline({})'.format(self.sm.patterns.fqdn), None, True, False], ['Enter a fully qualified hostname for this system ', 'sendline({})'.format(self.sm.patterns.fqdn), None, True, False], ['Configure IPv4 via DHCP or manually', 'sendline({})'.format(ipv4_mode_new), None, True, False], ['Configure IPv4 via DHCP or static configuration', 'sendline({})'.format(ipv4_mode_old), None, True, False], ]) if ipv4_mode is 'static': config_dialog.append(['Enter an IPv4 address for the management interface', 'sendline({})'.format(ipv4), None, True, False]) config_dialog.append(['Enter an IPv4 netmask for the management interface', 'sendline({})'.format(ipv4_netmask), None, True, False]) config_dialog.append(['Enter the IPv4 default gateway for the management interface', 'sendline({})'.format(ipv4_gateway), None, True, False]) if ipv6_mode: config_dialog.append(['Do you want to configure IPv6', 'sendline(y)', None, True, True]) config_dialog.append(['Configure IPv6 via DHCP, router, or manually', 'sendline({})'.format(ipv6_mode), None, True, True]) else: config_dialog.append(['Do you want to configure IPv6', 'sendline(n)', None, True, True]) if ipv6_mode is 'manual': config_dialog.append(['Enter the IPv6 address for the management interface', 'sendline({})'.format(ipv6), None, True, False]) config_dialog.append(['Enter the IPv6 address prefix for the management interface', 'sendline({})'.format(ipv6_prefix), None, True, False]) config_dialog.append(['Enter the IPv6 gateway for the management interface', 'sendline({})'.format(ipv6_gateway), None, True, False]) config_dialog.append(['Enter a comma-separated list of DNS servers', 'sendline({})'.format(dns_servers), None, True, False]) config_dialog.append(['Enter a comma-separated list of search domains', 'sendline({})'.format(search_domains), None, True, False]) config_dialog.append(['Enter a comma-separated list of NTP servers', 'sendline({})'.format(ntp_servers), None, True, False]) config_dialog.append(['Are these settings correct', 'sendline(y)', None, True, False]) config_dialog.append(['Updated network configuration', None, None, True, False]) response = config_dialog.process(self.spawn_id, timeout=900) self.spawn_id.sendline() self.go_to('any') if 'Updated network configuration' in response.match_output: logger.info("Network configuration completed") return True return False