Skip to content

Commit

Permalink
Merge pull request #657 from ktbyers/develop
Browse files Browse the repository at this point in the history
Netmiko release 2.0.0
  • Loading branch information
ktbyers authored Dec 15, 2017
2 parents 2871816 + f70c19e commit cc08641
Show file tree
Hide file tree
Showing 69 changed files with 1,637 additions and 585 deletions.
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
language: python
python:
- "2.7"
- "3.4"
- "3.5"
- "3.6"
#before_install:
# - openssl aes-256-cbc -K $encrypted_25c51ccabb0e_key -iv $encrypted_25c51ccabb0e_iv -in travis_test_env.tar.enc -out travis_test_env.tar -d
# - tar xvf travis_test_env.tar
install:
- pip install -r requirements-dev.txt
- pip install tox-travis
script:
- pylama .
- tox
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Huawei
Mellanox
Palo Alto PAN-OS
Pluribus
Ubiquiti EdgeOS
Ubiquiti EdgeSwitch
Vyatta VyOS

###### Experimental
Expand Down Expand Up @@ -75,6 +75,10 @@ https://pynet.twb-tech.com/blog/automation/netmiko.html

https://pynet.twb-tech.com/blog/automation/netmiko-proxy.html

##### Documentation (Stable)

http://netmiko.readthedocs.io/en/stable/index.html

## Examples:

#### Create a dictionary representing the device.
Expand Down
7 changes: 3 additions & 4 deletions netmiko/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
from netmiko.ssh_dispatcher import ssh_dispatcher
from netmiko.ssh_dispatcher import redispatch
from netmiko.ssh_dispatcher import platforms
from netmiko.ssh_dispatcher import FileTransfer
from netmiko.scp_handler import SCPConn
from netmiko.scp_handler import FileTransfer
from netmiko.scp_handler import InLineTransfer
from netmiko.cisco.cisco_ios import InLineTransfer
from netmiko.ssh_exception import NetMikoTimeoutException
from netmiko.ssh_exception import NetMikoAuthenticationException
from netmiko.ssh_autodetect import SSHDetect
Expand All @@ -21,8 +21,7 @@
NetmikoTimeoutError = NetMikoTimeoutException
NetmikoAuthError = NetMikoAuthenticationException

__version__ = '1.4.3'

