def call_service(self, command='redundancy switchover', dialog=Dialog([]), timeout=None, sync_standby=True, error_pattern=None, *args, **kwargs): # create an alias for connection. con = self.connection if error_pattern is None: self.error_pattern = con.settings.ERROR_PATTERN else: self.error_pattern = error_pattern start_time = datetime.now() timeout = timeout or self.timeout con.log.debug("+++ Issuing switchover on %s with " "switchover_command %s and timeout is %s +++" % (con.hostname, command, timeout)) dialog += self.dialog # Issue switchover command con.active.spawn.sendline(command) try: self.result = dialog.process(con.active.spawn, timeout=self.timeout, prompt_recovery=self.prompt_recovery, context=con.context) except SubCommandFailure as err: raise SubCommandFailure("Switchover Failed %s" % str(err)) output = "" if self.result: self.result = self.get_service_result() output += self.result.match_output con.log.info('Switchover done, switching sessions') con.active.spawn.sendline() con.standby.spawn.sendline() con.connection_provider.prompt_recovery = True con.connection_provider.connect() con.connection_provider.prompt_recovery = False if sync_standby: con.log.info('Waiting for standby state') delta_time = timedelta(seconds=timeout) current_time = datetime.now() while (current_time - start_time) < delta_time: show_redundancy = con.execute('show redundancy', prompt_recovery=True) standby_state = re.findall(con.settings.STANDBY_STATE_REGEX, show_redundancy) standby_state = [s.strip() for s in standby_state] con.log.info('Standy state: %s' % standby_state) if standby_state == con.settings.STANDBY_EXPECTED_STATE: break wait_time = con.settings.STANDBY_STATE_INTERVAL con.log.info('Waiting %s seconds' % wait_time) sleep(wait_time) current_time = datetime.now() if current_time - start_time > delta_time: raise SubCommandFailure('Switchover timed out, standby state: %s' % standby_state) # TODO: return all/most console output, not only from the switchover # This requires work on the bases.router.connection_provider BaseDualRpConnectionProvider implementation self.result = output
class WebserverDialog: ssh_connect_dialog = Dialog([ ['continue connecting (yes/no)?', 'sendline(yes)', None, True, False], ['Password:'******'sendline_ctx(password)', None, True, False], ['Last login:', None, None, True, False], ])
def configure_crypto_pki_server( device, domain_name, database_level, issuer_name, hash, modulus_size, password, server_name, ): """Configures crypto pki server on device Args: device (`obj`): Device object domain_name ('str'): Name of the domain to be configured database_level ('str'): Database level to be configured issuer_name ('str'): Issuer name to be configured hash ('str'): Hash to be configured modulus_size ('str'): Modulus size to be configured Password ('str'): Password to be configured server_name ('str'): Name of the server to be configured Returns: None Raise: SubCommandFailure: Failed to configure crypto pki server on device """ def send_password(spawn, password): spawn.sendline(password) dialog_1 = Dialog([ Statement( r"^.*Destination filename \[nvram\.pub\]\?.*$", action="sendline(\r)", loop_continue=True, ), Statement( r"^.*Do you really want to overwrite it\? \[yes/no\]:.*$", action="sendline(yes)", loop_continue=True, ), Statement( r"^.*Destination filename \[nvram\.prv\]\?.*$", action="sendline(\r)", loop_continue=True, ), Statement( r"^.*Do you really want to overwrite it\? \[yes/no\]:.*$", action="sendline(yes)", loop_continue=True, ), ]) try: device.configure([ f"ip domain-name {domain_name}", f"crypto pki server {server_name}", f"database level {database_level}", f"issuer-name {issuer_name}", f"hash {hash}", "shut", "exit", ]) time.sleep(10) device.configure([ f"crypto key generate rsa modulus {modulus_size} label cisco exportable", f"crypto key export rsa cisco pem url nvram 3des {password}", ], timeout=5, reply=dialog_1) time.sleep(20) dialog_2 = Dialog([ Statement( r"Password:\s?$", action=send_password, args={"password": password}, loop_continue=True, ), Statement( r"Re-enter password:\s?$", action=send_password, args={"password": password}, loop_continue=True, ), ]) device.configure([ f"crypto pki server {server_name}", "no shut", ], timeout=120, reply=dialog_2) time.sleep(120) except SubCommandFailure: raise SubCommandFailure( "Could not configure crypto pki server on device")
def call_service(self, to_state, timeout=None, *args, **kwargs): if not self.connection.connected: return con = self.connection sm = self.get_sm() dialog = Dialog([fxos_statements.command_not_completed_stmt]) timeout = timeout if timeout is not None else self.timeout if isinstance(to_state, str): to_state_list = [to_state] elif isinstance(to_state, list): to_state_list = to_state else: raise Exception('Invalid switchto to_state type: %s' % repr(to_state)) for to_state in to_state_list: m1 = re.match(r'module(\s+(\d+))?(\s+(console|telnet))?', to_state) m2 = re.match(r'cimc(\s+(\S+))?', to_state) m3 = re.match(r'fxos[ _]scope ?(.*)', to_state) m4 = re.match(r'adapter(\s+(\S+))?', to_state) if m1: mod = m1.group(2) or 1 con_type = m1.group(4) or 'console' self.context._module = mod self.context._mod_con_type = con_type to_state = 'module' elif m2: mod = m2.group(2) or '1/1' self.context._cimc_module = mod to_state = 'cimc' con.state_machine.go_to('fxos', con.spawn, context=self.context, hop_wise=True, timeout=timeout) elif m3: scope = m3.group(1) if not scope: con.log.warning('No scope specified, ignoring switchto') continue else: self.context._scope = scope to_state = 'fxos_scope' con.state_machine.go_to('fxos', con.spawn, context=self.context, hop_wise=True, timeout=timeout) elif m4: mod = m4.group(2) or '1/1' self.context._adapter_module = mod to_state = 'adapter' else: to_state = to_state.replace(' ', '_') valid_states = [x.name for x in sm.states] if to_state not in valid_states: con.log.warning( '%s is not a valid state, ignoring switchto' % to_state) continue con.state_machine.go_to(to_state, con.spawn, context=self.context, hop_wise=True, timeout=timeout, dialog=dialog) self.end_state = sm.current_state
def call_service(self, reload_command='system reboot', dialog=Dialog([]), timeout=None, *args, **kwargs): con = self.connection timeout = timeout or self.timeout fmt_msg = "+++ reloading %s " \ " with reload_command '%s' " \ "and timeout %s +++" con.log.info(fmt_msg % (self.connection.hostname, reload_command, timeout)) if not isinstance(dialog, Dialog): raise SubCommandFailure( "dialog passed must be an instance of Dialog") if self.context.get('console'): dialog = self.service_dialog(service_dialog=dialog) dialog += Dialog(authentication_statement_list) dialog += Dialog(reload_continue_statement_list) con.spawn.sendline(reload_command) try: self.result = dialog.process( con.spawn, timeout=timeout, prompt_recovery=self.prompt_recovery, context=self.context) except Exception as err: raise SubCommandFailure("Reload failed %s" % err) if self.result: self.result = utils.remove_ansi_escape_codes( self.result.match_output) else: con.log.warning( 'Did not detect a console session, will try to reconnect...') dialog = Dialog(reload_statement_list) con.spawn.sendline(reload_command) dialog.process(con.spawn, timeout=timeout, prompt_recovery=self.prompt_recovery, context=self.context) con.expect('.+') con.log.warning('Disconnecting...') con.disconnect() for x in range(3): con.log.warning('Waiting for {} seconds'.format( con.settings.RELOAD_WAIT)) sleep(con.settings.RELOAD_WAIT) con.log.warning('Trying to connect... attempt #{}'.format(x + 1)) try: output = con.connect() self.result = output except: con.log.warning('Connection failed') if con.connected: break if not con.connected: raise SubCommandFailure('Reload failed - could not reconnect')
def call_service(self, reply=Dialog([]), vrf=None, *args, **kwargs): if vrf is not None: kwargs['extra_options'] = kwargs.setdefault('extra_options', '') \ + ' vrf {}'.format(vrf) super().call_service(reply=reply, *args, **kwargs)
def get_connection_dialog(self): dialog = super().get_connection_dialog() dialog += Dialog(additional_connection_dialog) return dialog
def call_service(self, reload_command=None, reply=Dialog([]), timeout=None, image_to_boot=None, return_output=False, *args, **kwargs): self.result = False reload_cmd = reload_command or self.reload_command timeout = timeout or self.timeout conn = self.connection.active # update all subconnection context with image_to_boot if image_to_boot: for subconn in self.connection: subconn.context.image_to_boot = image_to_boot reload_dialog = self.dialog if reply: reload_dialog = reply + reload_dialog custom_auth_stmt = custom_auth_statements( conn.settings.LOGIN_PROMPT, conn.settings.PASSWORD_PROMPT) if custom_auth_stmt: reload_dialog += Dialog(custom_auth_stmt) reload_dialog += Dialog([switch_prompt]) conn.log.info('Processing on active rp %s-%s' % (conn.hostname, conn.alias)) conn.sendline(reload_cmd) try: reload_cmd_output = reload_dialog.process( conn.spawn, timeout=timeout, prompt_recovery=self.prompt_recovery, context=conn.context) except Exception as e: raise SubCommandFailure('Error during reload', e) from e if 'state' in conn.context and conn.context.state == 'rommon': # If manual boot enabled wait for all peers to come to boot state. sleep(self.connection.settings.STACK_ROMMON_SLEEP) conn.context.pop('state') try: # send boot command for each subconnection for subconn in self.connection.subconnections: utils.send_boot_cmd(subconn, timeout, self.prompt_recovery, reply) # process boot up for each subconnection for subconn in self.connection.subconnections: self.connection.log.info('Processing on rp ' '%s-%s' % (conn.hostname, subconn.alias)) utils.boot_process(subconn, timeout, self.prompt_recovery, reload_dialog) except Exception as e: self.connection.log.error(e) raise SubCommandFailure('Reload failed.', e) from e else: try: # bring device to enable mode conn.state_machine.go_to('any', conn.spawn, timeout=timeout, prompt_recovery=self.prompt_recovery, context=conn.context) conn.state_machine.go_to('enable', conn.spawn, timeout=timeout, prompt_recovery=self.prompt_recovery, context=conn.context) except Exception as e: raise SubCommandFailure( 'Failed to bring device to disable mode.', e) from e # check active and standby rp is ready self.connection.log.info('Wait for Standby RP to be ready.') interval = self.connection.settings.RELOAD_POSTCHECK_INTERVAL if utils.is_active_standby_ready(conn, timeout=timeout, interval=interval): self.connection.log.info('Active and Standby RPs are ready.') else: self.connection.log.info( 'Timeout in %s secs. ' 'Standby RP is not in Ready state. Reload failed' % timeout) self.result = False return self.connection.log.info('Sleeping for %s secs.' % \ self.connection.settings.STACK_POST_RELOAD_SLEEP) sleep(self.connection.settings.STACK_POST_RELOAD_SLEEP) self.connection.log.info('Disconnecting and reconnecting') self.connection.disconnect() self.connection.connect() self.connection.log.info("+++ Reload Completed Successfully +++") self.result = True if return_output: Result = namedtuple('Result', ['result', 'output']) self.result = Result( self.result, reload_cmd_output.match_output.replace(reload_cmd, '', 1))
def call_service(self, command=None, reply=Dialog([]), timeout=None, *args, **kwargs): switchover_cmd = command or self.command timeout = timeout or self.timeout conn = self.connection.active expected_active_sw = self.connection.standby.member_id dialog = self.dialog if reply: dialog = reply + self.dialog # added connection dialog in case switchover ask for username/password connect_dialog = self.connection.connection_provider.get_connection_dialog( ) dialog += connect_dialog conn.log.info('Processing on active rp %s-%s' % (conn.hostname, conn.alias)) conn.sendline(switchover_cmd) try: match_object = dialog.process(conn.spawn, timeout=timeout, prompt_recovery=self.prompt_recovery, context=conn.context) except Exception as e: raise SubCommandFailure('Error during switchover ', e) from e # try boot up original active rp with current active system # image, if it moved to rommon state. if 'state' in conn.context and conn.context.state == 'rommon': try: conn.state_machine.detect_state(conn.spawn, context=conn.context) conn.state_machine.go_to('enable', conn.spawn, timeout=timeout, prompt_recovery=self.prompt_recovery, context=conn.context, dialog=Dialog([switch_prompt])) except Exception as e: self.connection.log.warning( 'Fail to bring up original active rp from rommon state.', e) finally: conn.context.pop('state') # To ensure the stack is ready to accept the login self.connection.log.info('Sleeping for %s secs.' % \ self.connection.settings.POST_SWITCHOVER_SLEEP) sleep(self.connection.settings.POST_SWITCHOVER_SLEEP) # check all members are ready conn.state_machine.detect_state(conn.spawn, context=conn.context) interval = self.connection.settings.SWITCHOVER_POSTCHECK_INTERVAL if utils.is_all_member_ready(conn, timeout=timeout, interval=interval): self.connection.log.info('All members are ready.') else: self.connection.log.info('Timeout in %s secs. ' 'Not all members are in Ready state.' % timeout) self.result = False return self.connection.log.info('Disconnecting and reconnecting') self.connection.disconnect() self.connection.connect() self.connection.log.info('Verifying active and standby switch State.') if self.connection.active.member_id == expected_active_sw: self.connection.log.info('Switchover successful') self.result = True else: self.connection.log.info('Switchover failed') self.result = False
def __init__(self, connection, context, **kwargs): super().__init__(connection, context, **kwargs) self.start_state = 'enable' self.end_state = 'enable' self.dialog += Dialog([slxos_statements.save_confirm])
def install_image_and_packages(section, steps, device, image, packages, install_timeout=300, reload_timeout=900): """ This stage installs the provided image and optional packages onto your device using the install CLI. The stage will also handle the automatic reload. Stage Schema ------------ install_image_and_packages: image: - <image to install> (Mandatory) packages: - <package to install> (Optional) - <package to install> (Optional) install_timeout: <timeout used for install operations, 'int', Default 300> (Optional) reload_timeout: <timeout used for device reloads, 'int', Default 900> (Optional) Example ------- install_image_and_packages: image: - flash:image.iso packages: - flash:package.rpm """ # Commonly used patterns error_patterns = [ r".*Could not start this install operation.*", r".*Install operation \d+ aborted.*"] successful_operation_string = \ r".*Install operation (?P<id>\d+) finished successfully.*" if ':' not in image[0]: section.failed("The image provided is not in the format '<dir>:<image>'.") with steps.start("Running install commit to clear any in progress " "installs") as step: try: device.execute("install commit") device.expect( [successful_operation_string], timeout=install_timeout) except Exception as e: step.failed("The command 'install commit' failed. Reason: " "{}".format(str(e))) with steps.start("Adding image and any provided packages to the " "install repository") as step: # Separate directory and image directory, image = image[0].replace('/', '').split(':') # Get packages and remove directories # pkgs = ' pkg1 pkg2 pkg3 ...' pkgs = '' for pkg in packages: pkg = pkg.replace('/', '').split(':') if len(pkg) == 1: pkgs += ' '+pkg[0] else: pkgs += ' '+pkg[1] # install add source flash: <image> <pkg1> <pkg2> cmd = 'install add source {dir}: {image}{packages}'.format( dir=directory, image=image, packages=pkgs) try: device.execute( cmd, timeout=install_timeout, error_pattern=error_patterns) out = device.expect( [successful_operation_string], trim_buffer=False, timeout=install_timeout) except Exception as e: step.failed("The command '{cmd}' failed. Error: {e}" .format(cmd=cmd, e=str(e))) out = out.match_output # If code execution reaches here the regex has already been matched # via the expect. So we know it will match again here. We just need # to retrieve the operation id for the next steps. p1 = re.compile(successful_operation_string) for line in out.splitlines(): m = p1.match(line) if m: operation_id = m.groupdict()['id'] break step.passed("The command '{cmd}' succeeded. The " "operation ID is '{operation_id}'" .format(cmd=cmd, operation_id=operation_id)) with steps.start("Activating operation ID {}".format(operation_id)) as step: cmd = 'install activate id {id}'.format(id=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( [successful_operation_string], timeout=install_timeout) except Exception as e: step.failed("Attempting to activate install id '{id}' " "failed. Error: {e}" .format(id=operation_id, e=str(e))) with steps.start("Reconnecting to '{dev}'".format( dev=device.name)) as step: timeout = Timeout(reload_timeout, 60) while timeout.iterate(): timeout.sleep() device.destroy() try: device.connect(learn_hostname=True) except Exception as e: connection_error = e log.info("Could not connect to {dev}" .format(dev=device.hostname)) else: step.passed("Connected to {dev}" .format(dev=device.hostname)) step.failed("Could not connect to {dev}. Error: {e}" .format(dev=device.hostname, e=str(connection_error))) with steps.start("Completing install") as step: try: device.execute("install commit") device.expect( [successful_operation_string], trim_buffer=False, timeout=install_timeout) except Exception as e: step.failed("The command 'install commit' failed. Reason: {}".format(str(e)))
def __init__(self, connection, context, **kwargs): super().__init__(connection, context, **kwargs) self.dialog += Dialog(execution_statement_list)
def call_service(self, command=[], reply=Dialog([]), target='active', timeout=None, *args, **kwargs): self.commit_cmd = get_commit_cmd(**kwargs) super().call_service(command, reply=reply + Dialog(config_commit_stmt_list), target=target, timeout=timeout, *args, **kwargs)
def __init__(self, connection, context, **kwargs): # Connection object will have all the received details super().__init__(connection, context, **kwargs) self.dialog += Dialog(execution_statement_list)
else: platform = None try: c = Connection(hostname='Router', start=['bash'], os=_os, platform=platform, log_stdout=False) # c = Connection(hostname='Router', start=['bash'], os=_os, platform=platform) c.init_service() c.connection_provider = c.connection_provider_class(c) except Exception: print('---------------- ERROR ---------------', file=sys.stderr) traceback.print_exc() print('--------------------------------------', file=sys.stderr) else: print('\n\n') print(plugin_name) print('-' * len(plugin_name) + '\n') print_dialogs('default', c.state_machine.default_dialog) print_dialogs('connect', c.connection_provider.get_connection_dialog()) try: print_dialogs('execute', c.execute.dialog if c.execute.dialog else Dialog([])) print_dialogs('configure', c.configure.dialog if c.configure.dialog else Dialog([])) except Exception: print('---------------- ERROR ---------------', file=sys.stderr) traceback.print_exc() print('--------------------------------------', file=sys.stderr)
def call_service(self, reload_command='reload', dialog=Dialog([]), timeout=None, reload_creds=None, *args, **kwargs): con = self.connection timeout = timeout or self.timeout fmt_msg = "+++ reloading %s " \ " with reload_command %s " \ "and timeout is %s +++" con.log.debug(fmt_msg % (self.connection.hostname, reload_command, timeout)) con.state_machine.go_to(self.start_state, con.spawn, prompt_recovery=self.prompt_recovery, context=self.context) if not isinstance(dialog, Dialog): raise SubCommandFailure( "dialog passed must be an instance of Dialog") show_terminal = con.execute('show terminal') line_type = re.search(r"Line .*, Type \"(\w+)\"", show_terminal) if line_type and line_type.groups(): line_type = line_type.group(1) if reload_creds: context = self.context.copy() context.update(cred_list=reload_creds) else: context = self.context if line_type == 'Console': dialog += self.dialog con.spawn.sendline(reload_command) try: self.result = dialog.process( con.spawn, timeout=timeout, prompt_recovery=self.prompt_recovery, context=context) if self.result: self.result = self.result.match_output con.state_machine.go_to('any', con.spawn, prompt_recovery=self.prompt_recovery, context=self.context) except Exception as err: raise SubCommandFailure("Reload failed %s" % err) output = self.result output = output.replace(reload_command, "", 1) # only strip first newline and leave formatting intact output = re.sub(r"^\r?\r\n", "", output, 1) output = output.rstrip() else: con.log.warning( 'Did not detect a console session, will try to reconnect...') dialog = Dialog(reload_statement_list_vty) con.spawn.sendline(reload_command) output = "" self.result = dialog.process(con.spawn, timeout=timeout, prompt_recovery=self.prompt_recovery, context=self.context) if self.result: output += self.result.match_output try: m = con.spawn.expect('.+', timeout=10) if m: output += m.match_output except TimeoutError: pass con.log.warning('Disconnecting...') con.disconnect() for x in range(3): con.log.warning('Waiting for {} seconds'.format( con.settings.RELOAD_WAIT)) sleep(con.settings.RELOAD_WAIT) con.log.warning('Trying to connect... attempt #{}'.format(x + 1)) try: output += con.connect() except: con.log.warning('Connection failed') if con.is_connected: break if not con.is_connected: raise SubCommandFailure('Reload failed - could not reconnect') self.result = output
def __init__(self, connection, context, **kwargs): super().__init__(connection, context, **kwargs) self.dialog += Dialog( [overwrite_previous, delete_filename, confirm, want_continue])
def cb5(spawn, context, session, name, city='bangalore', country='america'): print('spawn=%s; context=%s, name=%s; city=%s; contry=%s;' % (spawn, context, name, city, country)) print(session.check) session.num *= session.num print('number is %s' % session.num) s_list = [ Statement(pattern=pattern, action=cb1), Statement(pattern=pattern, action=cb2), Statement(pattern=pattern, action=cb3, args={'name': 'person1'}), Statement(pattern=pattern, action=cb4), Statement(pattern=pattern, action=cb5, args={'name': 'person1', 'country': 'country1'}), Statement(pattern=pattern, action=None) ] d = Dialog(s_list) context = AttributeDict(dict(username='******', password='******')) dp1 = DialogProcessor(d, s1, context) dp1.process(context) print('-- After dp1') for st in d.statements: if st._action is not None: st._action() for st in d.statements: if st._action is not None:
def execute_install_package(device, image_dir, image, save_system_config=True, timeout=660, _install=True): """ Installs package Args: device ("obj"): Device object image_dir ("str"): Directory image is located in image ("str"): Image name save_system_config ("bool"): If config changed do we save it? timeout ("int"): maximum time for install _install ("bool"): True to install, False to uninstall. Not meant to be changed manually. Raises: Exception Returns: True if install succeeded else False """ dialog = Dialog([ Statement(pattern=r".*Press Quit\(q\) to exit, you may save " r"configuration and re-enter the command\. " r"\[y\/n\/q\]", action='sendline(y)' if save_system_config else 'sendline(n)', loop_continue=True, continue_timer=False), Statement(pattern=r".*This operation may require a reload of the " r"system\. Do you want to proceed\? \[y\/n\]", action='sendline(y)', loop_continue=True, continue_timer=False), Statement(pattern=r"^.*RETURN to get started", action='sendline()', loop_continue=False, continue_timer=False) ]) if _install: cmd = """install add file {dir}{image} install activate file {dir}{image}""".format( dir=image_dir, image=image ) else: cmd = "install deactivate file {dir}{image}".format( dir=image_dir, image=image ) try: device.execute(cmd, reply=dialog, timeout=timeout) except StateMachineError: # this will be raised after 'Return to get started' is seen device.destroy() timeout = Timeout(90, 30) while timeout.iterate(): try: connect_device(device) except Exception: timeout.sleep() continue break else: raise Exception("Couldnt reconnect to the device") if _install: cmd = "install commit" else: cmd = """install commit install remove file {dir}{image}""".format( dir=image_dir, image=image ) device.execute(cmd) try: out = device.parse("show install summary") except SchemaEmptyParserError: out = {} for location in out.get("location"): for pkg in out['location'][location]['pkg_state']: pkg = out['location'][location]['pkg_state'][pkg] if (_install and image in pkg['filename_version'] and 'C' == pkg['state']): # the image should exist; it was just installed return True elif (not _install and image in pkg['filename_version']): # the image should not exist; it was just uninstalled. return False return False if _install else True
def restore_configuration(self, device, method, abstract, iteration=10, interval=60, compare=False, compare_exclude=[], reload_timeout=None, delete_after_restore=True): if method == 'checkpoint': # Enable the feature for i in range(1, iteration): try: self.rollback_checkpoint(device=device, name=self.ckname) break except Exception as e: if i == iteration - 1: raise Exception('Unable to rollback config') else: log.info('Rollback configuration failed: sleeping {} ' 'seconds and retrying...'.format(interval)) time.sleep(interval) if delete_after_restore: # Delete the checkpoint self.create_delete_checkpoint(device=device, name=self.ckname, abstract=abstract, action='delete') # Check if checkpoint is successfully deleted self.check_checkpoint_status(device=device, name=self.ckname, expect='delete', abstract=abstract) elif method == 'local': # reover the deivce with whole running-config device.configure(self.run_config) elif method == 'config_replace': # delete the archive file dialog = Dialog([ Statement(pattern=r'This will apply all necessary.*', action='sendline(Y)', loop_continue=True, continue_timer=False), Statement(pattern=r'less than running config.*', action='sendline(Y)', loop_continue=True, continue_timer=False), ]) for i in range(1, iteration): # configure replace location:<filename> output = device.execute('configure replace {}'.format( self.to_url), reply=dialog) if 'Rollback Done' in output: break elif i == iteration - 1: raise Exception('Unable to execute config replace') else: log.info( 'Config replace failed: sleeping {} seconds before' ' retrying.'.format(interval)) time.sleep(interval) # Compare restored configuration to details in file if compare: log.info( "Comparing current running-config with config-replace file" ) # Default exclude = [ 'device', 'maker', 'diff_ignore', 'callables', '(Current configuration.*)', '(.*Building configuration.*)', '(.*Load for.*)', '(.*Time source.*)' ] if compare_exclude: if isinstance(compare_exclude, str): exclude.extend([compare_exclude]) else: exclude.extend(compare_exclude) # show run show_run_output = device.execute('show running-config') show_run_config = Config(show_run_output) show_run_config.tree() # location:<filename> contents more_file = device.execute('more {}'.format(self.to_url)) more_file_config = Config(more_file) more_file_config.tree() # Diff 'show run' and config replace file contents diff = Diff(show_run_config.config, more_file_config.config, exclude=exclude) diff.findDiff() # Check for differences if len(diff.diffs): log.error( "Differences observed betweenrunning-config and " "config-replce file:'{f}' for device {d}:".format( f=self.to_url, d=device.name)) log.error(str(diff.diffs)) raise Exception( "Comparison between running-config and " "config-replace file '{f}' failed for device" " {d}".format(f=self.to_url, d=device.name)) else: log.info( "Comparison between running-config and config-replace" "file '{f}' passed for device {d}".format( f=self.to_url, d=device.name)) if delete_after_restore: # Delete location:<filename> self.filetransfer = FileUtils.from_device(device) self.filename = self.to_url self.filetransfer.deletefile(target=self.to_url, device=device) # Verify location:<filename> deleted dir_output = self.filetransfer.dir(target=self.to_url, device=device) for file in dir_output: if self.filename in file: break else: log.info("Successfully deleted '{}'".format(self.to_url)) return raise Exception("Unable to delete '{}'".format(self.to_url)) else: # modify the device via callable function # using Conf object self.modify_func(device=device, conf=self.conf, values_dict=self.conf_argument, recover=True, **self.specific_args)
def call_service(self, reload_command='reboot', reply=Dialog([]), timeout=None, *args, **kwargs): # noqa C901 # Clear log buffer self.log_buffer.seek(0) self.log_buffer.truncate() con = self.connection timeout = timeout or self.timeout con.log.debug("+++ reloading %s with reload_command %s " "and timeout is %s +++" % (self.connection.hostname, reload_command, timeout)) console = con.context.get('console', False) if console: dialog = reply + self.dialog con.spawn.sendline(reload_command) try: con.log.info('Rebooting system..') # reload and wait until 'Restarting system' is seen self.result = dialog.process(con.spawn, timeout=timeout, prompt_recovery=self.prompt_recovery, context=self.context) con.log.info('Waiting for boot to finish..') # Wait until boot is done boot_wait(con.spawn, timeout=timeout or self.timeout) con.log.info('Reload done, waiting %s seconds' % con.settings.POST_RELOAD_WAIT) time.sleep(con.settings.POST_RELOAD_WAIT) dialog = Dialog(login_statements + [Statement(fxos_patterns.fxos_prompt)]) con.log.info('Trying to login..') # try to login con.spawn.sendline() self.result = dialog.process(con.spawn, timeout=timeout or self.timeout, prompt_recovery=self.prompt_recovery, context=self.context) con.state_machine.detect_state(con.spawn) except Exception as err: raise SubCommandFailure("Reload failed %s" % err) else: con.log.debug('Did not detect a console session, will try to reconnect...') dialog = reply + self.dialog con.spawn.sendline(reload_command) self.result = dialog.process(con.spawn, timeout=timeout or self.timeout, prompt_recovery=self.prompt_recovery, context=self.context) try: con.spawn.expect('.+', timeout=10, log_timeout=False) except TimeoutError: pass con.log.info('Disconnecting...') con.disconnect() for x in range(con.settings.RELOAD_RECONNECT_ATTEMPTS): con.log.info('Waiting for {} seconds'.format(con.settings.RELOAD_WAIT)) time.sleep(con.settings.RELOAD_WAIT) con.log.info('Trying to connect... attempt #{}'.format(x + 1)) try: con.connect() except Exception: con.log.warning('Connection failed') if con.is_connected: break if not con.is_connected: raise SubCommandFailure('Reload failed - could not reconnect') self.log_buffer.seek(0) self.result = self.log_buffer.read()
def create_delete_checkpoint(self, device, name, abstract, action): ''' Create or Delete checkpoint Args: device (`obj`): Device Object. name (`str`): Checkpoint name. action (`str`): Create or Delete the checkpoint Only accept 'create' and 'delete' Returns: None Raises: SyntaxError, AssertionError example: >>> create_delete_checkpoint(device=device, name='bgp-001', action='create') ''' assert action in ['create', 'delete'] log.info('{a} checkpoint {n}'.format(a=action, n=name)) if action == 'create': # create checkpoint try: # get dir location dir_loc = abstract.parser.show_platform.Dir( device=device).parse() dir_loc = dir_loc['dir']['dir'].replace(':/', '') # activate archive mode cfg_strs = [ "archive", "path {dir}:{name}".format(dir=dir_loc, name=name), "do-exec archive config" ] ret = device.configure(cfg_strs) except Exception as e: raise SyntaxError( "Issue sending {c}".format(c=cfg_strs)) from e else: if 'ERROR' in ret: raise SyntaxError("Issue sending {c}".format(c=cfg_strs)) else: try: # get location location = re.search(r'(([\w\-]+)\:+).*', self.ckname).groups()[0] # delete the archive file dialog = Dialog([ Statement(pattern=r'Delete filename.*', action='sendline()', loop_continue=True, continue_timer=False), Statement(pattern=r'Do you want to delete.*', action='sendline(y)', loop_continue=True, continue_timer=False), Statement(pattern=r'Delete {}.*'.format(location), action='sendline()', loop_continue=True, continue_timer=False), Statement(pattern=r'\[confirm\]', action='sendline()', loop_continue=True, continue_timer=False), ]) device.execute('delete {}'.format(self.ckname), reply=dialog) # deactivate archive mode cfg_strs = ['archive', 'no path', 'exit'] ret = device.configure(cfg_strs) except Exception as e: raise SyntaxError( "Issue sending {c}".format(c=cfg_strs)) from e else: if 'ERROR' in ret: raise SyntaxError("Issue sending {c}".format(c=cfg_strs))
rtr_list = [] while True: hostname = input() if hostname: rtr_list.append(hostname) else: break for rtr in rtr_list: nodes = rtr tb = load('Operation_List_Master.yaml') dev = tb.devices[nodes] d = Dialog([ Statement(pattern=r'Permission denied', action=None, args=None, loop_continue=True, continue_timer=False) ]) dev.connect(connect_reply=d) p0 = dev.admin_execute('show inventory') P0 = re.split('\r\n|NAME:|, DESCR:|PID:|, VID:|, SN:', p0) del P0[0] P1 = (list(filter(None, P0))) NAME = [] DESCR = [] SN = [] PID = [] VID = []
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] ]) 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, '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], ['Use SPACE to begin boot immediately.', 'send(" ")', None, True, True], ['Use SPACE to launch Cisco FTD immediately.', 'send(" ")', None, True, True], ['firepower login: '******'sendline()', None, False, False], ]) d2.process(self.spawn_id, timeout=3900) # 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 __init__(self, connection, context, **kwargs): super().__init__(connection, context, **kwargs) self.dialog = Dialog(reload_statement_list + [boot_from_rommon_stmt])
def rommon_to_new_image(self, rommon_tftp_server, pkg_image, uut_ip, uut_netmask, uut_gateway, rommon_image, dns_server, hostname='firepower', search_domains='cisco.com', is_device_kenton=True, retry_count=MAX_RETRY_COUNT, power_cycle_flag=False, pdu_ip='', pdu_port='', pdu_user='******', pdu_pwd='admn', ntp_server=None, mode='local', uut_ip6=None, uut_prefix=None, uut_gateway6=None, manager=None, manager_key=None, manager_nat_id=None, firewall_mode='routed', timeout=600, **kwargs): """Install rommon image and FTD pkg image on ASA. :param rommon_tftp_server: TFTP Server IP Address :param pkg_image: FTD image to be transferred via HTTP, e.g. 'http://192.168.0.50/Release/6.0.0-1005/installers/ftd-6.0.0-1005.pkg' :param uut_ip: Device IP Address to access TFTP Server :param uut_netmask: Device Netmask :param uut_gateway: Device Gateway :param rommon_image: boot image under /tftpboot to be transferred via TFTP, e.g. 'asa/Release/6.0.0-1005/installers/ftd-boot-99.1.3.194.lfbff' :param dns_server: DNS server :param hostname: hostname to be set :param search_domains: search domains delimited by comma, defaulted to 'cisco.com' :param is_device_kenton: True if device is Kenton, False if device is Saleen :param retry_count: download retry count, defaulted to MAX_RETRY_COUNT :param power_cycle_flag: True power cylce before baseline, False otherwise :param pdu_ip: PDU IP :param pdu_port: PDU Port :param pdu_user: PDU admn :param pdu_pwd: PDU pwd :param ntp_server: NTP server delimited by comma, defaulted to None, otherwise the value of ntp_server is - e.g. "ntp.esl.cisco.com" :param mode: the manager mode (local, remote) :param uut_ip6: Device IPv6 Address :param uut_prefix: Device IPv6 Prefix :param uut_gateway6: Device IPv6 Gateway :param manager: FMC to be configured for registration :param manager_key: Registration key :param manager_nat_id: Registration NAT Id :param firewall_mode: the firewall mode (routed, transparent, ngips) :param timeout: in seconds; time to wait for fetching the boot image from TFTP server; defaulted to 600s :return: None """ logger.info('Starting baseline') graphite.publish_kick_metric('device.ftd5500x.baseline', 1) self.rommon_tftp_server = rommon_tftp_server self.pkg_image = pkg_image self.uut_ip = uut_ip self.uut_netmask = uut_netmask self.uut_gateway = uut_gateway self.uut_ip6 = uut_ip6 self.uut_prefix = uut_prefix self.uut_gateway6 = uut_gateway6 self.rommon_image = rommon_image self.dns_server = dns_server self.hostname = hostname self.search_domains = search_domains self.retry_count = retry_count self.ntp_server = ntp_server self.mode = mode self.firewall_mode=firewall_mode self.manager = manager self.manager_key = manager_key self.manager_nat_id = manager_nat_id if not (self.sm.current_state in ['rommon_state', 'boot_state']): if not power_cycle_flag: if self.sm.current_state is 'disable_state': logger.info('Device is in disable state. Go to enable and reload ...') self.go_to('enable_state') self.spawn_id.sendline('reload noconfirm') elif self.sm.current_state in ['enable_state', 'config_state']: logger.info('Device is in enable or config state. Reloading ...') self.spawn_id.sendline('reload noconfirm') else: logger.info('Reboot the device ...') self.go_to('sudo_state') self.spawn_id.sendline('reboot') else: logger.info('Power cycle the device ...') self.power_cycle(pdu_ip, pdu_port, wait_until_device_is_on=False, power_bar_user=pdu_user, power_bar_pwd=pdu_pwd) try: self.spawn_id.expect('Use (.*?BREAK.*?|.*?ESC.*?) to interrupt boot', timeout=120) except TimeoutError: RuntimeError(">>>>>> Failed to stop rebooting") logger.info('Drop the device to rommon.') self.rommon_go_to() if self.sm.current_state is 'boot_state': logger.info('Device is in boot_state, drop the device to rommon.') self.spawn_id.sendline('system reload') d1 = Dialog([ ['Are you sure you want to reload the system', 'sendline(y)', None, False, False], ]) d1.process(self.spawn_id, timeout=30) self.rommon_go_to() if is_device_kenton: logger.info('Device is Kenton. Rommon configure.') self.rommon_configure() else: logger.info('Device is Saleen. Rommon configure.') self.rommon_configure_saleen() logger.info('tftpdnld - tftp server: {}, ' 'rommon image: {} ...'.format(rommon_tftp_server, rommon_image)) self.rommon_boot(timeout=timeout) self.go_to('any') logger.info('firepower boot configure ...') self.firepower_boot_configure() logger.info('FTD image install - image: {} ...'.format(pkg_image)) self.firepower_install() self.go_to('any') if self.manager is not None and self.mode != 'local': logger.info('Configure manager') self.configure_manager() logger.info('Validate version installed') self.validate_version() logger.info('Installation completed successfully.')
def load_config_precessor(section, configs, unconfig=False): '''load configuration prepostprocessor Can be controlled via sections parameters which is provided by the triggers/verification datafile Args: Mandatory: section (`obj`): Aetest Subsection object. configs (`dict`) : Contains the configuration file location unconfig (`bool`) : True when apply the unconfigurations Default as False Returns: AETEST results Raises: None ''' log.info( banner('Load {} on devices'.format( 'configurations' if not unconfig else 'unconfigurations'))) if section and getattr(section, 'parameters', {}): testbed = section.parameters.get('testbed', {}) # get uut in case there is need to store hardcode values uut = testbed.devices['uut'] if os.path.isfile(configs): configs = yaml.load(open(configs)) elif isinstance(configs, str): module = Lookup.from_device(uut) path = configs.split('.') for item in path: module = getattr(module, item) configs = module else: section.skipped('The configs type {} is not supported'.format( type(configs))) # copy dictionary without changing original configs # due to reuse it with conf/unconfig tmp_config = copy.deepcopy(configs) # Get hardcode values from uut for key, val in sorted(configs['devices']['uut'].items()): if not key.isdigit(): if hasattr(section, 'mapping'): # check if device if key == 'peer': uut.peer = testbed.devices[val] tmp_config['devices']['uut'].pop(key) continue section.mapping.requirements.setdefault( 'provided_values', {}).setdefault(key, val) tmp_config['devices']['uut'].pop(key) for dev in sorted(configs.get('devices', {})): device = testbed.devices[dev] # Sort the item; it is expected to be # Sort them by the key, which needs to be an inter # 1, 2, 3, and so on for num, conf in sorted(tmp_config['devices'][dev].items()): if unconfig and 'unconfig' in conf: conf['config'] = conf['unconfig'] # replace the format syntax if has any conf['config'] = conf['config'].format( **section.mapping.requirements.get('provided_values', {}) if hasattr(section, 'mapping') else {}) log.info( banner("Applying configuration on '{d}'".format( d=device.name))) if os.path.isfile(conf['config']): if 'invalid' not in conf: # Set default conf['invalid'] = [] try: device.tftp.copy_file_to_device( device=device, filename=conf['config'], location='running-config', vrf='management', invalid=conf['invalid']) except Exception as e: log.error(str(e)) section.failed( "Issue while applying the configuration " "on {d}".format(d=dev)) elif isinstance(conf['config'], str): try: # Do you wish to continue? [yes]: dialog = Dialog([ Statement(pattern=r'\[startup\-config\]\?.*', action='sendline()', loop_continue=True, continue_timer=False), Statement(pattern=r'\[yes]\:.*', action='sendline()', loop_continue=True, continue_timer=False) ]) device.configure(conf['config'], reply=dialog) except Exception as e: log.error(str(e)) section.failed( "Issue while applying the configuration " "on {d}".format(d=dev)) else: section.failed( 'The configs type {} is not supported'.format( type(conf['config']))) # sleep for x amount of time after if 'sleep' in conf and not unconfig: log.info("Sleeping for '{s}' " "seconds for waiting system is stable " "after loading the configuration".format( s=conf['sleep'])) time.sleep(conf['sleep'])
def convert_to_elektra(self, rommon_tftp_server, uut_ip, uut_netmask, uut_gateway, asa_image, dns_server, hostname='firepower', search_domains='cisco.com', is_device_kenton=True, retry_count=MAX_RETRY_COUNT, power_cycle_flag=False, pdu_ip='', pdu_port='', mgmt_port='Management1/1', timeout=600): """Install rommon image and FTD pkg image on ASA. :param rommon_tftp_server: TFTP Server IP Address :param uut_ip: Device IP Address to access TFTP Server :param uut_netmask: Device Netmask :param uut_gateway: Device Gateway :param asa_image: asa boot image to be transferred via TFTP, e.g. 'asa/asa952-2-smp-k8.bin' for saleen or 'asa/asa952-2-lfbff-k8.SPA' for Kenton :param dns_server: DNS server :param hostname: hostname to be set :param search_domains: search domains delimited by comma, defaulted to 'cisco.com' :param is_device_kenton: True if device is Kenton, False if device is Saleen :param retry_count: download retry count, defaulted to MAX_RETRY_COUNT :param power_cycle_flag: True power cylce before baseline, False otherwise :param pdu_ip: PDU IP :param pdu_port: PDU Port :param mgmt_port: name of the management port; if not provided, defaulted to 'Management1/1' :param timeout: in seconds; time to wait for fetching the boot image from TFTP server; defaulted to 600s :return: None """ self.rommon_tftp_server = rommon_tftp_server self.uut_ip = uut_ip self.uut_netmask = uut_netmask self.uut_gateway = uut_gateway self.rommon_image = asa_image self.dns_server = dns_server self.hostname = hostname self.search_domains = search_domains if self.sm.current_state is 'rommon_state': logger.info('Reboot the device ...') self.spawn_id.sendline('reboot') if self.sm.current_state is 'boot_state': logger.info('Device is in boot_state, reload the device') self.spawn_id.sendline('system reload') d1 = Dialog([ ['Are you sure you want to reload the system', 'sendline(y)', None, False, False], ]) d1.process(self.spawn_id, timeout=30) logger.info('=== Enable configure') self.enable_configure() logger.info("=== Configure manamgement interface") self.configure_mgmt_interface(uut_ip, uut_netmask, uut_gateway, rommon_tftp_server, mgmt_port) logger.info("=== Set the new boot image") self.set_boot_image(self.rommon_tftp_server, asa_image) logger.info('=== Reboot the device ...') self.go_to('config_state') self.spawn_id.sendline('reload') d = Dialog([ ['Proceed with reload?', 'sendline()', None, True, False], ['Rebooting', None, None, False, False], ]) d.process(self.spawn_id, timeout=180) logger.info('==== Drop the device to rommon.') self.rommon_go_to() if is_device_kenton: logger.info('Device is Kenton. Rommon configure.') self.rommon_configure() else: logger.info('Device is Saleen. Rommon configure.') self.rommon_configure_saleen() logger.info('tftpdnld - tftp server: {}, ' 'rommon image: {} ...'.format(rommon_tftp_server, asa_image)) self.rommon_boot(timeout=timeout) logger.info("=== Configure management interface") self.go_to('any') self.configure_mgmt_interface(uut_ip, uut_netmask, uut_gateway, rommon_tftp_server, mgmt_port) logger.info("=== You have converted successfully the device to Elektra")
def call_service(self, reload_command='reload', dialog=Dialog([]), target='active', timeout=None, reload_creds=None, *args, **kwargs): con = self.connection self.context = con.active.context timeout = timeout or self.timeout fmt_msg = "+++ reloading %s " \ " with reload_command %s " \ "and timeout is %s +++" con.log.debug(fmt_msg % (self.connection.hostname, reload_command, timeout)) con.active.state_machine.go_to(self.start_state, con.active.spawn, prompt_recovery=self.prompt_recovery, context=self.context) if not isinstance(dialog, Dialog): raise SubCommandFailure( "dialog passed must be an instance of Dialog") show_terminal = con.execute('show terminal') line_type = re.search(r"Line .*, Type \"(\w+)\"", show_terminal) if line_type and line_type.groups(): line_type = line_type.group(1) if reload_creds: context = self.context.copy() context.update(cred_list=reload_creds) else: context = self.context if line_type == 'Console': dialog += self.dialog con.active.spawn.sendline(reload_command) try: try: self.result = dialog.process( con.active.spawn, timeout=timeout, prompt_recovery=self.prompt_recovery, context=context) if self.result: self.result = self.result.match_output except Exception: self.result = con.active.spawn.buffer if 'is in standby' in self.result: con.log.info( 'Timed out due to active/standby interchanged. Reconnecting...' ) else: con.log.info( 'Timed out. timeout might need to be increased. Reconnecting...' ) con.disconnect() original_connection_timeout = con.settings.CONNECTION_TIMEOUT con.settings.CONNECTION_TIMEOUT = timeout con.connect() con.settings.CONNECTION_TIMEOUT = original_connection_timeout con.active.state_machine.go_to( 'any', con.active.spawn, prompt_recovery=self.prompt_recovery, context=self.context) # Bring standby to good state. con.log.info('Waiting for config sync to finish') standby_wait_time = con.settings.POST_HA_RELOAD_CONFIG_SYNC_WAIT standby_wait_interval = 50 standby_sync_try = standby_wait_time // standby_wait_interval + 1 for round in range(standby_sync_try): con.standby.spawn.sendline() try: con.standby.state_machine.go_to( 'any', con.standby.spawn, context=context, timeout=standby_wait_interval, prompt_recovery=self.prompt_recovery, dialog=con.connection_provider. get_connection_dialog()) break except Exception as err: if round == standby_sync_try - 1: raise Exception( 'Bringing standby to any state failed within {} sec' .format(standby_wait_time)) from err except Exception as err: raise SubCommandFailure("Reload failed %s" % err) output = self.result output = output.replace(reload_command, "", 1) # only strip first newline and leave formatting intact output = re.sub(r"^\r?\r\n", "", output, 1) output = output.rstrip() else: raise Exception("Console is not used.") self.result = output
def call_service(self, command=[], reply=Dialog([]), timeout=None, error_pattern=None, *args, **kwargs): # Get current state of the state machine and determine end state sm = self.get_sm() con = self.connection con.log.debug('+++ configure state %s +++' % sm.current_state) if sm.current_cli_style == 'cisco': self.start_state = 'cisco_config' self.end_state = 'cisco_exec' PROMPT_PREFIX = None elif sm.current_cli_style == 'juniper': self.start_state = 'juniper_config' self.end_state = 'juniper_exec' PROMPT_PREFIX = con.settings.JUNIPER_PROMPT_PREFIX else: raise StateMachineError( 'Invalid state (%s) when calling configure' % sm.current_cli_style()) spawn = self.get_spawn() sm.go_to(self.start_state, spawn, context=self.context) timeout = timeout or self.timeout if isinstance(command, str): command = command.splitlines() self.command_list_is_empty = False if not isinstance(reply, Dialog): raise SubCommandFailure( "dialog passed via 'reply' must be an instance of Dialog") # No command passed, just move to config mode if len(command) == 0: self.result = None self.command_list_is_empty = True return if con.settings.IGNORE_CHATTY_TERM_OUTPUT: # clear buffer of 'System message at ...' messages chatty_term_wait(con.spawn, trim_buffer=True) command_output = {} # if commands is a list if not isinstance(command, collections.abc.Sequence): raise SubCommandFailure('Invalid command passed %s' % repr(command)) if 'commit' not in command: command.append('commit') try: for cmd in command: self.result = con.command(cmd, reply=reply, error_pattern=error_pattern, timeout=timeout) if self.result: output = utils.truncate_trailing_prompt( sm.get_state(sm.current_state), self.result, self.connection.hostname) output = output.replace(cmd, "", 1) output = re.sub(r"^\r\n", "", output, 1) if PROMPT_PREFIX: output = re.sub(PROMPT_PREFIX, "", output) command_output[cmd] = output.rstrip() except SubCommandFailure as e: # Go to exec state after command failure, # do not commit changes (handled by state transition) sm.go_to(self.end_state, spawn, context=self.context) raise if len(command_output) == 1: self.result = list(command_output.values())[0] else: self.result = command_output