Hello community,
here is the log from the commit of package python-junos-eznc for
openSUSE:Factory checked in at 2020-06-15 20:28:05
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-junos-eznc (Old)
and /work/SRC/openSUSE:Factory/.python-junos-eznc.new.3606 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-junos-eznc"
Mon Jun 15 20:28:05 2020 rev:3 rq:811738 version:2.4.1
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-junos-eznc/python-junos-eznc.changes
2019-12-10 22:47:11.409703008 +0100
+++
/work/SRC/openSUSE:Factory/.python-junos-eznc.new.3606/python-junos-eznc.changes
2020-06-15 20:28:10.125887567 +0200
@@ -1,0 +2,83 @@
+Thu Jun 4 11:04:08 UTC 2020 - [email protected]
+
+- version update to 2.4.1
+ ## [1.4.0]
+ ### Fixed
+ - [#617] - IOS show ip ospf database router: Removed reliance on static
spacing
+ - [#620] - NXOS show fex: Allow spaces in descriptions
+ - [#621] - Juniper show arp, etc.: Account for virtual chassis output
(`{master:0}`)
+ - [#626] - ASA show vpn-sessiondb anyconnect: Require index, capture
different format style
+ - [#650] - IOS show ip ospf database network: Change to allow one or more
whitespace at the beginning of the line rather than 1 or more due to different
output
+ - [#647] - ASA show route: Allow multiline route statements
+ - [#659] - IOS show mac address-table: Allow VLAN to be non-whitespace to
allow N/A as an option
+ ### Added
+ - [#618] - IOS show ip ospf database network: New template
+ - [#619] - HP Comware display lldp neighbor information verbose: New
template
+ - [#625] - ASA show vpn-sessiondb anyconnect: New template
+ - [#628] - Cisco WLC show mobility sum: New template
+ - [#631] - ASA show vpn-sessiondb anyconnect: Account for new data for
assigned/public IP, group policy, and tunnel group
+ - [#629] - ASA show crypto ipsec sa - Add LOCAL_ADDRESS_NAME,
CURRENT_PEER_NAME, DYNAMIC_PEER_NAME, LOCAL_CRYPTO_ENDPOINT_NAME,
REMOTE_CRYPTO_ENDPOINT_NAME
+ - [#632] - ASA show nat: Added SERVICE_PROTOCOL
+ - [#635] - IOS show ip route summary: New template
+ - [#636] - ASA show vpn-sessiondb: New template
+ - [#638] - ASA show inventory: Capture PID and VID withoout serial
+ - [#637] - Cisco WLC show band select: New template
+ ## [1.4.0]
+ ### Fixed
+ - [#548] IOS show mac address-table: Account for Total Mac Addresses
+ - [#565] IOS show license: Avoid trailing spaces for features
+ - [#575] NXOS show version: Match N5K PLATFORM & LAST_REBOOT captures
split words
+ - [#574] ASA show failover: Account for new output (IPS)
+ - [#577] IOS show mac address-table: Account for Multicast Entries
+ - [#582] NXOS show interface transceiver: Remove requirement for TYPE
+ - [#585] IOS show mac address-table: Fixed ordering for TYPE2
+ - [#587] IOS show interfaces switchport: Account for Vepa Enabled and
Operational Dot1q Ethertype
+ - [#584] IOS show switch detail: Account for Mac persistency wait time
+ - [#589] EOS show ip route: Filldown for DISTANCE and METRIC - Added new
data formats for VRF and NEXT_HOP and INTERFACE
+ - [#592] Fortinet get router info bgp summary: Account for more data, fix
UP_DOWN regex from word to non-whitespace
+ - [#603] IOS show ip access-list: Update PROTOCOL to capture numbered
protocols
+ - [610] Aruba os show arp: Fix tests to have the full output from the
command and device
+ - [#608] Vyatta VyOS show interfaces: Capture IP_ADDRESS with or without
netmask
+ - [#614] IOS show interfaces status: Remove reliance on whitespaces
+ ### Added
+ - [#406] Testing: Add yamllint to test suite
+ - [#407] Testing: Add python black to test suite
+ - [#553] IOS show lldp neighbors: Added CAPABILITIES capture group
+ - [#554] IOS show logging: New template
+ - [#563] IOS show interfaces switchport: Added ADMIN_MDOE capture group
+ - [#562] ASA show logging: New template
+ - [#564] NXOS show interface transceiver: New template
+ - [#567] XR show arp: New template
+ - [#572] IOS show lldp neighbors detail: Added SERIAL capture group
+ - [#573] ASA show arp: New template
+ - [#578] Fortinet get system interface: New template
+ - [#576] Huawei VRP display lldp neighbor: New template
+ - [#581] Cisco WLC show vlan sum: New template
+ - [#580] XR show interfaces summary: New template
+ - [#590] IOS show ip bgp neighbors: New template
+ - [#591] NXOS show vdc: New template
+ - [#595] Checkpoint GAIA show arp dynamic all: New template
+ - [#593] IOS show module: New template
+ - [#597] Huwai VRP display version: New template
+ - [#602] NXOS show vrf interface: New template
+ - [#598] IOS show running-config partition access list: Added TCP_FLAG
capture group
+ - [#598] IOS show running-config partition access list: Convert COMMENT to
list
+ - [#598] IOS show running-config partition access list: Update PROTOCOL to
include numbered protocols
+ - [#596] XR admin show environment power: New template
+ - [#594] Aruba os show arp: New template
+ - [#605] SG300 show version: New template
+ - [#604] NXOS show vlan: Added INTERFACES capture group, Require VLAN_ID
+ - [#600] IOS show mpls interfaces: New template
+ - [#599] IOS show etherchannel summary: New template
+ - [#611] NXOS show interface: Added MODE capture group
+ - [#612] NXOS show interfaces switchport: Added ACCESS_VLAN_NAME and
NATIVE_VLAN_NAME capture groups
+ - [#609] HP Comware display ip interface: New template
+ - [#606] IOS show ip ospf database router: New template
+ ### Changed
+ - [#406] Helpers: Added development_helpers cli utility to replace
existing helpers
+- python3 package only, as ntc-templates is python3 only
+- added patches
+ https://github.com/Juniper/py-junos-eznc/pull/1040
+ + python-junos-eznc-no-unittest2.patch
+
+-------------------------------------------------------------------
Old:
----
python-junos-eznc-2.3.1.tar.gz
New:
----
python-junos-eznc-2.4.1.tar.gz
python-junos-eznc-no-unittest2.patch
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-junos-eznc.spec ++++++
--- /var/tmp/diff_new_pack.B02tZm/_old 2020-06-15 20:28:11.173891198 +0200
+++ /var/tmp/diff_new_pack.B02tZm/_new 2020-06-15 20:28:11.173891198 +0200
@@ -1,7 +1,7 @@
#
# spec file for package python-junos-eznc
#
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2020 SUSE LLC
# Copyright (c) 2017, Martin Hauke <[email protected]>
#
# All modifications and additions to the file contributed by third parties
@@ -18,13 +18,16 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
+%define skip_python2 1
Name: python-junos-eznc
-Version: 2.3.1
+Version: 2.4.1
Release: 0
Summary: Junos 'EZ' automation for non-programmers
License: Apache-2.0
URL: https://www.github.com/Juniper/py-junos-eznc
Source:
https://github.com/Juniper/py-junos-eznc/archive/%{version}.tar.gz#/%{name}-%{version}.tar.gz
+# https://github.com/Juniper/py-junos-eznc/pull/1040
+Patch0: python-junos-eznc-no-unittest2.patch
BuildRequires: %{python_module Jinja2 >= 2.7.1}
BuildRequires: %{python_module PyYAML >= 5.1}
BuildRequires: %{python_module lxml >= 3.2.4}
@@ -32,6 +35,7 @@
BuildRequires: %{python_module ncclient >= 0.6.3}
BuildRequires: %{python_module netaddr}
BuildRequires: %{python_module nose}
+BuildRequires: %{python_module ntc-templates}
BuildRequires: %{python_module paramiko >= 1.15.2}
BuildRequires: %{python_module pyparsing}
BuildRequires: %{python_module pyserial}
@@ -40,7 +44,6 @@
BuildRequires: %{python_module setuptools}
BuildRequires: %{python_module six}
BuildRequires: %{python_module transitions}
-BuildRequires: %{python_module unittest2 >= 0.5.1}
BuildRequires: fdupes
BuildRequires: python-rpm-macros
Requires: python-Jinja2 >= 2.7.1
@@ -48,6 +51,7 @@
Requires: python-lxml >= 3.2.4
Requires: python-ncclient >= 0.6.3
Requires: python-netaddr
+Requires: python-ntc-templates
Requires: python-paramiko >= 1.15.2
Requires: python-pyparsing
Requires: python-pyserial
@@ -72,6 +76,7 @@
%prep
%setup -q -n py-junos-eznc-%{version}
+%patch0 -p1
sed -i -e '/yamlordereddictloader/d' requirements.txt
# requires deprecated and not working yamlordereddictloader
rm tests/unit/factory/test_cmdtable.py
++++++ python-junos-eznc-2.3.1.tar.gz -> python-junos-eznc-2.4.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py-junos-eznc-2.3.1/.travis.yml
new/py-junos-eznc-2.4.1/.travis.yml
--- old/py-junos-eznc-2.3.1/.travis.yml 2019-12-10 07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/.travis.yml 2020-04-29 18:00:59.000000000 +0200
@@ -3,17 +3,22 @@
include:
- python: 2.7
dist: trusty
- sudo: false
- python: 3.5
dist: trusty
- sudo: false
- python: 3.6
dist: trusty
- sudo: false
- python: 3.7
dist: xenial
- sudo: true
-
+ - python: 3.8
+ dist: xenial
+ - os: windows
+ language: shell
+ python: 3.7
+ before_install:
+ - choco install python3 --version=3.7.4
+ env:
+ - PATH=/c/Python37:/c/Python37/Scripts:$PATH
+ - TRAVIS_PYTHON_VERSION=3.7
addons:
apt:
packages:
@@ -24,7 +29,7 @@
install:
- "pip install -r development.txt"
- "pip install -r requirements.txt"
- - "pip install -U
git+https://github.com/vnitinv/ncclient.git@junos-sax-parser"
+ - "pip install ."
script: nosetests -v --with-coverage --cover-package=jnpr.junos
--cover-inclusive -a unit
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py-junos-eznc-2.3.1/README.md
new/py-junos-eznc-2.4.1/README.md
--- old/py-junos-eznc-2.3.1/README.md 2019-12-10 07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/README.md 2020-04-29 18:00:59.000000000 +0200
@@ -140,6 +140,8 @@
[Nitin Kumar](https://github.com/vnitinv), [Stacy
Smith](https://github.com/stacywsmith), [Stephen
Steiner](https://github.com/ntwrkguru)
+* v2.4.1: [Nitin Kumar](https://github.com/vnitinv)
+* v2.4.0: [Nitin Kumar](https://github.com/vnitinv)
* v2.3.0: [Nitin Kumar](https://github.com/vnitinv), [Raja Shekar
Mekala](https://github.com/rsmekala), [Dinesh
Babu](https://github.com/dineshbaburam91), [Chris
Jenn](https://github.com/ipmonk), [Shigechika](https://github.com/shigechika)
* v2.2.1: [Nitin Kumar](https://github.com/vnitinv), [Raja Shekar
Mekala](https://github.com/rsmekala), [Dinesh
Babu](https://github.com/dineshbaburam91), [Marcel
Wiget](https://github.com/mwiget), [John Tishey](https://github.com/jtishey),
[Alex Carp](https://github.com/carpalex), [Cory
Councilman](https://github.com/dragonballbw3)
* v2.2.0: [Nitin Kumar](https://github.com/vnitinv), [Raja Shekar
Mekala](https://github.com/rsmekala), [Marek](https://github.com/mzbroch),
[Marcel Wiget](https://github.com/mwiget)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py-junos-eznc-2.3.1/RELEASE-NOTES.md
new/py-junos-eznc-2.4.1/RELEASE-NOTES.md
--- old/py-junos-eznc-2.3.1/RELEASE-NOTES.md 2019-12-10 07:54:12.000000000
+0100
+++ new/py-junos-eznc-2.4.1/RELEASE-NOTES.md 2020-04-29 18:00:59.000000000
+0200
@@ -1,3 +1,28 @@
+## Release 2.4.1 - 29 APRIL 2020
+### Features Added
+- None
+
+### Bugs fixed:
+- Latest `textfsm` doesn’t support in windows. Hence, supporting `textfsm
0.4.1` for windows user #1019
+- Convert `port` argument when passed as `str` to `int` data type #1020
+- Return type of `sw.install` function going to change in the upcoming major
release.
+ So, added a deprecation warning in `sw.install` #1025
+
+## Release 2.4.0 - 1 APRIL 2020
+### Features Added
+- Added TableView Null Key support #983
+- Added timeout support for commit_check() #998
+- Added Win serial COM support #1000
+- Added load patch support #1001
+- Added textfsm support for table/view #1009
+
+### Bugs fixed:
+- Fixed table/view issue w.r.t to get() call #981
+- Fixed documentation typo #986
+- Handled sax parser input for nested fields #997
+- Fixed outbound ssh issue #1007
+- Fixed xpath issue when defined with a string function #1008
+
## Release 2.3.1 - 10 December 2019
### Features Added
- None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py-junos-eznc-2.3.1/lib/jnpr/junos/console.py
new/py-junos-eznc-2.4.1/lib/jnpr/junos/console.py
--- old/py-junos-eznc-2.3.1/lib/jnpr/junos/console.py 2019-12-10
07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/lib/jnpr/junos/console.py 2020-04-29
18:00:59.000000000 +0200
@@ -133,6 +133,7 @@
self.junos_dev_handler = JunosDeviceHandler(
device_params={'name': 'junos',
'local': False})
+ self._conn = None
self._j2ldr = _Jinja2ldr
if self._fact_style == 'old':
self.facts = self.ofacts
@@ -237,6 +238,7 @@
logger.info('facts: retrieving device facts...')
self.facts_refresh()
self.results['facts'] = self.facts
+ self._conn = self._tty
return self
def close(self, skip_logout=False):
@@ -333,7 +335,7 @@
# -----------------------------------------------------------------------
def __enter__(self):
- self._conn = self.open()
+ self.open()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py-junos-eznc-2.3.1/lib/jnpr/junos/device.py
new/py-junos-eznc-2.4.1/lib/jnpr/junos/device.py
--- old/py-junos-eznc-2.3.1/lib/jnpr/junos/device.py 2019-12-10
07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/lib/jnpr/junos/device.py 2020-04-29
18:00:59.000000000 +0200
@@ -428,7 +428,6 @@
with open(sshconf_path, 'r') as fp:
sshconf.parse(fp)
found = sshconf.lookup(self._hostname)
- self._hostname = found.get('hostname', self._hostname)
self._port = found.get('port', self._port)
self._conf_auth_user = found.get('user')
self._conf_ssh_private_key_file = found.get('identityfile')
@@ -458,6 +457,8 @@
encode = None if sys.version < '3' else 'unicode'
return etree.tostring(rsp[0], encoding=encode)
return rsp[0]
+ except TypeError:
+ return "No RPC equivalent found for: " + command
except:
return "invalid command: " + command
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/py-junos-eznc-2.3.1/lib/jnpr/junos/factory/cmdtable.py
new/py-junos-eznc-2.4.1/lib/jnpr/junos/factory/cmdtable.py
--- old/py-junos-eznc-2.3.1/lib/jnpr/junos/factory/cmdtable.py 2019-12-10
07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/lib/jnpr/junos/factory/cmdtable.py 2020-04-29
18:00:59.000000000 +0200
@@ -2,37 +2,44 @@
import copy
#
https://stackoverflow.com/questions/5121931/in-python-how-can-you-load-yaml-mappings-as-ordereddicts
+# stdlib
+import os
+from inspect import isclass
+from lxml import etree
+import json
+
# local
from jnpr.junos.exception import RpcError
from jnpr.junos.utils.start_shell import StartShell
from jnpr.junos.factory.state_machine import StateMachine
from jnpr.junos.factory.to_json import TableJSONEncoder
-# stdlib
-from inspect import isclass
-from lxml import etree
-
-import json
-
from jinja2 import Template
+from ntc_templates import parse as ntc_parse
+
+import logging
+logger = logging.getLogger("jnpr.junos.factory.cmdtable")
class CMDTable(object):
- def __init__(self, dev=None, output=None, path=None):
+ def __init__(self, dev=None, raw=None, path=None, template_dir=None):
"""
:dev: Device instance
- :output: string blob of the command output
+ :raw: string blob of the command output
:path: file path to XML, to be used rather than :dev:
+ :template_dir: To look for textfsm templates in this folder first
"""
self._dev = dev
- self.xml = output
+ self.xml = None
self.view = None
self.ITEM_FILTER = 'name'
self._key_list = []
self._path = path
self._parser = None
self.output = None
+ self.data = raw
+ self.template_dir = template_dir
# -------------------------------------------------------------------------
# PUBLIC METHODS
@@ -69,6 +76,8 @@
"""
self._clearkeys()
+ if self._path and self.data:
+ raise AttributeError('path and data are mutually exclusive')
if self._path is not None:
# for loading from local file-path
with open(self._path, 'r') as fp:
@@ -76,9 +85,6 @@
if self.data.startswith('<output>') and self.data.endswith(
'</output>'):
self.data = etree.fromstring(self.data).text
- sm = StateMachine(self)
- self.output = sm.parse(self.data.splitlines())
- return self
if 'target' in kvargs:
self.TARGET = kvargs['target']
@@ -95,54 +101,60 @@
str) else \
kvargs['filters']
+ cmd_args = self.CMD_ARGS.copy()
if 'args' in kvargs and isinstance(kvargs['args'], dict):
- self.CMD_ARGS.update(kvargs['args'])
+ cmd_args.update(kvargs['args'])
- if len(self.CMD_ARGS) > 0:
- self.GET_CMD = Template(self.GET_CMD).render(**self.CMD_ARGS)
+ if len(cmd_args) > 0:
+ self.GET_CMD = Template(self.GET_CMD).render(**cmd_args)
- # execute the Junos RPC to retrieve the table
- if hasattr(self, 'TARGET'):
- if self.TARGET is None:
- raise ValueError('"target" value not provided')
- rpc_args = {'target': self.TARGET, 'command': self.GET_CMD,
- 'timeout': '0'}
- try:
- self.xml = getattr(self.RPC, 'request_pfe_execute')(**rpc_args)
+ if self.data is None:
+ # execute the Junos RPC to retrieve the table
+ if hasattr(self, 'TARGET'):
+ if self.TARGET is None:
+ raise ValueError('"target" value not provided')
+ rpc_args = {'target': self.TARGET, 'command': self.GET_CMD,
+ 'timeout': '0'}
+ try:
+ self.xml = getattr(self.RPC,
'request_pfe_execute')(**rpc_args)
+ self.data = self.xml.text
+ ver_info = self._dev.facts.get('version_info')
+ if ver_info and ver_info.major[0] <= 15:
+ # Junos <=15.x output has output something like below
+ #
+ # <rpc-reply>
+ # <output>
+ # SENT: Ukern command: show memory
+ # GOT:
+ # GOT: ID Base Total(b) Free(b)
Used(b)
+ # GOT: -- -------- --------- ---------
---------
+ # GOT: 0 44e72078 1882774284 1689527364
193246920
+ # GOT: 1 b51ffb88 67108860 57651900
9456960
+ # GOT: 2 bcdfffe0 52428784 52428784
0
+ # GOT: 3 b91ffb88 62914556 62914556
0
+ # LOCAL: End of file
+ # </output>
+ # </rpc-reply>
+ # hence need to do cleanup
+ self.data = self.data.replace("GOT: ", "")
+ except RpcError:
+ with StartShell(self.D) as ss:
+ ret = ss.run('cprod -A %s -c "%s"' % (self.TARGET,
+ self.GET_CMD))
+ if ret[0]:
+ self.data = ret[1]
+ else:
+ self.xml = self.RPC.cli(self.GET_CMD)
self.data = self.xml.text
- ver_info = self._dev.facts.get('version_info')
- if ver_info and ver_info.major[0] <= 15:
- # Junos <=15.x output has output something like below
- #
- # <rpc-reply>
- # <output>
- # SENT: Ukern command: show memory
- # GOT:
- # GOT: ID Base Total(b) Free(b) Used(b)
- # GOT: -- -------- --------- --------- ---------
- # GOT: 0 44e72078 1882774284 1689527364 193246920
- # GOT: 1 b51ffb88 67108860 57651900 9456960
- # GOT: 2 bcdfffe0 52428784 52428784 0
- # GOT: 3 b91ffb88 62914556 62914556 0
- # LOCAL: End of file
- # </output>
- # </rpc-reply>
- # hence need to do cleanup
- self.data = self.data.replace("GOT: ", "")
- except RpcError:
- with StartShell(self.D) as ss:
- ret = ss.run('cprod -A %s -c "%s"' % (self.TARGET,
- self.GET_CMD))
- if ret[0]:
- self.data = ret[1]
- else:
- self.xml = self.RPC.cli(self.GET_CMD)
- self.data = self.xml.text
- # state machine
- sm = StateMachine(self)
-
- self.output = sm.parse(self.data.splitlines())
+ if self.USE_TEXTFSM:
+ self.output = self._parse_textfsm(platform=self.PLATFORM,
+ command=self.GET_CMD,
+ raw=self.data)
+ else:
+ # state machine
+ sm = StateMachine(self)
+ self.output = sm.parse(self.data.splitlines())
# returning self for call-chaining purposes, yo!
return self
@@ -296,3 +308,112 @@
def __contains__(self, key):
""" membership for use with 'in' """
return bool(key in self.keys())
+
+ # ------------------------------------------------------------------------
+ # textfsm
+ # ------------------------------------------------------------------------
+
+ def _parse_textfsm(self, platform=None, command=None, raw=None):
+ """
+ textfsm returns list of dict, make it JSON/dict
+
+ :param platform: vendor platform, for ex cisco_xr
+ :param command: cli command to be parsed
+ :param raw: string blob output from the cli command execution
+ :return: dict of parsed data.
+ """
+ attrs = dict(
+ Command=command,
+ Platform=platform
+ )
+
+ template = None
+ template_dir = None
+ if self.template_dir is not None:
+ # we dont need index file for lookup
+ index = None
+ template_path = os.path.join(self.template_dir,
+ '{}_{}.textfsm'.format(
+ platform,
+ '_'.join(command.split())))
+ if not os.path.exists(template_path):
+ msg = 'Template file %s missing' % template_path
+ logger.error(msg)
+ raise FileNotFoundError(msg)
+ else:
+ template = template_path
+ template_dir = self.template_dir
+ if template_dir is None:
+ index = 'index'
+ template_dir = ntc_parse._get_template_dir()
+
+ cli_table = ntc_parse.clitable.CliTable(index, template_dir)
+ try:
+ cli_table.ParseCmd(raw, attrs, template)
+ except ntc_parse.clitable.CliTableError as ex:
+ logger.error('Unable to parse command "%s" on platform %s' % (
+ command, platform))
+ raise ex
+ return self._filter_output(cli_table)
+
+ def _filter_output(self, cli_table):
+ """
+ textfsm return list of list, covert it into more consumable format
+
+ :param cli_table: CLiTable object from textfsm
+ :return: dict of key, fields and its values, list of dict when key is
None
+ """
+ self._set_key(cli_table)
+
+ fields = self.VIEW.FIELDS if self.VIEW is not None else {}
+ reverse_fields = {val: key for key, val in fields.items()}
+ if self.KEY is None:
+ cli_table_size = cli_table.size
+ if cli_table_size > 1:
+ raise KeyError("Key is Mandatory for parsed o/p of %s "
+ "length" % cli_table_size)
+ elif cli_table_size == 1:
+ temp_dict = self._parse_row(cli_table[1], cli_table,
+ reverse_fields)
+ logger.debug("For Null Key, data returned:
{}".format(temp_dict))
+ return temp_dict
+ output = {}
+ for row in cli_table:
+ temp_dict = self._parse_row(row, cli_table, reverse_fields)
+ logger.debug("data at index {} is {}".format(row.row, temp_dict))
+ if self.KEY in temp_dict:
+ if self.KEY not in fields:
+ output[temp_dict.pop(self.KEY)] = temp_dict
+ else:
+ output[temp_dict[self.KEY]] = temp_dict
+ else:
+ logger.debug("Key {} not present in {}".format(self.KEY,
+ temp_dict))
+ return output
+
+ def _parse_row(self, row, cli_table, reverse_fields):
+ temp_dict = {}
+ for index, element in enumerate(row):
+ key = cli_table.header[index]
+ if self.KEY and key in self.KEY:
+ temp_dict[key] = element
+ if reverse_fields:
+ if key in reverse_fields:
+ temp_dict[reverse_fields[key]] = element
+ else:
+ temp_dict[key] = element
+ return temp_dict
+
+ def _set_key(self, cli_table):
+ """
+ Preference to user provided key, then template and at last default
+ Checks and update if we need KEY from template file
+
+ :param cli_table: CLiTable object from textfsm
+ :return:
+ """
+ if self.KEY == 'name' and len(cli_table._keys) > 0:
+ template_keys = list(cli_table._keys)
+ self.KEY = template_keys[0] if len(template_keys) == 1 else \
+ template_keys
+ logger.debug("KEY being used: {}".format(self.KEY))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/py-junos-eznc-2.3.1/lib/jnpr/junos/factory/factory_cls.py
new/py-junos-eznc-2.4.1/lib/jnpr/junos/factory/factory_cls.py
--- old/py-junos-eznc-2.3.1/lib/jnpr/junos/factory/factory_cls.py
2019-12-10 07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/lib/jnpr/junos/factory/factory_cls.py
2020-04-29 18:00:59.000000000 +0200
@@ -45,9 +45,8 @@
def FactoryCMDTable(cmd, args=None, item=None, key_items=None,
key='name', view=None, table_name=None, title=None,
- delimiter=None, eval=None, **kwargs):
- # if table_name is None:
- # table_name = "CMDTable." + cmd
+ delimiter=None, eval=None, platform='juniper_junos',
use_textfsm=False,
+ **kwargs):
new_cls = type(table_name, (CMDTable,), {})
new_cls.GET_CMD = cmd
if 'target' in kwargs:
@@ -60,6 +59,8 @@
new_cls.TITLE = title
new_cls.DELIMITER = delimiter
new_cls.EVAL = eval
+ new_cls.PLATFORM = platform
+ new_cls.USE_TEXTFSM = use_textfsm
new_cls.__module__ = __name__.replace('factory_cls', 'CMDTable')
return new_cls
@@ -67,8 +68,6 @@
def FactoryCMDChildTable(title=None, regex=None,
key='name', delimiter=None, table_name=None,
view=None,
key_items=None, item=None, eval=None):
- # if table_name is None:
- # table_name = "CMDTable." + title
new_cls = type(table_name, (CMDTable,), {})
new_cls.DELIMITER = delimiter
new_cls.KEY = key
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/py-junos-eznc-2.3.1/lib/jnpr/junos/factory/factory_loader.py
new/py-junos-eznc-2.4.1/lib/jnpr/junos/factory/factory_loader.py
--- old/py-junos-eznc-2.3.1/lib/jnpr/junos/factory/factory_loader.py
2019-12-10 07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/lib/jnpr/junos/factory/factory_loader.py
2020-04-29 18:00:59.000000000 +0200
@@ -176,31 +176,14 @@
def _add_cmd_view_fields(self, view_dict, fields_name, fields):
""" add a group of fields to the view """
fields_dict = view_dict[fields_name]
- # try:
- # # see if this is a 'fields_<group>' collection, and if so
- # # then we automatically setup using the group mechanism
- # mark = fields_name.index('_')
- # group = {'group': fields_name[mark + 1:]}
- # except:
- # # otherwise, no group, just standard 'fields'
- # group = {}
-
for f_name, f_data in fields_dict.items():
- # each field could have its own unique set of properties
- # so create a kvargs <dict> each time. but copy in the
- # groups <dict> (single item) generically.
- # kvargs = {}
- # kvargs.update(group)
-
- # if isinstance(f_data, dict):
- # self._add_dictfield(fields, f_name, f_data, kvargs)
- # continue
-
if f_data in self._catalog_dict:
- # f_data is the table name
cls_tbl = self.catalog.get(f_data,
self._build_cmdtable(f_data))
fields.table(f_name, cls_tbl)
continue
+
+ # if we are here, it means we need to filter fields from textfsm
+ fields._fields.update({f_name: f_data})
# -------------------------------------------------------------------------
def _build_view(self, view_name):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/py-junos-eznc-2.3.1/lib/jnpr/junos/factory/optable.py
new/py-junos-eznc-2.4.1/lib/jnpr/junos/factory/optable.py
--- old/py-junos-eznc-2.3.1/lib/jnpr/junos/factory/optable.py 2019-12-10
07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/lib/jnpr/junos/factory/optable.py 2020-04-29
18:00:59.000000000 +0200
@@ -133,17 +133,23 @@
# fields:
# input-bytes: traffic-statistics/input-bytes
# output-bytes: traffic-statistics/output-bytes
- existing_elem = parser_ingest.xpath(tags[0])
- if existing_elem:
- obj = existing_elem[0]
- for tag in tags[1:]:
- obj.append(E(tag))
+ # or
+ # fields:
+ # prefix-count:
bgp-option-information/prefix-limit/prefix-count
+ # prefix-dummy:
bgp-option-information/prefix-limit/prefix-dummy
+ local_obj = parser_ingest
+ for tag in tags[:-1]:
+ existing_elem = local_obj.xpath(tag)
+ if existing_elem:
+ local_obj = existing_elem[0]
+ else:
+ continue
else:
- continue
+ local_obj.append(E(tags[-1]))
else:
- obj = E(tags[0])
- for tag in tags[1:]:
- obj.append(E(tag))
+ obj = E(tags[-1])
+ for tag in tags[:-1][::-1]:
+ obj = E(tag, obj)
map_multilayer_fields[tags[0]] = obj
parser_ingest.insert(i + 1, obj)
else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py-junos-eznc-2.3.1/lib/jnpr/junos/factory/table.py
new/py-junos-eznc-2.4.1/lib/jnpr/junos/factory/table.py
--- old/py-junos-eznc-2.3.1/lib/jnpr/junos/factory/table.py 2019-12-10
07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/lib/jnpr/junos/factory/table.py 2020-04-29
18:00:59.000000000 +0200
@@ -99,6 +99,9 @@
try:
keys.append(this.xpath(k)[0].text)
except:
+ # Case where key is provided like key: re-name | Null
+ if ' | ' in k and 'Null' in k:
+ continue
keys.append(None)
return tuple(keys)
@@ -134,8 +137,9 @@
# Check if pipe is in the key_value, if so append xpath
# to each value
if ' | ' in key_value:
- return self._keys_simple(' | '.join([xpath + '/' + x for x in
- key_value.split(' | ')]))
+ return self._keys_simple(' | '.join(
+ [xpath + '/' + x for x in key_value.split(' | ') if
+ x != 'Null']))
return self._keys_simple(xpath + '/' + key_value)
# user explicitly passed key as Null in Table
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py-junos-eznc-2.3.1/lib/jnpr/junos/factory/view.py
new/py-junos-eznc-2.4.1/lib/jnpr/junos/factory/view.py
--- old/py-junos-eznc-2.3.1/lib/jnpr/junos/factory/view.py 2019-12-10
07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/lib/jnpr/junos/factory/view.py 2020-04-29
18:00:59.000000000 +0200
@@ -85,6 +85,8 @@
if isinstance(self.ITEM_NAME_XPATH, str):
# xpath union key
if ' | ' in self.ITEM_NAME_XPATH:
+ if 'Null' in self.ITEM_NAME_XPATH:
+ return self._check_key_delimiter_null(self._xml,
self.ITEM_NAME_XPATH)
return self._xml.xpath(self.ITEM_NAME_XPATH)[0].text.strip()
# simple key
return self._xml.findtext(self.ITEM_NAME_XPATH).strip()
@@ -92,16 +94,44 @@
# composite key
# keys with missing XPATH nodes are set to None
keys = []
- for i in self.ITEM_NAME_XPATH:
- try:
- keys.append(self.xml.xpath(i)[0].text.strip())
- except:
- keys.append(None)
- return tuple(keys)
+ for item_name_xpath in self.ITEM_NAME_XPATH:
+ if ' | ' in item_name_xpath:
+ key_with_null_cleaned = \
+ self._check_key_delimiter_null(self._xml,
+ item_name_xpath)
+ if key_with_null_cleaned:
+ keys.append(key_with_null_cleaned)
+ else:
+ try:
+
keys.append(self.xml.xpath(item_name_xpath)[0].text.strip())
+ except:
+ keys.append(None)
+ if keys:
+ return tuple(keys)
+ else:
+ return keys
# ALIAS key <=> name
key = name
+ def _check_key_delimiter_null(self, xml, item_name_xpath):
+ """
+ Case where key is provided like key: re-name | Null
+
+ :param xml: xml object retrieved from device
+ :param item_name_xpath: key xpath
+ :return: key if fetched else []
+ """
+ if 'Null' in item_name_xpath:
+ # Let try get value for valid xpath key
+ xpath_key = [x for x in item_name_xpath.split(' | ') if x !=
'Null']
+ if xpath_key:
+ val = xml.xpath(xpath_key[0])
+ if val:
+ return val[0].text.strip()
+ else:
+ # To handle Null key
+ return []
@property
def xml(self):
""" returns the XML associated to the item """
@@ -281,6 +311,10 @@
if 1 == len_found:
return _munch(found[0])
+ # -- 2020-March-26, if string function (like string-before or
string-after) is used as xpath (instead of as xpath condition), lxml will
return ElementUnicodeResult object, which will be converted wrongly by the next
interation, we should return the original UnicodeResult
+ if isinstance(found, etree._ElementUnicodeResult):
+ return found
+
return [_munch(this) for this in found]
except:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py-junos-eznc-2.3.1/lib/jnpr/junos/rpcmeta.py
new/py-junos-eznc-2.4.1/lib/jnpr/junos/rpcmeta.py
--- old/py-junos-eznc-2.3.1/lib/jnpr/junos/rpcmeta.py 2019-12-10
07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/lib/jnpr/junos/rpcmeta.py 2020-04-29
18:00:59.000000000 +0200
@@ -263,6 +263,8 @@
pass
elif ('action' in options) and (options['action'] == 'set'):
rpc.append(E('configuration-set', contents))
+ elif ('action' in options) and (options['action'] == 'patch'):
+ rpc.append(E('configuration-patch', contents))
elif ('format' in options) and (options['format'] == 'text'):
rpc.append(E('configuration-text', contents))
elif ('format' in options) and (options['format'] == 'json'):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/py-junos-eznc-2.3.1/lib/jnpr/junos/transport/tty_netconf.py
new/py-junos-eznc-2.4.1/lib/jnpr/junos/transport/tty_netconf.py
--- old/py-junos-eznc-2.3.1/lib/jnpr/junos/transport/tty_netconf.py
2019-12-10 07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/lib/jnpr/junos/transport/tty_netconf.py
2020-04-29 18:00:59.000000000 +0200
@@ -132,6 +132,14 @@
# -------------------------------------------------------------------------
def _receive(self):
+ # On windows select.select throws io.UnsupportedOperation: fileno
+ # so use read function for windows serial COM ports
+ if hasattr(self._tty, 'port') and
str(self._tty.port).startswith('COM'):
+ return self._receive_serial_win()
+ else:
+ return self._receive_serial()
+
+ def _receive_serial(self):
""" process the XML response into an XML object """
rxbuf = PY6.EMPTY_STR
line = PY6.EMPTY_STR
@@ -153,10 +161,36 @@
rxbuf = rxbuf + line
if _NETCONF_EOM in rxbuf:
break
+ return self._parse_buffer(rxbuf)
+
+ # -------------------------------------------------------------------------
+ # Read message from windows COM ports
+ # -------------------------------------------------------------------------
+
+ def _receive_serial_win(self):
+ """ process incoming data from windows port"""
+ rxbuf = PY6.EMPTY_STR
+ line = PY6.EMPTY_STR
+ while True:
+ line, lastline = self._tty.read().strip(), line
+ if not line:
+ continue
+ if _NETCONF_EOM in line or _NETCONF_EOM in lastline + line:
+ rxbuf = rxbuf + line
+ break
+ else:
+ rxbuf = rxbuf + line
+ if _NETCONF_EOM in rxbuf:
+ break
+ return self._parse_buffer(rxbuf)
+
+ def _parse_buffer(self, rxbuf):
rxbuf = rxbuf.splitlines()
if _NETCONF_EOM in rxbuf[-1]:
- rxbuf.pop()
-
+ if rxbuf[-1] == _NETCONF_EOM:
+ rxbuf.pop()
+ else:
+ rxbuf[-1] = rxbuf[-1].split(_NETCONF_EOM)[0]
try:
rxbuf = [i.strip() for i in rxbuf if i.strip() != PY6.EMPTY_STR]
rcvd_data = PY6.NEW_LINE.join(rxbuf)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py-junos-eznc-2.3.1/lib/jnpr/junos/utils/config.py
new/py-junos-eznc-2.4.1/lib/jnpr/junos/utils/config.py
--- old/py-junos-eznc-2.3.1/lib/jnpr/junos/utils/config.py 2019-12-10
07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/lib/jnpr/junos/utils/config.py 2020-04-29
18:00:59.000000000 +0200
@@ -172,11 +172,13 @@
# commit check
# -------------------------------------------------------------------------
- def commit_check(self):
+ def commit_check(self, **kvargs):
"""
Perform a commit check. If the commit check passes, this function
will return ``True``. If the commit-check results in warnings, they
are reported and available in the Exception errs.
+ :param int timeout: If provided the command will wait for completion
+ using the provided value as timeout (seconds).
:returns: ``True`` if commit-check is successful (no errors)
:raises CommitError: When errors detected in candidate configuration.
@@ -184,8 +186,16 @@
to identify the specific problems
:raises RpcError: When underlying ncclient has an error
"""
+ rpc_args = {}
+
+ # if a timeout is provided, then include that in the RPC
+
+ timeout = kvargs.get('timeout')
+ if timeout:
+ rpc_args['dev_timeout'] = timeout
+
try:
- self.rpc.commit_configuration(check=True)
+ self.rpc.commit_configuration(check=True, **rpc_args)
except RpcTimeoutError:
raise
except RpcError as err: # jnpr.junos exception
@@ -208,7 +218,7 @@
# show | compare rollback <number|0*>
# -------------------------------------------------------------------------
- def diff(self, rb_id=0):
+ def diff(self, rb_id=0, ignore_warning=False):
"""
Retrieve a diff (patch-format) report of the candidate config against
either the current active config, or a different rollback.
@@ -224,9 +234,9 @@
raise ValueError("Invalid rollback #" + str(rb_id))
try:
- rsp = self.rpc.get_configuration(dict(
- compare='rollback', rollback=str(rb_id), format='text'
- ))
+ rsp = self.rpc.get_configuration(
+ dict(compare='rollback', rollback=str(rb_id),
format='text'),
+ ignore_warning=ignore_warning)
except RpcTimeoutError:
raise
except RpcError as err:
@@ -311,6 +321,9 @@
.. note:: This option cannot be used if **format** is "set".
+ :param bool patch:
+ If set to ``True`` will set the load-config action to load patch.
+
:param str template_path:
Similar to the **path** parameter, but this indicates that
the file contents are ``Jinja2`` format and will require
@@ -382,7 +395,7 @@
rpc_contents = None
actions = filter(lambda item: kvargs.get(item, False),
- ('overwrite', 'merge', 'update'))
+ ('overwrite', 'merge', 'update', 'patch'))
if len(list(actions)) >= 2:
raise ValueError('actions can be only one among %s'
% ', '.join(actions))
@@ -397,6 +410,8 @@
rpc_xattrs['action'] = 'update'
elif kvargs.get('merge') is True:
del rpc_xattrs['action']
+ elif kvargs.get('patch') is True:
+ rpc_xattrs['action'] = 'patch'
ignore_warning = kvargs.get('ignore_warning', False)
@@ -498,7 +513,12 @@
elif 'path' in kvargs:
# then this is a static-config file. load that as our rpc_contents
- rpc_contents = open(kvargs['path'], 'rU').read()
+ try:
+ # Explicitly request Python 3.x universal newline
+ rpc_contents = open(kvargs['path'], 'r', newline=None).read()
+ except TypeError:
+ # Fallback to Python 2.x universal newline
+ rpc_contents = open(kvargs['path'], 'rU').read()
_lset_fromfile(kvargs['path'])
if rpc_xattrs['format'] == 'xml':
# covert the XML string into XML structure
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/py-junos-eznc-2.3.1/lib/jnpr/junos/utils/ssh_client.py
new/py-junos-eznc-2.4.1/lib/jnpr/junos/utils/ssh_client.py
--- old/py-junos-eznc-2.3.1/lib/jnpr/junos/utils/ssh_client.py 2019-12-10
07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/lib/jnpr/junos/utils/ssh_client.py 2020-04-29
18:00:59.000000000 +0200
@@ -35,8 +35,10 @@
if dev._ssh_private_key_file is not None:
kwargs['key_filename'] = dev._ssh_private_key_file
- ssh_client.connect(hostname=dev._hostname,
- port=(22, int(dev._port))[dev._hostname == 'localhost'],
+ # pick hostname from .ssh config if any
+ hostname = config.get('hostname', dev._hostname)
+ ssh_client.connect(hostname=hostname,
+ port=(22, int(dev._port))[hostname == 'localhost'],
username=dev._auth_user,
password=dev._auth_password,
sock=sock, **kwargs
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py-junos-eznc-2.3.1/lib/jnpr/junos/utils/sw.py
new/py-junos-eznc-2.4.1/lib/jnpr/junos/utils/sw.py
--- old/py-junos-eznc-2.3.1/lib/jnpr/junos/utils/sw.py 2019-12-10
07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/lib/jnpr/junos/utils/sw.py 2020-04-29
18:00:59.000000000 +0200
@@ -11,6 +11,8 @@
# Python 2.x
from urlparse import urlparse
+import warnings
+warnings.simplefilter('default', PendingDeprecationWarning)
# 3rd-party modules
from lxml.builder import E
@@ -781,9 +783,9 @@
checksum, then skip the copy to optimize time.
:param bool all_re:
- (Optional) When ``True`` (default) perform the software install on
- all Routing Engines of the Junos device. When ``False`` if the
- only preform the software install on the current Routing Engine.
+ (Optional) When ``True`` (default) install the package on
+ all Routing Engines of the Junos device. When ``False`` perform
+ the software install only on the current Routing Engine.
:param bool vmhost:
(Optional) A boolean indicating if this is a software update of the
@@ -797,6 +799,8 @@
* ``True`` when the installation is successful
* ``False`` otherwise
"""
+ warnings.warn("sw.install interface bool response is going to change "
+ "in next release.", PendingDeprecationWarning)
if issu is True and nssu is True:
raise TypeError(
'install function can either take issu or nssu not both')
@@ -1045,7 +1049,7 @@
Perform a system shutdown, with optional delay (in minutes) .
If the device is equipped with dual-RE, then both RE will be
- rebooted. This code also handles EX/QFX VC.
+ shut down. This code also handles EX/QFX VC.
:param int in_min: time (minutes) before shutting down the device.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py-junos-eznc-2.3.1/lib/jnpr/junos/version.py
new/py-junos-eznc-2.4.1/lib/jnpr/junos/version.py
--- old/py-junos-eznc-2.3.1/lib/jnpr/junos/version.py 2019-12-10
07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/lib/jnpr/junos/version.py 2020-04-29
18:00:59.000000000 +0200
@@ -1,5 +1,5 @@
-VERSION = "2.3.1"
-DATE = "2019-Dec-10"
+VERSION = "2.4.1"
+DATE = "2020-Apr-29"
# Augment with the internal version if present
try:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py-junos-eznc-2.3.1/requirements.txt
new/py-junos-eznc-2.4.1/requirements.txt
--- old/py-junos-eznc-2.3.1/requirements.txt 2019-12-10 07:54:12.000000000
+0100
+++ new/py-junos-eznc-2.4.1/requirements.txt 2020-04-29 18:00:59.000000000
+0200
@@ -10,3 +10,4 @@
yamlordereddictloader
pyparsing
transitions
+ntc_templates
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py-junos-eznc-2.3.1/setup.py
new/py-junos-eznc-2.4.1/setup.py
--- old/py-junos-eznc-2.3.1/setup.py 2019-12-10 07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/setup.py 2020-04-29 18:00:59.000000000 +0200
@@ -5,13 +5,16 @@
req_lines = [line.strip() for line in open(
'requirements.txt').readlines()]
install_reqs = list(filter(None, req_lines))
-if sys.version_info[:2] == (2, 6):
- install_reqs.append('importlib>=1.0.3')
+
+# refer: https://github.com/Juniper/py-junos-eznc/issues/1015
+# should be removed when textfsm releases >=1.1.1
+if sys.platform == 'win32':
+ install_reqs.append('textfsm==0.4.1')
setup(
name="junos-eznc",
namespace_packages=['jnpr'],
- version="2.3.1",
+ version="2.4.1",
author="Jeremy Schulman, Nitin Kumar, Rick Sherman, Stacy Smith",
author_email="[email protected]",
description=("Junos 'EZ' automation for non-programmers"),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/py-junos-eznc-2.3.1/tests/unit/factory/rpc-reply/show-utmd-status-use-Null.xml
new/py-junos-eznc-2.4.1/tests/unit/factory/rpc-reply/show-utmd-status-use-Null.xml
---
old/py-junos-eznc-2.3.1/tests/unit/factory/rpc-reply/show-utmd-status-use-Null.xml
1970-01-01 01:00:00.000000000 +0100
+++
new/py-junos-eznc-2.4.1/tests/unit/factory/rpc-reply/show-utmd-status-use-Null.xml
2020-04-29 18:00:59.000000000 +0200
@@ -0,0 +1,5 @@
+<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"
xmlns:junos="http://xml.juniper.net/junos/19.4I0/junos"
xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
message-id="urn:uuid:d002acd0-0f28-4ba2-a78c-042aeb5cc910">
+<utmd-status xmlns="http://xml.juniper.net/junos/19.4I0/junos-utmd">
+<running/>
+</utmd-status>
+</rpc-reply>
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/py-junos-eznc-2.3.1/tests/unit/factory/rpc-reply/show-utmd-status.xml
new/py-junos-eznc-2.4.1/tests/unit/factory/rpc-reply/show-utmd-status.xml
--- old/py-junos-eznc-2.3.1/tests/unit/factory/rpc-reply/show-utmd-status.xml
1970-01-01 01:00:00.000000000 +0100
+++ new/py-junos-eznc-2.4.1/tests/unit/factory/rpc-reply/show-utmd-status.xml
2020-04-29 18:00:59.000000000 +0200
@@ -0,0 +1,21 @@
+<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"
xmlns:junos="http://xml.juniper.net/junos/20.2I0/junos"
xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
message-id="urn:uuid:c9c57ecd-dc9f-44cf-803b-5487182b9475">
+<multi-routing-engine-results>
+
+<multi-routing-engine-item>
+
+<re-name>node0</re-name>
+
+<utmd-status xmlns="http://xml.juniper.net/junos/20.2I0/junos-utmd"><running/>
+</utmd-status>
+</multi-routing-engine-item>
+
+<multi-routing-engine-item>
+
+<re-name>node1</re-name>
+
+<utmd-status xmlns="http://xml.juniper.net/junos/20.2I0/junos-utmd"><running/>
+</utmd-status>
+</multi-routing-engine-item>
+
+</multi-routing-engine-results>
+</rpc-reply>
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/py-junos-eznc-2.3.1/tests/unit/factory/test_cfgtable.py
new/py-junos-eznc-2.4.1/tests/unit/factory/test_cfgtable.py
--- old/py-junos-eznc-2.3.1/tests/unit/factory/test_cfgtable.py 2019-12-10
07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/tests/unit/factory/test_cfgtable.py 2020-04-29
18:00:59.000000000 +0200
@@ -3,6 +3,8 @@
import unittest
import os
+import sys
+
from nose.plugins.attrib import attr
import yaml
@@ -83,6 +85,8 @@
@attr('unit')
[email protected](sys.platform == 'win32',
+ "will work for windows in coming days")
class TestFactoryCfgTable(unittest.TestCase):
@patch('ncclient.manager.connect')
@@ -604,6 +608,7 @@
fpath = os.path.join(os.path.dirname(__file__),
'rpc-reply', fname)
+
foo = open(fpath).read()
if fname == 'user.xml':
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/py-junos-eznc-2.3.1/tests/unit/factory/test_cmdtable.py
new/py-junos-eznc-2.4.1/tests/unit/factory/test_cmdtable.py
--- old/py-junos-eznc-2.3.1/tests/unit/factory/test_cmdtable.py 2019-12-10
07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/tests/unit/factory/test_cmdtable.py 2020-04-29
18:00:59.000000000 +0200
@@ -469,7 +469,7 @@
key_items:
- High
- Low
- view: _FPCTTPQueueSizesView
+ # view: _FPCTTPQueueSizesView
_FPCTTPQueueSizesTable2:
title: TTP Receive Queue Sizes
@@ -477,7 +477,7 @@
key_items:
- High
- Low
- view: _FPCTTPQueueSizesView
+ # view: _FPCTTPQueueSizesView
_FPCTTPQueueSizesView:
fields:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/py-junos-eznc-2.3.1/tests/unit/factory/test_optable.py
new/py-junos-eznc-2.4.1/tests/unit/factory/test_optable.py
--- old/py-junos-eznc-2.3.1/tests/unit/factory/test_optable.py 2019-12-10
07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/tests/unit/factory/test_optable.py 2020-04-29
18:00:59.000000000 +0200
@@ -4,6 +4,7 @@
import unittest
import os
import yaml
+import json
from nose.plugins.attrib import attr
from jnpr.junos import Device
@@ -94,6 +95,29 @@
self.assertRaises(ValueError, bad, 'bunk')
+ def test_generate_sax_parser_fields_with_many_slash(self):
+ yaml_data = """
+---
+bgpNeighborTable:
+ rpc: get-bgp-neighbor-information
+ item: bgp-peer
+ key: peer-address
+ view: bgpNeighborView
+bgpNeighborView:
+ fields:
+ prefix-count: bgp-option-information/prefix-limit/prefix-count
+ prefix-dummy: bgp-option-information/prefix-limit/prefix-dummy
+"""
+ globals().update(FactoryLoader().load(yaml.load(yaml_data,
+ Loader=yaml.Loader)))
+ tbl = bgpNeighborTable(self.dev)
+ data = generate_sax_parser_input(tbl)
+ self.assertEqual(data.tag, 'bgp-peer')
+ self.assertEqual(len(etree.tostring(data)), len(
+ b'<bgp-peer><peer-address/><bgp-option-information><prefix-limit>'
+ b'<prefix-count/><prefix-dummy/></prefix-limit>'
+ b'</bgp-option-information></bgp-peer>'))
+
def test_generate_sax_parser_item_with_many_slash(self):
yaml_data = """
---
@@ -175,6 +199,71 @@
b'</traffic-statistics></logical-interface></physical-interface>')
)
+ @patch('jnpr.junos.Device.execute')
+ def test_key_pipe_delim_with_Null(self, mock_execute):
+ mock_execute.side_effect = self._mock_manager
+ yaml_data = """
+---
+UTMStatusTable:
+ rpc: show-utmd-status
+ item: //utmd-status
+ view: UTMStatusView
+ key: ../re-name | Null
+
+UTMStatusView:
+ fields:
+ running: { running: flag }
+ """
+ globals().update(FactoryLoader().load(yaml.load(yaml_data,
+ Loader=yaml.Loader)))
+ tbl = UTMStatusTable(self.dev)
+ data = tbl.get()
+ self.assertEqual(json.loads(data.to_json()),
+ {'node0': {'running': True}, 'node1': {'running':
True}})
+
+ @patch('jnpr.junos.Device.execute')
+ def test_key_pipe_delim_with_Null_use_Null(self, mock_execute):
+ mock_execute.side_effect = self._mock_manager
+ yaml_data = """
+---
+UTMStatusTable:
+ rpc: show-utmd-status_use_Null
+ item: //utmd-status
+ view: UTMStatusView
+ key: ../re-name | Null
+
+UTMStatusView:
+ fields:
+ running: { running: flag }
+ """
+ globals().update(FactoryLoader().load(yaml.load(yaml_data,
+ Loader=yaml.Loader)))
+ tbl = UTMStatusTable(self.dev)
+ data = tbl.get()
+ self.assertEqual(json.loads(data.to_json()), {'running': True})
+
+ @patch('jnpr.junos.Device.execute')
+ def test_key_and_item_pipe_delim_with_Null_use_Null(self, mock_execute):
+ mock_execute.side_effect = self._mock_manager
+ yaml_data = """
+---
+UTMStatusTable:
+ rpc: show-utmd-status_use_Null
+ item: //multi-routing-engine-item/utmd-status | //utmd-status
+ view: UTMStatusView
+ key:
+ - ../re-name | Null
+
+UTMStatusView:
+ fields:
+ running: { running: flag }
+ """
+ globals().update(FactoryLoader().load(yaml.load(yaml_data,
+ Loader=yaml.Loader)))
+ tbl = UTMStatusTable(self.dev)
+ data = tbl.get()
+ self.assertEqual(json.loads(data.to_json()), {'running': True})
+
def _read_file(self, fname):
from ncclient.xml_ import NCElement
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py-junos-eznc-2.3.1/tests/unit/factory/test_table.py
new/py-junos-eznc-2.4.1/tests/unit/factory/test_table.py
--- old/py-junos-eznc-2.3.1/tests/unit/factory/test_table.py 2019-12-10
07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/tests/unit/factory/test_table.py 2020-04-29
18:00:59.000000000 +0200
@@ -125,7 +125,6 @@
def test_table_items(self, mock_execute):
mock_execute.side_effect = self._mock_manager
self.ppt.get('ge-0/0/0')
- print (self.ppt.items())
self.assertEqual(len(self.ppt.items()[1][1]), 8)
def test_table_get_return_none(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/py-junos-eznc-2.3.1/tests/unit/facts/test_get_software_information.py
new/py-junos-eznc-2.4.1/tests/unit/facts/test_get_software_information.py
--- old/py-junos-eznc-2.3.1/tests/unit/facts/test_get_software_information.py
2019-12-10 07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/tests/unit/facts/test_get_software_information.py
2020-04-29 18:00:59.000000000 +0200
@@ -110,7 +110,6 @@
@patch('jnpr.junos.Device.execute')
def test_sw_info_dual_other_re_off(self, mock_execute):
mock_execute.side_effect = self._mock_manager_dual_other_re_off
- print (self.dev.facts)
self.assertEqual(self.dev.facts['junos_info']['re1']['text'],
'18.3I20180716_1639')
self.assertEqual(self.dev.facts['hostname'], 'R1_re01')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/py-junos-eznc-2.3.1/tests/unit/facts/test_get_virtual_chassis_information.py
new/py-junos-eznc-2.4.1/tests/unit/facts/test_get_virtual_chassis_information.py
---
old/py-junos-eznc-2.3.1/tests/unit/facts/test_get_virtual_chassis_information.py
2019-12-10 07:54:12.000000000 +0100
+++
new/py-junos-eznc-2.4.1/tests/unit/facts/test_get_virtual_chassis_information.py
2020-04-29 18:00:59.000000000 +0200
@@ -5,6 +5,7 @@
from nose.plugins.attrib import attr
from mock import patch, MagicMock
import os
+import sys
from lxml import etree
from jnpr.junos import Device
@@ -57,6 +58,8 @@
self.assertEqual(self.dev.facts['vc_master'], None)
@patch('jnpr.junos.Device.execute')
+ @unittest.skipIf(sys.platform == 'win32',
+ "will work for windows in coming days")
def test_vc_mmvcf(self, mock_execute):
mock_execute.side_effect = self._mock_manager_vc_mmvcf
self.assertEqual(self.dev.facts['vc_capable'], True)
@@ -65,6 +68,8 @@
self.assertEqual(self.dev.facts['vc_master'], '0')
@patch('jnpr.junos.Device.execute')
+ @unittest.skipIf(sys.platform == 'win32',
+ "will work for windows in coming days")
def test_vc_mmvc(self, mock_execute):
mock_execute.side_effect = self._mock_manager_vc_mmvc
self.assertEqual(self.dev.facts['vc_capable'], True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/py-junos-eznc-2.3.1/tests/unit/ofacts/test_routing_engines.py
new/py-junos-eznc-2.4.1/tests/unit/ofacts/test_routing_engines.py
--- old/py-junos-eznc-2.3.1/tests/unit/ofacts/test_routing_engines.py
2019-12-10 07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/tests/unit/ofacts/test_routing_engines.py
2020-04-29 18:00:59.000000000 +0200
@@ -5,6 +5,7 @@
from nose.plugins.attrib import attr
from mock import patch, MagicMock
import os
+import sys
from jnpr.junos import Device
from jnpr.junos.ofacts.routing_engines import facts_routing_engines as
routing_engines
@@ -30,6 +31,8 @@
self.vcf = False
@patch('jnpr.junos.Device.execute')
+ @unittest.skipIf(sys.platform == 'win32',
+ "will work for windows in coming days")
def test_multi_re_vc(self, mock_execute):
mock_execute.side_effect = self._mock_manager
self.mode = 'multi'
@@ -52,6 +55,8 @@
self.assertEqual(self.facts['RE1']['mastership_state'], 'backup')
@patch('jnpr.junos.Device.execute')
+ @unittest.skipIf(sys.platform == 'win32',
+ "will work for windows in coming days")
def test_mixed_mode_vcf(self, mock_execute):
mock_execute.side_effect = self._mock_manager
self.mode = 'multi'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py-junos-eznc-2.3.1/tests/unit/test_device.py
new/py-junos-eznc-2.4.1/tests/unit/test_device.py
--- old/py-junos-eznc-2.3.1/tests/unit/test_device.py 2019-12-10
07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/tests/unit/test_device.py 2020-04-29
18:00:59.000000000 +0200
@@ -680,6 +680,8 @@
self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
self.assertRaises(RpcError, self.dev.rpc.get_rpc_error)
+ @unittest.skipIf(sys.platform == 'win32',
+ "will work for windows in coming days")
def test_device_execute_permission_error(self):
self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
self.assertRaises(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/py-junos-eznc-2.3.1/tests/unit/transport/test_serial.py
new/py-junos-eznc-2.4.1/tests/unit/transport/test_serial.py
--- old/py-junos-eznc-2.3.1/tests/unit/transport/test_serial.py 2019-12-10
07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/tests/unit/transport/test_serial.py 2020-04-29
18:00:59.000000000 +0200
@@ -2,6 +2,7 @@
from nose.plugins.attrib import attr
from mock import MagicMock, patch
import sys
+import six
from jnpr.junos.console import Console
@@ -33,7 +34,6 @@
@patch('jnpr.junos.transport.tty_serial.Serial._tty_close')
def tearDown(self, mock_serial_close, mock_write, mock_read, mock_close,
mock_sleep):
- # mock_read.side_effect = [('shell', 'shell'), ('login', 'login'),
mock_read.side_effect = [('shell', 'shell'), ('login', 'login'),
('cli', 'cli'), ]
self.dev.close()
@@ -67,3 +67,90 @@
self.dev._tty.EXPECT_TIMEOUT = 0.1
self.dev._tty._ser.readline.side_effect = ['', 'test']
self.assertEqual(self.dev._tty.read_prompt()[0], None)
+
+
+@attr('unit')
+class TestSerialWin(unittest.TestCase):
+
+ @patch('jnpr.junos.transport.tty_serial.serial.Serial.open')
+ @patch('jnpr.junos.transport.tty_serial.serial.Serial.read')
+ @patch('jnpr.junos.transport.tty_serial.serial.Serial.write')
+ @patch('jnpr.junos.transport.tty_serial.serial.Serial.flush')
+ @patch('jnpr.junos.transport.tty_serial.Serial.read_prompt')
+ def setUp(self, mock_read, mock_flush, mock_write, mock_serial_read,
+ mock_open):
+ self.dev = Console(port='COM4', baud=9600, mode='Serial')
+ mock_read.side_effect = [
+ ('login', 'login'), ('passwd', 'passwd'), ('shell', 'shell')]
+ mock_serial_read.side_effect = [
+ six.b("<!-- No zombies were killed during the creation of this
user interface -->"),
+ six.b(''), six.b("""<!-- user root, class super-user -->
+<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <capabilities>
+ <capability>urn:ietf:params:netconf:base:1.0</capability>
+ <capability>urn:ietf:params:netconf:capability:candidate:1.0</capability>
+
<capability>urn:ietf:params:netconf:capability:confirmed-commit:1.0</capability>
+ <capability>urn:ietf:params:netconf:capability:validate:1.0</capability>
+
<capability>urn:ietf:params:netconf:capability:url:1.0?scheme=http,ftp,file</capability>
+ <capability>urn:ietf:params:xml:ns:netconf:base:1.0</capability>
+
<capability>urn:ietf:params:xml:ns:netconf:capability:candidate:1.0</capability>
+
<capability>urn:ietf:params:xml:ns:netconf:capability:confirmed-commit:1.0</capability>
+
<capability>urn:ietf:params:xml:ns:netconf:capability:validate:1.0</capability>
+
<capability>urn:ietf:params:xml:ns:netconf:capability:url:1.0?scheme=http,ftp,file</capability>
+
<capability>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring</capability>
+ <capability>http://xml.juniper.net/netconf/junos/1.0</capability>
+ <capability>http://xml.juniper.net/dmi/system/1.0</capability>
+ </capabilities>
+ <session-id>7478</session-id>
+</hello>
+]]>]]>"""), six.b('')]
+ self.dev.open()
+
+ @patch('jnpr.junos.transport.tty.sleep')
+ @patch('jnpr.junos.transport.tty.tty_netconf.close')
+ @patch('jnpr.junos.transport.tty_serial.Serial.read_prompt')
+ @patch('jnpr.junos.transport.tty_serial.Serial.write')
+ @patch('jnpr.junos.transport.tty_serial.Serial._tty_close')
+ def tearDown(self, mock_serial_close, mock_write, mock_read, mock_close,
+ mock_sleep):
+ mock_read.side_effect = [('shell', 'shell'), ('login', 'login'),
+ ('cli', 'cli'), ]
+ self.dev.close()
+
+ def test_tty_serial_win_connected(self):
+ self.assertTrue(self.dev.connected)
+
+ @patch('jnpr.junos.transport.tty.tty_netconf.close')
+ @patch('jnpr.junos.transport.tty_serial.Serial._tty_close')
+ def test_tty_serial_win_rpc_call(self, mock_serial_close, mock_close):
+ self.dev._tty.read = MagicMock()
+ self.dev._tty.rawwrite = MagicMock()
+ self.dev._tty.read.side_effect = \
+ [six.b('<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"'
+ ' xmlns:junos="http://xml.juniper.net/junos/15.1X49/junos">'
+ '<route-engine-information xmlns="http://xml.juniper.net/ju'
+ 'nos/15.1X49/junos-chassis"><route-engine><status>OK</statu'
+ 's><temperature junos:celsius="45">45 degrees C / 113 degre'
+ 'es F</temperature><cpu-temperature junos:celsius="61">61 d'
+ 'egrees C / 141 degrees F</cpu-temperature><memory-system-t'
+ 'otal>4096</memory-system-total><memory-system-total-used>1'
+ '024</memory-system-total-used><memory-system-total-util>25'
+ '</memory-system-total-util><memory-control-plane>2624</mem'
+ 'ory-control-plane><memory-control-plane-used>682</memory-c'
+ 'ontrol-plane-used><memory-control-plane-util>26</memory-co'
+ 'ntrol-plane-util><memory-data-plane>1472</memory-data-plan'
+ 'e><memory-data-plane-used>353</memory-data-plane-used><mem'
+ 'ory-data-plane-util>24</memory-data-plane-util><cpu-user>1'
+ '2</cpu-user><cpu-background>0</cpu-background><cpu-system>'
+ '6</cpu-system><cpu-interrupt>0</cpu-interrupt><cpu-idle>83'
+ '</cpu-idle><model>RE-SRX300</model><serial-number>CV0918AF'
+ '1022</serial-number><start-time junos:seconds="1584539305"'
+ '>2020-03-18 08:48:25 CDT</start-time><up-time junos:second'
+ 's="137925">1 day, 14 hours, 18 minutes, 45 seconds</up-tim'
+ 'e><last-reboot-reason>0x1:power cycle/failure</last-reboot'
+ '-reason><load-average-one>0.12</load-average-one><load-ave'
+ 'rage-five>0.08</load-average-five><load-average-fifteen>0.'
+ '06</load-average-fifteen></route-engine></route-engine-inf'
+ 'ormation></rpc-reply>]]>]]>')]
+ res = self.dev.rpc.get_route_engine_information()
+ self.assertEqual(res.tag, 'route-engine-information')
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/py-junos-eznc-2.3.1/tests/unit/transport/test_tty_netconf.py
new/py-junos-eznc-2.4.1/tests/unit/transport/test_tty_netconf.py
--- old/py-junos-eznc-2.3.1/tests/unit/transport/test_tty_netconf.py
2019-12-10 07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/tests/unit/transport/test_tty_netconf.py
2020-04-29 18:00:59.000000000 +0200
@@ -14,6 +14,7 @@
def setUp(self):
self.tty_net = tty_netconf(MagicMock())
+ self.tty_net._tty.port = '/dev/tty'
@patch('jnpr.junos.transport.tty_netconf.tty_netconf._receive')
def test_open_at_shell_true(self, mock_rcv):
@@ -108,6 +109,7 @@
@patch('jnpr.junos.transport.tty_netconf.select.select')
def test_tty_netconf_receive_XMLSyntaxError(self, mock_select):
rx = MagicMock()
+
rx.read_until.side_effect = iter([
six.b('<rpc-reply>ok<dummy></rpc-reply>'),
six.b('\n]]>]]>')])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py-junos-eznc-2.3.1/tests/unit/utils/test_config.py
new/py-junos-eznc-2.4.1/tests/unit/utils/test_config.py
--- old/py-junos-eznc-2.3.1/tests/unit/utils/test_config.py 2019-12-10
07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/tests/unit/utils/test_config.py 2020-04-29
18:00:59.000000000 +0200
@@ -184,7 +184,8 @@
self.conf.diff()
self.conf.rpc.get_configuration.\
assert_called_with(
- {'compare': 'rollback', 'rollback': '0', 'format': 'text'})
+ {'compare': 'rollback', 'rollback': '0', 'format': 'text'},
+ ignore_warning=False)
def test_config_diff_exception_severity_warning(self):
rpc_xml = '''
@@ -809,6 +810,43 @@
self.assertEqual(self.conf.rpc.load_config.call_args[1]['url'],
'/var/home/user/golden.conf')
+ @patch('jnpr.junos.Device.execute')
+ def test_load_config_patch(self, mock_exec):
+ conf = \
+ """[edit system]
+ - host-name pakzds904;
+ + host-name pakzds904_set;
+ """
+ self.conf.load(conf, format='text', patch=True)
+ self.assertEqual(mock_exec.call_args[0][0].tag, 'load-configuration')
+ self.assertEqual(mock_exec.call_args[0][0].attrib,
+ {'format': 'text', 'action': 'patch'})
+
+ @patch('jnpr.junos.Device.execute')
+ def test_load_config_text(self, mock_exec):
+ textdata = """policy-options {
+ prefix-list TEST1-NETS {
+ 100.0.0.0/24;
+ }
+ policy-statement TEST1-NETS {
+ term TEST1 {
+ from {
+ prefix-list TEST1-NETS;
+ }
+ then accept;
+ }
+ term REJECT {
+ then reject;
+ }
+ }
+ }"""
+ self.conf.load(textdata, overwrite=True)
+ self.assertEqual(mock_exec.call_args[0][0].tag, 'load-configuration')
+ self.assertEqual(mock_exec.call_args[0][0].getchildren()[0].tag,
+ 'configuration-text')
+ self.assertEqual(mock_exec.call_args[0][0].attrib,
+ {'format': 'text', 'action': 'override'})
+
def _read_file(self, fname):
fpath = os.path.join(os.path.dirname(__file__),
'rpc-reply', fname)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py-junos-eznc-2.3.1/tests/unit/utils/test_ftp.py
new/py-junos-eznc-2.4.1/tests/unit/utils/test_ftp.py
--- old/py-junos-eznc-2.3.1/tests/unit/utils/test_ftp.py 2019-12-10
07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/tests/unit/utils/test_ftp.py 2020-04-29
18:00:59.000000000 +0200
@@ -3,6 +3,7 @@
from nose.plugins.attrib import attr
import ftplib
import sys
+import os
from jnpr.junos import Device
import jnpr.junos.utils.ftp
@@ -16,6 +17,8 @@
@attr('unit')
[email protected](sys.platform == 'win32',
+ "will work for windows in coming days")
class TestFtp(unittest.TestCase):
@patch('ftplib.FTP.connect')
@@ -121,15 +124,18 @@
@patch('ftplib.FTP.storbinary')
@patch(builtin_string + '.open')
def test_ftp_upload_file_rem_full_path(self, mock_open, mock_ftpstore):
- self.assertEqual(self.dev_ftp.put(local_file="/var/tmp/conf.txt",
- remote_path="/var/tmp/test.txt"),
True)
+ self.assertEqual(self.dev_ftp.put(local_file=os.path.abspath(
+ "/var/tmp/conf.txt"),
+ remote_path=os.path.abspath(
+ "/var/tmp/test.txt")), True)
self.assertEqual(tuple(mock_ftpstore.call_args)[1]['cmd'],
- 'STOR /var/tmp/test.txt')
+ 'STOR '+os.path.abspath("/var/tmp/test.txt"))
@patch('ftplib.FTP.storbinary')
@patch(builtin_string + '.open')
def test_ftp_upload_file_rem_path_create(self, mock_open, mock_ftpstore):
self.assertEqual(self.dev_ftp.put(local_file="conf.txt",
- remote_path="/var/tmp"), True)
+ remote_path=os.path.abspath(
+ "/var/tmp")), True)
self.assertEqual(tuple(mock_ftpstore.call_args)[1]['cmd'],
- 'STOR /var/tmp/conf.txt')
+ 'STOR '+os.path.abspath("/var/tmp/conf.txt"))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/py-junos-eznc-2.3.1/tests/unit/utils/test_sw.py
new/py-junos-eznc-2.4.1/tests/unit/utils/test_sw.py
--- old/py-junos-eznc-2.3.1/tests/unit/utils/test_sw.py 2019-12-10
07:54:12.000000000 +0100
+++ new/py-junos-eznc-2.4.1/tests/unit/utils/test_sw.py 2020-04-29
18:00:59.000000000 +0200
@@ -756,6 +756,8 @@
self.assertEqual(eval(self.sw.rollback()), msg)
@patch('jnpr.junos.Device.execute')
+ @unittest.skipIf(sys.platform == 'win32',
+ "will work for windows in coming days")
def test_sw_rollback_multi_exception(self, mock_execute):
fname = 'request-package-rollback-multi-error.xml'
mock_execute.side_effect = self._read_file(fname)
++++++ python-junos-eznc-no-unittest2.patch ++++++
Index: py-junos-eznc-2.3.1/development.txt
===================================================================
--- py-junos-eznc-2.3.1.orig/development.txt 2019-12-10 07:54:12.000000000
+0100
+++ py-junos-eznc-2.3.1/development.txt 2020-06-02 09:22:40.050714175 +0200
@@ -6,4 +6,3 @@ nose # http://nose.readthedocs.o
pep8 # https://github.com/jcrocholl/pep8
pyflakes # https://launchpad.net/pyflakes
coveralls # https://coveralls.io/
-unittest2>=0.5.1 # https://pypi.python.org/pypi/unittest2
Index: py-junos-eznc-2.3.1/tests/functional/test_core.py
===================================================================
--- py-junos-eznc-2.3.1.orig/tests/functional/test_core.py 2019-12-10
07:54:12.000000000 +0100
+++ py-junos-eznc-2.3.1/tests/functional/test_core.py 2020-06-02
09:24:17.503246419 +0200
@@ -1,6 +1,9 @@
__author__ = "rsherman, vnitinv"
-import unittest2 as unittest
+try:
+ import unittest2 as unittest
+except ImportError:
+ import unittest
from nose.plugins.attrib import attr
from jnpr.junos.exception import RpcTimeoutError
Index: py-junos-eznc-2.3.1/tests/functional/test_table.py
===================================================================
--- py-junos-eznc-2.3.1.orig/tests/functional/test_table.py 2019-12-10
07:54:12.000000000 +0100
+++ py-junos-eznc-2.3.1/tests/functional/test_table.py 2020-06-02
09:24:46.555405079 +0200
@@ -1,6 +1,9 @@
__author__ = "rsherman, vnitinv"
-import unittest2 as unittest
+try:
+ import unittest2 as unittest
+except ImportError:
+ import unittest
from nose.plugins.attrib import attr
from jnpr.junos.op.routes import RouteTable
Index: py-junos-eznc-2.3.1/tests/unit/factory/test_to_json.py
===================================================================
--- py-junos-eznc-2.3.1.orig/tests/unit/factory/test_to_json.py 2019-12-10
07:54:12.000000000 +0100
+++ py-junos-eznc-2.3.1/tests/unit/factory/test_to_json.py 2020-06-02
09:37:16.499457233 +0200
@@ -1,6 +1,9 @@
__author__ = "Rick Sherman"
-import unittest2 as unittest
+try:
+ import unittest2 as unittest
+except ImportError:
+ import unittest
from nose.plugins.attrib import attr
from mock import patch
import os
Index: py-junos-eznc-2.3.1/tests/unit/facts/test__init__.py
===================================================================
--- py-junos-eznc-2.3.1.orig/tests/unit/facts/test__init__.py 2019-12-10
07:54:12.000000000 +0100
+++ py-junos-eznc-2.3.1/tests/unit/facts/test__init__.py 2020-06-02
09:38:06.663731374 +0200
@@ -1,7 +1,10 @@
__author__ = "Stacy Smith"
__credits__ = "Jeremy Schulman, Nitin Kumar"
-import unittest2 as unittest
+try:
+ import unittest2 as unittest
+except ImportError:
+ import unittest
from nose.plugins.attrib import attr
import importlib
import sys
Index: py-junos-eznc-2.3.1/tests/unit/facts/test_swver.py
===================================================================
--- py-junos-eznc-2.3.1.orig/tests/unit/facts/test_swver.py 2019-12-10
07:54:12.000000000 +0100
+++ py-junos-eznc-2.3.1/tests/unit/facts/test_swver.py 2020-06-04
12:31:16.270468805 +0200
@@ -1,7 +1,11 @@
__author__ = "Stacy Smith"
__credits__ = "Jeremy Schulman, Nitin Kumar"
-import unittest2 as unittest
+import six
+try:
+ import unittest2 as unittest
+except:
+ import unittest
from nose.plugins.attrib import attr
from jnpr.junos.facts.swver import version_info, get_facts
@@ -9,17 +13,18 @@ from jnpr.junos.facts.swver import versi
@attr('unit')
class TestVersionInfo(unittest.TestCase):
-
+ if six.PY2:
+ assertCountEqual = unittest.TestCase.assertItemsEqual
def test_version_info_after_type_len_else(self):
self.assertEqual(version_info('12.1X46-D10').build, None)
def test_version_info_X_type_non_hyphenated(self):
- self.assertItemsEqual(
+ self.assertCountEqual(
version_info('11.4X12.2'),
[('build', 2), ('major', (11, 4)), ('minor', '12'), ('type', 'X')])
def test_version_info_X_type_non_hyphenated_nobuild(self):
- self.assertItemsEqual(
+ self.assertCountEqual(
version_info('11.4X12'),
[('build', None), ('major', (11, 4)), ('minor', '12'), ('type',
'X')])
@@ -61,12 +66,12 @@ class TestVersionInfo(unittest.TestCase)
"build: 5\nmajor: !!python/tuple\n- 11\n- 4\nminor: '7'\ntype:
R\n")
def test_version_iter(self):
- self.assertItemsEqual(
+ self.assertCountEqual(
version_info('11.4R7.5'),
[('build', 5), ('major', (11, 4)), ('minor', '7'), ('type', 'R')])
def test_version_feature_velocity(self):
- self.assertItemsEqual(
+ self.assertCountEqual(
version_info('15.4F7.5'),
[('build', 5), ('major', (15, 4)), ('minor', '7'), ('type', 'F')])
Index: py-junos-eznc-2.3.1/tests/unit/ofacts/test_swver.py
===================================================================
--- py-junos-eznc-2.3.1.orig/tests/unit/ofacts/test_swver.py 2019-12-10
07:54:12.000000000 +0100
+++ py-junos-eznc-2.3.1/tests/unit/ofacts/test_swver.py 2020-06-02
09:39:36.380221690 +0200
@@ -1,7 +1,10 @@
__author__ = "Nitin Kumar, Rick Sherman"
__credits__ = "Jeremy Schulman"
-import unittest2 as unittest
+try:
+ import unittest2 as unittest
+except ImportError:
+ import unittest
from nose.plugins.attrib import attr
from mock import patch, MagicMock
import os
Index: py-junos-eznc-2.3.1/tests/unit/test_console.py
===================================================================
--- py-junos-eznc-2.3.1.orig/tests/unit/test_console.py 2019-12-10
07:54:12.000000000 +0100
+++ py-junos-eznc-2.3.1/tests/unit/test_console.py 2020-06-02
09:40:33.860535824 +0200
@@ -1,4 +1,7 @@
-import unittest2 as unittest
+try:
+ import unittest2 as unittest
+except ImportError:
+ import unittest
from jnpr.junos.utils.config import Config
from nose.plugins.attrib import attr
from mock import patch, MagicMock, call
Index: py-junos-eznc-2.3.1/tests/unit/test_decorators.py
===================================================================
--- py-junos-eznc-2.3.1.orig/tests/unit/test_decorators.py 2019-12-10
07:54:12.000000000 +0100
+++ py-junos-eznc-2.3.1/tests/unit/test_decorators.py 2020-06-02
09:40:56.432659185 +0200
@@ -1,4 +1,7 @@
-import unittest2 as unittest
+try:
+ import unittest2 as unittest
+except ImportError:
+ import unittest
from nose.plugins.attrib import attr
from lxml.etree import XML
Index: py-junos-eznc-2.3.1/tests/unit/test_device.py
===================================================================
--- py-junos-eznc-2.3.1.orig/tests/unit/test_device.py 2019-12-10
07:54:12.000000000 +0100
+++ py-junos-eznc-2.3.1/tests/unit/test_device.py 2020-06-02
09:41:17.232772861 +0200
@@ -1,4 +1,7 @@
-import unittest2 as unittest
+try:
+ import unittest2 as unittest
+except ImportError:
+ import unittest
from nose.plugins.attrib import attr
from mock import MagicMock, patch, mock_open, call
import os
Index: py-junos-eznc-2.3.1/tests/unit/test_factcache.py
===================================================================
--- py-junos-eznc-2.3.1.orig/tests/unit/test_factcache.py 2019-12-10
07:54:12.000000000 +0100
+++ py-junos-eznc-2.3.1/tests/unit/test_factcache.py 2020-06-02
09:42:15.129089270 +0200
@@ -1,4 +1,7 @@
-import unittest2 as unittest
+try:
+ import unittest2 as unittest
+except ImportError:
+ import unittest
from nose.plugins.attrib import attr
from mock import patch, MagicMock, call
from jnpr.junos.exception import FactLoopError
Index: py-junos-eznc-2.3.1/tests/unit/transport/test_serial.py
===================================================================
--- py-junos-eznc-2.3.1.orig/tests/unit/transport/test_serial.py
2019-12-10 07:54:12.000000000 +0100
+++ py-junos-eznc-2.3.1/tests/unit/transport/test_serial.py 2020-06-02
09:44:13.877738198 +0200
@@ -1,4 +1,7 @@
-import unittest2 as unittest
+try:
+ import unittest2 as unittest
+except ImportError:
+ import unittest
from nose.plugins.attrib import attr
from mock import MagicMock, patch
import sys
Index: py-junos-eznc-2.3.1/tests/unit/transport/test_tty_netconf.py
===================================================================
--- py-junos-eznc-2.3.1.orig/tests/unit/transport/test_tty_netconf.py
2019-12-10 07:54:12.000000000 +0100
+++ py-junos-eznc-2.3.1/tests/unit/transport/test_tty_netconf.py
2020-06-02 09:44:54.209958559 +0200
@@ -1,4 +1,7 @@
-import unittest2 as unittest
+try:
+ import unittest2 as unittest
+except ImportError:
+ import unittest
from nose.plugins.attrib import attr
from mock import MagicMock, patch
from jnpr.junos.transport.tty_netconf import tty_netconf
Index: py-junos-eznc-2.3.1/tests/unit/transport/test_tty.py
===================================================================
--- py-junos-eznc-2.3.1.orig/tests/unit/transport/test_tty.py 2019-12-10
07:54:12.000000000 +0100
+++ py-junos-eznc-2.3.1/tests/unit/transport/test_tty.py 2020-06-02
09:44:28.917820369 +0200
@@ -1,5 +1,8 @@
import logging
-import unittest2 as unittest
+try:
+ import unittest2 as unittest
+except ImportError:
+ import unittest
from nose.plugins.attrib import attr
from mock import MagicMock, patch
Index: py-junos-eznc-2.3.1/tests/unit/transport/test_tty_ssh.py
===================================================================
--- py-junos-eznc-2.3.1.orig/tests/unit/transport/test_tty_ssh.py
2019-12-10 07:54:12.000000000 +0100
+++ py-junos-eznc-2.3.1/tests/unit/transport/test_tty_ssh.py 2020-06-02
09:45:28.666146801 +0200
@@ -1,6 +1,9 @@
import socket
import sys
-import unittest2 as unittest
+try:
+ import unittest2 as unittest
+except ImportError:
+ import unittest
from nose.plugins.attrib import attr
from mock import MagicMock, patch
from jnpr.junos.transport.tty_ssh import SSH
Index: py-junos-eznc-2.3.1/tests/unit/transport/test_tty_telnet.py
===================================================================
--- py-junos-eznc-2.3.1.orig/tests/unit/transport/test_tty_telnet.py
2019-12-10 07:54:12.000000000 +0100
+++ py-junos-eznc-2.3.1/tests/unit/transport/test_tty_telnet.py 2020-06-02
09:48:57.923290082 +0200
@@ -1,5 +1,8 @@
import sys
-import unittest2 as unittest
+try:
+ import unittest2 as unittest
+except ImportError:
+ import unittest
from nose.plugins.attrib import attr
from mock import MagicMock, patch
from jnpr.junos.transport.tty_telnet import Telnet
Index: py-junos-eznc-2.3.1/tests/unit/utils/test_sw.py
===================================================================
--- py-junos-eznc-2.3.1.orig/tests/unit/utils/test_sw.py 2019-12-10
07:54:12.000000000 +0100
+++ py-junos-eznc-2.3.1/tests/unit/utils/test_sw.py 2020-06-02
09:43:36.313532958 +0200
@@ -2,7 +2,10 @@ from __future__ import print_function
import os
import sys
from six import StringIO
-import unittest2 as unittest
+try:
+ import unittest2 as unittest
+except ImportError:
+ import unittest
from nose.plugins.attrib import attr
from contextlib import contextmanager
from jnpr.junos import Device