From 5bedf1ea434ce8b28202a93a8f5cc539ce3148fe Mon Sep 17 00:00:00 2001 From: jcrotts Date: Sat, 10 Feb 2018 21:03:19 -0800 Subject: [PATCH 01/69] Add test cases for save_config method and add example commands for tests --- tests/etc/commands.yml.example | 5 ++- tests/etc/responses.yml.example | 1 + tests/test_netmiko_config.py | 64 +++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/tests/etc/commands.yml.example b/tests/etc/commands.yml.example index 065438165..4e9daa281 100644 --- a/tests/etc/commands.yml.example +++ b/tests/etc/commands.yml.example @@ -9,7 +9,10 @@ cisco_ios: - "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" + config_file: 'cisco_ios_commands.txt' + save_config_cmd: 'copy run start' + save_config_confirm: True + save_config_response: '' cisco_asa: version: "show version" diff --git a/tests/etc/responses.yml.example b/tests/etc/responses.yml.example index b5b4b334a..534984752 100644 --- a/tests/etc/responses.yml.example +++ b/tests/etc/responses.yml.example @@ -8,6 +8,7 @@ cisco_ios: version_banner: "Cisco IOS Software" multiple_line_output: "Configuration register is" file_check_cmd: "logging buffered 8880" + save_config: 'OK' juniper: base_prompt: pyclass@pynet-jnpr-srx1 diff --git a/tests/test_netmiko_config.py b/tests/test_netmiko_config.py index 275e3e96d..e9867c52c 100755 --- a/tests/test_netmiko_config.py +++ b/tests/test_netmiko_config.py @@ -10,6 +10,7 @@ test_exit_config_mode: verify exit config mode test_command_set: verify sending a set of config commands test_commands_from_file: verify sending a set of config commands from a file +test_save_config: verify save config with default values test_disconnect: cleanly disconnect the SSH session """ @@ -100,6 +101,69 @@ def test_commands_from_file(net_connect, commands, expected_responses): else: print("Skipping test (no file specified)...",) +def test_save_base(net_connect, commands, expected_responses): + ''' + Test save config with no options. + ''' + save_verify = expected_responses['save_config'] + + cmd_response = net_connect.save_config() + assert save_verify in cmd_response + +def test_save_confirm(net_connect, commands, expected_responses): + ''' + Test save config with the confirm parameter. + ''' + confirm = commands['save_config_confirm'] + save_verify = expected_responses['save_config'] + + cmd_response = net_connect.save_config(confirm) + assert save_verify in cmd_response + +def test_save_response(net_connect, commands, expected_responses): + ''' + Test save config with the confirm response parameter. + ''' + confirm_response = commands['save_config_response'] + save_verify = expected_responses['save_config'] + + cmd_response = net_connect.save_config(confirm_response=confirm_response) + assert save_verify in cmd_response + +def test_save_cmd(net_connect, commands, expected_responses): + ''' + Test save config with cmd parameter. + ''' + cmd = commands['save_config_cmd'] + save_verify = expected_responses['save_config'] + + cmd_response = net_connect.save_config(cmd=cmd) + assert save_verify in cmd_response + +def test_save_confirm_response(net_connect, commands, expected_responses): + ''' + Test save config with confirm and confirm response parameters + ''' + confirm = commands['save_config_confirm'] + confirm_response = commands['save_config_response'] + save_verify = expected_responses['save_config'] + + cmd_response = net_connect.save_config(confirm=confirm, + confirm_response=confirm_response) + assert save_verify in cmd_response + +def test_save_all(net_connect, commands, expected_responses): + ''' + Test the save config method with all additional parameters. + ''' + cmd = commands['save_config_cmd'] + confirm = commands['save_config_confirm'] + confirm_response = commands['save_config_response'] + save_verify = expected_responses['save_config'] + + cmd_response = net_connect.save_config(cmd=cmd, confirm=confirm, + confirm_response=confirm_response) + assert save_verify in cmd_response def test_disconnect(net_connect, commands, expected_responses): ''' From d782db76fb258cc6bce4c5844280ff5a08357f4f Mon Sep 17 00:00:00 2001 From: jcrotts Date: Sat, 10 Feb 2018 21:08:25 -0800 Subject: [PATCH 02/69] Add testing messages to module docstring --- tests/test_netmiko_config.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/test_netmiko_config.py b/tests/test_netmiko_config.py index e9867c52c..c317a0863 100755 --- a/tests/test_netmiko_config.py +++ b/tests/test_netmiko_config.py @@ -10,7 +10,12 @@ test_exit_config_mode: verify exit config mode test_command_set: verify sending a set of config commands test_commands_from_file: verify sending a set of config commands from a file -test_save_config: verify save config with default values +test_save_base: verify save config with default values +test_save_confirm: verify save config with confirm +test_save_response: verify save config with response +test_save_cmd: verify save config with cmd +test_save_confirm_response: verify save config with confirm and confirm response +test_save_all: verify save config with all options test_disconnect: cleanly disconnect the SSH session """ From 5e31ac7b8903421b59e658141f60b872386cc67a Mon Sep 17 00:00:00 2001 From: Daniel Molkentin Date: Wed, 28 Feb 2018 21:18:07 +0100 Subject: [PATCH 03/69] Add Dell DNOS6 support --- netmiko/dell/__init__.py | 5 ++++- netmiko/dell/dell_dnos6.py | 29 +++++++++++++++++++++++++++++ netmiko/ssh_dispatcher.py | 4 ++++ 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 netmiko/dell/dell_dnos6.py diff --git a/netmiko/dell/__init__.py b/netmiko/dell/__init__.py index 40d788850..e252ede9f 100644 --- a/netmiko/dell/__init__.py +++ b/netmiko/dell/__init__.py @@ -1,6 +1,9 @@ from __future__ import unicode_literals +from netmiko.dell.dell_dnos6 import DellDNOS6SSH +from netmiko.dell.dell_dnos6 import DellDNOS6Telnet from netmiko.dell.dell_force10_ssh import DellForce10SSH from netmiko.dell.dell_powerconnect import DellPowerConnectSSH from netmiko.dell.dell_powerconnect import DellPowerConnectTelnet -__all__ = ['DellForce10SSH', 'DellPowerConnectSSH', 'DellPowerConnectTelnet'] +__all__ = ['DellDNOS6SSH', 'DellDNOS6Telnet', 'DellForce10SSH', + 'DellPowerConnectSSH', 'DellPowerConnectTelnet'] diff --git a/netmiko/dell/dell_dnos6.py b/netmiko/dell/dell_dnos6.py new file mode 100644 index 000000000..3f1eb72aa --- /dev/null +++ b/netmiko/dell/dell_dnos6.py @@ -0,0 +1,29 @@ +"""Dell N2/3/4000 base driver- supports DNOS6.""" +from __future__ import unicode_literals +from netmiko.dell.dell_powerconnect import DellPowerConnectBase + + +class DellDNOS6Base(DellPowerConnectBase): + 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.enable() + self.disable_paging(command="terminal length 0") + self.set_terminal_width() + # Clear the read buffer + time.sleep(.3 * self.global_delay_factor) + self.clear_buffer() + + def save_config(self, cmd='copy running-configuration startup-configuration', confirm=False): + """Saves Config""" + return super(DellDNOS6SSH, self).save_config(cmd=cmd, confirm=confirm) + + +class DellDNOS6SSH(DellDNOS6Base): + pass + + +class DellDNOS6Telnet(DellDNOS6Base): + pass diff --git a/netmiko/ssh_dispatcher.py b/netmiko/ssh_dispatcher.py index 67be9225a..f7920267d 100644 --- a/netmiko/ssh_dispatcher.py +++ b/netmiko/ssh_dispatcher.py @@ -24,6 +24,8 @@ from netmiko.cisco import CiscoWlcSSH from netmiko.cisco import CiscoXrSSH, CiscoXrFileTransfer from netmiko.coriant import CoriantSSH +from netmiko.dell import DellDNOS6SSH +from netmiko.dell import DellDNOS6Telnet from netmiko.dell import DellForce10SSH from netmiko.dell import DellPowerConnectSSH from netmiko.dell import DellPowerConnectTelnet @@ -81,6 +83,7 @@ 'cisco_xe': CiscoIosSSH, 'cisco_xr': CiscoXrSSH, 'coriant': CoriantSSH, + 'dell_dnos6': DellDNOS6SSH, 'dell_force10': DellForce10SSH, 'dell_powerconnect': DellPowerConnectSSH, 'eltex': EltexSSH, @@ -143,6 +146,7 @@ CLASS_MAPPER['cisco_ios_telnet'] = CiscoIosTelnet CLASS_MAPPER['arista_eos_telnet'] = AristaTelnet CLASS_MAPPER['juniper_junos_telnet'] = JuniperTelnet +CLASS_MAPPER['dell_dnos6_telnet'] = DellDNOS6Telnet CLASS_MAPPER['dell_powerconnect_telnet'] = DellPowerConnectTelnet CLASS_MAPPER['generic_termserver_telnet'] = TerminalServerTelnet CLASS_MAPPER['extreme_telnet'] = ExtremeTelnet From 6cdd6ac6d1049a4e1763a692ea4a8363fda27e41 Mon Sep 17 00:00:00 2001 From: Daniel Molkentin Date: Wed, 28 Feb 2018 21:29:39 +0100 Subject: [PATCH 04/69] Alias the Force10 implementation to DNOS9 ...as per the drivers compatibility claims. --- netmiko/dell/dell_dnos6.py | 1 + netmiko/ssh_dispatcher.py | 1 + 2 files changed, 2 insertions(+) diff --git a/netmiko/dell/dell_dnos6.py b/netmiko/dell/dell_dnos6.py index 3f1eb72aa..7bf3d3465 100644 --- a/netmiko/dell/dell_dnos6.py +++ b/netmiko/dell/dell_dnos6.py @@ -1,6 +1,7 @@ """Dell N2/3/4000 base driver- supports DNOS6.""" from __future__ import unicode_literals from netmiko.dell.dell_powerconnect import DellPowerConnectBase +import time class DellDNOS6Base(DellPowerConnectBase): diff --git a/netmiko/ssh_dispatcher.py b/netmiko/ssh_dispatcher.py index f7920267d..9d10e12e6 100644 --- a/netmiko/ssh_dispatcher.py +++ b/netmiko/ssh_dispatcher.py @@ -84,6 +84,7 @@ 'cisco_xr': CiscoXrSSH, 'coriant': CoriantSSH, 'dell_dnos6': DellDNOS6SSH, + 'dell_dnos9': DellForce10SSH, 'dell_force10': DellForce10SSH, 'dell_powerconnect': DellPowerConnectSSH, 'eltex': EltexSSH, From 455419dbe9c2f14ae7913c33d5d1269d1ab98d86 Mon Sep 17 00:00:00 2001 From: ScottW514 Date: Fri, 30 Mar 2018 16:02:54 -0400 Subject: [PATCH 05/69] Fix is_alive() for telnet Issue #763 Python's telnetlib escaped the IAC+NOP sequence that was being sent to the host. On some devices this led to a disconnect on subsequent calls to find_prompt(). --- netmiko/base_connection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netmiko/base_connection.py b/netmiko/base_connection.py index baf4da046..fc1f5cd32 100644 --- a/netmiko/base_connection.py +++ b/netmiko/base_connection.py @@ -303,7 +303,7 @@ def is_alive(self): # Try sending IAC + NOP (IAC is telnet way of sending command # IAC = Interpret as Command (it comes before the NOP) log.debug("Sending IAC + NOP") - self.write_channel(telnetlib.IAC + telnetlib.NOP) + self.remote_conn.sock.sendall(telnetlib.IAC + telnetlib.NOP) return True except AttributeError: return False From a1271245cbe8083f24f0225a60fe5e277e36af9a Mon Sep 17 00:00:00 2001 From: Stephen Kiely Date: Tue, 10 Jul 2018 12:43:00 -0500 Subject: [PATCH 06/69] Initial upload to Github These changes will add in experimental support for the RAD ETX series devices. This has not gone through testing yet, it is currently just a rebase of other modules, specifically the Dell Powerconnect and Ciena SAOS. --- README.md | 1 + netmiko/ssh_dispatcher.py | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/README.md b/README.md index 0023ba535..41f81209f 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,7 @@ Fortinet MRV Communications OptiSwitch Nokia/Alcatel SR-OS QuantaMesh +Rad ETX ## Tutorials: diff --git a/netmiko/ssh_dispatcher.py b/netmiko/ssh_dispatcher.py index 987def376..a538abc09 100644 --- a/netmiko/ssh_dispatcher.py +++ b/netmiko/ssh_dispatcher.py @@ -50,6 +50,8 @@ from netmiko.paloalto import PaloAltoPanosSSH from netmiko.pluribus import PluribusSSH from netmiko.quanta import QuantaMeshSSH +from netmiko.rad import RadETXSSH +from netmiko.rad import RadETXTelnet from netmiko.ruckus import RuckusFastironSSH from netmiko.ruckus import RuckusFastironTelnet from netmiko.terminal_server import TerminalServerSSH @@ -112,6 +114,7 @@ 'paloalto_panos': PaloAltoPanosSSH, 'pluribus': PluribusSSH, 'quanta_mesh': QuantaMeshSSH, + 'rad_etx': RadETXSSH, 'ruckus_fastiron': RuckusFastironSSH, 'ubiquiti_edge': UbiquitiEdgeSSH, 'ubiquiti_edgeswitch': UbiquitiEdgeSSH, @@ -159,6 +162,7 @@ CLASS_MAPPER['dell_powerconnect_telnet'] = DellPowerConnectTelnet CLASS_MAPPER['generic_termserver_telnet'] = TerminalServerTelnet CLASS_MAPPER['extreme_telnet'] = ExtremeTelnet +CLASS_MAPPER['rad_etx_telnet'] = RadETXTelnet CLASS_MAPPER['ruckus_fastiron_telnet'] = RuckusFastironTelnet # Add serial drivers From 0541f0a39a3a9828e2560c265c40ac1c7b847f19 Mon Sep 17 00:00:00 2001 From: Stephen Kiely Date: Tue, 10 Jul 2018 12:44:54 -0500 Subject: [PATCH 07/69] Add files rad/__init__ and rad/rad_etx --- netmiko/rad/__init__.py | 5 ++++ netmiko/rad/rad_etx.py | 53 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 netmiko/rad/__init__.py create mode 100644 netmiko/rad/rad_etx.py diff --git a/netmiko/rad/__init__.py b/netmiko/rad/__init__.py new file mode 100644 index 000000000..1bd24e246 --- /dev/null +++ b/netmiko/rad/__init__.py @@ -0,0 +1,5 @@ +from __future__ import unicode_literals +from netmiko.rad.rad_etx import RadETXSSH +from netmiko.rad.rad_etx import RadETXTelnet + +__all__ = ['RadETXSSH', 'RadETXTelnet'] \ No newline at end of file diff --git a/netmiko/rad/rad_etx.py b/netmiko/rad/rad_etx.py new file mode 100644 index 000000000..e9395c97a --- /dev/null +++ b/netmiko/rad/rad_etx.py @@ -0,0 +1,53 @@ +from __future__ import unicode_literals +from __future__ import print_function +import time +from netmiko.base_connection import BaseConnection + +class RadETXBase(BaseConnection): + """RAD ETX Support, Tested on RAD 203AX, 205A and 220A""" + def session_preparation(self): + self._test_channel_read() + self.set_base_prompt() + self.disable_paging(command="config term length 0") + # Clear the read buffer + time.sleep(.3 * self.global_delay_factor) + self.clear_buffer() + + def save_config(self, cmd='admin save', confirm=False): + """Saves Config Using admin save""" + return super(RadETXBase, self).save_config(cmd=cmd, confirm=confirm) + + def enable(self, *args, **kwargs): + pass + +class RadETXSSH(RadETXBase): + """RAD ETX SSH Support""" + pass + +class RadETXTelnet(RadETXBase): + """RAD ETX Telnet Support""" + def special_login_handler(self, delay_factor=1): + """ + RAD presents with the following on login + + user> + + password> **** + """ + delay_factor = self.select_delay_factor(delay_factor) + i = 0 + time.sleep(delay_factor * .5) + output = "" + while i <= 12: + output = self.read_channel() + if output: + if 'user>' in output: + self.write_channel(self.username + self.RETURN) + elif 'password>' in output: + self.write_channel(self.password + self.RETURN) + break + time.sleep(delay_factor * 1) + else: + self.write_channel(self.RETURN) + time.sleep(delay_factor * 1.5) + i += 1 From c564877ded664c41cae60684b05616b7ae06af24 Mon Sep 17 00:00:00 2001 From: Stephen Kiely Date: Tue, 10 Jul 2018 16:43:08 -0500 Subject: [PATCH 08/69] Support the config_save command. This adds the save_config, this is based on the Cisco save command. --- netmiko/rad/rad_etx.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/netmiko/rad/rad_etx.py b/netmiko/rad/rad_etx.py index e9395c97a..649aa52bc 100644 --- a/netmiko/rad/rad_etx.py +++ b/netmiko/rad/rad_etx.py @@ -13,20 +13,30 @@ def session_preparation(self): time.sleep(.3 * self.global_delay_factor) self.clear_buffer() - def save_config(self, cmd='admin save', confirm=False): + def save_config(self, cmd='admin save', confirm=False, confirm_response=''): """Saves Config Using admin save""" - return super(RadETXBase, self).save_config(cmd=cmd, confirm=confirm) + if confirm: + output = self.send_command_timing(command_string=cmd) + if confirm_response: + output += self.send_command_timing(confirm_response) + else: + # Send enter by default + output += self.send_command_timing(self.RETURN) + else: + # Some devices are slow so match on trailing-prompt if you can + output = self.send_command(command_string=cmd) + return output def enable(self, *args, **kwargs): pass - + class RadETXSSH(RadETXBase): """RAD ETX SSH Support""" pass class RadETXTelnet(RadETXBase): """RAD ETX Telnet Support""" - def special_login_handler(self, delay_factor=1): + def telnet_login(self, delay_factor=1): """ RAD presents with the following on login From ea7ec17e23cca8d4fb089fd8e8136412ca1f5efc Mon Sep 17 00:00:00 2001 From: Stephen Kiely Date: Wed, 11 Jul 2018 10:13:21 -0500 Subject: [PATCH 09/69] Add config mode for Rad ETX Added the config mode for the Rad ETX. The config mode is technically just another command branch in the Rad, but works similiar enough to Cisco to add support in. --- netmiko/rad/rad_etx.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/netmiko/rad/rad_etx.py b/netmiko/rad/rad_etx.py index 649aa52bc..a4154a62e 100644 --- a/netmiko/rad/rad_etx.py +++ b/netmiko/rad/rad_etx.py @@ -1,6 +1,7 @@ from __future__ import unicode_literals from __future__ import print_function import time +import re from netmiko.base_connection import BaseConnection class RadETXBase(BaseConnection): @@ -28,8 +29,31 @@ def save_config(self, cmd='admin save', confirm=False, confirm_response=''): return output def enable(self, *args, **kwargs): + """The Rad ETX software does not have an enable""" pass + def config_mode(self, config_command='config', pattern='>config'): + """ + Enter into configuration mode on remote device. + + This needs some extended testing. + """ + return super(RadETXBase, self).config_mode(config_command=config_command, + pattern=pattern) + def check_config_mode(self, check_string='>config', pattern=''): + """ + Checks if the device is in configuration mode or not. + + Rad config starts with baseprompt>config + """ + return super(RadETXBase, self).check_config_mode(check_string=check_string, + pattern=pattern) + + def exit_config_mode(self, exit_config='exit all', pattern='#'): + """Exit from configuration mode.""" + return super(RadETXBase, self).exit_config_mode(exit_config=exit_config, + pattern=pattern) + class RadETXSSH(RadETXBase): """RAD ETX SSH Support""" pass From 6168efb157e90bdcde440e086fbcb07a8911fc1d Mon Sep 17 00:00:00 2001 From: Stephen Kiely Date: Wed, 11 Jul 2018 10:20:14 -0500 Subject: [PATCH 10/69] Add New line to support PEP convention --- netmiko/rad/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netmiko/rad/__init__.py b/netmiko/rad/__init__.py index 1bd24e246..22a125b3b 100644 --- a/netmiko/rad/__init__.py +++ b/netmiko/rad/__init__.py @@ -2,4 +2,4 @@ from netmiko.rad.rad_etx import RadETXSSH from netmiko.rad.rad_etx import RadETXTelnet -__all__ = ['RadETXSSH', 'RadETXTelnet'] \ No newline at end of file +__all__ = ['RadETXSSH', 'RadETXTelnet'] From 916ae0c0e414d23bb325ea64f6a755cafb46bb13 Mon Sep 17 00:00:00 2001 From: Stephen Kiely Date: Wed, 11 Jul 2018 10:44:33 -0500 Subject: [PATCH 11/69] Fix pylint errors found with Pylama --- netmiko/rad/rad_etx.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/netmiko/rad/rad_etx.py b/netmiko/rad/rad_etx.py index a4154a62e..d99990410 100644 --- a/netmiko/rad/rad_etx.py +++ b/netmiko/rad/rad_etx.py @@ -1,15 +1,15 @@ from __future__ import unicode_literals from __future__ import print_function import time -import re from netmiko.base_connection import BaseConnection + class RadETXBase(BaseConnection): """RAD ETX Support, Tested on RAD 203AX, 205A and 220A""" def session_preparation(self): self._test_channel_read() self.set_base_prompt() - self.disable_paging(command="config term length 0") + self.disable_paging(command='config term length 0') # Clear the read buffer time.sleep(.3 * self.global_delay_factor) self.clear_buffer() @@ -27,7 +27,7 @@ def save_config(self, cmd='admin save', confirm=False, confirm_response=''): # Some devices are slow so match on trailing-prompt if you can output = self.send_command(command_string=cmd) return output - + def enable(self, *args, **kwargs): """The Rad ETX software does not have an enable""" pass @@ -39,7 +39,8 @@ def config_mode(self, config_command='config', pattern='>config'): This needs some extended testing. """ return super(RadETXBase, self).config_mode(config_command=config_command, - pattern=pattern) + pattern=pattern) + def check_config_mode(self, check_string='>config', pattern=''): """ Checks if the device is in configuration mode or not. @@ -47,17 +48,22 @@ def check_config_mode(self, check_string='>config', pattern=''): Rad config starts with baseprompt>config """ return super(RadETXBase, self).check_config_mode(check_string=check_string, - pattern=pattern) + pattern=pattern) def exit_config_mode(self, exit_config='exit all', pattern='#'): """Exit from configuration mode.""" return super(RadETXBase, self).exit_config_mode(exit_config=exit_config, - pattern=pattern) + pattern=pattern) + class RadETXSSH(RadETXBase): - """RAD ETX SSH Support""" + """RAD ETX SSH Support. + + Found that a global_delay_factor of 2 is needed at minimum for SSH to the Rad ETX. + """ pass + class RadETXTelnet(RadETXBase): """RAD ETX Telnet Support""" def telnet_login(self, delay_factor=1): From 91faf75f2ed31dd2459a75afbe389c34959a0e9d Mon Sep 17 00:00:00 2001 From: Stephen Kiely Date: Wed, 11 Jul 2018 13:41:20 -0500 Subject: [PATCH 12/69] Add periods in docstring to match PEP standards. --- netmiko/rad/rad_etx.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/netmiko/rad/rad_etx.py b/netmiko/rad/rad_etx.py index d99990410..d7f28873e 100644 --- a/netmiko/rad/rad_etx.py +++ b/netmiko/rad/rad_etx.py @@ -5,7 +5,7 @@ class RadETXBase(BaseConnection): - """RAD ETX Support, Tested on RAD 203AX, 205A and 220A""" + """RAD ETX Support, Tested on RAD 203AX, 205A and 220A.""" def session_preparation(self): self._test_channel_read() self.set_base_prompt() @@ -15,7 +15,7 @@ def session_preparation(self): self.clear_buffer() def save_config(self, cmd='admin save', confirm=False, confirm_response=''): - """Saves Config Using admin save""" + """Saves Config Using admin save.""" if confirm: output = self.send_command_timing(command_string=cmd) if confirm_response: @@ -29,15 +29,11 @@ def save_config(self, cmd='admin save', confirm=False, confirm_response=''): return output def enable(self, *args, **kwargs): - """The Rad ETX software does not have an enable""" + """The Rad ETX software does not have an enable.""" pass def config_mode(self, config_command='config', pattern='>config'): - """ - Enter into configuration mode on remote device. - - This needs some extended testing. - """ + """Enter into configuration mode on remote device.""" return super(RadETXBase, self).config_mode(config_command=config_command, pattern=pattern) @@ -45,7 +41,7 @@ def check_config_mode(self, check_string='>config', pattern=''): """ Checks if the device is in configuration mode or not. - Rad config starts with baseprompt>config + Rad config starts with baseprompt>config. """ return super(RadETXBase, self).check_config_mode(check_string=check_string, pattern=pattern) @@ -65,7 +61,7 @@ class RadETXSSH(RadETXBase): class RadETXTelnet(RadETXBase): - """RAD ETX Telnet Support""" + """RAD ETX Telnet Support.""" def telnet_login(self, delay_factor=1): """ RAD presents with the following on login From 8b666e62e0aae9fc9d605d83cf72620a72355d51 Mon Sep 17 00:00:00 2001 From: routerman Date: Thu, 19 Jul 2018 17:11:37 +0900 Subject: [PATCH 13/69] Add support for paloalto_panos_telnet --- netmiko/paloalto/__init__.py | 4 ++-- ...paloalto_panos_ssh.py => paloalto_panos.py} | 18 +++++++++++++----- netmiko/ssh_dispatcher.py | 2 ++ 3 files changed, 17 insertions(+), 7 deletions(-) rename netmiko/paloalto/{paloalto_panos_ssh.py => paloalto_panos.py} (91%) diff --git a/netmiko/paloalto/__init__.py b/netmiko/paloalto/__init__.py index f34f9fdfa..57262d6fe 100644 --- a/netmiko/paloalto/__init__.py +++ b/netmiko/paloalto/__init__.py @@ -1,4 +1,4 @@ from __future__ import unicode_literals -from netmiko.paloalto.paloalto_panos_ssh import PaloAltoPanosSSH +from netmiko.paloalto.paloalto_panos import PaloAltoPanosSSH, PaloAltoPanosTelnet -__all__ = ['PaloAltoPanosSSH'] +__all__ = ['PaloAltoPanosSSH', 'PaloAltoPanosTelnet'] diff --git a/netmiko/paloalto/paloalto_panos_ssh.py b/netmiko/paloalto/paloalto_panos.py similarity index 91% rename from netmiko/paloalto/paloalto_panos_ssh.py rename to netmiko/paloalto/paloalto_panos.py index 8dc0b07e2..f8ff5a8f3 100644 --- a/netmiko/paloalto/paloalto_panos_ssh.py +++ b/netmiko/paloalto/paloalto_panos.py @@ -4,7 +4,7 @@ from netmiko.base_connection import BaseConnection -class PaloAltoPanosSSH(BaseConnection): +class PaloAltoPanosBase(BaseConnection): """ Implement methods for interacting with PaloAlto devices. @@ -39,15 +39,15 @@ def exit_enable_mode(self, *args, **kwargs): def check_config_mode(self, check_string=']'): """Checks if the device is in configuration mode or not.""" - return super(PaloAltoPanosSSH, self).check_config_mode(check_string=check_string) + return super(PaloAltoPanosBase, self).check_config_mode(check_string=check_string) def config_mode(self, config_command='configure'): """Enter configuration mode.""" - return super(PaloAltoPanosSSH, self).config_mode(config_command=config_command) + return super(PaloAltoPanosBase, self).config_mode(config_command=config_command) def exit_config_mode(self, exit_config='exit', pattern=r'>'): """Exit configuration mode.""" - return super(PaloAltoPanosSSH, self).exit_config_mode(exit_config=exit_config, + return super(PaloAltoPanosBase, self).exit_config_mode(exit_config=exit_config, pattern=pattern) def commit(self, force=False, partial=False, device_and_network=False, @@ -146,4 +146,12 @@ def send_command_expect(self, *args, **kwargs): def send_command(self, *args, **kwargs): """Palo Alto requires an extra delay""" kwargs['delay_factor'] = kwargs.get('delay_factor', 2.5) - return super(PaloAltoPanosSSH, self).send_command(*args, **kwargs) + return super(PaloAltoPanosBase, self).send_command(*args, **kwargs) + + +class PaloAltoPanosSSH(PaloAltoPanosBase): + pass + + +class PaloAltoPanosTelnet(PaloAltoPanosBase): + pass \ No newline at end of file diff --git a/netmiko/ssh_dispatcher.py b/netmiko/ssh_dispatcher.py index 987def376..f4a9ce29d 100644 --- a/netmiko/ssh_dispatcher.py +++ b/netmiko/ssh_dispatcher.py @@ -48,6 +48,7 @@ from netmiko.netapp import NetAppcDotSSH from netmiko.ovs import OvsLinuxSSH from netmiko.paloalto import PaloAltoPanosSSH +from netmiko.paloalto import PaloAltoPanosTelnet from netmiko.pluribus import PluribusSSH from netmiko.quanta import QuantaMeshSSH from netmiko.ruckus import RuckusFastironSSH @@ -155,6 +156,7 @@ CLASS_MAPPER['hp_procurve_telnet'] = HPProcurveTelnet CLASS_MAPPER['hp_comware_telnet'] = HPComwareTelnet CLASS_MAPPER['juniper_junos_telnet'] = JuniperTelnet +CLASS_MAPPER['paloalto_panos_telnet'] = PaloAltoPanosTelnet CLASS_MAPPER['calix_b6_telnet'] = CalixB6Telnet CLASS_MAPPER['dell_powerconnect_telnet'] = DellPowerConnectTelnet CLASS_MAPPER['generic_termserver_telnet'] = TerminalServerTelnet From bf939958c15106a8b7f631622cf9ac9813e2361e Mon Sep 17 00:00:00 2001 From: routerman Date: Thu, 19 Jul 2018 18:05:03 +0900 Subject: [PATCH 14/69] add 1 line at end of paloalto_panos.py --- netmiko/paloalto/paloalto_panos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netmiko/paloalto/paloalto_panos.py b/netmiko/paloalto/paloalto_panos.py index f8ff5a8f3..0f92620dc 100644 --- a/netmiko/paloalto/paloalto_panos.py +++ b/netmiko/paloalto/paloalto_panos.py @@ -154,4 +154,4 @@ class PaloAltoPanosSSH(PaloAltoPanosBase): class PaloAltoPanosTelnet(PaloAltoPanosBase): - pass \ No newline at end of file + pass From 88d095652f204c24406e6d2596be350e238ce5a6 Mon Sep 17 00:00:00 2001 From: routerman Date: Thu, 19 Jul 2018 18:13:55 +0900 Subject: [PATCH 15/69] add space --- netmiko/paloalto/paloalto_panos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netmiko/paloalto/paloalto_panos.py b/netmiko/paloalto/paloalto_panos.py index 0f92620dc..f43c20128 100644 --- a/netmiko/paloalto/paloalto_panos.py +++ b/netmiko/paloalto/paloalto_panos.py @@ -48,7 +48,7 @@ def config_mode(self, config_command='configure'): def exit_config_mode(self, exit_config='exit', pattern=r'>'): """Exit configuration mode.""" return super(PaloAltoPanosBase, self).exit_config_mode(exit_config=exit_config, - pattern=pattern) + pattern=pattern) def commit(self, force=False, partial=False, device_and_network=False, policy_and_objects=False, vsys='', no_vsys=False, delay_factor=.1): From ed8c3eea465f1a549354d6a93591e0be6c9fb37e Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Sun, 22 Jul 2018 20:13:06 -0700 Subject: [PATCH 16/69] Adding HP ProCurve --- netmiko/snmp_autodetect.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/netmiko/snmp_autodetect.py b/netmiko/snmp_autodetect.py index 29d819a2f..0ba00ba26 100644 --- a/netmiko/snmp_autodetect.py +++ b/netmiko/snmp_autodetect.py @@ -42,6 +42,9 @@ 'hp_comware': {"oid": ".1.3.6.1.2.1.1.1.0", "expr": re.compile(r".*HP Comware.*", re.IGNORECASE), "priority": 99}, + 'hp_procurve': {"oid": ".1.3.6.1.2.1.1.1.0", + "expr": re.compile(r".ProCurve", re.IGNORECASE), + "priority": 99}, 'cisco_ios': {"oid": ".1.3.6.1.2.1.1.1.0", "expr": re.compile(r".*Cisco IOS Software,.*", re.IGNORECASE), "priority": 60}, From fe4872a37d14fb2ec9c3ae824cdd36b1ccd6d312 Mon Sep 17 00:00:00 2001 From: Jason Nixon Date: Tue, 24 Jul 2018 17:50:38 -0700 Subject: [PATCH 17/69] Changed brocade netiron, vdx and avaya ers and vsp to extreme, added in extreme slx support --- README.md | 17 ++++--- netmiko/avaya/__init__.py | 5 -- netmiko/base_connection.py | 2 +- netmiko/brocade/__init__.py | 6 --- netmiko/extreme/__init__.py | 14 ++++-- .../extreme_ers_ssh.py} | 12 ++--- netmiko/extreme/extreme_exos.py | 22 ++++---- .../extreme_netiron.py} | 10 ++-- .../extreme_nos_ssh.py} | 14 +++--- netmiko/extreme/extreme_slx_ssh.py | 28 +++++++++++ .../extreme_vsp_ssh.py} | 8 +-- netmiko/ssh_dispatcher.py | 50 +++++++++++-------- netmiko/utilities.py | 7 +++ 13 files changed, 119 insertions(+), 76 deletions(-) delete mode 100644 netmiko/avaya/__init__.py delete mode 100644 netmiko/brocade/__init__.py rename netmiko/{avaya/avaya_ers_ssh.py => extreme/extreme_ers_ssh.py} (75%) rename netmiko/{brocade/brocade_netiron.py => extreme/extreme_netiron.py} (60%) rename netmiko/{brocade/brocade_nos_ssh.py => extreme/extreme_nos_ssh.py} (69%) create mode 100644 netmiko/extreme/extreme_slx_ssh.py rename netmiko/{avaya/avaya_vsp_ssh.py => extreme/extreme_vsp_ssh.py} (72%) diff --git a/README.md b/README.md index eda987b9e..1f4580011 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![PyPI](https://img.shields.io/pypi/v/netmiko.svg)](https://pypi.python.org/pypi/netmiko) - - + + Netmiko ======= @@ -31,20 +31,20 @@ HP Comware7 HP ProCurve Juniper Junos Linux - + ###### Limited testing Alcatel AOS6/AOS8 Apresia Systems AEOS -Avaya ERS -Avaya VSP -Brocade VDX -Brocade MLX/NetIron Calix B6 Cisco WLC Dell OS10 Dell-Force10 Dell PowerConnect +Extreme ERS +Extreme VSP +Extreme VDX +Extreme MLX/NetIron Huawei Mellanox NetApp cDOT @@ -68,7 +68,8 @@ Dell EMC Isilon Eltex Enterasys Extreme EXOS -Extreme Wing +Extreme Wing +Extreme SLX F5 LTM Fortinet MRV Communications OptiSwitch diff --git a/netmiko/avaya/__init__.py b/netmiko/avaya/__init__.py deleted file mode 100644 index 54bd407a9..000000000 --- a/netmiko/avaya/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import unicode_literals -from netmiko.avaya.avaya_vsp_ssh import AvayaVspSSH -from netmiko.avaya.avaya_ers_ssh import AvayaErsSSH - -__all__ = ['AvayaVspSSH', 'AvayaErsSSH'] diff --git a/netmiko/base_connection.py b/netmiko/base_connection.py index 975e7ada3..a99500394 100644 --- a/netmiko/base_connection.py +++ b/netmiko/base_connection.py @@ -841,7 +841,7 @@ def select_delay_factor(self, delay_factor): return self.global_delay_factor def special_login_handler(self, delay_factor=1): - """Handler for devices like WLC, Avaya ERS that throw up characters prior to login.""" + """Handler for devices like WLC, Extreme ERS that throw up characters prior to login.""" pass def disable_paging(self, command="terminal length 0", delay_factor=1): diff --git a/netmiko/brocade/__init__.py b/netmiko/brocade/__init__.py deleted file mode 100644 index 6b3eb01ec..000000000 --- a/netmiko/brocade/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from __future__ import unicode_literals -from netmiko.brocade.brocade_nos_ssh import BrocadeNosSSH -from netmiko.brocade.brocade_netiron import BrocadeNetironSSH -from netmiko.brocade.brocade_netiron import BrocadeNetironTelnet - -__all__ = ['BrocadeNosSSH', 'BrocadeNetironSSH', 'BrocadeNetironTelnet'] diff --git a/netmiko/extreme/__init__.py b/netmiko/extreme/__init__.py index 1074d9428..5cf4877f1 100644 --- a/netmiko/extreme/__init__.py +++ b/netmiko/extreme/__init__.py @@ -1,6 +1,14 @@ from __future__ import unicode_literals -from netmiko.extreme.extreme_exos import ExtremeSSH -from netmiko.extreme.extreme_exos import ExtremeTelnet +from netmiko.extreme.extreme_ers_ssh import ExtremeErsSSH +from netmiko.extreme.extreme_exos import ExtremeExosSSH +from netmiko.extreme.extreme_exos import ExtremeExosTelnet +from netmiko.extreme.extreme_netiron import ExtremeNetironSSH +from netmiko.extreme.extreme_netiron import ExtremeNetironTelnet +from netmiko.extreme.extreme_nos_ssh import ExtremeNosSSH +from netmiko.extreme.extreme_slx_ssh import ExtremeSlxSSH +from netmiko.extreme.extreme_vsp_ssh import ExtremeVspSSH from netmiko.extreme.extreme_wing_ssh import ExtremeWingSSH -__all__ = ['ExtremeSSH', 'ExtremeWingSSH', 'ExtremeTelnet'] +__all__ = ['ExtremeErsSSH', 'ExtremeExosSSH', 'ExtremeExosTelnet', + 'ExtremeNetironSSH', 'ExtremeNetironTelnet', 'ExtremeNosSSH', + 'ExtremeSlxSSH', 'ExtremeVspSSH', 'ExtremeWingSSH'] diff --git a/netmiko/avaya/avaya_ers_ssh.py b/netmiko/extreme/extreme_ers_ssh.py similarity index 75% rename from netmiko/avaya/avaya_ers_ssh.py rename to netmiko/extreme/extreme_ers_ssh.py index f234b78dc..e51848405 100644 --- a/netmiko/avaya/avaya_ers_ssh.py +++ b/netmiko/extreme/extreme_ers_ssh.py @@ -1,18 +1,18 @@ -"""Netmiko support for Avaya Ethernet Routing Switch.""" +"""Netmiko support for Extreme Ethernet Routing Switch.""" from __future__ import print_function from __future__ import unicode_literals import time from netmiko.cisco_base_connection import CiscoSSHConnection -# Avaya presents Enter Ctrl-Y to begin. +# Extreme ERS presents Enter Ctrl-Y to begin. CTRL_Y = '\x19' -class AvayaErsSSH(CiscoSSHConnection): - """Netmiko support for Avaya Ethernet Routing Switch.""" +class ExtremeErsSSH(CiscoSSHConnection): + """Netmiko support for Extreme Ethernet Routing Switch.""" def special_login_handler(self, delay_factor=1): """ - Avaya ERS presents the following as part of the login process: + Extreme ERS presents the following as part of the login process: Enter Ctrl-Y to begin. """ @@ -39,4 +39,4 @@ def special_login_handler(self, delay_factor=1): def save_config(self, cmd='save config', confirm=False): """Save Config""" - return super(AvayaErsSSH, self).save_config(cmd=cmd, confirm=confirm) + return super(ExtremeErsSSH, self).save_config(cmd=cmd, confirm=confirm) diff --git a/netmiko/extreme/extreme_exos.py b/netmiko/extreme/extreme_exos.py index 94e406a81..a116c82ac 100644 --- a/netmiko/extreme/extreme_exos.py +++ b/netmiko/extreme/extreme_exos.py @@ -5,8 +5,8 @@ from netmiko.cisco_base_connection import CiscoSSHConnection -class ExtremeBase(CiscoSSHConnection): - """Extreme support. +class ExtremeExosBase(CiscoSSHConnection): + """Extreme Exos support. Designed for EXOS >= 15.0 """ @@ -34,7 +34,7 @@ def set_base_prompt(self, *args, **kwargs): * testhost.4 # * testhost.5 # """ - cur_base_prompt = super(ExtremeBase, self).set_base_prompt(*args, **kwargs) + cur_base_prompt = super(ExtremeExosBase, self).set_base_prompt(*args, **kwargs) # Strip off any leading * or whitespace chars; strip off trailing period and digits match = re.search(r'[\*\s]*(.*)\.\d+', cur_base_prompt) if match: @@ -51,31 +51,31 @@ def send_command(self, *args, **kwargs): # refresh self.base_prompt self.set_base_prompt() - return super(ExtremeBase, self).send_command(*args, **kwargs) + return super(ExtremeExosBase, self).send_command(*args, **kwargs) def config_mode(self, config_command=''): - """No configuration mode on Extreme.""" + """No configuration mode on Extreme Exos.""" return '' def check_config_mode(self, check_string='#'): """Checks whether in configuration mode. Returns a boolean.""" - return super(ExtremeBase, self).check_config_mode(check_string=check_string) + return super(ExtremeExosBase, self).check_config_mode(check_string=check_string) def exit_config_mode(self, exit_config=''): - """No configuration mode on Extreme.""" + """No configuration mode on Extreme Exos.""" return '' def save_config(self, cmd='save configuration primary', confirm=False): """Saves configuration.""" - return super(ExtremeBase, self).save_config(cmd=cmd, confirm=confirm) + return super(ExtremeExosBase, self).save_config(cmd=cmd, confirm=confirm) -class ExtremeSSH(ExtremeBase): +class ExtremeExosSSH(ExtremeExosBase): pass -class ExtremeTelnet(ExtremeBase): +class ExtremeExosTelnet(ExtremeExosBase): def __init__(self, *args, **kwargs): default_enter = kwargs.get('default_enter') kwargs['default_enter'] = '\r\n' if default_enter is None else default_enter - super(ExtremeTelnet, self).__init__(*args, **kwargs) + super(ExtremeExosTelnet, self).__init__(*args, **kwargs) diff --git a/netmiko/brocade/brocade_netiron.py b/netmiko/extreme/extreme_netiron.py similarity index 60% rename from netmiko/brocade/brocade_netiron.py rename to netmiko/extreme/extreme_netiron.py index 153879cdb..39ad3861b 100644 --- a/netmiko/brocade/brocade_netiron.py +++ b/netmiko/extreme/extreme_netiron.py @@ -2,18 +2,18 @@ from netmiko.cisco_base_connection import CiscoSSHConnection -class BrocadeNetironBase(CiscoSSHConnection): +class ExtremeNetironBase(CiscoSSHConnection): def save_config(self, cmd='write memory', confirm=False): """Save Config""" - return super(BrocadeNetironBase, self).save_config(cmd=cmd, confirm=confirm) + return super(ExtremeNetironBase, self).save_config(cmd=cmd, confirm=confirm) -class BrocadeNetironSSH(BrocadeNetironBase): +class ExtremeNetironSSH(ExtremeNetironBase): pass -class BrocadeNetironTelnet(BrocadeNetironBase): +class ExtremeNetironTelnet(ExtremeNetironBase): def __init__(self, *args, **kwargs): default_enter = kwargs.get('default_enter') kwargs['default_enter'] = '\r\n' if default_enter is None else default_enter - super(BrocadeNetironTelnet, self).__init__(*args, **kwargs) + super(ExtremeNetironTelnet, self).__init__(*args, **kwargs) diff --git a/netmiko/brocade/brocade_nos_ssh.py b/netmiko/extreme/extreme_nos_ssh.py similarity index 69% rename from netmiko/brocade/brocade_nos_ssh.py rename to netmiko/extreme/extreme_nos_ssh.py index 4eb315b31..49135fec1 100644 --- a/netmiko/brocade/brocade_nos_ssh.py +++ b/netmiko/extreme/extreme_nos_ssh.py @@ -1,17 +1,17 @@ -"""Support for Brocade NOS/VDX.""" +"""Support for Extreme NOS/VDX.""" from __future__ import unicode_literals import time from netmiko.cisco_base_connection import CiscoSSHConnection -class BrocadeNosSSH(CiscoSSHConnection): - """Support for Brocade NOS/VDX.""" +class ExtremeNosSSH(CiscoSSHConnection): + """Support for Extreme NOS/VDX.""" def enable(self, *args, **kwargs): - """No enable mode on Brocade VDX.""" + """No enable mode on Extreme VDX.""" pass def exit_enable_mode(self, *args, **kwargs): - """No enable mode on Brocade VDX.""" + """No enable mode on Extreme VDX.""" pass def special_login_handler(self, delay_factor=1): @@ -22,6 +22,6 @@ def special_login_handler(self, delay_factor=1): def save_config(self, cmd='copy running-config startup-config', confirm=True, confirm_response='y'): - """Save Config for Brocade VDX.""" - return super(BrocadeNosSSH, self).save_config(cmd=cmd, confirm=confirm, + """Save Config for Extreme VDX.""" + return super(ExtremeNosSSH, self).save_config(cmd=cmd, confirm=confirm, confirm_response=confirm_response) diff --git a/netmiko/extreme/extreme_slx_ssh.py b/netmiko/extreme/extreme_slx_ssh.py new file mode 100644 index 000000000..74aa91495 --- /dev/null +++ b/netmiko/extreme/extreme_slx_ssh.py @@ -0,0 +1,28 @@ +"""Support for Extreme SLX.""" +from __future__ import unicode_literals +import time +from netmiko.cisco_base_connection import CiscoSSHConnection + + +class ExtremeSlxSSH(CiscoSSHConnection): + """Support for Extreme SLX.""" + def enable(self, *args, **kwargs): + """No enable mode on Extreme SLX.""" + pass + + def exit_enable_mode(self, *args, **kwargs): + """No enable mode on Extreme Slx.""" + pass + + def special_login_handler(self, delay_factor=1): + """Adding a delay after login.""" + delay_factor = self.select_delay_factor(delay_factor) + self.write_channel(self.RETURN) + time.sleep(1 * delay_factor) + + def save_config(self, cmd='copy running-config startup-config', + confirm=True, confirm_response='y'): + """Save Config for Extreme SLX.""" + return super(ExtremeSlxSSH, self).save_config(cmd=cmd, + confirm=confirm, + confirm_response=confirm_response) diff --git a/netmiko/avaya/avaya_vsp_ssh.py b/netmiko/extreme/extreme_vsp_ssh.py similarity index 72% rename from netmiko/avaya/avaya_vsp_ssh.py rename to netmiko/extreme/extreme_vsp_ssh.py index a5cade6c2..daf8e0967 100644 --- a/netmiko/avaya/avaya_vsp_ssh.py +++ b/netmiko/extreme/extreme_vsp_ssh.py @@ -1,12 +1,12 @@ -"""Avaya Virtual Services Platform Support.""" +"""Extreme Virtual Services Platform Support.""" from __future__ import print_function from __future__ import unicode_literals import time from netmiko.cisco_base_connection import CiscoSSHConnection -class AvayaVspSSH(CiscoSSHConnection): - """Avaya Virtual Services Platform Support.""" +class ExtremeVspSSH(CiscoSSHConnection): + """Extreme Virtual Services Platform Support.""" def session_preparation(self): """Prepare the session after the connection has been established.""" self._test_channel_read() @@ -18,4 +18,4 @@ def session_preparation(self): def save_config(self, cmd='save config', confirm=False): """Save Config""" - return super(AvayaVspSSH, self).save_config(cmd=cmd, confirm=confirm) + return super(ExtremeVspSSH, self).save_config(cmd=cmd, confirm=confirm) diff --git a/netmiko/ssh_dispatcher.py b/netmiko/ssh_dispatcher.py index f4a9ce29d..d6a2705dc 100644 --- a/netmiko/ssh_dispatcher.py +++ b/netmiko/ssh_dispatcher.py @@ -9,11 +9,6 @@ from netmiko.arista import AristaFileTransfer from netmiko.apresia import ApresiaAeosSSH, ApresiaAeosTelnet from netmiko.aruba import ArubaSSH -from netmiko.avaya import AvayaErsSSH -from netmiko.avaya import AvayaVspSSH -from netmiko.brocade import BrocadeNetironSSH -from netmiko.brocade import BrocadeNetironTelnet -from netmiko.brocade import BrocadeNosSSH from netmiko.calix import CalixB6SSH, CalixB6Telnet from netmiko.checkpoint import CheckPointGaiaSSH from netmiko.ciena import CienaSaosSSH @@ -33,9 +28,15 @@ from netmiko.dell import DellIsilonSSH from netmiko.eltex import EltexSSH from netmiko.enterasys import EnterasysSSH -from netmiko.extreme import ExtremeSSH +from netmiko.extreme import ExtremeErsSSH +from netmiko.extreme import ExtremeExosSSH +from netmiko.extreme import ExtremeExosTelnet +from netmiko.extreme import ExtremeNetironSSH +from netmiko.extreme import ExtremeNetironTelnet +from netmiko.extreme import ExtremeNosSSH +from netmiko.extreme import ExtremeSlxSSH +from netmiko.extreme import ExtremeVspSSH from netmiko.extreme import ExtremeWingSSH -from netmiko.extreme import ExtremeTelnet from netmiko.f5 import F5LtmSSH from netmiko.fortinet import FortinetSSH from netmiko.hp import HPProcurveSSH, HPProcurveTelnet, HPComwareSSH, HPComwareTelnet @@ -68,12 +69,12 @@ 'apresia_aeos': ApresiaAeosSSH, 'arista_eos': AristaSSH, 'aruba_os': ArubaSSH, - 'avaya_ers': AvayaErsSSH, - 'avaya_vsp': AvayaVspSSH, + 'avaya_ers': ExtremeErsSSH, + 'avaya_vsp': ExtremeVspSSH, 'brocade_fastiron': RuckusFastironSSH, - 'brocade_netiron': BrocadeNetironSSH, - 'brocade_nos': BrocadeNosSSH, - 'brocade_vdx': BrocadeNosSSH, + 'brocade_netiron': ExtremeNetironSSH, + 'brocade_nos': ExtremeNosSSH, + 'brocade_vdx': ExtremeNosSSH, 'brocade_vyos': VyOSSSH, 'checkpoint_gaia': CheckPointGaiaSSH, 'calix_b6': CalixB6SSH, @@ -93,7 +94,14 @@ 'dell_isilon': DellIsilonSSH, 'eltex': EltexSSH, 'enterasys': EnterasysSSH, - 'extreme': ExtremeSSH, + 'extreme': ExtremeExosSSH, + 'extreme_ers': ExtremeErsSSH, + 'extreme_exos': ExtremeExosSSH, + 'extreme_netiron': ExtremeNetironSSH, + 'extreme_nos': ExtremeNosSSH, + 'extreme_slx': ExtremeSlxSSH, + 'extreme_vdx': ExtremeNosSSH, + 'extreme_vsp': ExtremeVspSSH, 'extreme_wing': ExtremeWingSSH, 'f5_ltm': F5LtmSSH, 'fortinet': FortinetSSH, @@ -148,19 +156,21 @@ FILE_TRANSFER_MAP = new_mapper # Add telnet drivers -CLASS_MAPPER['brocade_fastiron_telnet'] = RuckusFastironTelnet -CLASS_MAPPER['brocade_netiron_telnet'] = BrocadeNetironTelnet -CLASS_MAPPER['cisco_ios_telnet'] = CiscoIosTelnet CLASS_MAPPER['apresia_aeos_telnet'] = ApresiaAeosTelnet CLASS_MAPPER['arista_eos_telnet'] = AristaTelnet +CLASS_MAPPER['brocade_fastiron_telnet'] = RuckusFastironTelnet +CLASS_MAPPER['brocade_netiron_telnet'] = ExtremeNetironTelnet +CLASS_MAPPER['calix_b6_telnet'] = CalixB6Telnet +CLASS_MAPPER['cisco_ios_telnet'] = CiscoIosTelnet +CLASS_MAPPER['dell_powerconnect_telnet'] = DellPowerConnectTelnet +CLASS_MAPPER['extreme_telnet'] = ExtremeExosTelnet +CLASS_MAPPER['extreme_exos_telnet'] = ExtremeExosTelnet +CLASS_MAPPER['extreme_netiron_telnet'] = ExtremeNetironTelnet +CLASS_MAPPER['generic_termserver_telnet'] = TerminalServerTelnet CLASS_MAPPER['hp_procurve_telnet'] = HPProcurveTelnet CLASS_MAPPER['hp_comware_telnet'] = HPComwareTelnet CLASS_MAPPER['juniper_junos_telnet'] = JuniperTelnet CLASS_MAPPER['paloalto_panos_telnet'] = PaloAltoPanosTelnet -CLASS_MAPPER['calix_b6_telnet'] = CalixB6Telnet -CLASS_MAPPER['dell_powerconnect_telnet'] = DellPowerConnectTelnet -CLASS_MAPPER['generic_termserver_telnet'] = TerminalServerTelnet -CLASS_MAPPER['extreme_telnet'] = ExtremeTelnet CLASS_MAPPER['ruckus_fastiron_telnet'] = RuckusFastironTelnet # Add serial drivers diff --git a/netmiko/utilities.py b/netmiko/utilities.py index fd7d3896d..e7ea43ee4 100644 --- a/netmiko/utilities.py +++ b/netmiko/utilities.py @@ -15,6 +15,13 @@ 'juniper': 'show configuration', 'juniper_junos': 'show configuration', 'extreme': 'show configuration', + 'extreme_ers': 'show running-config', + 'extreme_exos': 'show configuration', + 'extreme_netiron': 'show running-config', + 'extreme_nos': 'show running-config', + 'extreme_slx': 'show running-config', + 'extreme_vdx': 'show running-config', + 'extreme_vsp': 'show running-config', 'extreme_wing': 'show running-config', 'hp_comware': 'display current-configuration', 'huawei': 'display current-configuration', From aef26db9692ae20bedd0eff30c8a94231eeb7733 Mon Sep 17 00:00:00 2001 From: mvsiva Date: Sun, 29 Jul 2018 08:00:54 -0400 Subject: [PATCH 18/69] updates to support IP Infusion OcNOS for both ssh and telnet connections. --- netmiko/ipinfusion/__init__.py | 4 ++ netmiko/ipinfusion/ipinfusion_ocnos.py | 80 ++++++++++++++++++++++++++ netmiko/ssh_dispatcher.py | 3 + tests/etc/commands.yml.example | 26 +++++++++ tests/etc/responses.yml.example | 22 +++++++ tests/etc/test_devices.yml.example | 15 +++++ tests/test_ipinfusion.sh | 11 ++++ tests/test_ipinfusion_telnet.sh | 11 ++++ 8 files changed, 172 insertions(+) create mode 100644 netmiko/ipinfusion/__init__.py create mode 100644 netmiko/ipinfusion/ipinfusion_ocnos.py create mode 100755 tests/test_ipinfusion.sh create mode 100755 tests/test_ipinfusion_telnet.sh diff --git a/netmiko/ipinfusion/__init__.py b/netmiko/ipinfusion/__init__.py new file mode 100644 index 000000000..1b4fb310e --- /dev/null +++ b/netmiko/ipinfusion/__init__.py @@ -0,0 +1,4 @@ +from __future__ import unicode_literals +from netmiko.ipinfusion.ipinfusion_ocnos import IpinfusionOcnosSSH, IpinfusionOcNOSTelnet + +__all__ = ['IpinfusionOcnosSSH', 'IpinfusionOcNOSTelnet'] diff --git a/netmiko/ipinfusion/ipinfusion_ocnos.py b/netmiko/ipinfusion/ipinfusion_ocnos.py new file mode 100644 index 000000000..c8c92acff --- /dev/null +++ b/netmiko/ipinfusion/ipinfusion_ocnos.py @@ -0,0 +1,80 @@ +from __future__ import unicode_literals +import time +import re +from telnetlib import Telnet, IAC, DO, DONT, WILL, WONT, SB, SE, TTYPE +from netmiko.ssh_exception import NetMikoTimeoutException +from netmiko.cisco_base_connection import CiscoBaseConnection + +class IpinfusionOcnosBase(CiscoBaseConnection): + """Common Methods for IP Infusion OcNOS support.""" + def session_preparation(self): + self._test_channel_read() + self.set_base_prompt() + self.disable_paging(command="terminal length 0") + + # Clear the read buffer + time.sleep(.3 * self.global_delay_factor) + self.clear_buffer() + + def save_config(self, cmd='write', confirm=False): + """Saves Config Using write command""" + return super(IpinfusionOcnosBase, self).save_config(cmd=cmd, confirm=confirm) + + def enable(self, cmd='enable', pattern='ssword', re_flags=re.IGNORECASE): + """Enter enable mode. + + :param cmd: Device command to enter enable mode + :type cmd: str + + :param pattern: pattern to search for indicating device is waiting for password + :type pattern: str + + :param re_flags: Regular expression flags used in conjunction with pattern + :type re_flags: int + """ + output = "" + msg = "Failed to enter enable mode. Please ensure you pass " \ + "the 'secret' argument to ConnectHandler." + if not self.check_enable_mode(): + self.write_channel(self.normalize_cmd(cmd)) + try: + output += self.read_until_prompt_or_pattern(pattern=pattern, re_flags=re_flags) + self.write_channel(self.secret + self.TELNET_RETURN) + output += self.read_until_prompt() + except NetMikoTimeoutException: + raise ValueError(msg) + if not self.check_enable_mode(): + raise ValueError(msg) + return output + +class IpinfusionOcnosSSH(IpinfusionOcnosBase): + """IP Infusion OcNOS SSH driver.""" + pass + +class IpinfusionOcNOSTelnet(IpinfusionOcnosBase): + """IP Infusion OcNOS Telnet driver.""" + + """ + For all telnet options, re-implement the default telnetlib behaviour + and refuse to handle any options. If the server expresses interest in + 'terminal type' option, then reply back with 'xterm' terminal type. + """ + def process_option(self, tsocket, command, option): + if command == DO and option == TTYPE: + tsocket.sendall(IAC + WILL + TTYPE) + tsocket.sendall(IAC + SB + TTYPE + b'\0' + b'xterm' + IAC + SE) + elif command in (DO, DONT): + tsocket.sendall(IAC + WONT + option) + elif command in (WILL, WONT): + tsocket.sendall(IAC + DONT + option) + + def telnet_login(self, pri_prompt_terminator='#', alt_prompt_terminator='>', + username_pattern=r"(?:user:|sername|login|user name)", pwd_pattern=r"assword:", + delay_factor=1, max_loops=20): + #set callback function to handle telnet options. + self.remote_conn.set_option_negotiation_callback(self.process_option) + return super(IpinfusionOcNOSTelnet, self).telnet_login( + pri_prompt_terminator=pri_prompt_terminator, + alt_prompt_terminator=alt_prompt_terminator, + username_pattern=username_pattern, pwd_pattern=pwd_pattern, + delay_factor=delay_factor, max_loops=max_loops) diff --git a/netmiko/ssh_dispatcher.py b/netmiko/ssh_dispatcher.py index f4a9ce29d..22268099c 100644 --- a/netmiko/ssh_dispatcher.py +++ b/netmiko/ssh_dispatcher.py @@ -40,6 +40,7 @@ from netmiko.fortinet import FortinetSSH from netmiko.hp import HPProcurveSSH, HPProcurveTelnet, HPComwareSSH, HPComwareTelnet from netmiko.huawei import HuaweiSSH, HuaweiVrpv8SSH +from netmiko.ipinfusion import IpinfusionOcnosSSH, IpinfusionOcNOSTelnet from netmiko.juniper import JuniperSSH, JuniperTelnet from netmiko.juniper import JuniperFileTransfer from netmiko.linux import LinuxSSH, LinuxFileTransfer @@ -102,6 +103,7 @@ 'hp_procurve': HPProcurveSSH, 'huawei': HuaweiSSH, 'huawei_vrpv8': HuaweiVrpv8SSH, + 'ipinfusion_ocnos': IpinfusionOcnosSSH, 'juniper': JuniperSSH, 'juniper_junos': JuniperSSH, 'linux': LinuxSSH, @@ -155,6 +157,7 @@ CLASS_MAPPER['arista_eos_telnet'] = AristaTelnet CLASS_MAPPER['hp_procurve_telnet'] = HPProcurveTelnet CLASS_MAPPER['hp_comware_telnet'] = HPComwareTelnet +CLASS_MAPPER['ipinfusion_ocnos_telnet'] = IpinfusionOcNOSTelnet CLASS_MAPPER['juniper_junos_telnet'] = JuniperTelnet CLASS_MAPPER['paloalto_panos_telnet'] = PaloAltoPanosTelnet CLASS_MAPPER['calix_b6_telnet'] = CalixB6Telnet diff --git a/tests/etc/commands.yml.example b/tests/etc/commands.yml.example index 079c68208..b41f8852a 100644 --- a/tests/etc/commands.yml.example +++ b/tests/etc/commands.yml.example @@ -182,3 +182,29 @@ calix_b6_ssh: - "access-list ethernet 999 permit ip" - "access-list ethernet 999 permit arp" config_verification: "find running-config 999" + +ipinfusion_ocnos: + version: "show version" + basic: "show ip interface eth0 brief" + extended_output: "show ip interface brief" # requires paging to be disabled + config: + - "logging level ospf 4" # base command + - "no logging level ospf" + - "logging level ospf 5" # something you can verify has changed + config_verification: "show logging level ospf" + save_config_cmd: 'write' + save_config_confirm: False + save_config_response: "[OK]" + +ipinfusion_ocnos_telnet: + version: "show version" + basic: "show ip interface eth0 brief" + extended_output: "show ip interface brief" # requires paging to be disabled + config: + - "logging level ospf 4" # base command + - "no logging level ospf" + - "logging level ospf 5" # something you can verify has changed + config_verification: "show logging level ospf" + save_config_cmd: 'write' + save_config_confirm: False + save_config_response: "[OK]" diff --git a/tests/etc/responses.yml.example b/tests/etc/responses.yml.example index 37afab419..767d63f2a 100644 --- a/tests/etc/responses.yml.example +++ b/tests/etc/responses.yml.example @@ -133,3 +133,25 @@ calix_b6_ssh: multiple_line_output: "rtcPwrUptimeTotal" cmd_response_init: "Building configuration... Done" cmd_response_final: "access-list ethernet 999 permit ip" + +ipinfusion_ocnos: + base_prompt: rtr1 + router_prompt: rtr1> + enable_prompt: rtr1# + interface_ip: 10.12.39.34 + version_banner: "Software Product: OcNOS" + multiple_line_output: "lo 127.0.0.1" + cmd_response_init: "ospfd 2 4" + cmd_response_final: "ospfd 2 5" + save_config: '[OK]' + +ipinfusion_ocnos_telnet: + base_prompt: rtr1 + router_prompt: rtr1> + enable_prompt: rtr1# + interface_ip: 10.12.39.34 + version_banner: "Software Product: OcNOS" + multiple_line_output: "lo 127.0.0.1" + cmd_response_init: "ospfd 2 4" + cmd_response_final: "ospfd 2 5" + save_config: '[OK]' diff --git a/tests/etc/test_devices.yml.example b/tests/etc/test_devices.yml.example index d322da5be..18161b2d9 100644 --- a/tests/etc/test_devices.yml.example +++ b/tests/etc/test_devices.yml.example @@ -119,3 +119,18 @@ calix_b6_ssh: username: cli password: occam secret: razor + +ipinfusion_ocnos: + device_type: ipinfusion_ocnos + ip: 10.12.39.34 + username: ocnos + password: ocnos + secret: ocnos + +ipinfusion_ocnos_telnet: + device_type: ipinfusion_ocnos_telnet + ip: 10.12.39.34 + username: ocnos + password: ocnos + secret: ocnos + diff --git a/tests/test_ipinfusion.sh b/tests/test_ipinfusion.sh new file mode 100755 index 000000000..26dbffaf7 --- /dev/null +++ b/tests/test_ipinfusion.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +RETURN_CODE=0 + +# Exit on the first test failure and set RETURN_CODE = 1 +echo "Starting tests...good luck:" \ +&& py.test -v test_netmiko_show.py --test_device ipinfusion_ocnos \ +&& py.test -v test_netmiko_config.py --test_device ipinfusion_ocnos \ +|| RETURN_CODE=1 + +exit $RETURN_CODE diff --git a/tests/test_ipinfusion_telnet.sh b/tests/test_ipinfusion_telnet.sh new file mode 100755 index 000000000..3a8a862e6 --- /dev/null +++ b/tests/test_ipinfusion_telnet.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +RETURN_CODE=0 + +# Exit on the first test failure and set RETURN_CODE = 1 +echo "Starting tests...good luck:" \ +&& py.test -v test_netmiko_show.py --test_device ipinfusion_ocnos_telnet \ +&& py.test -v test_netmiko_config.py --test_device ipinfusion_ocnos_telnet \ +|| RETURN_CODE=1 + +exit $RETURN_CODE From ddae41e902778a96d2f487510dc60a8a4737ea8e Mon Sep 17 00:00:00 2001 From: mvsiva Date: Sun, 29 Jul 2018 09:04:26 -0400 Subject: [PATCH 19/69] removed pylama error and warnings. --- netmiko/ipinfusion/ipinfusion_ocnos.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/netmiko/ipinfusion/ipinfusion_ocnos.py b/netmiko/ipinfusion/ipinfusion_ocnos.py index c8c92acff..2aa56353a 100644 --- a/netmiko/ipinfusion/ipinfusion_ocnos.py +++ b/netmiko/ipinfusion/ipinfusion_ocnos.py @@ -1,10 +1,11 @@ from __future__ import unicode_literals import time import re -from telnetlib import Telnet, IAC, DO, DONT, WILL, WONT, SB, SE, TTYPE +from telnetlib import IAC, DO, DONT, WILL, WONT, SB, SE, TTYPE from netmiko.ssh_exception import NetMikoTimeoutException from netmiko.cisco_base_connection import CiscoBaseConnection + class IpinfusionOcnosBase(CiscoBaseConnection): """Common Methods for IP Infusion OcNOS support.""" def session_preparation(self): @@ -47,10 +48,12 @@ def enable(self, cmd='enable', pattern='ssword', re_flags=re.IGNORECASE): raise ValueError(msg) return output + class IpinfusionOcnosSSH(IpinfusionOcnosBase): """IP Infusion OcNOS SSH driver.""" pass + class IpinfusionOcNOSTelnet(IpinfusionOcnosBase): """IP Infusion OcNOS Telnet driver.""" @@ -71,7 +74,7 @@ def process_option(self, tsocket, command, option): def telnet_login(self, pri_prompt_terminator='#', alt_prompt_terminator='>', username_pattern=r"(?:user:|sername|login|user name)", pwd_pattern=r"assword:", delay_factor=1, max_loops=20): - #set callback function to handle telnet options. + # set callback function to handle telnet options. self.remote_conn.set_option_negotiation_callback(self.process_option) return super(IpinfusionOcNOSTelnet, self).telnet_login( pri_prompt_terminator=pri_prompt_terminator, From 9192366c2f15155304a8326c85847c04292536b6 Mon Sep 17 00:00:00 2001 From: Stephen Kiely Date: Mon, 30 Jul 2018 22:41:16 -0500 Subject: [PATCH 20/69] Use base_connection telnet_login instead of custom login Found that the default telnet_login will work with the RADs after changing the TELNET_RETURN to the regular Return. Also added in the Userprompt for the RAD. --- netmiko/rad/rad_etx.py | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/netmiko/rad/rad_etx.py b/netmiko/rad/rad_etx.py index d7f28873e..fb95133c8 100644 --- a/netmiko/rad/rad_etx.py +++ b/netmiko/rad/rad_etx.py @@ -62,7 +62,7 @@ class RadETXSSH(RadETXBase): class RadETXTelnet(RadETXBase): """RAD ETX Telnet Support.""" - def telnet_login(self, delay_factor=1): + def telnet_login(self, username_pattern=r"(?:user>)"): """ RAD presents with the following on login @@ -70,20 +70,6 @@ def telnet_login(self, delay_factor=1): password> **** """ - delay_factor = self.select_delay_factor(delay_factor) - i = 0 - time.sleep(delay_factor * .5) - output = "" - while i <= 12: - output = self.read_channel() - if output: - if 'user>' in output: - self.write_channel(self.username + self.RETURN) - elif 'password>' in output: - self.write_channel(self.password + self.RETURN) - break - time.sleep(delay_factor * 1) - else: - self.write_channel(self.RETURN) - time.sleep(delay_factor * 1.5) - i += 1 + self.TELNET_RETURN = self.RETURN + return super(RadETXTelnet, + self).telnet_login(username_pattern=username_pattern) From bd907f52f5cb015f315bc9717a142b2240d6a261 Mon Sep 17 00:00:00 2001 From: Stephen Kiely Date: Tue, 31 Jul 2018 10:44:09 -0500 Subject: [PATCH 21/69] Correct issue with matching > on RAD ETX The RAD software uses user> and password> for the username and password prompt. The default alternative_prompt_terminator was catching the these prompts and exiting the while loop prematurely. --- netmiko/rad/rad_etx.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/netmiko/rad/rad_etx.py b/netmiko/rad/rad_etx.py index fb95133c8..cbf8860b7 100644 --- a/netmiko/rad/rad_etx.py +++ b/netmiko/rad/rad_etx.py @@ -62,7 +62,8 @@ class RadETXSSH(RadETXBase): class RadETXTelnet(RadETXBase): """RAD ETX Telnet Support.""" - def telnet_login(self, username_pattern=r"(?:user>)"): + def telnet_login(self, username_pattern=r"(?:user>)", + alt_prompt_term=r"#\s*$"): """ RAD presents with the following on login @@ -72,4 +73,5 @@ def telnet_login(self, username_pattern=r"(?:user>)"): """ self.TELNET_RETURN = self.RETURN return super(RadETXTelnet, - self).telnet_login(username_pattern=username_pattern) + self).telnet_login(username_pattern=username_pattern, + alt_prompt_terminator=alt_prompt_term) From 0196e9724547cea17f9e5df5bda7e9e5874dedf7 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Tue, 31 Jul 2018 14:13:25 -0700 Subject: [PATCH 22/69] Add SROS enable mode support --- netmiko/alcatel/alcatel_sros_ssh.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/netmiko/alcatel/alcatel_sros_ssh.py b/netmiko/alcatel/alcatel_sros_ssh.py index 21ec9cf0b..192bb3b5b 100644 --- a/netmiko/alcatel/alcatel_sros_ssh.py +++ b/netmiko/alcatel/alcatel_sros_ssh.py @@ -25,7 +25,33 @@ def set_base_prompt(self, *args, **kwargs): self.base_prompt = match.group(1) return self.base_prompt - def enable(self, *args, **kwargs): + def enable(self, cmd='enable-admin', pattern='ssword', re_flags=re.IGNORECASE): + """Enter enable mode.""" + return super(AlcatelSrosSSH, self).enable(cmd=cmd, pattern=pattern, re_flags=re_flags) + + def check_enable_mode(self, check_string='CLI Already in admin mode'): + """Check whether we are in enable-admin mode. + SROS requires us to do this: + *A:HOSTNAME# enable-admin + MINOR: CLI Already in admin mode. + *A:HOSTNAME# + *A:HOSTNAME# enable-admin + Password: + MINOR: CLI Invalid password. + *A:HOSTNAME# + """ + output = self.send_command_timing('enable-admin') + if re.search(r"ssword", output): + # Just hit enter as we don't actually want to enter enable here + self.write_channel(self.normalize_cmd(self.RETURN)) + self.read_until_prompt() + return False + elif check_string in output: + return True + raise ValueError("Unexpected response in check_enable_mode() method") + + def exit_enable_mode(self, exit_command=''): + """No corresponding exit of enable mode on SROS.""" pass def config_mode(self, config_command='configure', pattern='#'): From 37b8cdf40b482e014128c138f5595ab8cf371b23 Mon Sep 17 00:00:00 2001 From: mvsiva Date: Thu, 2 Aug 2018 14:27:31 -0400 Subject: [PATCH 23/69] corrected the test script file and added parameter save_config_response for save_config function of Ipinfusion ocnos --- netmiko/ipinfusion/ipinfusion_ocnos.py | 5 +++-- tests/test_netmiko_config.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/netmiko/ipinfusion/ipinfusion_ocnos.py b/netmiko/ipinfusion/ipinfusion_ocnos.py index 2aa56353a..11bfb747b 100644 --- a/netmiko/ipinfusion/ipinfusion_ocnos.py +++ b/netmiko/ipinfusion/ipinfusion_ocnos.py @@ -17,9 +17,10 @@ def session_preparation(self): time.sleep(.3 * self.global_delay_factor) self.clear_buffer() - def save_config(self, cmd='write', confirm=False): + def save_config(self, cmd='write', confirm=False, confirm_response=''): """Saves Config Using write command""" - return super(IpinfusionOcnosBase, self).save_config(cmd=cmd, confirm=confirm) + return super(IpinfusionOcnosBase, self).save_config( + cmd=cmd, confirm=confirm, confirm_response=confirm_response) def enable(self, cmd='enable', pattern='ssword', re_flags=re.IGNORECASE): """Enter enable mode. diff --git a/tests/test_netmiko_config.py b/tests/test_netmiko_config.py index c317a0863..644b21920 100755 --- a/tests/test_netmiko_config.py +++ b/tests/test_netmiko_config.py @@ -122,7 +122,7 @@ def test_save_confirm(net_connect, commands, expected_responses): confirm = commands['save_config_confirm'] save_verify = expected_responses['save_config'] - cmd_response = net_connect.save_config(confirm) + cmd_response = net_connect.save_config(confirm=confirm) assert save_verify in cmd_response def test_save_response(net_connect, commands, expected_responses): From 157074f4fd3990bd7d0b39b0de7c8c8817b928d6 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Sun, 5 Aug 2018 09:25:36 -0700 Subject: [PATCH 24/69] Decouple netmiko save tests from config tests --- tests/test_netmiko_config.py | 86 ------------------------------------ tests/test_netmiko_save.py | 74 +++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 86 deletions(-) create mode 100755 tests/test_netmiko_save.py diff --git a/tests/test_netmiko_config.py b/tests/test_netmiko_config.py index c317a0863..237627f95 100755 --- a/tests/test_netmiko_config.py +++ b/tests/test_netmiko_config.py @@ -1,25 +1,4 @@ #!/usr/bin/env python -""" -This module runs tests against Cisco IOS devices. - -setup_module: setup variables for later use. - -test_ssh_connect: verify ssh connectivity -test_enable_mode: verify enter enable mode -test_config_mode: verify enter config mode -test_exit_config_mode: verify exit config mode -test_command_set: verify sending a set of config commands -test_commands_from_file: verify sending a set of config commands from a file -test_save_base: verify save config with default values -test_save_confirm: verify save config with confirm -test_save_response: verify save config with response -test_save_cmd: verify save config with cmd -test_save_confirm_response: verify save config with confirm and confirm response -test_save_all: verify save config with all options -test_disconnect: cleanly disconnect the SSH session - -""" - from __future__ import print_function from __future__ import unicode_literals @@ -106,74 +85,9 @@ def test_commands_from_file(net_connect, commands, expected_responses): else: print("Skipping test (no file specified)...",) -def test_save_base(net_connect, commands, expected_responses): - ''' - Test save config with no options. - ''' - save_verify = expected_responses['save_config'] - - cmd_response = net_connect.save_config() - assert save_verify in cmd_response - -def test_save_confirm(net_connect, commands, expected_responses): - ''' - Test save config with the confirm parameter. - ''' - confirm = commands['save_config_confirm'] - save_verify = expected_responses['save_config'] - - cmd_response = net_connect.save_config(confirm) - assert save_verify in cmd_response - -def test_save_response(net_connect, commands, expected_responses): - ''' - Test save config with the confirm response parameter. - ''' - confirm_response = commands['save_config_response'] - save_verify = expected_responses['save_config'] - - cmd_response = net_connect.save_config(confirm_response=confirm_response) - assert save_verify in cmd_response - -def test_save_cmd(net_connect, commands, expected_responses): - ''' - Test save config with cmd parameter. - ''' - cmd = commands['save_config_cmd'] - save_verify = expected_responses['save_config'] - - cmd_response = net_connect.save_config(cmd=cmd) - assert save_verify in cmd_response - -def test_save_confirm_response(net_connect, commands, expected_responses): - ''' - Test save config with confirm and confirm response parameters - ''' - confirm = commands['save_config_confirm'] - confirm_response = commands['save_config_response'] - save_verify = expected_responses['save_config'] - - cmd_response = net_connect.save_config(confirm=confirm, - confirm_response=confirm_response) - assert save_verify in cmd_response - -def test_save_all(net_connect, commands, expected_responses): - ''' - Test the save config method with all additional parameters. - ''' - cmd = commands['save_config_cmd'] - confirm = commands['save_config_confirm'] - confirm_response = commands['save_config_response'] - save_verify = expected_responses['save_config'] - - cmd_response = net_connect.save_config(cmd=cmd, confirm=confirm, - confirm_response=confirm_response) - assert save_verify in cmd_response def test_disconnect(net_connect, commands, expected_responses): ''' Terminate the SSH session ''' net_connect.disconnect() - - diff --git a/tests/test_netmiko_save.py b/tests/test_netmiko_save.py new file mode 100755 index 000000000..9be4acdae --- /dev/null +++ b/tests/test_netmiko_save.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python +from __future__ import print_function +from __future__ import unicode_literals + + +def test_save_base(net_connect, commands, expected_responses): + ''' + Test save config with no options. + ''' + save_verify = expected_responses['save_config'] + + cmd_response = net_connect.save_config() + assert save_verify in cmd_response + +def test_save_confirm(net_connect, commands, expected_responses): + ''' + Test save config with the confirm parameter. + ''' + confirm = commands['save_config_confirm'] + save_verify = expected_responses['save_config'] + + cmd_response = net_connect.save_config(confirm) + assert save_verify in cmd_response + +def test_save_response(net_connect, commands, expected_responses): + ''' + Test save config with the confirm response parameter. + ''' + confirm_response = commands['save_config_response'] + save_verify = expected_responses['save_config'] + + cmd_response = net_connect.save_config(confirm_response=confirm_response) + assert save_verify in cmd_response + +def test_save_cmd(net_connect, commands, expected_responses): + ''' + Test save config with cmd parameter. + ''' + cmd = commands['save_config_cmd'] + save_verify = expected_responses['save_config'] + + cmd_response = net_connect.save_config(cmd=cmd) + assert save_verify in cmd_response + +def test_save_confirm_response(net_connect, commands, expected_responses): + ''' + Test save config with confirm and confirm response parameters + ''' + confirm = commands['save_config_confirm'] + confirm_response = commands['save_config_response'] + save_verify = expected_responses['save_config'] + + cmd_response = net_connect.save_config(confirm=confirm, + confirm_response=confirm_response) + assert save_verify in cmd_response + +def test_save_all(net_connect, commands, expected_responses): + ''' + Test the save config method with all additional parameters. + ''' + cmd = commands['save_config_cmd'] + confirm = commands['save_config_confirm'] + confirm_response = commands['save_config_response'] + save_verify = expected_responses['save_config'] + + cmd_response = net_connect.save_config(cmd=cmd, confirm=confirm, + confirm_response=confirm_response) + assert save_verify in cmd_response + +def test_disconnect(net_connect, commands, expected_responses): + ''' + Terminate the SSH session + ''' + net_connect.disconnect() From 36c2ab7058c26ebce364f6c2739c1b14cd358b18 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Sun, 5 Aug 2018 14:09:16 -0700 Subject: [PATCH 25/69] Updates to ipinfusion driver --- netmiko/ipinfusion/__init__.py | 4 +- netmiko/ipinfusion/ipinfusion_ocnos.py | 58 ++++++++------------------ netmiko/ssh_dispatcher.py | 6 +-- 3 files changed, 22 insertions(+), 46 deletions(-) diff --git a/netmiko/ipinfusion/__init__.py b/netmiko/ipinfusion/__init__.py index 1b4fb310e..66158c272 100644 --- a/netmiko/ipinfusion/__init__.py +++ b/netmiko/ipinfusion/__init__.py @@ -1,4 +1,4 @@ from __future__ import unicode_literals -from netmiko.ipinfusion.ipinfusion_ocnos import IpinfusionOcnosSSH, IpinfusionOcNOSTelnet +from netmiko.ipinfusion.ipinfusion_ocnos import IpInfusionOcNOSSSH, IpInfusionOcNOSTelnet -__all__ = ['IpinfusionOcnosSSH', 'IpinfusionOcNOSTelnet'] +__all__ = ['IpInfusionOcNOSSSH', 'IpInfusionOcNOSTelnet'] diff --git a/netmiko/ipinfusion/ipinfusion_ocnos.py b/netmiko/ipinfusion/ipinfusion_ocnos.py index 11bfb747b..2cccd4121 100644 --- a/netmiko/ipinfusion/ipinfusion_ocnos.py +++ b/netmiko/ipinfusion/ipinfusion_ocnos.py @@ -1,13 +1,16 @@ from __future__ import unicode_literals import time -import re from telnetlib import IAC, DO, DONT, WILL, WONT, SB, SE, TTYPE -from netmiko.ssh_exception import NetMikoTimeoutException from netmiko.cisco_base_connection import CiscoBaseConnection -class IpinfusionOcnosBase(CiscoBaseConnection): +class IpInfusionOcNOSBase(CiscoBaseConnection): """Common Methods for IP Infusion OcNOS support.""" + def __init__(self, **kwargs): + if kwargs.get('default_enter') is not None: + kwargs['default_enter'] = '\r\n' + return super(IpInfusionOcNOSBase, self).__init__(**kwargs) + def session_preparation(self): self._test_channel_read() self.set_base_prompt() @@ -19,51 +22,24 @@ def session_preparation(self): def save_config(self, cmd='write', confirm=False, confirm_response=''): """Saves Config Using write command""" - return super(IpinfusionOcnosBase, self).save_config( + return super(IpInfusionOcNOSBase, self).save_config( cmd=cmd, confirm=confirm, confirm_response=confirm_response) - def enable(self, cmd='enable', pattern='ssword', re_flags=re.IGNORECASE): - """Enter enable mode. - - :param cmd: Device command to enter enable mode - :type cmd: str - - :param pattern: pattern to search for indicating device is waiting for password - :type pattern: str - - :param re_flags: Regular expression flags used in conjunction with pattern - :type re_flags: int - """ - output = "" - msg = "Failed to enter enable mode. Please ensure you pass " \ - "the 'secret' argument to ConnectHandler." - if not self.check_enable_mode(): - self.write_channel(self.normalize_cmd(cmd)) - try: - output += self.read_until_prompt_or_pattern(pattern=pattern, re_flags=re_flags) - self.write_channel(self.secret + self.TELNET_RETURN) - output += self.read_until_prompt() - except NetMikoTimeoutException: - raise ValueError(msg) - if not self.check_enable_mode(): - raise ValueError(msg) - return output - -class IpinfusionOcnosSSH(IpinfusionOcnosBase): +class IpInfusionOcNOSSSH(IpInfusionOcNOSBase): """IP Infusion OcNOS SSH driver.""" pass -class IpinfusionOcNOSTelnet(IpinfusionOcnosBase): +class IpInfusionOcNOSTelnet(IpInfusionOcNOSBase): """IP Infusion OcNOS Telnet driver.""" - """ - For all telnet options, re-implement the default telnetlib behaviour - and refuse to handle any options. If the server expresses interest in - 'terminal type' option, then reply back with 'xterm' terminal type. - """ - def process_option(self, tsocket, command, option): + def _process_option(self, tsocket, command, option): + """ + For all telnet options, re-implement the default telnetlib behaviour + and refuse to handle any options. If the server expresses interest in + 'terminal type' option, then reply back with 'xterm' terminal type. + """ if command == DO and option == TTYPE: tsocket.sendall(IAC + WILL + TTYPE) tsocket.sendall(IAC + SB + TTYPE + b'\0' + b'xterm' + IAC + SE) @@ -76,8 +52,8 @@ def telnet_login(self, pri_prompt_terminator='#', alt_prompt_terminator='>', username_pattern=r"(?:user:|sername|login|user name)", pwd_pattern=r"assword:", delay_factor=1, max_loops=20): # set callback function to handle telnet options. - self.remote_conn.set_option_negotiation_callback(self.process_option) - return super(IpinfusionOcNOSTelnet, self).telnet_login( + self.remote_conn.set_option_negotiation_callback(self._process_option) + return super(IpInfusionOcNOSTelnet, self).telnet_login( pri_prompt_terminator=pri_prompt_terminator, alt_prompt_terminator=alt_prompt_terminator, username_pattern=username_pattern, pwd_pattern=pwd_pattern, diff --git a/netmiko/ssh_dispatcher.py b/netmiko/ssh_dispatcher.py index 22268099c..820435bb9 100644 --- a/netmiko/ssh_dispatcher.py +++ b/netmiko/ssh_dispatcher.py @@ -40,7 +40,7 @@ from netmiko.fortinet import FortinetSSH from netmiko.hp import HPProcurveSSH, HPProcurveTelnet, HPComwareSSH, HPComwareTelnet from netmiko.huawei import HuaweiSSH, HuaweiVrpv8SSH -from netmiko.ipinfusion import IpinfusionOcnosSSH, IpinfusionOcNOSTelnet +from netmiko.ipinfusion import IpInfusionOcNOSSSH, IpInfusionOcNOSTelnet from netmiko.juniper import JuniperSSH, JuniperTelnet from netmiko.juniper import JuniperFileTransfer from netmiko.linux import LinuxSSH, LinuxFileTransfer @@ -103,7 +103,7 @@ 'hp_procurve': HPProcurveSSH, 'huawei': HuaweiSSH, 'huawei_vrpv8': HuaweiVrpv8SSH, - 'ipinfusion_ocnos': IpinfusionOcnosSSH, + 'ipinfusion_ocnos': IpInfusionOcNOSSSH, 'juniper': JuniperSSH, 'juniper_junos': JuniperSSH, 'linux': LinuxSSH, @@ -157,7 +157,7 @@ CLASS_MAPPER['arista_eos_telnet'] = AristaTelnet CLASS_MAPPER['hp_procurve_telnet'] = HPProcurveTelnet CLASS_MAPPER['hp_comware_telnet'] = HPComwareTelnet -CLASS_MAPPER['ipinfusion_ocnos_telnet'] = IpinfusionOcNOSTelnet +CLASS_MAPPER['ipinfusion_ocnos_telnet'] = IpInfusionOcNOSTelnet CLASS_MAPPER['juniper_junos_telnet'] = JuniperTelnet CLASS_MAPPER['paloalto_panos_telnet'] = PaloAltoPanosTelnet CLASS_MAPPER['calix_b6_telnet'] = CalixB6Telnet From d79887e8b9561eb2d6c94e497cde3abe9bd0ccd4 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Sun, 5 Aug 2018 14:16:37 -0700 Subject: [PATCH 26/69] Update README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index eda987b9e..ac58f085c 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ Dell OS10 Dell-Force10 Dell PowerConnect Huawei +IP Infusion OcNOS Mellanox NetApp cDOT Palo Alto PAN-OS From f62cbe7952c9a0eb3a2c758d97704d409fdf500e Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Sun, 5 Aug 2018 14:21:21 -0700 Subject: [PATCH 27/69] Fixing logic error in ipinfusion driver --- netmiko/ipinfusion/ipinfusion_ocnos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netmiko/ipinfusion/ipinfusion_ocnos.py b/netmiko/ipinfusion/ipinfusion_ocnos.py index 2cccd4121..20e0dd283 100644 --- a/netmiko/ipinfusion/ipinfusion_ocnos.py +++ b/netmiko/ipinfusion/ipinfusion_ocnos.py @@ -7,7 +7,7 @@ class IpInfusionOcNOSBase(CiscoBaseConnection): """Common Methods for IP Infusion OcNOS support.""" def __init__(self, **kwargs): - if kwargs.get('default_enter') is not None: + if kwargs.get('default_enter') is None: kwargs['default_enter'] = '\r\n' return super(IpInfusionOcNOSBase, self).__init__(**kwargs) From 86ea771f137cef91aa7d02de6b6ba14f6442389f Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Mon, 6 Aug 2018 10:40:23 -0700 Subject: [PATCH 28/69] Fix for enter issue --- netmiko/ipinfusion/ipinfusion_ocnos.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/netmiko/ipinfusion/ipinfusion_ocnos.py b/netmiko/ipinfusion/ipinfusion_ocnos.py index 20e0dd283..209e62915 100644 --- a/netmiko/ipinfusion/ipinfusion_ocnos.py +++ b/netmiko/ipinfusion/ipinfusion_ocnos.py @@ -7,8 +7,9 @@ class IpInfusionOcNOSBase(CiscoBaseConnection): """Common Methods for IP Infusion OcNOS support.""" def __init__(self, **kwargs): - if kwargs.get('default_enter') is None: + if kwargs.get('default_enter') is None and kwargs.get('response_return') is None: kwargs['default_enter'] = '\r\n' + kwargs['response_return'] = '\r\n' return super(IpInfusionOcNOSBase, self).__init__(**kwargs) def session_preparation(self): From 2640137d564be207d5bbf9713b8a3949b7c5ced9 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Wed, 8 Aug 2018 15:47:27 -0700 Subject: [PATCH 29/69] IPInfusion enable + enter issue --- netmiko/aruba/aruba_ssh.py | 5 +++++ netmiko/ipinfusion/ipinfusion_ocnos.py | 5 ++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/netmiko/aruba/aruba_ssh.py b/netmiko/aruba/aruba_ssh.py index 98e929b29..b5ecf7f81 100644 --- a/netmiko/aruba/aruba_ssh.py +++ b/netmiko/aruba/aruba_ssh.py @@ -7,6 +7,11 @@ class ArubaSSH(CiscoSSHConnection): """Aruba OS support""" + def __init__(self, **kwargs): + if kwargs.get('default_enter') is None: + kwargs['default_enter'] = '\r' + return super(ArubaSSH, self).__init__(**kwargs) + def session_preparation(self): """Aruba OS requires enable mode to disable paging.""" delay_factor = self.select_delay_factor(delay_factor=0) diff --git a/netmiko/ipinfusion/ipinfusion_ocnos.py b/netmiko/ipinfusion/ipinfusion_ocnos.py index 209e62915..0ed24f045 100644 --- a/netmiko/ipinfusion/ipinfusion_ocnos.py +++ b/netmiko/ipinfusion/ipinfusion_ocnos.py @@ -7,9 +7,8 @@ class IpInfusionOcNOSBase(CiscoBaseConnection): """Common Methods for IP Infusion OcNOS support.""" def __init__(self, **kwargs): - if kwargs.get('default_enter') is None and kwargs.get('response_return') is None: - kwargs['default_enter'] = '\r\n' - kwargs['response_return'] = '\r\n' + if kwargs.get('default_enter') is None: + kwargs['default_enter'] = '\r' return super(IpInfusionOcNOSBase, self).__init__(**kwargs) def session_preparation(self): From 0e815e1d3d03e472bbe71901201e16a995cf9506 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Wed, 8 Aug 2018 16:06:21 -0700 Subject: [PATCH 30/69] Updating README --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index af862bb3b..203efbe90 100644 --- a/README.md +++ b/README.md @@ -41,10 +41,10 @@ Cisco WLC Dell OS10 Dell-Force10 Dell PowerConnect -Extreme ERS -Extreme VSP -Extreme VDX -Extreme MLX/NetIron +Extreme ERS (Avaya) +Extreme VSP (Avaya) +Extreme VDX (Brocade) +Extreme MLX/NetIron (Brocade/Foundry) Huawei IP Infusion OcNOS Mellanox @@ -70,7 +70,7 @@ Eltex Enterasys Extreme EXOS Extreme Wing -Extreme SLX +Extreme SLX (Brocade) F5 LTM Fortinet MRV Communications OptiSwitch From a6f1145a4ae21fea6782dc1ae411ccf0eed5d0c3 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Wed, 8 Aug 2018 16:23:18 -0700 Subject: [PATCH 31/69] Fix ASA terminal width issue --- netmiko/cisco/cisco_asa_ssh.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netmiko/cisco/cisco_asa_ssh.py b/netmiko/cisco/cisco_asa_ssh.py index ce46bf6c2..30476c4a3 100644 --- a/netmiko/cisco/cisco_asa_ssh.py +++ b/netmiko/cisco/cisco_asa_ssh.py @@ -17,7 +17,7 @@ def session_preparation(self): else: self.asa_login() self.disable_paging(command="terminal pager 0") - self.set_terminal_width(command="terminal width 511") + self.send_config_set("terminal width 511") # Clear the read buffer time.sleep(.3 * self.global_delay_factor) self.clear_buffer() From bacfeb08612e85b324915c6a7f358b734476fb03 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Wed, 8 Aug 2018 16:37:02 -0700 Subject: [PATCH 32/69] Update README --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 203efbe90..9323bbeba 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,11 @@ pynet-rtr1(config)#end pynet-rtr1# ``` +#### Note, Netmiko in certain situations will automatically execute configuration changes to change terminal settings. + +For example, if a platform requires a configuration mode change to disable output paging or to set the terminal width. Netmiko, will generally not attempt to track state on these settings (so your program would need to reset it to the value you require, if you are permanently saving the configuration). + + ## Questions/Discussion If you find an issue with Netmiko, then you can open an issue on this projects issue page here: [https://github.com/ktbyers/netmiko/issues](https://github.com/ktbyers/netmiko/issues) From e72c9105343317412cbf31c9aa53f70b5481b5fa Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Wed, 8 Aug 2018 17:04:38 -0700 Subject: [PATCH 33/69] Fix ASA terminal width issue; add argument for auto change configuration --- README.md | 4 ---- netmiko/apresia/apresia_aeos.py | 2 +- netmiko/base_connection.py | 7 ++++++- netmiko/cisco/cisco_asa_ssh.py | 8 +++++++- netmiko/ipinfusion/ipinfusion_ocnos.py | 2 +- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 9323bbeba..69237e077 100644 --- a/README.md +++ b/README.md @@ -160,10 +160,6 @@ pynet-rtr1(config)#end pynet-rtr1# ``` -#### Note, Netmiko in certain situations will automatically execute configuration changes to change terminal settings. - -For example, if a platform requires a configuration mode change to disable output paging or to set the terminal width. Netmiko, will generally not attempt to track state on these settings (so your program would need to reset it to the value you require, if you are permanently saving the configuration). - ## Questions/Discussion diff --git a/netmiko/apresia/apresia_aeos.py b/netmiko/apresia/apresia_aeos.py index e310218ad..2f1dfc900 100644 --- a/netmiko/apresia/apresia_aeos.py +++ b/netmiko/apresia/apresia_aeos.py @@ -19,7 +19,7 @@ def disable_paging(self, command="", delay_factor=1): check_command = "show running-config | include terminal length 0" output = self.send_command(check_command) - if "terminal length 0" not in output: + if self.allow_auto_change and "terminal length 0" not in output: self.send_config_set("terminal length 0") self.exit_enable_mode() diff --git a/netmiko/base_connection.py b/netmiko/base_connection.py index a99500394..8ac9ee437 100644 --- a/netmiko/base_connection.py +++ b/netmiko/base_connection.py @@ -40,7 +40,8 @@ def __init__(self, ip='', host='', username='', password='', secret='', port=Non alt_host_keys=False, alt_key_file='', ssh_config_file=None, timeout=100, session_timeout=60, blocking_timeout=8, keepalive=0, default_enter=None, response_return=None, serial_settings=None, fast_cli=False, session_log=None, - session_log_record_writes=False, session_log_file_mode='write'): + session_log_record_writes=False, session_log_file_mode='write', + allow_auto_change=False): """ Initialize attributes for establishing connection to target device. @@ -135,6 +136,10 @@ def __init__(self, ip='', host='', username='', password='', secret='', port=Non :param session_log_file_mode: "write" or "append" for session_log file mode (default: "write") :type session_log_file_mode: str + + :param allow_auto_change: Allow automatic configuration changes for terminal settings. + (default: False) + :type allow_auto_change: bool """ self.remote_conn = None self.RETURN = '\n' if default_enter is None else default_enter diff --git a/netmiko/cisco/cisco_asa_ssh.py b/netmiko/cisco/cisco_asa_ssh.py index 30476c4a3..6067a76ff 100644 --- a/netmiko/cisco/cisco_asa_ssh.py +++ b/netmiko/cisco/cisco_asa_ssh.py @@ -17,7 +17,13 @@ def session_preparation(self): else: self.asa_login() self.disable_paging(command="terminal pager 0") - self.send_config_set("terminal width 511") + if self.allow_auto_change: + try: + self.send_config_set("terminal width 511") + except ValueError: + # Don't fail for the terminal width + pass + # Clear the read buffer time.sleep(.3 * self.global_delay_factor) self.clear_buffer() diff --git a/netmiko/ipinfusion/ipinfusion_ocnos.py b/netmiko/ipinfusion/ipinfusion_ocnos.py index 20e0dd283..c5b4c2258 100644 --- a/netmiko/ipinfusion/ipinfusion_ocnos.py +++ b/netmiko/ipinfusion/ipinfusion_ocnos.py @@ -6,7 +6,7 @@ class IpInfusionOcNOSBase(CiscoBaseConnection): """Common Methods for IP Infusion OcNOS support.""" - def __init__(self, **kwargs): + def __init__(self, *args, **kwargs): if kwargs.get('default_enter') is None: kwargs['default_enter'] = '\r\n' return super(IpInfusionOcNOSBase, self).__init__(**kwargs) From feaf88f80b348761594edfe32a8ef92c886e66a1 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Wed, 8 Aug 2018 20:24:11 -0700 Subject: [PATCH 34/69] Fixing str references --- netmiko/base_connection.py | 4 ++-- netmiko/cisco/cisco_xr_ssh.py | 16 +++++++++------- netmiko/juniper/juniper.py | 3 ++- netmiko/snmp_autodetect.py | 5 +++-- netmiko/utilities.py | 3 ++- 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/netmiko/base_connection.py b/netmiko/base_connection.py index 8ac9ee437..e05f7c4bc 100644 --- a/netmiko/base_connection.py +++ b/netmiko/base_connection.py @@ -23,7 +23,7 @@ from netmiko import log from netmiko.netmiko_globals import MAX_BUFFER, BACKSPACE_CHAR -from netmiko.py23_compat import string_types, bufferedio_types +from netmiko.py23_compat import string_types, bufferedio_types, text_type from netmiko.ssh_exception import NetMikoTimeoutException, NetMikoAuthenticationException from netmiko.utilities import write_bytes, check_serial_port, get_structured_data @@ -750,7 +750,7 @@ def establish_connection(self, width=None, height=None): self.paramiko_cleanup() msg = "Authentication failure: unable to connect {device_type} {ip}:{port}".format( device_type=self.device_type, ip=self.host, port=self.port) - msg += self.RETURN + str(auth_err) + msg += self.RETURN + text_type(auth_err) raise NetMikoAuthenticationException(msg) if self.verbose: diff --git a/netmiko/cisco/cisco_xr_ssh.py b/netmiko/cisco/cisco_xr_ssh.py index 7ada09150..12c79ce33 100644 --- a/netmiko/cisco/cisco_xr_ssh.py +++ b/netmiko/cisco/cisco_xr_ssh.py @@ -3,6 +3,7 @@ import time import re from netmiko.cisco_base_connection import CiscoSSHConnection, CiscoFileTransfer +from netmiko.py23_compat import text_type class CiscoXrSSH(CiscoSSHConnection): @@ -70,22 +71,23 @@ def commit(self, confirm=False, confirm_delay=None, comment='', label='', delay_ raise ValueError("Invalid comment contains double quote") comment = '"{0}"'.format(comment) - label = str(label) + label = text_type(label) error_marker = 'Failed to' alt_error_marker = 'One or more commits have occurred from other' # Select proper command string based on arguments provided if label: if comment: - command_string = 'commit label {0} comment {1}'.format(label, comment) + command_string = 'commit label {} comment {}'.format(label, comment) elif confirm: - command_string = 'commit label {0} confirmed {1}'.format(label, str(confirm_delay)) + command_string = 'commit label {} confirmed {}'.format(label, + text_type(confirm_delay)) else: - command_string = 'commit label {0}'.format(label) + command_string = 'commit label {}'.format(label) elif confirm: - command_string = 'commit confirmed {0}'.format(str(confirm_delay)) + command_string = 'commit confirmed {}'.format(text_type(confirm_delay)) elif comment: - command_string = 'commit comment {0}'.format(comment) + command_string = 'commit comment {}'.format(comment) else: command_string = 'commit' @@ -99,7 +101,7 @@ def commit(self, confirm=False, confirm_delay=None, comment='', label='', delay_ # Other commits occurred, don't proceed with commit output += self.send_command_timing("no", strip_prompt=False, strip_command=False, delay_factor=delay_factor) - raise ValueError("Commit failed with the following errors:\n\n{0}".format(output)) + raise ValueError("Commit failed with the following errors:\n\n{}".format(output)) return output diff --git a/netmiko/juniper/juniper.py b/netmiko/juniper/juniper.py index 269b745d2..e40a41bf7 100644 --- a/netmiko/juniper/juniper.py +++ b/netmiko/juniper/juniper.py @@ -5,6 +5,7 @@ from netmiko.base_connection import BaseConnection from netmiko.scp_handler import BaseFileTransfer +from netmiko.py23_compat import text_type class JuniperBase(BaseConnection): @@ -127,7 +128,7 @@ def commit(self, confirm=False, confirm_delay=None, check=False, comment='', commit_marker = 'configuration check succeeds' elif confirm: if confirm_delay: - command_string = 'commit confirmed ' + str(confirm_delay) + command_string = 'commit confirmed ' + text_type(confirm_delay) else: command_string = 'commit confirmed' commit_marker = 'commit confirmed will be automatically rolled back in' diff --git a/netmiko/snmp_autodetect.py b/netmiko/snmp_autodetect.py index 0ba00ba26..94c47458f 100644 --- a/netmiko/snmp_autodetect.py +++ b/netmiko/snmp_autodetect.py @@ -29,6 +29,7 @@ raise ImportError("pysnmp not installed; please install it: 'pip install pysnmp'") from netmiko.ssh_dispatcher import CLASS_MAPPER +from netmiko.py23_compat import text_type # Higher priority indicates a better match. @@ -201,7 +202,7 @@ def _get_snmpv3(self, oid): oid, lookupNames=True, lookupValues=True) if not error_detected and snmp_data[0][1]: - return str(snmp_data[0][1]) + return text_type(snmp_data[0][1]) return "" def _get_snmpv2c(self, oid): @@ -227,7 +228,7 @@ def _get_snmpv2c(self, oid): oid, lookupNames=True, lookupValues=True) if not error_detected and snmp_data[0][1]: - return str(snmp_data[0][1]) + return text_type(snmp_data[0][1]) return "" def _get_snmp(self, oid): diff --git a/netmiko/utilities.py b/netmiko/utilities.py index e7ea43ee4..548072310 100644 --- a/netmiko/utilities.py +++ b/netmiko/utilities.py @@ -8,6 +8,7 @@ import serial.tools.list_ports from netmiko._textfsm import _clitable as clitable from netmiko._textfsm._clitable import CliTableError +from netmiko.py23_compat import text_type # Dictionary mapping 'show run' for vendors with different command @@ -183,7 +184,7 @@ def check_serial_port(name): msg += "available devices are: " ports = list(serial.tools.list_ports.comports()) for p in ports: - msg += "{},".format(str(p)) + msg += "{},".format(text_type(p)) raise ValueError(msg) From f41f15a0a161b76664c27670f76a2c7a2873f8f9 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Thu, 9 Aug 2018 09:52:00 -0700 Subject: [PATCH 35/69] Performance improvements in send_command --- netmiko/base_connection.py | 61 ++++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/netmiko/base_connection.py b/netmiko/base_connection.py index e05f7c4bc..747fca6c3 100644 --- a/netmiko/base_connection.py +++ b/netmiko/base_connection.py @@ -1021,6 +1021,33 @@ def strip_prompt(self, a_string): else: return a_string + def _first_line_handler(self, data, search_pattern): + """ + In certain situations the first line will get repainted which causes a false + match on the terminating pattern. + + Filter this out. + + returns a tuple of (data, first_line_processed) + + Where data is the original data potentially with the first line modified + and the first_line_processed is a flag indicating that we have handled the + first line. + """ + try: + # First line is the echo line containing the command. In certain situations + # it gets repainted and needs filtered + lines = data.split(self.RETURN) + first_line = lines[0] + if BACKSPACE_CHAR in first_line: + pattern = search_pattern + r'.*$' + first_line = re.sub(pattern, repl='', string=first_line) + lines[0] = first_line + data = self.RETURN.join(lines) + return (data, True) + except IndexError: + return (data, False) + def send_command(self, command_string, expect_string=None, delay_factor=1, max_loops=500, auto_find_prompt=True, strip_prompt=True, strip_command=True, normalize=True, @@ -1088,27 +1115,31 @@ def send_command(self, command_string, expect_string=None, i = 1 output = '' + first_line_processed = False + # Keep reading data until search_pattern is found or until max_loops is reached. while i <= max_loops: new_data = self.read_channel() if new_data: if self.ansi_escape_codes: new_data = self.strip_ansi_escape_codes(new_data) - output += new_data - try: - lines = output.split(self.RETURN) - first_line = lines[0] - # First line is the echo line containing the command. In certain situations - # it gets repainted and needs filtered - if BACKSPACE_CHAR in first_line: - pattern = search_pattern + r'.*$' - first_line = re.sub(pattern, repl='', string=first_line) - lines[0] = first_line - output = self.RETURN.join(lines) - except IndexError: - pass - if re.search(search_pattern, output): - break + + # Case where we haven't processed the first_line yet + if not first_line_processed: + output += new_data + output, first_line_processed = self._first_line_handler( + output, + search_pattern + ) + # Check if we have already found our pattern + if re.search(search_pattern, output): + break + + else: + output += new_data + # Check if pattern is in the incremental data + if re.search(search_pattern, new_data): + break time.sleep(delay_factor * loop_delay) i += 1 From 6a4eb707d1afd0223dbf69900a115450403d5da3 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Thu, 9 Aug 2018 10:43:20 -0700 Subject: [PATCH 36/69] Add comment --- netmiko/base_connection.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/netmiko/base_connection.py b/netmiko/base_connection.py index 747fca6c3..d3c3d895e 100644 --- a/netmiko/base_connection.py +++ b/netmiko/base_connection.py @@ -1124,7 +1124,8 @@ def send_command(self, command_string, expect_string=None, if self.ansi_escape_codes: new_data = self.strip_ansi_escape_codes(new_data) - # Case where we haven't processed the first_line yet + # Case where we haven't processed the first_line yet (there is a potential issue + # in the first line (in cases where the line is repainted). if not first_line_processed: output += new_data output, first_line_processed = self._first_line_handler( From 020f884235a9b0bc7184d9784877a9f16b012495 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Thu, 9 Aug 2018 11:52:59 -0700 Subject: [PATCH 37/69] Fixing bug on ASA driver --- netmiko/base_connection.py | 1 + 1 file changed, 1 insertion(+) diff --git a/netmiko/base_connection.py b/netmiko/base_connection.py index d3c3d895e..b4a7134de 100644 --- a/netmiko/base_connection.py +++ b/netmiko/base_connection.py @@ -170,6 +170,7 @@ def __init__(self, ip='', host='', username='', password='', secret='', port=Non self.session_timeout = session_timeout self.blocking_timeout = blocking_timeout self.keepalive = keepalive + self.allow_auto_change = allow_auto_change # Netmiko will close the session_log if we open the file self.session_log = None From 82ddb83df40746332aae9293a063e52ff35214cf Mon Sep 17 00:00:00 2001 From: Howard Johnson Date: Thu, 9 Aug 2018 22:55:19 +0100 Subject: [PATCH 38/69] Support directly using paramiko PKey objects for SSH key authentication --- netmiko/base_connection.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/netmiko/base_connection.py b/netmiko/base_connection.py index e05f7c4bc..624daa161 100644 --- a/netmiko/base_connection.py +++ b/netmiko/base_connection.py @@ -36,12 +36,12 @@ class BaseConnection(object): """ def __init__(self, ip='', host='', username='', password='', secret='', port=None, device_type='', verbose=False, global_delay_factor=1, use_keys=False, - key_file=None, allow_agent=False, ssh_strict=False, system_host_keys=False, - alt_host_keys=False, alt_key_file='', ssh_config_file=None, timeout=100, - session_timeout=60, blocking_timeout=8, keepalive=0, default_enter=None, - response_return=None, serial_settings=None, fast_cli=False, session_log=None, - session_log_record_writes=False, session_log_file_mode='write', - allow_auto_change=False): + key_file=None, priv_key=None, allow_agent=False, ssh_strict=False, + system_host_keys=False, alt_host_keys=False, alt_key_file='', + ssh_config_file=None, timeout=100, session_timeout=60, blocking_timeout=8, + keepalive=0, default_enter=None, response_return=None, serial_settings=None, + fast_cli=False, session_log=None, session_log_record_writes=False, + session_log_file_mode='write', allow_auto_change=False): """ Initialize attributes for establishing connection to target device. @@ -83,6 +83,9 @@ def __init__(self, ip='', host='', username='', password='', secret='', port=Non :param key_file: Filename path of the SSH key file to use. :type key_file: str + :param priv_key: SSH key object to use. + :type priv_key: paramiko.PKey + :param allow_agent: Enable use of SSH key-agent. :type allow_agent: bool @@ -238,6 +241,7 @@ def __init__(self, ip='', host='', username='', password='', secret='', port=Non # Options for SSH host_keys self.use_keys = use_keys self.key_file = key_file + self.priv_key = priv_key self.allow_agent = allow_agent self.system_host_keys = system_host_keys self.alt_host_keys = alt_host_keys @@ -686,6 +690,7 @@ def _connect_params_dict(self): 'look_for_keys': self.use_keys, 'allow_agent': self.allow_agent, 'key_filename': self.key_file, + 'pkey': self.priv_key, 'timeout': self.timeout, } From fef85f24eb7d3fb2b4c3752c5f08c776178fb299 Mon Sep 17 00:00:00 2001 From: duckhawk Date: Sat, 11 Aug 2018 16:44:26 +0500 Subject: [PATCH 39/69] Fixing huawei command "send_config_set" --- netmiko/huawei/huawei_ssh.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/netmiko/huawei/huawei_ssh.py b/netmiko/huawei/huawei_ssh.py index 2c584a762..a42feb0ce 100644 --- a/netmiko/huawei/huawei_ssh.py +++ b/netmiko/huawei/huawei_ssh.py @@ -21,9 +21,10 @@ def config_mode(self, config_command='system-view'): """Enter configuration mode.""" return super(HuaweiSSH, self).config_mode(config_command=config_command) - def exit_config_mode(self, exit_config='return'): + def exit_config_mode(self, exit_config='return', pattern=r'>'): """Exit configuration mode.""" - return super(HuaweiSSH, self).exit_config_mode(exit_config=exit_config) + return super(HuaweiSSH, self).exit_config_mode(exit_config=exit_config, + pattern=pattern) def check_config_mode(self, check_string=']'): """Checks whether in configuration mode. Returns a boolean.""" From 6abb0cc83f955d4542d812c90f0b886898fead3b Mon Sep 17 00:00:00 2001 From: labulaka521 Date: Wed, 15 Aug 2018 14:58:26 +0800 Subject: [PATCH 40/69] fix chinese become empty --- netmiko/utilities.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/netmiko/utilities.py b/netmiko/utilities.py index 548072310..87392f451 100644 --- a/netmiko/utilities.py +++ b/netmiko/utilities.py @@ -162,12 +162,12 @@ def write_bytes(out_data): """Write Python2 and Python3 compatible byte stream.""" if sys.version_info[0] >= 3: if isinstance(out_data, type(u'')): - return out_data.encode('ascii', 'ignore') + return out_data.encode('utf-8') elif isinstance(out_data, type(b'')): return out_data else: if isinstance(out_data, type(u'')): - return out_data.encode('ascii', 'ignore') + return out_data.encode('utf-8') elif isinstance(out_data, type(str(''))): return out_data msg = "Invalid value for out_data neither unicode nor byte string: {0}".format(out_data) From bab03031a06dc3dc35d37bc3113b0042008db15f Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Sun, 19 Aug 2018 17:29:48 -0700 Subject: [PATCH 41/69] Adding encoding --- netmiko/base_connection.py | 13 +++++++------ netmiko/utilities.py | 12 +++++++++--- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/netmiko/base_connection.py b/netmiko/base_connection.py index b4a7134de..d85dd9f62 100644 --- a/netmiko/base_connection.py +++ b/netmiko/base_connection.py @@ -41,7 +41,7 @@ def __init__(self, ip='', host='', username='', password='', secret='', port=Non session_timeout=60, blocking_timeout=8, keepalive=0, default_enter=None, response_return=None, serial_settings=None, fast_cli=False, session_log=None, session_log_record_writes=False, session_log_file_mode='write', - allow_auto_change=False): + allow_auto_change=False, write_encoding='ascii'): """ Initialize attributes for establishing connection to target device. @@ -171,6 +171,7 @@ def __init__(self, ip='', host='', username='', password='', secret='', port=Non self.blocking_timeout = blocking_timeout self.keepalive = keepalive self.allow_auto_change = allow_auto_change + self.write_encoding = write_encoding # Netmiko will close the session_log if we open the file self.session_log = None @@ -309,16 +310,16 @@ def _write_channel(self, out_data): :type out_data: str (can be either unicode/byte string) """ if self.protocol == 'ssh': - self.remote_conn.sendall(write_bytes(out_data)) + self.remote_conn.sendall(write_bytes(out_data, encoding=self.encoding)) elif self.protocol == 'telnet': - self.remote_conn.write(write_bytes(out_data)) + self.remote_conn.write(write_bytes(out_data, encoding=self.encoding)) elif self.protocol == 'serial': - self.remote_conn.write(write_bytes(out_data)) + self.remote_conn.write(write_bytes(out_data, encoding=self.encoding)) self.remote_conn.flush() else: raise ValueError("Invalid protocol specified") try: - log.debug("write_channel: {}".format(write_bytes(out_data))) + log.debug("write_channel: {}".format(write_bytes(out_data, encoding=self.encoding))) if self._session_log_fin or self.session_log_record_writes: self._write_session_log(out_data) except UnicodeDecodeError: @@ -327,7 +328,7 @@ def _write_channel(self, out_data): def _write_session_log(self, data): if self.session_log is not None and len(data) > 0: - self.session_log.write(write_bytes(data)) + self.session_log.write(write_bytes(data, encoding=self.encoding)) self.session_log.flush() def write_channel(self, out_data): diff --git a/netmiko/utilities.py b/netmiko/utilities.py index 87392f451..c2f9107df 100644 --- a/netmiko/utilities.py +++ b/netmiko/utilities.py @@ -158,16 +158,22 @@ def find_netmiko_dir(): return (netmiko_base_dir, netmiko_full_dir) -def write_bytes(out_data): +def write_bytes(out_data, encoding='ascii'): """Write Python2 and Python3 compatible byte stream.""" if sys.version_info[0] >= 3: if isinstance(out_data, type(u'')): - return out_data.encode('utf-8') + if encoding == 'utf-8': + return out_data.encode('utf-8') + else: + return out_data.encode('ascii', 'ignore') elif isinstance(out_data, type(b'')): return out_data else: if isinstance(out_data, type(u'')): - return out_data.encode('utf-8') + if encoding == 'utf-8': + return out_data.encode('utf-8') + else: + return out_data.encode('ascii', 'ignore') elif isinstance(out_data, type(str(''))): return out_data msg = "Invalid value for out_data neither unicode nor byte string: {0}".format(out_data) From ad872c34e12e54715add7a94e47eb59646200d77 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Sun, 19 Aug 2018 20:55:51 -0700 Subject: [PATCH 42/69] Fixing inconsistent naming --- netmiko/base_connection.py | 8 ++++++-- netmiko/utilities.py | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/netmiko/base_connection.py b/netmiko/base_connection.py index d85dd9f62..f936476cf 100644 --- a/netmiko/base_connection.py +++ b/netmiko/base_connection.py @@ -41,7 +41,7 @@ def __init__(self, ip='', host='', username='', password='', secret='', port=Non session_timeout=60, blocking_timeout=8, keepalive=0, default_enter=None, response_return=None, serial_settings=None, fast_cli=False, session_log=None, session_log_record_writes=False, session_log_file_mode='write', - allow_auto_change=False, write_encoding='ascii'): + allow_auto_change=False, encoding='ascii'): """ Initialize attributes for establishing connection to target device. @@ -140,6 +140,10 @@ def __init__(self, ip='', host='', username='', password='', secret='', port=Non :param allow_auto_change: Allow automatic configuration changes for terminal settings. (default: False) :type allow_auto_change: bool + + :param encoding: Encoding to be used when writing bytes to the output channel. + (default: 'ascii') + :type encoding: str """ self.remote_conn = None self.RETURN = '\n' if default_enter is None else default_enter @@ -171,7 +175,7 @@ def __init__(self, ip='', host='', username='', password='', secret='', port=Non self.blocking_timeout = blocking_timeout self.keepalive = keepalive self.allow_auto_change = allow_auto_change - self.write_encoding = write_encoding + self.encoding = encoding # Netmiko will close the session_log if we open the file self.session_log = None diff --git a/netmiko/utilities.py b/netmiko/utilities.py index c2f9107df..9820f739d 100644 --- a/netmiko/utilities.py +++ b/netmiko/utilities.py @@ -176,7 +176,7 @@ def write_bytes(out_data, encoding='ascii'): return out_data.encode('ascii', 'ignore') elif isinstance(out_data, type(str(''))): return out_data - msg = "Invalid value for out_data neither unicode nor byte string: {0}".format(out_data) + msg = "Invalid value for out_data neither unicode nor byte string: {}".format(out_data) raise ValueError(msg) From f2ebda2877256bf89f941820253c7886ef7c2181 Mon Sep 17 00:00:00 2001 From: tcosmos Date: Thu, 23 Aug 2018 18:01:30 -0500 Subject: [PATCH 43/69] Add paramiko option to extend auth_timeout. Default is none, but configurable type is float. Timeout is measured in seconds --- netmiko/base_connection.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/netmiko/base_connection.py b/netmiko/base_connection.py index f936476cf..8d7f27f99 100644 --- a/netmiko/base_connection.py +++ b/netmiko/base_connection.py @@ -38,7 +38,7 @@ def __init__(self, ip='', host='', username='', password='', secret='', port=Non device_type='', verbose=False, global_delay_factor=1, use_keys=False, key_file=None, allow_agent=False, ssh_strict=False, system_host_keys=False, alt_host_keys=False, alt_key_file='', ssh_config_file=None, timeout=100, - session_timeout=60, blocking_timeout=8, keepalive=0, default_enter=None, + session_timeout=60, auth_timeout=None, blocking_timeout=8, keepalive=0, default_enter=None, response_return=None, serial_settings=None, fast_cli=False, session_log=None, session_log_record_writes=False, session_log_file_mode='write', allow_auto_change=False, encoding='ascii'): @@ -108,6 +108,9 @@ def __init__(self, ip='', host='', username='', password='', secret='', port=Non :param session_timeout: Set a timeout for parallel requests. :type session_timeout: float + :param auth_timeout: Set a timeout (in seconds) to wait for an authentication response. + :type auth_timeout: float + :param keepalive: Send SSH keepalive packets at a specific interval, in seconds. Currently defaults to 0, for backwards compatibility (it will not attempt to keep the connection alive). @@ -171,6 +174,7 @@ def __init__(self, ip='', host='', username='', password='', secret='', port=Non self.ansi_escape_codes = False self.verbose = verbose self.timeout = timeout + self.auth_timeout = auth_timeout self.session_timeout = session_timeout self.blocking_timeout = blocking_timeout self.keepalive = keepalive @@ -693,6 +697,7 @@ def _connect_params_dict(self): 'allow_agent': self.allow_agent, 'key_filename': self.key_file, 'timeout': self.timeout, + 'auth_timeout': self.auth_timeout } # Check if using SSH 'config' file mainly for SSH proxy support From 1ede19d61c0afc7b93e60d14f9d88585b242e751 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Fri, 24 Aug 2018 21:23:55 -0700 Subject: [PATCH 44/69] Fixing linter issue --- netmiko/base_connection.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/netmiko/base_connection.py b/netmiko/base_connection.py index 8d7f27f99..bba50bf34 100644 --- a/netmiko/base_connection.py +++ b/netmiko/base_connection.py @@ -38,9 +38,9 @@ def __init__(self, ip='', host='', username='', password='', secret='', port=Non device_type='', verbose=False, global_delay_factor=1, use_keys=False, key_file=None, allow_agent=False, ssh_strict=False, system_host_keys=False, alt_host_keys=False, alt_key_file='', ssh_config_file=None, timeout=100, - session_timeout=60, auth_timeout=None, blocking_timeout=8, keepalive=0, default_enter=None, - response_return=None, serial_settings=None, fast_cli=False, session_log=None, - session_log_record_writes=False, session_log_file_mode='write', + session_timeout=60, auth_timeout=None, blocking_timeout=8, keepalive=0, + default_enter=None, response_return=None, serial_settings=None, fast_cli=False, + session_log=None, session_log_record_writes=False, session_log_file_mode='write', allow_auto_change=False, encoding='ascii'): """ Initialize attributes for establishing connection to target device. From 6037963d9c436c9219a145658e736883a0036510 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Fri, 24 Aug 2018 21:44:29 -0700 Subject: [PATCH 45/69] Add paramiko passphrase --- netmiko/base_connection.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/netmiko/base_connection.py b/netmiko/base_connection.py index 1be278ba4..077385628 100644 --- a/netmiko/base_connection.py +++ b/netmiko/base_connection.py @@ -36,8 +36,8 @@ class BaseConnection(object): """ def __init__(self, ip='', host='', username='', password='', secret='', port=None, device_type='', verbose=False, global_delay_factor=1, use_keys=False, - key_file=None, pkey=None, allow_agent=False, ssh_strict=False, - system_host_keys=False, + key_file=None, pkey=None, passphrase=None, allow_agent=False, + ssh_strict=False, system_host_keys=False, alt_host_keys=False, alt_key_file='', ssh_config_file=None, timeout=100, session_timeout=60, auth_timeout=None, blocking_timeout=8, keepalive=0, default_enter=None, response_return=None, serial_settings=None, fast_cli=False, @@ -84,8 +84,12 @@ def __init__(self, ip='', host='', username='', password='', secret='', port=Non :param key_file: Filename path of the SSH key file to use. :type key_file: str - :param priv_key: SSH key object to use. - :type priv_key: paramiko.PKey + :param pkey: SSH key object to use. + :type pkey: paramiko.PKey + + :param passphrase: Passphrase to use for encrypted key; password will be used for key + decryption if not specified. + :type passphrase: str :param allow_agent: Enable use of SSH key-agent. :type allow_agent: bool @@ -252,7 +256,8 @@ def __init__(self, ip='', host='', username='', password='', secret='', port=Non # Options for SSH host_keys self.use_keys = use_keys self.key_file = key_file - self.priv_key = priv_key + self.pkey = pkey + self.passphrase = passphrase self.allow_agent = allow_agent self.system_host_keys = system_host_keys self.alt_host_keys = alt_host_keys @@ -701,7 +706,8 @@ def _connect_params_dict(self): 'look_for_keys': self.use_keys, 'allow_agent': self.allow_agent, 'key_filename': self.key_file, - 'pkey': self.priv_key, + 'pkey': self.pkey, + 'passphrase': self.passphrase, 'timeout': self.timeout, 'auth_timeout': self.auth_timeout } From e968f93f58bf840b6169a9d24dcc88822fb84bd3 Mon Sep 17 00:00:00 2001 From: txb5022 Date: Mon, 27 Aug 2018 10:48:29 -0400 Subject: [PATCH 46/69] Add blurb about textfsm integration. --- README.md | 137 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 72 insertions(+), 65 deletions(-) diff --git a/README.md b/README.md index 69237e077..66e3658c2 100644 --- a/README.md +++ b/README.md @@ -6,76 +6,76 @@ Netmiko Multi-vendor library to simplify Paramiko SSH connections to network devices -Python 2.7, 3.5, 3.6 +Python 2.7, 3.5, 3.6 #### Requires: -Paramiko >= 2 -scp >= 0.10.0 -pyyaml -pyserial -textfsm +Paramiko >= 2 +scp >= 0.10.0 +pyyaml +pyserial +textfsm #### Supports: ###### Regularly tested -Arista vEOS -Cisco ASA -Cisco IOS -Cisco IOS-XE -Cisco IOS-XR -Cisco NX-OS -Cisco SG300 -HP Comware7 -HP ProCurve -Juniper Junos -Linux +Arista vEOS +Cisco ASA +Cisco IOS +Cisco IOS-XE +Cisco IOS-XR +Cisco NX-OS +Cisco SG300 +HP Comware7 +HP ProCurve +Juniper Junos +Linux ###### Limited testing -Alcatel AOS6/AOS8 -Apresia Systems AEOS -Calix B6 -Cisco WLC -Dell OS10 -Dell-Force10 -Dell PowerConnect -Extreme ERS (Avaya) -Extreme VSP (Avaya) -Extreme VDX (Brocade) -Extreme MLX/NetIron (Brocade/Foundry) -Huawei -IP Infusion OcNOS -Mellanox -NetApp cDOT -Palo Alto PAN-OS -Pluribus -Ruckus ICX/FastIron -Ubiquiti EdgeSwitch -Vyatta VyOS +Alcatel AOS6/AOS8 +Apresia Systems AEOS +Calix B6 +Cisco WLC +Dell OS10 +Dell-Force10 +Dell PowerConnect +Extreme ERS (Avaya) +Extreme VSP (Avaya) +Extreme VDX (Brocade) +Extreme MLX/NetIron (Brocade/Foundry) +Huawei +IP Infusion OcNOS +Mellanox +NetApp cDOT +Palo Alto PAN-OS +Pluribus +Ruckus ICX/FastIron +Ubiquiti EdgeSwitch +Vyatta VyOS ###### Experimental -A10 -Accedian -Aruba -Ciena SAOS -Citrix Netscaler -Cisco Telepresence -Check Point GAiA -Coriant -Dell EMC Isilon -Eltex -Enterasys -Extreme EXOS +A10 +Accedian +Aruba +Ciena SAOS +Citrix Netscaler +Cisco Telepresence +Check Point GAiA +Coriant +Dell EMC Isilon +Eltex +Enterasys +Extreme EXOS Extreme Wing -Extreme SLX (Brocade) -F5 LTM -Fortinet -MRV Communications OptiSwitch -Nokia/Alcatel SR-OS -QuantaMesh +Extreme SLX (Brocade) +F5 LTM +Fortinet +MRV Communications OptiSwitch +Nokia/Alcatel SR-OS +QuantaMesh ## Tutorials: @@ -133,12 +133,12 @@ print(output) ``` ``` Interface IP-Address OK? Method Status Protocol -FastEthernet0 unassigned YES unset down down -FastEthernet1 unassigned YES unset down down -FastEthernet2 unassigned YES unset down down -FastEthernet3 unassigned YES unset down down -FastEthernet4 10.10.10.10 YES manual up up -Vlan1 unassigned YES unset down down +FastEthernet0 unassigned YES unset down down +FastEthernet1 unassigned YES unset down down +FastEthernet2 unassigned YES unset down down +FastEthernet3 unassigned YES unset down down +FastEthernet4 10.10.10.10 YES manual up up +Vlan1 unassigned YES unset down down ``` #### Execute configuration change commands (will automatically enter into config mode) @@ -160,6 +160,13 @@ pynet-rtr1(config)#end pynet-rtr1# ``` +## TextFSM Integration + +Netmiko has been configured to automatically look in `~/ntc-template/templates/index` for the ntc-templates index file. Alternatively, you can explicitly tell Netmiko where to look for the TextFSM template directory by setting the `NET_TEXTFSM` environment variable (note, there must be an index file in this directory): + +``` +export NET_TEXTFSM=/path/to/ntc-templates/templates/ +``` ## Questions/Discussion @@ -170,7 +177,7 @@ If you have questions or would like to discuss Netmiko, a Netmiko channel exists ---- -Kirk Byers -Python for Network Engineers -https://pynet.twb-tech.com +--- +Kirk Byers +Python for Network Engineers +https://pynet.twb-tech.com From 97a4a603b8078989a12a6b2b14f03821a6a68f51 Mon Sep 17 00:00:00 2001 From: txb5022 Date: Mon, 27 Aug 2018 10:49:34 -0400 Subject: [PATCH 47/69] Add link to detailed TextFSM integration. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 66e3658c2..31eb49f17 100644 --- a/README.md +++ b/README.md @@ -168,6 +168,8 @@ Netmiko has been configured to automatically look in `~/ntc-template/templates/i export NET_TEXTFSM=/path/to/ntc-templates/templates/ ``` +(More info on TextFSM and Netmiko)[https://pynet.twb-tech.com/blog/automation/netmiko-textfsm.html]. + ## Questions/Discussion If you find an issue with Netmiko, then you can open an issue on this projects issue page here: [https://github.com/ktbyers/netmiko/issues](https://github.com/ktbyers/netmiko/issues) From 51916976ce438b7ca5c706836ec5c346a91be2dc Mon Sep 17 00:00:00 2001 From: txb5022 Date: Mon, 27 Aug 2018 10:50:37 -0400 Subject: [PATCH 48/69] Correct link syntax. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 31eb49f17..a5d71cb3e 100644 --- a/README.md +++ b/README.md @@ -168,7 +168,7 @@ Netmiko has been configured to automatically look in `~/ntc-template/templates/i export NET_TEXTFSM=/path/to/ntc-templates/templates/ ``` -(More info on TextFSM and Netmiko)[https://pynet.twb-tech.com/blog/automation/netmiko-textfsm.html]. +[More info on TextFSM and Netmiko](https://pynet.twb-tech.com/blog/automation/netmiko-textfsm.html). ## Questions/Discussion From 90362ef34d8107f39b4ac0c35506acec8d80337c Mon Sep 17 00:00:00 2001 From: txb5022 Date: Mon, 27 Aug 2018 14:13:51 -0400 Subject: [PATCH 49/69] Change text lists to markdown lists. --- README.md | 110 +++++++++++++++++++++++++++--------------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index a5d71cb3e..1687ef614 100644 --- a/README.md +++ b/README.md @@ -10,72 +10,72 @@ Python 2.7, 3.5, 3.6 #### Requires: -Paramiko >= 2 -scp >= 0.10.0 -pyyaml -pyserial -textfsm +- Paramiko >= 2 +- scp >= 0.10.0 +- pyyaml +- pyserial +- textfsm #### Supports: ###### Regularly tested -Arista vEOS -Cisco ASA -Cisco IOS -Cisco IOS-XE -Cisco IOS-XR -Cisco NX-OS -Cisco SG300 -HP Comware7 -HP ProCurve -Juniper Junos -Linux +- Arista vEOS +- Cisco ASA +- Cisco IOS +- Cisco IOS-XE +- Cisco IOS-XR +- Cisco NX-OS +- Cisco SG300 +- HP Comware7 +- HP ProCurve +- Juniper Junos +- Linux ###### Limited testing -Alcatel AOS6/AOS8 -Apresia Systems AEOS -Calix B6 -Cisco WLC -Dell OS10 -Dell-Force10 -Dell PowerConnect -Extreme ERS (Avaya) -Extreme VSP (Avaya) -Extreme VDX (Brocade) -Extreme MLX/NetIron (Brocade/Foundry) -Huawei -IP Infusion OcNOS -Mellanox -NetApp cDOT -Palo Alto PAN-OS -Pluribus -Ruckus ICX/FastIron -Ubiquiti EdgeSwitch -Vyatta VyOS +- Alcatel AOS6/AOS8 +- Apresia Systems AEOS +- Calix B6 +- Cisco WLC +- Dell OS10 +- Dell-Force10 +- Dell PowerConnect +- Extreme ERS (Avaya) +- Extreme VSP (Avaya) +- Extreme VDX (Brocade) +- Extreme MLX/NetIron (Brocade/Foundry) +- Huawei +- IP Infusion OcNOS +- Mellanox +- NetApp cDOT +- Palo Alto PAN-OS +- Pluribus +- Ruckus ICX/FastIron +- Ubiquiti EdgeSwitch +- Vyatta VyOS ###### Experimental -A10 -Accedian -Aruba -Ciena SAOS -Citrix Netscaler -Cisco Telepresence -Check Point GAiA -Coriant -Dell EMC Isilon -Eltex -Enterasys -Extreme EXOS -Extreme Wing -Extreme SLX (Brocade) -F5 LTM -Fortinet -MRV Communications OptiSwitch -Nokia/Alcatel SR-OS -QuantaMesh +- A10 +- Accedian +- Aruba +- Ciena SAOS +- Citrix Netscaler +- Cisco Telepresence +- Check Point GAiA +- Coriant +- Dell EMC Isilon +- Eltex +- Enterasys +- Extreme EXOS +- Extreme Wing +- Extreme SLX (Brocade) +- F5 LTM +- Fortinet +- MRV Communications OptiSwitch +- Nokia/Alcatel SR-OS +- QuantaMesh ## Tutorials: From d716f355a01d381f377cb961c8131925771e673e Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Mon, 27 Aug 2018 20:14:35 -0700 Subject: [PATCH 50/69] Readd whitespace that was stripped off --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1687ef614..23fe7b885 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Netmiko Multi-vendor library to simplify Paramiko SSH connections to network devices -Python 2.7, 3.5, 3.6 +Python 2.7, 3.5, 3.6 #### Requires: @@ -179,7 +179,7 @@ If you have questions or would like to discuss Netmiko, a Netmiko channel exists ---- -Kirk Byers -Python for Network Engineers -https://pynet.twb-tech.com +--- +Kirk Byers +Python for Network Engineers +https://pynet.twb-tech.com From 81bf23a0ea19e0f1233bd547846adf0a02a640bd Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Mon, 27 Aug 2018 20:18:24 -0700 Subject: [PATCH 51/69] Updating readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 23fe7b885..75479db6e 100644 --- a/README.md +++ b/README.md @@ -179,7 +179,7 @@ If you have questions or would like to discuss Netmiko, a Netmiko channel exists ---- +--- Kirk Byers Python for Network Engineers https://pynet.twb-tech.com From f28a139c782ac28175dfe14574f74c3c5ffb3dd4 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Wed, 5 Sep 2018 20:58:20 -0700 Subject: [PATCH 52/69] Updating some minor items to Rad Etx driver. --- netmiko/rad/rad_etx.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/netmiko/rad/rad_etx.py b/netmiko/rad/rad_etx.py index cbf8860b7..0aeb62153 100644 --- a/netmiko/rad/rad_etx.py +++ b/netmiko/rad/rad_etx.py @@ -28,10 +28,18 @@ def save_config(self, cmd='admin save', confirm=False, confirm_response=''): output = self.send_command(command_string=cmd) return output + def check_enable_mode(self, *args, **kwargs): + """The Rad ETX software does not have an enable.""" + pass + def enable(self, *args, **kwargs): """The Rad ETX software does not have an enable.""" pass + def exit_enable_mode(self, *args, **kwargs): + """The Rad ETX software does not have an enable.""" + pass + def config_mode(self, config_command='config', pattern='>config'): """Enter into configuration mode on remote device.""" return super(RadETXBase, self).config_mode(config_command=config_command, @@ -53,17 +61,17 @@ def exit_config_mode(self, exit_config='exit all', pattern='#'): class RadETXSSH(RadETXBase): - """RAD ETX SSH Support. - - Found that a global_delay_factor of 2 is needed at minimum for SSH to the Rad ETX. - """ - pass + """RAD ETX SSH Support.""" + def __init__(self, **kwargs): + # Found that a global_delay_factor of 2 is needed at minimum for SSH to the Rad ETX. + kwargs.setdefault('global_delay_factor', 2) + return super(RadETXSSH, self).__init__(**kwargs) class RadETXTelnet(RadETXBase): """RAD ETX Telnet Support.""" def telnet_login(self, username_pattern=r"(?:user>)", - alt_prompt_term=r"#\s*$"): + alt_prompt_term=r"#\s*$", **kwargs): """ RAD presents with the following on login @@ -74,4 +82,4 @@ def telnet_login(self, username_pattern=r"(?:user>)", self.TELNET_RETURN = self.RETURN return super(RadETXTelnet, self).telnet_login(username_pattern=username_pattern, - alt_prompt_terminator=alt_prompt_term) + alt_prompt_terminator=alt_prompt_term, **kwargs) From 33ee393ecc5f1dc6563556f6c7f2c9ea440f017a Mon Sep 17 00:00:00 2001 From: TomCos Date: Tue, 11 Sep 2018 15:28:35 -0500 Subject: [PATCH 53/69] add support to detect an F5 system the the user logs into the tmsh shell directly --- netmiko/ssh_autodetect.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/netmiko/ssh_autodetect.py b/netmiko/ssh_autodetect.py index 8297f704d..f90a0ebd5 100644 --- a/netmiko/ssh_autodetect.py +++ b/netmiko/ssh_autodetect.py @@ -135,6 +135,12 @@ "priority": 99, "dispatch": "_autodetect_std", }, + 'f5_ltm': { + "cmd": "show sys version", + "search_patterns": [r"BIG-IP"], + "priority": 99, + "dispatch": "_autodetect_std", + } } @@ -275,6 +281,8 @@ def _autodetect_std(self, cmd="", search_patterns=None, re_flags=re.I, priority= r'syntax error, expecting', r'Error: Unrecognized command', r'%Error' + r'command not found' + r'Syntax Error: unexpected argument' ] if not cmd or not search_patterns: return 0 From 7b1c64ebafeeaf48cae5a4db6720afbc74384704 Mon Sep 17 00:00:00 2001 From: tcosmos Date: Wed, 12 Sep 2018 00:44:33 -0500 Subject: [PATCH 54/69] add linux support as well --- netmiko/ssh_autodetect.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/netmiko/ssh_autodetect.py b/netmiko/ssh_autodetect.py index f90a0ebd5..8720a0da1 100644 --- a/netmiko/ssh_autodetect.py +++ b/netmiko/ssh_autodetect.py @@ -141,6 +141,12 @@ "priority": 99, "dispatch": "_autodetect_std", } + 'linux': { + "cmd": "uname -a", + "search_patterns": [r"Linux"], + "priority": 99, + "dispatch": "_autodetect_std", + } } From 92b1fe0cca26fd81585b13b46ef22be000cfce51 Mon Sep 17 00:00:00 2001 From: tcosmos Date: Wed, 12 Sep 2018 00:51:12 -0500 Subject: [PATCH 55/69] I forgot a comma, of course --- netmiko/ssh_autodetect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netmiko/ssh_autodetect.py b/netmiko/ssh_autodetect.py index 8720a0da1..0b355b63c 100644 --- a/netmiko/ssh_autodetect.py +++ b/netmiko/ssh_autodetect.py @@ -140,7 +140,7 @@ "search_patterns": [r"BIG-IP"], "priority": 99, "dispatch": "_autodetect_std", - } + }, 'linux': { "cmd": "uname -a", "search_patterns": [r"Linux"], From 271780b7fe95a4e86f57a83bade95a646a90d4e5 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Fri, 14 Sep 2018 13:58:16 -0700 Subject: [PATCH 56/69] Roll Paramiko version to 2.4.1 --- README.md | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 49b058c8b..daa7d5fb8 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Python 2.7, 3.5, 3.6 #### Requires: -- Paramiko >= 2 +- Paramiko >= 2.4.1 - scp >= 0.10.0 - pyyaml - pyserial diff --git a/setup.py b/setup.py index 3ad8fda75..6648c02a8 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ requirements = [ - 'paramiko>=2.0.0', + 'paramiko>=2.4.1', 'scp>=0.10.0', 'pyyaml', 'pyserial', From eedea515d06c720a7761dcfad8745e9246a59dcf Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Fri, 14 Sep 2018 14:14:52 -0700 Subject: [PATCH 57/69] Reorder autodetect to improve performance --- netmiko/ssh_autodetect.py | 42 +++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/netmiko/ssh_autodetect.py b/netmiko/ssh_autodetect.py index 8297f704d..65650f517 100644 --- a/netmiko/ssh_autodetect.py +++ b/netmiko/ssh_autodetect.py @@ -50,12 +50,6 @@ # remaining keys indicate kwargs that will be passed to dispatch method. # Note, the 'cmd' needs to avoid output paging. SSH_MAPPER_BASE = { - 'alcatel_aos': { - "cmd": "show system", - "search_patterns": [r"Alcatel-Lucent"], - "priority": 99, - "dispatch": "_autodetect_std", - }, 'alcatel_sros': { "cmd": "show version", "search_patterns": [ @@ -65,12 +59,6 @@ "priority": 99, "dispatch": "_autodetect_std", }, - 'apresia_aeos': { - "cmd": "show system", - "search_patterns": ["Apresia"], - "priority": 99, - "dispatch": "_autodetect_std", - }, 'arista_eos': { "cmd": "show version", "search_patterns": [r"Arista"], @@ -104,15 +92,6 @@ "priority": 99, "dispatch": "_autodetect_std", }, - 'huawei': { - "cmd": "display version", - "search_patterns": [ - r"Huawei Technologies", - r"Huawei Versatile Routing Platform Software" - ], - "priority": 99, - "dispatch": "_autodetect_std", - }, 'juniper_junos': { "cmd": "show version", "search_patterns": [ @@ -135,6 +114,27 @@ "priority": 99, "dispatch": "_autodetect_std", }, + 'alcatel_aos': { + "cmd": "show system", + "search_patterns": [r"Alcatel-Lucent"], + "priority": 99, + "dispatch": "_autodetect_std", + }, + 'apresia_aeos': { + "cmd": "show system", + "search_patterns": ["Apresia"], + "priority": 99, + "dispatch": "_autodetect_std", + }, + 'huawei': { + "cmd": "display version", + "search_patterns": [ + r"Huawei Technologies", + r"Huawei Versatile Routing Platform Software" + ], + "priority": 99, + "dispatch": "_autodetect_std", + }, } From b54fc9e530156591834bc23a5a07bdff4d44415c Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Fri, 14 Sep 2018 21:06:53 -0700 Subject: [PATCH 58/69] Dell OS6 driver --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index daa7d5fb8..9cf913d8f 100644 --- a/README.md +++ b/README.md @@ -38,8 +38,8 @@ Python 2.7, 3.5, 3.6 - Apresia Systems AEOS - Calix B6 - Cisco WLC +- Dell OS9 (Force10) - Dell OS10 -- Dell-Force10 - Dell PowerConnect - Extreme ERS (Avaya) - Extreme VSP (Avaya) @@ -65,6 +65,7 @@ Python 2.7, 3.5, 3.6 - Cisco Telepresence - Check Point GAiA - Coriant +- Dell OS6 - Dell EMC Isilon - Eltex - Enterasys From 7c64fb4ca8a4e5135e4a6394ac03b74d6244db8f Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Fri, 14 Sep 2018 21:32:01 -0700 Subject: [PATCH 59/69] Telnet is_alive fixes --- netmiko/base_connection.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/netmiko/base_connection.py b/netmiko/base_connection.py index 23dd61b5e..b8336221a 100644 --- a/netmiko/base_connection.py +++ b/netmiko/base_connection.py @@ -370,11 +370,17 @@ def is_alive(self): return False if self.protocol == 'telnet': try: - # Try sending IAC + NOP (IAC is telnet way of sending command - # IAC = Interpret as Command (it comes before the NOP) + # Try sending IAC + NOP (IAC is telnet way of sending command) + # IAC = Interpret as Command; it comes before the NOP. log.debug("Sending IAC + NOP") - self.remote_conn.sock.sendall(telnetlib.IAC + telnetlib.NOP) - return True + if self.remote_conn.sock: + # Need to send multiple times to test connection + self.remote_conn.sock.sendall(telnetlib.IAC + telnetlib.NOP) + self.remote_conn.sock.sendall(telnetlib.IAC + telnetlib.NOP) + self.remote_conn.sock.sendall(telnetlib.IAC + telnetlib.NOP) + return True + else: + return False except AttributeError: return False else: From 5df9c457e420da455ef11c8cf831a305e566f801 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Fri, 14 Sep 2018 21:56:55 -0700 Subject: [PATCH 60/69] Improvements to telnet is_alive() --- netmiko/base_connection.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/netmiko/base_connection.py b/netmiko/base_connection.py index b8336221a..e28b9eb10 100644 --- a/netmiko/base_connection.py +++ b/netmiko/base_connection.py @@ -373,14 +373,11 @@ def is_alive(self): # Try sending IAC + NOP (IAC is telnet way of sending command) # IAC = Interpret as Command; it comes before the NOP. log.debug("Sending IAC + NOP") - if self.remote_conn.sock: - # Need to send multiple times to test connection - self.remote_conn.sock.sendall(telnetlib.IAC + telnetlib.NOP) - self.remote_conn.sock.sendall(telnetlib.IAC + telnetlib.NOP) - self.remote_conn.sock.sendall(telnetlib.IAC + telnetlib.NOP) - return True - else: - return False + # Need to send multiple times to test connection + self.remote_conn.sock.sendall(telnetlib.IAC + telnetlib.NOP) + self.remote_conn.sock.sendall(telnetlib.IAC + telnetlib.NOP) + self.remote_conn.sock.sendall(telnetlib.IAC + telnetlib.NOP) + return True except AttributeError: return False else: From 7fe6bb643c41dfe91005c3a6efb2fca9d84a3801 Mon Sep 17 00:00:00 2001 From: Roman Verchikov Date: Wed, 26 Sep 2018 16:49:34 -0700 Subject: [PATCH 61/69] Close connection on prompt read failure Resolves the issue observed with Dell OS10 switches. In our environment we're using code, which can be simplified to this: ``` from netmiko import ConnectHandler while 1: try: dev = ConnectHandler( device_type='dell_os10', ip=, username=, password=) except: LOG.critical("something bad happened, retrying") time.sleep(5) ``` For some OS10 devices, prompt gets shown with a significant delay, in our particular case, more than 3 seconds. This delay results in empty prompt returned by `BaseConnection.find_prompt()`, which in turn results in `ValueError` raised. This error is not handled by `BaseConnection` constructor and happens right after `BaseConnection.establish_connection()` is called, which for the code above results in endlessly growing number of SSH connections to an OS10 device, which at some point exhausts allowed number of SSH connections, and noone can access device over SSH unless script above is stopped which cleans up all the connections. --- netmiko/base_connection.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/netmiko/base_connection.py b/netmiko/base_connection.py index e28b9eb10..a3778e0a4 100644 --- a/netmiko/base_connection.py +++ b/netmiko/base_connection.py @@ -239,12 +239,12 @@ def __init__(self, ip='', host='', username='', password='', secret='', port=Non self.protocol = 'telnet' self._modify_connection_params() self.establish_connection() - self.session_preparation() + self._safe_session_preparation() elif '_serial' in device_type: self.protocol = 'serial' self._modify_connection_params() self.establish_connection() - self.session_preparation() + self._safe_session_preparation() else: self.protocol = 'ssh' @@ -268,7 +268,7 @@ def __init__(self, ip='', host='', username='', password='', secret='', port=Non self._modify_connection_params() self.establish_connection() - self.session_preparation() + self._safe_session_preparation() def __enter__(self): """Establish a session using a Context Manager.""" @@ -639,6 +639,17 @@ def telnet_login(self, pri_prompt_terminator=r'#\s*$', alt_prompt_terminator=r'> self.remote_conn.close() raise NetMikoAuthenticationException(msg) + def _safe_session_preparation(self): + # `session_preparation()` may fail to retrieve command prompt, and raises + # ValueError, which results in connection not being closed in cases + # when context manager cannot be used. Make sure connection is always closed + # in those cases. + try: + self.session_preparation() + except Exception: + self.disconnect() + raise + def session_preparation(self): """ Prepare the session after the connection has been established From 1a091cd79c81f9bb53d62cef004621796c025f4b Mon Sep 17 00:00:00 2001 From: tcosmos Date: Tue, 2 Oct 2018 12:49:52 -0500 Subject: [PATCH 62/69] add support for f5 bash and rename ltm to tmsh --- README.md | 3 +- docs/build/html/classes/base_connection.html | 2 +- netmiko/base_connection.py | 2 +- netmiko/f5/__init__.py | 5 +-- netmiko/f5/f5_linux_ssh.py | 6 ++++ netmiko/f5/{f5_ltm_ssh.py => f5_tmsh_ssh.py} | 2 +- netmiko/snmp_autodetect.py | 6 ++-- netmiko/ssh_autodetect.py | 38 +++++++++++--------- netmiko/ssh_dispatcher.py | 6 ++-- 9 files changed, 43 insertions(+), 27 deletions(-) create mode 100644 netmiko/f5/f5_linux_ssh.py rename netmiko/f5/{f5_ltm_ssh.py => f5_tmsh_ssh.py} (96%) diff --git a/README.md b/README.md index 9cf913d8f..cddc92d5b 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,8 @@ Python 2.7, 3.5, 3.6 - Extreme EXOS - Extreme Wing - Extreme SLX (Brocade) -- F5 LTM +- F5 TMSH +- F5 Linux - Fortinet - MRV Communications OptiSwitch - Nokia/Alcatel SR-OS diff --git a/docs/build/html/classes/base_connection.html b/docs/build/html/classes/base_connection.html index 4f2ff9a05..ed5a82338 100644 --- a/docs/build/html/classes/base_connection.html +++ b/docs/build/html/classes/base_connection.html @@ -434,7 +434,7 @@

