netmiko-1.4.3/0000775000127700012770000000000013161517110014361 5ustar gitusergituser00000000000000netmiko-1.4.3/MANIFEST.in0000664000127700012770000000006713127751172016134 0ustar gitusergituser00000000000000include *.md include requirements.txt include LICENSE netmiko-1.4.3/setup.cfg0000664000127700012770000000026013161517110016200 0ustar gitusergituser00000000000000[pylama] linters = mccabe,pep8,pyflakes ignore = D203,C901 skip = tests/*,examples/*,build/*,.tox/* [pylama:pep8] max_line_length = 100 [egg_info] tag_build = tag_date = 0 netmiko-1.4.3/TESTING.md0000664000127700012770000000174513161264117016035 0ustar gitusergituser00000000000000# Testing This document covers the test suite for Netmiko. ## The simple version ``` cd ./netmiko/tests/etc cp test_devices.yml.example test_devices.yml cp responses.yml.example responses.yml cp commands.yml.example commands.yml ``` #### edit test_devices.yml Pick the device_types you want to test against; update: * ip * username * password * secret (optional) #### edit responses.yml For the device_types that you are testing against, update the following to match the test device(s): * the base_prompt * router_prompt * enable_prompt * interface_ip #### Execute the test ``` cd ./netmiko/tests ``` Note, the test_device is the name of the device from test_devices.yml and responses.yml: ``` py.test -v test_netmiko_show.py --test_device cisco881 py.test -v test_netmiko_config.py --test_device cisco881 ``` There are three tests available: * test_netmiko_show.py * test_netmiko_config.py * test_netmiko_commit.py # currently only for Juniper and IOS-XR netmiko-1.4.3/requirements.txt0000664000127700012770000000004413127751172017655 0ustar gitusergituser00000000000000paramiko>=1.13.0 scp>=0.10.0 pyyaml netmiko-1.4.3/VENDOR.md0000664000127700012770000000437413127751172015722 0ustar gitusergituser00000000000000Steps for adding a new vendor ======= Create a new vendor directory underneath netmiko/netmiko: ``` $ cd netmiko/netmiko $ mkdir arista ``` Make the directory a Python package: ``` $ cd arista $ touch __init__.py ``` Create a new module for the vendor: ``` $ vi arista_ssh.py from netmiko.cisco_base_connection import CiscoSSHConnection class AristaSSH(CiscoSSHConnection): pass ``` Inherit from the CiscoSSHConnection class. Note, the netmiko package will need to be in your PYTHONPATH Update \_\_init__.py to export the new class: ``` $ vi __init__.py from netmiko.arista.arista_ssh import AristaSSH __all__ = ['AristaSSH'] ``` Update the dispatcher adding the new class: ``` $ cd netmiko/netmiko $ vi ssh_dispatcher.py from netmiko.cisco import CiscoIosSSH from netmiko.cisco import CiscoAsaSSH from netmiko.arista import AristaSSH # Add here CLASS_MAPPER = { 'cisco_ios' : CiscoIosSSH, 'cisco_asa' : CiscoAsaSSH, 'arista_eos' : AristaSSH, # Add Here (device_type to class mapping) } ``` Your class will need to support the following methods: ``` def __init__(self, ip, username, password, secret='', port=22, device_type='', verbose=True): def establish_connection(self, sleep_time=3, verbose=True): def disable_paging(self): def find_prompt(self): def clear_buffer(self): def send_command(self, command_string, delay_factor=1, max_loops=30): def strip_prompt(self, a_string): def strip_command(self, command_string, output): def normalize_linefeeds(self, a_string): def enable(self): def config_mode(self): def exit_config_mode(self): def send_config_set(self, config_commands=None): def cleanup(self): def disconnect(self): ``` As much as possible, you should re-use the inherited methods from CiscoSSHConnection and BaseConnection (i.e. only re-write what you have to). BaseConnection is intended to be generic (i.e. irrespective of the vendor) CiscoSSHConnection is Cisco-IOS specific (because lots of vendors imitate Cisco IOS). You should also write unit tests and verify the functionality of your new class. See netmiko/tests/test_cisco_ios.py and netmiko/tests/test_cisco_ios_enable.py. Note, you will also need to update the 'packages' section of 'setup.py' file if you are adding a completely new package. netmiko-1.4.3/setup.py0000664000127700012770000000471313127751172016112 0ustar gitusergituser00000000000000from setuptools import setup import os import re def find_version(*file_paths): """ This pattern was modeled on a method from the Python Packaging User Guide: https://packaging.python.org/en/latest/single_source_version.html We read instead of importing so we don't get import errors if our code imports from dependencies listed in install_requires. """ base_module_file = os.path.join(*file_paths) with open(base_module_file) as f: base_module_data = f.read() version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", base_module_data, re.M) if version_match: return version_match.group(1) raise RuntimeError("Unable to find version string.") setup( name='netmiko', version=find_version('netmiko', '__init__.py'), description='Multi-vendor library to simplify Paramiko SSH connections to network devices', url='https://github.com/ktbyers/netmiko', author='Kirk Byers', author_email='ktbyers@twb-tech.com', license='MIT', classifiers=[ 'Development Status :: 4 - Beta', 'License :: OSI Approved :: MIT License', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', ], packages=['netmiko', 'netmiko/a10', 'netmiko/accedian', 'netmiko/alcatel', 'netmiko/arista', 'netmiko/aruba', 'netmiko/avaya', 'netmiko/brocade', 'netmiko/ciena', 'netmiko/cisco', 'netmiko/dell', 'netmiko/eltex', 'netmiko/enterasys', 'netmiko/extreme', 'netmiko/f5', 'netmiko/fortinet', 'netmiko/checkpoint', 'netmiko/hp', 'netmiko/huawei', 'netmiko/juniper', 'netmiko/linux', 'netmiko/mellanox', 'netmiko/mrv', 'netmiko/ovs', 'netmiko/paloalto', 'netmiko/pluribus', 'netmiko/quanta', 'netmiko/terminal_server', 'netmiko/ubiquiti', 'netmiko/vyos'], install_requires=['paramiko>=1.13.0', 'scp>=0.10.0', 'pyyaml'], extras_require={ 'test': ['pytest>=2.6.0', ] }, ) netmiko-1.4.3/LICENSE0000664000127700012770000000206613127751172015404 0ustar gitusergituser00000000000000The MIT License (MIT) Copyright (c) 2016 Kirk Byers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. netmiko-1.4.3/netmiko.egg-info/0000775000127700012770000000000013161517110017521 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko.egg-info/dependency_links.txt0000664000127700012770000000000113161517107023575 0ustar gitusergituser00000000000000 netmiko-1.4.3/netmiko.egg-info/requires.txt0000664000127700012770000000007213161517107022126 0ustar gitusergituser00000000000000paramiko>=1.13.0 scp>=0.10.0 pyyaml [test] pytest>=2.6.0 netmiko-1.4.3/netmiko.egg-info/top_level.txt0000664000127700012770000000070013161517107022256 0ustar gitusergituser00000000000000netmiko netmiko/a10 netmiko/accedian netmiko/alcatel netmiko/arista netmiko/aruba netmiko/avaya netmiko/brocade netmiko/checkpoint netmiko/ciena netmiko/cisco netmiko/dell netmiko/eltex netmiko/enterasys netmiko/extreme netmiko/f5 netmiko/fortinet netmiko/hp netmiko/huawei netmiko/juniper netmiko/linux netmiko/mellanox netmiko/mrv netmiko/ovs netmiko/paloalto netmiko/pluribus netmiko/quanta netmiko/terminal_server netmiko/ubiquiti netmiko/vyos netmiko-1.4.3/netmiko.egg-info/SOURCES.txt0000664000127700012770000000521313161517110021406 0ustar gitusergituser00000000000000COMMON_ISSUES.md LICENSE MANIFEST.in README.md TESTING.md VENDOR.md requirements.txt setup.cfg setup.py netmiko/__init__.py netmiko/base_connection.py netmiko/cisco_base_connection.py netmiko/netmiko_globals.py netmiko/py23_compat.py netmiko/scp_handler.py netmiko/snmp_autodetect.py netmiko/ssh_autodetect.py netmiko/ssh_dispatcher.py netmiko/ssh_exception.py netmiko/utilities.py netmiko.egg-info/PKG-INFO netmiko.egg-info/SOURCES.txt netmiko.egg-info/dependency_links.txt netmiko.egg-info/requires.txt netmiko.egg-info/top_level.txt netmiko/a10/__init__.py netmiko/a10/a10_ssh.py netmiko/accedian/__init__.py netmiko/accedian/accedian_ssh.py netmiko/alcatel/__init__.py netmiko/alcatel/alcatel_aos_ssh.py netmiko/alcatel/alcatel_sros_ssh.py netmiko/arista/__init__.py netmiko/arista/arista_ssh.py netmiko/aruba/__init__.py netmiko/aruba/aruba_ssh.py netmiko/avaya/__init__.py netmiko/avaya/avaya_ers_ssh.py netmiko/avaya/avaya_vsp_ssh.py netmiko/brocade/__init__.py netmiko/brocade/brocade_fastiron_ssh.py netmiko/brocade/brocade_netiron_ssh.py netmiko/brocade/brocade_nos_ssh.py netmiko/checkpoint/__init__.py netmiko/checkpoint/checkpoint_gaia_ssh.py netmiko/ciena/__init__.py netmiko/ciena/ciena_saos_ssh.py netmiko/cisco/__init__.py netmiko/cisco/cisco_asa_ssh.py netmiko/cisco/cisco_ios.py netmiko/cisco/cisco_nxos_ssh.py netmiko/cisco/cisco_s300.py netmiko/cisco/cisco_tp_tcce.py netmiko/cisco/cisco_wlc_ssh.py netmiko/cisco/cisco_xr_ssh.py netmiko/dell/__init__.py netmiko/dell/dell_force10_ssh.py netmiko/dell/dell_powerconnect_ssh.py netmiko/dell/dell_powerconnect_telnet.py netmiko/eltex/__init__.py netmiko/eltex/eltex_ssh.py netmiko/enterasys/__init__.py netmiko/enterasys/enterasys_ssh.py netmiko/extreme/__init__.py netmiko/extreme/extreme_ssh.py netmiko/extreme/extreme_wing_ssh.py netmiko/f5/__init__.py netmiko/f5/f5_ltm_ssh.py netmiko/fortinet/__init__.py netmiko/fortinet/fortinet_ssh.py netmiko/hp/__init__.py netmiko/hp/hp_comware_ssh.py netmiko/hp/hp_procurve_ssh.py netmiko/huawei/__init__.py netmiko/huawei/huawei_ssh.py netmiko/juniper/__init__.py netmiko/juniper/juniper_ssh.py netmiko/linux/__init__.py netmiko/linux/linux_ssh.py netmiko/mellanox/__init__.py netmiko/mellanox/mellanox_ssh.py netmiko/mrv/__init__.py netmiko/mrv/mrv_ssh.py netmiko/ovs/__init__.py netmiko/ovs/ovs_linux_ssh.py netmiko/paloalto/__init__.py netmiko/paloalto/paloalto_panos_ssh.py netmiko/pluribus/__init__.py netmiko/pluribus/pluribus_ssh.py netmiko/quanta/__init__.py netmiko/quanta/quanta_mesh_ssh.py netmiko/terminal_server/__init__.py netmiko/terminal_server/terminal_server.py netmiko/ubiquiti/__init__.py netmiko/ubiquiti/edge_ssh.py netmiko/vyos/__init__.py netmiko/vyos/vyos_ssh.pynetmiko-1.4.3/netmiko.egg-info/PKG-INFO0000664000127700012770000000116513161517107020627 0ustar gitusergituser00000000000000Metadata-Version: 1.1 Name: netmiko Version: 1.4.3 Summary: Multi-vendor library to simplify Paramiko SSH connections to network devices Home-page: https://github.com/ktbyers/netmiko Author: Kirk Byers Author-email: ktbyers@twb-tech.com License: MIT Description: UNKNOWN Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: License :: OSI Approved :: MIT License Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 netmiko-1.4.3/README.md0000664000127700012770000000776313161264117015663 0ustar gitusergituser00000000000000[![PyPI](https://img.shields.io/pypi/v/netmiko.svg)](https://pypi.python.org/pypi/netmiko) Netmiko ======= Multi-vendor library to simplify Paramiko SSH connections to network devices Python 2.7, 3.4, 3.5 #### Requires: Paramiko >= 1.13+ scp >= 0.10.0 pyyaml pytest (for unit tests) #### 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 ###### Limited testing Alcatel AOS6/AOS8 Avaya ERS Avaya VSP Brocade VDX Brocade ICX/FastIron Brocade MLX/NetIron Cisco WLC Dell-Force10 DNOS9 Dell PowerConnect Huawei Mellanox Palo Alto PAN-OS Pluribus Ubiquiti EdgeOS Vyatta VyOS ###### Experimental A10 Accedian Alcatel-Lucent SR-OS Aruba Ciena SAOS Cisco Telepresence CheckPoint Gaia Enterasys Extreme EXOS Extreme Wing F5 LTM Fortinet MRV Communications OptiSwitch ## Tutorials: ##### Standard Tutorial: https://pynet.twb-tech.com/blog/automation/netmiko.html ##### SSH Proxy: https://pynet.twb-tech.com/blog/automation/netmiko-proxy.html ## Examples: #### Create a dictionary representing the device. Supported device_types can be found [here](https://github.com/ktbyers/netmiko/blob/master/netmiko/ssh_dispatcher.py), see CLASS_MAPPER keys. ```py from netmiko import ConnectHandler cisco_881 = { 'device_type': 'cisco_ios', 'ip': '10.10.10.10', 'username': 'test', 'password': 'password', 'port' : 8022, # optional, defaults to 22 'secret': 'secret', # optional, defaults to '' 'verbose': False, # optional, defaults to False } ``` #### Establish an SSH connection to the device by passing in the device dictionary. ```py net_connect = ConnectHandler(**cisco_881) ``` #### Execute show commands. ```py output = net_connect.send_command('show ip int brief') 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 ``` #### For long-running commands, use `send_command_expect()` `send_command_expect` waits for the trailing prompt (or for an optional pattern) ```py net_connect.send_command_expect('write memory') ``` ``` Building configuration... [OK] ``` #### Enter and exit enable mode. ```py net_connect.enable() net_connect.exit_enable_mode() ``` #### Execute configuration change commands (will automatically enter into config mode) ```py config_commands = [ 'logging buffered 20000', 'logging buffered 20010', 'no logging console' ] output = net_connect.send_config_set(config_commands) print(output) ``` ``` pynet-rtr1#config term Enter configuration commands, one per line. End with CNTL/Z. pynet-rtr1(config)#logging buffered 20000 pynet-rtr1(config)#logging buffered 20010 pynet-rtr1(config)#no logging console pynet-rtr1(config)#end pynet-rtr1# ``` ## 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) If you have questions or would like to discuss Netmiko, a Netmiko channel exists on [this Slack](https://networktocode.slack.com) team. To join, visit [this url](http://slack.networktocode.com/) and request access to the Slack team. Once access is granted you can join the [#netmiko](https://networktocode.slack.com/messages/netmiko/) channel. --- Kirk Byers Python for Network Engineers https://pynet.twb-tech.com netmiko-1.4.3/COMMON_ISSUES.md0000664000127700012770000000561513161264117017003 0ustar gitusergituser00000000000000### Show commands that prompt for more information In these cases, I generally use the send_command_timing() method (which doesn't look for prompts) For example, a CLI interaction that looks like this: ``` pynet-rtr1#copy running-config flash:test1.txt Destination filename [test1.txt]? 5587 bytes copied in 1.316 secs (4245 bytes/sec) pynet-rtr1# ``` ```python cmd1 = "copy running-config flash:test1.txt output = net_connect.send_command_timing(cmd1) if 'Destination filename' in output: output += net_connect.send_command_timing("\n") print(output) ``` ### Enable Netmiko logging of all reads and writes of the communications channel This will create a file named 'test.log' in the current working directory. ```python import logging logging.basicConfig(filename='test.log', level=logging.DEBUG) logger = logging.getLogger("netmiko") ``` ### Does Netmiko support connecting via a terminal server There is a 'terminal_server' device_type that basically does nothing post SSH connect. This means you have to manually handle the interaction with the terminal server to connect to the end device. After you are fully connected to the end network device, you can then 'redispatch' and Netmiko will behave normally ```python from __future__ import unicode_literals, print_function import time from netmiko import ConnectHandler, redispatch net_connect = ConnectHandler( device_type='terminal_server', # Notice 'terminal_server' here ip='10.10.10.10', username='admin', password='admin123', secret='secret123') # Manually handle interaction in the Terminal Server # (fictional example, but hopefully you see the pattern) # Send Enter a Couple of Times net_connect.write_channel("\r\n") time.sleep(1) net_connect.write_channel("\r\n") time.sleep(1) output = net_connect.read_channel() print(output) # Should hopefully see the terminal server prompt # Login to end device from terminal server net_connect.write_channel("connect 1\r\n") time.sleep(1) # Manually handle the Username and Password max_loops = 10 i = 1 while i <= max_loops: output = net_connect.read_channel() if 'Username' in output: net_connect.write_channel(net_connect.username + '\r\n') time.sleep(1) output = net_connect.read_channel() # Search for password pattern / send password if 'Password' in output: net_connect.write_channel(net_connect.password + '\r\n') time.sleep(.5) output = net_connect.read_channel() # Did we successfully login if '>' in output or '#' in output: break net_connect.write_channel('\r\n') time.sleep(.5) i += 1 # We are now logged into the end device # Dynamically reset the class back to the proper Netmiko class redispatch(net_connect, device_type='cisco_ios') # Now just do your normal Netmiko operations new_output = net_connect.send_command("show ip int brief") ``` netmiko-1.4.3/PKG-INFO0000664000127700012770000000116513161517110015461 0ustar gitusergituser00000000000000Metadata-Version: 1.1 Name: netmiko Version: 1.4.3 Summary: Multi-vendor library to simplify Paramiko SSH connections to network devices Home-page: https://github.com/ktbyers/netmiko Author: Kirk Byers Author-email: ktbyers@twb-tech.com License: MIT Description: UNKNOWN Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: License :: OSI Approved :: MIT License Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 netmiko-1.4.3/netmiko/0000775000127700012770000000000013161517110016027 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/vyos/0000775000127700012770000000000013161517110017027 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/vyos/vyos_ssh.py0000664000127700012770000000773613160550515021300 0ustar gitusergituser00000000000000from __future__ import print_function from __future__ import unicode_literals from netmiko.cisco_base_connection import CiscoSSHConnection class VyOSSSH(CiscoSSHConnection): """Implement methods for interacting with VyOS network devices.""" def session_preparation(self): """Prepare the session after the connection has been established.""" self._test_channel_read() self.set_base_prompt() self.disable_paging(command="set terminal length 0\n") def check_enable_mode(self, *args, **kwargs): """No enable mode on VyOS.""" pass def enable(self, *args, **kwargs): """No enable mode on VyOS.""" pass def exit_enable_mode(self, *args, **kwargs): """No enable mode on VyOS.""" pass def check_config_mode(self, check_string='#'): """Checks if the device is in configuration mode""" return super(VyOSSSH, self).check_config_mode(check_string=check_string) def config_mode(self, config_command='configure', pattern=r'[edit]'): """Enter configuration mode.""" return super(VyOSSSH, self).config_mode(config_command=config_command, pattern=pattern) def exit_config_mode(self, exit_config='exit', pattern=r'exit'): """Exit configuration mode""" output = "" if self.check_config_mode(): output = self.send_command_timing(exit_config, strip_prompt=False, strip_command=False) if 'Cannot exit: configuration modified' in output: output += self.send_command_timing('exit discard', strip_prompt=False, strip_command=False) if self.check_config_mode(): raise ValueError("Failed to exit configuration mode") return output def commit(self, comment='', delay_factor=.1): """ Commit the candidate configuration. Commit the entered configuration. Raise an error and return the failure if the commit fails. default: command_string = commit comment: command_string = commit comment """ delay_factor = self.select_delay_factor(delay_factor) error_marker = 'Failed to generate committed config' command_string = 'commit' if comment: command_string += ' comment "{}"'.format(comment) output = self.config_mode() output += self.send_command_expect(command_string, strip_prompt=False, strip_command=False, delay_factor=delay_factor) if error_marker in output: raise ValueError('Commit failed with following errors:\n\n{}'.format(output)) return output def set_base_prompt(self, pri_prompt_terminator='$', alt_prompt_terminator='#', delay_factor=1): """Sets self.base_prompt: used as delimiter for stripping of trailing prompt in output.""" prompt = super(VyOSSSH, self).set_base_prompt(pri_prompt_terminator=pri_prompt_terminator, alt_prompt_terminator=alt_prompt_terminator, delay_factor=delay_factor) # Set prompt to user@hostname (remove two additional characters) self.base_prompt = prompt[:-2].strip() return self.base_prompt def send_config_set(self, config_commands=None, exit_config_mode=False, delay_factor=1, max_loops=150, strip_prompt=False, strip_command=False): """Remain in configuration mode.""" return super(VyOSSSH, self).send_config_set(config_commands=config_commands, exit_config_mode=exit_config_mode, delay_factor=delay_factor, max_loops=max_loops, strip_prompt=strip_prompt, strip_command=strip_command) netmiko-1.4.3/netmiko/vyos/__init__.py0000664000127700012770000000015113127751172021147 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.vyos.vyos_ssh import VyOSSSH __all__ = ['VyOSSSH'] netmiko-1.4.3/netmiko/py23_compat.py0000664000127700012770000000062613127751172020557 0ustar gitusergituser00000000000000"""Simplify Python3 compatibility. Modeled after six behavior for small set of things""" from __future__ import print_function from __future__ import unicode_literals import sys PY2 = sys.version_info.major == 2 PY3 = sys.version_info.major == 3 if sys.version_info.major == 3: string_types = (str,) text_type = str else: string_types = (basestring,) # noqa text_type = unicode # noqa netmiko-1.4.3/netmiko/eltex/0000775000127700012770000000000013161517110017150 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/eltex/eltex_ssh.py0000664000127700012770000000072213160550515021526 0ustar gitusergituser00000000000000from __future__ import print_function from __future__ import unicode_literals from netmiko.cisco_base_connection import CiscoSSHConnection class EltexSSH(CiscoSSHConnection): def session_preparation(self): """ Prepare the session after the connection has been established """ self.ansi_escape_codes = True self._test_channel_read() self.set_base_prompt() self.disable_paging(command='terminal datadump') netmiko-1.4.3/netmiko/eltex/__init__.py0000664000127700012770000000015513127751172021274 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.eltex.eltex_ssh import EltexSSH __all__ = ['EltexSSH'] netmiko-1.4.3/netmiko/quanta/0000775000127700012770000000000013161517110017320 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/quanta/quanta_mesh_ssh.py0000664000127700012770000000075613127751172023076 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.cisco_base_connection import CiscoSSHConnection class QuantaMeshSSH(CiscoSSHConnection): def disable_paging(self, command="no pager", delay_factor=1): """Disable paging""" return super(QuantaMeshSSH, self).disable_paging(command=command) def config_mode(self, config_command='configure'): """Enter configuration mode.""" return super(QuantaMeshSSH, self).config_mode(config_command=config_command) netmiko-1.4.3/netmiko/quanta/__init__.py0000664000127700012770000000017613127751172021447 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.quanta.quanta_mesh_ssh import QuantaMeshSSH __all__ = ['QuantaMeshSSH'] netmiko-1.4.3/netmiko/terminal_server/0000775000127700012770000000000013161517110021230 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/terminal_server/__init__.py0000664000127700012770000000036013127751172023352 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.terminal_server.terminal_server import TerminalServerSSH from netmiko.terminal_server.terminal_server import TerminalServerTelnet __all__ = ['TerminalServerSSH', 'TerminalServerTelnet'] netmiko-1.4.3/netmiko/terminal_server/terminal_server.py0000664000127700012770000000122113160550515025004 0ustar gitusergituser00000000000000"""Generic Terminal Server driver.""" from __future__ import unicode_literals from netmiko.base_connection import BaseConnection class TerminalServer(BaseConnection): """Generic Terminal Server driver. Allow direct write_channel / read_channel operations without session_preparation causing an exception. """ def session_preparation(self): """Do nothing here; base_prompt is not set; paging is not disabled.""" pass class TerminalServerSSH(TerminalServer): """Generic Terminal Server driver SSH.""" pass class TerminalServerTelnet(TerminalServer): """Generic Terminal Server driver telnet.""" pass netmiko-1.4.3/netmiko/fortinet/0000775000127700012770000000000013161517110017661 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/fortinet/__init__.py0000664000127700012770000000017113127751172022003 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.fortinet.fortinet_ssh import FortinetSSH __all__ = ['FortinetSSH'] netmiko-1.4.3/netmiko/fortinet/fortinet_ssh.py0000664000127700012770000000537413160550515022760 0ustar gitusergituser00000000000000from __future__ import unicode_literals import paramiko from netmiko.cisco_base_connection import CiscoSSHConnection class FortinetSSH(CiscoSSHConnection): def _modify_connection_params(self): """Modify connection parameters prior to SSH connection.""" paramiko.Transport._preferred_kex = ('diffie-hellman-group14-sha1', 'diffie-hellman-group-exchange-sha1', 'diffie-hellman-group-exchange-sha256', 'diffie-hellman-group1-sha1',) def session_preparation(self): """Prepare the session after the connection has been established.""" self._test_channel_read() self.set_base_prompt(alt_prompt_terminator='$') self.disable_paging() def disable_paging(self, delay_factor=1): """Disable paging is only available with specific roles so it may fail.""" check_command = "get system status | grep Virtual\n" output = self.send_command_timing(check_command) self.allow_disable_global = True self.vdoms = False if "Virtual domain configuration: enable" in output: self.vdoms = True vdom_additional_command = "config global" output = self.send_command_timing(vdom_additional_command, delay_factor=2) if "Command fail" in output: self.allow_disable_global = False self.remote_conn.close() self.establish_connection(width=100, height=1000) new_output = '' if self.allow_disable_global: disable_paging_commands = ["config system console", "set output standard", "end"] # There is an extra 'end' required if in multi-vdoms are enabled if self.vdoms: disable_paging_commands.append("end") outputlist = [self.send_command_timing(command, delay_factor=2) for command in disable_paging_commands] # Should test output is valid new_output = "\n".join(outputlist) return output + new_output def cleanup(self): """Re-enable paging globally.""" if self.allow_disable_global: enable_paging_commands = ["config system console", "set output more", "end"] if self.vdoms: enable_paging_commands.insert(0, "config global") # Should test output is valid for command in enable_paging_commands: self.send_command_timing(command) def config_mode(self, config_command=''): """No config mode for Fortinet devices.""" return '' def exit_config_mode(self, exit_config=''): """No config mode for Fortinet devices.""" return '' netmiko-1.4.3/netmiko/base_connection.py0000664000127700012770000012362213161264117021546 0ustar gitusergituser00000000000000''' Base connection class for netmiko Handles SSH connection and methods that are generically applicable to different platforms (Cisco and non-Cisco). Also defines methods that should generally be supported by child classes ''' from __future__ import print_function from __future__ import unicode_literals import paramiko import telnetlib import time import socket import re import io from os import path from threading import Lock from netmiko.netmiko_globals import MAX_BUFFER, BACKSPACE_CHAR from netmiko.ssh_exception import NetMikoTimeoutException, NetMikoAuthenticationException from netmiko.utilities import write_bytes from netmiko.py23_compat import string_types from netmiko import log class BaseConnection(object): """ Defines vendor independent methods. Otherwise method left as a stub method. """ 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=8, session_timeout=60, keepalive=0): """ Initialize attributes for establishing connection to target device. :param ip: IP address of target device. Not required if `host` is provided. :type ip: str :param host: Hostname of target device. Not required if `ip` is provided. :type host: str :param username: Username to authenticate against target device if required. :type username: str :param password: Password to authenticate against target device if required. :type password: str :param secret: The enable password if target device requires one. :type secret: str :param port: The destination port used to connect to the target device. :type port: int or None :param device_type: Class selection based on device type. :type device_type: str :param verbose: Enable additional messages to standard output. :type verbose: bool :param global_delay_factor: Multiplication factor affecting Netmiko delays (default: 1). :type global_delay_factor: int :param use_keys: Connect to target device using SSH keys. :type use_keys: bool :param key_file: Filename path of the SSH key file to use. :type key_file: str :param allow_agent: Enable use of SSH key-agent. :type allow_agent: bool :param ssh_strict: Automatically reject unknown SSH host keys (default: False, which means unknown SSH host keys will be accepted). :type ssh_strict: bool :param system_host_keys: Load host keys from the user's 'known_hosts' file. :type system_host_keys: bool :param alt_host_keys: If `True` host keys will be loaded from the file specified in 'alt_key_file'. :type alt_host_keys: bool :param alt_key_file: SSH host key file to use (if alt_host_keys=True). :type alt_key_file: str :param ssh_config_file: File name of OpenSSH configuration file. :type ssh_config_file: str :param timeout: Connection timeout. :type timeout: float :param session_timeout: Set a timeout for parallel requests. :type session_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). :type keepalive: int """ self.remote_conn = None if ip: self.host = ip self.ip = ip elif host: self.host = host if not ip and not host: raise ValueError("Either ip or host must be set") if port is None: if 'telnet' in device_type: self.port = 23 else: self.port = 22 else: self.port = int(port) self.username = username self.password = password self.secret = secret self.device_type = device_type self.ansi_escape_codes = False self.verbose = verbose self.timeout = timeout self.session_timeout = session_timeout self.keepalive = keepalive # Use the greater of global_delay_factor or delay_factor local to method self.global_delay_factor = global_delay_factor # set in set_base_prompt method self.base_prompt = '' self._session_locker = Lock() # determine if telnet or SSH if '_telnet' in device_type: self.protocol = 'telnet' self._modify_connection_params() self.establish_connection() self.session_preparation() else: self.protocol = 'ssh' if not ssh_strict: self.key_policy = paramiko.AutoAddPolicy() else: self.key_policy = paramiko.RejectPolicy() # Options for SSH host_keys self.use_keys = use_keys self.key_file = key_file self.allow_agent = allow_agent self.system_host_keys = system_host_keys self.alt_host_keys = alt_host_keys self.alt_key_file = alt_key_file # For SSH proxy support self.ssh_config_file = ssh_config_file self._modify_connection_params() self.establish_connection() self.session_preparation() # Clear the read buffer time.sleep(.3 * self.global_delay_factor) self.clear_buffer() def __enter__(self): """Establish a session using a Context Manager.""" return self def __exit__(self, exc_type, exc_value, traceback): """Gracefully close connection on Context Manager exit.""" self.disconnect() if exc_type is not None: raise exc_type(exc_value) def _modify_connection_params(self): """Modify connection parameters prior to SSH connection.""" pass def _timeout_exceeded(self, start, msg='Timeout exceeded!'): """ Raise NetMikoTimeoutException if waiting too much in the serving queue. """ if not start: # Must provide a comparison time return False if time.time() - start > self.session_timeout: # session_timeout exceeded raise NetMikoTimeoutException(msg) return False def _lock_netmiko_session(self, start=None): """ Try to acquire the Netmiko session lock. If not available, wait in the queue until the channel is available again. """ if not start: start = time.time() # Wait here until the SSH channel lock is acquired or until session_timeout exceeded while (not self._session_locker.acquire(False) and not self._timeout_exceeded(start, 'The netmiko channel is not available!')): time.sleep(.1) return True def _unlock_netmiko_session(self): """ Release the channel at the end of the task. """ if self._session_locker.locked(): self._session_locker.release() def _write_channel(self, out_data): """Generic handler that will write to both SSH and telnet channel.""" if self.protocol == 'ssh': self.remote_conn.sendall(write_bytes(out_data)) elif self.protocol == 'telnet': self.remote_conn.write(write_bytes(out_data)) else: raise ValueError("Invalid protocol specified") try: log.debug("write_channel: {}".format(write_bytes(out_data))) except UnicodeDecodeError: # Don't log non-ASCII characters; this is null characters and telnet IAC (PY2) pass def write_channel(self, out_data): """Generic handler that will write to both SSH and telnet channel.""" self._lock_netmiko_session() try: self._write_channel(out_data) finally: # Always unlock the SSH channel, even on exception. self._unlock_netmiko_session() def is_alive(self): """Returns a boolean flag with the state of the connection.""" null = chr(0) if self.remote_conn is None: log.error("Connection is not initialised, is_alive returns False") 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) log.debug("Sending IAC + NOP") self.device.write_channel(telnetlib.IAC + telnetlib.NOP) return True except AttributeError: return False else: # SSH try: # Try sending ASCII null byte to maintain the connection alive log.debug("Sending the NULL byte") self.write_channel(null) return self.remote_conn.transport.is_active() except (socket.error, EOFError): log.error("Unable to send", exc_info=True) # If unable to send, we can tell for sure that the connection is unusable return False return False def _read_channel(self): """Generic handler that will read all the data from an SSH or telnet channel.""" if self.protocol == 'ssh': output = "" while True: if self.remote_conn.recv_ready(): outbuf = self.remote_conn.recv(MAX_BUFFER) if len(outbuf) == 0: raise EOFError("Channel stream closed by remote device.") output += outbuf.decode('utf-8', 'ignore') else: break elif self.protocol == 'telnet': output = self.remote_conn.read_very_eager().decode('utf-8', 'ignore') log.debug("read_channel: {}".format(output)) return output def read_channel(self): """Generic handler that will read all the data from an SSH or telnet channel.""" output = "" self._lock_netmiko_session() try: output = self._read_channel() finally: # Always unlock the SSH channel, even on exception. self._unlock_netmiko_session() return output def _read_channel_expect(self, pattern='', re_flags=0, max_loops=None): """ Function that reads channel until pattern is detected. pattern takes a regular expression. By default pattern will be self.base_prompt Note: this currently reads beyond pattern. In the case of SSH it reads MAX_BUFFER. In the case of telnet it reads all non-blocking data. There are dependencies here like determining whether in config_mode that are actually depending on reading beyond pattern. """ output = '' if not pattern: pattern = re.escape(self.base_prompt) log.debug("Pattern is: {0}".format(pattern)) # Will loop for self.timeout time (override with max_loops argument) i = 1 loop_delay = .1 if not max_loops: max_loops = self.timeout / loop_delay while i < max_loops: if self.protocol == 'ssh': try: # If no data available will wait timeout seconds trying to read self._lock_netmiko_session() new_data = self.remote_conn.recv(MAX_BUFFER) if len(new_data) == 0: raise EOFError("Channel stream closed by remote device.") new_data = new_data.decode('utf-8', 'ignore') log.debug("_read_channel_expect read_data: {0}".format(new_data)) output += new_data except socket.timeout: raise NetMikoTimeoutException("Timed-out reading channel, data not available.") finally: self._unlock_netmiko_session() elif self.protocol == 'telnet': output += self.read_channel() if re.search(pattern, output, flags=re_flags): log.debug("Pattern found: {0} {1}".format(pattern, output)) return output time.sleep(loop_delay * self.global_delay_factor) i += 1 raise NetMikoTimeoutException("Timed-out reading channel, pattern not found in output: {}" .format(pattern)) def _read_channel_timing(self, delay_factor=1, max_loops=150): """ Read data on the channel based on timing delays. Attempt to read channel max_loops number of times. If no data this will cause a 15 second delay. Once data is encountered read channel for another two seconds (2 * delay_factor) to make sure reading of channel is complete. """ delay_factor = self.select_delay_factor(delay_factor) channel_data = "" i = 0 while i <= max_loops: time.sleep(.1 * delay_factor) new_data = self.read_channel() if new_data: channel_data += new_data else: # Safeguard to make sure really done time.sleep(2 * delay_factor) new_data = self.read_channel() if not new_data: break else: channel_data += new_data i += 1 return channel_data def read_until_prompt(self, *args, **kwargs): """Read channel until self.base_prompt detected. Return ALL data available.""" return self._read_channel_expect(*args, **kwargs) def read_until_pattern(self, *args, **kwargs): """Read channel until pattern detected. Return ALL data available.""" return self._read_channel_expect(*args, **kwargs) def read_until_prompt_or_pattern(self, pattern='', re_flags=0): """Read until either self.base_prompt or pattern is detected. Return ALL data available.""" combined_pattern = re.escape(self.base_prompt) if pattern: combined_pattern = r"({}|{})".format(combined_pattern, pattern) return self._read_channel_expect(combined_pattern, re_flags=re_flags) def telnet_login(self, pri_prompt_terminator='#', alt_prompt_terminator='>', username_pattern=r"sername", pwd_pattern=r"assword", delay_factor=1, max_loops=60): """Telnet login. Can be username/password or just password.""" TELNET_RETURN = '\r\n' delay_factor = self.select_delay_factor(delay_factor) time.sleep(1 * delay_factor) output = '' return_msg = '' i = 1 while i <= max_loops: try: output = self.read_channel() return_msg += output # Search for username pattern / send username if re.search(username_pattern, output): self.write_channel(self.username + TELNET_RETURN) time.sleep(1 * delay_factor) output = self.read_channel() return_msg += output # Search for password pattern / send password if re.search(pwd_pattern, output): self.write_channel(self.password + TELNET_RETURN) time.sleep(.5 * delay_factor) output = self.read_channel() return_msg += output if pri_prompt_terminator in output or alt_prompt_terminator in output: return return_msg # Check if proper data received if pri_prompt_terminator in output or alt_prompt_terminator in output: return return_msg self.write_channel(TELNET_RETURN) time.sleep(.5 * delay_factor) i += 1 except EOFError: msg = "Telnet login failed: {0}".format(self.host) raise NetMikoAuthenticationException(msg) # Last try to see if we already logged in self.write_channel(TELNET_RETURN) time.sleep(.5 * delay_factor) output = self.read_channel() return_msg += output if pri_prompt_terminator in output or alt_prompt_terminator in output: return return_msg msg = "Telnet login failed: {0}".format(self.host) raise NetMikoAuthenticationException(msg) def session_preparation(self): """ Prepare the session after the connection has been established This method handles some differences that occur between various devices early on in the session. In general, it should include: self._test_channel_read() self.set_base_prompt() self.disable_paging() self.set_terminal_width() """ self._test_channel_read() self.set_base_prompt() self.disable_paging() self.set_terminal_width() def _use_ssh_config(self, dict_arg): """Update SSH connection parameters based on contents of SSH 'config' file.""" connect_dict = dict_arg.copy() # Use SSHConfig to generate source content. full_path = path.abspath(path.expanduser(self.ssh_config_file)) if path.exists(full_path): ssh_config_instance = paramiko.SSHConfig() with io.open(full_path, "rt", encoding='utf-8') as f: ssh_config_instance.parse(f) source = ssh_config_instance.lookup(self.host) else: source = {} if source.get('proxycommand'): proxy = paramiko.ProxyCommand(source['proxycommand']) elif source.get('ProxyCommand'): proxy = paramiko.ProxyCommand(source['proxycommand']) else: proxy = None # Only update 'hostname', 'sock', 'port', and 'username' # For 'port' and 'username' only update if using object defaults if connect_dict['port'] == 22: connect_dict['port'] = int(source.get('port', self.port)) if connect_dict['username'] == '': connect_dict['username'] = source.get('username', self.username) if proxy: connect_dict['sock'] = proxy connect_dict['hostname'] = source.get('hostname', self.host) return connect_dict def _connect_params_dict(self): """Generate dictionary of Paramiko connection parameters.""" conn_dict = { 'hostname': self.host, 'port': self.port, 'username': self.username, 'password': self.password, 'look_for_keys': self.use_keys, 'allow_agent': self.allow_agent, 'key_filename': self.key_file, 'timeout': self.timeout, } # Check if using SSH 'config' file mainly for SSH proxy support if self.ssh_config_file: conn_dict = self._use_ssh_config(conn_dict) return conn_dict def _sanitize_output(self, output, strip_command=False, command_string=None, strip_prompt=False): """Sanitize the output.""" if self.ansi_escape_codes: output = self.strip_ansi_escape_codes(output) output = self.normalize_linefeeds(output) if strip_command and command_string: output = self.strip_command(command_string, output) if strip_prompt: output = self.strip_prompt(output) return output def establish_connection(self, width=None, height=None): """ Establish SSH connection to the network device Timeout will generate a NetMikoTimeoutException Authentication failure will generate a NetMikoAuthenticationException width and height are needed for Fortinet paging setting. """ if self.protocol == 'telnet': self.remote_conn = telnetlib.Telnet(self.host, port=self.port, timeout=self.timeout) self.telnet_login() elif self.protocol == 'ssh': ssh_connect_params = self._connect_params_dict() self.remote_conn_pre = self._build_ssh_client() # initiate SSH connection try: self.remote_conn_pre.connect(**ssh_connect_params) except socket.error: msg = "Connection to device timed-out: {device_type} {ip}:{port}".format( device_type=self.device_type, ip=self.host, port=self.port) raise NetMikoTimeoutException(msg) except paramiko.ssh_exception.AuthenticationException as auth_err: msg = "Authentication failure: unable to connect {device_type} {ip}:{port}".format( device_type=self.device_type, ip=self.host, port=self.port) msg += '\n' + str(auth_err) raise NetMikoAuthenticationException(msg) if self.verbose: print("SSH connection established to {0}:{1}".format(self.host, self.port)) # Use invoke_shell to establish an 'interactive session' if width and height: self.remote_conn = self.remote_conn_pre.invoke_shell(term='vt100', width=width, height=height) else: self.remote_conn = self.remote_conn_pre.invoke_shell() self.remote_conn.settimeout(self.timeout) if self.keepalive: self.remote_conn.transport.set_keepalive(self.keepalive) self.special_login_handler() if self.verbose: print("Interactive SSH session established") return "" def _test_channel_read(self, count=40, pattern=""): """Try to read the channel (generally post login) verify you receive data back.""" def _increment_delay(main_delay, increment=1.1, maximum=8): """Increment sleep time to a maximum value.""" main_delay = main_delay * increment if main_delay >= maximum: main_delay = maximum return main_delay i = 0 delay_factor = self.select_delay_factor(delay_factor=0) main_delay = delay_factor * .1 time.sleep(main_delay * 10) new_data = "" while i <= count: new_data += self._read_channel_timing() if new_data and pattern: if re.search(pattern, new_data): break elif new_data: break else: self.write_channel('\n') main_delay = _increment_delay(main_delay) time.sleep(main_delay) i += 1 # check if data was ever present if new_data: return "" else: raise NetMikoTimeoutException("Timed out waiting for data") def _build_ssh_client(self): """Prepare for Paramiko SSH connection.""" # Create instance of SSHClient object remote_conn_pre = paramiko.SSHClient() # Load host_keys for better SSH security if self.system_host_keys: remote_conn_pre.load_system_host_keys() if self.alt_host_keys and path.isfile(self.alt_key_file): remote_conn_pre.load_host_keys(self.alt_key_file) # Default is to automatically add untrusted hosts (make sure appropriate for your env) remote_conn_pre.set_missing_host_key_policy(self.key_policy) return remote_conn_pre def select_delay_factor(self, delay_factor): """Choose the greater of delay_factor or self.global_delay_factor.""" if delay_factor >= self.global_delay_factor: return delay_factor else: 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.""" pass def disable_paging(self, command="terminal length 0", delay_factor=1): """Disable paging default to a Cisco CLI method.""" delay_factor = self.select_delay_factor(delay_factor) time.sleep(delay_factor * .1) self.clear_buffer() command = self.normalize_cmd(command) log.debug("In disable_paging") log.debug("Command: {0}".format(command)) self.write_channel(command) output = self.read_until_prompt() if self.ansi_escape_codes: output = self.strip_ansi_escape_codes(output) log.debug("{0}".format(output)) log.debug("Exiting disable_paging") return output def set_terminal_width(self, command="", delay_factor=1): """ CLI terminals try to automatically adjust the line based on the width of the terminal. This causes the output to get distorted when accessed programmatically. Set terminal width to 511 which works on a broad set of devices. """ if not command: return "" delay_factor = self.select_delay_factor(delay_factor) command = self.normalize_cmd(command) self.write_channel(command) output = self.read_until_prompt() if self.ansi_escape_codes: output = self.strip_ansi_escape_codes(output) log.debug("{0}".format(output)) log.debug("Exiting set_terminal_width") return output def set_base_prompt(self, pri_prompt_terminator='#', alt_prompt_terminator='>', delay_factor=1): """ Sets self.base_prompt Used as delimiter for stripping of trailing prompt in output. Should be set to something that is general and applies in multiple contexts. For Cisco devices this will be set to router hostname (i.e. prompt without '>' or '#'). This will be set on entering user exec or privileged exec on Cisco, but not when entering/exiting config mode. """ prompt = self.find_prompt(delay_factor=delay_factor) if not prompt[-1] in (pri_prompt_terminator, alt_prompt_terminator): raise ValueError("Router prompt not found: {0}".format(repr(prompt))) # Strip off trailing terminator self.base_prompt = prompt[:-1] return self.base_prompt def find_prompt(self, delay_factor=1): """Finds the current network device prompt, last line only.""" delay_factor = self.select_delay_factor(delay_factor) self.clear_buffer() self.write_channel("\n") time.sleep(delay_factor * .1) # Initial attempt to get prompt prompt = self.read_channel() if self.ansi_escape_codes: prompt = self.strip_ansi_escape_codes(prompt) # Check if the only thing you received was a newline count = 0 prompt = prompt.strip() while count <= 10 and not prompt: prompt = self.read_channel().strip() if prompt: if self.ansi_escape_codes: prompt = self.strip_ansi_escape_codes(prompt).strip() else: self.write_channel("\n") time.sleep(delay_factor * .1) count += 1 # If multiple lines in the output take the last line prompt = self.normalize_linefeeds(prompt) prompt = prompt.split('\n')[-1] prompt = prompt.strip() if not prompt: raise ValueError("Unable to find prompt: {}".format(prompt)) time.sleep(delay_factor * .1) self.clear_buffer() return prompt def clear_buffer(self): """Read any data available in the channel.""" self.read_channel() def send_command_timing(self, command_string, delay_factor=1, max_loops=150, strip_prompt=True, strip_command=True, normalize=True): """Execute command_string on the SSH channel using a delay-based mechanism. Generally used for show commands. :param command_string: The command to be executed on the remote device. :type command_string: str :param delay_factor: Multiplying factor used to adjust delays (default: 1). :type delay_factor: int :param max_loops: Controls wait time in conjunction with delay_factor (default: 150). :type max_loops: int :param strip_prompt: Remove the trailing router prompt from the output (default: True). :type strip_prompt: bool :param strip_command: Remove the echo of the command from the output (default: True). :type strip_command: bool :param normalize: Ensure the proper enter is sent at end of command (default: True). :type normalize: bool """ output = '' delay_factor = self.select_delay_factor(delay_factor) self.clear_buffer() if normalize: command_string = self.normalize_cmd(command_string) self.write_channel(command_string) output = self._read_channel_timing(delay_factor=delay_factor, max_loops=max_loops) output = self._sanitize_output(output, strip_command=strip_command, command_string=command_string, strip_prompt=strip_prompt) return output def strip_prompt(self, a_string): """Strip the trailing router prompt from the output.""" response_list = a_string.split('\n') last_line = response_list[-1] if self.base_prompt in last_line: return '\n'.join(response_list[:-1]) else: return a_string def 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): """Execute command_string on the SSH channel using a pattern-based mechanism. Generally used for show commands. By default this method will keep waiting to receive data until the network device prompt is detected. The current network device prompt will be determined automatically. :param command_string: The command to be executed on the remote device. :type command_string: str :param expect_string: Regular expression pattern to use for determining end of output. If left blank will default to being based on router prompt. :type expect_str: str :param delay_factor: Multiplying factor used to adjust delays (default: 1). :type delay_factor: int :param max_loops: Controls wait time in conjunction with delay_factor (default: 150). :type max_loops: int :param strip_prompt: Remove the trailing router prompt from the output (default: True). :type strip_prompt: bool :param strip_command: Remove the echo of the command from the output (default: True). :type strip_command: bool :param normalize: Ensure the proper enter is sent at end of command (default: True). :type normalize: bool """ delay_factor = self.select_delay_factor(delay_factor) # Find the current router prompt if expect_string is None: if auto_find_prompt: try: prompt = self.find_prompt(delay_factor=delay_factor) except ValueError: prompt = self.base_prompt else: prompt = self.base_prompt search_pattern = re.escape(prompt.strip()) else: search_pattern = expect_string if normalize: command_string = self.normalize_cmd(command_string) time.sleep(delay_factor * .2) self.clear_buffer() self.write_channel(command_string) # Keep reading data until search_pattern is found (or max_loops) i = 1 output = '' while i <= max_loops: new_data = self.read_channel() if new_data: output += new_data try: lines = output.split("\n") 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 = "\n".join(lines) except IndexError: pass if re.search(search_pattern, output): break else: time.sleep(delay_factor * .2) i += 1 else: # nobreak raise IOError("Search pattern never detected in send_command_expect: {0}".format( search_pattern)) output = self._sanitize_output(output, strip_command=strip_command, command_string=command_string, strip_prompt=strip_prompt) return output def send_command_expect(self, *args, **kwargs): """Support previous name of send_command method.""" return self.send_command(*args, **kwargs) @staticmethod def strip_backspaces(output): """Strip any backspace characters out of the output.""" backspace_char = '\x08' return output.replace(backspace_char, '') @staticmethod def strip_command(command_string, output): """ Strip command_string from output string Cisco IOS adds backspaces into output for long commands (i.e. for commands that line wrap) """ backspace_char = '\x08' # Check for line wrap (remove backspaces) if backspace_char in output: output = output.replace(backspace_char, '') output_lines = output.split("\n") new_output = output_lines[1:] return "\n".join(new_output) else: command_length = len(command_string) return output[command_length:] @staticmethod def normalize_linefeeds(a_string): """Convert `\r\r\n`,`\r\n`, `\n\r` to `\n.`""" newline = re.compile('(\r\r\r\n|\r\r\n|\r\n|\n\r)') a_string = newline.sub('\n', a_string) # Convert any remaining \r to \n return re.sub('\r', '\n', a_string) @staticmethod def normalize_cmd(command): """Normalize CLI commands to have a single trailing newline.""" command = command.rstrip("\n") command += '\n' return command def check_enable_mode(self, check_string=''): """Check if in enable mode. Return boolean.""" self.write_channel('\n') output = self.read_until_prompt() log.debug("{0}".format(output)) return check_string in output def enable(self, cmd='', pattern='ssword', re_flags=re.IGNORECASE): """Enter enable mode.""" output = "" if not self.check_enable_mode(): self.write_channel(self.normalize_cmd(cmd)) output += self.read_until_prompt_or_pattern(pattern=pattern, re_flags=re_flags) self.write_channel(self.normalize_cmd(self.secret)) output += self.read_until_prompt() if not self.check_enable_mode(): msg = "Failed to enter enable mode. Please ensure you pass " \ "the 'secret' argument to ConnectHandler." raise ValueError(msg) return output def exit_enable_mode(self, exit_command=''): """Exit enable mode.""" output = "" if self.check_enable_mode(): self.write_channel(self.normalize_cmd(exit_command)) output += self.read_until_prompt() if self.check_enable_mode(): raise ValueError("Failed to exit enable mode.") return output def check_config_mode(self, check_string='', pattern=''): """Checks if the device is in configuration mode or not.""" log.debug("pattern: {0}".format(pattern)) self.write_channel('\n') output = self.read_until_pattern(pattern=pattern) log.debug("check_config_mode: {0}".format(repr(output))) return check_string in output def config_mode(self, config_command='', pattern=''): """Enter into config_mode.""" output = '' if not self.check_config_mode(): self.write_channel(self.normalize_cmd(config_command)) output = self.read_until_pattern(pattern=pattern) if not self.check_config_mode(): raise ValueError("Failed to enter configuration mode.") return output def exit_config_mode(self, exit_config='', pattern=''): """Exit from configuration mode.""" output = '' if self.check_config_mode(): self.write_channel(self.normalize_cmd(exit_config)) output = self.read_until_pattern(pattern=pattern) if self.check_config_mode(): raise ValueError("Failed to exit configuration mode") log.debug("exit_config_mode: {0}".format(output)) return output def send_config_from_file(self, config_file=None, **kwargs): """ Send configuration commands down the SSH channel from a file. The file is processed line-by-line and each command is sent down the SSH channel. **kwargs are passed to send_config_set method. """ with io.open(config_file, "rt", encoding='utf-8') as cfg_file: return self.send_config_set(cfg_file, **kwargs) def send_config_set(self, config_commands=None, exit_config_mode=True, delay_factor=1, max_loops=150, strip_prompt=False, strip_command=False): """ Send configuration commands down the SSH channel. config_commands is an iterable containing all of the configuration commands. The commands will be executed one after the other. Automatically exits/enters configuration mode. """ delay_factor = self.select_delay_factor(delay_factor) if config_commands is None: return '' elif isinstance(config_commands, string_types): config_commands = (config_commands,) if not hasattr(config_commands, '__iter__'): raise ValueError("Invalid argument passed into send_config_set") # Send config commands output = self.config_mode() for cmd in config_commands: self.write_channel(self.normalize_cmd(cmd)) time.sleep(delay_factor * .5) # Gather output output += self._read_channel_timing(delay_factor=delay_factor, max_loops=max_loops) if exit_config_mode: output += self.exit_config_mode() output = self._sanitize_output(output) log.debug("{0}".format(output)) return output @staticmethod def strip_ansi_escape_codes(string_buffer): """ Remove any ANSI (VT100) ESC codes from the output http://en.wikipedia.org/wiki/ANSI_escape_code Note: this does not capture ALL possible ANSI Escape Codes only the ones I have encountered Current codes that are filtered: ESC = '\x1b' or chr(27) ESC = is the escape character [^ in hex ('\x1b') ESC[24;27H Position cursor ESC[?25h Show the cursor ESC[E Next line (HP does ESC-E) ESC[K Erase line from cursor to the end of line ESC[2K Erase entire line ESC[1;24r Enable scrolling from start to row end ESC[?6l Reset mode screen with options 640 x 200 monochrome (graphics) ESC[?7l Disable line wrapping ESC[2J Code erase display ESC[00;32m Color Green (30 to 37 are different colors) more general pattern is ESC[\d\d;\d\dm and ESC[\d\d;\d\d;\d\dm HP ProCurve's, Cisco SG300, and F5 LTM's require this (possible others) """ log.debug("In strip_ansi_escape_codes") log.debug("repr = {0}".format(repr(string_buffer))) code_position_cursor = chr(27) + r'\[\d+;\d+H' code_show_cursor = chr(27) + r'\[\?25h' code_next_line = chr(27) + r'E' code_erase_line_end = chr(27) + r'\[K' code_erase_line = chr(27) + r'\[2K' code_erase_start_line = chr(27) + r'\[K' code_enable_scroll = chr(27) + r'\[\d+;\d+r' code_form_feed = chr(27) + r'\[1L' code_carriage_return = chr(27) + r'\[1M' code_disable_line_wrapping = chr(27) + r'\[\?7l' code_reset_mode_screen_options = chr(27) + r'\[\?\d+l' code_erase_display = chr(27) + r'\[2J' code_graphics_mode = chr(27) + r'\[\d\d;\d\dm' code_graphics_mode2 = chr(27) + r'\[\d\d;\d\d;\d\dm' code_set = [code_position_cursor, code_show_cursor, code_erase_line, code_enable_scroll, code_erase_start_line, code_form_feed, code_carriage_return, code_disable_line_wrapping, code_erase_line_end, code_reset_mode_screen_options, code_erase_display, code_graphics_mode, code_graphics_mode2] output = string_buffer for ansi_esc_code in code_set: output = re.sub(ansi_esc_code, '', output) # CODE_NEXT_LINE must substitute with '\n' output = re.sub(code_next_line, '\n', output) log.debug("new_output = {0}".format(output)) log.debug("repr = {0}".format(repr(output))) return output def cleanup(self): """Any needed cleanup before closing connection.""" pass def disconnect(self): """Gracefully close the SSH connection.""" self.cleanup() if self.protocol == 'ssh': self.remote_conn_pre.close() elif self.protocol == 'telnet': self.remote_conn.close() self.remote_conn = None def commit(self): """Commit method for platforms that support this.""" raise AttributeError("Network device does not support 'commit()' method") class TelnetConnection(BaseConnection): pass netmiko-1.4.3/netmiko/enterasys/0000775000127700012770000000000013161517110020044 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/enterasys/enterasys_ssh.py0000664000127700012770000000063713161264117023324 0ustar gitusergituser00000000000000"""Enterasys support.""" from __future__ import unicode_literals from netmiko.cisco_base_connection import CiscoSSHConnection class EnterasysSSH(CiscoSSHConnection): """Enterasys support.""" def session_preparation(self): """Enterasys requires enable mode to disable paging.""" self._test_channel_read() self.set_base_prompt() self.disable_paging(command="set length 0\n") netmiko-1.4.3/netmiko/enterasys/__init__.py0000664000127700012770000000017513127751172022172 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.enterasys.enterasys_ssh import EnterasysSSH __all__ = ['EnterasysSSH'] netmiko-1.4.3/netmiko/ssh_dispatcher.py0000664000127700012770000001211513160550515021411 0ustar gitusergituser00000000000000"""Controls selection of proper class based on the device type.""" from __future__ import unicode_literals from netmiko.a10 import A10SSH from netmiko.accedian import AccedianSSH from netmiko.alcatel import AlcatelAosSSH from netmiko.alcatel import AlcatelSrosSSH from netmiko.arista import AristaSSH from netmiko.aruba import ArubaSSH from netmiko.avaya import AvayaErsSSH from netmiko.avaya import AvayaVspSSH from netmiko.brocade import BrocadeFastironSSH from netmiko.brocade import BrocadeNetironSSH from netmiko.brocade import BrocadeNosSSH from netmiko.checkpoint import CheckPointGaiaSSH from netmiko.ciena import CienaSaosSSH from netmiko.cisco import CiscoAsaSSH from netmiko.cisco import CiscoIosBase from netmiko.cisco import CiscoNxosSSH from netmiko.cisco import CiscoS300SSH from netmiko.cisco import CiscoTpTcCeSSH from netmiko.cisco import CiscoWlcSSH from netmiko.cisco import CiscoXrSSH from netmiko.dell import DellForce10SSH from netmiko.dell import DellPowerConnectSSH from netmiko.dell import DellPowerConnectTelnet from netmiko.eltex import EltexSSH from netmiko.enterasys import EnterasysSSH from netmiko.extreme import ExtremeSSH from netmiko.extreme import ExtremeWingSSH from netmiko.f5 import F5LtmSSH from netmiko.fortinet import FortinetSSH from netmiko.hp import HPProcurveSSH, HPComwareSSH from netmiko.huawei import HuaweiSSH from netmiko.juniper import JuniperSSH from netmiko.linux import LinuxSSH from netmiko.mellanox import MellanoxSSH from netmiko.mrv import MrvOptiswitchSSH from netmiko.ovs import OvsLinuxSSH from netmiko.paloalto import PaloAltoPanosSSH from netmiko.pluribus import PluribusSSH from netmiko.quanta import QuantaMeshSSH from netmiko.terminal_server import TerminalServerSSH from netmiko.terminal_server import TerminalServerTelnet from netmiko.ubiquiti import UbiquitiEdgeSSH from netmiko.vyos import VyOSSSH # The keys of this dictionary are the supported device_types CLASS_MAPPER_BASE = { 'a10': A10SSH, 'accedian': AccedianSSH, 'alcatel_aos': AlcatelAosSSH, 'alcatel_sros': AlcatelSrosSSH, 'arista_eos': AristaSSH, 'aruba_os': ArubaSSH, 'avaya_ers': AvayaErsSSH, 'avaya_vsp': AvayaVspSSH, 'brocade_fastiron': BrocadeFastironSSH, 'brocade_netiron': BrocadeNetironSSH, 'brocade_nos': BrocadeNosSSH, 'brocade_vdx': BrocadeNosSSH, 'brocade_vyos': VyOSSSH, 'checkpoint_gaia': CheckPointGaiaSSH, 'ciena_saos': CienaSaosSSH, 'cisco_asa': CiscoAsaSSH, 'cisco_ios': CiscoIosBase, 'cisco_nxos': CiscoNxosSSH, 'cisco_s300': CiscoS300SSH, 'cisco_tp': CiscoTpTcCeSSH, 'cisco_wlc': CiscoWlcSSH, 'cisco_xe': CiscoIosBase, 'cisco_xr': CiscoXrSSH, 'dell_force10': DellForce10SSH, 'dell_powerconnect': DellPowerConnectSSH, 'eltex': EltexSSH, 'enterasys': EnterasysSSH, 'extreme': ExtremeSSH, 'extreme_wing': ExtremeWingSSH, 'f5_ltm': F5LtmSSH, 'fortinet': FortinetSSH, 'generic_termserver': TerminalServerSSH, 'hp_comware': HPComwareSSH, 'hp_procurve': HPProcurveSSH, 'huawei': HuaweiSSH, 'juniper': JuniperSSH, 'juniper_junos': JuniperSSH, 'linux': LinuxSSH, 'mellanox_ssh': MellanoxSSH, 'mrv_optiswitch': MrvOptiswitchSSH, 'ovs_linux': OvsLinuxSSH, 'paloalto_panos': PaloAltoPanosSSH, 'pluribus': PluribusSSH, 'quanta_mesh': QuantaMeshSSH, 'ubiquiti_edge': UbiquitiEdgeSSH, 'vyatta_vyos': VyOSSSH, 'vyos': VyOSSSH, } # Also support keys that end in _ssh new_mapper = {} for k, v in CLASS_MAPPER_BASE.items(): new_mapper[k] = v alt_key = k + u"_ssh" new_mapper[alt_key] = v CLASS_MAPPER = new_mapper # Add telnet drivers CLASS_MAPPER['cisco_ios_telnet'] = CiscoIosBase CLASS_MAPPER['dell_powerconnect_telnet'] = DellPowerConnectTelnet CLASS_MAPPER['generic_termserver_telnet'] = TerminalServerTelnet # Add general terminal_server driver and autodetect CLASS_MAPPER['terminal_server'] = TerminalServerSSH CLASS_MAPPER['autodetect'] = TerminalServerSSH platforms = list(CLASS_MAPPER.keys()) platforms.sort() platforms_base = list(CLASS_MAPPER_BASE.keys()) platforms_base.sort() platforms_str = u"\n".join(platforms_base) platforms_str = u"\n" + platforms_str def ConnectHandler(*args, **kwargs): """Factory function selects the proper class and creates object based on device_type.""" if kwargs['device_type'] not in platforms: raise ValueError('Unsupported device_type: ' 'currently supported platforms are: {0}'.format(platforms_str)) ConnectionClass = ssh_dispatcher(kwargs['device_type']) return ConnectionClass(*args, **kwargs) def ssh_dispatcher(device_type): """Select the class to be instantiated based on vendor/platform.""" return CLASS_MAPPER[device_type] def redispatch(obj, device_type, session_prep=True): """Dynamically change Netmiko object's class to proper class. Generally used with terminal_server device_type when you need to redispatch after interacting with terminal server. """ new_class = ssh_dispatcher(device_type) obj.device_type = device_type obj.__class__ = new_class if session_prep: obj.session_preparation() netmiko-1.4.3/netmiko/cisco_base_connection.py0000664000127700012770000001460613161264117022727 0ustar gitusergituser00000000000000"""CiscoBaseConnection is netmiko SSH class for Cisco and Cisco-like platforms.""" from __future__ import unicode_literals from netmiko.base_connection import BaseConnection from netmiko.ssh_exception import NetMikoAuthenticationException import re import time class CiscoBaseConnection(BaseConnection): """Base Class for cisco-like behavior.""" def check_enable_mode(self, check_string='#'): """Check if in enable mode. Return boolean.""" return super(CiscoBaseConnection, self).check_enable_mode(check_string=check_string) def enable(self, cmd='enable', pattern='ssword', re_flags=re.IGNORECASE): """Enter enable mode.""" return super(CiscoBaseConnection, self).enable(cmd=cmd, pattern=pattern, re_flags=re_flags) def exit_enable_mode(self, exit_command='disable'): """Exits enable (privileged exec) mode.""" return super(CiscoBaseConnection, self).exit_enable_mode(exit_command=exit_command) def check_config_mode(self, check_string=')#', pattern=''): """ Checks if the device is in configuration mode or not. Cisco IOS devices abbreviate the prompt at 20 chars in config mode """ if not pattern: pattern = re.escape(self.base_prompt[:16]) return super(CiscoBaseConnection, self).check_config_mode(check_string=check_string, pattern=pattern) def config_mode(self, config_command='config term', pattern=''): """ Enter into configuration mode on remote device. Cisco IOS devices abbreviate the prompt at 20 chars in config mode """ if not pattern: pattern = re.escape(self.base_prompt[:16]) return super(CiscoBaseConnection, self).config_mode(config_command=config_command, pattern=pattern) def exit_config_mode(self, exit_config='end', pattern=''): """Exit from configuration mode.""" if not pattern: pattern = re.escape(self.base_prompt[:16]) return super(CiscoBaseConnection, self).exit_config_mode(exit_config=exit_config, pattern=pattern) def telnet_login(self, pri_prompt_terminator='#', alt_prompt_terminator='>', username_pattern=r"sername", pwd_pattern=r"assword", delay_factor=1, max_loops=60): """Telnet login. Can be username/password or just password.""" TELNET_RETURN = '\r\n' delay_factor = self.select_delay_factor(delay_factor) time.sleep(1 * delay_factor) output = '' return_msg = '' i = 1 while i <= max_loops: try: output = self.read_channel() return_msg += output # Search for username pattern / send username if re.search(username_pattern, output): self.write_channel(self.username + TELNET_RETURN) time.sleep(1 * delay_factor) output = self.read_channel() return_msg += output # Search for password pattern / send password if re.search(pwd_pattern, output): self.write_channel(self.password + TELNET_RETURN) time.sleep(.5 * delay_factor) output = self.read_channel() return_msg += output if pri_prompt_terminator in output or alt_prompt_terminator in output: return return_msg # Support direct telnet through terminal server if re.search(r"initial configuration dialog\? \[yes/no\]: ", output): self.write_channel("no" + TELNET_RETURN) time.sleep(.5 * delay_factor) count = 0 while count < 15: output = self.read_channel() return_msg += output if re.search(r"ress RETURN to get started", output): output = "" break time.sleep(2 * delay_factor) count += 1 # Check for device with no password configured if re.search(r"assword required, but none set", output): msg = "Telnet login failed - Password required, but none set: {0}".format( self.host) raise NetMikoAuthenticationException(msg) # Check if proper data received if pri_prompt_terminator in output or alt_prompt_terminator in output: return return_msg self.write_channel(TELNET_RETURN) time.sleep(.5 * delay_factor) i += 1 except EOFError: msg = "Telnet login failed: {0}".format(self.host) raise NetMikoAuthenticationException(msg) # Last try to see if we already logged in self.write_channel(TELNET_RETURN) time.sleep(.5 * delay_factor) output = self.read_channel() return_msg += output if pri_prompt_terminator in output or alt_prompt_terminator in output: return return_msg msg = "Telnet login failed: {0}".format(self.host) raise NetMikoAuthenticationException(msg) def cleanup(self): """Gracefully exit the SSH session.""" try: self.exit_config_mode() except Exception: # Always try to send 'exit' regardless of whether exit_config_mode works or not. pass self.write_channel("exit\n") def _autodetect_fs(self, cmd='dir', pattern=r'Directory of (.*)/'): """Autodetect the file system on the remote device. Used by SCP operations.""" output = self.send_command_expect(cmd) match = re.search(pattern, output) if match: file_system = match.group(1) # Test file_system cmd = "dir {}".format(file_system) output = self.send_command_expect(cmd) if '% Invalid' not in output: return file_system raise ValueError("An error occurred in dynamically determining remote file " "system: {} {}".format(cmd, output)) class CiscoSSHConnection(CiscoBaseConnection): pass netmiko-1.4.3/netmiko/ovs/0000775000127700012770000000000013161517110016636 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/ovs/ovs_linux_ssh.py0000664000127700012770000000017513127751172022130 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.linux.linux_ssh import LinuxSSH class OvsLinuxSSH(LinuxSSH): pass netmiko-1.4.3/netmiko/ovs/__init__.py0000664000127700012770000000016513127751172020763 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.ovs.ovs_linux_ssh import OvsLinuxSSH __all__ = ['OvsLinuxSSH'] netmiko-1.4.3/netmiko/scp_handler.py0000664000127700012770000003525113157327305020703 0ustar gitusergituser00000000000000""" Netmiko SCP operations. Supports file get and file put operations. SCP requires a separate SSH connection for a control channel. Currently only supports Cisco IOS and Cisco ASA. """ from __future__ import print_function from __future__ import unicode_literals import re import os import hashlib import time import io import scp class SCPConn(object): """ Establish a secure copy channel to the remote network device. Must close the SCP connection to get the file to write to the remote filesystem """ def __init__(self, ssh_conn): self.ssh_ctl_chan = ssh_conn self.establish_scp_conn() def establish_scp_conn(self): """Establish the secure copy connection.""" ssh_connect_params = self.ssh_ctl_chan._connect_params_dict() self.scp_conn = self.ssh_ctl_chan._build_ssh_client() self.scp_conn.connect(**ssh_connect_params) self.scp_client = scp.SCPClient(self.scp_conn.get_transport()) def scp_transfer_file(self, source_file, dest_file): """Put file using SCP (for backwards compatibility).""" self.scp_client.put(source_file, dest_file) def scp_get_file(self, source_file, dest_file): """Get file using SCP.""" self.scp_client.get(source_file, dest_file) def scp_put_file(self, source_file, dest_file): """Put file using SCP.""" self.scp_client.put(source_file, dest_file) def close(self): """Close the SCP connection.""" self.scp_conn.close() class FileTransfer(object): """Class to manage SCP file transfer and associated SSH control channel.""" def __init__(self, ssh_conn, source_file, dest_file, file_system=None, direction='put'): self.ssh_ctl_chan = ssh_conn self.source_file = source_file self.dest_file = dest_file self.direction = direction if not file_system: self.file_system = self.ssh_ctl_chan._autodetect_fs() else: self.file_system = file_system if direction == 'put': self.source_md5 = self.file_md5(source_file) self.file_size = os.stat(source_file).st_size elif direction == 'get': self.source_md5 = self.remote_md5(remote_file=source_file) self.file_size = self.remote_file_size(remote_file=source_file) else: raise ValueError("Invalid direction specified") def __enter__(self): """Context manager setup""" self.establish_scp_conn() return self def __exit__(self, exc_type, exc_value, traceback): """Context manager cleanup.""" self.close_scp_chan() if exc_type is not None: raise exc_type(exc_value) def establish_scp_conn(self): """Establish SCP connection.""" self.scp_conn = SCPConn(self.ssh_ctl_chan) def close_scp_chan(self): """Close the SCP connection to the remote network device.""" self.scp_conn.close() self.scp_conn = None def remote_space_available(self, search_pattern=r"bytes total \((.*) bytes free\)"): """Return space available on remote device.""" remote_cmd = "dir {0}".format(self.file_system) remote_output = self.ssh_ctl_chan.send_command_expect(remote_cmd) match = re.search(search_pattern, remote_output) return int(match.group(1)) def local_space_available(self): """Return space available on local filesystem.""" destination_stats = os.statvfs(".") return destination_stats.f_bsize * destination_stats.f_bavail def verify_space_available(self, search_pattern=r"bytes total \((.*) bytes free\)"): """Verify sufficient space is available on destination file system (return boolean).""" if self.direction == 'put': space_avail = self.remote_space_available(search_pattern=search_pattern) elif self.direction == 'get': space_avail = self.local_space_available() if space_avail > self.file_size: return True return False def check_file_exists(self, remote_cmd=""): """Check if the dest_file already exists on the file system (return boolean).""" if self.direction == 'put': if not remote_cmd: remote_cmd = "dir {0}/{1}".format(self.file_system, self.dest_file) remote_out = self.ssh_ctl_chan.send_command_expect(remote_cmd) search_string = r"Directory of .*{0}".format(self.dest_file) if 'Error opening' in remote_out: return False elif re.search(search_string, remote_out): return True else: raise ValueError("Unexpected output from check_file_exists") elif self.direction == 'get': return os.path.exists(self.dest_file) def remote_file_size(self, remote_cmd="", remote_file=None): """Get the file size of the remote file.""" if remote_file is None: remote_file = self.dest_file if not remote_cmd: remote_cmd = "dir {0}/{1}".format(self.file_system, remote_file) remote_out = self.ssh_ctl_chan.send_command_expect(remote_cmd) # Strip out "Directory of flash:/filename line remote_out = re.split(r"Directory of .*", remote_out) remote_out = "".join(remote_out) # Match line containing file name escape_file_name = re.escape(remote_file) pattern = r".*({0}).*".format(escape_file_name) match = re.search(pattern, remote_out) if match: line = match.group(0) # Format will be 26 -rw- 6738 Jul 30 2016 19:49:50 -07:00 filename file_size = line.split()[2] if 'Error opening' in remote_out: raise IOError("Unable to find file on remote system") else: return int(file_size) def file_md5(self, file_name): """Compute MD5 hash of file.""" with open(file_name, "rb") as f: file_contents = f.read() file_hash = hashlib.md5(file_contents).hexdigest() return file_hash @staticmethod def process_md5(md5_output, pattern=r"= (.*)"): """ Process the string to retrieve the MD5 hash Output from Cisco IOS (ASA is similar) .MD5 of flash:file_name Done! verify /md5 (flash:file_name) = 410db2a7015eaa42b1fe71f1bf3d59a2 """ match = re.search(pattern, md5_output) if match: return match.group(1) else: raise ValueError("Invalid output from MD5 command: {0}".format(md5_output)) def compare_md5(self, base_cmd='verify /md5'): """Compare md5 of file on network device to md5 of local file""" if self.direction == 'put': remote_md5 = self.remote_md5(base_cmd=base_cmd) return self.source_md5 == remote_md5 elif self.direction == 'get': local_md5 = self.file_md5(self.dest_file) return self.source_md5 == local_md5 def remote_md5(self, base_cmd='verify /md5', remote_file=None): """ Calculate remote MD5 and return the checksum. This command can be CPU intensive on the remote device. """ if remote_file is None: remote_file = self.dest_file remote_md5_cmd = "{0} {1}{2}".format(base_cmd, self.file_system, remote_file) dest_md5 = self.ssh_ctl_chan.send_command_expect(remote_md5_cmd, delay_factor=3.0) dest_md5 = self.process_md5(dest_md5) return dest_md5 def transfer_file(self): """SCP transfer file.""" if self.direction == 'put': self.put_file() elif self.direction == 'get': self.get_file() def get_file(self): """SCP copy the file from the remote device to local system.""" self.scp_conn.scp_get_file(self.source_file, self.dest_file) self.scp_conn.close() def put_file(self): """SCP copy the file from the local system to the remote device.""" destination = "{0}{1}".format(self.file_system, self.dest_file) if ':' not in destination: raise ValueError("Invalid destination file system specified") self.scp_conn.scp_transfer_file(self.source_file, destination) # Must close the SCP connection to get the file written (flush) self.scp_conn.close() def verify_file(self): """Verify the file has been transferred correctly.""" return self.compare_md5() def enable_scp(self, cmd=None): """ Enable SCP on remote device. Defaults to Cisco IOS command """ if cmd is None: cmd = ['ip scp server enable'] elif not hasattr(cmd, '__iter__'): cmd = [cmd] self.ssh_ctl_chan.send_config_set(cmd) def disable_scp(self, cmd=None): """ Disable SCP on remote device. Defaults to Cisco IOS command """ if cmd is None: cmd = ['no ip scp server enable'] elif not hasattr(cmd, '__iter__'): cmd = [cmd] self.ssh_ctl_chan.send_config_set(cmd) class InLineTransfer(FileTransfer): """Use TCL on Cisco IOS to directly transfer file.""" def __init__(self, ssh_conn, source_file=None, dest_file=None, file_system=None, direction='put', source_config=None): if source_file and source_config: msg = "Invalid call to InLineTransfer both source_file and source_config specified." raise ValueError(msg) if direction != 'put': raise ValueError("Only put operation supported by InLineTransfer.") self.ssh_ctl_chan = ssh_conn if source_file: self.source_file = source_file self.source_config = None self.source_md5 = self.file_md5(source_file) self.file_size = os.stat(source_file).st_size elif source_config: self.source_file = None self.source_config = source_config self.source_md5 = self.config_md5(source_config) self.file_size = len(source_config.encode('UTF-8')) self.dest_file = dest_file self.direction = direction if not file_system: self.file_system = self.ssh_ctl_chan._autodetect_fs() else: self.file_system = file_system @staticmethod def _read_file(file_name): with io.open(file_name, "rt", encoding='utf-8') as f: return f.read() @staticmethod def _tcl_newline_rationalize(tcl_string): """ When using put inside a TCL {} section the newline is considered a new TCL statement and causes a missing curly-brace message. Convert "\n" to "\r". TCL will convert the "\r" to a "\n" i.e. you will see a "\n" inside the file on the Cisco IOS device. """ NEWLINE = r"\n" CARRIAGE_RETURN = r"\r" tmp_string = re.sub(NEWLINE, CARRIAGE_RETURN, tcl_string) if re.search(r"[{}]", tmp_string): msg = "Curly brace detected in string; TCL requires this be escaped." raise ValueError(msg) return tmp_string def __enter__(self): self._enter_tcl_mode() return self def __exit__(self, exc_type, exc_value, traceback): _ = self._exit_tcl_mode() # noqa if exc_type is not None: raise exc_type(exc_value) def _enter_tcl_mode(self): TCL_ENTER = 'tclsh' cmd_failed = ['Translating "tclsh"', '% Unknown command', '% Bad IP address'] output = self.ssh_ctl_chan.send_command(TCL_ENTER, expect_string=r"\(tcl\)#", strip_prompt=False, strip_command=False) for pattern in cmd_failed: if pattern in output: raise ValueError("Failed to enter tclsh mode on router: {}".format(output)) return output def _exit_tcl_mode(self): TCL_EXIT = 'tclquit' self.ssh_ctl_chan.write_channel("\r") time.sleep(1) output = self.ssh_ctl_chan.read_channel() if '(tcl)' in output: self.ssh_ctl_chan.write_channel(TCL_EXIT + "\r") time.sleep(1) output += self.ssh_ctl_chan.read_channel() return output def establish_scp_conn(self): raise NotImplementedError def close_scp_chan(self): raise NotImplementedError def local_space_available(self): raise NotImplementedError def file_md5(self, file_name): """Compute MD5 hash of file.""" file_contents = self._read_file(file_name) file_contents = file_contents + '\n' # Cisco IOS automatically adds this file_contents = file_contents.encode('UTF-8') return hashlib.md5(file_contents).hexdigest() def config_md5(self, source_config): """Compute MD5 hash of file.""" file_contents = source_config + '\n' # Cisco IOS automatically adds this file_contents = file_contents.encode('UTF-8') return hashlib.md5(file_contents).hexdigest() def put_file(self): curlybrace = r'{' TCL_FILECMD_ENTER = 'puts [open "{}{}" w+] {}'.format(self.file_system, self.dest_file, curlybrace) TCL_FILECMD_EXIT = '}' if self.source_file: file_contents = self._read_file(self.source_file) elif self.source_config: file_contents = self.source_config file_contents = self._tcl_newline_rationalize(file_contents) # Try to remove any existing data self.ssh_ctl_chan.clear_buffer() self.ssh_ctl_chan.write_channel(TCL_FILECMD_ENTER) time.sleep(.25) self.ssh_ctl_chan.write_channel(file_contents) self.ssh_ctl_chan.write_channel(TCL_FILECMD_EXIT + "\r") # This operation can be slow (depends on the size of the file) max_loops = 400 sleep_time = 4 if self.file_size >= 2500: max_loops = 1500 sleep_time = 12 elif self.file_size >= 7500: max_loops = 3000 sleep_time = 25 # Initial delay time.sleep(sleep_time) # File paste and TCL_FILECMD_exit should be indicated by "router(tcl)#" output = self.ssh_ctl_chan._read_channel_expect(pattern=r"\(tcl\)", max_loops=max_loops) # The file doesn't write until tclquit TCL_EXIT = 'tclquit' self.ssh_ctl_chan.write_channel(TCL_EXIT + "\r") time.sleep(1) # Read all data remaining from the TCLSH session output += self.ssh_ctl_chan._read_channel_expect(max_loops=max_loops) return output def get_file(self): raise NotImplementedError def enable_scp(self, cmd=None): raise NotImplementedError def disable_scp(self, cmd=None): raise NotImplementedError netmiko-1.4.3/netmiko/mellanox/0000775000127700012770000000000013161517110017646 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/mellanox/__init__.py0000664000127700012770000000017113127751172021770 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.mellanox.mellanox_ssh import MellanoxSSH __all__ = ['MellanoxSSH'] netmiko-1.4.3/netmiko/mellanox/mellanox_ssh.py0000664000127700012770000000374013161264117022726 0ustar gitusergituser00000000000000 from __future__ import unicode_literals from netmiko.cisco_base_connection import CiscoSSHConnection from netmiko import log import time class MellanoxSSH(CiscoSSHConnection): def config_mode(self, config_command='config term', pattern='#'): """Enter into config_mode.""" output = '' if not self.check_config_mode(): self.write_channel(self.normalize_cmd(config_command)) output = self.read_until_pattern(pattern=pattern) if not self.check_config_mode(): raise ValueError("Failed to enter configuration mode.") return output def check_config_mode(self, check_string='(config)', pattern=r'[>|#]'): return super(MellanoxSSH, self).check_config_mode(check_string=check_string, pattern=pattern) def disable_paging(self, command="terminal length 999", delay_factor=1): """Disable paging default to a Cisco CLI method.""" delay_factor = self.select_delay_factor(delay_factor) time.sleep(delay_factor * .1) self.clear_buffer() command = self.normalize_cmd(command) log.debug("In disable_paging") log.debug("Command: {0}".format(command)) self.write_channel(command) output = self.read_until_prompt() if self.ansi_escape_codes: output = self.strip_ansi_escape_codes(output) log.debug("{0}".format(output)) log.debug("Exiting disable_paging") return output def exit_config_mode(self, exit_config='exit', pattern='#'): """Exit from configuration mode.""" output = '' if self.check_config_mode(): self.write_channel(self.normalize_cmd(exit_config)) output = self.read_until_pattern(pattern=pattern) if self.check_config_mode(): raise ValueError("Failed to exit configuration mode") log.debug("exit_config_mode: {0}".format(output)) return output netmiko-1.4.3/netmiko/linux/0000775000127700012770000000000013161517110017166 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/linux/__init__.py0000664000127700012770000000015513127751172021312 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.linux.linux_ssh import LinuxSSH __all__ = ['LinuxSSH'] netmiko-1.4.3/netmiko/linux/linux_ssh.py0000664000127700012770000000620713161264117021567 0ustar gitusergituser00000000000000from __future__ import unicode_literals import re import socket import time from netmiko.cisco_base_connection import CiscoSSHConnection from netmiko.ssh_exception import NetMikoTimeoutException class LinuxSSH(CiscoSSHConnection): def disable_paging(self, *args, **kwargs): """Linux doesn't have paging by default.""" return "" def set_base_prompt(self, pri_prompt_terminator='$', alt_prompt_terminator='#', delay_factor=1): """Determine base prompt.""" return super(CiscoSSHConnection, self).set_base_prompt( pri_prompt_terminator=pri_prompt_terminator, alt_prompt_terminator=alt_prompt_terminator, delay_factor=delay_factor) def send_config_set(self, config_commands=None, exit_config_mode=True, **kwargs): """Can't exit from root (if root)""" if self.username == "root": exit_config_mode = False return super(CiscoSSHConnection, self).send_config_set(config_commands=config_commands, exit_config_mode=exit_config_mode, **kwargs) def check_config_mode(self, check_string='#'): """Verify root""" return self.check_enable_mode(check_string=check_string) def config_mode(self, config_command='sudo su'): """Attempt to become root.""" return self.enable(cmd=config_command) def exit_config_mode(self, exit_config='exit'): return self.exit_enable_mode(exit_command=exit_config) def check_enable_mode(self, check_string='#'): """Verify root""" return super(CiscoSSHConnection, self).check_enable_mode(check_string=check_string) def exit_enable_mode(self, exit_command='exit'): """Exit enable mode.""" delay_factor = self.select_delay_factor(delay_factor=0) output = "" if self.check_enable_mode(): self.write_channel(self.normalize_cmd(exit_command)) time.sleep(.3 * delay_factor) self.set_base_prompt() if self.check_enable_mode(): raise ValueError("Failed to exit enable mode.") return output def enable(self, cmd='sudo su', pattern='ssword', re_flags=re.IGNORECASE): """Attempt to become root.""" delay_factor = self.select_delay_factor(delay_factor=0) output = "" if not self.check_enable_mode(): self.write_channel(self.normalize_cmd(cmd)) time.sleep(.3 * delay_factor) try: output += self.read_channel() if re.search(pattern, output, flags=re_flags): self.write_channel(self.normalize_cmd(self.secret)) self.set_base_prompt() except socket.timeout: raise NetMikoTimeoutException("Timed-out reading channel, data not available.") if not self.check_enable_mode(): msg = "Failed to enter enable mode. Please ensure you pass " \ "the 'secret' argument to ConnectHandler." raise ValueError(msg) return output netmiko-1.4.3/netmiko/ciena/0000775000127700012770000000000013161517110017106 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/ciena/ciena_saos_ssh.py0000664000127700012770000000072113160550515022446 0ustar gitusergituser00000000000000"""Ciena SAOS support.""" from __future__ import print_function from __future__ import unicode_literals from netmiko.cisco_base_connection import CiscoSSHConnection class CienaSaosSSH(CiscoSSHConnection): """Ciena SAOS support.""" def session_preparation(self): self._test_channel_read() self.set_base_prompt() self.disable_paging(command="system shell session set more off\n") def enable(self, *args, **kwargs): pass netmiko-1.4.3/netmiko/ciena/__init__.py0000664000127700012770000000017213127751172021231 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.ciena.ciena_saos_ssh import CienaSaosSSH __all__ = ['CienaSaosSSH'] netmiko-1.4.3/netmiko/__init__.py0000664000127700012770000000225013161264117020145 0ustar gitusergituser00000000000000from __future__ import unicode_literals import logging # Logging configuration log = logging.getLogger(__name__) # noqa log.addHandler(logging.NullHandler()) # noqa from netmiko.ssh_dispatcher import ConnectHandler from netmiko.ssh_dispatcher import ssh_dispatcher from netmiko.ssh_dispatcher import redispatch from netmiko.ssh_dispatcher import platforms from netmiko.scp_handler import SCPConn from netmiko.scp_handler import FileTransfer from netmiko.scp_handler import InLineTransfer from netmiko.ssh_exception import NetMikoTimeoutException from netmiko.ssh_exception import NetMikoAuthenticationException from netmiko.ssh_autodetect import SSHDetect from netmiko.base_connection import BaseConnection # Alternate naming NetmikoTimeoutError = NetMikoTimeoutException NetmikoAuthError = NetMikoAuthenticationException __version__ = '1.4.3' __all__ = ('ConnectHandler', 'ssh_dispatcher', 'platforms', 'SCPConn', 'FileTransfer', 'NetMikoTimeoutException', 'NetMikoAuthenticationException', 'NetmikoTimeoutError', 'NetmikoAuthError', 'InLineTransfer', 'redispatch', 'SSHDetect', 'BaseConnection') # Cisco cntl-shift-six sequence CNTL_SHIFT_6 = chr(30) netmiko-1.4.3/netmiko/ubiquiti/0000775000127700012770000000000013161517110017662 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/ubiquiti/__init__.py0000664000127700012770000000017513127751172022010 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.ubiquiti.edge_ssh import UbiquitiEdgeSSH __all__ = ['UbiquitiEdgeSSH'] netmiko-1.4.3/netmiko/ubiquiti/edge_ssh.py0000664000127700012770000000200513137412636022024 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.cisco_base_connection import CiscoSSHConnection class UbiquitiEdgeSSH(CiscoSSHConnection): """ Implements support for Ubiquity Edge devices. Mostly conforms to Cisco IOS style syntax with a few minor changes. """ def check_config_mode(self, check_string=')#'): """Checks if the device is in configuration mode or not.""" return super(UbiquitiEdgeSSH, self).check_config_mode(check_string=check_string) def config_mode(self, config_command='configure'): """Enter configuration mode.""" return super(UbiquitiEdgeSSH, self).config_mode(config_command=config_command) def exit_config_mode(self, exit_config='exit'): """Exit configuration mode.""" return super(UbiquitiEdgeSSH, self).exit_config_mode(exit_config=exit_config) def exit_enable_mode(self, exit_command='exit'): """Exit enable mode.""" return super(UbiquitiEdgeSSH, self).exit_enable_mode(exit_command=exit_command) netmiko-1.4.3/netmiko/hp/0000775000127700012770000000000013161517110016436 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/hp/hp_comware_ssh.py0000664000127700012770000000457313160550515022027 0ustar gitusergituser00000000000000from __future__ import print_function from __future__ import unicode_literals from netmiko.cisco_base_connection import CiscoSSHConnection class HPComwareSSH(CiscoSSHConnection): def session_preparation(self): """ Prepare the session after the connection has been established. Extra time to read HP banners. """ self._test_channel_read(pattern=r'[>\]]') self.set_base_prompt() self.disable_paging(command="\nscreen-length disable\n") def config_mode(self, config_command='system-view'): """Enter configuration mode.""" return super(HPComwareSSH, self).config_mode(config_command=config_command) def exit_config_mode(self, exit_config='return'): """Exit config mode.""" return super(HPComwareSSH, self).exit_config_mode(exit_config=exit_config) def check_config_mode(self, check_string=']'): """Check whether device is in configuration mode. Return a boolean.""" return super(HPComwareSSH, self).check_config_mode(check_string=check_string) def set_base_prompt(self, pri_prompt_terminator='>', alt_prompt_terminator=']', delay_factor=1): """ Sets self.base_prompt Used as delimiter for stripping of trailing prompt in output. Should be set to something that is general and applies in multiple contexts. For Comware this will be the router prompt with < > or [ ] stripped off. This will be set on logging in, but not when entering system-view """ prompt = super(HPComwareSSH, self).set_base_prompt( pri_prompt_terminator=pri_prompt_terminator, alt_prompt_terminator=alt_prompt_terminator, delay_factor=delay_factor) # Strip off leading character prompt = prompt[1:] prompt = prompt.strip() self.base_prompt = prompt return self.base_prompt def enable(self, cmd='system-view'): """enable mode on Comware is system-view.""" return self.config_mode(config_command=cmd) def exit_enable_mode(self, exit_command='return'): """enable mode on Comware is system-view.""" return self.exit_config_mode(exit_config=exit_command) def check_enable_mode(self, check_string=']'): """enable mode on Comware is system-view.""" return self.check_config_mode(check_string=check_string) netmiko-1.4.3/netmiko/hp/hp_procurve_ssh.py0000664000127700012770000000443613161264117022236 0ustar gitusergituser00000000000000from __future__ import print_function from __future__ import unicode_literals import re import time import socket from netmiko.cisco_base_connection import CiscoSSHConnection from netmiko import log class HPProcurveSSH(CiscoSSHConnection): def session_preparation(self): """ Prepare the session after the connection has been established. Procurve uses - 'Press any key to continue' """ delay_factor = self.select_delay_factor(delay_factor=0) output = "" count = 1 while count <= 30: output += self.read_channel() if 'any key to continue' in output: self.write_channel("\n") break else: time.sleep(.33 * delay_factor) count += 1 # Try one last time to past "Press any key to continue self.write_channel("\n") # HP output contains VT100 escape codes self.ansi_escape_codes = True self._test_channel_read(pattern=r'[>#]') self.set_base_prompt() self.disable_paging(command="\nno page\n") self.set_terminal_width(command='terminal width 511') def enable(self, cmd='enable', pattern='password', re_flags=re.IGNORECASE, default_username='manager'): """Enter enable mode""" output = self.send_command_timing(cmd) if 'username' in output.lower(): output += self.send_command_timing(default_username) if 'password' in output.lower(): output += self.send_command_timing(self.secret) log.debug("{0}".format(output)) self.clear_buffer() return output def cleanup(self): """Gracefully exit the SSH session.""" self.exit_config_mode() self.write_channel("logout\n") count = 0 while count <= 5: time.sleep(.5) output = self.read_channel() if 'Do you want to log out' in output: self.write_channel("y\n") # Don't automatically save the config (user's responsibility) elif 'Do you want to save the current' in output: self.write_channel("n\n") try: self.write_channel("\n") except socket.error: break count += 1 netmiko-1.4.3/netmiko/hp/__init__.py0000664000127700012770000000027513127751172020565 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.hp.hp_procurve_ssh import HPProcurveSSH from netmiko.hp.hp_comware_ssh import HPComwareSSH __all__ = ['HPProcurveSSH', 'HPComwareSSH'] netmiko-1.4.3/netmiko/snmp_autodetect.py0000664000127700012770000002433613127751172021621 0ustar gitusergituser00000000000000""" This module is used to auto-detect the type of a device in order to automatically create a Netmiko connection. The will avoid to hard coding the 'device_type' when using the ConnectHandler factory function from Netmiko. Example: ------------------ from netmiko.snmp_autodetect import SNMPDetect my_snmp = SNMPDetect(hostname='1.1.1.70', user='pysnmp', auth_key='key1', encrypt_key='key2') device_type = my_snmp.autodetect() ------------------ autodetect will return None if no match. SNMPDetect class defaults to SNMPv3 Note, pysnmp is a required dependency for SNMPDetect and is intentionally not included in netmiko requirements. So installation of pysnmp might be required. """ from __future__ import unicode_literals import re try: from pysnmp.entity.rfc3413.oneliner import cmdgen except ImportError: raise ImportError("pysnmp not installed; please install it: 'pip install pysnmp'") from netmiko.ssh_dispatcher import CLASS_MAPPER # Higher priority indicates a better match. SNMP_MAPPER_BASE = { 'arista_eos': {"oid": ".1.3.6.1.2.1.1.1.0", "expr": re.compile(r".*Arista Networks EOS.*", re.IGNORECASE), "priority": 99}, 'hp_comware': {"oid": ".1.3.6.1.2.1.1.1.0", "expr": re.compile(r".*HP Comware.*", 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}, 'cisco_xe': {"oid": ".1.3.6.1.2.1.1.1.0", "expr": re.compile(r".*IOS-XE Software,.*", re.IGNORECASE), "priority": 99}, 'cisco_xr': {"oid": ".1.3.6.1.2.1.1.1.0", "expr": re.compile(r".*Cisco IOS XR Software.*", re.IGNORECASE), "priority": 99}, 'cisco_asa': {"oid": ".1.3.6.1.2.1.1.1.0", "expr": re.compile(r".*Cisco Adaptive Security Appliance.*", re.IGNORECASE), "priority": 99}, 'cisco_nxos': {"oid": ".1.3.6.1.2.1.1.1.0", "expr": re.compile(r".*Cisco NX-OS.*", re.IGNORECASE), "priority": 99}, '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}, 'fortinet': {"oid": ".1.3.6.1.2.1.1.1.0", "expr": re.compile(r"Forti.*", re.IGNORECASE), "priority": 80}, 'checkpoint': {"oid": ".1.3.6.1.4.1.2620.1.6.16.9.0", "expr": re.compile(r"CheckPoint"), "priority": 79}, } # Ensure all SNMP device types are supported by Netmiko SNMP_MAPPER = {} std_device_types = list(CLASS_MAPPER.keys()) for device_type in std_device_types: if SNMP_MAPPER_BASE.get(device_type): SNMP_MAPPER[device_type] = SNMP_MAPPER_BASE[device_type] class SNMPDetect(object): """ The SNMPDetect class tries to automatically determine the device type. Typically this will use the MIB-2 SysDescr and regular expressions. Parameters ---------- hostname: str The name or IP address of the hostname we want to guess the type snmp_version : str, optional ('v1', 'v2c' or 'v3') The SNMP version that is running on the device (default: 'v3') snmp_port : int, optional The UDP port on which SNMP is listening (default: 161) community : str, optional The SNMP read community when using SNMPv2 (default: None) user : str, optional The SNMPv3 user for authentication (default: '') auth_key : str, optional The SNMPv3 authentication key (default: '') encrypt_key : str, optional The SNMPv3 encryption key (default: '') auth_proto : str, optional ('des', '3des', 'aes128', 'aes192', 'aes256') The SNMPv3 authentication protocol (default: 'aes128') encrypt_proto : str, optional ('sha', 'md5') The SNMPv3 encryption protocol (default: 'sha') Attributes ---------- hostname: str The name or IP address of the device we want to guess the type snmp_version : str The SNMP version that is running on the device snmp_port : int The UDP port on which SNMP is listening community : str The SNMP read community when using SNMPv2 user : str The SNMPv3 user for authentication auth_key : str The SNMPv3 authentication key encrypt_key : str The SNMPv3 encryption key auth_proto : str The SNMPv3 authentication protocol encrypt_proto : str The SNMPv3 encryption protocol Methods ------- autodetect() Try to determine the device type. """ def __init__(self, hostname, snmp_version="v3", snmp_port=161, community=None, user="", auth_key="", encrypt_key="", auth_proto="sha", encrypt_proto="aes128"): # Check that the SNMP version is matching predefined type or raise ValueError if snmp_version == "v1" or snmp_version == "v2c": if not community: raise ValueError("SNMP version v1/v2c community must be set.") elif snmp_version == "v3": if not user: raise ValueError("SNMP version v3 user and password must be set") else: raise ValueError("SNMP version must be set to 'v1', 'v2c' or 'v3'") # Check that the SNMPv3 auth & priv parameters match allowed types self._snmp_v3_authentication = {"sha": cmdgen.usmHMACSHAAuthProtocol, "md5": cmdgen.usmHMACMD5AuthProtocol} self._snmp_v3_encryption = {"des": cmdgen.usmDESPrivProtocol, "3des": cmdgen.usm3DESEDEPrivProtocol, "aes128": cmdgen.usmAesCfb128Protocol, "aes192": cmdgen.usmAesCfb192Protocol, "aes256": cmdgen.usmAesCfb256Protocol} if auth_proto not in self._snmp_v3_authentication.keys(): raise ValueError("SNMP V3 'auth_proto' argument must be one of the following: {}" .format(self._snmp_v3_authentication.keys())) if encrypt_proto not in self._snmp_v3_encryption.keys(): raise ValueError("SNMP V3 'encrypt_proto' argument must be one of the following: {}" .format(self._snmp_v3_encryption.keys())) self.hostname = hostname self.snmp_version = snmp_version self.snmp_port = snmp_port self.community = community self.user = user self.auth_key = auth_key self.encrypt_key = encrypt_key self.auth_proto = self._snmp_v3_authentication[auth_proto] self.encryp_proto = self._snmp_v3_encryption[encrypt_proto] self._response_cache = {} def _get_snmpv3(self, oid): """ Try to send an SNMP GET operation using SNMPv3 for the specified OID. Parameters ---------- oid : str The SNMP OID that you want to get. Returns ------- string : str The string as part of the value from the OID you are trying to retrieve. """ snmp_target = (self.hostname, self.snmp_port) cmd_gen = cmdgen.CommandGenerator() (error_detected, error_status, error_index, snmp_data) = cmd_gen.getCmd( cmdgen.UsmUserData(self.user, self.auth_key, self.encrypt_key, authProtocol=self.auth_proto, privProtocol=self.encryp_proto), cmdgen.UdpTransportTarget(snmp_target, timeout=1.5, retries=2), oid, lookupNames=True, lookupValues=True) if not error_detected and snmp_data[0][1]: return str(snmp_data[0][1]) return "" def _get_snmpv2c(self, oid): """ Try to send an SNMP GET operation using SNMPv2 for the specified OID. Parameters ---------- oid : str The SNMP OID that you want to get. Returns ------- string : str The string as part of the value from the OID you are trying to retrieve. """ snmp_target = (self.hostname, self.snmp_port) cmd_gen = cmdgen.CommandGenerator() (error_detected, error_status, error_index, snmp_data) = cmd_gen.getCmd( cmdgen.CommunityData(self.community), cmdgen.UdpTransportTarget(snmp_target, timeout=1.5, retries=2), oid, lookupNames=True, lookupValues=True) if not error_detected and snmp_data[0][1]: return str(snmp_data[0][1]) return "" def _get_snmp(self, oid): """Wrapper for generic SNMP call.""" if self.snmp_version in ["v1", "v2c"]: return self._get_snmpv2c(oid) else: return self._get_snmpv3(oid) def autodetect(self): """ Try to guess the device_type using SNMP GET based on the SNMP_MAPPER dict. The type which is returned is directly matching the name in *netmiko.ssh_dispatcher.CLASS_MAPPER_BASE* dict. Thus you can use this name to retrieve automatically the right ConnectionClass Returns ------- potential_type : str The name of the device_type that must be running. """ # Convert SNMP_MAPPER to a list and sort by priority snmp_mapper_list = [] for k, v in SNMP_MAPPER.items(): snmp_mapper_list.append({k: v}) snmp_mapper_list = sorted(snmp_mapper_list, key=lambda x: list(x.values())[0]['priority']) snmp_mapper_list.reverse() for entry in snmp_mapper_list: for device_type, v in entry.items(): oid = v['oid'] regex = v['expr'] # Used cache data if we already queryied this OID if self._response_cache.get(oid): snmp_response = self._response_cache.get(oid) else: snmp_response = self._get_snmp(oid) self._response_cache[oid] = snmp_response # See if we had a match if re.search(regex, snmp_response): return device_type return None netmiko-1.4.3/netmiko/extreme/0000775000127700012770000000000013161517110017500 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/extreme/extreme_wing_ssh.py0000664000127700012770000000074113160550515023433 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.cisco_base_connection import CiscoSSHConnection class ExtremeWingSSH(CiscoSSHConnection): """Extreme WiNG support.""" def session_preparation(self): self.set_base_prompt(pri_prompt_terminator='>', alt_prompt_terminator='#', delay_factor=2) self.disable_paging(command="no page\n") self.set_terminal_width(command='terminal width 512') netmiko-1.4.3/netmiko/extreme/__init__.py0000664000127700012770000000030313127751172021617 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.extreme.extreme_ssh import ExtremeSSH from netmiko.extreme.extreme_wing_ssh import ExtremeWingSSH __all__ = ['ExtremeSSH', 'ExtremeWingSSH'] netmiko-1.4.3/netmiko/extreme/extreme_ssh.py0000664000127700012770000000400113161264117022401 0ustar gitusergituser00000000000000"""Extreme support.""" from __future__ import unicode_literals import re from netmiko.cisco_base_connection import CiscoSSHConnection class ExtremeSSH(CiscoSSHConnection): """Extreme support. Designed for EXOS >= 15.0 """ def session_preparation(self): self._test_channel_read() self.set_base_prompt() self.disable_paging(command="disable clipaging\n") def set_base_prompt(self, *args, **kwargs): """ Extreme attaches an id to the prompt. The id increases with every command. It needs to br stripped off to match the prompt. Eg. testhost.1 # testhost.2 # testhost.3 # If new config is loaded and not saved yet, a '* ' prefix appears before the prompt, eg. * testhost.4 # * testhost.5 # """ cur_base_prompt = super(ExtremeSSH, 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: self.base_prompt = match.group(1) return self.base_prompt else: return self.base_prompt def send_command(self, *args, **kwargs): """Extreme needs special handler here due to the prompt changes.""" # Change send_command behavior to use self.base_prompt kwargs.setdefault('auto_find_prompt', False) # refresh self.base_prompt self.set_base_prompt() return super(ExtremeSSH, self).send_command(*args, **kwargs) def config_mode(self, config_command=''): """No configuration mode on Extreme.""" return '' def check_config_mode(self, check_string='#'): """Checks whether in configuration mode. Returns a boolean.""" return super(ExtremeSSH, self).check_config_mode(check_string=check_string) def exit_config_mode(self, exit_config=''): """No configuration mode on Extreme.""" return '' netmiko-1.4.3/netmiko/ssh_autodetect.py0000664000127700012770000002273413161264117021435 0ustar gitusergituser00000000000000""" The ssh_autodetect module is used to auto-detect the netmiko device_type to use to further initiate a new SSH connection with a remote host. This auto-detection is based on a unique class called **SSHDetect**. Notes ----- The **SSHDetect** class is instantiated using the same parameters than a standard Netmiko connection (see the *netmiko.ssh_dispatacher.ConnectHandler* function). The only acceptable value for the 'device_type' argument is 'autodetect'. The auto-detection is solely based on the *SSH_MAPPER_BASE* dictionary. The keys are the name of the 'device_type' supported for auto-detection and the value is another dictionary describing how to handle the auto-detection. * "cmd" : The command to send to the remote device. **The command output must not require paging.** * "search_patterns" : A list of regex to compare with the output of the command * "priority" : An integer (0-99) which specifies the confidence of the match above * "dispatch" : The function to call to try the autodetection (per default SSHDetect._autodetect_std) Examples -------- # Auto-detection section >>> from netmiko.ssh_autodetect import SSHDetect >>> from netmiko.ssh_dispatcher import ConnectHandler >>> remote_device = {'device_type': 'autodetect', 'host': 'remote.host', 'username': 'test', 'password': 'foo'} >>> guesser = SSHDetect(**remote_device) >>> best_match = guesser.autodetect() >>> print(best_match) # Name of the best device_type to use further >>> print(guesser.potential_matches) # Dictionary of the whole matching result # Netmiko connection creation section >>> remote_device['device_type'] = best_match >>> connection = ConnectHandler(**remote_device) """ from __future__ import unicode_literals import re import time from netmiko.ssh_dispatcher import ConnectHandler from netmiko.base_connection import BaseConnection # 'dispatch' key is the SSHDetect method to call. dispatch key will be popped off dictionary # remaining keys indicate kwargs that will be passed to dispatch method. SSH_MAPPER_BASE = { 'alcatel_aos': { "cmd": "show system", "search_patterns": ["Alcatel-Lucent"], "priority": 99, "dispatch": "_autodetect_std", }, 'alcatel_sros': { "cmd": "show version | match ALCATEL", "search_patterns": ["TiMOS"], "priority": 99, "dispatch": "_autodetect_std", }, 'arista_eos': { "cmd": "show version | inc rist", "search_patterns": ["Arista"], "priority": 99, "dispatch": "_autodetect_std", }, 'cisco_ios': { "cmd": "show version | inc Cisco", "search_patterns": [ "Cisco IOS Software", "Cisco Internetwork Operating System Software" ], "priority": 99, "dispatch": "_autodetect_std", }, 'cisco_asa': { "cmd": "show version | inc Cisco", "search_patterns": ["Cisco Adaptive Security Appliance", "Cisco ASA"], "priority": 99, "dispatch": "_autodetect_std", }, 'cisco_nxos': { "cmd": "show version | inc Cisco", "search_patterns": ["Cisco Nexus Operating System", "NX-OS"], "priority": 99, "dispatch": "_autodetect_std", }, 'cisco_xr': { "cmd": "show version | inc Cisco", "search_patterns": ["Cisco IOS XR"], "priority": 99, "dispatch": "_autodetect_std", }, 'huawei': { "cmd": "display version | inc Huawei", "search_patterns": ["Huawei Technologies", "Huawei Versatile Routing Platform Software"], "priority": 99, "dispatch": "_autodetect_std", }, 'juniper_junos': { "cmd": "show version | match JUNOS", "search_patterns": ["JUNOS Software Release", "JUNOS .+ Software"], "priority": 99, "dispatch": "_autodetect_std", }, } class SSHDetect(object): """ The SSHDetect class tries to automatically guess the device type running on the SSH remote end. Be careful that the kwargs 'device_type' must be set to 'autodetect', otherwise it won't work at all. Parameters ---------- *args : list The same *args that you might provide to the netmiko.ssh_dispatcher.ConnectHandler. *kwargs : dict The same *kwargs that you might provide to the netmiko.ssh_dispatcher.ConnectHandler. Attributes ---------- connection : netmiko.terminal_server.TerminalServer A basic connection to the remote SSH end. potential_matches: dict Dict of (device_type, accuracy) that is populated through an interaction with the remote end. Methods ------- autodetect() Try to determine the device type. """ def __init__(self, *args, **kwargs): """ Constructor of the SSHDetect class """ if kwargs["device_type"] != "autodetect": raise ValueError("The connection device_type must be 'autodetect'") self.connection = ConnectHandler(*args, **kwargs) # Call the _test_channel_read() in base to clear initial data output = BaseConnection._test_channel_read(self.connection) self.initial_buffer = output self.potential_matches = {} self._results_cache = {} def autodetect(self): """ Try to guess the best 'device_type' based on patterns defined in SSH_MAPPER_BASE Returns ------- best_match : str or None The device type that is currently the best to use to interact with the device """ for device_type, autodetect_dict in SSH_MAPPER_BASE.items(): tmp_dict = autodetect_dict.copy() call_method = tmp_dict.pop("dispatch") autodetect_method = getattr(self, call_method) accuracy = autodetect_method(**tmp_dict) if accuracy: self.potential_matches[device_type] = accuracy if accuracy >= 99: # Stop the loop as we are sure of our match best_match = sorted(self.potential_matches.items(), key=lambda t: t[1], reverse=True) self.connection.disconnect() return best_match[0][0] if not self.potential_matches: self.connection.disconnect() return None best_match = sorted(self.potential_matches.items(), key=lambda t: t[1], reverse=True) self.connection.disconnect() return best_match[0][0] def _send_command(self, cmd=""): """ Handle reading/writing channel directly. It is also sanitizing the output received. Parameters ---------- cmd : str, optional The command to send to the remote device (default : "", just send a new line) Returns ------- output : str The output from the command sent """ self.connection.write_channel(cmd + "\n") time.sleep(1) output = self.connection._read_channel_timing() output = self.connection.strip_ansi_escape_codes(output) output = self.connection.strip_backspaces(output) return output def _send_command_wrapper(self, cmd): """ Send command to the remote device with a caching feature to avoid sending the same command twice based on the SSH_MAPPER_BASE dict cmd key. Parameters ---------- cmd : str The command to send to the remote device after checking cache. Returns ------- response : str The response from the remote device. """ cached_results = self._results_cache.get(cmd) if not cached_results: response = self._send_command(cmd) self._results_cache[cmd] = response return response else: return cached_results def _autodetect_std(self, cmd="", search_patterns=None, re_flags=re.I, priority=99): """ Standard method to try to auto-detect the device type. This method will be called for each device_type present in SSH_MAPPER_BASE dict ('dispatch' key). It will attempt to send a command and match some regular expression from the ouput for each entry in SSH_MAPPER_BASE ('cmd' and 'search_pattern' keys). Parameters ---------- cmd : str The command to send to the remote device after checking cache. search_patterns : list A list of regular expression to look for in the command's output (default: None). re_flags: re.flags, optional Any flags from the python re module to modify the regular expression (default: re.I). priority: int, optional The confidence the match is right between 0 and 99 (default: 99). """ invalid_responses = [ r'% Invalid input detected', r'syntax error, expecting', r'Error: Unrecognized command', r'%Error' ] if not cmd or not search_patterns: return 0 try: response = self._send_command_wrapper(cmd) # Look for error conditions in output for pattern in invalid_responses: match = re.search(pattern, response, flags=re.I) if match: return 0 for pattern in search_patterns: match = re.search(pattern, response, flags=re_flags) if match: return priority except Exception: return 0 return 0 netmiko-1.4.3/netmiko/accedian/0000775000127700012770000000000013161517110017556 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/accedian/accedian_ssh.py0000664000127700012770000000266613160550514022552 0ustar gitusergituser00000000000000 from __future__ import unicode_literals from netmiko.cisco_base_connection import CiscoSSHConnection class AccedianSSH(CiscoSSHConnection): def session_preparation(self): self._test_channel_read() self.set_base_prompt() def check_enable_mode(self, *args, **kwargs): raise AttributeError("Accedian devices do not support enable mode!") def enable(self, *args, **kwargs): raise AttributeError("Accedian devices do not support enable mode!") def exit_enable_mode(self, *args, **kwargs): raise AttributeError("Accedian devices do not support enable mode!") def check_config_mode(self): """Accedian devices do not have a config mode.""" return False def config_mode(self): """Accedian devices do not have a config mode.""" return '' def exit_config_mode(self): """Accedian devices do not have a config mode.""" return '' def set_base_prompt(self, pri_prompt_terminator=':', alt_prompt_terminator='#', delay_factor=2): """Sets self.base_prompt: used as delimiter for stripping of trailing prompt in output.""" super(AccedianSSH, self).set_base_prompt(pri_prompt_terminator=pri_prompt_terminator, alt_prompt_terminator=alt_prompt_terminator, delay_factor=delay_factor) return self.base_prompt netmiko-1.4.3/netmiko/accedian/__init__.py0000664000127700012770000000012113127751172021673 0ustar gitusergituser00000000000000from netmiko.accedian.accedian_ssh import AccedianSSH __all__ = ['AccedianSSH'] netmiko-1.4.3/netmiko/ssh_exception.py0000664000127700012770000000064413127751172021272 0ustar gitusergituser00000000000000from __future__ import unicode_literals from paramiko.ssh_exception import SSHException from paramiko.ssh_exception import AuthenticationException class NetMikoTimeoutException(SSHException): """SSH session timed trying to connect to the device.""" pass class NetMikoAuthenticationException(AuthenticationException): """SSH authentication exception based on Paramiko AuthenticationException.""" pass netmiko-1.4.3/netmiko/avaya/0000775000127700012770000000000013161517110017130 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/avaya/avaya_ers_ssh.py0000664000127700012770000000235013160550515022336 0ustar gitusergituser00000000000000"""Netmiko support for Avaya 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. CTRL_Y = '\x19' class AvayaErsSSH(CiscoSSHConnection): """Netmiko support for Avaya Ethernet Routing Switch.""" def special_login_handler(self, delay_factor=1): """ Avaya ERS presents the following as part of the login process: Enter Ctrl-Y to begin. """ delay_factor = self.select_delay_factor(delay_factor) # Handle 'Enter Ctrl-Y to begin' output = "" i = 0 while i <= 12: output = self.read_channel() if output: if 'Ctrl-Y' in output: self.write_channel(CTRL_Y) if 'sername' in output: self.write_channel(self.username + '\n') elif 'ssword' in output: self.write_channel(self.password + '\n') break time.sleep(.5 * delay_factor) else: self.write_channel('\n') time.sleep(1 * delay_factor) i += 1 netmiko-1.4.3/netmiko/avaya/avaya_vsp_ssh.py0000664000127700012770000000100613160550515022352 0ustar gitusergituser00000000000000"""Avaya Virtual Services Platform Support.""" from __future__ import print_function from __future__ import unicode_literals from netmiko.cisco_base_connection import CiscoSSHConnection class AvayaVspSSH(CiscoSSHConnection): """Avaya Virtual Services Platform Support.""" def session_preparation(self): """Prepare the session after the connection has been established.""" self._test_channel_read() self.set_base_prompt() self.disable_paging(command="terminal more disable\n") netmiko-1.4.3/netmiko/avaya/__init__.py0000664000127700012770000000027213127751172021254 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.avaya.avaya_vsp_ssh import AvayaVspSSH from netmiko.avaya.avaya_ers_ssh import AvayaErsSSH __all__ = ['AvayaVspSSH', 'AvayaErsSSH'] netmiko-1.4.3/netmiko/juniper/0000775000127700012770000000000013161517110017503 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/juniper/__init__.py0000664000127700012770000000016513127751172021630 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.juniper.juniper_ssh import JuniperSSH __all__ = ['JuniperSSH'] netmiko-1.4.3/netmiko/juniper/juniper_ssh.py0000664000127700012770000001455413160550515022424 0ustar gitusergituser00000000000000from __future__ import unicode_literals import re import time from netmiko.base_connection import BaseConnection class JuniperSSH(BaseConnection): """ Implement methods for interacting with Juniper Networks devices. Disables `enable()` and `check_enable_mode()` methods. Overrides several methods for Juniper-specific compatibility. """ def session_preparation(self): """ Prepare the session after the connection has been established. Disable paging (the '--more--' prompts). Set the base prompt for interaction ('>'). """ self._test_channel_read() self.enter_cli_mode() self.set_base_prompt() self.disable_paging(command="set cli screen-length 0\n") self.set_terminal_width(command='set cli screen-width 511') def enter_cli_mode(self): """Check if at shell prompt root@ and go into CLI.""" delay_factor = self.select_delay_factor(delay_factor=0) count = 0 cur_prompt = '' while count < 50: self.write_channel("\n") time.sleep(.1 * delay_factor) cur_prompt = self.read_channel() if re.search(r'root@', cur_prompt): self.write_channel("cli\n") time.sleep(.3 * delay_factor) self.clear_buffer() break elif '>' in cur_prompt or '#' in cur_prompt: break count += 1 def check_enable_mode(self, *args, **kwargs): """No enable mode on Juniper.""" pass def enable(self, *args, **kwargs): """No enable mode on Juniper.""" pass def exit_enable_mode(self, *args, **kwargs): """No enable mode on Juniper.""" pass def check_config_mode(self, check_string=']'): """Checks if the device is in configuration mode or not.""" return super(JuniperSSH, self).check_config_mode(check_string=check_string) def config_mode(self, config_command='configure'): """Enter configuration mode.""" return super(JuniperSSH, self).config_mode(config_command=config_command) def exit_config_mode(self, exit_config='exit configuration-mode'): """Exit configuration mode.""" output = "" if self.check_config_mode(): output = self.send_command_timing(exit_config, strip_prompt=False, strip_command=False) if 'Exit with uncommitted changes?' in output: output += self.send_command_timing('yes', strip_prompt=False, strip_command=False) if self.check_config_mode(): raise ValueError("Failed to exit configuration mode") return output def commit(self, confirm=False, confirm_delay=None, check=False, comment='', and_quit=False, delay_factor=1): """ Commit the candidate configuration. Commit the entered configuration. Raise an error and return the failure if the commit fails. Automatically enters configuration mode default: command_string = commit check and (confirm or confirm_dely or comment): Exception confirm_delay and no confirm: Exception confirm: confirm_delay option comment option command_string = commit confirmed or commit confirmed check: command_string = commit check """ delay_factor = self.select_delay_factor(delay_factor) if check and (confirm or confirm_delay or comment): raise ValueError("Invalid arguments supplied with commit check") if confirm_delay and not confirm: raise ValueError("Invalid arguments supplied to commit method both confirm and check") # Select proper command string based on arguments provided command_string = 'commit' commit_marker = 'commit complete' if check: command_string = 'commit check' commit_marker = 'configuration check succeeds' elif confirm: if confirm_delay: command_string = 'commit confirmed ' + str(confirm_delay) else: command_string = 'commit confirmed' commit_marker = 'commit confirmed will be automatically rolled back in' # wrap the comment in quotes if comment: if '"' in comment: raise ValueError("Invalid comment contains double quote") comment = '"{0}"'.format(comment) command_string += ' comment ' + comment if and_quit: command_string += ' and-quit' # Enter config mode (if necessary) output = self.config_mode() # and_quit will get out of config mode on commit if and_quit: prompt = self.base_prompt output += self.send_command_expect(command_string, expect_string=prompt, strip_prompt=False, strip_command=False, delay_factor=delay_factor) else: output += self.send_command_expect(command_string, strip_prompt=False, strip_command=False, delay_factor=delay_factor) if commit_marker not in output: raise ValueError("Commit failed with the following errors:\n\n{0}" .format(output)) return output def strip_prompt(self, *args, **kwargs): """Strip the trailing router prompt from the output.""" a_string = super(JuniperSSH, self).strip_prompt(*args, **kwargs) return self.strip_context_items(a_string) @staticmethod def strip_context_items(a_string): """Strip Juniper-specific output. Juniper will also put a configuration context: [edit] and various chassis contexts: {master:0}, {backup:1} This method removes those lines. """ strings_to_strip = [ r'\[edit.*\]', r'\{master:.*\}', r'\{backup:.*\}', r'\{line.*\}', r'\{primary.*\}', r'\{secondary.*\}', ] response_list = a_string.split('\n') last_line = response_list[-1] for pattern in strings_to_strip: if re.search(pattern, last_line): return "\n".join(response_list[:-1]) return a_string netmiko-1.4.3/netmiko/arista/0000775000127700012770000000000013161517110017312 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/arista/arista_ssh.py0000664000127700012770000000210213161264117022025 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.cisco_base_connection import CiscoSSHConnection from netmiko import log class AristaSSH(CiscoSSHConnection): def session_preparation(self): """Prepare the session after the connection has been established.""" self._test_channel_read(pattern=r'[>#]') self.set_base_prompt() self.disable_paging() self.set_terminal_width(command='terminal width 511') def check_config_mode(self, check_string=')#', pattern=''): """ Checks if the device is in configuration mode or not. Arista, unfortunately, does this: loc1-core01(s1)# Can also be (s2) """ log.debug("pattern: {0}".format(pattern)) self.write_channel('\n') output = self.read_until_pattern(pattern=pattern) log.debug("check_config_mode: {0}".format(repr(output))) output = output.replace("(s1)", "") output = output.replace("(s2)", "") log.debug("check_config_mode: {0}".format(repr(output))) return check_string in output netmiko-1.4.3/netmiko/arista/__init__.py0000664000127700012770000000016113127751172021433 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.arista.arista_ssh import AristaSSH __all__ = ['AristaSSH'] netmiko-1.4.3/netmiko/alcatel/0000775000127700012770000000000013161517110017434 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/alcatel/alcatel_aos_ssh.py0000664000127700012770000000210013160550514023127 0ustar gitusergituser00000000000000"""Alcatel-Lucent Enterprise AOS support (AOS6 and AOS8).""" from __future__ import print_function from __future__ import unicode_literals from netmiko.cisco_base_connection import CiscoSSHConnection class AlcatelAosSSH(CiscoSSHConnection): """Alcatel-Lucent Enterprise AOS support (AOS6 and AOS8).""" def session_preparation(self): # Prompt can be anything, but best practice is to end with > or # self._test_channel_read(pattern=r'[>#]') self.set_base_prompt() def check_enable_mode(self, *args, **kwargs): """No enable mode on AOS""" pass def enable(self, *args, **kwargs): """No enable mode on AOS""" pass def exit_enable_mode(self, *args, **kwargs): """No enable mode on AOS""" pass def check_config_mode(self, *args, **kwargs): """No config mode on AOS""" pass def config_mode(self, *args, **kwargs): """No config mode on AOS""" return '' def exit_config_mode(self, *args, **kwargs): """No config mode on AOS""" return '' netmiko-1.4.3/netmiko/alcatel/__init__.py0000664000127700012770000000031513127751172021556 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.alcatel.alcatel_sros_ssh import AlcatelSrosSSH from netmiko.alcatel.alcatel_aos_ssh import AlcatelAosSSH __all__ = ['AlcatelSrosSSH', 'AlcatelAosSSH'] netmiko-1.4.3/netmiko/alcatel/alcatel_sros_ssh.py0000664000127700012770000000335113160550515023345 0ustar gitusergituser00000000000000"""Alcatel-Lucent SROS support.""" from __future__ import print_function from __future__ import unicode_literals import re from netmiko.cisco_base_connection import CiscoSSHConnection class AlcatelSrosSSH(CiscoSSHConnection): """Alcatel-Lucent SROS support.""" def session_preparation(self): self._test_channel_read() self.set_base_prompt() self.disable_paging(command="environment no more\n") def set_base_prompt(self, *args, **kwargs): """Remove the > when navigating into the different config level.""" cur_base_prompt = super(AlcatelSrosSSH, self).set_base_prompt(*args, **kwargs) match = re.search(r'(.*)(>.*)*#', cur_base_prompt) if match: # strip off >... from base_prompt self.base_prompt = match.group(1) return self.base_prompt def enable(self, *args, **kwargs): pass def config_mode(self, config_command='configure', pattern='#'): """ Enter into configuration mode on SROS device.""" return super(AlcatelSrosSSH, self).config_mode(config_command=config_command, pattern=pattern) def exit_config_mode(self, exit_config='exit all', pattern='#'): """ Exit from configuration mode.""" return super(AlcatelSrosSSH, self).exit_config_mode(exit_config=exit_config, pattern=pattern) def check_config_mode(self, check_string='config', pattern='#'): """ Checks if the device is in configuration mode or not. """ return super(AlcatelSrosSSH, self).check_config_mode(check_string=check_string, pattern=pattern) netmiko-1.4.3/netmiko/huawei/0000775000127700012770000000000013161517110017311 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/huawei/__init__.py0000664000127700012770000000016113127751172021432 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.huawei.huawei_ssh import HuaweiSSH __all__ = ['HuaweiSSH'] netmiko-1.4.3/netmiko/huawei/huawei_ssh.py0000664000127700012770000000542113161264117022032 0ustar gitusergituser00000000000000from __future__ import print_function from __future__ import unicode_literals import time import re from netmiko.cisco_base_connection import CiscoSSHConnection from netmiko import log class HuaweiSSH(CiscoSSHConnection): def session_preparation(self): """Prepare the session after the connection has been established.""" self._test_channel_read() self.set_base_prompt() self.disable_paging(command="screen-length 0 temporary\n") 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'): """Exit configuration mode.""" return super(HuaweiSSH, self).exit_config_mode(exit_config=exit_config) def check_config_mode(self, check_string=']'): """Checks whether in configuration mode. Returns a boolean.""" return super(HuaweiSSH, self).check_config_mode(check_string=check_string) def check_enable_mode(self, *args, **kwargs): """Huawei has no enable mode.""" pass def enable(self, *args, **kwargs): """Huawei has no enable mode.""" return '' def exit_enable_mode(self, *args, **kwargs): """Huawei has no enable mode.""" return '' def set_base_prompt(self, pri_prompt_terminator='>', alt_prompt_terminator=']', delay_factor=1): """ Sets self.base_prompt Used as delimiter for stripping of trailing prompt in output. Should be set to something that is general and applies in multiple contexts. For Comware this will be the router prompt with < > or [ ] stripped off. This will be set on logging in, but not when entering system-view """ log.debug("In set_base_prompt") delay_factor = self.select_delay_factor(delay_factor) self.clear_buffer() self.write_channel("\n") time.sleep(.5 * delay_factor) prompt = self.read_channel() prompt = self.normalize_linefeeds(prompt) # If multiple lines in the output take the last line prompt = prompt.split('\n')[-1] prompt = prompt.strip() # Check that ends with a valid terminator character if not prompt[-1] in (pri_prompt_terminator, alt_prompt_terminator): raise ValueError("Router prompt not found: {0}".format(prompt)) # Strip off any leading HRP_. characters for USGv5 HA prompt = re.sub(r"^HRP_.", "", prompt, flags=re.M) # Strip off leading and trailing terminator prompt = prompt[1:-1] prompt = prompt.strip() self.base_prompt = prompt log.debug("prompt: {0}".format(self.base_prompt)) return self.base_prompt netmiko-1.4.3/netmiko/checkpoint/0000775000127700012770000000000013161517110020156 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/checkpoint/checkpoint_gaia_ssh.py0000664000127700012770000000140613160550515024523 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.base_connection import BaseConnection class CheckPointGaiaSSH(BaseConnection): """ Implements methods for communicating with Check Point Gaia firewalls. """ def session_preparation(self): """ Prepare the session after the connection has been established. Set the base prompt for interaction ('>'). """ self._test_channel_read() self.set_base_prompt() self.disable_paging(command="set clienv rows 0\n") def config_mode(self, config_command=''): """No config mode for Check Point devices.""" return '' def exit_config_mode(self, exit_config=''): """No config mode for Check Point devices.""" return '' netmiko-1.4.3/netmiko/checkpoint/__init__.py0000664000127700012770000000021613127751172022300 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.checkpoint.checkpoint_gaia_ssh import CheckPointGaiaSSH __all__ = ['CheckPointGaiaSSH'] netmiko-1.4.3/netmiko/mrv/0000775000127700012770000000000013161517110016633 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/mrv/__init__.py0000664000127700012770000000017113127751172020755 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.mrv.mrv_ssh import MrvOptiswitchSSH __all__ = ['MrvOptiswitchSSH'] netmiko-1.4.3/netmiko/mrv/mrv_ssh.py0000664000127700012770000000212113161264117020670 0ustar gitusergituser00000000000000"""MRV Communications Driver (OptiSwitch).""" from __future__ import unicode_literals import re from netmiko.cisco_base_connection import CiscoSSHConnection class MrvOptiswitchSSH(CiscoSSHConnection): """MRV Communications Driver (OptiSwitch).""" 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.disable_paging(command="no cli-paging") def enable(self, cmd='enable', pattern=r'#', re_flags=re.IGNORECASE): """Enable mode on MRV uses no password.""" output = "" if not self.check_enable_mode(): self.write_channel(self.normalize_cmd(cmd)) output += self.read_until_prompt_or_pattern(pattern=pattern, re_flags=re_flags) if not self.check_enable_mode(): msg = "Failed to enter enable mode. Please ensure you pass " \ "the 'secret' argument to ConnectHandler." raise ValueError(msg) return output netmiko-1.4.3/netmiko/a10/0000775000127700012770000000000013161517110016410 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/a10/__init__.py0000664000127700012770000000014513127751172020533 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.a10.a10_ssh import A10SSH __all__ = ['A10SSH'] netmiko-1.4.3/netmiko/a10/a10_ssh.py0000664000127700012770000000100713160550514020222 0ustar gitusergituser00000000000000"""A10 support.""" from __future__ import unicode_literals from netmiko.cisco_base_connection import CiscoSSHConnection class A10SSH(CiscoSSHConnection): """A10 support.""" def session_preparation(self): """A10 requires to be enable mode to disable paging.""" self._test_channel_read() self.set_base_prompt() self.enable() self.disable_paging(command="terminal length 0\n") # Will not do anything without A10 specific command self.set_terminal_width() netmiko-1.4.3/netmiko/utilities.py0000664000127700012770000001211013127751172020421 0ustar gitusergituser00000000000000"""Miscellaneous utility functions.""" from __future__ import print_function from __future__ import unicode_literals import sys import io import os # Dictionary mapping 'show run' for vendors with different command SHOW_RUN_MAPPER = { 'juniper': 'show configuration', 'juniper_junos': 'show configuration', 'extreme': 'show configuration', 'extreme_wing': 'show running-config', 'hp_comware': 'display current-configuration', 'huawei': 'display current-configuration', 'fortinet': 'show full-configuration', 'checkpoint': 'show configuration', 'cisco_wlc': 'show run-config', 'enterasys': 'show running-config', 'dell_force10': 'show running-config', 'avaya_vsp': 'show running-config', 'avaya_ers': 'show running-config', 'brocade_vdx': 'show running-config', 'brocade_nos': 'show running-config', 'brocade_fastiron': 'show running-config', 'brocade_netiron': 'show running-config', 'alcatel_aos': 'show configuration snapshot', } # Expand SHOW_RUN_MAPPER to include '_ssh' key new_dict = {} for k, v in SHOW_RUN_MAPPER.items(): new_key = k + '_ssh' new_dict[k] = v new_dict[new_key] = v SHOW_RUN_MAPPER = new_dict # Default location of netmiko temp directory for netmiko tools NETMIKO_BASE_DIR = '~/.netmiko' def load_yaml_file(yaml_file): """Read YAML file.""" try: import yaml except ImportError: sys.exit("Unable to import yaml module.") try: with io.open(yaml_file, "rt", encoding='utf-8') as fname: return yaml.load(fname) except IOError: sys.exit("Unable to open YAML file: {0}".format(yaml_file)) def load_devices(file_name=None): """Find and load .netmiko.yml file.""" yaml_devices_file = find_cfg_file(file_name) return load_yaml_file(yaml_devices_file) def find_cfg_file(file_name=None): """Look for .netmiko.yml in current dir, then ~/.netmiko.yml.""" base_file = '.netmiko.yml' check_files = [ base_file, os.path.expanduser('~') + '/' + base_file, ] if file_name: check_files.insert(0, file_name) for test_file in check_files: if os.path.isfile(test_file): return test_file raise IOError("{}: file not found in current dir or home dir.".format(base_file)) def display_inventory(my_devices): """Print out inventory devices and groups.""" inventory_groups = ['all'] inventory_devices = [] for k, v in my_devices.items(): if isinstance(v, list): inventory_groups.append(k) elif isinstance(v, dict): inventory_devices.append((k, v['device_type'])) inventory_groups.sort() inventory_devices.sort(key=lambda x: x[0]) print("\nDevices:") print('-' * 40) for a_device, device_type in inventory_devices: device_type = " ({})".format(device_type) print("{:<25}{:>15}".format(a_device, device_type)) print("\n\nGroups:") print('-' * 40) for a_group in inventory_groups: print(a_group) print() def obtain_all_devices(my_devices): """Dynamically create 'all' group.""" new_devices = {} for device_name, device_or_group in my_devices.items(): # Skip any groups if not isinstance(device_or_group, list): new_devices[device_name] = device_or_group return new_devices def obtain_netmiko_filename(device_name): """Create file name based on device_name.""" _, netmiko_full_dir = find_netmiko_dir() return "{}/{}.txt".format(netmiko_full_dir, device_name) def write_tmp_file(device_name, output): file_name = obtain_netmiko_filename(device_name) with open(file_name, "w") as f: f.write(output) return file_name def ensure_dir_exists(verify_dir): """Ensure directory exists. Create if necessary.""" if not os.path.exists(verify_dir): # Doesn't exist create dir os.makedirs(verify_dir) else: # Exists if not os.path.isdir(verify_dir): # Not a dir, raise an exception raise ValueError("{} is not a directory".format(verify_dir)) def find_netmiko_dir(): """Check environment first, then default dir""" try: netmiko_base_dir = os.environ['NETMIKO_DIR'] except KeyError: netmiko_base_dir = NETMIKO_BASE_DIR netmiko_base_dir = os.path.expanduser(netmiko_base_dir) if netmiko_base_dir == '/': raise ValueError("/ cannot be netmiko_base_dir") netmiko_full_dir = "{}/tmp".format(netmiko_base_dir) return (netmiko_base_dir, netmiko_full_dir) 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') elif isinstance(out_data, type(b'')): return out_data else: if isinstance(out_data, type(u'')): 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) raise ValueError(msg) netmiko-1.4.3/netmiko/netmiko_globals.py0000664000127700012770000000012413127751172021561 0ustar gitusergituser00000000000000from __future__ import unicode_literals MAX_BUFFER = 65535 BACKSPACE_CHAR = '\x08' netmiko-1.4.3/netmiko/dell/0000775000127700012770000000000013161517110016747 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/dell/dell_powerconnect_telnet.py0000664000127700012770000000300513161264117024406 0ustar gitusergituser00000000000000"""Dell Telnet Driver.""" from __future__ import unicode_literals import time from netmiko.cisco_base_connection import CiscoBaseConnection from netmiko import log class DellPowerConnectTelnet(CiscoBaseConnection): def disable_paging(self, command="terminal length 0", delay_factor=1): """Must be in enable mode to disable paging.""" self.enable() delay_factor = self.select_delay_factor(delay_factor) time.sleep(delay_factor * .1) self.clear_buffer() command = self.normalize_cmd(command) log.debug("In disable_paging") log.debug("Command: {0}".format(command)) self.write_channel(command) output = self.read_until_prompt() if self.ansi_escape_codes: output = self.strip_ansi_escape_codes(output) log.debug("{0}".format(output)) log.debug("Exiting disable_paging") return output def telnet_login(self, pri_prompt_terminator='#', alt_prompt_terminator='>', username_pattern=r"User:", pwd_pattern=r"assword", delay_factor=1, max_loops=60): """Telnet login. Can be username/password or just password.""" super(DellPowerConnectTelnet, 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) netmiko-1.4.3/netmiko/dell/dell_force10_ssh.py0000664000127700012770000000036613127751172022454 0ustar gitusergituser00000000000000"""Dell Force10 Driver - supports DNOS9.""" from __future__ import unicode_literals from netmiko.cisco_base_connection import CiscoSSHConnection class DellForce10SSH(CiscoSSHConnection): """Dell Force10 Driver - supports DNOS9.""" pass netmiko-1.4.3/netmiko/dell/__init__.py0000664000127700012770000000047413160550515021072 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.dell.dell_force10_ssh import DellForce10SSH from netmiko.dell.dell_powerconnect_ssh import DellPowerConnectSSH from netmiko.dell.dell_powerconnect_telnet import DellPowerConnectTelnet __all__ = ['DellForce10SSH', 'DellPowerConnectSSH', 'DellPowerConnectTelnet'] netmiko-1.4.3/netmiko/dell/dell_powerconnect_ssh.py0000664000127700012770000000677613160550515023731 0ustar gitusergituser00000000000000"""Dell PowerConnect Driver.""" from __future__ import unicode_literals from netmiko.cisco_base_connection import CiscoSSHConnection from paramiko import SSHClient import time from os import path class SSHClient_noauth(SSHClient): def _auth(self, username, *args): self._transport.auth_none(username) return class DellPowerConnectSSH(CiscoSSHConnection): """Dell PowerConnect Driver. To make it work, we have to override the SSHClient _auth method. If we use login/password, the ssh server use the (none) auth mechanism. """ def _build_ssh_client(self): """Prepare for Paramiko SSH connection. See base_connection.py file for any updates. """ # Create instance of SSHClient object # If user does not provide SSH key, we use noauth if not self.use_keys: remote_conn_pre = SSHClient_noauth() else: remote_conn_pre = SSHClient() # Load host_keys for better SSH security if self.system_host_keys: remote_conn_pre.load_system_host_keys() if self.alt_host_keys and path.isfile(self.alt_key_file): remote_conn_pre.load_host_keys(self.alt_key_file) # Default is to automatically add untrusted hosts (make sure appropriate for your env) remote_conn_pre.set_missing_host_key_policy(self.key_policy) return remote_conn_pre def special_login_handler(self, delay_factor=1): """ Powerconnect presents with the following on login User Name: 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 Name:' in output: self.write_channel(self.username + '\n') elif 'Password:' in output: self.write_channel(self.password + '\n') break time.sleep(delay_factor * 1) else: self.write_channel('\n') time.sleep(delay_factor * 1.5) i += 1 def session_preparation(self): """Prepare the session after the connection has been established.""" self.ansi_escape_codes = True self._test_channel_read() self.set_base_prompt() self.disable_paging(command="terminal datadump") def set_base_prompt(self, pri_prompt_terminator='>', alt_prompt_terminator='#', delay_factor=1): """Sets self.base_prompt: used as delimiter for stripping of trailing prompt in output.""" prompt = super(DellPowerConnectSSH, self).set_base_prompt( pri_prompt_terminator=pri_prompt_terminator, alt_prompt_terminator=alt_prompt_terminator, delay_factor=delay_factor) prompt = prompt.strip() self.base_prompt = prompt return self.base_prompt def check_config_mode(self, check_string='(config)#'): """Checks if the device is in configuration mode""" return super(DellPowerConnectSSH, self).check_config_mode(check_string=check_string) def config_mode(self, config_command='config'): """Enter configuration mode.""" return super(DellPowerConnectSSH, self).config_mode(config_command=config_command) netmiko-1.4.3/netmiko/f5/0000775000127700012770000000000013161517110016341 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/f5/f5_ltm_ssh.py0000664000127700012770000000212213160550515020760 0ustar gitusergituser00000000000000from __future__ import unicode_literals import time import re from netmiko.base_connection import BaseConnection class F5LtmSSH(BaseConnection): def session_preparation(self): """Prepare the session after the connection has been established.""" delay_factor = self.select_delay_factor(delay_factor=0) self._test_channel_read() self.set_base_prompt() self.disable_paging(command="\nset length 0\n") time.sleep(1 * delay_factor) self.tmsh_mode() self.set_base_prompt() def tmsh_mode(self, delay_factor=1): """tmsh command is equivalent to config command on F5.""" delay_factor = self.select_delay_factor(delay_factor) self.clear_buffer() self.write_channel("\ntmsh\n") time.sleep(1 * delay_factor) self.clear_buffer() return None @staticmethod def normalize_linefeeds(a_string): """Convert '\r\n' or '\r\r\n' to '\n, and remove '\r's in the text.""" newline = re.compile(r'(\r\n|\r\n\r\n|\r\r\n|\n\r|\r)') return newline.sub('\n', a_string) netmiko-1.4.3/netmiko/f5/__init__.py0000664000127700012770000000015313127751172020463 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.f5.f5_ltm_ssh import F5LtmSSH __all__ = ['F5LtmSSH'] netmiko-1.4.3/netmiko/aruba/0000775000127700012770000000000013161517110017121 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/aruba/aruba_ssh.py0000664000127700012770000000176013160550515021453 0ustar gitusergituser00000000000000"""Aruba OS support""" from __future__ import unicode_literals import time import re from netmiko.cisco_base_connection import CiscoSSHConnection class ArubaSSH(CiscoSSHConnection): """Aruba OS support""" def session_preparation(self): """Aruba OS requires enable mode to disable paging.""" delay_factor = self.select_delay_factor(delay_factor=0) time.sleep(1 * delay_factor) self._test_channel_read() self.set_base_prompt() self.enable() self.disable_paging(command="no paging") def check_config_mode(self, check_string='(config) #', pattern=''): """ Checks if the device is in configuration mode or not. Aruba uses "() (config) #" as config prompt """ if not pattern: pattern = re.escape(self.base_prompt[:16]) return super(ArubaSSH, self).check_config_mode(check_string=check_string, pattern=pattern) netmiko-1.4.3/netmiko/aruba/__init__.py0000664000127700012770000000015513127751172021245 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.aruba.aruba_ssh import ArubaSSH __all__ = ['ArubaSSH'] netmiko-1.4.3/netmiko/cisco/0000775000127700012770000000000013161517110017127 5ustar gitusergituser00000000000000netmiko-1.4.3/netmiko/cisco/cisco_s300.py0000664000127700012770000000125313160550515021354 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.cisco_base_connection import CiscoSSHConnection class CiscoS300SSH(CiscoSSHConnection): """ Support for Cisco SG300 series of devices. Note, must configure the following to disable SG300 from prompting for username twice: configure terminal ip ssh password-auth """ def session_preparation(self): """Prepare the session after the connection has been established.""" self.ansi_escape_codes = True self._test_channel_read() self.set_base_prompt() self.disable_paging(command="terminal datadump\n") self.set_terminal_width(command='terminal width 511') netmiko-1.4.3/netmiko/cisco/cisco_tp_tcce.py0000664000127700012770000000533013160550515022310 0ustar gitusergituser00000000000000""" CiscoTpTcCeSSH Class Class to manage Cisco Telepresence Endpoint on TC/CE software release. Also working for Cisco Expressway/VCS Written by Ahmad Barrin """ from __future__ import unicode_literals import re from netmiko.cisco_base_connection import CiscoSSHConnection class CiscoTpTcCeSSH(CiscoSSHConnection): def disable_paging(self, *args, **kwargs): """Paging is disabled by default.""" return "" def session_preparation(self): """ Prepare the session after the connection has been established This method handles some of vagaries that occur between various devices early on in the session. In general, it should include: self.set_base_prompt() self.disable_paging() self.set_terminal_width() """ self._test_channel_read() self.set_base_prompt() self.disable_paging() self.set_terminal_width() def set_base_prompt(self, *args, **kwargs): """Use 'OK' as base_prompt.""" self.base_prompt = 'OK' return self.base_prompt def find_prompt(self, *args, **kwargs): """Use 'OK' as standard prompt.""" return 'OK' def strip_prompt(self, a_string): """Strip the trailing router prompt from the output.""" expect_string = r'^(OK|ERROR|Command not recognized\.)$' response_list = a_string.split('\n') last_line = response_list[-1] if re.search(expect_string, last_line): return '\n'.join(response_list[:-1]) else: return a_string def send_command(self, *args, **kwargs): ''' Send command to network device retrieve output until router_prompt or expect_string By default this method will keep waiting to receive data until the network device prompt is detected. The current network device prompt will be determined automatically. command_string = command to execute expect_string = pattern to search for uses re.search (use raw strings) delay_factor = decrease the initial delay before we start looking for data max_loops = number of iterations before we give up and raise an exception strip_prompt = strip the trailing prompt from the output strip_command = strip the leading command from the output ''' if len(args) >= 2: expect_string = args[1] else: expect_string = kwargs.get('expect_string') if expect_string is None: expect_string = r'\r\n(OK|ERROR|Command not recognized\.)\r\n' kwargs.setdefault('expect_string', expect_string) output = super(CiscoSSHConnection, self).send_command(*args, **kwargs) return output netmiko-1.4.3/netmiko/cisco/__init__.py0000664000127700012770000000112513127751172021251 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.cisco.cisco_ios import CiscoIosBase, CiscoIosSSH, CiscoIosTelnet from netmiko.cisco.cisco_asa_ssh import CiscoAsaSSH from netmiko.cisco.cisco_nxos_ssh import CiscoNxosSSH from netmiko.cisco.cisco_xr_ssh import CiscoXrSSH from netmiko.cisco.cisco_wlc_ssh import CiscoWlcSSH from netmiko.cisco.cisco_s300 import CiscoS300SSH from netmiko.cisco.cisco_tp_tcce import CiscoTpTcCeSSH __all__ = ['CiscoIosSSH', 'CiscoIosTelnet', 'CiscoAsaSSH', 'CiscoNxosSSH', 'CiscoXrSSH', 'CiscoWlcSSH', 'CiscoS300SSH', 'CiscoTpTcCeSSH', 'CiscoIosBase'] netmiko-1.4.3/netmiko/cisco/cisco_asa_ssh.py0000664000127700012770000000656413160550515022322 0ustar gitusergituser00000000000000"""Subclass specific to Cisco ASA.""" from __future__ import unicode_literals import re import time from netmiko.cisco_base_connection import CiscoSSHConnection class CiscoAsaSSH(CiscoSSHConnection): """Subclass specific to Cisco ASA.""" def session_preparation(self): """Prepare the session after the connection has been established.""" self._test_channel_read() self.set_base_prompt() if self.secret: self.enable() else: self.asa_login() self.disable_paging(command="terminal pager 0\n") self.set_terminal_width(command="terminal width 511\n") def send_command_timing(self, *args, **kwargs): """ If the ASA is in multi-context mode, then the base_prompt needs to be updated after each context change. """ output = super(CiscoAsaSSH, self).send_command_timing(*args, **kwargs) if len(args) >= 1: command_string = args[0] else: command_string = kwargs['command_string'] if "changeto" in command_string: self.set_base_prompt() return output def send_command(self, *args, **kwargs): """ If the ASA is in multi-context mode, then the base_prompt needs to be updated after each context change. """ if len(args) >= 1: command_string = args[0] else: command_string = kwargs['command_string'] # If changeto in command, look for '#' to determine command is done if "changeto" in command_string: if len(args) <= 1: expect_string = kwargs.get('expect_string', '#') kwargs['expect_string'] = expect_string output = super(CiscoAsaSSH, self).send_command(*args, **kwargs) if "changeto" in command_string: self.set_base_prompt() return output def send_command_expect(self, *args, **kwargs): """Backwards compaitibility.""" return self.send_command(*args, **kwargs) def set_base_prompt(self, *args, **kwargs): """ Cisco ASA in multi-context mode needs to have the base prompt updated (if you switch contexts i.e. 'changeto') This switch of ASA contexts can occur in configuration mode. If this happens the trailing '(config*' needs stripped off. """ cur_base_prompt = super(CiscoAsaSSH, self).set_base_prompt(*args, **kwargs) match = re.search(r'(.*)\(conf.*', cur_base_prompt) if match: # strip off (conf.* from base_prompt self.base_prompt = match.group(1) return self.base_prompt def asa_login(self): """ Handle ASA reaching privilege level 15 using login twb-dc-fw1> login Username: admin Password: ************ """ delay_factor = self.select_delay_factor(0) i = 1 max_attempts = 50 self.write_channel("login\n") while i <= max_attempts: time.sleep(.5 * delay_factor) output = self.read_channel() if 'sername' in output: self.write_channel(self.username + '\n') elif 'ssword' in output: self.write_channel(self.password + '\n') elif '#' in output: break else: self.write_channel("login\n") i += 1 netmiko-1.4.3/netmiko/cisco/cisco_wlc_ssh.py0000664000127700012770000001301113161264117022325 0ustar gitusergituser00000000000000"""Netmiko Cisco WLC support.""" from __future__ import print_function from __future__ import unicode_literals import time import re from netmiko.base_connection import BaseConnection from netmiko.py23_compat import string_types from netmiko import log class CiscoWlcSSH(BaseConnection): """Netmiko Cisco WLC support.""" def special_login_handler(self, delay_factor=1): ''' WLC presents with the following on login (in certain OS versions) login as: user (Cisco Controller) User: 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 'login as' in output or 'User' in output: self.write_channel(self.username + '\n') elif 'Password' in output: self.write_channel(self.password + '\n') break time.sleep(delay_factor * 1) else: self.write_channel('\n') time.sleep(delay_factor * 1.5) i += 1 def send_command_w_enter(self, *args, **kwargs): ''' For 'show run-config' Cisco WLC adds a 'Press Enter to continue...' message Even though pagination is disabled show run-config also has excessive delays in the output which requires special handling. Arguments are the same as send_command() method ''' if len(args) > 1: raise ValueError("Must pass in delay_factor as keyword argument") # If no delay_factor use 1 for default value delay_factor = kwargs.get('delay_factor', 1) kwargs['delay_factor'] = self.select_delay_factor(delay_factor) output = self.send_command(*args, **kwargs) if 'Press Enter to' in output: new_args = list(args) if len(args) == 1: new_args[0] = '\n' else: kwargs['command_string'] = '\n' if not kwargs.get('max_loops'): kwargs['max_loops'] = 150 # Send an 'enter' output = self.send_command(*new_args, **kwargs) # WLC has excessive delay after this appears on screen if '802.11b Advanced Configuration' in output: # Defaults to 30 seconds time.sleep(kwargs['delay_factor'] * 30) not_done = True i = 1 while not_done and i <= 150: time.sleep(kwargs['delay_factor'] * 3) i += 1 new_data = "" new_data = self.read_channel() if new_data: output += new_data else: not_done = False strip_prompt = kwargs.get('strip_prompt', True) if strip_prompt: # Had to strip trailing prompt twice. output = self.strip_prompt(output) output = self.strip_prompt(output) return output def session_preparation(self): ''' Prepare the session after the connection has been established Cisco WLC uses "config paging disable" to disable paging ''' self._test_channel_read() self.set_base_prompt() self.disable_paging(command="config paging disable\n") def cleanup(self): """Reset WLC back to normal paging.""" self.send_command("config paging enable\n") def check_config_mode(self, check_string='config', pattern=''): """Checks if the device is in configuration mode or not.""" if not pattern: pattern = re.escape(self.base_prompt) return super(CiscoWlcSSH, self).check_config_mode(check_string, pattern) def config_mode(self, config_command='config', pattern=''): """Enter into config_mode.""" if not pattern: pattern = re.escape(self.base_prompt) return super(CiscoWlcSSH, self).config_mode(config_command, pattern) def exit_config_mode(self, exit_config='exit', pattern=''): """Exit config_mode.""" if not pattern: pattern = re.escape(self.base_prompt) return super(CiscoWlcSSH, self).exit_config_mode(exit_config, pattern) def send_config_set(self, config_commands=None, exit_config_mode=True, delay_factor=1, max_loops=150, strip_prompt=False, strip_command=False): """ Send configuration commands down the SSH channel. config_commands is an iterable containing all of the configuration commands. The commands will be executed one after the other. Does not automatically exit/enter configuration mode. """ delay_factor = self.select_delay_factor(delay_factor) if config_commands is None: return '' elif isinstance(config_commands, string_types): config_commands = (config_commands,) if not hasattr(config_commands, '__iter__'): raise ValueError("Invalid argument passed into send_config_set") # Send config commands for cmd in config_commands: self.write_channel(self.normalize_cmd(cmd)) time.sleep(delay_factor * .5) # Gather output output = self._read_channel_timing(delay_factor=delay_factor, max_loops=max_loops) output = self._sanitize_output(output) log.debug("{0}".format(output)) return output netmiko-1.4.3/netmiko/cisco/cisco_nxos_ssh.py0000664000127700012770000000127713161264117022542 0ustar gitusergituser00000000000000from __future__ import print_function from __future__ import unicode_literals import re from netmiko.cisco_base_connection import CiscoSSHConnection class CiscoNxosSSH(CiscoSSHConnection): def session_preparation(self): """Prepare the session after the connection has been established.""" self._test_channel_read(pattern=r'[>#]') self.ansi_escape_codes = True self.set_base_prompt() self.disable_paging() @staticmethod def normalize_linefeeds(a_string): """Convert '\r\n' or '\r\r\n' to '\n, and remove extra '\r's in the text.""" newline = re.compile(r'(\r\r\n|\r\n)') return newline.sub('\n', a_string).replace('\r', '') netmiko-1.4.3/netmiko/cisco/cisco_ios.py0000664000127700012770000000122213160550515021455 0ustar gitusergituser00000000000000from __future__ import unicode_literals from netmiko.cisco_base_connection import CiscoBaseConnection class CiscoIosBase(CiscoBaseConnection): """Common Methods for IOS (both SSH and telnet).""" def session_preparation(self): """Prepare the session after the connection has been established.""" self._test_channel_read(pattern=r'[>#]') self.set_base_prompt() self.disable_paging() self.set_terminal_width(command='terminal width 511') class CiscoIosSSH(CiscoBaseConnection): """Cisco IOS SSH driver.""" pass class CiscoIosTelnet(CiscoBaseConnection): """Cisco IOS Telnet driver.""" pass netmiko-1.4.3/netmiko/cisco/cisco_xr_ssh.py0000664000127700012770000001211713160550515022176 0ustar gitusergituser00000000000000from __future__ import print_function from __future__ import unicode_literals import re from netmiko.cisco_base_connection import CiscoSSHConnection class CiscoXrSSH(CiscoSSHConnection): def session_preparation(self): """Prepare the session after the connection has been established.""" self._test_channel_read() self.set_base_prompt() self.disable_paging() self.set_terminal_width(command='terminal width 511') def send_config_set(self, config_commands=None, exit_config_mode=True, **kwargs): """IOS-XR requires you not exit from configuration mode.""" return super(CiscoXrSSH, self).send_config_set(config_commands=config_commands, exit_config_mode=False, **kwargs) def commit(self, confirm=False, confirm_delay=None, comment='', label='', delay_factor=1): """ Commit the candidate configuration. default (no options): command_string = commit confirm and confirm_delay: command_string = commit confirmed label (which is a label name): command_string = commit label