Skip to content

Commit

Permalink
Merge pull request #705 from ktbyers/develop
Browse files Browse the repository at this point in the history
Netmiko release 2.0.2
  • Loading branch information
ktbyers authored Feb 9, 2018
2 parents 031aebf + fc5769d commit 2f60d4d
Show file tree
Hide file tree
Showing 44 changed files with 272 additions and 51 deletions.
22 changes: 14 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ Netmiko

Multi-vendor library to simplify Paramiko SSH connections to network devices

Python 2.7, 3.4, 3.5
Python 2.7, 3.5, 3.6

#### Requires:

Paramiko >= 1.13+
Paramiko >= 2
scp >= 0.10.0
pyyaml
pytest (for unit tests)
pyserial
textfsm

#### Supports:

Expand All @@ -37,33 +38,38 @@ Alcatel AOS6/AOS8
Avaya ERS
Avaya VSP
Brocade VDX
Brocade ICX/FastIron
Brocade MLX/NetIron
Calix B6
Cisco WLC
Dell-Force10 DNOS9
Dell-Force10
Dell PowerConnect
Huawei
Mellanox
NetApp cDOT
Palo Alto PAN-OS
Pluribus
Ubiquiti EdgeSwitch
Ruckus ICX/FastIron
Ubiquiti EdgeSwitch
Vyatta VyOS

###### Experimental

A10
Accedian
Alcatel-Lucent SR-OS
Aruba
Ciena SAOS
Cisco Telepresence
CheckPoint Gaia
Check Point GAiA
Coriant
Eltex
Enterasys
Extreme EXOS
Extreme Wing
F5 LTM
Fortinet
MRV Communications OptiSwitch
Nokia/Alcatel SR-OS
QuantaMesh

## Tutorials:

Expand Down
5 changes: 3 additions & 2 deletions netmiko/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@
# Alternate naming
NetmikoTimeoutError = NetMikoTimeoutException
NetmikoAuthError = NetMikoAuthenticationException
Netmiko = ConnectHandler

__version__ = '2.0.1'
__version__ = '2.0.2'
__all__ = ('ConnectHandler', 'ssh_dispatcher', 'platforms', 'SCPConn', 'FileTransfer',
'NetMikoTimeoutException', 'NetMikoAuthenticationException',
'NetmikoTimeoutError', 'NetmikoAuthError', 'InLineTransfer', 'redispatch',
'SSHDetect', 'BaseConnection')
'SSHDetect', 'BaseConnection', 'Netmiko')

# Cisco cntl-shift-six sequence
CNTL_SHIFT_6 = chr(30)
4 changes: 4 additions & 0 deletions netmiko/a10/a10_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,7 @@ def session_preparation(self):
# Clear the read buffer
time.sleep(.3 * self.global_delay_factor)
self.clear_buffer()

def save_config(self, cmd='', confirm=True, confirm_response=''):
"""Not Implemented"""
raise NotImplementedError
4 changes: 4 additions & 0 deletions netmiko/accedian/accedian_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,7 @@ def set_base_prompt(self, pri_prompt_terminator=':', alt_prompt_terminator='#',
alt_prompt_terminator=alt_prompt_terminator,
delay_factor=delay_factor)
return self.base_prompt

def save_config(self, cmd='', confirm=True, confirm_response=''):
"""Not Implemented"""
raise NotImplementedError
4 changes: 4 additions & 0 deletions netmiko/alcatel/alcatel_aos_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,7 @@ def config_mode(self, *args, **kwargs):
def exit_config_mode(self, *args, **kwargs):
"""No config mode on AOS"""
return ''

def save_config(self, cmd='write memory flash-synchro', confirm=False):
"""Save Config"""
return super(AlcatelAosSSH, self).save_config(cmd=cmd, confirm=confirm)
4 changes: 4 additions & 0 deletions netmiko/alcatel/alcatel_sros_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,7 @@ 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)

def save_config(self, cmd='', confirm=True, confirm_response=''):
"""Not Implemented"""
raise NotImplementedError
4 changes: 4 additions & 0 deletions netmiko/avaya/avaya_ers_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,7 @@ def special_login_handler(self, delay_factor=1):
self.write_channel(self.RETURN)
time.sleep(1 * delay_factor)
i += 1

def save_config(self, cmd='save config', confirm=False):
"""Save Config"""
return super(AvayaErsSSH, self).save_config(cmd=cmd, confirm=confirm)
4 changes: 4 additions & 0 deletions netmiko/avaya/avaya_vsp_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@ def session_preparation(self):
# Clear the read buffer
time.sleep(.3 * self.global_delay_factor)
self.clear_buffer()

def save_config(self, cmd='save config', confirm=False):
"""Save Config"""
return super(AvayaVspSSH, self).save_config(cmd=cmd, confirm=confirm)
4 changes: 4 additions & 0 deletions netmiko/base_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -1219,6 +1219,10 @@ def commit(self):
"""Commit method for platforms that support this."""
raise AttributeError("Network device does not support 'commit()' method")

