Skip to content

Commit cc08641

Browse files
authored
Merge pull request #657 from ktbyers/develop
Netmiko release 2.0.0
2 parents 2871816 + f70c19e commit cc08641

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+1637
-585
lines changed

.travis.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
language: python
33
python:
44
- "2.7"
5-
- "3.4"
65
- "3.5"
6+
- "3.6"
77
#before_install:
88
# - openssl aes-256-cbc -K $encrypted_25c51ccabb0e_key -iv $encrypted_25c51ccabb0e_iv -in travis_test_env.tar.enc -out travis_test_env.tar -d
99
# - tar xvf travis_test_env.tar
1010
install:
1111
- pip install -r requirements-dev.txt
12+
- pip install tox-travis
1213
script:
1314
- pylama .
15+
- tox

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ Huawei
4646
Mellanox
4747
Palo Alto PAN-OS
4848
Pluribus
49-
Ubiquiti EdgeOS
49+
Ubiquiti EdgeSwitch
5050
Vyatta VyOS
5151

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

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

78+
##### Documentation (Stable)
79+
80+
http://netmiko.readthedocs.io/en/stable/index.html
81+
7882
## Examples:
7983

8084
#### Create a dictionary representing the device.

netmiko/__init__.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
from netmiko.ssh_dispatcher import ssh_dispatcher
1010
from netmiko.ssh_dispatcher import redispatch
1111
from netmiko.ssh_dispatcher import platforms
12+
from netmiko.ssh_dispatcher import FileTransfer
1213
from netmiko.scp_handler import SCPConn
13-
from netmiko.scp_handler import FileTransfer
14-
from netmiko.scp_handler import InLineTransfer
14+
from netmiko.cisco.cisco_ios import InLineTransfer
1515
from netmiko.ssh_exception import NetMikoTimeoutException
1616
from netmiko.ssh_exception import NetMikoAuthenticationException
1717
from netmiko.ssh_autodetect import SSHDetect
@@ -21,8 +21,7 @@
2121
NetmikoTimeoutError = NetMikoTimeoutException
2222
NetmikoAuthError = NetMikoAuthenticationException
2323