__version__ = '2.0.0'
__all__ = ('ConnectHandler', 'ssh_dispatcher', 'platforms', 'SCPConn', 'FileTransfer',
'NetMikoTimeoutException', 'NetMikoAuthenticationException',
'NetmikoTimeoutError', 'NetmikoAuthError', 'InLineTransfer', 'redispatch',
Expand Down
7 changes: 6 additions & 1 deletion netmiko/a10/a10_ssh.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""A10 support."""
from __future__ import unicode_literals
import time
from netmiko.cisco_base_connection import CiscoSSHConnection


Expand All @@ -10,7 +11,11 @@ def session_preparation(self):
self._test_channel_read()
self.set_base_prompt()
self.enable()
self.disable_paging(command="terminal length 0\n")
self.disable_paging(command="terminal length 0")

# Will not do anything without A10 specific command
self.set_terminal_width()

# Clear the read buffer
time.sleep(.3 * self.global_delay_factor)
self.clear_buffer()
5 changes: 4 additions & 1 deletion netmiko/accedian/accedian_ssh.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@

from __future__ import unicode_literals
import time
from netmiko.cisco_base_connection import CiscoSSHConnection


class AccedianSSH(CiscoSSHConnection):
def session_preparation(self):
self._test_channel_read()
self.set_base_prompt()
# Clear the read buffer
time.sleep(.3 * self.global_delay_factor)
self.clear_buffer()

def check_enable_mode(self, *args, **kwargs):
raise AttributeError("Accedian devices do not support enable mode!")
Expand Down
4 changes: 4 additions & 0 deletions netmiko/alcatel/alcatel_aos_ssh.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Alcatel-Lucent Enterprise AOS support (AOS6 and AOS8)."""
from __future__ import print_function
from __future__ import unicode_literals
import time
from netmiko.cisco_base_connection import CiscoSSHConnection


Expand All @@ -10,6 +11,9 @@ 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()
# Clear the read buffer
time.sleep(.3 * self.global_delay_factor)
self.clear_buffer()

def check_enable_mode(self, *args, **kwargs):
"""No enable mode on AOS"""
Expand Down
6 changes: 5 additions & 1 deletion netmiko/alcatel/alcatel_sros_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from __future__ import print_function
from __future__ import unicode_literals
import re
import time
from netmiko.cisco_base_connection import CiscoSSHConnection


Expand All @@ -10,7 +11,10 @@ class AlcatelSrosSSH(CiscoSSHConnection):
def session_preparation(self):
self._test_channel_read()
self.set_base_prompt()
self.disable_paging(command="environment no more\n")
self.disable_paging(command="environment no more")
# Clear the read buffer
time.sleep(.3 * self.global_delay_factor)
self.clear_buffer()

def set_base_prompt(self, *args, **kwargs):
"""Remove the > when navigating into the different config level."""
Expand Down
4 changes: 2 additions & 2 deletions netmiko/arista/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from __future__ import unicode_literals
from netmiko.arista.arista_ssh import AristaSSH
from netmiko.arista.arista_ssh import AristaSSH, AristaFileTransfer

__all__ = ['AristaSSH']
__all__ = ['AristaSSH', 'AristaFileTransfer']
100 changes: 99 additions & 1 deletion netmiko/arista/arista_ssh.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
from __future__ import unicode_literals
import time
import re
from netmiko.cisco_base_connection import CiscoSSHConnection
from netmiko.cisco_base_connection import CiscoFileTransfer
from netmiko import log


Expand All @@ -10,6 +13,9 @@ def session_preparation(self):
self.set_base_prompt()
self.disable_paging()
self.set_terminal_width(command='terminal width 511')
# Clear the read buffer
time.sleep(.3 * self.global_delay_factor)
self.clear_buffer()

def check_config_mode(self, check_string=')#', pattern=''):
"""
Expand All @@ -21,10 +27,102 @@ def check_config_mode(self, check_string=')#', pattern=''):
Can also be (s2)
"""
log.debug("pattern: {0}".format(pattern))
self.write_channel('\n')
self.write_channel(self.RETURN)
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


class AristaFileTransfer(CiscoFileTransfer):
"""Arista SCP File Transfer driver."""
def __init__(self, ssh_conn, source_file, dest_file, file_system=None, direction='put'):
msg = "Arista SCP Driver is under development and not fully implemented"
raise NotImplementedError(msg)
self.ssh_ctl_chan = ssh_conn
self.source_file = source_file
self.dest_file = dest_file
self.direction = direction

if file_system:
self.file_system = file_system
else:
raise ValueError("Destination file system must be specified for Arista")

# 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 put_file(self):
"""SCP copy the file from the local system to the remote device."""
destination = "{}/{}".format(self.file_system, self.dest_file)
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 remote_space_available(self, search_pattern=r"(\d+) bytes free"):
"""Return space available on remote device."""
return super(AristaFileTransfer, 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(AristaFileTransfer, 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

def remote_file_size(self, remote_cmd="", remote_file=None):
"""Get the file size of the remote file."""
if remote_file is None:
if self.direction == 'put':
remote_file = self.dest_file
elif self.direction == 'get':
remote_file = self.source_file

if not remote_cmd:
remote_cmd = "dir {}/{}".format(self.file_system, remote_file)

remote_out = self.ssh_ctl_chan.send_command(remote_cmd)
# Match line containing file name
escape_file_name = re.escape(remote_file)
pattern = r".*({}).*".format(escape_file_name)
match = re.search(pattern, remote_out)
if match:
file_size = match.group(0)
file_size = file_size.split()[0]

if 'No such file or directory' in remote_out:
raise IOError("Unable to find file on remote system")
else:
return int(file_size)

@staticmethod
def process_md5(md5_output, pattern=r"= (.*)"):
raise NotImplementedError

def remote_md5(self, base_cmd='show file', remote_file=None):
if remote_file is None:
if self.direction == 'put':
remote_file = self.dest_file
elif self.direction == 'get':
remote_file = self.source_file
remote_md5_cmd = "{} {}{} md5sum".format(base_cmd, self.file_system, remote_file)
return self.ssh_ctl_chan.send_command(remote_md5_cmd, delay_factor=3.0)

def enable_scp(self, cmd=None):
raise NotImplementedError

def disable_scp(self, cmd=None):
raise NotImplementedError
3 changes: 3 additions & 0 deletions netmiko/aruba/aruba_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ def session_preparation(self):
self.set_base_prompt()
self.enable()
self.disable_paging(command="no paging")
# Clear the read buffer
time.sleep(.3 * self.global_delay_factor)
self.clear_buffer()

def check_config_mode(self, check_string='(config) #', pattern=''):
"""
Expand Down
6 changes: 3 additions & 3 deletions netmiko/avaya/avaya_ers_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ def special_login_handler(self, delay_factor=1):
if 'Ctrl-Y' in output:
self.write_channel(CTRL_Y)
if 'sername' in output:
self.write_channel(self.username + '\n')
self.write_channel(self.username + self.RETURN)
elif 'ssword' in output:
self.write_channel(self.password + '\n')
self.write_channel(self.password + self.RETURN)
break
time.sleep(.5 * delay_factor)
else:
self.write_channel('\n')
self.write_channel(self.RETURN)
time.sleep(1 * delay_factor)
i += 1
6 changes: 5 additions & 1 deletion netmiko/avaya/avaya_vsp_ssh.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Avaya Virtual Services Platform Support."""
from __future__ import print_function
from __future__ import unicode_literals
import time
from netmiko.cisco_base_connection import CiscoSSHConnection


Expand All @@ -10,4 +11,7 @@ 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")
self.disable_paging(command="terminal more disable")
# Clear the read buffer
time.sleep(.3 * self.global_delay_factor)
self.clear_buffer()
Loading

0 comments on commit cc08641

Please sign in to comment.