def save_config(self, cmd='', confirm=True, confirm_response=''):
"""Not Implemented"""
raise NotImplementedError


class TelnetConnection(BaseConnection):
pass
4 changes: 3 additions & 1 deletion netmiko/brocade/brocade_netiron.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@


class BrocadeNetironBase(CiscoSSHConnection):
pass
def save_config(self, cmd='write memory', confirm=False):
"""Save Config"""
return super(BrocadeNetironBase, self).save_config(cmd=cmd, confirm=confirm)


class BrocadeNetironSSH(BrocadeNetironBase):
Expand Down
6 changes: 6 additions & 0 deletions netmiko/brocade/brocade_nos_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,9 @@ def special_login_handler(self, delay_factor=1):
delay_factor = self.select_delay_factor(delay_factor)
self.write_channel(self.RETURN)
time.sleep(1 * delay_factor)

def save_config(self, cmd='copy running-config startup-config', confirm=True,
confirm_response='y'):
"""Save Config for Brocade VDX."""
return super(BrocadeNosSSH, self).save_config(cmd=cmd, confirm=confirm,
confirm_response=confirm_response)
4 changes: 4 additions & 0 deletions netmiko/calix/calix_b6_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,7 @@ def exit_config_mode(self, exit_config=None, pattern=''):
if exit_config is None:
exit_config = 'exit' + self.RETURN + 'end'
return super(CalixB6SSH, self).exit_config_mode(exit_config=exit_config, pattern=pattern)

def save_config(self, cmd='', confirm=True, confirm_response=''):
"""Not Implemented"""
raise NotImplementedError
4 changes: 4 additions & 0 deletions netmiko/checkpoint/checkpoint_gaia_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,7 @@ def config_mode(self, config_command=''):
def exit_config_mode(self, exit_config=''):
"""No config mode for Check Point devices."""
return ''

def save_config(self, cmd='', confirm=True, confirm_response=''):
"""Not Implemented"""
raise NotImplementedError
4 changes: 4 additions & 0 deletions netmiko/ciena/ciena_saos_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@ def session_preparation(self):

def enable(self, *args, **kwargs):
pass

def save_config(self, cmd='', confirm=True, confirm_response=''):
"""Not Implemented"""
raise NotImplementedError
4 changes: 4 additions & 0 deletions netmiko/cisco/cisco_asa_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ def asa_login(self):
self.write_channel("login" + self.RETURN)
i += 1

def save_config(self, cmd='write mem', confirm=False):
"""Saves Config"""
return super(CiscoAsaSSH, self).save_config(cmd=cmd, confirm=confirm)


class CiscoAsaFileTransfer(CiscoFileTransfer):
"""Cisco ASA SCP File Transfer driver."""
Expand Down
4 changes: 4 additions & 0 deletions netmiko/cisco/cisco_ios.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ def session_preparation(self):
time.sleep(.3 * self.global_delay_factor)
self.clear_buffer()

def save_config(self, cmd='write mem', confirm=False):
"""Saves Config Using Copy Run Start"""
return super(CiscoIosBase, self).save_config(cmd=cmd, confirm=confirm)


