38 Commits
0.1.2 ... 0.2.0

Author SHA1 Message Date
Piotr Pieprzycki
dd96e7dccd Merge pull request #37 from napalm-automation-community/develop
Merge Develop into master
2020-05-17 23:51:44 +02:00
Piotr Pieprzycki
fe3d5560ab Merge pull request #32 from bradmwalker/napalm3
Napalm 3 Compatibility
2020-05-17 23:46:12 +02:00
Piotr Pieprzycki
05296bc1fa Merge branch 'develop' into napalm3 2020-05-17 23:43:38 +02:00
Piotr Pieprzycki
ea4bc1a4ae Merge pull request #34 from bradmwalker/lldp
Implement get_lldp_neighbors() for simple case
2020-05-17 23:39:10 +02:00
Piotr Pieprzycki
011db99dcc Merge pull request #33 from bradmwalker/mtu
Add MTU to get_interfaces() results
2020-05-17 23:35:08 +02:00
Brad Walker
0420304a6d Implement get_lldp_neighbors() for simple case 2020-05-17 10:53:07 -06:00
Brad Walker
b883dcbbb0 Bump to 0.1.7 and require NAPALM 2.5 2020-05-16 13:06:10 -06:00
Brad Walker
c78fd09304 Add invalid mtu to get_interfaces 2020-05-16 13:02:21 -06:00
Brad Walker
d2d0f2723f Bump minor version and use NAPALM 3 2020-05-16 12:34:21 -06:00
Brad Walker
2bdb499b14 Replace _get_value with dict.get usage 2020-05-16 10:50:09 -06:00
Brad Walker
cbfe8ae0c4 Fix invalid escape sequence DeprecationWarnings 2020-05-16 10:44:11 -06:00
Brad Walker
3b53afd852 Improve SyntaxWarning for empty string checks 2020-05-16 10:39:20 -06:00
Brad Walker
b287f3d6c7 Remove py23_compat.text_type usage 2020-05-16 10:26:39 -06:00
Piotr Pieprzycki
1d11f45e68 Merge pull request #30 from napalm-automation-community/develop
Fix installation fails with the pip > 10  dev->master
2019-02-15 09:30:44 +01:00
Piotr Pieprzycki
df1d827038 Merge pull request #29 from ppieprzycki/issue28
Fix installation fails with the pip > 10
2019-02-15 09:19:34 +01:00
Pieprzycki Piotr
0175531bbb add additional parameters 2019-02-14 23:55:18 +01:00
Pieprzycki Piotr
42953c84ae add additional parameters 2019-02-14 23:43:56 +01:00
Pieprzycki Piotr
57b6110f13 fix pip issue 2019-02-14 07:03:57 +01:00
Piotr Pieprzycki
f1549d8af3 Merge pull request #25 from napalm-automation-community/master
Update develop branch
2018-04-08 18:26:36 +02:00
Piotr Pieprzycki
2278bddd3a Merge pull request #24 from ppieprzycki/master
Support for salt
2018-04-08 18:19:57 +02:00
Pieprzycki Piotr
55a6b15c3e Update docs 2018-04-08 18:15:28 +02:00
Pieprzycki Piotr
580da0edeb Update docs 2018-04-08 18:12:07 +02:00
Pieprzycki Piotr
23fe045167 Update docs 2018-04-08 18:09:21 +02:00
Pieprzycki Piotr
b8ec1396f7 Update docs 2018-04-08 17:56:49 +02:00
Pieprzycki Piotr
5c3492f13c Update docs 2018-04-08 11:28:15 +02:00
Pieprzycki Piotr
47227d1cf0 handle config as text in load and merge functions 2018-04-08 00:23:04 +02:00
Piotr Pieprzycki
06f9fc28d3 Merge pull request #23 from napalm-automation-community/develop
Merge develop branch with master
2018-02-22 21:30:01 +01:00
Piotr Pieprzycki
6e68dba692 Merge pull request #22 from ppieprzycki/master
Fix travis status and set new version 0.1.4
2018-02-22 20:36:50 +01:00
Piotr Pieprzycki
7d0e30fdba Merge pull request #20 from thomseddon/fix/use-napalm-base
Use napalm instead of napalm_base
2018-02-22 20:29:11 +01:00
Pieprzycki Piotr
4d52216866 Fix travis status and set new version 0.1.4 2018-02-22 20:28:24 +01:00
Piotr Pieprzycki
5c440b3df9 Merge pull request #21 from ppieprzycki/master
Fix imports to napalm2
2018-02-22 20:19:15 +01:00
Pieprzycki Piotr
69c8c66652 napalm 2 2018-02-22 20:00:24 +01:00
Thom Seddon
b9bcbbc7bc Use napalm instead of napalm_base 2018-02-22 10:16:54 +00:00
Mircea Ulinic
347d6a6603 Merge pull request #14 from napalm-automation/develop
Release 0.1.3
2017-02-08 15:28:04 -05:00
Mircea Ulinic
cc98324b6d Merge pull request #13 from napalm-automation/rel-0.1.3
Version 0.1.3
2017-02-08 15:09:07 -05:00
Mircea Ulinic
fcdcfb719f Merge pull request #12 from mirceaulinic/patch-1
Add vrf arg to ping
2017-02-08 15:08:59 -05:00
Mircea Ulinic
673cb74593 Version 0.1.3 2017-02-07 01:06:01 -05:00
Mircea Ulinic
44948805bc Add vrf arg to ping
Looks like vyos doesn't know about VRF
so these changes should be reflected only
in the method header
2017-02-02 12:06:48 +00:00
13 changed files with 361 additions and 129 deletions