24-
__version__ = '1.4.3'
25-
24+
__version__ = '2.0.0'
2625
__all__ = ('ConnectHandler', 'ssh_dispatcher', 'platforms', 'SCPConn', 'FileTransfer',
2726
'NetMikoTimeoutException', 'NetMikoAuthenticationException',
2827
'NetmikoTimeoutError', 'NetmikoAuthError', 'InLineTransfer', 'redispatch',

netmiko/a10/a10_ssh.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""A10 support."""
22
from __future__ import unicode_literals
3+
import time
34
from netmiko.cisco_base_connection import CiscoSSHConnection
45

56

@@ -10,7 +11,11 @@ def session_preparation(self):
1011
self._test_channel_read()
1112
self.set_base_prompt()
1213
self.enable()
13-
self.disable_paging(command="terminal length 0\n")
14+
self.disable_paging(command="terminal length 0")
1415

1516
# Will not do anything without A10 specific command
1617
self.set_terminal_width()
18+
19+
# Clear the read buffer
20+
time.sleep(.3 * self.global_delay_factor)
21+
self.clear_buffer()

netmiko/accedian/accedian_ssh.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
21
from __future__ import unicode_literals
2+
import time
33
from netmiko.cisco_base_connection import CiscoSSHConnection
44

55

66
class AccedianSSH(CiscoSSHConnection):
77
def session_preparation(self):
88
self._test_channel_read()
99
self.set_base_prompt()
10+
# Clear the read buffer
11+
time.sleep(.3 * self.global_delay_factor)
12+
self.clear_buffer()
1013

1114
def check_enable_mode(self, *args, **kwargs):
1215
raise AttributeError("Accedian devices do not support enable mode!")

netmiko/alcatel/alcatel_aos_ssh.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Alcatel-Lucent Enterprise AOS support (AOS6 and AOS8)."""
22
from __future__ import print_function
33
from __future__ import unicode_literals
4+
import time
45
from netmiko.cisco_base_connection import CiscoSSHConnection
56

67

@@ -10,6 +11,9 @@ def session_preparation(self):
1011
# Prompt can be anything, but best practice is to end with > or #
1112
self._test_channel_read(pattern=r'[>#]')
1213
self.set_base_prompt()
14+
# Clear the read buffer
15+
time.sleep(.3 * self.global_delay_factor)
16+
self.clear_buffer()
1317

1418
def check_enable_mode(self, *args, **kwargs):
1519
"""No enable mode on AOS"""

netmiko/alcatel/alcatel_sros_ssh.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from __future__ import print_function
33
from __future__ import unicode_literals
44
import re
5+
import time
56
from netmiko.cisco_base_connection import CiscoSSHConnection
67

78

@@ -10,7 +11,10 @@ class AlcatelSrosSSH(CiscoSSHConnection):
1011
def session_preparation(self):
1112
self._test_channel_read()
1213
self.set_base_prompt()
13-
self.disable_paging(command="environment no more\n")
14+
self.disable_paging(command="environment no more")
15+
# Clear the read buffer
16+
time.sleep(.3 * self.global_delay_factor)
17+
self.clear_buffer()
1418

1519
def set_base_prompt(self, *args, **kwargs):
1620
"""Remove the > when navigating into the different config level."""

netmiko/arista/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
from __future__ import unicode_literals
2-
from netmiko.arista.arista_ssh import AristaSSH
2+
from netmiko.arista.arista_ssh import AristaSSH, AristaFileTransfer
33

4-
__all__ = ['AristaSSH']
4+
__all__ = ['AristaSSH', 'AristaFileTransfer']

netmiko/arista/arista_ssh.py

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
from __future__ import unicode_literals
2+
import time
3+
import re
24
from netmiko.cisco_base_connection import CiscoSSHConnection
5+
from netmiko.cisco_base_connection import CiscoFileTransfer
36
from netmiko import log
47

58

@@ -10,6 +13,9 @@ def session_preparation(self):
1013
self.set_base_prompt()
1114
self.disable_paging()
1215
self.set_terminal_width(command='terminal width 511')
16+
# Clear the read buffer
17+
time.sleep(.3 * self.global_delay_factor)
18+
self.clear_buffer()
1319

1420
def check_config_mode(self, check_string=')#', pattern=''):
1521
"""
@@ -21,10 +27,102 @@ def check_config_mode(self, check_string=')#', pattern=''):
2127
Can also be (s2)
2228
"""
2329
log.debug("pattern: {0}".format(pattern))
24-
self.write_channel('\n')
30+
self.write_channel(self.RETURN)
2531
output = self.read_until_pattern(pattern=pattern)
2632
log.debug("check_config_mode: {0}".format(repr(output)))
2733
output = output.replace("(s1)", "")
2834
output = output.replace("(s2)", "")
2935
log.debug("check_config_mode: {0}".format(repr(output)))
3036
return check_string in output
37+
38+
39+
class AristaFileTransfer(CiscoFileTransfer):
40+
"""Arista SCP File Transfer driver."""
41+
def __init__(self, ssh_conn, source_file, dest_file, file_system=None, direction='put'):
42+
msg = "Arista SCP Driver is under development and not fully implemented"
43+
raise NotImplementedError(msg)
44+
self.ssh_ctl_chan = ssh_conn
45+
self.source_file = source_file
46+
self.dest_file = dest_file
47+
self.direction = direction
48+
49+
if file_system:
50+
self.file_system = file_system
51+
else:
52+
raise ValueError("Destination file system must be specified for Arista")
53+
54+
# if direction == 'put':
55+
# self.source_md5 = self.file_md5(source_file)
56+
# self.file_size = os.stat(source_file).st_size
57+
# elif direction == 'get':
58+
# self.source_md5 = self.remote_md5(remote_file=source_file)
59+
# self.file_size = self.remote_file_size(remote_file=source_file)
60+
# else:
61+
# raise ValueError("Invalid direction specified")
62+
63+
def put_file(self):
64+
"""SCP copy the file from the local system to the remote device."""
65+
destination = "{}/{}".format(self.file_system, self.dest_file)
66+
self.scp_conn.scp_transfer_file(self.source_file, destination)
67+
# Must close the SCP connection to get the file written (flush)
68+
self.scp_conn.close()
69+
70+
def remote_space_available(self, search_pattern=r"(\d+) bytes free"):
71+
"""Return space available on remote device."""
72+
return super(AristaFileTransfer, self).remote_space_available(
73+
search_pattern=search_pattern
74+
)
75+
76+
def verify_space_available(self, search_pattern=r"(\d+) bytes free"):
77+
"""Verify sufficient space is available on destination file system (return boolean)."""
78+
return super(AristaFileTransfer, self).verify_space_available(
79+
search_pattern=search_pattern
80+
)
81+
82+
def check_file_exists(self, remote_cmd=""):
83+
"""Check if the dest_file already exists on the file system (return boolean)."""
84+
raise NotImplementedError
85+
86+
def remote_file_size(self, remote_cmd="", remote_file=None):
87+
"""Get the file size of the remote file."""
88+
if remote_file is None:
89+
if self.direction == 'put':
90+
remote_file = self.dest_file
91+
elif self.direction == 'get':
92+
remote_file = self.source_file
93+
94+
if not remote_cmd:
95+
remote_cmd = "dir {}/{}".format(self.file_system, remote_file)
96+
97+
remote_out = self.ssh_ctl_chan.send_command(remote_cmd)
98+
# Match line containing file name
99+
escape_file_name = re.escape(remote_file)
100+
pattern = r".*({}).*".format(escape_file_name)
101+
match = re.search(pattern, remote_out)
102+
if match:
103+
file_size = match.group(0)
104+
file_size = file_size.split()[0]
105+
106+
if 'No such file or directory' in remote_out:
107+
raise IOError("Unable to find file on remote system")
108+
else:
109+
return int(file_size)
110+
111+
@staticmethod
112+
def process_md5(md5_output, pattern=r"= (.*)"):
113+
raise NotImplementedError
114+
115+
def remote_md5(self, base_cmd='show file', remote_file=None):
116+
if remote_file is None:
117+
if self.direction == 'put':
118+
remote_file = self.dest_file
119+
elif self.direction == 'get':
120+
remote_file = self.source_file
121+
remote_md5_cmd = "{} {}{} md5sum".format(base_cmd, self.file_system, remote_file)
122+
return self.ssh_ctl_chan.send_command(remote_md5_cmd, delay_factor=3.0)
123+
124+
def enable_scp(self, cmd=None):
125+
raise NotImplementedError
126+
127+
def disable_scp(self, cmd=None):
128+
raise NotImplementedError

netmiko/aruba/aruba_ssh.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ def session_preparation(self):
1515
self.set_base_prompt()
1616
self.enable()
1717
self.disable_paging(command="no paging")
18+
# Clear the read buffer
19+
time.sleep(.3 * self.global_delay_factor)
20+
self.clear_buffer()
1821

1922
def check_config_mode(self, check_string='(config) #', pattern=''):
2023
"""

0 commit comments

Comments
 (0)