BaseConnection diff --git a/netmiko/base_connection.py b/netmiko/base_connection.py index e28b9eb10..3b3c30284 100644 --- a/netmiko/base_connection.py +++ b/netmiko/base_connection.py @@ -1454,7 +1454,7 @@ def strip_ansi_escape_codes(self, string_buffer): ESC[\d\d;\d\dm and ESC[\d\d;\d\d;\d\dm ESC[6n Get cursor position - HP ProCurve's, Cisco SG300, and F5 LTM's require this (possible others) + HP ProCurve's, Cisco SG300, and F5 Big-IP's require this (possible others) :param string_buffer: The string to be processed to remove ANSI escape codes :type string_buffer: str diff --git a/netmiko/f5/__init__.py b/netmiko/f5/__init__.py index a6c60f8cc..6189a1ee5 100644 --- a/netmiko/f5/__init__.py +++ b/netmiko/f5/__init__.py @@ -1,4 +1,5 @@ from __future__ import unicode_literals -from netmiko.f5.f5_ltm_ssh import F5LtmSSH +from netmiko.f5.f5_tmsh_ssh import F5TmshSSH +from netmiko.f5.f5_linux_ssh import F5LinuxSSH -__all__ = ['F5LtmSSH'] +__all__ = ['F5TmshSSH', 'F5LinuxSSH'] diff --git a/netmiko/f5/f5_linux_ssh.py b/netmiko/f5/f5_linux_ssh.py new file mode 100644 index 000000000..3f31c38a5 --- /dev/null +++ b/netmiko/f5/f5_linux_ssh.py @@ -0,0 +1,6 @@ +from __future__ import unicode_literals +from netmiko.linux.linux_ssh import LinuxSSH + + +class F5LinuxSSH(LinuxSSH): + pass diff --git a/netmiko/f5/f5_ltm_ssh.py b/netmiko/f5/f5_tmsh_ssh.py similarity index 96% rename from netmiko/f5/f5_ltm_ssh.py rename to netmiko/f5/f5_tmsh_ssh.py index 0b7c84a29..a439c9791 100644 --- a/netmiko/f5/f5_ltm_ssh.py +++ b/netmiko/f5/f5_tmsh_ssh.py @@ -3,7 +3,7 @@ from netmiko.base_connection import BaseConnection -class F5LtmSSH(BaseConnection): +class F5TmshSSH(BaseConnection): def session_preparation(self): """Prepare the session after the connection has been established.""" diff --git a/netmiko/snmp_autodetect.py b/netmiko/snmp_autodetect.py index 94c47458f..9cbd0fb16 100644 --- a/netmiko/snmp_autodetect.py +++ b/netmiko/snmp_autodetect.py @@ -64,9 +64,9 @@ 'cisco_wlc': {"oid": ".1.3.6.1.2.1.1.1.0", "expr": re.compile(r".*Cisco Controller.*", re.IGNORECASE), "priority": 99}, - 'f5_ltm': {"oid": ".1.3.6.1.4.1.3375.2.1.4.1.0", - "expr": re.compile(r".*BIG-IP.*", re.IGNORECASE), - "priority": 99}, + 'f5_tmsh': {"oid": ".1.3.6.1.4.1.3375.2.1.4.1.0", + "expr": re.compile(r".*BIG-IP.*", re.IGNORECASE), + "priority": 99}, 'fortinet': {"oid": ".1.3.6.1.2.1.1.1.0", "expr": re.compile(r"Forti.*", re.IGNORECASE), "priority": 80}, diff --git a/netmiko/ssh_autodetect.py b/netmiko/ssh_autodetect.py index 22a5ec917..937e59124 100644 --- a/netmiko/ssh_autodetect.py +++ b/netmiko/ssh_autodetect.py @@ -50,21 +50,6 @@ # remaining keys indicate kwargs that will be passed to dispatch method. # Note, the 'cmd' needs to avoid output paging. SSH_MAPPER_BASE = { - 'alcatel_sros': { - "cmd": "show version", - "search_patterns": [ - "Nokia", - "Alcatel", - ], - "priority": 99, - "dispatch": "_autodetect_std", - }, - 'arista_eos': { - "cmd": "show version", - "search_patterns": [r"Arista"], - "priority": 99, - "dispatch": "_autodetect_std", - }, 'cisco_ios': { "cmd": "show version", "search_patterns": [ @@ -102,6 +87,21 @@ "priority": 99, "dispatch": "_autodetect_std", }, + 'alcatel_sros': { + "cmd": "show version", + "search_patterns": [ + "Nokia", + "Alcatel", + ], + "priority": 99, + "dispatch": "_autodetect_std", + }, + 'arista_eos': { + "cmd": "show version", + "search_patterns": [r"Arista"], + "priority": 99, + "dispatch": "_autodetect_std", + }, 'dell_force10': { "cmd": "show version", "search_patterns": [r"S4048-ON"], @@ -135,12 +135,18 @@ "priority": 99, "dispatch": "_autodetect_std", }, - 'f5_ltm': { + 'f5_tmsh': { "cmd": "show sys version", "search_patterns": [r"BIG-IP"], "priority": 99, "dispatch": "_autodetect_std", }, + 'f5_linux': { + "cmd": "cat /etc/issue", + "search_patterns": [r"BIG-IP"], + "priority": 99, + "dispatch": "_autodetect_std", + }, 'linux': { "cmd": "uname -a", "search_patterns": [r"Linux"], diff --git a/netmiko/ssh_dispatcher.py b/netmiko/ssh_dispatcher.py index f7a292d9e..6e075c69b 100644 --- a/netmiko/ssh_dispatcher.py +++ b/netmiko/ssh_dispatcher.py @@ -39,7 +39,8 @@ from netmiko.extreme import ExtremeSlxSSH from netmiko.extreme import ExtremeVspSSH from netmiko.extreme import ExtremeWingSSH -from netmiko.f5 import F5LtmSSH +from netmiko.f5 import F5TmshSSH +from netmiko.f5 import F5LinuxSSH from netmiko.fortinet import FortinetSSH from netmiko.hp import HPProcurveSSH, HPProcurveTelnet, HPComwareSSH, HPComwareTelnet from netmiko.huawei import HuaweiSSH, HuaweiVrpv8SSH @@ -111,7 +112,8 @@ 'extreme_vdx': ExtremeNosSSH, 'extreme_vsp': ExtremeVspSSH, 'extreme_wing': ExtremeWingSSH, - 'f5_ltm': F5LtmSSH, + 'f5_tmsh': F5TmshSSH, + 'f5_linux': F5LinuxSSH, 'fortinet': FortinetSSH, 'generic_termserver': TerminalServerSSH, 'hp_comware': HPComwareSSH, From e476d471298b8f77f923654b055f54bbc5644a5e Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Tue, 2 Oct 2018 12:09:29 -0700 Subject: [PATCH 63/69] Minor cleanup --- netmiko/base_connection.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/netmiko/base_connection.py b/netmiko/base_connection.py index a3778e0a4..bfaa10f44 100644 --- a/netmiko/base_connection.py +++ b/netmiko/base_connection.py @@ -239,12 +239,12 @@ def __init__(self, ip='', host='', username='', password='', secret='', port=Non self.protocol = 'telnet' self._modify_connection_params() self.establish_connection() - self._safe_session_preparation() + self._try_session_preparation() elif '_serial' in device_type: self.protocol = 'serial' self._modify_connection_params() self.establish_connection() - self._safe_session_preparation() + self._try_session_preparation() else: self.protocol = 'ssh' @@ -268,7 +268,7 @@ def __init__(self, ip='', host='', username='', password='', secret='', port=Non self._modify_connection_params() self.establish_connection() - self._safe_session_preparation() + self._try_session_preparation() def __enter__(self): """Establish a session using a Context Manager.""" @@ -639,11 +639,13 @@ def telnet_login(self, pri_prompt_terminator=r'#\s*$', alt_prompt_terminator=r'> self.remote_conn.close() raise NetMikoAuthenticationException(msg) - def _safe_session_preparation(self): - # `session_preparation()` may fail to retrieve command prompt, and raises - # ValueError, which results in connection not being closed in cases - # when context manager cannot be used. Make sure connection is always closed - # in those cases. + def _try_sesssion_preparation(self): + """ + In case of an exception happening during `session_preparation()` Netmiko should + gracefully clean-up after itself. This might be challenging for library users + to do since they don't have a reference to the object. This is possibly related + to threads used in Paramiko. + """ try: self.session_preparation() except Exception: From 0be480d058238a3c83385458994109eaf4e2a5df Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Tue, 2 Oct 2018 12:11:13 -0700 Subject: [PATCH 64/69] Fix redispatch reference to session_prep --- netmiko/ssh_dispatcher.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netmiko/ssh_dispatcher.py b/netmiko/ssh_dispatcher.py index 6e075c69b..0c00c0cc3 100644 --- a/netmiko/ssh_dispatcher.py +++ b/netmiko/ssh_dispatcher.py @@ -232,7 +232,7 @@ def redispatch(obj, device_type, session_prep=True): obj.device_type = device_type obj.__class__ = new_class if session_prep: - obj.session_preparation() + obj._try_session_preparation() def FileTransfer(*args, **kwargs): From ef222a0bf55f8e28d2e374d8c4acab5be8fc89e9 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Tue, 2 Oct 2018 19:36:07 -0700 Subject: [PATCH 65/69] Minor cleanup of F5 changes --- netmiko/base_connection.py | 2 +- netmiko/ssh_autodetect.py | 72 +++++++++++++++++++------------------- netmiko/ssh_dispatcher.py | 1 + 3 files changed, 38 insertions(+), 37 deletions(-) diff --git a/netmiko/base_connection.py b/netmiko/base_connection.py index 9fec978b3..a4483c4cb 100644 --- a/netmiko/base_connection.py +++ b/netmiko/base_connection.py @@ -1467,7 +1467,7 @@ def strip_ansi_escape_codes(self, string_buffer): ESC[\d\d;\d\dm and ESC[\d\d;\d\d;\d\dm ESC[6n Get cursor position - HP ProCurve's, Cisco SG300, and F5 Big-IP's require this (possible others) + HP ProCurve and Cisco SG300 require this (possible others). :param string_buffer: The string to be processed to remove ANSI escape codes :type string_buffer: str diff --git a/netmiko/ssh_autodetect.py b/netmiko/ssh_autodetect.py index 937e59124..7f1fe9bec 100644 --- a/netmiko/ssh_autodetect.py +++ b/netmiko/ssh_autodetect.py @@ -50,55 +50,57 @@ # remaining keys indicate kwargs that will be passed to dispatch method. # Note, the 'cmd' needs to avoid output paging. SSH_MAPPER_BASE = { - 'cisco_ios': { + 'alcatel_aos': { + "cmd": "show system", + "search_patterns": [r"Alcatel-Lucent"], + "priority": 99, + "dispatch": "_autodetect_std", + }, + 'alcatel_sros': { "cmd": "show version", "search_patterns": [ - "Cisco IOS Software", - "Cisco Internetwork Operating System Software" + "Nokia", + "Alcatel", ], "priority": 99, "dispatch": "_autodetect_std", }, - 'cisco_asa': { - "cmd": "show version", - "search_patterns": [r"Cisco Adaptive Security Appliance", r"Cisco ASA"], + 'apresia_aeos': { + "cmd": "show system", + "search_patterns": ["Apresia"], "priority": 99, "dispatch": "_autodetect_std", }, - 'cisco_nxos': { + 'arista_eos': { "cmd": "show version", - "search_patterns": [r"Cisco Nexus Operating System", r"NX-OS"], + "search_patterns": [r"Arista"], "priority": 99, "dispatch": "_autodetect_std", }, - 'cisco_xr': { + 'cisco_asa': { "cmd": "show version", - "search_patterns": [r"Cisco IOS XR"], + "search_patterns": [r"Cisco Adaptive Security Appliance", r"Cisco ASA"], "priority": 99, "dispatch": "_autodetect_std", }, - 'juniper_junos': { + 'cisco_ios': { "cmd": "show version", "search_patterns": [ - r"JUNOS Software Release", - r"JUNOS .+ Software", - r"JUNOS OS Kernel", + "Cisco IOS Software", + "Cisco Internetwork Operating System Software" ], "priority": 99, "dispatch": "_autodetect_std", }, - 'alcatel_sros': { + 'cisco_nxos': { "cmd": "show version", - "search_patterns": [ - "Nokia", - "Alcatel", - ], + "search_patterns": [r"Cisco Nexus Operating System", r"NX-OS"], "priority": 99, "dispatch": "_autodetect_std", }, - 'arista_eos': { + 'cisco_xr': { "cmd": "show version", - "search_patterns": [r"Arista"], + "search_patterns": [r"Cisco IOS XR"], "priority": 99, "dispatch": "_autodetect_std", }, @@ -114,15 +116,15 @@ "priority": 99, "dispatch": "_autodetect_std", }, - 'alcatel_aos': { - "cmd": "show system", - "search_patterns": [r"Alcatel-Lucent"], + 'f5_tmsh': { + "cmd": "show sys version", + "search_patterns": [r"BIG-IP"], "priority": 99, "dispatch": "_autodetect_std", }, - 'apresia_aeos': { - "cmd": "show system", - "search_patterns": ["Apresia"], + 'f5_linux': { + "cmd": "cat /etc/issue", + "search_patterns": [r"BIG-IP"], "priority": 99, "dispatch": "_autodetect_std", }, @@ -135,15 +137,13 @@ "priority": 99, "dispatch": "_autodetect_std", }, - 'f5_tmsh': { - "cmd": "show sys version", - "search_patterns": [r"BIG-IP"], - "priority": 99, - "dispatch": "_autodetect_std", - }, - 'f5_linux': { - "cmd": "cat /etc/issue", - "search_patterns": [r"BIG-IP"], + 'juniper_junos': { + "cmd": "show version", + "search_patterns": [ + r"JUNOS Software Release", + r"JUNOS .+ Software", + r"JUNOS OS Kernel", + ], "priority": 99, "dispatch": "_autodetect_std", }, diff --git a/netmiko/ssh_dispatcher.py b/netmiko/ssh_dispatcher.py index 0c00c0cc3..9837a402d 100644 --- a/netmiko/ssh_dispatcher.py +++ b/netmiko/ssh_dispatcher.py @@ -112,6 +112,7 @@ 'extreme_vdx': ExtremeNosSSH, 'extreme_vsp': ExtremeVspSSH, 'extreme_wing': ExtremeWingSSH, + 'f5_ltm': F5TmshSSH, 'f5_tmsh': F5TmshSSH, 'f5_linux': F5LinuxSSH, 'fortinet': FortinetSSH, From dabfabfcee815e22b4b6bae48a74a2bcc03b171e Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Thu, 4 Oct 2018 09:12:35 -0700 Subject: [PATCH 66/69] Fixing bug with misspelled method --- netmiko/base_connection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netmiko/base_connection.py b/netmiko/base_connection.py index a4483c4cb..c7e5a3334 100644 --- a/netmiko/base_connection.py +++ b/netmiko/base_connection.py @@ -639,7 +639,7 @@ def telnet_login(self, pri_prompt_terminator=r'#\s*$', alt_prompt_terminator=r'> self.remote_conn.close() raise NetMikoAuthenticationException(msg) - def _try_sesssion_preparation(self): + def _try_session_preparation(self): """ In case of an exception happening during `session_preparation()` Netmiko should gracefully clean-up after itself. This might be challenging for library users From 5cd9499fcc0c1f9b48216aeca11a7adcd8995a47 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Tue, 9 Oct 2018 13:45:30 -0700 Subject: [PATCH 67/69] Fix for MRV failing to enter enable mode --- netmiko/mrv/mrv_ssh.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/netmiko/mrv/mrv_ssh.py b/netmiko/mrv/mrv_ssh.py index dddbe7412..14bee22df 100644 --- a/netmiko/mrv/mrv_ssh.py +++ b/netmiko/mrv/mrv_ssh.py @@ -11,11 +11,12 @@ class MrvOptiswitchSSH(CiscoSSHConnection): def session_preparation(self): """Prepare the session after the connection has been established.""" self._test_channel_read(pattern=r'[>#]') - self.enable() self.set_base_prompt() + self.enable() self.disable_paging(command="no cli-paging") # Clear the read buffer time.sleep(.3 * self.global_delay_factor) + self.set_base_prompt() self.clear_buffer() def enable(self, cmd='enable', pattern=r'#', re_flags=re.IGNORECASE): From 1c7c9660628c9dedab4e4f0c42befb166f6a8d31 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Tue, 9 Oct 2018 19:31:28 -0700 Subject: [PATCH 68/69] Updates to unit tests --- tests/test_netmiko_scp.py | 2 +- tests/test_suite_alt.sh | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/test_netmiko_scp.py b/tests/test_netmiko_scp.py index ad5c938fb..965362dc6 100755 --- a/tests/test_netmiko_scp.py +++ b/tests/test_netmiko_scp.py @@ -43,7 +43,7 @@ def test_verify_space_available_put(scp_fixture): ssh_conn, scp_transfer = scp_fixture assert scp_transfer.verify_space_available() == True # intentional make there not be enough space available - scp_transfer.file_size = 10000000000 + scp_transfer.file_size = 100000000000 assert scp_transfer.verify_space_available() == False def test_remote_file_size(scp_fixture): diff --git a/tests/test_suite_alt.sh b/tests/test_suite_alt.sh index c84b6e424..82f8f75d2 100755 --- a/tests/test_suite_alt.sh +++ b/tests/test_suite_alt.sh @@ -44,10 +44,6 @@ echo "Starting tests...good luck:" \ && py.test -v test_netmiko_show.py --test_device hp_procurve \ && py.test -v test_netmiko_config.py --test_device hp_procurve \ \ -&& echo "HP Comware7" \ -&& py.test -v test_netmiko_show.py --test_device hp_comware \ -&& py.test -v test_netmiko_config.py --test_device hp_comware \ -\ && echo "Juniper" \ && py.test -v test_netmiko_scp.py --test_device juniper_srx \ && py.test -v test_netmiko_show.py --test_device juniper_srx \ @@ -85,3 +81,8 @@ echo "Starting tests...good luck:" \ || RETURN_CODE=1 exit $RETURN_CODE + +# && echo "HP Comware7" \ +# && py.test -v test_netmiko_show.py --test_device hp_comware \ +# && py.test -v test_netmiko_config.py --test_device hp_comware \ +# \ From cd904bbb6cac00583786e5464dd9cfc18b670f33 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Tue, 9 Oct 2018 19:33:34 -0700 Subject: [PATCH 69/69] Rolling the version --- netmiko/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netmiko/__init__.py b/netmiko/__init__.py index 8dcd39a0a..ec0c9a3d5 100644 --- a/netmiko/__init__.py +++ b/netmiko/__init__.py @@ -23,7 +23,7 @@ NetmikoAuthError = NetMikoAuthenticationException Netmiko = ConnectHandler -__version__ = '2.2.2' +__version__ = '2.3.0' __all__ = ('ConnectHandler', 'ssh_dispatcher', 'platforms', 'SCPConn', 'FileTransfer', 'NetMikoTimeoutException', 'NetMikoAuthenticationException', 'NetmikoTimeoutError', 'NetmikoAuthError', 'InLineTransfer', 'redispatch',