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 send_config_set(self, config_commands=None, with_commit=True, commit_comment='', exit_config_mode=True): """ Sending configuration commands to device By default automatically exits/enters configuration mode. :param list config_commands: iterable string list with commands for applying to network devices in system view :param bool with_commit: if true it commit all changes after applying all config_commands :param string commit_comment: message for configuration commit :param bool exit_config_mode: If true it will quit from configuration mode automatically :return: The output of these commands """ if config_commands is None: return '' # Send config commands output = await self.config_mode() output += await super().send_config_set(config_commands=config_commands) if with_commit: commit = type(self)._commit_command if commit_comment: commit = type(self)._commit_comment_command.format(commit_comment) self._stdin.write(self._normalize_cmd(commit)) output += await self._read_until_prompt() if exit_config_mode: output += await self.exit_config_mode() output = self._normalize_linefeeds(output) logger.debug("Host {}: Config commands output: {}".format(self._host, repr(output))) 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 _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 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 send_config_set(self, config_commands=None, exit_config_mode=True): """ Sending configuration commands to Cisco IOS like devices Automatically exits/enters configuration mode. :param list config_commands: iterable string list with commands for applying to network devices in conf mode :param bool exit_config_mode: If true it will quit from configuration mode automatically :return: The output of this commands """ if config_commands is None: return "" # Send config commands output = await self.config_mode() output += await super().send_config_set(config_commands=config_commands ) if exit_config_mode: output += await self.exit_config_mode() output = self._normalize_linefeeds(output) logger.debug("Host {}: Config commands 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 send_config_set(self, config_commands=None, exit_system_view=False): """ Sending configuration commands to device Automatically exits/enters system-view. :param list config_commands: iterable string list with commands for applying to network devices in system view :param bool exit_system_view: If true it will quit from system view automatically :return: The output of this commands """ if config_commands is None: return '' # Send config commands output = await self._system_view() output += await super().send_config_set(config_commands=config_commands ) if exit_system_view: output += await self._exit_system_view() output = self._normalize_linefeeds(output) logger.debug("Host {}: Config commands output: {}".format( self._host, repr(output))) return 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 _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
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_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 _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
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 send_config_set( self, config_commands=None, with_commit=True, commit_comment="", exit_config_mode=True, ): """ Sending configuration commands to device By default automatically exits/enters configuration mode. :param list config_commands: iterable string list with commands for applying to network devices in system view :param bool with_commit: if true it commit all changes after applying all config_commands :param string commit_comment: message for configuration commit :param bool exit_config_mode: If true it will quit from configuration mode automatically :return: The output of these commands """ if config_commands is None: return "" # Send config commands output = await self.config_mode() output += await super(IOSLikeDevice, self).send_config_set( config_commands=config_commands ) if with_commit: commit = type(self)._commit_command if commit_comment: commit = type(self)._commit_comment_command.format(commit_comment) self._stdin.write(self._normalize_cmd(commit)) output += await self._read_until_prompt_or_pattern( r"Do you wish to proceed with this commit anyway\?" ) if "Failed to commit" in output: show_config_failed = type(self)._show_config_failed reason = await self.send_command( self._normalize_cmd(show_config_failed) ) raise CommitError(self._host, reason) if "One or more commits have occurred" in output: show_commit_changes = type(self)._show_commit_changes self._stdin.write(self._normalize_cmd("no")) reason = await self.send_command( self._normalize_cmd(show_commit_changes) ) raise CommitError(self._host, reason) if exit_config_mode: output += await self.exit_config_mode() output = self._normalize_linefeeds(output) logger.debug( "Host {}: Config commands output: {}".format(self._host, repr(output)) ) return 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 _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 _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 _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 _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 _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 _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
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
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 * 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 _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 _read_until_prompt_or_pattern(self, pattern="", re_flags=0): """Read until either self.base_pattern or pattern is detected. Return ALL data available""" output = "" logger.info("Host {}: Reading until prompt or pattern".format( self._host)) if not pattern: pattern = self._base_pattern base_prompt_pattern = self._base_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) or re.search( base_prompt_pattern, output, flags=re_flags): logger.debug( "Host {}: Reading pattern '{}' or '{}' was found: {}". format(self._host, pattern, base_prompt_pattern, repr(output))) return output
async def send_config_set( self, config_commands=None, with_commit=True, commit_comment="", exit_config_mode=True, ): """ Sending configuration commands to device By default automatically exits/enters configuration mode. :param list config_commands: iterable string list with commands for applying to network devices in system view :param bool with_commit: if true it commit all changes after applying all config_commands :param string commit_comment: message for configuration commit :param bool exit_config_mode: If true it will quit from configuration mode automatically :return: The output of these commands """ if config_commands is None: return "" # Send config commands output = await self.config_mode() output += await super().send_config_set(config_commands=config_commands) if with_commit: commit = type(self)._commit_command if commit_comment: commit = type(self)._commit_comment_command.format(commit_comment) self._stdin.write(self._normalize_cmd(commit)) output += await self._read_until_prompt() if exit_config_mode: output += await self.exit_config_mode() output = self._normalize_linefeeds(output) logger.debug( "Host {}: Config commands output: {}".format(self._host, repr(output)) ) return output
async def send_config_set(self, config_commands=None, exit_config_mode=True): """ Sending configuration commands to Cisco IOS like devices Automatically exits/enters configuration mode. :param list config_commands: iterable string list with commands for applying to network devices in conf mode :param bool exit_config_mode: If true it will quit from configuration mode automatically :return: The output of this commands """ if config_commands is None: return '' # Send config commands output = await self.config_mode() output += await super().send_config_set(config_commands=config_commands) if exit_config_mode: output += await self.exit_config_mode() 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 send_config_set(self, config_commands=None, exit_system_view=False): """ Sending configuration commands to device Automatically exits/enters system-view. :param list config_commands: iterable string list with commands for applying to network devices in system view :param bool exit_system_view: If true it will quit from system view automatically :return: The output of this commands """ if config_commands is None: return '' # Send config commands output = await self._system_view() output += await super().send_config_set(config_commands=config_commands) if exit_system_view: output += await self._exit_system_view() 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 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 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