def get_redundancy_details(self, connection, timeout=None, who='my'): """ :arg connection: device connection object :return: device role and redundancy mode of the device """ timeout = timeout or connection.settings.EXEC_TIMEOUT show_red_out = connection.execute("show redundancy", timeout=timeout) # Redundancy information for node 0/RSP0/CPU0: # Node 0/RSP0/CPU0 is in ACTIVE role p1 = re.compile( r'[Nn]ode +(?P<master>\S+) +is +in +(?P<state>[A-Z\s]+) +role') m1 = p1.search(show_red_out) if m1: master = AttributeDict() state = m1.groupdict().get('state', '') master.update({'role': state.lower(), 'state': state}) # Node Redundancy Partner (0/RSP1/CPU0) is in STANDBY role p2 = re.compile( r'[Nn]ode +[Rr]edundancy +[Pp]artner +\((?P<peer>\S+)\) ' r'+is +in +(?P<state>[A-Z\s]+) +role') m2 = p2.search(show_red_out) if m2: peer = AttributeDict() state = m2.groupdict().get('state', '') peer.update({'role': state.lower(), 'state': state}) return master if who == 'my' else peer
def retry_state_machine_go_to(self, state_machine, to_state, spawn, retries, retry_sleep, context=AttributeDict(), dialog=None, timeout=None, hop_wise=False, prompt_recovery=False): for index in range(retries + 1): try: state_machine.go_to(to_state, spawn, context=context, dialog=dialog, timeout=timeout, hop_wise=hop_wise, prompt_recovery=prompt_recovery) break except Exception as err: if index == retries: raise SubCommandFailure(err, spawn.buffer) time.sleep(retry_sleep)
def get_redundancy_details(self, connection, timeout=None, who='my'): """ :arg connection: device connection object :return: device role and redundancy mode of the device """ timeout = timeout or connection.settings.EXEC_TIMEOUT redundancy_details = AttributeDict() if who == "peer": show_red_out = connection.execute("show redundancy sta | in peer", timeout=timeout) else: show_red_out = connection.execute("show redundancy sta | in my", timeout=timeout) if re.search("ACTIVE|active", show_red_out): redundancy_details['role'] = "active" redundancy_details['state'] =\ show_red_out[show_red_out.find('-') + 1:].strip() elif re.search("standby|STANDBY", show_red_out): redundancy_details['role'] = "standby" redundancy_details['state'] =\ show_red_out[show_red_out.find('-') + 1:].strip() elif re.search("DISABLED|disabled", show_red_out): redundancy_details['role'] = "disabled" redundancy_details['state'] =\ show_red_out[show_red_out.find('-') + 1:].strip() show_red_out = connection.execute( "show redundancy sta | inc Redundancy State") redundancy_details['mode'] =\ show_red_out[show_red_out.find("=") + 1:].strip() return redundancy_details
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 download_image(self, protocol, server, image_path, dst, port=None, noconfirm=True, overwrite=True, usr=None, pwd=None, timeout=600): """Download a required image from the source to the destination :param protocol: protocol going to be used :param server: server address :param image_path: image path :param dst: destination path on ASA :param noconfirm: flag to skip download dialog :param usr: username :param pwd: password :return: None """ cmd = 'copy ' if noconfirm: cmd += '/noconfirm ' cmd += '{protocol}://'.format(protocol=protocol) if usr: cmd += '{usr}:{pwd}@'.format(usr=usr, pwd=pwd) cmd += '{server}'.format(server=server) if port: cmd += ':{port}'.format(port=port) cmd += '/{image_path} {dst}'.format(image_path=image_path, dst=dst) if noconfirm: self.execute(cmd, timeout=timeout, exception_on_bad_command=True) else: overwrite = '' if overwrite is True else 'q' args = AttributeDict({'overwrite': overwrite}) self.spawn_id.sendline(cmd) dialog = AsaDialog.download_dialog output = dialog.process(self.spawn_id, context=args, timeout=timeout) if 'Error' in output.last_match.string: raise RuntimeError('bad command: {cmd}'.format(cmd=cmd))
def get_redundancy_details(self, connection, timeout=None): """ Get redundancy details from stack device Args: connection (`obj`): connection object timeout (`int`): execute timeout Returns: redundancy_details (`dict`): redundancy details of all peers eg: {'1': {'mac': 'bcc4.9346.7880', 'role': 'Member', 'state': 'Ready', 'sw_num': '1'}, '2': {'mac': 'bcc4.9346.9180', 'role': 'Standby', 'state': 'Ready', 'sw_num': '2'}, '3': {'mac': 'bcc4.9346.7280', 'role': 'Active', 'state': 'Ready', 'sw_num': '3'}} """ timeout = timeout or connection.settings.EXEC_TIMEOUT redundancy_details = AttributeDict() # 1 Member bcc4.9346.7880 1 V01 Ready # *2 Active bcc4.9346.9180 3 V04 Ready # 4 Standby d8b1.9009.bf80 1 V01 HA sync in progress p = re.compile(r'^(\*)?(?P<sw_num>[0-9])\s+(?P<role>Member|Active|Standby)\s+' r'(?P<mac>[\w\.]+)\s+\d+\s+\w+\s+(?P<state>[\S\s]+)$') output = connection.execute("show switch", timeout=timeout) for line in output.splitlines(): m = p.search(line.strip()) if m: group = m.groupdict() redundancy_details.update({group['sw_num']: group}) return redundancy_details
def setUpClass(cls): """create a connection with the device""" cls.con = Connection(hostname=device.hostname, start=device.start, os=device.os, tacacs_username=device.tacacs_username, tacacs_password=device.tacacs_password) cls.con.connect() cls.con.configure("license grace-period") cls.vdcs = AttributeDict({ "vdc1": "vdc1", "vdc2": "vdc2", "vdc3": "vdc3" })
def recreate_connection_spawn(self, timeout): logger.info('Recreating connection spawn ...') new_spawn_id = NewSpawn(self.spawn_command) ctx = AttributeDict( {'password': self.sm.patterns.login_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], ['[.*>#$] ', 'sendline()', None, False, False], ]) d.process(new_spawn_id, context=ctx, timeout=timeout) self.spawn_id.close() self.spawn_id = new_spawn_id
def retry_handle_state_machine_go_to(self, handle, to_state, retries, retry_sleep, context=AttributeDict(), dialog=None, timeout=None, hop_wise=False, prompt_recovery=False): self.retry_state_machine_go_to(handle.state_machine, to_state, handle.spawn, retries, retry_sleep, context=context, dialog=dialog, timeout=timeout, hop_wise=hop_wise, prompt_recovery=prompt_recovery)
def get_redundancy_details(self, connection, timeout=None, who='my'): """ :arg connection: device connection object :return: device role and redundancy mode of the device """ timeout = timeout or connection.settings.EXEC_TIMEOUT redundancy_details = AttributeDict() show_red_out = connection.execute("show redundancy status", timeout=timeout) if who == "peer": block = 'Other supervisor' else: block = "This supervisor" output = self.output_block_extract(data=show_red_out, block=block) redundancy_details['role'] = "" output = output.split("\n") for line in output: if re.search("Redundancy state", line): redundancy_details['role'] =\ line[line.find(":") + 1:].strip().lower() if redundancy_details['role'] == "not present": redundancy_details['state'] = 'DISABLED' if re.search("Internal state", line): mode = line[line.find(":") + 1:].strip() if mode == "HA standby": redundancy_details['mode'] = 'sso' redundancy_details['state'] = 'STANDBY HOT' elif mode == "Active with HA standby": redundancy_details['mode'] = 'sso' redundancy_details['state'] = 'STANDBY HOT' elif mode == "Active with no standby": redundancy_details['mode'] = 'rpr' redundancy_details['state'] = 'STANDBY COLD' else: redundancy_details['mode'] = 'unknown' redundancy_details['state'] = 'unknown' return redundancy_details
def detect_state(self, spawn, context=AttributeDict()): """ Detect the device state and glean the actual state if multiple matches are found. """ state_matches = [] result = spawn.match if result: prompt = result.match_output.splitlines()[-1] for state in self.states: if re.search(state.pattern, prompt): state_matches.append(state) spawn.log.debug( 'statemachine detected state(s): {}'.format(state_matches)) if len(state_matches) > 1: # If the current state is in the detected states, assume we can keep the same state # If not, try to glean the actual state if self.current_state not in [s.name for s in state_matches]: self.glean_state(spawn, state_matches) elif len(state_matches) == 1: self.update_cur_state(state_matches[0].name) else: spawn.sendline() super().go_to('any', spawn, context)
def call_service(self, lsp, timeout=20, **kwargs): # Stringify the command in case it is an object ping_str = str('ping mpls rsvp lsp {lsp}'.format(lsp=lsp)) con = self.connection con.log.debug('+++ mpls ping +++') mpls_ping_context = AttributeDict({}) for key in kwargs: mpls_ping_context[key] = str(kwargs[key]) dialog = self.service_dialog(service_dialog=self.dialog) spawn = self.get_spawn() sm = self.get_sm() spawn.sendline(ping_str) try: dialog_match = dialog.process(spawn, context=mpls_ping_context, timeout=timeout) except TimeoutError: # Recover prompt and re-raise # Ctrl+shift+6 spawn.send('\x1E') # Empty buffer spawn.expect(".+", trim_buffer=True) raise except Exception as err: raise SubCommandFailure("MPLS Ping failed", err) from err self.result = dialog_match.match_output if self.result: output = self.utils.truncate_trailing_prompt( sm.get_state(sm.current_state), self.result, hostname=con.hostname, result_match=dialog_match, )
class FxosStateMachine(StateMachine): STATE_GLEAN = AttributeDict({ 'fxos': AttributeDict( dict(command='show version | inc Version', pattern=patterns.fxos_glean_pattern)), 'enable': AttributeDict( dict(command='show version | inc Version', pattern=patterns.asa_glean_pattern)) }) def __init__(self, hostname=None): super().__init__(hostname) def create(self): ftd = State('ftd', patterns.ftd_prompt) ftd_expert = State('expert', patterns.ftd_expert_prompt) ftd_expert_root = State('sudo', patterns.ftd_expert_root_prompt) fxos = State('fxos', patterns.fxos_prompt) fxos_scope = State('fxos_scope', patterns.fxos_scope_prompt) fxos_local_mgmt = State('fxos_mgmt', patterns.fxos_local_mgmt_prompt) enable = State('enable', patterns.enable_prompt) disable = State('disable', patterns.disable_prompt) config = State('config', patterns.config_prompt) rommon = State('rommon', patterns.rommon_prompt) ftd_to_ftd_expert = Path(ftd, ftd_expert, 'expert', None) ftd_expert_to_ftd = Path(ftd_expert, ftd, 'exit', None) ftd_expert_to_ftd_expert_root = Path( ftd_expert, ftd_expert_root, 'sudo su -', Dialog([ Statement(generic_patterns.password, sudo_password_handler, None, True, False), Statement(patterns.sudo_incorrect_password_pattern, sudo_failed) ])) ftd_expert_root_to_ftd_expert = Path(ftd_expert_root, ftd_expert, 'exit', None) enable_to_disable = Path(enable, disable, 'disable', None) enable_to_config = Path( enable, config, 'config term', Dialog([fxos_statements.config_call_home_stmt])) disable_to_enable = Path( disable, enable, 'enable', Dialog([fxos_statements.enable_password_stmt])) config_to_enable = Path(config, enable, 'end', None) ftd_to_fxos = Path(ftd, fxos, ftd_fxos_transition, None) fxos_to_ftd = Path(fxos, ftd, fxos_ftd_transition, None) fxos_scope_to_fxos = Path(fxos_scope, fxos, 'top', None) fxos_to_fxos_scope = Path(fxos, fxos_scope, change_fxos_scope, None) ftd_to_disable = Path(ftd, disable, ftd_to_disable_transition, Dialog([fxos_statements.enable_password_stmt])) ftd_to_enable = Path(ftd, enable, ftd_to_enable_transition, Dialog([fxos_statements.enable_password_stmt])) ftd_to_config = Path(ftd, config, ftd_to_config_transition, Dialog([fxos_statements.enable_password_stmt])) disable_to_ftd = Path(disable, ftd, send_ctrl_a_d, None) enable_to_ftd = Path(enable, ftd, send_ctrl_a_d, None) config_to_ftd = Path(config, ftd, send_ctrl_a_d, None) fxos_to_local_mgmt = Path(fxos, fxos_local_mgmt, 'connect local-mgmt', None) local_mgmt_to_fxos = Path(fxos_local_mgmt, fxos, 'exit', None) local_mgmt_to_rommon = Path(fxos_local_mgmt, rommon, 'reboot', Dialog(boot_to_rommon_statements)) ftd_to_rommon = Path(ftd, rommon, 'reboot', Dialog(boot_to_rommon_statements)) rommon_to_fxos = Path(rommon, fxos, boot_fxos, None) self.add_state(enable) self.add_state(disable) self.add_state(config) self.add_state(ftd) self.add_state(ftd_expert) self.add_state(ftd_expert_root) self.add_state(fxos) self.add_state(fxos_scope) self.add_state(fxos_local_mgmt) self.add_state(rommon) self.add_path(enable_to_disable) self.add_path(enable_to_config) self.add_path(config_to_enable) self.add_path(disable_to_enable) self.add_path(ftd_to_ftd_expert) self.add_path(ftd_expert_to_ftd) self.add_path(ftd_expert_to_ftd_expert_root) self.add_path(ftd_expert_root_to_ftd_expert) self.add_path(ftd_to_fxos) self.add_path(fxos_to_ftd) self.add_path(fxos_to_fxos_scope) self.add_path(fxos_scope_to_fxos) self.add_path(ftd_to_enable) self.add_path(enable_to_ftd) self.add_path(ftd_to_disable) self.add_path(ftd_to_config) self.add_path(disable_to_ftd) self.add_path(config_to_ftd) self.add_path(fxos_to_local_mgmt) self.add_path(local_mgmt_to_fxos) self.add_path(local_mgmt_to_rommon) self.add_path(ftd_to_rommon) self.add_path(rommon_to_fxos) self.add_default_statements(default_statement_list) def detect_state(self, spawn): """ Detect the device state and glean the actual state if multiple matches are found. """ state_matches = [] result = spawn.match if result: prompt = result.match_output.splitlines()[-1] for state in self.states: if re.search(state.pattern, prompt): state_matches.append(state) spawn.log.debug( 'statemachine detected state(s): {}'.format(state_matches)) if len(state_matches) > 1: # If the current state is in the detected states, assume we can keep the same state # If not, try to glean the actual state if self.current_state not in [s.name for s in state_matches]: self.glean_state(spawn, state_matches) elif len(state_matches) == 1: self.update_cur_state(state_matches[0].name) else: spawn.sendline() super().go_to('any', spawn) def glean_state(self, spawn, possible_states): """ Try to figure out the state by sending commands and verifying the matches against known output. """ # Create list of commands to execute glean_command_map = {} state_patterns = [] for state in possible_states: state_patterns.append(state.pattern) glean_data = self.STATE_GLEAN.get(state.name, None) if glean_data: if glean_data.command in glean_command_map: glean_command_map[glean_data.command][ glean_data.pattern] = state else: glean_command_map[glean_data.command] = {} glean_command_map[glean_data.command][ glean_data.pattern] = state if not glean_command_map: raise StateMachineError( 'Unable to detect state, multiple states possible and no glean data available' ) # Execute each glean commnd and check for pattern match for glean_cmd in glean_command_map: glean_pattern_map = glean_command_map[glean_cmd] dialog = Dialog(default_statement_list + [Statement(p) for p in state_patterns]) spawn.sendline(glean_cmd) result = dialog.process(spawn) if result: output = result.match_output for glean_pattern in glean_pattern_map: if re.search(glean_pattern, output): self.update_cur_state(glean_pattern_map[glean_pattern]) return def go_to(self, to_state, spawn, **kwargs): spawn.log.debug('statemachine goto: {} -> {}'.format( self.current_state, to_state)) super().go_to(to_state, spawn, **kwargs) if to_state == 'any' and self.current_state in self.STATE_GLEAN: glean_states = [self.get_state(name) for name in self.STATE_GLEAN] self.glean_state(spawn, glean_states)
def ssh_vty(self, ip, port, username='******', password=KickConsts.DEFAULT_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) ssh_line = None 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, False, False], ['[>#$] ', 'sendline()', None, False, False] ]) output = d.process(spawn_id, context=ctx, timeout=timeout) logger.info('Output from login dialog is: {}'.format(output.match_output.replace( '\n', '[LF]').replace('\r', '[CR]'))) try: ssh_line = self._accept_configuration_and_change_password(spawn_id, line_type, username, password, timeout) except TimeoutError: logger.info("Device initialization has failed") logger.info('Spawn_id.buffer content is: {}'.format(spawn_id.buffer)) raise except OSError: logger.info( "Failed to login with user provided details: user: {}, password: {}".format( username, password)) raise logger.debug('ssh_vty() finished successfully') if not ssh_line: ssh_line = self.line_class(spawn_id, self.sm, line_type, timeout=timeout) return ssh_line
def ssh_console(self, ip, port, username=DEFAULT_USERNAME, password=DEFAULT_PASSWORD, timeout=None, en_password=DEFAULT_ENPASSWORD): """Set up an ssh console connection. This goes into device's console port, through a terminal server. :param ip: ip address of terminal server :param port: port of device on terminal server :param username: username :param password: password :param timeout: in seconds :param en_password: enable password to switch to line configuration mode :return: a line object (where users can call execute(), for example) """ if username == DEFAULT_USERNAME: username = get_username(username) if password == DEFAULT_PASSWORD: password = get_password(password) if en_password == DEFAULT_ENPASSWORD: en_password = get_en_password(en_password) graphite.publish_kick_metric('device.basic.ssh_console', 1) if not timeout: timeout = self.default_timeout 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, False, False], ]) try: d.process(spawn_id, context=ctx, timeout=timeout) except OSError: spawn_id.close() clear_line(ip, int(port) % 100, user=username, pwd=password, prompt='#', access='ssh', en_password=en_password, timeout=timeout) spawn_id = NewSpawn( 'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no ' '-l {} -p {} {} \n'.format(username, port, ip)) try: d.process(spawn_id, context=ctx, timeout=timeout) except: spawn_id.close() raise d1 = Dialog([ ['Password OK', 'sendline()', None, False, False], ['[.*>#] ', 'sendline()', None, False, False], ]) try: d1.process(spawn_id, timeout=timeout) except: spawn_id.sendline() logger.debug('ssh_console() finished successfully') try: ssh_line = self.line_class(spawn_id, self.sm, 'ssh', timeout=timeout) except: spawn_id.close() raise return ssh_line
def go_to(self, to_state, spawn, context=AttributeDict(), dialog=None, timeout=None, hop_wise=False, prompt_recovery=False): # get the composed full (slot_<slot>_<app>) state name to_state = self.get_full_state_name(to_state) # when a connection is made to the device and the device # is left in a random state we need to try to detect the # state or signal failure because going to 'any' state # can lead to circular transitions which go on in a loop # indefinetely if self.current_state == 'generic' and to_state is 'any': # try to detect in which state we are right now or fail # send a newline to initialize the prompt spawn.sendline('') # wait 10 seconds for the prompt to populate time.sleep(10) # match everything in the output buffer output = spawn.expect('.*', timeout=30).match_output for state_name, state_data in self.states_dict.items(): pattern = state_data.pattern if isinstance(pattern, str): if re.match(pattern, output.split('\r\n')[-1]): self.update_cur_state(state_name) return output if isinstance(pattern, list): for pat in pattern: if re.match(pat, output.split('\r\n')[-1]): self.update_cur_state(state_name) return output raise RuntimeError('Could not detect current state. Please ' + 'connect to the chassis and bring it to ' + 'the mio state prompt. Output is:' + output) elif (self.current_state != 'generic' and to_state is 'any') or \ isinstance(to_state, list): expected_state = to_state transition = AnyStateTransition(state_machine=self, to_state=to_state, spawn=spawn, dialog=dialog, timeout=timeout, context=context, prompt_recovery=prompt_recovery) else: if not isinstance(to_state, State): to_state = self.get_state(to_state) expected_state = to_state.name # Get the current state from SM current_state = self.get_state(self.current_state) # If the current and to_state state are same # we are already there so just return if to_state == current_state: return # If hop_wise is enabled then do step by step state transition if hop_wise: transition = HopWiseStateTransition(state_machine=self, to_state=to_state, spawn=spawn, dialog=dialog, timeout=timeout, context=context, prompt_recovery=prompt_recovery) else: transition = StateTransition(state_machine=self, to_state=to_state, spawn=spawn, dialog=dialog, timeout=timeout, context=context, prompt_recovery=prompt_recovery) # Start the state transition try: output = transition.do_transitions() except Exception as err: raise StateMachineError('Failed while bringing device to ' + '"%s" state' % \ str(expected_state)) from err finally: if transition.current_state is not 'generic': self.update_cur_state(transition.current_state) # If the current_state and to_state are not matching # the probably whe landed somewhere wrong, so raise exception if expected_state is not 'any' \ and self.current_state not in expected_state: raise StateMachineError( 'Changing state to %s failed\n' 'current_state: %s\n' 'last command: %s\n' 'buffer: %s\n' 'last match: %s' % ( expected_state, self.current_state, repr(spawn.last_sent), repr(spawn.buffer), repr(spawn.match.match_output) ) ) return output
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))
The tests are from black-box perspective and requires a device. Few tests are being tested implicitly. - Creation of VDC """ import unittest from unicon.utils import AttributeDict from unicon import Connection from unicon.core.errors import SubCommandFailure device = AttributeDict({ 'start': ['telnet 10.64.70.24 2020', 'telnet 10.64.70.24 2019'], 'hostname': 'step-n7k-2', 'tacacs_username': '******', 'tacacs_password': r'Cscats123!', 'os': 'nxos' }) class TestVdc(unittest.TestCase): @classmethod def setUpClass(cls): """create a connection with the device""" cls.con = Connection(hostname=device.hostname, start=device.start, os=device.os, tacacs_username=device.tacacs_username,
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: st._action()
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)
def execute(self, cmd, timeout=None, exception_on_bad_command=False, prompt=None): """Stay in current mode, run the command and return the output. :param cmd: a string, such as "show nameif" :param timeout: in seconds :param exception_on_bad_command: True/False - whether to raise an exception on a bad command :param prompt: a string representing a pattern to match against the content of the buffer if not given, the pattern of the current state will be used :return: output as string """ if not timeout: timeout = self.default_timeout if not prompt: prompt = self.sm.get_state(self.sm.current_state).pattern initial_state = self.sm.current_state try_reconnect = False try: # clear buffer before running a command if self.spawn_id.read_update_buffer(): if all(i in self.spawn_id.buffer for i in ['Connection', 'closed']): try_reconnect = True else: self.spawn_id.buffer = '' except OSError as e: if self.type in ['ssh', 'ssh_vty']: try_reconnect = True else: logger.error('Error while executing command: ', e) raise e if try_reconnect: # closing initial spawn self.spawn_id.close() logger.info('Line was disconnected, trying to reconnect') new_spawn_id = NewSpawn(self.spawn_command) ctx = AttributeDict({'password': self.sm.patterns.login_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], ['[.*>#$] ', 'sendline()', None, False, False], ]) try: d.process(new_spawn_id, context=ctx, timeout=timeout) self.spawn_id = new_spawn_id self.go_to('any') # at reconnection, reconfigure the terminal if needed self.__reconfigure_terminal(timeout) self.go_to(initial_state) except: logger.error('Connection could not be reestablished') raise RuntimeError('Connection could not be reestablished') self.spawn_id.sendline(cmd) # fmc/ftd inserts ' \r' for every 80 chars. sometimes for unknown # reason it gives prompt first, then output, then prompt again. # the typical pattern matching easily breaks here. we rely on the # fact of '\r\n' is always flanking the output. output = self.spawn_id.expect(prompt, timeout=timeout).last_match.string logger.debug("before trimming in execute(): {}".format(output)) index = output.find('\r\n') output = output[index:] # handle bad command errors = [ "% Invalid Command", "% Incomplete Command", "Error: ", "ERROR: ", "Error ", "ERROR " ] if any([error in output for error in errors]): if exception_on_bad_command: raise RuntimeError("bad command: {}".format(cmd)) else: logger.debug("bad command: {}".format(cmd)) return self.remove_prompt_from_output(prompt, output)