class CiscoIosSSH(CiscoIosBase):
"""Cisco IOS SSH driver."""
Expand Down
12 changes: 0 additions & 12 deletions netmiko/cisco/cisco_nxos_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,6 @@ def __init__(self, ssh_conn, source_file, dest_file, file_system='bootflash:', d
else:
raise ValueError("Invalid direction specified")

def remote_space_available(self, search_pattern=r"(\d+) bytes free"):
"""Return space available on remote device."""
return super(CiscoNxosFileTransfer, self).remote_space_available(
search_pattern=search_pattern
)

def verify_space_available(self, search_pattern=r"(\d+) bytes free"):
"""Verify sufficient space is available on destination file system (return boolean)."""
return super(CiscoNxosFileTransfer, self).verify_space_available(
search_pattern=search_pattern
)

def check_file_exists(self, remote_cmd=""):
"""Check if the dest_file already exists on the file system (return boolean)."""
raise NotImplementedError
Expand Down
4 changes: 3 additions & 1 deletion netmiko/cisco/cisco_s300.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ def session_preparation(self):
self.set_terminal_width(command='terminal width 511')
# Clear the read buffer
time.sleep(.3 * self.global_delay_factor)
self.clear_buffer()

def save_config(self, cmd='write memory', confirm=True, confirm_response='Y'):
return super(CiscoS300SSH, self).save_config(cmd=cmd, confirm=confirm)
4 changes: 4 additions & 0 deletions netmiko/cisco/cisco_tp_tcce.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,7 @@ def send_command(self, *args, **kwargs):

output = super(CiscoSSHConnection, self).send_command(*args, **kwargs)
return output

def save_config(self):
"""Not Implemented"""
raise NotImplementedError
4 changes: 4 additions & 0 deletions netmiko/cisco/cisco_wlc_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,7 @@ def send_config_set(self, config_commands=None, exit_config_mode=True, delay_fac
output = self._sanitize_output(output)
log.debug("{}".format(output))
return output

def save_config(self, cmd='save config', confirm=True, confirm_response='y'):
return super(CiscoWlcSSH, self).save_config(cmd=cmd, confirm=confirm,
confirm_response=confirm_response)
4 changes: 4 additions & 0 deletions netmiko/cisco/cisco_xr_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,7 @@ def exit_config_mode(self, exit_config='end'):
if self.check_config_mode():
raise ValueError("Failed to exit configuration mode")
return output

def save_config(self):
"""Not Implemented (use commit() method)"""
raise NotImplementedError
19 changes: 18 additions & 1 deletion netmiko/cisco_base_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ def serial_login(self, pri_prompt_terminator=r'#\s*$', alt_prompt_terminator=r'>
username_pattern, pwd_pattern, delay_factor, max_loops)

def telnet_login(self, pri_prompt_terminator=r'#\s*$', alt_prompt_terminator=r'>\s*$',
username_pattern=r"(?:[Uu]ser:|sername|ogin)", pwd_pattern=r"assword",
username_pattern=r"(?:[Uu]ser:|sername|ogin|User Name)",
pwd_pattern=r"assword",
delay_factor=1, max_loops=20):
"""Telnet login. Can be username/password or just password."""
delay_factor = self.select_delay_factor(delay_factor)
Expand Down Expand Up @@ -162,6 +163,22 @@ def _autodetect_fs(self, cmd='dir', pattern=r'Directory of (.*)/'):
raise ValueError("An error occurred in dynamically determining remote file "
"system: {} {}".format(cmd, output))

def save_config(self, cmd='copy running-config startup-config', confirm=False,
confirm_response=''):
"""Saves Config."""
self.enable()
if confirm:
output = self.send_command_timing(command_string=cmd)
if confirm_response:
output += self.send_command_timing(confirm_response)
else:
# Send enter by default
output += self.send_command_timing(self.RETURN)
else:
# Some devices are slow so match on trailing-prompt if you can
output = self.send_command(command_string=cmd)
return output


class CiscoSSHConnection(CiscoBaseConnection):
pass
Expand Down
4 changes: 4 additions & 0 deletions netmiko/coriant/coriant_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,7 @@ def set_base_prompt(self, pri_prompt_terminator=':', alt_prompt_terminator='>',
alt_prompt_terminator=alt_prompt_terminator,
delay_factor=delay_factor)
return self.base_prompt

def save_config(self, cmd='', confirm=True, confirm_response=''):
"""Not Implemented"""
raise NotImplementedError
5 changes: 4 additions & 1 deletion netmiko/dell/dell_force10_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,7 @@

class DellForce10SSH(CiscoSSHConnection):
"""Dell Force10 Driver - supports DNOS9."""
pass

def save_config(self, cmd='copy running-configuration startup-configuration', confirm=False):
"""Saves Config"""
return super(DellForce10SSH, self).save_config(cmd=cmd, confirm=confirm)
12 changes: 6 additions & 6 deletions netmiko/dell/dell_powerconnect.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,21 @@ def session_preparation(self):
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 = super(DellPowerConnectBase, 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)
return super(DellPowerConnectBase, 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)
return super(DellPowerConnectBase, self).config_mode(config_command=config_command)


class DellPowerConnectSSH(DellPowerConnectBase):
Expand Down
4 changes: 4 additions & 0 deletions netmiko/eltex/eltex_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@ def session_preparation(self):
# Clear the read buffer
time.sleep(.3 * self.global_delay_factor)
self.clear_buffer()

def save_config(self, cmd='', confirm=True, confirm_response=''):
"""Not Implemented"""
raise NotImplementedError
4 changes: 4 additions & 0 deletions netmiko/enterasys/enterasys_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@ def session_preparation(self):
# Clear the read buffer
time.sleep(.3 * self.global_delay_factor)
self.clear_buffer()

def save_config(self, cmd='', confirm=True, confirm_response=''):
"""Not Implemented"""
raise NotImplementedError
5 changes: 3 additions & 2 deletions netmiko/extreme/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import unicode_literals
from netmiko.extreme.extreme_ssh import ExtremeSSH
from netmiko.extreme.extreme_exos import ExtremeSSH
from netmiko.extreme.extreme_exos import ExtremeTelnet
from netmiko.extreme.extreme_wing_ssh import ExtremeWingSSH

__all__ = ['ExtremeSSH', 'ExtremeWingSSH']
__all__ = ['ExtremeSSH', 'ExtremeWingSSH', 'ExtremeTelnet']
Loading

0 comments on commit 2f60d4d

Please sign in to comment.