View File

@@ -1,8 +1,8 @@
language: python
python:
- 2.7
- 3.4
- 3.5
- 3.6
- 3.7
- 3.8
install:
- pip install tox-travis
- pip install coveralls

107
README.md
View File

@@ -1,5 +1,110 @@
[![PyPI](https://img.shields.io/pypi/v/napalm-vyos.svg)](https://pypi.python.org/pypi/napalm-vyos)
[![PyPI](https://img.shields.io/pypi/dm/napalm-vyos.svg)](https://pypi.python.org/pypi/napalm-vyos)
[![Build Status](https://travis-ci.org/napalm-automation/napalm-vyos.svg?branch=master)](https://travis-ci.org/napalm-automation/napalm-vyos)
[![Build Status](https://travis-ci.org/napalm-automation-community/napalm-vyos.svg?branch=master)](https://travis-ci.org/napalm-automation-community/napalm-vyos)
# napalm-vyos
Community NAPALM driver for the VyOS. https://vyos.io/
Also it can be used for other similar systems: Vyatta or EdgeOS
General support matrix
----------------------
| | VyOS |
|--------------------|--------------|
|**Module Name** | napalm-vyos |
|**Driver Name** | vyos |
|**Structured data** | Yes |
|**Minimum version** | 1.1.6 |
|**Backend library** | netmiko |
Configuration support matrix
----------------------------
| | VyOS |
| ------------------- | ----- |
| **Config. replace** | Yes |
| **Config. merge** | Yes |
|**Compare config** | Yes |
| **Atomic Changes** | Yes |
| **Rollback** | Yes |
Optional arguments
------------------
NAPALM supports passing certain optional arguments to some drivers. To do that you have to pass a dictionary via the
:code:`optional_args` parameter when creating the object::
>>> from napalm import get_network_driver
>>> driver = get_network_driver('vyos')
>>> optional_args = {'my_optional_arg1': 'my_value1', 'my_optional_arg2': 'my_value2'}
>>> device = driver('192.168.76.10', 'vagrant', 'this_is_not_a_secure_password', optional_args=optional_args)
>>> device.open()
List of supported optional arguments
____________________________________
* :code:`port` (vyos) - Allows you to specify a port other than the default.
* :code:`key_file` (vyos) - Netmiko/Paramiko argument, path to a private key file (default: 'False').
Prerequisites
-------------
VyOS has no native HTTP API or NETCONF capability.
We are using Netmiko for ssh connections and scp file transfers.
Having Netmiko installed in your working box is a prerequisite.
VyOS in version 1.1.x (tested 1.1.7)
napalm==2.*
paramiko
netmiko>=1.1.0
vyattaconfparser
Configuration file
------------------
Currently VyOS driver supports two different configuration formats:
* load_replace_candidate - Full config file (with brackets) like in /config/config.boot
Due to the OS nature, we do not support a replace using
a set-style configuration format.
* load_merge_candidate - Currently driver supports set-style configuration format.
Example
`set system login banner pre-login "test"`
Vyos require configuration file (load_replace) to contain comment like following
`/* Warning: Do not remove the following line. */
/* === vyatta-config-version: "cluster@1:config-management@1:conntrack-sync@1:conntrack@1:cron@1:dhcp-relay@1:dhcp-server@4:firewall@5:ipsec@4:nat@4:qos@1:quagga@2:system@6:vrrp@1:wanloadbalance@3:webgui@1:webproxy@1:zone-policy@1" === */
/* Release version: VyOS 1.1.7 */`
Otherwise VyOS reject `load` operation
Notes
------------------
* The NAPALM-vyos driver supports all Netmiko arguments as either standard arguments (hostname, username, password, timeout) or as optional_args (everything else).
* The NAPALM-vyos driver supports authentication with ssh key. Please specify path to a key in optional_args
`'optional_args': {'key_file': '/home/user/ssh_private_key'}`
Configuration Examples
----------------------
* Vyos as IPSec VPN endpoint and BGP router - https://github.com/DreamLab/ansible-vyos
* CI Demo for vyos+junos (Polish only) https://github.com/ppieprzycki/plnog2016
VyOS Community
------------------
Slack Channel https://slack.vyos.io

View File

@@ -22,6 +22,7 @@ Read napalm.readthedocs.org for more information.
import re
import os
import tempfile
import vyattaconfparser
@@ -30,10 +31,11 @@ from netmiko import ConnectHandler
from netmiko import SCPConn
# NAPALM base
from napalm_base.utils import py23_compat
from napalm_base.base import NetworkDriver
from napalm_base.exceptions import ConnectionException, \
MergeConfigException, ReplaceConfigException
import napalm.base.constants as C
from napalm.base.base import NetworkDriver
from napalm.base.exceptions import ConnectionException, MergeConfigException, \
ReplaceConfigException, CommitError, \
CommandErrorException
class VyOSDriver(NetworkDriver):
@@ -120,53 +122,73 @@ class VyOSDriver(NetworkDriver):
Due to the OS nature, we do not
support a replace using a configuration string.
"""
if filename is not None:
if os.path.exists(filename) is True:
self._scp_client.scp_transfer_file(filename, self._DEST_FILENAME)
self.device.send_command("cp "+self._BOOT_FILENAME+" "+self._BACKUP_FILENAME)
output_loadcmd = self.device.send_config_set(['load '+self._DEST_FILENAME])
match_loaded = re.findall("Load complete.", output_loadcmd)
match_notchanged = re.findall("No configuration changes to commit", output_loadcmd)
match_failed = re.findall("Failed to parse specified config file", output_loadcmd)
if not filename and not config:
raise ReplaceConfigException('filename or config param must be provided.')
if match_failed:
if filename is None:
temp_file = tempfile.NamedTemporaryFile()
temp_file.write(config)
temp_file.flush()
cfg_filename = temp_file.name
else:
cfg_filename = filename
if os.path.exists(cfg_filename) is True:
self._scp_client.scp_transfer_file(cfg_filename, self._DEST_FILENAME)
self.device.send_command("cp "+self._BOOT_FILENAME+" "+self._BACKUP_FILENAME)
output_loadcmd = self.device.send_config_set(['load '+self._DEST_FILENAME])
match_loaded = re.findall("Load complete.", output_loadcmd)
match_notchanged = re.findall("No configuration changes to commit", output_loadcmd)
match_failed = re.findall("Failed to parse specified config file", output_loadcmd)
if match_failed:
raise ReplaceConfigException("Failed replace config: "
+ output_loadcmd)
if not match_loaded:
if not match_notchanged:
raise ReplaceConfigException("Failed replace config: "
+ output_loadcmd)
if not match_loaded:
if not match_notchanged:
raise ReplaceConfigException("Failed replace config: "
+ output_loadcmd)
else:
raise ReplaceConfigException("config file is not found")
else:
raise ReplaceConfigException("no configuration found")
raise ReplaceConfigException("config file is not found")
def load_merge_candidate(self, filename=None, config=None):
"""
Only configuration in set-format is supported with load_merge_candidate.
"""
if filename is not None:
if os.path.exists(filename) is True:
with open(filename) as f:
self.device.send_command("cp "+self._BOOT_FILENAME+" "
+ self._BACKUP_FILENAME)
self._new_config = f.read()
cfg = [x for x in self._new_config.split("\n") if x is not ""]
output_loadcmd = self.device.send_config_set(cfg)
match_setfailed = re.findall("Delete failed", output_loadcmd)
match_delfailed = re.findall("Set failed", output_loadcmd)
if match_setfailed or match_delfailed:
raise MergeConfigException("Failed merge config: "
+ output_loadcmd)
else:
raise MergeConfigException("config file is not found")
elif config is not None:
self._new_config = config
if not filename and not config:
raise MergeConfigException('filename or config param must be provided.')
if filename is None:
temp_file = tempfile.NamedTemporaryFile()
temp_file.write(config)
temp_file.flush()
cfg_filename = temp_file.name
else:
raise MergeConfigException("no configuration found")
cfg_filename = filename
if os.path.exists(cfg_filename) is True:
with open(cfg_filename) as f:
self.device.send_command("cp "+self._BOOT_FILENAME+" "
+ self._BACKUP_FILENAME)
self._new_config = f.read()
cfg = [x for x in self._new_config.split("\n") if x]
output_loadcmd = self.device.send_config_set(cfg)
match_setfailed = re.findall("Delete failed", output_loadcmd)
match_delfailed = re.findall("Set failed", output_loadcmd)
if match_setfailed or match_delfailed:
raise MergeConfigException("Failed merge config: "
+ output_loadcmd)
else:
raise MergeConfigException("config file is not found")
def discard_config(self):
self.device.exit_config_mode()
@@ -181,9 +203,18 @@ class VyOSDriver(NetworkDriver):
diff = ''.join(output_compare.splitlines(True)[1:-1])
return diff
def commit_config(self):
if self.device.commit():
self.device.send_config_set(['save'])
def commit_config(self, message=""):
if message:
raise NotImplementedError(
"Commit message not implemented for this platform"
)
try:
self.device.commit()
except ValueError:
raise CommitError("Failed to commit config on the device")
self.device.send_config_set(['save'])
self.device.exit_config_mode()
def rollback(self):
@@ -277,7 +308,7 @@ class VyOSDriver(NetworkDriver):
output_iface = self.device.send_command("show interfaces")
# Collect all interfaces' name and status
match = re.findall("(\S+)\s+[:\-\d/\.]+\s+([uAD])/([uAD])", output_iface)
match = re.findall(r"(\S+)\s+[:\-\d/\.]+\s+([uAD])/([uAD])", output_iface)
# 'match' example:
# [("br0", "u", "D"), ("eth0", "u", "u"), ("eth1", "u", "u")...]
@@ -296,17 +327,12 @@ class VyOSDriver(NetworkDriver):
ifaces_detail = config["interfaces"][iface_type]
for iface_name in ifaces_detail:
description = self._get_value("description", ifaces_detail[iface_name])
if description is None:
description = ""
speed = self._get_value("speed", ifaces_detail[iface_name])
if speed is None:
speed = 0
details = ifaces_detail[iface_name]
description = details.get("description", "")
speed = details.get("speed", "0")
if speed == "auto":
speed = 0
hw_id = self._get_value("hw-id", ifaces_detail[iface_name])
if hw_id is None:
hw_id = "00:00:00:00:00:00"
hw_id = details.get("hw-id", "00:00:00:00:00:00")
is_up = (iface_state[iface_name]["Link"] == "u")
is_enabled = (iface_state[iface_name]["State"] == "u")
@@ -315,23 +341,17 @@ class VyOSDriver(NetworkDriver):
iface_name: {
"is_up": bool(is_up),
"is_enabled": bool(is_enabled),
"description": py23_compat.text_type(description),
"description": description,
"last_flapped": float(-1),
"mtu": -1,
"speed": int(speed),
"mac_address": py23_compat.text_type(hw_id)
"mac_address": hw_id,
}
})
return iface_dict
@staticmethod
def _get_value(key, target_dict):
if key in target_dict:
return target_dict[key]
else:
return None
def get_arp_table(self):
def get_arp_table(self, vrf=""):
# 'age' is not implemented yet
"""
@@ -343,6 +363,12 @@ class VyOSDriver(NetworkDriver):
10.129.2.97 ether 00:50:56:9f:64:09 C eth0
192.168.1.3 ether 00:50:56:86:7b:06 C eth1
"""
if vrf:
raise NotImplementedError(
"VRF support has not been added for this getter on this platform."
)
output = self.device.send_command("show arp")
output = output.split("\n")
@@ -357,16 +383,16 @@ class VyOSDriver(NetworkDriver):
# ["10.129.2.254", "ether", "00:50:56:97:af:b1", "C", "eth0"]
# [u'10.0.12.33', u'(incomplete)', u'eth1']
if "incomplete" in line[1]:
macaddr = py23_compat.text_type("00:00:00:00:00:00")
macaddr = "00:00:00:00:00:00"
else:
macaddr = py23_compat.text_type(line[2])
macaddr = line[2]
arp_table.append(
{
'interface': py23_compat.text_type(line[-1]),
'interface': line[-1],
'mac': macaddr,
'ip': py23_compat.text_type(line[0]),
'age': 0.0
'ip': line[0],
'age': 0.0,
}
)
@@ -394,23 +420,23 @@ class VyOSDriver(NetworkDriver):
# 'remote' contains '*' if the machine synchronized with NTP server
synchronized = "*" in remote
match = re.search("(\d+\.\d+\.\d+\.\d+)", remote)
match = re.search(r"(\d+\.\d+\.\d+\.\d+)", remote)
ip = match.group(1)
when = when if when != '-' else 0
ntp_stats.append({
"remote": py23_compat.text_type(ip),
"referenceid": py23_compat.text_type(refid),
"remote": ip,
"referenceid": refid,
"synchronized": bool(synchronized),
"stratum": int(st),
"type": py23_compat.text_type(t),
"when": py23_compat.text_type(when),
"type": t,
"when": when,
"hostpoll": int(hostpoll),
"reachability": int(reachability),
"delay": float(delay),
"offset": float(offset),
"jitter": float(jitter)
"jitter": float(jitter),
})
return ntp_stats
@@ -422,9 +448,9 @@ class VyOSDriver(NetworkDriver):
for line in output_peers:
if len(line) > 0:
match = re.search("(\d+\.\d+\.\d+\.\d+)\s+", line)
match = re.search(r"(\d+\.\d+\.\d+\.\d+)\s+", line)
ntp_peers.update({
py23_compat.text_type(match.group(1)): {}
match.group(1): {}
})
return ntp_peers
@@ -448,11 +474,11 @@ class VyOSDriver(NetworkDriver):
output = self.device.send_command("show ip bgp summary")
output = output.split("\n")
match = re.search(".* router identifier (\d+\.\d+\.\d+\.\d+), local AS number (\d+)",
match = re.search(r".* router identifier (\d+\.\d+\.\d+\.\d+), local AS number (\d+)",
output[0])
if not match:
return {}
router_id = py23_compat.text_type(match.group(1))
router_id = match.group(1)
local_as = int(match.group(2))
bgp_neighbor_data = dict()
@@ -461,7 +487,7 @@ class VyOSDriver(NetworkDriver):
bgp_neighbor_data["global"]["peers"] = {}
# delete the header and empty element
bgp_info = [i.strip() for i in output[6:-2] if i is not ""]
bgp_info = [i.strip() for i in output[6:-2] if i]
for i in bgp_info:
if len(i) > 0:
@@ -477,6 +503,8 @@ class VyOSDriver(NetworkDriver):
received_prefixes = int(state_prefix)
is_up = True
except ValueError:
state_prefix = -1
received_prefixes = -1
is_up = False
if bgp_version == "4":
@@ -498,19 +526,19 @@ class VyOSDriver(NetworkDriver):
"""
bgp_detail = self.device.send_command("show ip bgp neighbors %s" % peer_id)
match_rid = re.search("remote router ID (\d+\.\d+\.\d+\.\d+).*", bgp_detail)
match_rid = re.search(r"remote router ID (\d+\.\d+\.\d+\.\d+).*", bgp_detail)
remote_rid = match_rid.group(1)
match_prefix_accepted = re.search("(\d+) accepted prefixes", bgp_detail)
match_prefix_accepted = re.search(r"(\d+) accepted prefixes", bgp_detail)
accepted_prefixes = match_prefix_accepted.group(1)
bgp_neighbor_data["global"]["peers"].setdefault(peer_id, {})
peer_dict = {
"description": py23_compat.text_type(""),
"description": "",
"is_enabled": bool(is_enabled),
"local_as": int(local_as),
"is_up": bool(is_up),
"remote_id": py23_compat.text_type(remote_rid),
"remote_id": remote_rid,
"uptime": int(self._bgp_time_conversion(up_time)),
"remote_as": int(remote_as)
}
@@ -534,19 +562,19 @@ class VyOSDriver(NetworkDriver):
return -1
else:
if "y" in bgp_uptime:
match = re.search("(\d+)(\w)(\d+)(\w)(\d+)(\w)", bgp_uptime)
match = re.search(r"(\d+)(\w)(\d+)(\w)(\d+)(\w)", bgp_uptime)
uptime = ((int(match.group(1)) * self._YEAR_SECONDS) +
(int(match.group(3)) * self._WEEK_SECONDS) +
(int(match.group(5)) * self._DAY_SECONDS))
return uptime
elif "w" in bgp_uptime:
match = re.search("(\d+)(\w)(\d+)(\w)(\d+)(\w)", bgp_uptime)
match = re.search(r"(\d+)(\w)(\d+)(\w)(\d+)(\w)", bgp_uptime)
uptime = ((int(match.group(1)) * self._WEEK_SECONDS) +
(int(match.group(3)) * self._DAY_SECONDS) +
(int(match.group(5)) * self._HOUR_SECONDS))
return uptime
elif "d" in bgp_uptime:
match = re.search("(\d+)(\w)(\d+)(\w)(\d+)(\w)", bgp_uptime)
match = re.search(r"(\d+)(\w)(\d+)(\w)(\d+)(\w)", bgp_uptime)
uptime = ((int(match.group(1)) * self._DAY_SECONDS) +
(int(match.group(3)) * self._HOUR_SECONDS) +
(int(match.group(5)) * self._MINUTE_SECONDS))
@@ -557,6 +585,29 @@ class VyOSDriver(NetworkDriver):
(minutes * self._MINUTE_SECONDS) + seconds)
return uptime
def get_lldp_neighbors(self):
# Multiple neighbors per port are not implemented
# The show lldp neighbors commands lists port descriptions, not IDs
output = self.device.send_command("show lldp neighbors detail")
pattern = r'''(?s)Interface: +(?P<interface>\S+), [^\n]+
.+?
+SysName: +(?P<hostname>\S+)
.+?
+PortID: +ifname (?P<port>\S+)'''
def _get_interface(match):
return [
{
'hostname': match.group('hostname'),
'port': match.group('port'),
}
]
return {
match.group('interface'): _get_interface(match)
for match in re.finditer(pattern, output)
}
def get_interfaces_counters(self):
# 'rx_unicast_packet', 'rx_broadcast_packets', 'tx_unicast_packets',
# 'tx_multicast_packets' and 'tx_broadcast_packets' are not implemented yet
@@ -573,9 +624,9 @@ class VyOSDriver(NetworkDriver):
32776498 279273 0 0 0 0
"""
output = self.device.send_command("show interfaces detail")
interfaces = re.findall("(\S+): <.*", output)
interfaces = re.findall(r"(\S+): <.*", output)
# count = re.findall("(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+", output)
count = re.findall("(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)", output)
count = re.findall(r"(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)", output)
counters = dict()
j = 0
@@ -623,15 +674,15 @@ class VyOSDriver(NetworkDriver):
for i in config["service"]["snmp"]["community"]:
snmp["community"].update({
i: {
"acl": py23_compat.text_type(""),
"mode": py23_compat.text_type(config["service"]["snmp"]["community"][i]["authorization"])
"acl": "",
"mode": config["service"]["snmp"]["community"][i]["authorization"],
}
})
snmp.update({
"chassis_id": py23_compat.text_type(""),
"contact": py23_compat.text_type(config["service"]["snmp"]["contact"]),
"location": py23_compat.text_type(config["service"]["snmp"]["location"])
"chassis_id": "",
"contact": config["service"]["snmp"]["contact"],
"location": config["service"]["snmp"]["location"],
})
return snmp
@@ -673,13 +724,13 @@ class VyOSDriver(NetworkDriver):
facts = {
"uptime": int(uptime),
"vendor": py23_compat.text_type("VyOS"),
"os_version": py23_compat.text_type(version),
"serial_number": py23_compat.text_type(snumber),
"model": py23_compat.text_type(hwmodel),
"hostname": py23_compat.text_type(hostname),
"fqdn": py23_compat.text_type(fqdn),
"interface_list": iface_list
"vendor": "VyOS",
"os_version": version,
"serial_number": snumber,
"model": hwmodel,
"hostname": hostname,
"fqdn": fqdn,
"interface_list": iface_list,
}
return facts
@@ -782,7 +833,14 @@ class VyOSDriver(NetworkDriver):
return user_auth
def ping(self, destination, source='', ttl=255, timeout=2, size=100, count=5):
def ping(self,
destination,
source=C.PING_SOURCE,
ttl=C.PING_TTL,
timeout=C.PING_TIMEOUT,
size=C.PING_SIZE,
count=C.PING_COUNT,
vrf=C.PING_VRF):
# does not support multiple destination yet
deadline = timeout * count
@@ -803,7 +861,7 @@ class VyOSDriver(NetworkDriver):
else:
err = ""
if err is not "":
if err:
ping_result["error"] = err
else:
# 'packet_info' example:
@@ -831,7 +889,7 @@ class VyOSDriver(NetworkDriver):
else:
rtt_info = rtt_info[-2]
match = re.search("([\d\.]+)/([\d\.]+)/([\d\.]+)/([\d\.]+)", rtt_info)
match = re.search(r"([\d\.]+)/([\d\.]+)/([\d\.]+)/([\d\.]+)", rtt_info)
if match is not None:
rtt_min = float(match.group(1))

View File

@@ -1,4 +1,3 @@
future
coveralls
pytest
pytest-cov

View File

@@ -1,4 +1,4 @@
napalm_base
napalm>=3.0
paramiko
netmiko>=1.1.0
netmiko>=3.1.0
vyattaconfparser

View File

@@ -1,30 +1,32 @@
"""setup.py file."""
import uuid
from setuptools import setup, find_packages
from pip.req import parse_requirements
with open("requirements.txt", "r") as fs:
reqs = [r for r in fs.read().splitlines()
if (len(r) > 0 and not r.startswith("#"))]
__author__ = 'Piotr Pieprzycki <piotr.pieprzycki@dreamlab.pl>'
install_reqs = parse_requirements('requirements.txt', session=uuid.uuid1())
reqs = [str(ir.req) for ir in install_reqs]
setup(
name="napalm-vyos",
version="0.1.2",
version="0.2.0",
packages=find_packages(),
author="Piotr Pieprzycki",
author_email="piotr.pieprzycki@dreamlab.pl",
description="Network Automation and Programmability Abstraction Layer with Multivendor support",
classifiers=[
'Topic :: Utilities',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Operating System :: POSIX :: Linux',
'Operating System :: MacOS',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Operating System :: POSIX :: Linux',
'Operating System :: MacOS',
],
url="https://github.com/napalm-automation-community/napalm-vyos",
include_package_data=True,
install_requires=reqs,
)

View File

@@ -15,7 +15,7 @@
import unittest
from napalm_vyos import vyos
from napalm_base.test.base import TestConfigNetworkDriver
from napalm.base.test.base import TestConfigNetworkDriver
class TestConfigVyOSDriver(unittest.TestCase, TestConfigNetworkDriver):

View File

@@ -2,10 +2,9 @@
from builtins import super
import pytest
from napalm_base.test import conftest as parent_conftest
from napalm.base.test import conftest as parent_conftest
from napalm_base.test.double import BaseTestDouble
from napalm_base.utils import py23_compat
from napalm.base.test.double import BaseTestDouble
from napalm_vyos import vyos
@@ -55,5 +54,4 @@ class FakeVyOSDevice(BaseTestDouble):
def send_command(self, command, **kwargs):
filename = '{}.text'.format(self.sanitize_text(command))
full_path = self.find_file(filename)
result = self.read_txt_file(full_path)
return py23_compat.text_type(result)
return self.read_txt_file(full_path)

View File

@@ -1 +1 @@
{"lo": {"is_enabled": true, "description": "", "last_flapped": -1.0, "is_up": true, "mac_address": "00:00:00:00:00:00", "speed": 0}, "eth1": {"is_enabled": true, "description": "", "last_flapped": -1.0, "is_up": true, "mac_address": "...", "speed": 0}, "eth0": {"is_enabled": true, "description": "", "last_flapped": -1.0, "is_up": true, "mac_address": "...", "speed": 0}}
{"lo": {"is_enabled": true, "description": "", "last_flapped": -1.0, "is_up": true, "mac_address": "00:00:00:00:00:00", "mtu": -1, "speed": 0}, "eth1": {"is_enabled": true, "description": "", "last_flapped": -1.0, "is_up": true, "mac_address": "...", "mtu": -1, "speed": 0}, "eth0": {"is_enabled": true, "description": "", "last_flapped": -1.0, "is_up": true, "mac_address": "...", "mtu": -1, "speed": 0}}

View File

@@ -0,0 +1 @@
{"eth1": [{"hostname": "branch", "port": "eth0"}], "eth2": [{"hostname": "dmz", "port": "eth0"}]}

View File

@@ -0,0 +1,69 @@
-------------------------------------------------------------------------------
LLDP neighbors:
-------------------------------------------------------------------------------
Interface: eth1, via: LLDP, RID: 2, Time: 1 day, 18:17:44
Chassis:
ChassisID: mac 52:54:00:99:84:8a
SysName: branch
SysDescr: VyOS 1.3-rolling-202005151915
MgmtIP: 10.0.0.3
Capability: Bridge, off
Capability: Router, on
Capability: Wlan, off
Capability: Station, off
Port:
PortID: ifname eth0
PortDescr: to DC
TTL: 120
PMD autoneg: supported: yes, enabled: yes
Adv: 10Base-T, HD: yes, FD: yes
Adv: 100Base-TX, HD: yes, FD: yes
MAU oper type: 100BaseTXFD - 2 pair category 5 UTP, full duplex mode
LLDP-MED:
Device Type: Network Connectivity Device
Capability: Capabilities, yes
Capability: Policy, yes
Capability: Location, yes
Capability: MDI/PSE, yes
Capability: MDI/PD, yes
Capability: Inventory, yes
Inventory:
Hardware Revision: pc-i440fx-4.2
Software Revision: 4.19.122-amd64-vyos
Firmware Revision: 1.13.0-1ubuntu1
Manufacturer: QEMU
Model: Standard PC (i440FX + PIIX, 1996
-------------------------------------------------------------------------------
Interface: eth2, via: LLDP, RID: 1, Time: 1 day, 18:17:45
Chassis:
ChassisID: mac 52:54:00:98:e5:9f
SysName: dmz
SysDescr: VyOS 1.3-rolling-202005151915
MgmtIP: 10.0.0.2
Capability: Bridge, off
Capability: Router, on
Capability: Wlan, off
Capability: Station, off
Port:
PortID: ifname eth0
PortDescr: to DC
TTL: 120
PMD autoneg: supported: yes, enabled: yes
Adv: 10Base-T, HD: yes, FD: yes
Adv: 100Base-TX, HD: yes, FD: yes
MAU oper type: 100BaseTXFD - 2 pair category 5 UTP, full duplex mode
LLDP-MED:
Device Type: Network Connectivity Device
Capability: Capabilities, yes
Capability: Policy, yes
Capability: Location, yes
Capability: MDI/PSE, yes
Capability: MDI/PD, yes
Capability: Inventory, yes
Inventory:
Hardware Revision: pc-i440fx-4.2
Software Revision: 4.19.122-amd64-vyos
Firmware Revision: 1.13.0-1ubuntu1
Manufacturer: QEMU
Model: Standard PC (i440FX + PIIX, 1996
-------------------------------------------------------------------------------

View File

@@ -1,6 +1,6 @@
"""Tests for getters."""
from napalm_base.test.getters import BaseTestGetters
from napalm.base.test.getters import BaseTestGetters
import pytest

View File

@@ -1,5 +1,5 @@
[tox]
envlist = py27,py34,py35
envlist = py36,py37,py38
[testenv]
deps =