From 47227d1cf0ef7ba7f9788e6465f7cfe7386c9944 Mon Sep 17 00:00:00 2001 From: Pieprzycki Piotr Date: Sun, 8 Apr 2018 00:23:04 +0200 Subject: [PATCH 1/6] handle config as text in load and merge functions --- napalm_vyos/vyos.py | 106 ++++++++++++++++++++++++++++---------------- 1 file changed, 67 insertions(+), 39 deletions(-) diff --git a/napalm_vyos/vyos.py b/napalm_vyos/vyos.py index 20aee55..d6560ba 100644 --- a/napalm_vyos/vyos.py +++ b/napalm_vyos/vyos.py @@ -22,6 +22,7 @@ Read napalm.readthedocs.org for more information. import re import os +import tempfile import vyattaconfparser @@ -33,8 +34,9 @@ from netmiko import SCPConn import napalm.base.constants as C from napalm.base.utils import py23_compat from napalm.base.base import NetworkDriver -from napalm.base.exceptions import ConnectionException, \ - MergeConfigException, ReplaceConfigException +from napalm.base.exceptions import ConnectionException, MergeConfigException, \ + ReplaceConfigException, CommitError, \ + CommandErrorException class VyOSDriver(NetworkDriver): @@ -121,53 +123,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 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") + def discard_config(self): self.device.exit_config_mode() @@ -183,8 +205,12 @@ class VyOSDriver(NetworkDriver): return diff def commit_config(self): - if self.device.commit(): - self.device.send_config_set(['save']) + 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): @@ -478,6 +504,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": From 5c3492f13c039895a0cec78dfcd9f176fefcea24 Mon Sep 17 00:00:00 2001 From: Pieprzycki Piotr Date: Sun, 8 Apr 2018 11:28:15 +0200 Subject: [PATCH 2/6] Update docs --- README.md | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ setup.py | 2 +- 2 files changed, 105 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 967ba27..6baa9cc 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,107 @@ [![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 + + +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 +===================== ========== + + +Other methods +------------- + +============================== ===== +_ VyOS +============================== ===== +**load_template** |yes| +**ping** |yes| +**traceroute** |no| +============================== ===== + + +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('eos') + >>> optional_args = {'my_optional_arg1': 'my_value1', 'my_optional_arg2': 'my_value2'} + >>> device = driver('192.168.76.10', 'dbarroso', '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'}` diff --git a/setup.py b/setup.py index 363bcb2..ce58990 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ reqs = [str(ir.req) for ir in install_reqs] setup( name="napalm-vyos", - version="0.1.4", + version="0.1.5", packages=find_packages(), author="Piotr Pieprzycki", author_email="piotr.pieprzycki@dreamlab.pl", From b8ec1396f7fc78b92c513e23294014d98113c714 Mon Sep 17 00:00:00 2001 From: Pieprzycki Piotr Date: Sun, 8 Apr 2018 17:56:49 +0200 Subject: [PATCH 3/6] Update docs --- README.md | 56 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 6baa9cc..3bd6f83 100644 --- a/README.md +++ b/README.md @@ -8,41 +8,45 @@ General support matrix ---------------------- - ===================== ============== - _ VyOS - ===================== ============== - **Module Name** napalm-vyos - **Driver Name** vyos - **Structured data** Yes - **Minimum version** 1.1.6 - **Backend library** `netmiko`_ - ===================== ============== + +> +---------------------+---------------+ +> | \_ | 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 -===================== ========== - +\_ VyOS + --------------------- ------ + **Config. replace** Yes + **Config. merge** Yes + **Compare config** Yes + **Atomic Changes** Yes + **Rollback** Yes + Other methods ------------- -============================== ===== -_ VyOS -============================== ===== -**load_template** |yes| -**ping** |yes| -**traceroute** |no| -============================== ===== + \_ VyOS + -------------------- ------ + **load\_template** + **ping** + **traceroute** Optional arguments ------------------ From 23fe0451677f4f6d3e83428f8d4ed9d3ebf246c2 Mon Sep 17 00:00:00 2001 From: Pieprzycki Piotr Date: Sun, 8 Apr 2018 18:09:21 +0200 Subject: [PATCH 4/6] Update docs --- README.md | 52 ++++++++++++++++++++++------------------------------ 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 3bd6f83..ad6889e 100644 --- a/README.md +++ b/README.md @@ -9,44 +9,36 @@ General support matrix ---------------------- -> +---------------------+---------------+ -> | \_ | VyOS | -> +=====================+===============+ -> | **Module Name** | > napalm-vyos | -> +---------------------+---------------+ -> | **Driver Name** | > vyos | -> +---------------------+---------------+ -> | **Structured data** | > Yes | -> +---------------------+---------------+ -> | **Minimum version** | > 1.1.6 | -> +---------------------+---------------+ -> | **Backend library** | > [netmiko] | -> +---------------------+---------------+ -> + | | 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 - +| | VyOS | +| ------------------- | ----- | +| **Config. replace** | Yes | +| **Config. merge** | Yes | +|**Compare config** | Yes | +| **Atomic Changes** | Yes | +| **Rollback** | Yes | + Other methods ------------- - - \_ VyOS - -------------------- ------ - **load\_template** - **ping** - **traceroute** + | VyOS | + | ---------------- | + |**load_template** | + |**ping** | + |**traceroute** | Optional arguments ------------------ @@ -55,9 +47,9 @@ NAPALM supports passing certain optional arguments to some drivers. To do that y :code:`optional_args` parameter when creating the object:: >>> from napalm import get_network_driver - >>> driver = get_network_driver('eos') + >>> driver = get_network_driver('vyos') >>> optional_args = {'my_optional_arg1': 'my_value1', 'my_optional_arg2': 'my_value2'} - >>> device = driver('192.168.76.10', 'dbarroso', 'this_is_not_a_secure_password', optional_args=optional_args) + >>> device = driver('192.168.76.10', 'vagrant', 'this_is_not_a_secure_password', optional_args=optional_args) >>> device.open() List of supported optional arguments From 580da0edeb4183199fb4e91a430a7ff80aba0c33 Mon Sep 17 00:00:00 2001 From: Pieprzycki Piotr Date: Sun, 8 Apr 2018 18:12:07 +0200 Subject: [PATCH 5/6] Update docs --- README.md | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index ad6889e..fd9e507 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ # napalm-vyos +Community NAPALM driver for the VyOS devices. https://vyos.io/ + General support matrix ---------------------- @@ -31,14 +33,6 @@ Configuration support matrix | **Rollback** | Yes | -Other methods -------------- - - | VyOS | - | ---------------- | - |**load_template** | - |**ping** | - |**traceroute** | Optional arguments ------------------ From 55a6b15c3e92e34c691e1f0f30287a9cfd2b7114 Mon Sep 17 00:00:00 2001 From: Pieprzycki Piotr Date: Sun, 8 Apr 2018 18:15:28 +0200 Subject: [PATCH 6/6] Update docs --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fd9e507..01be396 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,9 @@ # napalm-vyos -Community NAPALM driver for the VyOS devices. https://vyos.io/ +Community NAPALM driver for the VyOS. https://vyos.io/ + +Also it can be used for other similar systems: Vyatta or EdgeOS General support matrix