Hello community, here is the log from the commit of package python-netmiko for openSUSE:Factory checked in at 2020-05-20 18:45:53 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-netmiko (Old) and /work/SRC/openSUSE:Factory/.python-netmiko.new.2738 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-netmiko" Wed May 20 18:45:53 2020 rev:9 rq:807425 version:3.1.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-netmiko/python-netmiko.changes 2020-03-27 21:58:41.882841635 +0100 +++ /work/SRC/openSUSE:Factory/.python-netmiko.new.2738/python-netmiko.changes 2020-05-20 18:46:22.905406255 +0200 @@ -1,0 +2,14 @@ +Tue May 19 17:17:24 UTC 2020 - Martin Hauke <[email protected]> + +- Update to version 3.1.1 + New Drivers/Platforms + * UnifiSwitchSSH + * Huawei OLT + * Huawei SmartAX + Bugs and Improvements + * Nokia SR-OS SCP Support + * Improve terminal width behavior + * Fix some issues related to cmd_verify + * Expanded autodetect support + +------------------------------------------------------------------- Old: ---- netmiko-3.1.0.tar.gz New: ---- netmiko-3.1.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-netmiko.spec ++++++ --- /var/tmp/diff_new_pack.4LLp1s/_old 2020-05-20 18:46:23.681407999 +0200 +++ /var/tmp/diff_new_pack.4LLp1s/_new 2020-05-20 18:46:23.681407999 +0200 @@ -19,7 +19,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %define skip_python2 1 Name: python-netmiko -Version: 3.1.0 +Version: 3.1.1 Release: 0 Summary: Multi-vendor library to simplify Paramiko SSH connections to network devices License: MIT @@ -30,7 +30,7 @@ BuildRequires: fdupes BuildRequires: python-rpm-macros Requires: python-PyYAML -Requires: python-paramiko >= 2.4.1 +Requires: python-paramiko >= 2.4.3 Requires: python-pyserial Requires: python-scp >= 0.13.2 Requires: python-textfsm ++++++ netmiko-3.1.0.tar.gz -> netmiko-3.1.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/PKG-INFO new/netmiko-3.1.1/PKG-INFO --- old/netmiko-3.1.0/PKG-INFO 2020-03-23 17:49:02.000000000 +0100 +++ new/netmiko-3.1.1/PKG-INFO 2020-05-19 00:25:34.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: netmiko -Version: 3.1.0 +Version: 3.1.1 Summary: Multi-vendor library to simplify Paramiko SSH connections to network devices Home-page: https://github.com/ktbyers/netmiko Author: Kirk Byers diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/PLATFORMS.md new/netmiko-3.1.1/PLATFORMS.md --- old/netmiko-3.1.0/PLATFORMS.md 2020-03-23 17:47:24.000000000 +0100 +++ new/netmiko-3.1.1/PLATFORMS.md 2020-04-30 22:03:14.000000000 +0200 @@ -29,6 +29,8 @@ - Extreme MLX/NetIron (Brocade/Foundry) - HPE Comware7 - Huawei +- Huawei OLT +- Huawei SmartAX - IP Infusion OcNOS - Juniper ScreenOS - Mellanox @@ -71,5 +73,6 @@ - QuantaMesh - Rad ETX - Sophos SFOS +- Ubiquiti Unifi Switch - Versa Networks FlexVNF - Watchguard Firebox diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/netmiko/__init__.py new/netmiko-3.1.1/netmiko/__init__.py --- old/netmiko-3.1.0/netmiko/__init__.py 2020-03-23 17:27:20.000000000 +0100 +++ new/netmiko-3.1.1/netmiko/__init__.py 2020-05-18 23:45:15.000000000 +0200 @@ -23,7 +23,7 @@ # Alternate naming Netmiko = ConnectHandler -__version__ = "3.1.0" +__version__ = "3.1.1" __all__ = ( "ConnectHandler", "ssh_dispatcher", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/netmiko/aruba/aruba_ssh.py new/netmiko-3.1.1/netmiko/aruba/aruba_ssh.py --- old/netmiko-3.1.0/netmiko/aruba/aruba_ssh.py 2020-03-20 16:58:01.000000000 +0100 +++ new/netmiko-3.1.1/netmiko/aruba/aruba_ssh.py 2020-04-30 22:03:14.000000000 +0200 @@ -10,6 +10,9 @@ def __init__(self, **kwargs): if kwargs.get("default_enter") is None: kwargs["default_enter"] = "\r" + # Aruba has an auto-complete on space behavior that is problematic + if kwargs.get("global_cmd_verify") is None: + kwargs["global_cmd_verify"] = False return super().__init__(**kwargs) def session_preparation(self): @@ -33,3 +36,9 @@ if not pattern: pattern = re.escape(self.base_prompt[:16]) return super().check_config_mode(check_string=check_string, pattern=pattern) + + def config_mode(self, config_command="configure term", pattern=""): + """ + Aruba auto completes on space so 'configure' needs fully spelled-out. + """ + return super().config_mode(config_command=config_command, pattern=pattern) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/netmiko/base_connection.py new/netmiko-3.1.1/netmiko/base_connection.py --- old/netmiko-3.1.0/netmiko/base_connection.py 2020-03-20 16:58:01.000000000 +0100 +++ new/netmiko-3.1.1/netmiko/base_connection.py 2020-04-30 22:03:14.000000000 +0200 @@ -870,18 +870,16 @@ output = self.strip_prompt(output) return output - def establish_connection(self, width=None, height=None): + def establish_connection(self, width=511, height=1000): """Establish SSH connection to the network device Timeout will generate a NetmikoTimeoutException Authentication failure will generate a NetmikoAuthenticationException - width and height are needed for Fortinet paging setting. - - :param width: Specified width of the VT100 terminal window + :param width: Specified width of the VT100 terminal window (default: 511) :type width: int - :param height: Specified height of the VT100 terminal window + :param height: Specified height of the VT100 terminal window (default: 1000) :type height: int """ if self.protocol == "telnet": @@ -917,12 +915,9 @@ print(f"SSH connection established to {self.host}:{self.port}") # Use invoke_shell to establish an 'interactive session' - if width and height: - self.remote_conn = self.remote_conn_pre.invoke_shell( - term="vt100", width=width, height=height - ) - else: - self.remote_conn = self.remote_conn_pre.invoke_shell() + self.remote_conn = self.remote_conn_pre.invoke_shell( + term="vt100", width=width, height=height + ) self.remote_conn.settimeout(self.blocking_timeout) if self.keepalive: @@ -1028,7 +1023,10 @@ log.debug(f"Command: {command}") self.write_channel(command) # Make sure you read until you detect the command echo (avoid getting out of sync) - output = self.read_until_pattern(pattern=re.escape(command.strip())) + if self.global_cmd_verify is not False: + output = self.read_until_pattern(pattern=re.escape(command.strip())) + else: + output = self.read_until_prompt() log.debug(f"{output}") log.debug("Exiting disable_paging") return output @@ -1051,7 +1049,10 @@ command = self.normalize_cmd(command) self.write_channel(command) # Make sure you read until you detect the command echo (avoid getting out of sync) - output = self.read_until_pattern(pattern=re.escape(command.strip())) + if self.global_cmd_verify is not False: + output = self.read_until_pattern(pattern=re.escape(command.strip())) + else: + output = self.read_until_prompt() return output def set_base_prompt( @@ -1618,7 +1619,10 @@ if not self.check_config_mode(): self.write_channel(self.normalize_cmd(config_command)) # Make sure you read until you detect the command echo (avoid getting out of sync) - output += self.read_until_pattern(pattern=re.escape(config_command.strip())) + if self.global_cmd_verify is not False: + output += self.read_until_pattern( + pattern=re.escape(config_command.strip()) + ) if not re.search(pattern, output, flags=re.M): output += self.read_until_pattern(pattern=pattern) if not self.check_config_mode(): @@ -1638,7 +1642,10 @@ if self.check_config_mode(): self.write_channel(self.normalize_cmd(exit_config)) # Make sure you read until you detect the command echo (avoid getting out of sync) - output += self.read_until_pattern(pattern=re.escape(exit_config.strip())) + if self.global_cmd_verify is not False: + output += self.read_until_pattern( + pattern=re.escape(exit_config.strip()) + ) if not re.search(pattern, output, flags=re.M): output += self.read_until_pattern(pattern=pattern) if self.check_config_mode(): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/netmiko/cisco/cisco_asa_ssh.py new/netmiko-3.1.1/netmiko/cisco/cisco_asa_ssh.py --- old/netmiko-3.1.0/netmiko/cisco/cisco_asa_ssh.py 2020-03-20 16:58:01.000000000 +0100 +++ new/netmiko-3.1.1/netmiko/cisco/cisco_asa_ssh.py 2020-04-30 22:03:14.000000000 +0200 @@ -22,6 +22,9 @@ except ValueError: # Don't fail for the terminal width pass + else: + # Disable cmd_verify if the terminal width can't be set + self.global_cmd_verify = False # Clear the read buffer time.sleep(0.3 * self.global_delay_factor) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/netmiko/cisco/cisco_nxos_ssh.py new/netmiko-3.1.1/netmiko/cisco/cisco_nxos_ssh.py --- old/netmiko-3.1.0/netmiko/cisco/cisco_nxos_ssh.py 2020-03-20 16:58:01.000000000 +0100 +++ new/netmiko-3.1.1/netmiko/cisco/cisco_nxos_ssh.py 2020-05-18 18:17:43.000000000 +0200 @@ -89,6 +89,8 @@ remote_cmd = f"dir {self.file_system}/{remote_file}" remote_out = self.ssh_ctl_chan.send_command(remote_cmd) + if re.search("no such file or directory", remote_out, flags=re.I): + raise IOError("Unable to find file on remote system") # Match line containing file name escape_file_name = re.escape(remote_file) pattern = r".*({}).*".format(escape_file_name) @@ -96,12 +98,10 @@ if match: file_size = match.group(0) file_size = file_size.split()[0] - - if "No such file or directory" in remote_out: - raise IOError("Unable to find file on remote system") - else: return int(file_size) + raise IOError("Unable to find file on remote system") + @staticmethod def process_md5(md5_output, pattern=r"= (.*)"): """Not needed on NX-OS.""" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/netmiko/huawei/__init__.py new/netmiko-3.1.1/netmiko/huawei/__init__.py --- old/netmiko-3.1.0/netmiko/huawei/__init__.py 2019-12-11 19:37:51.000000000 +0100 +++ new/netmiko-3.1.1/netmiko/huawei/__init__.py 2020-04-30 22:03:14.000000000 +0200 @@ -1,4 +1,5 @@ from netmiko.huawei.huawei import HuaweiSSH, HuaweiVrpv8SSH from netmiko.huawei.huawei import HuaweiTelnet +from netmiko.huawei.huawei_smartax import HuaweiSmartAXSSH -__all__ = ["HuaweiSSH", "HuaweiVrpv8SSH", "HuaweiTelnet"] +__all__ = ["HuaweiSmartAXSSH", "HuaweiSSH", "HuaweiVrpv8SSH", "HuaweiTelnet"] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/netmiko/huawei/huawei.py new/netmiko-3.1.1/netmiko/huawei/huawei.py --- old/netmiko-3.1.0/netmiko/huawei/huawei.py 2020-03-20 16:58:01.000000000 +0100 +++ new/netmiko-3.1.1/netmiko/huawei/huawei.py 2020-04-30 22:03:14.000000000 +0200 @@ -111,8 +111,9 @@ def special_login_handler(self): """Handle password change request by ignoring it""" - password_change_prompt = r"(Change now|Please choose 'YES' or 'NO').+" - output = self.read_until_prompt_or_pattern(password_change_prompt) + # Huawei can prompt for password change. Search for that or for normal prompt + password_change_prompt = r"((Change now|Please choose))|([\]>]\s*$)" + output = self.read_until_pattern(password_change_prompt) if re.search(password_change_prompt, output): self.write_channel("N\n") self.clear_buffer() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/netmiko/huawei/huawei_smartax.py new/netmiko-3.1.1/netmiko/huawei/huawei_smartax.py --- old/netmiko-3.1.0/netmiko/huawei/huawei_smartax.py 1970-01-01 01:00:00.000000000 +0100 +++ new/netmiko-3.1.1/netmiko/huawei/huawei_smartax.py 2020-04-30 22:03:14.000000000 +0200 @@ -0,0 +1,82 @@ +import time +import re +from netmiko.cisco_base_connection import CiscoBaseConnection +from netmiko import log + + +class HuaweiSmartAXSSH(CiscoBaseConnection): + """Supports Huawei SmartAX and OLT.""" + + def session_preparation(self): + """Prepare the session after the connection has been established.""" + self.ansi_escape_codes = True + self._test_channel_read() + self.set_base_prompt() + self._disable_smart_interaction() + self.disable_paging() + # Clear the read buffer + time.sleep(0.3 * self.global_delay_factor) + self.clear_buffer() + + def strip_ansi_escape_codes(self, string_buffer): + """ + Huawei does a strange thing where they add a space and then add ESC[1D + to move the cursor to the left one. + The extra space is problematic. + """ + code_cursor_left = chr(27) + r"\[\d+D" + output = string_buffer + pattern = rf" {code_cursor_left}" + output = re.sub(pattern, "", output) + + log.debug("Stripping ANSI escape codes") + log.debug(f"new_output = {output}") + log.debug(f"repr = {repr(output)}") + return super().strip_ansi_escape_codes(output) + + def _disable_smart_interaction(self, command="undo smart", delay_factor=1): + """Disables the { <cr> } prompt to avoid having to sent a 2nd return after each command""" + delay_factor = self.select_delay_factor(delay_factor) + time.sleep(delay_factor * 0.1) + self.clear_buffer() + command = self.normalize_cmd(command) + log.debug("In disable_smart_interaction") + log.debug(f"Command: {command}") + self.write_channel(command) + if self.global_cmd_verify is not False: + output = self.read_until_pattern(pattern=re.escape(command.strip())) + else: + output = self.read_until_prompt() + log.debug(f"{output}") + log.debug("Exiting disable_smart_interaction") + + def disable_paging(self, command="scroll"): + return super().disable_paging(command=command) + + def config_mode(self, config_command="config", pattern=""): + """Enter configuration mode.""" + return super().config_mode(config_command=config_command, pattern=pattern) + + def check_config_mode(self, check_string=")#"): + return super().check_config_mode(check_string=check_string) + + def exit_config_mode(self, exit_config="return"): + return super().exit_config_mode(exit_config=exit_config) + + def check_enable_mode(self, check_string="#"): + return super().check_enable_mode(check_string=check_string) + + def enable(self, cmd="enable", pattern="", re_flags=re.IGNORECASE): + return super().enable(cmd=cmd, pattern=pattern, re_flags=re_flags) + + def set_base_prompt(self, pri_prompt_terminator=">", alt_prompt_terminator="#"): + return super().set_base_prompt( + pri_prompt_terminator=pri_prompt_terminator, + alt_prompt_terminator=alt_prompt_terminator, + ) + + def save_config(self, cmd="save", confirm=False, confirm_response=""): + """ Save Config for HuaweiSSH""" + return super().save_config( + cmd=cmd, confirm=confirm, confirm_response=confirm_response + ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/netmiko/nokia/__init__.py new/netmiko-3.1.1/netmiko/nokia/__init__.py --- old/netmiko-3.1.0/netmiko/nokia/__init__.py 2020-03-20 16:58:01.000000000 +0100 +++ new/netmiko-3.1.1/netmiko/nokia/__init__.py 2020-05-11 18:23:42.000000000 +0200 @@ -1,3 +1,3 @@ -from netmiko.nokia.nokia_sros_ssh import NokiaSrosSSH +from netmiko.nokia.nokia_sros_ssh import NokiaSrosSSH, NokiaSrosFileTransfer -__all__ = ["NokiaSrosSSH"] +__all__ = ["NokiaSrosSSH", "NokiaSrosFileTransfer"] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/netmiko/nokia/nokia_sros_ssh.py new/netmiko-3.1.1/netmiko/nokia/nokia_sros_ssh.py --- old/netmiko-3.1.0/netmiko/nokia/nokia_sros_ssh.py 2020-03-20 16:58:01.000000000 +0100 +++ new/netmiko-3.1.1/netmiko/nokia/nokia_sros_ssh.py 2020-05-11 18:23:42.000000000 +0200 @@ -7,10 +7,12 @@ # https://github.com/ktbyers/netmiko/blob/develop/LICENSE import re +import os import time from netmiko import log from netmiko.base_connection import BaseConnection +from netmiko.scp_handler import BaseFileTransfer class NokiaSrosSSH(BaseConnection): @@ -39,6 +41,8 @@ # "@" indicates model-driven CLI (vs Classical CLI) if "@" in self.base_prompt: self.disable_paging(command="environment more false") + # To perform file operations we need to disable paging in classical-CLI also + self.disable_paging(command="//environment no more") self.set_terminal_width(command="environment console width 512") else: self.disable_paging(command="environment no more") @@ -89,7 +93,10 @@ output += self._discard() cmd = "quit-config" self.write_channel(self.normalize_cmd(cmd)) - output += self.read_until_pattern(pattern=re.escape(cmd)) + if self.global_cmd_verify is not False: + output += self.read_until_pattern(pattern=re.escape(cmd)) + else: + output += self.read_until_prompt() if self.check_config_mode(): raise ValueError("Failed to exit configuration mode") return output @@ -124,16 +131,25 @@ log.info("Apply uncommitted changes!") cmd = "commit" self.write_channel(self.normalize_cmd(cmd)) - output += self.read_until_pattern(pattern=re.escape(cmd)) - output += self.read_until_pattern(r"@") + new_output = "" + if self.global_cmd_verify is not False: + new_output += self.read_until_pattern(pattern=re.escape(cmd)) + if "@" not in new_output: + new_output += self.read_until_pattern(r"@") + output += new_output return output def _exit_all(self): """Return to the 'root' context.""" + output = "" exit_cmd = "exit all" self.write_channel(self.normalize_cmd(exit_cmd)) # Make sure you read until you detect the command echo (avoid getting out of sync) - return self.read_until_pattern(pattern=re.escape(exit_cmd)) + if self.global_cmd_verify is not False: + output += self.read_until_pattern(pattern=re.escape(exit_cmd)) + else: + output += self.read_until_prompt() + return output def _discard(self): """Discard changes from private candidate for Nokia SR OS""" @@ -141,7 +157,9 @@ if "@" in self.base_prompt: cmd = "discard" self.write_channel(self.normalize_cmd(cmd)) - new_output = self.read_until_pattern(pattern=re.escape(cmd)) + new_output = "" + if self.global_cmd_verify is not False: + new_output += self.read_until_pattern(pattern=re.escape(cmd)) if "@" not in new_output: new_output += self.read_until_prompt() output += new_output @@ -168,3 +186,102 @@ # Always try to send final 'logout'. self._session_log_fin = True self.write_channel(command + self.RETURN) + + +class NokiaSrosFileTransfer(BaseFileTransfer): + def __init__( + self, ssh_conn, source_file, dest_file, hash_supported=False, **kwargs + ): + super().__init__( + ssh_conn, source_file, dest_file, hash_supported=hash_supported, **kwargs + ) + + def _file_cmd_prefix(self): + """ + Allow MD-CLI to execute file operations by using classical CLI. + + Returns "//" if the current prompt is MD-CLI (empty string otherwise). + """ + return "//" if "@" in self.ssh_ctl_chan.base_prompt else "" + + def remote_space_available(self, search_pattern=r"(\d+)\s+\w+\s+free"): + """Return space available on remote device.""" + + # Sample text for search_pattern. + # " 3 Dir(s) 961531904 bytes free." + remote_cmd = self._file_cmd_prefix() + "file dir {}".format(self.file_system) + remote_output = self.ssh_ctl_chan.send_command(remote_cmd) + match = re.search(search_pattern, remote_output) + return int(match.group(1)) + + def check_file_exists(self, remote_cmd=""): + """Check if destination file exists (returns boolean).""" + + if self.direction == "put": + if not remote_cmd: + remote_cmd = self._file_cmd_prefix() + "file dir {}/{}".format( + self.file_system, self.dest_file + ) + dest_file_name = self.dest_file.replace("\\", "/").split("/")[-1] + remote_out = self.ssh_ctl_chan.send_command(remote_cmd) + if "File Not Found" in remote_out: + return False + elif dest_file_name in remote_out: + return True + else: + raise ValueError("Unexpected output from check_file_exists") + elif self.direction == "get": + return os.path.exists(self.dest_file) + + def remote_file_size(self, remote_cmd=None, remote_file=None): + """Get the file size of the remote file.""" + + if remote_file is None: + if self.direction == "put": + remote_file = self.dest_file + elif self.direction == "get": + remote_file = self.source_file + if not remote_cmd: + remote_cmd = self._file_cmd_prefix() + "file dir {}/{}".format( + self.file_system, remote_file + ) + remote_out = self.ssh_ctl_chan.send_command(remote_cmd) + + if "File Not Found" in remote_out: + raise IOError("Unable to find file on remote system") + + # Parse dir output for filename. Output format is: + # "10/16/2019 10:00p 6738 {filename}" + + pattern = r"\S+\s+\S+\s+(\d+)\s+{}".format(re.escape(remote_file)) + match = re.search(pattern, remote_out) + + if not match: + raise ValueError("Filename entry not found in dir output") + + file_size = int(match.group(1)) + return file_size + + def verify_file(self): + """Verify the file has been transferred correctly based on filesize.""" + if self.direction == "put": + return os.stat(self.source_file).st_size == self.remote_file_size( + remote_file=self.dest_file + ) + elif self.direction == "get": + return ( + self.remote_file_size(remote_file=self.source_file) + == os.stat(self.dest_file).st_size + ) + + def file_md5(self, **kwargs): + raise AttributeError("SR-OS does not support an MD5-hash operation.") + + def process_md5(self, **kwargs): + raise AttributeError("SR-OS does not support an MD5-hash operation.") + + def compare_md5(self, **kwargs): + raise AttributeError("SR-OS does not support an MD5-hash operation.") + + def remote_md5(self, **kwargs): + raise AttributeError("SR-OS does not support an MD5-hash operation.") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/netmiko/scp_functions.py new/netmiko-3.1.1/netmiko/scp_functions.py --- old/netmiko-3.1.0/netmiko/scp_functions.py 2020-03-20 16:58:01.000000000 +0100 +++ new/netmiko-3.1.1/netmiko/scp_functions.py 2020-05-11 18:23:42.000000000 +0200 @@ -27,6 +27,7 @@ inline_transfer=False, overwrite_file=False, socket_timeout=10.0, + verify_file=None, ): """Use Secure Copy or Inline (IOS-only) to transfer files to/from network devices. @@ -61,6 +62,10 @@ if not cisco_ios and inline_transfer: raise ValueError("Inline Transfer only supported for Cisco IOS/Cisco IOS-XE") + # Replace disable_md5 argument with verify_file argument across time + if verify_file is None: + verify_file = not disable_md5 + scp_args = { "ssh_conn": ssh_conn, "source_file": source_file, @@ -76,13 +81,13 @@ with TransferClass(**scp_args) as scp_transfer: if scp_transfer.check_file_exists(): if overwrite_file: - if not disable_md5: - if scp_transfer.compare_md5(): + if verify_file: + if scp_transfer.verify_file(): return nottransferred_but_verified else: # File exists, you can overwrite it, MD5 is wrong (transfer file) verifyspace_and_transferfile(scp_transfer) - if scp_transfer.compare_md5(): + if scp_transfer.verify_file(): return transferred_and_verified else: raise ValueError( @@ -94,16 +99,16 @@ return transferred_and_notverified else: # File exists, but you can't overwrite it. - if not disable_md5: - if scp_transfer.compare_md5(): + if verify_file: + if scp_transfer.verify_file(): return nottransferred_but_verified msg = "File already exists and overwrite_file is disabled" raise ValueError(msg) else: verifyspace_and_transferfile(scp_transfer) # File doesn't exist - if not disable_md5: - if scp_transfer.compare_md5(): + if verify_file: + if scp_transfer.verify_file(): return transferred_and_verified else: raise ValueError("MD5 failure between source and destination files") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/netmiko/scp_handler.py new/netmiko-3.1.1/netmiko/scp_handler.py --- old/netmiko-3.1.0/netmiko/scp_handler.py 2020-03-20 16:58:01.000000000 +0100 +++ new/netmiko-3.1.1/netmiko/scp_handler.py 2020-05-11 18:23:42.000000000 +0200 @@ -64,6 +64,7 @@ file_system=None, direction="put", socket_timeout=10.0, + hash_supported=True, ): self.ssh_ctl_chan = ssh_conn self.source_file = source_file @@ -85,10 +86,12 @@ self.file_system = file_system if direction == "put": - self.source_md5 = self.file_md5(source_file) + self.source_md5 = self.file_md5(source_file) if hash_supported else None self.file_size = os.stat(source_file).st_size elif direction == "get": - self.source_md5 = self.remote_md5(remote_file=source_file) + self.source_md5 = ( + self.remote_md5(remote_file=source_file) if hash_supported else None + ) self.file_size = self.remote_file_size(remote_file=source_file) else: raise ValueError("Invalid direction specified") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/netmiko/ssh_autodetect.py new/netmiko-3.1.1/netmiko/ssh_autodetect.py --- old/netmiko-3.1.0/netmiko/ssh_autodetect.py 2020-03-23 17:10:22.000000000 +0100 +++ new/netmiko-3.1.1/netmiko/ssh_autodetect.py 2020-05-18 18:17:43.000000000 +0200 @@ -105,12 +105,27 @@ "priority": 99, "dispatch": "_autodetect_std", }, + "dell_os9": { + "cmd": "show system", + "search_patterns": [ + r"Dell Application Software Version: 9", + r"Dell Networking OS Version : 9", + ], + "priority": 99, + "dispatch": "_autodetect_std", + }, "dell_os10": { "cmd": "show version", "search_patterns": [r"Dell EMC Networking OS10-Enterprise"], "priority": 99, "dispatch": "_autodetect_std", }, + "dell_powerconnect": { + "cmd": "show system", + "search_patterns": [r"PowerConnect"], + "priority": 99, + "dispatch": "_autodetect_std", + }, "f5_tmsh": { "cmd": "show sys version", "search_patterns": [r"BIG-IP"], @@ -167,6 +182,17 @@ "priority": 99, "dispatch": "_autodetect_std", }, + "cisco_wlc": { + "dispatch": "_autodetect_remote_version", + "search_patterns": [r"CISCO_WLC"], + "priority": 99, + }, + "mellanox_mlnxos": { + "cmd": "show version", + "search_patterns": [r"Onyx", r"SX_PPC_M460EX"], + "priority": 99, + "dispatch": "_autodetect_std", + }, } @@ -288,7 +314,45 @@ else: return cached_results - def _autodetect_std(self, cmd="", search_patterns=None, re_flags=re.I, priority=99): + def _autodetect_remote_version( + self, search_patterns=None, re_flags=re.IGNORECASE, priority=99 + ): + """ + Method to try auto-detect the device type, by matching a regular expression on the reported + remote version of the SSH server. + + Parameters + ---------- + search_patterns : list + A list of regular expression to look for in the reported remote SSH version + (default: None). + re_flags: re.flags, optional + Any flags from the python re module to modify the regular expression (default: re.I). + priority: int, optional + The confidence the match is right between 0 and 99 (default: 99). + """ + invalid_responses = [r"^$"] + + if not search_patterns: + return 0 + + try: + remote_version = self.connection.remote_conn.transport.remote_version + for pattern in invalid_responses: + match = re.search(pattern, remote_version, flags=re.I) + if match: + return 0 + for pattern in search_patterns: + match = re.search(pattern, remote_version, flags=re_flags) + if match: + return priority + except Exception: + return 0 + return 0 + + def _autodetect_std( + self, cmd="", search_patterns=None, re_flags=re.IGNORECASE, priority=99 + ): """ Standard method to try to auto-detect the device type. This method will be called for each device_type present in SSH_MAPPER_BASE dict ('dispatch' key). It will attempt to send a diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/netmiko/ssh_dispatcher.py new/netmiko-3.1.1/netmiko/ssh_dispatcher.py --- old/netmiko-3.1.0/netmiko/ssh_dispatcher.py 2020-03-22 23:23:29.000000000 +0100 +++ new/netmiko-3.1.1/netmiko/ssh_dispatcher.py 2020-05-11 18:23:42.000000000 +0200 @@ -50,6 +50,7 @@ from netmiko.fortinet import FortinetSSH from netmiko.hp import HPProcurveSSH, HPProcurveTelnet, HPComwareSSH, HPComwareTelnet from netmiko.huawei import HuaweiSSH, HuaweiVrpv8SSH, HuaweiTelnet +from netmiko.huawei import HuaweiSmartAXSSH from netmiko.ipinfusion import IpInfusionOcNOSSSH, IpInfusionOcNOSTelnet from netmiko.juniper import JuniperSSH, JuniperTelnet, JuniperScreenOsSSH from netmiko.juniper import JuniperFileTransfer @@ -61,7 +62,7 @@ from netmiko.mrv import MrvLxSSH from netmiko.mrv import MrvOptiswitchSSH from netmiko.netapp import NetAppcDotSSH -from netmiko.nokia import NokiaSrosSSH +from netmiko.nokia import NokiaSrosSSH, NokiaSrosFileTransfer from netmiko.oneaccess import OneaccessOneOSTelnet, OneaccessOneOSSSH from netmiko.ovs import OvsLinuxSSH from netmiko.paloalto import PaloAltoPanosSSH @@ -77,6 +78,7 @@ from netmiko.terminal_server import TerminalServerSSH from netmiko.terminal_server import TerminalServerTelnet from netmiko.ubiquiti import UbiquitiEdgeSSH +from netmiko.ubiquiti import UbiquitiUnifiSwitchSSH from netmiko.vyos import VyOSSSH from netmiko.watchguard import WatchguardFirewareSSH @@ -140,6 +142,8 @@ "hp_comware": HPComwareSSH, "hp_procurve": HPProcurveSSH, "huawei": HuaweiSSH, + "huawei_smartax": HuaweiSmartAXSSH, + "huawei_olt": HuaweiSmartAXSSH, "huawei_vrpv8": HuaweiVrpv8SSH, "ipinfusion_ocnos": IpInfusionOcNOSSSH, "juniper": JuniperSSH, @@ -168,6 +172,7 @@ "sophos_sfos": SophosSfosSSH, "ubiquiti_edge": UbiquitiEdgeSSH, "ubiquiti_edgeswitch": UbiquitiEdgeSSH, + "ubiquiti_unifiswitch": UbiquitiUnifiSwitchSSH, "vyatta_vyos": VyOSSSH, "vyos": VyOSSSH, "watchguard_fireware": WatchguardFirewareSSH, @@ -184,6 +189,7 @@ "dell_os10": DellOS10FileTransfer, "juniper_junos": JuniperFileTransfer, "linux": LinuxFileTransfer, + "nokia_sros": NokiaSrosFileTransfer, } # Also support keys that end in _ssh @@ -220,6 +226,7 @@ CLASS_MAPPER["hp_procurve_telnet"] = HPProcurveTelnet CLASS_MAPPER["hp_comware_telnet"] = HPComwareTelnet CLASS_MAPPER["huawei_telnet"] = HuaweiTelnet +CLASS_MAPPER["huawei_olt_telnet"] = HuaweiSmartAXSSH CLASS_MAPPER["ipinfusion_ocnos_telnet"] = IpInfusionOcNOSTelnet CLASS_MAPPER["juniper_junos_telnet"] = JuniperTelnet CLASS_MAPPER["paloalto_panos_telnet"] = PaloAltoPanosTelnet diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/netmiko/ubiquiti/__init__.py new/netmiko-3.1.1/netmiko/ubiquiti/__init__.py --- old/netmiko-3.1.0/netmiko/ubiquiti/__init__.py 2019-12-11 19:37:51.000000000 +0100 +++ new/netmiko-3.1.1/netmiko/ubiquiti/__init__.py 2020-04-30 22:03:14.000000000 +0200 @@ -1,3 +1,4 @@ from netmiko.ubiquiti.edge_ssh import UbiquitiEdgeSSH +from netmiko.ubiquiti.unifiswitch_ssh import UbiquitiUnifiSwitchSSH -__all__ = ["UbiquitiEdgeSSH"] +__all__ = ["UbiquitiEdgeSSH", "UnifiSwitchSSH", "UbiquitiUnifiSwitchSSH"] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/netmiko/ubiquiti/unifiswitch_ssh.py new/netmiko-3.1.1/netmiko/ubiquiti/unifiswitch_ssh.py --- old/netmiko-3.1.0/netmiko/ubiquiti/unifiswitch_ssh.py 1970-01-01 01:00:00.000000000 +0100 +++ new/netmiko-3.1.1/netmiko/ubiquiti/unifiswitch_ssh.py 2020-04-30 22:03:14.000000000 +0200 @@ -0,0 +1,40 @@ +import time +from netmiko.ubiquiti.edge_ssh import UbiquitiEdgeSSH + + +class UbiquitiUnifiSwitchSSH(UbiquitiEdgeSSH): + def session_preparation(self): + """ + Prepare the session after the connection has been established. + When SSHing to a UniFi switch, the session initially starts at a Linux + shell. Nothing interesting can be done in this environment, however, + running `telnet localhost` drops the session to a more familiar + environment. + """ + + self._test_channel_read() + self.set_base_prompt() + self.send_command( + command_string="telnet localhost", expect_string=r"\(UBNT\) >" + ) + self.set_base_prompt() + self.enable() + self.disable_paging() + + # Clear read buffer + time.sleep(0.3 * self.global_delay_factor) + self.clear_buffer() + + def cleanup(self, command="exit"): + """Gracefully exit the SSH session.""" + try: + # The pattern="" forces use of send_command_timing + if self.check_config_mode(pattern=""): + self.exit_config_mode() + + # Exit from the first 'telnet localhost' + self.write_channel(command + self.RETURN) + except Exception: + pass + + super().cleanup() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/netmiko/vyos/vyos_ssh.py new/netmiko-3.1.1/netmiko/vyos/vyos_ssh.py --- old/netmiko-3.1.0/netmiko/vyos/vyos_ssh.py 2020-03-20 16:58:01.000000000 +0100 +++ new/netmiko-3.1.1/netmiko/vyos/vyos_ssh.py 2020-04-30 22:03:14.000000000 +0200 @@ -10,6 +10,7 @@ self._test_channel_read() self.set_base_prompt() self.disable_paging(command="set terminal length 0") + self.set_terminal_width(command="set terminal width 512") # Clear the read buffer time.sleep(0.3 * self.global_delay_factor) self.clear_buffer() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/netmiko.egg-info/PKG-INFO new/netmiko-3.1.1/netmiko.egg-info/PKG-INFO --- old/netmiko-3.1.0/netmiko.egg-info/PKG-INFO 2020-03-23 17:49:02.000000000 +0100 +++ new/netmiko-3.1.1/netmiko.egg-info/PKG-INFO 2020-05-19 00:25:34.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: netmiko -Version: 3.1.0 +Version: 3.1.1 Summary: Multi-vendor library to simplify Paramiko SSH connections to network devices Home-page: https://github.com/ktbyers/netmiko Author: Kirk Byers diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/netmiko.egg-info/SOURCES.txt new/netmiko-3.1.1/netmiko.egg-info/SOURCES.txt --- old/netmiko-3.1.0/netmiko.egg-info/SOURCES.txt 2020-03-23 17:49:02.000000000 +0100 +++ new/netmiko-3.1.1/netmiko.egg-info/SOURCES.txt 2020-05-19 00:25:34.000000000 +0200 @@ -95,6 +95,7 @@ netmiko/hp/hp_procurve.py netmiko/huawei/__init__.py netmiko/huawei/huawei.py +netmiko/huawei/huawei_smartax.py netmiko/ipinfusion/__init__.py netmiko/ipinfusion/ipinfusion_ocnos.py netmiko/juniper/__init__.py @@ -138,6 +139,7 @@ netmiko/terminal_server/terminal_server.py netmiko/ubiquiti/__init__.py netmiko/ubiquiti/edge_ssh.py +netmiko/ubiquiti/unifiswitch_ssh.py netmiko/vyos/__init__.py netmiko/vyos/vyos_ssh.py netmiko/watchguard/__init__.py @@ -173,6 +175,7 @@ tests/test_hp_comware.sh tests/test_hp_comware_telnet.sh tests/test_hp_telnet.sh +tests/test_huawei_smartax.sh tests/test_import_netmiko.py tests/test_iosxe.sh tests/test_iosxr.sh @@ -199,7 +202,9 @@ tests/test_suite_alt.sh tests/test_suite_tmp.sh tests/test_ubiquiti_edgeswitch.sh +tests/test_ubiquiti_unifi.sh tests/test_utils.py +tests/testx.txt tests/SLOG/cisco881_slog.log tests/SLOG/cisco881_slog_append.log tests/SLOG/cisco881_slog_append_compare.log @@ -208,12 +213,15 @@ tests/SLOG/cisco881_slog_wr_compare.log tests/__pycache__/__init__.cpython-36-pytest-5.1.2.pyc tests/__pycache__/__init__.cpython-36-pytest-5.2.1.pyc +tests/__pycache__/__init__.cpython-36-pytest-5.4.1.pyc tests/__pycache__/__init__.cpython-36.pyc tests/__pycache__/conftest.cpython-36-PYTEST.pyc tests/__pycache__/conftest.cpython-36-pytest-5.1.2.pyc tests/__pycache__/conftest.cpython-36-pytest-5.2.1.pyc +tests/__pycache__/conftest.cpython-36-pytest-5.4.1.pyc tests/__pycache__/mock_device.cpython-36.pyc tests/__pycache__/test_import_netmiko.cpython-36-PYTEST.pyc +tests/__pycache__/test_import_netmiko.cpython-36-pytest-5.1.2.pyc tests/__pycache__/test_import_netmiko.cpython-36-pytest-5.2.1.pyc tests/__pycache__/test_mock_netmiko_show.cpython-36-PYTEST.pyc tests/__pycache__/test_netmiko_autodetect.cpython-36-PYTEST.pyc @@ -231,6 +239,7 @@ tests/__pycache__/test_netmiko_scp.cpython-36-PYTEST.pyc tests/__pycache__/test_netmiko_scp.cpython-36-pytest-5.1.2.pyc tests/__pycache__/test_netmiko_scp.cpython-36-pytest-5.2.1.pyc +tests/__pycache__/test_netmiko_scp.cpython-36-pytest-5.4.1.pyc tests/__pycache__/test_netmiko_session_log.cpython-36-PYTEST.pyc tests/__pycache__/test_netmiko_session_log.cpython-36-pytest-5.1.2.pyc tests/__pycache__/test_netmiko_session_log.cpython-36-pytest-5.2.1.pyc @@ -238,12 +247,14 @@ tests/__pycache__/test_netmiko_show.cpython-36-PYTEST.pyc tests/__pycache__/test_netmiko_show.cpython-36-pytest-5.1.2.pyc tests/__pycache__/test_netmiko_show.cpython-36-pytest-5.2.1.pyc +tests/__pycache__/test_netmiko_show.cpython-36-pytest-5.4.1.pyc tests/__pycache__/test_netmiko_tcl.cpython-36-PYTEST.pyc tests/__pycache__/test_netmiko_tcl.cpython-36-pytest-5.1.2.pyc tests/__pycache__/test_netmiko_tcl.cpython-36-pytest-5.2.1.pyc tests/__pycache__/test_utils.cpython-36-PYTEST.pyc tests/__pycache__/test_utils.cpython-36-pytest-5.1.2.pyc tests/__pycache__/test_utils.cpython-36-pytest-5.2.1.pyc +tests/__pycache__/test_utils.cpython-36-pytest-5.4.1.pyc tests/etc/.netmiko.yml tests/etc/cisco_ios_show_version.template tests/etc/commands.yml @@ -261,9 +272,12 @@ tests/unit/__init__.py tests/unit/test_base_connection.py tests/unit/test_utilities.py +tests/unit/__pycache__/__init__.cpython-36-pytest-5.1.2.pyc tests/unit/__pycache__/__init__.cpython-36-pytest-5.2.1.pyc tests/unit/__pycache__/__init__.cpython-36.pyc tests/unit/__pycache__/test_base_connection.cpython-36-PYTEST.pyc +tests/unit/__pycache__/test_base_connection.cpython-36-pytest-5.1.2.pyc tests/unit/__pycache__/test_base_connection.cpython-36-pytest-5.2.1.pyc tests/unit/__pycache__/test_utilities.cpython-36-PYTEST.pyc +tests/unit/__pycache__/test_utilities.cpython-36-pytest-5.1.2.pyc tests/unit/__pycache__/test_utilities.cpython-36-pytest-5.2.1.pyc \ No newline at end of file Binary files old/netmiko-3.1.0/tests/__pycache__/__init__.cpython-36-pytest-5.4.1.pyc and new/netmiko-3.1.1/tests/__pycache__/__init__.cpython-36-pytest-5.4.1.pyc differ Binary files old/netmiko-3.1.0/tests/__pycache__/conftest.cpython-36-pytest-5.1.2.pyc and new/netmiko-3.1.1/tests/__pycache__/conftest.cpython-36-pytest-5.1.2.pyc differ Binary files old/netmiko-3.1.0/tests/__pycache__/conftest.cpython-36-pytest-5.4.1.pyc and new/netmiko-3.1.1/tests/__pycache__/conftest.cpython-36-pytest-5.4.1.pyc differ Binary files old/netmiko-3.1.0/tests/__pycache__/test_import_netmiko.cpython-36-pytest-5.1.2.pyc and new/netmiko-3.1.1/tests/__pycache__/test_import_netmiko.cpython-36-pytest-5.1.2.pyc differ Binary files old/netmiko-3.1.0/tests/__pycache__/test_netmiko_autodetect.cpython-36-pytest-5.1.2.pyc and new/netmiko-3.1.1/tests/__pycache__/test_netmiko_autodetect.cpython-36-pytest-5.1.2.pyc differ Binary files old/netmiko-3.1.0/tests/__pycache__/test_netmiko_commit.cpython-36-pytest-5.1.2.pyc and new/netmiko-3.1.1/tests/__pycache__/test_netmiko_commit.cpython-36-pytest-5.1.2.pyc differ Binary files old/netmiko-3.1.0/tests/__pycache__/test_netmiko_config.cpython-36-pytest-5.1.2.pyc and new/netmiko-3.1.1/tests/__pycache__/test_netmiko_config.cpython-36-pytest-5.1.2.pyc differ Binary files old/netmiko-3.1.0/tests/__pycache__/test_netmiko_config_acl.cpython-36-pytest-5.1.2.pyc and new/netmiko-3.1.1/tests/__pycache__/test_netmiko_config_acl.cpython-36-pytest-5.1.2.pyc differ Binary files old/netmiko-3.1.0/tests/__pycache__/test_netmiko_scp.cpython-36-pytest-5.1.2.pyc and new/netmiko-3.1.1/tests/__pycache__/test_netmiko_scp.cpython-36-pytest-5.1.2.pyc differ Binary files old/netmiko-3.1.0/tests/__pycache__/test_netmiko_scp.cpython-36-pytest-5.4.1.pyc and new/netmiko-3.1.1/tests/__pycache__/test_netmiko_scp.cpython-36-pytest-5.4.1.pyc differ Binary files old/netmiko-3.1.0/tests/__pycache__/test_netmiko_session_log.cpython-36-pytest-5.1.2.pyc and new/netmiko-3.1.1/tests/__pycache__/test_netmiko_session_log.cpython-36-pytest-5.1.2.pyc differ Binary files old/netmiko-3.1.0/tests/__pycache__/test_netmiko_show.cpython-36-pytest-5.1.2.pyc and new/netmiko-3.1.1/tests/__pycache__/test_netmiko_show.cpython-36-pytest-5.1.2.pyc differ Binary files old/netmiko-3.1.0/tests/__pycache__/test_netmiko_show.cpython-36-pytest-5.4.1.pyc and new/netmiko-3.1.1/tests/__pycache__/test_netmiko_show.cpython-36-pytest-5.4.1.pyc differ Binary files old/netmiko-3.1.0/tests/__pycache__/test_netmiko_tcl.cpython-36-pytest-5.1.2.pyc and new/netmiko-3.1.1/tests/__pycache__/test_netmiko_tcl.cpython-36-pytest-5.1.2.pyc differ Binary files old/netmiko-3.1.0/tests/__pycache__/test_utils.cpython-36-pytest-5.1.2.pyc and new/netmiko-3.1.1/tests/__pycache__/test_utils.cpython-36-pytest-5.1.2.pyc differ Binary files old/netmiko-3.1.0/tests/__pycache__/test_utils.cpython-36-pytest-5.4.1.pyc and new/netmiko-3.1.1/tests/__pycache__/test_utils.cpython-36-pytest-5.4.1.pyc differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/tests/cisco3-out.txt new/netmiko-3.1.1/tests/cisco3-out.txt --- old/netmiko-3.1.0/tests/cisco3-out.txt 2020-03-23 17:13:55.000000000 +0100 +++ new/netmiko-3.1.1/tests/cisco3-out.txt 2020-05-18 23:32:35.000000000 +0200 @@ -1,5 +1,10 @@ + +cisco3# +cisco3# +cisco3# +cisco3# cisco3# cisco3#terminal length 0 cisco3#terminal width 511 @@ -120,6 +125,10 @@ cisco3(config-ext-nacl)#end cisco3# cisco3# +cisco3# +cisco3# +cisco3# +cisco3# cisco3#show ip access-lists netmiko_test_large_acl Extended IP access list netmiko_test_large_acl 10 permit ip host 192.168.0.1 any diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/tests/conftest.py new/netmiko-3.1.1/tests/conftest.py --- old/netmiko-3.1.0/tests/conftest.py 2020-03-20 16:58:01.000000000 +0100 +++ new/netmiko-3.1.1/tests/conftest.py 2020-05-11 18:23:42.000000000 +0200 @@ -223,6 +223,20 @@ return output +def delete_file_nokia_sros(ssh_conn, dest_file_system, dest_file): + """Delete a remote file for a Nokia SR OS device.""" + full_file_name = "{}/{}".format(dest_file_system, dest_file) + cmd = "file delete {} force".format(full_file_name) + cmd_prefix = "" + if "@" in ssh_conn.base_prompt: + cmd_prefix = "//" + ssh_conn.send_command(cmd_prefix + "environment no more") + output = ssh_conn.send_command_timing( + cmd_prefix + cmd, strip_command=False, strip_prompt=False + ) + return output + + @pytest.fixture(scope="module") def scp_fixture(request): """ @@ -474,4 +488,9 @@ "enable_scp": False, "delete_file": delete_file_ciena_saos, }, + "nokia_sros": { + "file_system": "cf3:", + "enable_scp": False, + "delete_file": delete_file_nokia_sros, + }, } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/tests/etc/commands.yml new/netmiko-3.1.1/tests/etc/commands.yml --- old/netmiko-3.1.0/tests/etc/commands.yml 2020-02-22 00:55:42.000000000 +0100 +++ new/netmiko-3.1.1/tests/etc/commands.yml 2020-05-18 20:46:17.000000000 +0200 @@ -3,6 +3,7 @@ cisco_ios: version: "show version" basic: "show ip interface brief" + wide_command: "show ip access-lists myverybiglongaccesslistthatdoesntexistandwherethisexceeds80characterssolinewrappingoccurs" extended_output: "show version" # requires paging to be disabled config: - "logging buffered 20000" # base command @@ -15,6 +16,7 @@ cisco_ios_telnet: version: "show version" basic: "show ip interface brief" + wide_command: "show ip access-lists myverybiglongaccesslistthatdoesntexistandwherethisexceeds80characterssolinewrappingoccurs" extended_output: "show version" # requires paging to be disabled config: - "logging buffered 20000" # base command @@ -28,7 +30,8 @@ version: "show version" basic: "show ip interface brief" basic_textfsm: "show interface brief" - extended_output: "show version" # requires paging to be disabled + wide_command: "show access-list myverybiglongaccesslistthatdoesntexistandwherethisexceeds80characterssolinewrappingoccurs" + extended_output: "show run" # requires paging to be disabled config: - "logging buffered 4000000" # base command - "no logging console" @@ -40,6 +43,7 @@ cisco_s300: version: "show version" basic: "show ip interface" + wide_command: "show ip access-lists myverybiglongaccesslistthatdoesntexistandwherethisexceeds80characterssolinewrappingoccurs" extended_output: "show run" # requires paging to be disabled config: - 'logging buffered notifications' @@ -52,6 +56,7 @@ cisco_asa: version: "show version" basic: "show ip" + wide_command: "show access-list myverybiglongaccesslistthatdoesntexistandwherethisexceeds80characterssolinewrappingoccurs" basic_textfsm: "show route" extended_output: "show version" # requires paging to be disabled config: @@ -64,6 +69,7 @@ arista_eos: version: "show version" basic: "show ip int brief" + wide_command: "show ip access-lists myverybiglongaccesslistthatdoesntexistandwherethisexceeds80characterssolinewrappingoccurs" extended_output: "show logging" # requires paging to be disabled config: - "logging buffered 20000" @@ -109,6 +115,7 @@ linux: version: "uname -a" basic: "ifconfig -a | grep inet | grep -v inet6 " + wide_command: 'echo "cable modem deny 0015.f2fe.ba11"; echo "cable modem deny 0015.f2fe.ba12"; echo "cable modem deny 0015.f2fe.ba13"' extended_output: "netstat -an" # requires paging to be disabled # config_long_command: "ls verylongcommandnamethatwillcauselinewrapissuesasitdoesnotfitonesinglescreengreaterthan127charsandthensomesothingsreallyarennotright" # config_verification: "ls" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/tests/etc/commands.yml.example new/netmiko-3.1.1/tests/etc/commands.yml.example --- old/netmiko-3.1.0/tests/etc/commands.yml.example 2020-03-22 01:38:04.000000000 +0100 +++ new/netmiko-3.1.1/tests/etc/commands.yml.example 2020-04-30 22:03:14.000000000 +0200 @@ -3,20 +3,61 @@ cisco_ios: version: "show version" basic: "show ip interface brief" + wide_command: "show ip access-lists myverybiglongaccesslistthatdoesntexistandwherethisexceeds80characterssolinewrappingoccurs" extended_output: "show version" # requires paging to be disabled - config: + config: - "logging buffered 20000" # base command - "no logging console" - "logging buffered 20010" # something you can verify has changed config_verification: "show run | inc logging buffer" - config_file: 'cisco_ios_commands.txt' - save_config_cmd: 'copy run start' + config_file: "cisco_ios_commands.txt" + save_config_confirm: False + +cisco_ios_telnet: + version: "show version" + basic: "show ip interface brief" + wide_command: "show ip access-lists myverybiglongaccesslistthatdoesntexistandwherethisexceeds80characterssolinewrappingoccurs" + extended_output: "show version" # requires paging to be disabled + config: + - "logging buffered 20000" # base command + - "no logging console" + - "logging buffered 20010" # something you can verify has changed + config_verification: "show run | inc logging buffer" + config_file: "cisco_ios_commands.txt" + save_config_confirm: False + +cisco_xr: + version: "show version" + basic: "show ip interface brief" + basic_textfsm: "show interface brief" + wide_command: "show access-list myverybiglongaccesslistthatdoesntexistandwherethisexceeds80characterssolinewrappingoccurs" + extended_output: "show version" # requires paging to be disabled + config: + - "logging buffered 4000000" # base command + - "no logging console" + - "logging buffered 4000010" # something you can verify has changed + config_verification: "show run | inc logging buffer" + support_commit: True + commit_verification: "show configuration commit list 1 detail" + +cisco_s300: + version: "show version" + basic: "show ip interface" + wide_command: "show ip access-lists myverybiglongaccesslistthatdoesntexistandwherethisexceeds80characterssolinewrappingoccurs" + extended_output: "show run" # requires paging to be disabled + config: + - 'logging buffered notifications' + - 'no logging console' + - 'logging buffered warnings' + config_verification: "show run" + config_file: "cisco_ios_commands.txt" save_config_confirm: True - save_config_response: '' cisco_asa: version: "show version" basic: "show ip" + wide_command: "show access-list myverybiglongaccesslistthatdoesntexistandwherethisexceeds80characterssolinewrappingoccurs" + basic_textfsm: "show route" extended_output: "show version" # requires paging to be disabled config: - 'logging buffered notifications' @@ -28,8 +69,9 @@ arista_eos: version: "show version" basic: "show ip int brief" + wide_command: "show ip access-lists myverybiglongaccesslistthatdoesntexistandwherethisexceeds80characterssolinewrappingoccurs" extended_output: "show logging" # requires paging to be disabled - config: + config: - "logging buffered 20000" - "no logging console" - "logging buffered 20010" @@ -38,18 +80,30 @@ hp_procurve: version: "show version" basic: "show ip" + basic_textfsm: "show system" extended_output: "show logging" # requires paging to be disabled - config: + config: - 'time timezone -420' - 'time daylight-time-rule Continental-US-and-Canada' - 'time timezone -480' - config_verification: "show run" + config_verification: "show run" + +hp_comware: + version: "display version" + basic: "display ip int brief" + extended_output: "display version" # requires paging to be disabled + config: + - 'ip host test1 1.1.1.1' + - 'undo ip host test1 1.1.1.1' + - 'ip host test1 1.1.1.2' + config_verification: "display current-configuration" -juniper: +juniper_junos: version: "show version" basic: "show interfaces terse" + basic_textfsm: "show interfaces" extended_output: "show configuration" # requires paging to be disabled - config: + config: - 'set system syslog archive size 110k files 3' - 'set system time-zone America/New_York' - 'set system syslog archive size 120k files 3' @@ -58,6 +112,46 @@ rollback: 'rollback 0' commit_verification: "run show system commit" +linux: + version: "uname -a" + basic: "ifconfig -a | grep inet | grep -v inet6 " + wide_command: 'echo "cable modem deny 0015.f2fe.ba11"; echo "cable modem deny 0015.f2fe.ba12"; echo "cable modem deny 0015.f2fe.ba13"' + extended_output: "netstat -an" # requires paging to be disabled + # config_long_command: "ls verylongcommandnamethatwillcauselinewrapissuesasitdoesnotfitonesinglescreengreaterthan127charsandthensomesothingsreallyarennotright" + # config_verification: "ls" + +dell_force10: + version: "show version" + basic: "show ip interface brief managementethernet 0/0" + extended_output: "show ip interface brief" # requires paging to be disabled + config: + - "logging buffered 50000" # base command + - "no logging console" + - "logging buffered 50010" # something you can verify has changed + config_verification: "show run" + +cisco_nxos: + version: "show version" + basic: "show ip interface brief vrf management" + basic_textfsm: "show interface brief" + extended_output: "show logging" # requires paging to be disabled + config: + - "logging console 0" # base command + - "no logging console" + - "logging console 4" # something you can verify has changed + config_verification: "show run | inc logging" + config_long_command: "snmp-server location verylongsnmplocationnamethatwillcauselinewrapissuesasitdoesnotfitonesinglescreengreaterthan127charsandthensomesothingsreallyarennotright" + +cisco_xe: + version: "show version" + basic: "show ip interface brief" + extended_output: "show version" # requires paging to be disabled + config: + - "logging buffered 20000" # base command + - "no logging console" + - "logging buffered 20010" # something you can verify has changed + config_verification: "show run | inc logging buffer" + juniper_screenos: version: "get system version" basic: "get route" @@ -137,6 +231,16 @@ - "logging persistent 4" config_verification: "show running-config | include 'logging'" +ubiquiti_unifiswitch: + version: "show version" + basic: "show network" + extended_output: "show running-config" + config: + - "logging persistent 3" + - "no logging persistent" + - "logging persistent 4" + config_verification: "show running-config | include 'logging'" + dellos10: version: "show version" basic: "show ip interface brief" @@ -316,3 +420,10 @@ basic: "system diagnostics utilities route lookup 172.16.16.16" extended_output: "system diagnostics show version-info" +huawei_smartax: + version: "display version" + basic: "display system sys-info" + extended_output: "display version" + config: + - acl 2456 + config_verification: "display current-configuration | include acl 2456" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/tests/etc/responses.yml new/netmiko-3.1.1/tests/etc/responses.yml --- old/netmiko-3.1.0/tests/etc/responses.yml 2019-12-09 21:21:29.000000000 +0100 +++ new/netmiko-3.1.1/tests/etc/responses.yml 2020-05-18 22:16:55.000000000 +0200 @@ -108,6 +108,16 @@ save_config: 'OK' save_config_response: '' +cisco_xr_azure: + base_prompt: RP/0/RP0/CPU0:iosxr3 + router_prompt : RP/0/RP0/CPU0:iosxr3# + enable_prompt: RP/0/RP0/CPU0:iosxr3# + interface_ip: 10.0.2.15 + version_banner: "Cisco IOS XR Software" + multiple_line_output: "ssh server v2" + commit_comment: 'Unit test on commit with comment' + scp_remote_space: 1500000000 + cisco_xrv: base_prompt: RP/0/0/CPU0:pynet-iosxr1 router_prompt : RP/0/0/CPU0:pynet-iosxr1# @@ -115,9 +125,9 @@ interface_ip: 10.220.88.37 interface_name: GigabitEthernet0/0/0/0 version_banner: "Cisco IOS XR Software" - multiple_line_output: "iosxr-security, V 5.3.1[Default], Cisco Systems" + multiple_line_output: "ssh server v2" commit_comment: 'Unit test on commit with comment' - scp_remote_space: 1500000000 + scp_remote_space: 15000000000 cisco_s300: base_prompt: sf-dc-sw1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/tests/etc/responses.yml.example new/netmiko-3.1.1/tests/etc/responses.yml.example --- old/netmiko-3.1.0/tests/etc/responses.yml.example 2020-03-22 01:38:04.000000000 +0100 +++ new/netmiko-3.1.1/tests/etc/responses.yml.example 2020-04-30 22:03:14.000000000 +0200 @@ -89,6 +89,16 @@ cmd_response_init: "" cmd_response_final: "logging persistent 4" +ubiquiti_unifiswitch: + base_prompt: "(UBNT) " + router_prompt: "(UBNT) >" + enable_prompt: "(UBNT) #" + interface_ip: 10.0.132.4 + version_banner: "Software Version" + multiple_line_output: "Current Configuration:" + cmd_response_init: "" + cmd_response_final: "logging persistent 4" + dellos10: base_prompt: OS10 router_prompt : OS10# @@ -258,3 +268,10 @@ version_banner: "Serial Number" multiple_line_output: "" +huawei_smartax: + base_prompt: "ol01.test-lab.xyz" + router_prompt: "ol01.test-lab.xyz>" + enable_prompt: "ol01.test-lab.xyz#" + interface_ip: 192.0.2.1 + version_banner: "VERSION :" + multiple_line_output: "" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/tests/etc/test_devices.yml new/netmiko-3.1.1/tests/etc/test_devices.yml --- old/netmiko-3.1.0/tests/etc/test_devices.yml 2020-03-15 19:05:22.000000000 +0100 +++ new/netmiko-3.1.1/tests/etc/test_devices.yml 2020-05-11 18:41:55.000000000 +0200 @@ -72,12 +72,14 @@ username: admin password: '{g76l%m30WlJ' secret: '{g76l%m30WlJ' + allow_auto_change: True cisco_asa_login: device_type: cisco_asa ip: 184.105.247.66 username: admin password: '{g76l%m30WlJ' + allow_auto_change: True arista_sw: device_type: arista_eos @@ -117,6 +119,13 @@ secret: '' banner_timeout: 60 +cisco_xr_azure: + device_type: cisco_xr + host: iosxr3.lasthop.io + username: pyclass + password: 88newclass + secret: '' + linux_srv1: device_type: linux host: pynetqa.lasthop.io diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/tests/etc/test_devices.yml.example new/netmiko-3.1.1/tests/etc/test_devices.yml.example --- old/netmiko-3.1.0/tests/etc/test_devices.yml.example 2020-03-22 01:38:04.000000000 +0100 +++ new/netmiko-3.1.1/tests/etc/test_devices.yml.example 2020-04-30 22:03:14.000000000 +0200 @@ -203,4 +203,8 @@ username: admin password: admin - +huawei_smartax: + device_type: huawei_smartax + ip: 192.0.2.1 + username: TEST + password: TEST diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/tests/test_huawei_smartax.sh new/netmiko-3.1.1/tests/test_huawei_smartax.sh --- old/netmiko-3.1.0/tests/test_huawei_smartax.sh 1970-01-01 01:00:00.000000000 +0100 +++ new/netmiko-3.1.1/tests/test_huawei_smartax.sh 2020-04-30 22:03:14.000000000 +0200 @@ -0,0 +1,7 @@ +echo "Huawei SmartAX SSH" \ +&& date \ +&& py.test -v test_netmiko_show.py --test_device huawei_smartax \ +&& date \ +|| RETURN_CODE=1 + +exit $RETURN_CODE diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/tests/test_netmiko_scp.py new/netmiko-3.1.1/tests/test_netmiko_scp.py --- old/netmiko-3.1.0/tests/test_netmiko_scp.py 2020-03-20 16:58:01.000000000 +0100 +++ new/netmiko-3.1.1/tests/test_netmiko_scp.py 2020-05-11 18:23:42.000000000 +0200 @@ -2,17 +2,6 @@ import pytest from netmiko import file_transfer -# def test_enable_scp(scp_fixture): -# ssh_conn, scp_transfer = scp_fixture -# -# scp_transfer.disable_scp() -# output = ssh_conn.send_command_expect("show run | inc scp") -# assert 'ip scp server enable' not in output -# -# scp_transfer.enable_scp() -# output = ssh_conn.send_command_expect("show run | inc scp") -# assert 'ip scp server enable' in output - def test_scp_put(scp_fixture): ssh_conn, scp_transfer = scp_fixture @@ -53,6 +42,8 @@ def test_md5_methods(scp_fixture): ssh_conn, scp_transfer = scp_fixture + if "nokia_sros" in ssh_conn.device_type: + pytest.skip("MD5 not supported on this platform") md5_value = "d8df36973ff832b564ad84642d07a261" remote_md5 = scp_transfer.remote_md5() @@ -70,7 +61,7 @@ ssh_conn, scp_transfer = scp_fixture_get assert scp_transfer.verify_space_available() is True # intentional make there not be enough space available - scp_transfer.file_size = 100000000000000 + scp_transfer.file_size = 100000000000000000 assert scp_transfer.verify_space_available() is False @@ -90,6 +81,8 @@ def test_md5_methods_get(scp_fixture_get): ssh_conn, scp_transfer = scp_fixture_get + if "nokia_sros" in ssh_conn.device_type: + pytest.skip("MD5 not supported on this platform") md5_value = "d8df36973ff832b564ad84642d07a261" local_md5 = scp_transfer.file_md5("test9.txt") assert local_md5 == md5_value diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/tests/test_netmiko_show.py new/netmiko-3.1.1/tests/test_netmiko_show.py --- old/netmiko-3.1.0/tests/test_netmiko_show.py 2020-03-21 00:33:27.000000000 +0100 +++ new/netmiko-3.1.1/tests/test_netmiko_show.py 2020-04-30 22:03:14.000000000 +0200 @@ -35,6 +35,14 @@ assert expected_responses["multiple_line_output"] in multiple_line_output +def test_terminal_width(net_connect, commands, expected_responses): + """Verify long commands work properly.""" + wide_command = commands.get("wide_command") + if wide_command: + net_connect.send_command(wide_command) + assert True + + def test_ssh_connect(net_connect, commands, expected_responses): """Verify the connection was established successfully.""" show_version = net_connect.send_command(commands["version"]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/tests/test_suite_alt.sh new/netmiko-3.1.1/tests/test_suite_alt.sh --- old/netmiko-3.1.0/tests/test_suite_alt.sh 2020-03-20 16:58:01.000000000 +0100 +++ new/netmiko-3.1.1/tests/test_suite_alt.sh 2020-05-18 22:38:12.000000000 +0200 @@ -71,6 +71,11 @@ && py.test -v test_netmiko_config.py --test_device cisco_xrv \ && py.test -v test_netmiko_commit.py --test_device cisco_xrv \ \ +&& echo "Cisco IOS-XR (Azure)" \ +&& py.test -v test_netmiko_show.py --test_device cisco_xr_azure \ +&& py.test -v test_netmiko_config.py --test_device cisco_xr_azure \ +&& py.test -v test_netmiko_commit.py --test_device cisco_xr_azure \ +\ && echo "Cisco NXOS" \ && py.test -v test_netmiko_scp.py --test_device nxos1 \ && py.test -v test_netmiko_show.py --test_device nxos1 \ @@ -86,6 +91,7 @@ && py.test -s -v test_netmiko_autodetect.py --test_device juniper_srx \ && py.test -s -v test_netmiko_autodetect.py --test_device cisco_asa \ && py.test -s -v test_netmiko_autodetect.py --test_device cisco_xrv \ +&& py.test -s -v test_netmiko_autodetect.py --test_device cisco_xr_azure \ \ && echo "HP ProCurve" \ && py.test -v test_netmiko_show.py --test_device hp_procurve \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/tests/test_ubiquiti_unifi.sh new/netmiko-3.1.1/tests/test_ubiquiti_unifi.sh --- old/netmiko-3.1.0/tests/test_ubiquiti_unifi.sh 1970-01-01 01:00:00.000000000 +0100 +++ new/netmiko-3.1.1/tests/test_ubiquiti_unifi.sh 2020-04-30 22:03:14.000000000 +0200 @@ -0,0 +1,12 @@ +#!/bin/sh + +RETURN_CODE=0 + +# Exit on the first test failure and set RETURN_CODE = 1 +echo "Starting tests...good luck:" \ +&& echo "Ubiquiti UniFi Switch" \ +&& py.test -v test_netmiko_show.py --test_device ubiquiti_unifi \ +&& py.test -v test_netmiko_config.py --test_device ubiquiti_unifi \ +|| RETURN_CODE=1 + +exit $RETURN_CODE diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/netmiko-3.1.0/tests/testx.txt new/netmiko-3.1.1/tests/testx.txt --- old/netmiko-3.1.0/tests/testx.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/netmiko-3.1.1/tests/testx.txt 2020-05-18 22:48:33.000000000 +0200 @@ -0,0 +1 @@ +no logging console Binary files old/netmiko-3.1.0/tests/unit/__pycache__/__init__.cpython-36-pytest-5.1.2.pyc and new/netmiko-3.1.1/tests/unit/__pycache__/__init__.cpython-36-pytest-5.1.2.pyc differ Binary files old/netmiko-3.1.0/tests/unit/__pycache__/test_base_connection.cpython-36-pytest-5.1.2.pyc and new/netmiko-3.1.1/tests/unit/__pycache__/test_base_connection.cpython-36-pytest-5.1.2.pyc differ Binary files old/netmiko-3.1.0/tests/unit/__pycache__/test_utilities.cpython-36-pytest-5.1.2.pyc and new/netmiko-3.1.1/tests/unit/__pycache__/test_utilities.cpython-36-pytest-5.1.2.pyc differ
