async def check_cli_mode(self): """Check if we are in cli mode. Return boolean""" logger.info("Host {}: Checking shell mode".format(self._host)) cli_check = type(self)._cli_check self._stdin.write(self._normalize_cmd("\n")) output = await self._read_until_prompt() return cli_check in output
async def check_config_mode(self): """Check if are in configuration mode. Return boolean""" logger.info("Host {}: Checking configuration mode".format(self._host)) check_string = type(self)._config_check self._stdin.write(self._normalize_cmd("\n")) output = await self._read_until_prompt() return check_string in output
async def _set_base_prompt(self): """ Setting two important vars for ASA base_prompt - textual prompt in CLI (usually hostname) base_pattern - regexp for finding the end of command. IT's platform specific parameter For ASA devices base_pattern is "prompt([\/\w]+)?(\(.*?\))?[#|>] """ logger.info("Host {}: Setting base prompt".format(self._host)) prompt = await self._find_prompt() # Cut off prompt from "prompt/context/other" if it exists # If not we get all prompt prompt = prompt[:-1].split('/') prompt = prompt[0] self._base_prompt = prompt delimiters = map(re.escape, type(self)._delimiter_list) delimiters = r"|".join(delimiters) base_prompt = re.escape(self._base_prompt[:12]) pattern = type(self)._pattern self._base_pattern = pattern.format(base_prompt, delimiters) logger.debug("Host {}: Base Prompt: {}".format(self._host, self._base_prompt)) logger.debug("Host {}: Base Pattern: {}".format( self._host, self._base_pattern)) return self._base_prompt
async def check_config_mode(self): """Checks if the device is in configuration mode or not""" logger.info('Host {}: Checking configuration mode'.format(self._host)) check_string = type(self)._config_check self._stdin.write(self._normalize_cmd('\n')) output = await self._read_until_prompt() return check_string in output
async def send_config_set(self, config_commands=None): """ Sending configuration commands to device The commands will be executed one after the other. :param list config_commands: iterable string list with commands for applying to network device :return: The output of this commands """ logger.info("Host {}: Sending configuration settings".format(self._host)) if config_commands is None: return "" if not hasattr(config_commands, "__iter__"): raise ValueError( "Host {}: Invalid argument passed into send_config_set".format( self._host ) ) # Send config commands logger.debug("Host {}: Config commands: {}".format(self._host, config_commands)) output = "" for cmd in config_commands: self._stdin.write(self._normalize_cmd(cmd)) output += await self._read_until_prompt() if self._ansi_escape_codes: output = self._strip_ansi_escape_codes(output) output = self._normalize_linefeeds(output) logger.debug( "Host {}: Config commands output: {}".format(self._host, repr(output)) ) return output
async def _check_system_view(self): """Check if we are in system view. Return boolean""" logger.info('Host {}: Checking system view'.format(self._host)) check_string = type(self)._system_view_check self._stdin.write(self._normalize_cmd('\n')) output = await self._read_until_prompt() return check_string in output
async def enable_mode(self, pattern='password', re_flags=re.IGNORECASE): """Enter to privilege exec""" logger.info('Host {}: Entering to privilege exec'.format(self._host)) output = "" enable_command = type(self)._priv_enter if not await self.check_enable_mode(): self._stdin.write(self._normalize_cmd(enable_command)) output += await self._read_until_prompt_or_pattern( pattern=pattern, re_flags=re_flags) if re.search(pattern, output, re_flags): self._stdin.write(self._normalize_cmd(self._secret)) output += await self._read_until_prompt_or_pattern( pattern=type(self)._priv_confirm_message, re_flags=re_flags) if re.search( type(self)._priv_confirm_message, output, re_flags): if self._preempt_privilege: self._stdin.write(self._normalize_cmd("Yes")) else: raise ValueError( "Failed to enter privilege exec:" "there is already a active administration session." "Use preempt_privilege=True") if not await self.check_enable_mode(): raise ValueError("Failed to enter to privilege exec") return output
async def send_command(self, command_string, pattern='', re_flags=0, strip_command=True, strip_prompt=True): """ Sending command to device (support interactive commands with pattern) :param str command_string: command for executing basically in privilege mode :param str pattern: pattern for waiting in output (for interactive commands) :param re.flags re_flags: re flags for pattern :param bool strip_command: True or False for stripping command from output :param bool strip_prompt: True or False for stripping ending device prompt :return: The output of the command """ logger.info('Host {}: Sending command'.format(self._host)) output = '' command_string = self._normalize_cmd(command_string) logger.debug("Host {}: Send command: {}".format(self._host, repr(command_string))) self._stdin.write(command_string) output = await self._read_until_prompt_or_pattern(pattern, re_flags) # Some platforms have ansi_escape codes if self._ansi_escape_codes: output = self._strip_ansi_escape_codes(output) output = self._normalize_linefeeds(output) if strip_prompt: output = self._strip_prompt(output) if strip_command: output = self._strip_command(command_string, output) logger.debug("Host {}: Send command output: {}".format(self._host, repr(output))) return output
async def check_config_mode(self): """Check if are in configuration mode. Return boolean""" logger.info('Host {}: Checking configuration mode'.format(self._host)) check_string = type(self)._config_check self._stdin.write(self._normalize_cmd('\n')) output = await self._read_until_prompt() return check_string in output
async def _establish_connection(self): """Establishing SSH connection to the network device""" logger.info( "Host {}: Establishing connection to port {}".format(self._host, self._port) ) output = "" # initiate SSH connection fut = asyncssh.connect(**self._connect_params_dict) try: self._conn = await asyncio.wait_for(fut, self._timeout) except asyncssh.DisconnectError as e: raise DisconnectError(self._host, e.code, e.reason) except asyncio.TimeoutError: raise TimeoutError(self._host) self._stdin, self._stdout, self._stderr = await self._conn.open_session( term_type="Dumb", term_size=(200, 24) ) logger.info("Host {}: Connection is established".format(self._host)) # Flush unnecessary data delimiters = map(re.escape, type(self)._delimiter_list) delimiters = r"|".join(delimiters) output = await self._read_until_pattern(delimiters) logger.debug( "Host {}: Establish Connection Output: {}".format(self._host, repr(output)) ) return output
async def send_config_set(self, config_commands=None): """ Sending configuration commands to device The commands will be executed one after the other. :param list config_commands: iterable string list with commands for applying to network device :return: The output of this commands """ logger.info("Host {}: Sending configuration settings".format(self._host)) if config_commands is None: return '' if not hasattr(config_commands, '__iter__'): raise ValueError("Host {}: Invalid argument passed into send_config_set".format(self._host)) # Send config commands logger.debug("Host {}: Config commands: {}".format(self._host, config_commands)) output = '' for cmd in config_commands: self._stdin.write(self._normalize_cmd(cmd)) output += await self._read_until_prompt() if self._ansi_escape_codes: output = self._strip_ansi_escape_codes(output) output = self._normalize_linefeeds(output) logger.debug("Host {}: Config commands output: {}".format(self._host, repr(output))) return output
async def _set_base_prompt(self): """ Setting two important vars base_prompt - textual prompt in CLI (usually username or hostname) base_pattern - regexp for finding the end of command. IT's platform specific parameter For JunOS devices base_pattern is "user(@[hostname])?[>|#] """ logger.info("Host {}: Setting base prompt".format(self._host)) prompt = await self._find_prompt() prompt = prompt[:-1] # Strip off trailing terminator if '@' in prompt: prompt = prompt.split('@')[1] self._base_prompt = prompt delimiters = map(re.escape, type(self)._delimiter_list) delimiters = r"|".join(delimiters) base_prompt = re.escape(self._base_prompt[:12]) pattern = type(self)._pattern self._base_pattern = pattern.format(delimiters) logger.debug("Host {}: Base Prompt: {}".format(self._host, self._base_prompt)) logger.debug("Host {}: Base Pattern: {}".format( self._host, self._base_pattern)) return self._base_prompt
async def _set_base_prompt(self): """ Setting two important vars base_prompt - textual prompt in CLI (usually hostname) base_pattern - regexp for finding the end of command. IT's platform specific parameter For Comware devices base_pattern is "[\]|>]prompt(\-\w+)?[\]|>] """ logger.info("Host {}: Setting base prompt".format(self._host)) prompt = await self._find_prompt() # Strip off any leading HRP_. characters for USGv5 HA prompt = re.sub(r"^HRP_.", "", prompt, flags=re.M) # Strip off trailing terminator self._base_prompt = prompt[1:-1] delimiter_right = map(re.escape, type(self)._delimiter_list) delimiter_right = r"|".join(delimiter_right) delimiter_left = map(re.escape, type(self)._delimiter_left_list) delimiter_left = r"|".join(delimiter_left) base_prompt = re.escape(self._base_prompt[:12]) pattern = type(self)._pattern self._base_pattern = pattern.format( delimiter_left=delimiter_left, prompt=base_prompt, delimiter_right=delimiter_right, ) logger.debug("Host {}: Base Prompt: {}".format(self._host, self._base_prompt)) logger.debug("Host {}: Base Pattern: {}".format( self._host, self._base_pattern)) return self._base_prompt
async def check_enable_mode(self): """Check if we are in privilege exec. Return boolean""" logger.info("Host {}: Checking privilege exec".format(self._host)) check_string = type(self)._priv_check self._stdin.write(self._normalize_cmd("\n")) output = await self._read_until_prompt() return check_string in output
async def _set_base_prompt(self): """ Setting two important vars: base_prompt - textual prompt in CLI (usually hostname) base_pattern - regexp for finding the end of command. It's platform specific parameter For Cisco devices base_pattern is "prompt(\(.*?\))?[#|>] """ logger.info("Host {}: Setting base prompt".format(self._host)) prompt = await self._find_prompt() # Strip off trailing terminator self._base_prompt = prompt[:-1] delimiters = map(re.escape, type(self)._delimiter_list) delimiters = r"|".join(delimiters) base_prompt = re.escape(self._base_prompt[:12]) pattern = type(self)._pattern self._base_pattern = pattern.format(prompt=base_prompt, delimiters=delimiters) logger.debug("Host {}: Base Prompt: {}".format(self._host, self._base_prompt)) logger.debug("Host {}: Base Pattern: {}".format( self._host, self._base_pattern)) return self._base_prompt
async def check_enable_mode(self): """Check if we are in privilege exec. Return boolean""" logger.info('Host {}: Checking privilege exec'.format(self._host)) check_string = type(self)._priv_check self._stdin.write(self._normalize_cmd('\n')) output = await self._read_until_prompt() return check_string in output
def _strip_ansi_escape_codes(string_buffer): """ Remove some ANSI ESC codes from the output http://en.wikipedia.org/wiki/ANSI_escape_code Note: this does not capture ALL possible ANSI Escape Codes only the ones I have encountered Current codes that are filtered: ESC = '\x1b' or chr(27) ESC = is the escape character [^ in hex ('\x1b') ESC[24;27H Position cursor ESC[?25h Show the cursor ESC[E Next line (HP does ESC-E) ESC[2K Erase line ESC[1;24r Enable scrolling from start to row end ESC7 Save cursor position ESC[r Scroll all screen ESC8 Restore cursor position ESC[nA Move cursor up to n cells ESC[nB Move cursor down to n cells require: HP ProCurve F5 LTM's Mikrotik """ logger.info("Stripping ansi escape codes") logger.debug("Unstripped output: {}".format(repr(string_buffer))) code_save_cursor = chr(27) + r'7' code_scroll_screen = chr(27) + r'\[r' code_restore_cursor = chr(27) + r'8' code_cursor_up = chr(27) + r'\[\d+A' code_cursor_down = chr(27) + r'\[\d+B' code_position_cursor = chr(27) + r'\[\d+;\d+H' code_show_cursor = chr(27) + r'\[\?25h' code_next_line = chr(27) + r'E' code_erase_line = chr(27) + r'\[2K' code_enable_scroll = chr(27) + r'\[\d+;\d+r' code_set = [ code_save_cursor, code_scroll_screen, code_restore_cursor, code_cursor_up, code_cursor_down, code_position_cursor, code_show_cursor, code_erase_line, code_enable_scroll ] output = string_buffer for ansi_esc_code in code_set: output = re.sub(ansi_esc_code, '', output) # CODE_NEXT_LINE must substitute with '\n' output = re.sub(code_next_line, '\n', output) logger.debug('Stripped output: {}'.format(repr(output))) return output
async def check_shell_mode(self): """Checks if device in shell mode or not""" logger.info('Host {}: Checking shell mode'.format(self._host)) check_string = type(self)._shell_check self._stdin.write(self._normalize_cmd('\n')) output = await self._read_until_pattern(r'[\>|\#]') logger.info(output) return check_string in output
async def _check_multiple_mode(self): """Check mode multiple. If mode is multiple we adding info about contexts""" logger.info("Host {}:Checking multiple mode".format(self._host)) out = await self.send_command('show mode') if 'multiple' in out: self._multiple_mode = True logger.debug("Host {}: Multiple mode: {}".format(self._host, self._multiple_mode))
async def _check_multiple_mode(self): """Check mode multiple. If mode is multiple we adding info about contexts""" logger.info("Host {}:Checking multiple mode".format(self._host)) out = await self.send_command('show mode') if 'multiple' in out: self._multiple_mode = True logger.debug("Host {}: Multiple mode: {}".format( self._host, self._multiple_mode))
def _strip_prompt(self, a_string): """Strip the trailing router prompt from the output""" logger.info('Host {}: Stripping prompt'.format(self._host)) response_list = a_string.split('\n') last_line = response_list[-1] if self._base_prompt in last_line: return '\n'.join(response_list[:-1]) else: return a_string
async def _set_base_prompt(self): """Setting base pattern""" logger.info("Host {}: Setting base prompt".format(self._host)) delimiters = map(re.escape, type(self)._delimiter_list) delimiters = r"|".join(delimiters) pattern = type(self)._pattern self._base_pattern = pattern.format(delimiters) logger.debug("Host {}: Base Pattern: {}".format(self._host, self._base_pattern)) return self._base_prompt
def _strip_prompt(self, a_string): """Strip the trailing router prompt from the output""" logger.info("Host {}: Stripping prompt".format(self._host)) response_list = a_string.split("\n") last_line = response_list[-1] if self._base_prompt in last_line: return "\n".join(response_list[:-1]) else: return a_string
def _strip_ansi_escape_codes(string_buffer): """ Remove some ANSI ESC codes from the output http://en.wikipedia.org/wiki/ANSI_escape_code Note: this does not capture ALL possible ANSI Escape Codes only the ones I have encountered Current codes that are filtered: ESC = '\x1b' or chr(27) ESC = is the escape character [^ in hex ('\x1b') ESC[24;27H Position cursor ESC[?25h Show the cursor ESC[E Next line (HP does ESC-E) ESC[2K Erase line ESC[1;24r Enable scrolling from start to row end ESC7 Save cursor position ESC[r Scroll all screen ESC8 Restore cursor position ESC[nA Move cursor up to n cells ESC[nB Move cursor down to n cells require: HP ProCurve F5 LTM's Mikrotik """ logger.info("Stripping ansi escape codes") logger.debug("Unstripped output: {}".format(repr(string_buffer))) code_save_cursor = chr(27) + r'7' code_scroll_screen = chr(27) + r'\[r' code_restore_cursor = chr(27) + r'8' code_cursor_up = chr(27) + r'\[\d+A' code_cursor_down = chr(27) + r'\[\d+B' code_position_cursor = chr(27) + r'\[\d+;\d+H' code_show_cursor = chr(27) + r'\[\?25h' code_next_line = chr(27) + r'E' code_erase_line = chr(27) + r'\[2K' code_enable_scroll = chr(27) + r'\[\d+;\d+r' code_set = [code_save_cursor, code_scroll_screen, code_restore_cursor, code_cursor_up, code_cursor_down, code_position_cursor, code_show_cursor, code_erase_line, code_enable_scroll] output = string_buffer for ansi_esc_code in code_set: output = re.sub(ansi_esc_code, '', output) # CODE_NEXT_LINE must substitute with '\n' output = re.sub(code_next_line, '\n', output) logger.debug('Stripped output: {}'.format(repr(output))) return output
async def _set_base_prompt(self): """Setting base pattern""" logger.info("Host {}: Setting base prompt".format(self._host)) delimiters = map(re.escape, type(self)._delimiter_list) delimiters = r"|".join(delimiters) pattern = type(self)._pattern self._base_pattern = pattern.format(delimiters=delimiters) logger.debug("Host {}: Base Pattern: {}".format( self._host, self._base_pattern)) return self._base_prompt
async def config_mode(self): """Enter to configuration mode""" logger.info('Host {}: Entering to configuration mode'.format(self._host)) output = "" config_enter = type(self)._config_enter if not await self.check_config_mode(): self._stdin.write(self._normalize_cmd(config_enter)) output += await self._read_until_prompt() if not await self.check_config_mode(): raise ValueError("Failed to enter to configuration mode") return output
async def _system_view(self): """Enter to system view""" logger.info('Host {}: Entering to system view'.format(self._host)) output = "" system_view_enter = type(self)._system_view_enter if not await self._check_system_view(): self._stdin.write(self._normalize_cmd(system_view_enter)) output += await self._read_until_prompt() if not await self._check_system_view(): raise ValueError("Failed to enter to system view") return output
async def exit_config_mode(self): """Exit from configuration mode""" logger.info('Host {}: Exiting from configuration mode'.format(self._host)) output = "" config_exit = type(self)._config_exit if await self.check_config_mode(): self._stdin.write(self._normalize_cmd(config_exit)) output += await self._read_until_prompt() if await self.check_config_mode(): raise ValueError("Failed to exit from configuration mode") return output
async def _exit_system_view(self): """Exit from system view""" logger.info('Host {}: Exiting from system view'.format(self._host)) output = "" system_view_exit = type(self)._system_view_exit if await self._check_system_view(): self._stdin.write(self._normalize_cmd(system_view_exit)) output += await self._read_until_prompt() if await self._check_system_view(): raise ValueError("Failed to exit from system view") return output
async def exit_enable_mode(self): """Exit from privilege exec""" logger.info('Host {}: Exiting from privilege exec'.format(self._host)) output = "" exit_enable = type(self)._priv_exit if await self.check_enable_mode(): self._stdin.write(self._normalize_cmd(exit_enable)) output += await self._read_until_prompt() if await self.check_enable_mode(): raise ValueError("Failed to exit from privilege exec") return output
async def exit_config_mode(self): """Exit from configuration mode""" logger.info("Host {}: Exiting from configuration mode".format(self._host)) output = "" config_exit = type(self)._config_exit if await self.check_config_mode(): self._stdin.write(self._normalize_cmd(config_exit)) output += await self._read_until_prompt() if await self.check_config_mode(): raise ValueError("Failed to exit from configuration mode") return output
async def config_mode(self): """Enter to configuration mode""" logger.info("Host {}: Entering to configuration mode".format(self._host)) output = "" config_enter = type(self)._config_enter if not await self.check_config_mode(): self._stdin.write(self._normalize_cmd(config_enter)) output += await self._read_until_prompt() if not await self.check_config_mode(): raise ValueError("Failed to enter to configuration mode") return output
async def exit_enable_mode(self): """Exit from privilege exec""" logger.info("Host {}: Exiting from privilege exec".format(self._host)) output = "" exit_enable = type(self)._priv_exit if await self.check_enable_mode(): self._stdin.write(self._normalize_cmd(exit_enable)) output += await self._read_until_prompt() if await self.check_enable_mode(): raise ValueError("Failed to exit from privilege exec") return output
async def _disable_paging(self): """Disable paging method""" logger.info("Host {}: Trying to disable paging".format(self._host)) command = type(self)._disable_paging_command command = self._normalize_cmd(command) logger.debug("Host {}: Disable paging command: {}".format(self._host, repr(command))) self._stdin.write(command) output = await self._read_until_prompt() logger.debug("Host {}: Disable paging output: {}".format(self._host, repr(output))) if self._ansi_escape_codes: output = self._strip_ansi_escape_codes(output) return output
async def exit_shell_mode(self): """Exit from shell mode""" logger.info('Host {}: Exiting from shell mode'.format(self._host)) output = '' exit_shell = type(self)._shell_exit if await self.check_shell_mode(): self._stdin.write(self._normalize_cmd(exit_shell)) output = await self._read_until_pattern(r'[\>|\#]') if await self.check_shell_mode(): raise ValueError("Failed to exit from shell mode") await self._set_base_prompt() # base promt differs in shell mode return output
async def connect(self): """ Async Connection method General Terminal using 2 functions: * _establish_connection() for connecting to device * _set_base_prompt() for setting base pattern without setting base prompt """ logger.info("Host {}: Connecting to device".format(self._host)) await self._establish_connection() await self._set_base_prompt() logger.info("Host {}: Connected to device".format(self._host))
async def connect(self): """ Async Connection method RouterOS using 2 functions: * _establish_connection() for connecting to device * _set_base_prompt() for finding and setting device prompt """ logger.info("Host {}: Connecting to device".format(self._host)) await self._establish_connection() await self._set_base_prompt() logger.info("Host {}: Connected to device".format(self._host))
async def _find_prompt(self): """Finds the current network device prompt, last line only.""" logger.info("Host {}: Finding prompt".format(self._host)) self._stdin.write("\r") prompt = "" prompt = await self._read_until_prompt() prompt = prompt.strip() if self._ansi_escape_codes: prompt = self._strip_ansi_escape_codes(prompt) if not prompt: raise ValueError("Unable to find prompt: {0}".format(prompt)) logger.debug("Host {}: Prompt: {}".format(self._host, prompt)) return prompt
async def _find_prompt(self): """Finds the current network device prompt, last line only.""" logger.info("Host {}: Finding prompt".format(self._host)) self._stdin.write("\r") prompt = '' prompt = await self._read_until_prompt() prompt = prompt.strip() if self._ansi_escape_codes: prompt = self._strip_ansi_escape_codes(prompt) if not prompt: raise ValueError("Unable to find prompt: {0}".format(prompt)) logger.debug("Host {}: Prompt: {}".format(self._host, prompt)) return prompt
async def send_command( self, command_string, pattern="", re_flags=0, strip_command=True, strip_prompt=True, use_textfsm=False ): """ Sending command to device (support interactive commands with pattern) :param str command_string: command for executing basically in privilege mode :param str pattern: pattern for waiting in output (for interactive commands) :param re.flags re_flags: re flags for pattern :param bool strip_command: True or False for stripping command from output :param bool strip_prompt: True or False for stripping ending device prompt :return: The output of the command """ logger.info("Host {}: Sending command".format(self._host)) output = "" command_string = self._normalize_cmd(command_string) logger.debug( "Host {}: Send command: {}".format(self._host, repr(command_string)) ) self._stdin.write(command_string) output = await self._read_until_prompt_or_pattern(pattern, re_flags) # Some platforms have ansi_escape codes if self._ansi_escape_codes: output = self._strip_ansi_escape_codes(output) output = self._normalize_linefeeds(output) if strip_prompt: output = self._strip_prompt(output) if strip_command: output = self._strip_command(command_string, output) logger.debug( "Host {}: Send command output: {}".format(self._host, repr(output)) ) # If both TextFSM and Genie are set, try TextFSM then Genie if use_textfsm: structured_output = get_structured_data( output, platform=self._device_type, command=command_string ) # If we have structured data; return it. if not isinstance(structured_output, str): return structured_output logger.debug(f"send_command_timing final output: {output}") return output
async def enable_mode(self, pattern='password', re_flags=re.IGNORECASE): """Enter to privilege exec""" logger.info('Host {}: Entering to privilege exec'.format(self._host)) output = "" enable_command = type(self)._priv_enter if not await self.check_enable_mode(): self._stdin.write(self._normalize_cmd(enable_command)) output += await self._read_until_prompt_or_pattern(pattern=pattern, re_flags=re_flags) if re.search(pattern, output, re_flags): self._stdin.write(self._normalize_cmd(self._secret)) output += await self._read_until_prompt() if not await self.check_enable_mode(): raise ValueError("Failed to enter to privilege exec") return output
async def _find_prompt(self): """Finds the current network device prompt, last line only""" logger.info("Host {}: Finding prompt".format(self._host)) self._stdin.write(self._normalize_cmd("\n")) prompt = '' delimiters = map(re.escape, type(self)._delimiter_list) delimiters = r"|".join(delimiters) prompt = await self._read_until_pattern(delimiters) prompt = prompt.strip() if self._ansi_escape_codes: prompt = self._strip_ansi_escape_codes(prompt) if not prompt: raise ValueError("Host {}: Unable to find prompt: {}".format(self._host, repr(prompt))) logger.debug("Host {}: Found Prompt: {}".format(self._host, repr(prompt))) return prompt
async def enable_mode(self, pattern="password", re_flags=re.IGNORECASE): """Enter to privilege exec""" logger.info("Host {}: Entering to privilege exec".format(self._host)) output = "" enable_command = type(self)._priv_enter if not await self.check_enable_mode(): self._stdin.write(self._normalize_cmd(enable_command)) output += await self._read_until_prompt_or_pattern( pattern=pattern, re_flags=re_flags) if re.search(pattern, output, re_flags): self._stdin.write(self._normalize_cmd(self._secret)) output += await self._read_until_prompt() if not await self.check_enable_mode(): raise ValueError("Failed to enter to privilege exec") return output
async def _read_until_pattern(self, pattern='', re_flags=0): """Read channel until pattern detected. Return ALL data available""" output = '' logger.info("Host {}: Reading until pattern".format(self._host)) if not pattern: pattern = self._base_pattern logger.debug("Host {}: Reading pattern: {}".format(self._host, pattern)) while True: fut = self._stdout.read(self._MAX_BUFFER) try: output += await asyncio.wait_for(fut, self._timeout) except asyncio.TimeoutError: raise TimeoutError(self._host) if re.search(pattern, output, flags=re_flags): logger.debug("Host {}: Reading pattern '{}' was found: {}".format(self._host, pattern, repr(output))) return output
async def _establish_connection(self): """Establish SSH connection to the network device""" logger.info('Host {}: Establishing connection to port {}'.format(self._host, self._port)) output = "" # initiate SSH connection try: self._conn = await asyncssh.connect(**self._connect_params_dict) except asyncssh.DisconnectError as e: raise DisconnectError(self._host, e.code, e.reason) self._stdin, self._stdout, self._stderr = await self._conn.open_session(term_type='dumb') logger.info("Host {}: Connection is established".format(self._host)) # Flush unnecessary data output = await self._read_until_prompt() logger.debug("Host {}: Establish Connection Output: {}".format(self._host, repr(output))) return output
async def connect(self): """ Basic asynchronous connection method It connects to device and makes some preparation steps for working. Usual using 3 functions: * _establish_connection() for connecting to device * _set_base_prompt() for finding and setting device prompt * _disable_paging() for non interactive output in commands """ logger.info("Host {}: Trying to connect to the device".format(self._host)) await self._establish_connection() await self._set_base_prompt() await self._disable_paging() logger.info("Host {}: Has connected to the device".format(self._host))
async def _cmdline_mode_enter(self): """Entering to cmdline-mode""" logger.info('Host {}: Entering to cmdline mode'.format(self._host)) output = '' cmdline_mode_enter = type(self)._cmdline_mode_enter_command check_error_string = type(self)._cmdline_mode_check output = await self.send_command(cmdline_mode_enter, pattern='\[Y\/N\]') output += await self.send_command('Y', pattern='password\:') output += await self.send_command(self._cmdline_password) logger.debug("Host {}: cmdline mode output: {}".format(self._host, repr(output))) logger.info('Host {}: Checking cmdline mode'.format(self._host)) if check_error_string in output: raise ValueError('Failed to enter to cmdline mode') return output
def _strip_command(command_string, output): """ Strip command_string from output string Cisco IOS adds backspaces into output for long commands (i.e. for commands that line wrap) """ logger.info('Stripping command') backspace_char = '\x08' # Check for line wrap (remove backspaces) if backspace_char in output: output = output.replace(backspace_char, '') output_lines = output.split("\n") new_output = output_lines[1:] return "\n".join(new_output) else: command_length = len(command_string) return output[command_length:]
async def connect(self): """ Async Connection method Using 5 functions: * _establish_connection() for connecting to device * _set_base_prompt() for finding and setting device prompt * _enable() for getting privilege exec mode * _disable_paging() for non interact output in commands * _check_multiple_mode() for checking multiple mode in ASA """ logger.info("Host {}: trying to connect to the device".format(self._host)) await self._establish_connection() await self._set_base_prompt() await self.enable_mode() await self._disable_paging() await self._check_multiple_mode() logger.info("Host {}: Has connected to the device".format(self._host))
async def _set_base_prompt(self): """ Setting two important vars base_prompt - textual prompt in CLI (usually hostname) base_pattern - regexp for finding the end of command. IT's platform specific parameter For Fujitsu devices base_pattern is "(prompt) (\(.*?\))?[>|#]" """ logger.info("Host {}: Setting base prompt".format(self._host)) prompt = await self._find_prompt() # Strip off trailing terminator self._base_prompt = prompt[1:-3] delimiters = map(re.escape, type(self)._delimiter_list) delimiters = r"|".join(delimiters) base_prompt = re.escape(self._base_prompt[:12]) pattern = type(self)._pattern self._base_pattern = pattern.format(base_prompt, delimiters) logger.debug("Host {}: Base Prompt: {}".format(self._host, self._base_prompt)) logger.debug("Host {}: Base Pattern: {}".format(self._host, self._base_pattern)) return self._base_prompt
async def _set_base_prompt(self): """ Setting two important vars * base_prompt - textual prompt in CLI (usually hostname) * base_pattern - regexp for finding the end of command. IT's platform specific parameter For Mikrotik devices base_pattern is "r"\[.*?\] (\/.*?)?\>" """ logger.info("Host {}: Setting base prompt".format(self._host)) self._base_pattern = type(self)._pattern prompt = await self._find_prompt() user = '' # Strip off trailing terminator prompt = prompt[1:-3] if '@' in prompt: prompt = prompt.split('@')[1] self._base_prompt = prompt logger.debug("Host {}: Base Prompt: {}".format(self._host, self._base_prompt)) logger.debug("Host {}: Base Pattern: {}".format(self._host, self._base_pattern)) return self._base_prompt
async def _establish_connection(self): """Establishing SSH connection to the network device""" logger.info('Host {}: Establishing connection to port {}'.format(self._host, self._port)) output = "" # initiate SSH connection fut = asyncssh.connect(**self._connect_params_dict) try: self._conn = await asyncio.wait_for(fut, self._timeout) except asyncssh.DisconnectError as e: raise DisconnectError(self._host, e.code, e.reason) except asyncio.TimeoutError: raise TimeoutError(self._host) self._stdin, self._stdout, self._stderr = await self._conn.open_session(term_type='Dumb', term_size=(200, 24)) logger.info("Host {}: Connection is established".format(self._host)) # Flush unnecessary data delimiters = map(re.escape, type(self)._delimiter_list) delimiters = r"|".join(delimiters) output = await self._read_until_pattern(delimiters) logger.debug("Host {}: Establish Connection Output: {}".format(self._host, repr(output))) return output
async def _set_base_prompt(self): """ Setting two important vars for ASA base_prompt - textual prompt in CLI (usually hostname) base_pattern - regexp for finding the end of command. IT's platform specific parameter For ASA devices base_pattern is "prompt([\/\w]+)?(\(.*?\))?[#|>] """ logger.info("Host {}: Setting base prompt".format(self._host)) prompt = await self._find_prompt() # Cut off prompt from "prompt/context/other" if it exists # If not we get all prompt prompt = prompt[:-1].split('/') prompt = prompt[0] self._base_prompt = prompt delimiters = map(re.escape, type(self)._delimiter_list) delimiters = r"|".join(delimiters) base_prompt = re.escape(self._base_prompt[:12]) pattern = type(self)._pattern self._base_pattern = pattern.format(base_prompt, delimiters) logger.debug("Host {}: Base Prompt: {}".format(self._host, self._base_prompt)) logger.debug("Host {}: Base Pattern: {}".format(self._host, self._base_pattern)) return self._base_prompt