Hello community,
here is the log from the commit of package python-ncclient for openSUSE:Factory
checked in at 2020-08-10 15:05:21
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-ncclient (Old)
and /work/SRC/openSUSE:Factory/.python-ncclient.new.3399 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-ncclient"
Mon Aug 10 15:05:21 2020 rev:12 rq:825318 version:0.6.9
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-ncclient/python-ncclient.changes
2020-02-19 12:41:31.311737996 +0100
+++
/work/SRC/openSUSE:Factory/.python-ncclient.new.3399/python-ncclient.changes
2020-08-10 15:06:00.600254285 +0200
@@ -1,0 +2,12 @@
+Sun Aug 9 14:03:46 UTC 2020 - Martin Hauke <[email protected]>
+
+- Update to version 0.6.9
+ * Fix for breaking API change
+- Update to version 0.6.8
+ * Support for namespace prefixes for XPath queries
+ * edit-config parameter validation
+ * Support for multiple RPC errors
+ * API to get supported device types
+ * Support for subtree filters with multiple top-level tags
+
+-------------------------------------------------------------------
Old:
----
ncclient-0.6.7.tar.gz
New:
----
ncclient-0.6.9.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-ncclient.spec ++++++
--- /var/tmp/diff_new_pack.Z0w8Bd/_old 2020-08-10 15:06:01.608254818 +0200
+++ /var/tmp/diff_new_pack.Z0w8Bd/_new 2020-08-10 15:06:01.608254818 +0200
@@ -18,7 +18,7 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-ncclient
-Version: 0.6.7
+Version: 0.6.9
Release: 0
Summary: Python library for NETCONF clients
License: Apache-2.0
@@ -83,6 +83,6 @@
%{python_sitelib}/*
%files -n python-ncclient-doc
-%doc README README.rst examples docs/build/html
+%doc README.md README.rst examples docs/build/html
%changelog
++++++ ncclient-0.6.7.tar.gz -> ncclient-0.6.9.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/Changelog new/ncclient-0.6.9/Changelog
--- old/ncclient-0.6.7/Changelog 2019-12-21 20:16:07.000000000 +0100
+++ new/ncclient-0.6.9/Changelog 2020-08-09 00:09:16.000000000 +0200
@@ -1,3 +1,74 @@
+version 0.6.9
+-------------
+
+* Resiolved breaking API change
+
+version 0.6.8
+-------------
+
+* Variety of small updates and bugfixes, but of note:
+ - Support for namespace prefixes for XPath queries
+ - `edit-config` parameter validation
+ - Support for multiple RPC errors
+ - API to get supported device types
+ - Support for subtree filters with multiple top-level tags
+* Thanks to all contributors!
+* Pulled due to avccidental breaking API change
+
+version 0.6.7
+-------------
+
+* Variety of bugfixes from a variety of contributors since 0.6.6 (see commit
history)
+
+
+version 0.6.6
+-------------
+
+* Read ssh timeout from config file if not specified in method call
+* Tox support
+* Huge XML tree parser support
+* Adding optional bind address to connect
+
+
+version 0.6.5
+-------------
+
+* Updated README for 0.6.5 release
+
+
+version 0.6.4
+-------------
+
+* Pin selectors2 to Python versions <= 3.4
+* Fix config examples to actually use the nc namespace
+* Fix: correctly set port for paramiko when using ssh_config file
+* Test: add test to check ProxyCommand uses correct port
+* Update commits for py3
+* Enhance Alcatel-Lucent-support
+* Juniper RPC: allow specifying format in CompareConfiguration
+* Parsing of NETCONF 1.1 frames no longer decodes each chunk of bytes
+* Fix filter in create_subscription
+* Validate 'with-defaults' mode based on supported modes advertised in
capability URI
+
+
+version 0.6.3
+-------------
+
+* Fix homepage link registered with PyPi
+* SSH Host Key checking
+* Updated junos.py to resolve RestrictedUser error
+* Close the channel when closing SSH session
+* Invoke self.parse() to ensure errors, if any, have been detected before
check in ok()
+
+
+version 0.6.2
+-------------
+
+* Migration to user selectors instead of select, allowing higher scale
operations
+* Improved netconf:base:1.1 parsing
+* Graceful exit on session close
+
+
version 0.6.0
-------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/README new/ncclient-0.6.9/README
--- old/ncclient-0.6.7/README 2019-12-21 20:16:07.000000000 +0100
+++ new/ncclient-0.6.9/README 1970-01-01 01:00:00.000000000 +0100
@@ -1,90 +0,0 @@
-[](https://travis-ci.org/einarnn/ncclient)
-
-ncclient: Python library for NETCONF clients
---------------------------------------------
-
-ncclient is a Python library that facilitates client-side scripting
-and application development around the NETCONF protocol. `ncclient` was
-developed by [Shikar Bhushan](http://schmizz.net). It is now maintained
-by [Leonidas Poulopoulos (@leopoul)](http://ncclient.org/ncclient/)
-
-**Docs**: [http://ncclient.readthedocs.org](http://ncclient.readthedocs.org)
-
-**PyPI**:
[https://pypi.python.org/pypi/ncclient](https://pypi.python.org/pypi/ncclient)
-
-#### Requirements:
-* Python 2.7 or Python 3.4+
-* setuptools 0.6+
-* Paramiko 1.7+
-* lxml 3.3.0+
-* libxml2
-* libxslt
-
-If you are on Debian/Ubuntu install the following libs (via aptitude or
apt-get):
-* libxml2-dev
-* libxslt1-dev
-
-#### Installation:
-
- [ncclient] $ sudo python setup.py install
-
-or via pip:
-
- pip install ncclient
-
-#### Examples:
-
- [ncclient] $ python examples/juniper/*.py
-
-### Usage
-####Get device running config
-Use either an interactive Python console (ipython)
-or integrate the following in your code:
-
- from ncclient import manager
-
- with manager.connect(host=host, port=830, username=user,
hostkey_verify=False) as m:
- c = m.get_config(source='running').data_xml
- with open("%s.xml" % host, 'w') as f:
- f.write(c)
-
-As of 0.4.1 ncclient integrates Juniper's and Cisco's forks, lots of new
concepts
-have been introduced that ease management of Juniper and Cisco devices
respectively.
-The biggest change is the introduction of device handlers in connection
paramms.
-For example to invoke Juniper's functions annd params one has to re-write the
above with ***device_params={'name':'junos'}***:
-
- from ncclient import manager
-
- with manager.connect(host=host, port=830, username=user,
hostkey_verify=False, device_params={'name':'junos'}) as m:
- c = m.get_config(source='running').data_xml
- with open("%s.xml" % host, 'w') as f:
- f.write(c)
-
-Device handlers are easy to implement and prove to be futureproof.
-
-####Supported device handlers
-
-* Juniper: device_params={'name':'junos'}
-* Cisco CSR: device_params={'name':'csr'}
-* Cisco Nexus: device_params={'name':'nexus'}
-* Huawei: device_params={'name':'huawei'}
-* Alcatel Lucent: device_params={'name':'alu'}
-* H3C: device_params={'name':'h3c'}
-* HP Comware: device_params={'name':'hpcomware'}
-
-
-### Changes | brief - v0.5.3
-
-* Add notifications support
-* Add support for ecdsa keys
-* Various bug fixes
-
-### Contributors
-* v0.5.3: [Justin Wilcox](https://github.com/jwwilcox), [Stacy W.
Smith](https://github.com/stacywsmith), [Mircea
Ulinic](https://github.com/mirceaulinic), [Ebben
Aries](https://github.com/earies), [Einar
Nilsen-Nygaard](https://github.com/einarnn),
[QijunPan](https://github.com/QijunPan)
-* v0.5.2: [Nitin Kumar](https://github.com/vnitinv), [Kristian
Larsson](https://github.com/plajjan),
[palashgupta](https://github.com/palashgupta), [Jonathan
Provost](https://github.com/JoProvost),
[Jainpriyal](https://github.com/Jainpriyal),
[sharang](https://github.com/sharang), [pseguel](https://github.com/pseguel),
[nnakamot](https://github.com/nnakamot), [Алексей
Пастухов](https://github.com/p-alik), [Christian
Giese](https://github.com/GIC-de), [Peipei Guo](https://github.com/peipeiguo),
[Time Warner Cable Openstack Team](https://github.com/twc-openstack)
-* v0.4.7: [Einar Nilsen-Nygaard](https://github.com/einarnn), [Vaibhav
Bajpai](https://github.com/vbajpai), Norio Nakamoto
-* v0.4.6: [Nitin Kumar](https://github.com/vnitinv), [Carl
Moberg](https://github.com/cmoberg), [Stavros
Kroustouris](https://github.com/kroustou)
-* v0.4.5: [Sebastian Wiesinger](https://github.com/sebastianw), [Vincent
Bernat](https://github.com/vincentbernat), [Matthew
Stone](https://github.com/bigmstone), [Nitin Kumar](https://github.com/vnitinv)
-* v0.4.3: [Jeremy Schulman](https://github.com/jeremyschulman), [Ray
Solomon](https://github.com/rsolomo), [Rick
Sherman](https://github.com/shermdog), [subhak186](https://github.com/subhak186)
-* v0.4.2: [katharh](https://github.com/katharh), [Francis Luong
(Franco)](https://github.com/francisluong), [Vincent
Bernat](https://github.com/vincentbernat), [Juergen
Brendel](https://github.com/juergenbrendel), [Quentin
Loos](https://github.com/Kent1), [Ray Solomon](https://github.com/rsolomo),
[Sebastian Wiesinger](https://github.com/sebastianw), [Ebben
Aries](https://github.com/earies)
-* v0.4.1: [Jeremy Schulman](https://github.com/jeremyschulman), [Ebben
Aries](https://github.com/earies), Juergen Brendel
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/README.md new/ncclient-0.6.9/README.md
--- old/ncclient-0.6.7/README.md 2019-12-21 20:16:07.000000000 +0100
+++ new/ncclient-0.6.9/README.md 2020-08-09 00:09:16.000000000 +0200
@@ -19,6 +19,8 @@
| Date | Release | Description |
| :----: | :-----: | :---------- |
+| 08/08/20 | `0.6.9` | See [release
page](https://github.com/ncclient/ncclient/releases/tag/v0.6.9) |
+| 08/01/20 | `0.6.8` | Pulled due to accidental breaking API change |
| 12/21/19 | `0.6.7` | See [release
page](https://github.com/ncclient/ncclient/releases/tag/v0.6.7) |
| 05/27/19 | `0.6.6` | See [release
page](https://github.com/ncclient/ncclient/releases/tag/v0.6.6) |
| 05/27/19 | `0.6.5` | Pulled due to bug in PyPi upload |
@@ -186,6 +188,7 @@
## Contributors
+* v0.6.8: [Fred Gan](https://github.com/fredgan), @vnitinv, @kbijakowski,
@iwanb, @badguy99, @liuyong, Andrew Mallory, William Lvory
* v0.6.7: @vnitinv, @chaitu-tk, @sidhujasminder, @crutcha, @markgoddard,
@ganeshrn, @songxl, @doesitblend, @psikala, @xuxiaowei0512, @muffizone
* v0.6.6: @sstancu, @hemna, @ishayansheikh
* v0.6.4: @davidhankins, @mzagozen, @knobix, @markafarrell, @psikala,
@moepman, @apt-itude, @yuekyang
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/README.rst
new/ncclient-0.6.9/README.rst
--- old/ncclient-0.6.7/README.rst 2019-12-21 20:16:07.000000000 +0100
+++ new/ncclient-0.6.9/README.rst 2020-08-09 00:09:16.000000000 +0200
@@ -3,8 +3,9 @@
ncclient is a Python library that facilitates client-side scripting and
application development around the NETCONF protocol. ``ncclient`` was
-developed by `Shikar Bhushan <http://schmizz.net>`_. It is now
-maintained by `Leonidas Poulopoulos (@leopoul) <http://ncclient.org>`_
+developed by `Shikar Bhushan <http://schmizz.net>`. It is now
+maintained by `Leonidas Poulopoulos (@leopoul) <http://ncclient.org>`
+and `Einar Nilsen-Nygaard (@einarnn)`.
Docs:
`http://ncclient.readthedocs.org <http://ncclient.readthedocs.org>`_
@@ -86,17 +87,80 @@
Supported device handlers
'''''''''''''''''''''''''
-* Juniper: device_params={'name':'junos'}
-* Cisco CSR: device_params={'name':'csr'}
-* Cisco Nexus: device_params={'name':'nexus'}
-* Huawei: device_params={'name':'huawei'}
-* Alcatel Lucent: device_params={'name':'alu'}
-* H3C: device_params={'name':'h3c'}
-* HP Comware: device_params={'name':'hpcomware'}
+* Juniper: `device_params={'name':'junos'}`
+* Cisco:
+ - CSR: `device_params={'name':'csr'}`
+ - Nexus: `device_params={'name':'nexus'}`
+ - IOS XR: `device_params={'name':'iosxr'}`
+ - IOS XE: `device_params={'name':'iosxe'}`
+* Huawei:
+ - `device_params={'name':'huawei'}`
+ - `device_params={'name':'huaweiyang'}`
+* Alcatel Lucent: `device_params={'name':'alu'}`
+* H3C: `device_params={'name':'h3c'}`
+* HP Comware: `device_params={'name':'hpcomware'}`
+* Server or anything not in above: `device_params={'name':'default'}`
Changes \| brief
~~~~~~~~~~~~~~~~
+**v0.6.9**
+
+* Fix for breaking API change
+
+**v0.6.8**
+
+* Pulled due to accidental breaking API change
+* Variety of small updates and bugfixes, but of note:
+ - Support for namespace prefixes for XPath queries
+ - `edit-config` parameter validation
+ - Support for multiple RPC errors
+ - API to get supported device types
+ - Support for subtree filters with multiple top-level tags
+* Thanks to all contributors!
+
+**v0.6.7**
+
+- Variety of bugfixes from a variety of contributors since 0.6.6 (see commit
history)
+
+**v0.6.6**
+
+- Read ssh timeout from config file if not specified in method call
+- Tox support
+- Huge XML tree parser support
+- Adding optional bind address to connect
+
+**v0.6.5**
+
+- Updated README for 0.6.5 release
+
+**v0.6.4**
+
+- Pin selectors2 to Python versions <= 3.4
+- Fix config examples to actually use the nc namespace
+- Fix: correctly set port for paramiko when using ssh_config file
+- Test: add test to check ProxyCommand uses correct port
+- Update commits for py3
+- Enhance Alcatel-Lucent-support
+- Juniper RPC: allow specifying format in CompareConfiguration
+- Parsing of NETCONF 1.1 frames no longer decodes each chunk of bytes
+- Fix filter in create_subscription
+- Validate 'with-defaults' mode based on supported modes advertised in
capability URI
+
+**v0.6.3**
+
+- Fix homepage link registered with PyPi
+- SSH Host Key checking
+- Updated junos.py to resolve RestrictedUser error
+- Close the channel when closing SSH session
+- Invoke self.parse() to ensure errors, if any, have been detected before
check in ok()
+
+**v0.6.2**
+
+- Migration to user selectors instead of select, allowing higher scale
operations
+- Improved netconf:base:1.1 parsing
+- Graceful exit on session close
+
**v0.6.0**
- Fix use of new Python 3.7 keyword, async
@@ -180,7 +244,13 @@
Acknowledgements
~~~~~~~~~~~~~~~~
-
+- v0.6.9: [Fred Gan](https://github.com/fredgan)
+- v0.6.8: [Fred Gan](https://github.com/fredgan), @vnitinv, @kbijakowski,
@iwanb, @badguy99, @liuyong, Andrew Mallory, William Lvory
+- v0.6.7: @vnitinv, @chaitu-tk, @sidhujasminder, @crutcha, @markgoddard,
@ganeshrn, @songxl, @doesitblend, @psikala, @xuxiaowei0512, @muffizone
+- v0.6.6: @sstancu, @hemna, @ishayansheikh
+- v0.6.4: @davidhankins, @mzagozen, @knobix, @markafarrell, @psikala,
@moepman, @apt-itude, @yuekyang
+- v0.6.3: @rdkls, @Anthony25, @rsmekala, @vnitinv, @siming85
+- v0.6.2: @einarnn, @glennmatthews, @bryan-stripe, @nickylba
- v0.6.0: `Einar Nilsen-Nygaard`_
- v0.5.4: Various
- v0.5.3: `Justin Wilcox`_, `Stacy W. Smith`_, `Mircea Ulinic`_,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/docs/requirements.txt
new/ncclient-0.6.9/docs/requirements.txt
--- old/ncclient-0.6.7/docs/requirements.txt 1970-01-01 01:00:00.000000000
+0100
+++ new/ncclient-0.6.9/docs/requirements.txt 2020-08-09 00:09:16.000000000
+0200
@@ -0,0 +1,2 @@
+Sphinx==3.2.0
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/docs/source/conf.py
new/ncclient-0.6.9/docs/source/conf.py
--- old/ncclient-0.6.7/docs/source/conf.py 2019-12-21 20:16:07.000000000
+0100
+++ new/ncclient-0.6.9/docs/source/conf.py 2020-08-09 00:09:16.000000000
+0200
@@ -46,9 +46,9 @@
# built documents.
#
# The short X.Y version.
-version = '0.5'
+version = '0.6'
# The full version, including alpha/beta/rc tags.
-release = '0.5.3'
+release = '0.6.9'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/docs/source/index.rst
new/ncclient-0.6.9/docs/source/index.rst
--- old/ncclient-0.6.7/docs/source/index.rst 2019-12-21 20:16:07.000000000
+0100
+++ new/ncclient-0.6.9/docs/source/index.rst 2020-08-09 00:09:16.000000000
+0200
@@ -3,7 +3,7 @@
`ncclient` is a Python library for NETCONF clients. It aims to offer an
intuitive API that sensibly maps the XML-encoded nature of NETCONF to Python
constructs and idioms, and make writing network-management scripts easier.
Other key features are:
-* Supports all operations and capabilities defined in :rfc:`4741`.
+* Supports all operations and capabilities defined in :rfc:`6241`.
* Request pipelining.
* Asynchronous RPC requests.
* Keeping XML out of the way unless really needed.
@@ -39,10 +39,19 @@
Supported device handlers
-------------------------
-* Juniper: device_params={'name':'junos'}
-* Cisco CSR: device_params={'name':'csr'}
-* Cisco Nexus: device_params={'name':'nexus'}
-* Huawei: device_params={'name':'huawei'}
+* Juniper: `device_params={'name':'junos'}`
+* Cisco:
+ - CSR: `device_params={'name':'csr'}`
+ - Nexus: `device_params={'name':'nexus'}`
+ - IOS XR: `device_params={'name':'iosxr'}`
+ - IOS XE: `device_params={'name':'iosxe'}`
+* Huawei:
+ - `device_params={'name':'huawei'}`
+ - `device_params={'name':'huaweiyang'}`
+* Alcatel Lucent: `device_params={'name':'alu'}`
+* H3C: `device_params={'name':'h3c'}`
+* HP Comware: `device_params={'name':'hpcomware'}`
+* Server or anything not in above: `device_params={'name':'default'}`
Contents:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/docs/source/manager.rst
new/ncclient-0.6.9/docs/source/manager.rst
--- old/ncclient-0.6.7/docs/source/manager.rst 2019-12-21 20:16:07.000000000
+0100
+++ new/ncclient-0.6.9/docs/source/manager.rst 2020-08-09 00:09:16.000000000
+0200
@@ -40,37 +40,79 @@
.. autoattribute:: HUGE_TREE_DEFAULT
- .. automethod:: get_config(source, filter=None)
+ .. method:: get_config(source, filter=None, with_defaults=None)
- .. automethod:: edit_config(target, config, default_operation=None,
test_option=None, error_option=None)
+ `get_config` is mapped to :class:`~ncclient.operations.GetConfig`
- .. automethod:: copy_config(source, target)
+ .. method:: get_schema(identifier, version=None, format=None)
- .. automethod:: delete_config(target)
+ `get_schema` is mapped to :class:`~ncclient.operations.GetSchema`
- .. automethod:: dispatch(rpc_command, source=None, filter=None)
+ .. method:: edit_config(config, format='xml', target='candidate',
default_operation=None, test_option=None, error_option=None)
- .. automethod:: lock(target)
+ `edit_config` is mapped to :class:`~ncclient.operations.EditConfig`
- .. automethod:: unlock(target)
+ .. method:: copy_config(source, target)
- .. automethod:: locked(target)
+ `copy_config` is mapped to :class:`~ncclient.operations.CopyConfig`
+
+ .. method:: delete_config(target)
+
+ `delete_config` is mapped to :class:`~ncclient.operations.DeleteConfig`
+
+ .. method:: dispatch(rpc_command, source=None, filter=None)
+
+ `dispatch` is mapped to :class:`~ncclient.operations.Dispatch`
+
+ .. method:: lock(target="candidate")
+
+ `lock` is mapped to :class:`~ncclient.operations.Lock`
+
+ .. method:: unlock(target="candidate")
+
+ `unlock` is mapped to :class:`~ncclient.operations.Unlock`
+
+ .. method:: get(filter=None, with_defaults=None)
+
+ `get` is mapped to :class:`~ncclient.operations.Get`
+
+ .. method:: close_session()
+
+ `close_session` is mapped to :class:`~ncclient.operations.CloseSession`
- .. automethod:: get()
+ .. method:: kill_session(session_id)
- .. automethod:: close_session()
+ `kill_session` is mapped to :class:`~ncclient.operations.KillSession`
- .. automethod:: kill_session(session_id)
+ .. method:: commit(confirmed=False, timeout=None, persist=None,
persist_id=None)
- .. automethod:: commit(confirmed=False, timeout=None, persist=None)
+ `commit` is mapped to :class:`~ncclient.operations.Commit`
- .. automethod:: cancel_commit(persist_id=None)
+ .. method:: cancel_commit(persist_id=None)
- .. automethod:: discard_changes()
+ `cancel_commit` is mapped to :class:`~ncclient.operations.CancelCommit`
- .. automethod:: validate(source)
+ .. method:: discard_changes()
- .. automethod:: create_subscription()
+ `discard_changes` is mapped to
:class:`~ncclient.operations.DiscardChanges`
+
+ .. method:: validate(source="candidate")
+
+ `validate` is mapped to :class:`~ncclient.operations.Validate`
+
+ .. method:: create_subscription(filter=None, stream_name=None,
start_time=None, stop_time=None)
+
+ `create_subscription` is mapped to
:class:`~ncclient.operations.CreateSubscription`
+
+ .. method:: reboot_machine()
+
+ `reboot_machine` is mapped to
:class:`~ncclient.operations.RebootMachine`
+
+ .. method:: poweroff_machine()
+
+ `poweroff_machine` is mapped to
:class:`~ncclient.operations.PoweroffMachine`
+
+ .. automethod:: locked(target)
.. automethod:: take_notification(block=True, timeout=None)
@@ -115,7 +157,13 @@
Here *type* has to be one of `"xpath"` or `"subtree"`.
- * For `"xpath"` the *criteria* should be a string containing the XPath
expression.
+ * For `"xpath"` the *criteria* should be a string containing the XPath
expression or a tuple containing a dict of namespace mapping and the XPath
expression.
* For `"subtree"` the *criteria* should be an XML string or an
:class:`~xml.etree.ElementTree.Element` object containing the criteria.
+* A list of *spec*
+
+ Here *type* has to be `"subtree"`.
+
+ * the *spec* should be a list containing multiple XML string or multiple
:class:`~xml.etree.ElementTree.Element` objects.
+
* A `<filter>` element as an XML string or an
:class:`~xml.etree.ElementTree.Element` object.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/docs/source/operations.rst
new/ncclient-0.6.9/docs/source/operations.rst
--- old/ncclient-0.6.7/docs/source/operations.rst 2019-12-21
20:16:07.000000000 +0100
+++ new/ncclient-0.6.9/docs/source/operations.rst 2020-08-09
00:09:16.000000000 +0200
@@ -48,6 +48,12 @@
.. autoattribute:: REPLY_CLS
+.. autoclass:: GetSchema
+ :members: request
+ :show-inheritance:
+
+ .. autoattribute:: REPLY_CLS
+
Editing
........
@@ -79,6 +85,17 @@
:members: request
:show-inheritance:
+Flowmon
+........
+
+.. autoclass:: PoweroffMachine
+ :members: request
+ :show-inheritance:
+
+.. autoclass:: RebootMachine
+ :members: request
+ :show-inheritance:
+
Locking
........
@@ -101,6 +118,13 @@
:members: request
:show-inheritance:
+Subscribing
+............
+
+.. autoclass:: CreateSubscription
+ :members: request
+ :show-inheritance:
+
Exceptions
----------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/ncclient/__init__.py
new/ncclient-0.6.9/ncclient/__init__.py
--- old/ncclient-0.6.7/ncclient/__init__.py 2019-12-21 20:16:07.000000000
+0100
+++ new/ncclient-0.6.9/ncclient/__init__.py 2020-08-09 00:09:16.000000000
+0200
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-__version__ = (0,5,3)
+__version__ = (0,6,9)
import sys
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/ncclient/_version.py
new/ncclient-0.6.9/ncclient/_version.py
--- old/ncclient-0.6.7/ncclient/_version.py 2019-12-21 20:16:07.000000000
+0100
+++ new/ncclient-0.6.9/ncclient/_version.py 2020-08-09 00:09:16.000000000
+0200
@@ -23,9 +23,9 @@
# setup.py/versioneer.py will grep for the variable names, so they must
# each be defined on a line of their own. _version.py will just call
# get_keywords().
- git_refnames = " (tag: v0.6.7)"
- git_full = "8d4cc7195a8160a1e35b4307b8b08c5de3dec97f"
- git_date = "2019-12-21 19:16:07 +0000"
+ git_refnames = " (HEAD -> master, tag: v0.6.9)"
+ git_full = "3380f1140791f4a8de5d303f919f1e4cc9532f32"
+ git_date = "2020-08-08 23:09:16 +0100"
keywords = {"refnames": git_refnames, "full": git_full, "date": git_date}
return keywords
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/ncclient/capabilities.py
new/ncclient-0.6.9/ncclient/capabilities.py
--- old/ncclient-0.6.7/ncclient/capabilities.py 2019-12-21 20:16:07.000000000
+0100
+++ new/ncclient-0.6.9/ncclient/capabilities.py 2020-08-09 00:09:16.000000000
+0200
@@ -13,7 +13,6 @@
# limitations under the License.
import logging
-import sys
import six
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/ncclient/devices/__init__.py
new/ncclient-0.6.9/ncclient/devices/__init__.py
--- old/ncclient-0.6.7/ncclient/devices/__init__.py 2019-12-21
20:16:07.000000000 +0100
+++ new/ncclient-0.6.9/ncclient/devices/__init__.py 2020-08-09
00:09:16.000000000 +0200
@@ -0,0 +1,19 @@
+# supported devices config, add new device (eg: 'device name':'device lable').
+supported_devices_cfg = {'junos':'Juniper',
+ 'csr':'Cisco CSR1000v',
+ 'nexus':'Cisco Nexus',
+ 'iosxr':'Cisco IOS XR',
+ 'iosxe':'Cisco IOS XE',
+ 'huawei':'Huawei',
+ 'huaweiyang':'Huawei',
+ 'alu':'Alcatel Lucent',
+ 'h3c':'H3C',
+ 'hpcomware':'HP Comware',
+ 'default':'Server or anything not in above'}
+
+def get_supported_devices():
+ return tuple(supported_devices_cfg.keys())
+
+def get_supported_device_labels():
+ return supported_devices_cfg
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/ncclient/devices/csr.py
new/ncclient-0.6.9/ncclient/devices/csr.py
--- old/ncclient-0.6.7/ncclient/devices/csr.py 2019-12-21 20:16:07.000000000
+0100
+++ new/ncclient-0.6.9/ncclient/devices/csr.py 2020-08-09 00:09:16.000000000
+0200
@@ -28,6 +28,4 @@
super(CsrDeviceHandler, self).__init__(device_params)
def add_additional_ssh_connect_params(self, kwargs):
- kwargs['allow_agent'] = False
- kwargs['look_for_keys'] = False
kwargs['unknown_host_cb'] = csr_unknown_host_cb
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/ncclient/devices/h3c.py
new/ncclient-0.6.9/ncclient/devices/h3c.py
--- old/ncclient-0.6.7/ncclient/devices/h3c.py 2019-12-21 20:16:07.000000000
+0100
+++ new/ncclient-0.6.9/ncclient/devices/h3c.py 2020-08-09 00:09:16.000000000
+0200
@@ -1,19 +1,17 @@
"""
-Handler for Huawei device specific information.
+Handler for H3c device specific information.
Note that for proper import, the classname has to be:
"<Devicename>DeviceHandler"
-...where <Devicename> is something like "Default", "Huawei", etc.
+...where <Devicename> is something like "Default", "H3c", etc.
All device-specific handlers derive from the DefaultDeviceHandler, which
implements the
generic information needed for interaction with a Netconf server.
"""
-from ncclient.xml_ import BASE_NS_1_0
-
from .default import DefaultDeviceHandler
from ncclient.operations.third_party.h3c.rpc import *
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/ncclient/devices/iosxe.py
new/ncclient-0.6.9/ncclient/devices/iosxe.py
--- old/ncclient-0.6.7/ncclient/devices/iosxe.py 2019-12-21
20:16:07.000000000 +0100
+++ new/ncclient-0.6.9/ncclient/devices/iosxe.py 2020-08-09
00:09:16.000000000 +0200
@@ -35,6 +35,4 @@
return dict
def add_additional_ssh_connect_params(self, kwargs):
- kwargs['allow_agent'] = False
- kwargs['look_for_keys'] = False
kwargs['unknown_host_cb'] = iosxe_unknown_host_cb
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/ncclient/devices/iosxr.py
new/ncclient-0.6.9/ncclient/devices/iosxr.py
--- old/ncclient-0.6.7/ncclient/devices/iosxr.py 2019-12-21
20:16:07.000000000 +0100
+++ new/ncclient-0.6.9/ncclient/devices/iosxr.py 2020-08-09
00:09:16.000000000 +0200
@@ -28,9 +28,6 @@
super(IosxrDeviceHandler, self).__init__(device_params)
def add_additional_ssh_connect_params(self, kwargs):
- kwargs['allow_agent'] = False
- kwargs['look_for_keys'] = False
- kwargs['hostkey_verify'] = False
kwargs['unknown_host_cb'] = iosxr_unknown_host_cb
def perform_qualify_check(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/ncclient/manager.py
new/ncclient-0.6.9/ncclient/manager.py
--- old/ncclient-0.6.7/ncclient/manager.py 2019-12-21 20:16:07.000000000
+0100
+++ new/ncclient-0.6.9/ncclient/manager.py 2020-08-09 00:09:16.000000000
+0200
@@ -18,10 +18,8 @@
It exposes all core functionality.
"""
-from ncclient import capabilities
from ncclient import operations
from ncclient import transport
-import six
import logging
import functools
@@ -57,8 +55,6 @@
operations to the :class:`Manager` API.
"""
-VENDOR_OPERATIONS = {}
-
def make_device_handler(device_params):
"""
@@ -131,8 +127,6 @@
device_handler = make_device_handler(device_params)
device_handler.add_additional_ssh_connect_params(kwds)
- global VENDOR_OPERATIONS
- VENDOR_OPERATIONS.update(device_handler.add_additional_operations())
session = transport.SSHSession(device_handler)
if "hostkey_verify" not in kwds or kwds["hostkey_verify"]:
session.load_known_hosts()
@@ -157,8 +151,6 @@
device_handler = make_device_handler(device_params)
- global VENDOR_OPERATIONS
- VENDOR_OPERATIONS.update(device_handler.add_additional_operations())
session = third_party_import.IOProc(device_handler)
session.connect()
@@ -180,7 +172,7 @@
"""
For details on the expected behavior of the operations and their
- parameters refer to :rfc:`4741`.
+ parameters refer to :rfc:`6241`.
Manager instances are also context managers so you can use it like this::
@@ -209,6 +201,9 @@
self._raise_mode = operations.RaiseMode.ALL
self._huge_tree = self.HUGE_TREE_DEFAULT
self._device_handler = device_handler
+ self._vendor_operations = {}
+ if device_handler:
+
self._vendor_operations.update(device_handler.add_additional_operations())
def __enter__(self):
return self
@@ -259,8 +254,8 @@
raise NotImplementedError
def __getattr__(self, method):
- if method in VENDOR_OPERATIONS:
- return functools.partial(self.execute, VENDOR_OPERATIONS[method])
+ if method in self._vendor_operations:
+ return functools.partial(self.execute,
self._vendor_operations[method])
elif method in OPERATIONS:
return functools.partial(self.execute, OPERATIONS[method])
else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/ncclient/operations/edit.py
new/ncclient-0.6.9/ncclient/operations/edit.py
--- old/ncclient-0.6.7/ncclient/operations/edit.py 2019-12-21
20:16:07.000000000 +0100
+++ new/ncclient-0.6.9/ncclient/operations/edit.py 2020-08-09
00:09:16.000000000 +0200
@@ -39,7 +39,7 @@
*default_operation* if specified must be one of { `"merge"`,
`"replace"`, or `"none"` }
- *test_option* if specified must be one of { `"test_then_set"`, `"set"`
}
+ *test_option* if specified must be one of { `"test-then-set"`,
`"set"`, `"test-only"` }
*error_option* if specified must be one of { `"stop-on-error"`,
`"continue-on-error"`, `"rollback-on-error"` }
@@ -47,25 +47,25 @@
"""
node = new_ele("edit-config")
node.append(util.datastore_or_url("target", target, self._assert))
- if default_operation is not None:
- # TODO: check if it is a valid default-operation
+ if (default_operation is not None
+ and util.validate_args('default_operation', default_operation,
["merge", "replace", "none"]) is True):
sub_ele(node, "default-operation").text = default_operation
- if test_option is not None:
+ if (test_option is not None
+ and util.validate_args('test_option', test_option,
["test-then-set", "set", "test-only"]) is True):
self._assert(':validate')
+ if test_option == 'test-only':
+ self._assert(':validate:1.1')
sub_ele(node, "test-option").text = test_option
- if error_option is not None:
+ if (error_option is not None
+ and util.validate_args('error_option', error_option,
["stop-on-error", "continue-on-error", "rollback-on-error"]) is True):
if error_option == "rollback-on-error":
self._assert(":rollback-on-error")
sub_ele(node, "error-option").text = error_option
-# <<<<<<< HEAD
-# node.append(validated_element(config, ("config", qualify("config"))))
-# =======
if format == 'xml':
node.append(validated_element(config, ("config",
qualify("config"))))
if format == 'text':
config_text = sub_ele(node, "config-text")
sub_ele(config_text, "configuration-text").text = config
-# >>>>>>> juniper
return self._request(node)
@@ -149,8 +149,8 @@
*persist_id* value must be equal to the value given in the <persist>
parameter to the original <commit> operation.
"""
node = new_ele("commit")
- if (confirmed or persist) and persist_id:
- raise OperationError("Invalid operation as confirmed or persist
cannot be present with persist-id")
+ if persist and persist_id:
+ raise OperationError("Invalid operation as persist cannot be
present with persist-id")
if confirmed:
self._assert(":confirmed-commit")
sub_ele(node, "confirmed")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/ncclient/operations/retrieve.py
new/ncclient-0.6.9/ncclient/operations/retrieve.py
--- old/ncclient-0.6.7/ncclient/operations/retrieve.py 2019-12-21
20:16:07.000000000 +0100
+++ new/ncclient-0.6.9/ncclient/operations/retrieve.py 2020-08-09
00:09:16.000000000 +0200
@@ -74,7 +74,7 @@
*filter* specifies the portion of the configuration to retrieve (by
default entire configuration is retrieved)
- *with_defaults* defines an explicit method of retrieving default
values from the configuration (see RFC 6243)
+ *with_defaults* defines an explicit method of retrieving default
values from the configuration (see :rfc:`6243`)
:seealso: :ref:`filter_params`
"""
@@ -149,7 +149,7 @@
*filter* specifies the portion of the configuration to retrieve (by
default entire configuration is retrieved)
- *with_defaults* defines an explicit method of retrieving default
values from the configuration (see RFC 6243)
+ *with_defaults* defines an explicit method of retrieving default
values from the configuration (see :rfc:`6243`)
:seealso: :ref:`filter_params`"""
node = new_ele("get-config")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/ncclient/operations/rpc.py
new/ncclient-0.6.9/ncclient/operations/rpc.py
--- old/ncclient-0.6.7/ncclient/operations/rpc.py 2019-12-21
20:16:07.000000000 +0100
+++ new/ncclient-0.6.9/ncclient/operations/rpc.py 2020-08-09
00:09:16.000000000 +0200
@@ -14,7 +14,6 @@
from threading import Event, Lock
from uuid import uuid4
-import six
from ncclient.xml_ import *
from ncclient.logging_ import SessionLoggerAdapter
@@ -33,6 +32,7 @@
tag_to_attr = {
qualify("error-type"): "_type",
qualify("error-tag"): "_tag",
+ qualify("error-app-tag"): "_app_tag",
qualify("error-severity"): "_severity",
qualify("error-info"): "_info",
qualify("error-path"): "_path",
@@ -43,6 +43,7 @@
self._raw = raw
if errs is None:
# Single RPCError
+ self._errlist = None
for attr in six.itervalues(RPCError.tag_to_attr):
setattr(self, attr, None)
for subele in raw:
@@ -55,6 +56,7 @@
OperationError.__init__(self, self.to_dict())
else:
# Multiple errors returned. Errors is a list of RPCError objs
+ self._errlist = errs
errlist = []
for err in errs:
if err.severity:
@@ -96,6 +98,11 @@
return self._tag
@property
+ def app_tag(self):
+ "The contents of the `error-app-tag` element."
+ return self._app_tag
+
+ @property
def severity(self):
"The contents of the `error-severity` element."
return self._severity
@@ -115,6 +122,11 @@
"XML string or `None`; representing the `error-info` element."
return self._info
+ @property
+ def errlist(self):
+ "List of errors if this represents multiple errors, otherwise None."
+ return self._errlist
+
class RPCReply(object):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/ncclient/operations/util.py
new/ncclient-0.6.9/ncclient/operations/util.py
--- old/ncclient-0.6.7/ncclient/operations/util.py 2019-12-21
20:16:07.000000000 +0100
+++ new/ncclient-0.6.9/ncclient/operations/util.py 2020-08-09
00:09:16.000000000 +0200
@@ -49,13 +49,23 @@
type = None
if isinstance(spec, tuple):
type, criteria = spec
- rep = new_ele("filter", type=type)
if type == "xpath":
- rep.attrib["select"] = criteria
+ if isinstance(criteria, tuple):
+ ns, select = criteria
+ rep = new_ele_nsmap("filter", ns, type=type)
+ rep.attrib["select"] = select
+ else:
+ rep = new_ele("filter", type=type)
+ rep.attrib["select"]=criteria
elif type == "subtree":
+ rep = new_ele("filter", type=type)
rep.append(to_ele(criteria))
else:
raise OperationError("Invalid filter type")
+ elif isinstance(spec, list):
+ rep = new_ele("filter", type="subtree")
+ for cri in spec:
+ rep.append(to_ele(cri))
else:
rep = validated_element(spec, ("filter", qualify("filter"),
@@ -67,3 +77,9 @@
if type == "xpath" and capcheck is not None:
capcheck(":xpath")
return rep
+
+def validate_args(arg_name, value, args_list):
+ # this is a common method, which used to check whether a value is in
args_list
+ if value not in args_list:
+ raise OperationError('Invalid value "%s" in "%s" element' % (value,
arg_name))
+ return True
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/ncclient/transport/session.py
new/ncclient-0.6.9/ncclient/transport/session.py
--- old/ncclient-0.6.7/ncclient/transport/session.py 2019-12-21
20:16:07.000000000 +0100
+++ new/ncclient-0.6.9/ncclient/transport/session.py 2020-08-09
00:09:16.000000000 +0200
@@ -14,8 +14,6 @@
# limitations under the License.
-import re
-import sys
import logging
from threading import Thread, Lock, Event
try:
@@ -72,10 +70,12 @@
else:
self.logger.error('error parsing dispatch message: %s', e)
return
+ self.logger.debug('dispatching message to different listeners: %s',
+ raw)
with self._lock:
listeners = list(self._listeners)
for l in listeners:
- self.logger.debug('dispatching message to %r: %s', l, raw)
+ self.logger.debug('dispatching message to listener: %r', l)
l.callback(root, raw) # no try-except; fail loudly if you must!
def _dispatch_error(self, err):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/ncclient/transport/ssh.py
new/ncclient-0.6.9/ncclient/transport/ssh.py
--- old/ncclient-0.6.7/ncclient/transport/ssh.py 2019-12-21
20:16:07.000000000 +0100
+++ new/ncclient-0.6.9/ncclient/transport/ssh.py 2020-08-09
00:09:16.000000000 +0200
@@ -322,7 +322,7 @@
host_port = '[%s]:%s' % (host, port)
known_host_keys_for_this_host.update(self._host_keys.lookup(host_port) or {})
if known_host_keys_for_this_host:
- self._transport._preferred_keys = [x.key.get_name() for x in
known_host_keys_for_this_host._entries]
+ self._transport._preferred_keys =
list(known_host_keys_for_this_host)
# Connect
try:
@@ -349,7 +349,7 @@
is_known_host = any(self._host_keys.check(lookup,
server_key_obj) for lookup in known_hosts_lookups)
if not is_known_host and not unknown_host_cb(host, fingerprint):
- raise SSHUnknownHostError(known_hosts_lookup[0], fingerprint)
+ raise SSHUnknownHostError(known_hosts_lookups[0], fingerprint)
# Authenticating with our private key/identity
if key_filename is None:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/ncclient-0.6.7/ncclient/transport/third_party/junos/ioproc.py
new/ncclient-0.6.9/ncclient/transport/third_party/junos/ioproc.py
--- old/ncclient-0.6.7/ncclient/transport/third_party/junos/ioproc.py
2019-12-21 20:16:07.000000000 +0100
+++ new/ncclient-0.6.9/ncclient/transport/third_party/junos/ioproc.py
2020-08-09 00:09:16.000000000 +0200
@@ -1,4 +1,3 @@
-import os
import sys
import re
import six
@@ -7,7 +6,6 @@
from cStringIO import StringIO
else:
from io import BytesIO as StringIO
-from select import select
if sys.version>='2.7':
from subprocess import Popen, check_output, PIPE, STDOUT
else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/ncclient-0.6.7/ncclient/transport/third_party/junos/parser.py
new/ncclient-0.6.9/ncclient/transport/third_party/junos/parser.py
--- old/ncclient-0.6.7/ncclient/transport/third_party/junos/parser.py
2019-12-21 20:16:07.000000000 +0100
+++ new/ncclient-0.6.9/ncclient/transport/third_party/junos/parser.py
2020-08-09 00:09:16.000000000 +0200
@@ -33,12 +33,10 @@
import logging
logger = logging.getLogger("ncclient.transport.third_party.junos.parser")
+from ncclient.xml_ import BASE_NS_1_0
-class RPCTags:
- RPC_REPLY_END_TAG = "</rpc-reply>"
- RPC_REPLY_END_TAG_LEN = len(RPC_REPLY_END_TAG)
- RPC_REPLY_START_TAG = "<rpc-reply"
- NAMESPACES = {"nc": "urn:ietf:params:xml:ns:netconf:base:1.0"}
+RPC_REPLY_END_TAG = "</rpc-reply>"
+RFC_RPC_REPLY_END_TAG = "</nc:rpc-reply>"
class JunosXMLParser(DefaultXMLParser):
@@ -47,7 +45,6 @@
self._session = session
self.sax_parser = make_parser()
self.sax_parser.setContentHandler(SAXParser(session))
- self.rpc_tags = RPCTags
def parse(self, data):
try:
@@ -82,9 +79,11 @@
# we need to renew parser, as old parser is gone.
self.sax_parser = make_parser()
self.sax_parser.setContentHandler(SAXParser(self._session))
- elif self.rpc_tags.RPC_REPLY_END_TAG in data:
+ elif RPC_REPLY_END_TAG in data or RFC_RPC_REPLY_END_TAG in data:
+ tag = RPC_REPLY_END_TAG if RPC_REPLY_END_TAG in data else \
+ RFC_RPC_REPLY_END_TAG
logger.warning("Check for rpc reply end tag within data received:
%s" % data)
- msg, delim, remaining =
data.partition(self.rpc_tags.RPC_REPLY_END_TAG)
+ msg, delim, remaining = data.partition(tag)
self._session._buffer.seek(0, os.SEEK_END)
self._session._buffer.write(remaining.encode())
else:
@@ -94,9 +93,13 @@
# if then, wait for next iteration of data and do a recursive call
to
# _delimiter_check for MSG_DELIM check
buf = self._session._buffer
- buf.seek(buf.tell() - self.rpc_tags.RPC_REPLY_END_TAG_LEN -
MSG_DELIM_LEN)
+ buf.seek(buf.tell() - len(RFC_RPC_REPLY_END_TAG) - MSG_DELIM_LEN)
rpc_response_last_msg = buf.read().decode('UTF-8').replace('\n',
'')
- if self.rpc_tags.RPC_REPLY_END_TAG in rpc_response_last_msg:
+ if RPC_REPLY_END_TAG in rpc_response_last_msg or \
+ RFC_RPC_REPLY_END_TAG in rpc_response_last_msg:
+ tag = RPC_REPLY_END_TAG if RPC_REPLY_END_TAG in \
+ rpc_response_last_msg else \
+ RFC_RPC_REPLY_END_TAG
# rpc_response_last_msg and data can be overlapping
match_obj = difflib.SequenceMatcher(None,
rpc_response_last_msg,
data).get_matching_blocks()
@@ -114,9 +117,7 @@
# as first if condition will add full delimiter,
so clean
# it off
clean_up = len(rpc_response_last_msg) - (
- rpc_response_last_msg.find(
- self.rpc_tags.RPC_REPLY_END_TAG) +
- self.rpc_tags.RPC_REPLY_END_TAG_LEN)
+ rpc_response_last_msg.find(tag) + len(tag))
self._session._buffer.truncate(buf.tell() -
clean_up)
self._delimiter_check(data.encode())
else:
@@ -193,12 +194,12 @@
self._session = session
self._validate_reply_and_sax_tag = False
self._lock = Lock()
+ self.nc_namespace = None
def startElement(self, tag, attributes):
if tag in ['rpc-reply', 'nc:rpc-reply']:
if tag == 'nc:rpc-reply':
- RPCTags.RPC_REPLY_END_TAG = "</nc:rpc-reply>"
- RPCTags.RPC_REPLY_START_TAG = "<nc:rpc-reply"
+ self.nc_namespace = BASE_NS_1_0
# in case last rpc called used sax parsing and error'd out
# without resetting use_filer in endElement rpc-reply check
with self._lock:
@@ -222,7 +223,7 @@
if self._cur == self._root and self._cur.tag == tag:
node = self._root
else:
- node = self._cur.find(tag, namespaces=RPCTags.NAMESPACES)
+ node = self._cur.find(tag, namespaces={"nc": self.nc_namespace})
if self._validate_reply_and_sax_tag:
if tag != self._root.tag:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/ncclient/xml_.py
new/ncclient-0.6.9/ncclient/xml_.py
--- old/ncclient-0.6.7/ncclient/xml_.py 2019-12-21 20:16:07.000000000 +0100
+++ new/ncclient-0.6.9/ncclient/xml_.py 2020-08-09 00:09:16.000000000 +0200
@@ -223,11 +223,17 @@
parser=self.__parser)
return self.__root
+def parent_ns(node):
+ if node.prefix:
+ return node.nsmap[node.prefix]
+ return None
+
+new_ele_nsmap = lambda tag, nsmap, attrs={}, **extra:
etree.Element(qualify(tag), attrs, nsmap, **extra)
new_ele = lambda tag, attrs={}, **extra: etree.Element(qualify(tag), attrs,
**extra)
new_ele_ns = lambda tag, ns, attrs={}, **extra: etree.Element(qualify(tag,ns),
attrs, **extra)
-sub_ele = lambda parent, tag, attrs={}, **extra: etree.SubElement(parent,
qualify(tag), attrs, **extra)
+sub_ele = lambda parent, tag, attrs={}, **extra: etree.SubElement(parent,
qualify(tag, parent_ns(parent)), attrs, **extra)
sub_ele_ns = lambda parent, tag, ns, attrs={}, **extra:
etree.SubElement(parent, qualify(tag, ns), attrs, **extra)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/setup.py new/ncclient-0.6.9/setup.py
--- old/ncclient-0.6.7/setup.py 2019-12-21 20:16:07.000000000 +0100
+++ new/ncclient-0.6.9/setup.py 2020-08-09 00:09:16.000000000 +0200
@@ -49,7 +49,7 @@
author=__author__,
author_email=__author_email__,
url="https://github.com/ncclient/ncclient",
- packages=find_packages('.'),
+ packages=find_packages(exclude=['test', 'test.*']),
install_requires=install_reqs,
tests_require=test_reqs,
license=__licence__,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/test/unit/devices/test_default.py
new/ncclient-0.6.9/test/unit/devices/test_default.py
--- old/ncclient-0.6.7/test/unit/devices/test_default.py 2019-12-21
20:16:07.000000000 +0100
+++ new/ncclient-0.6.9/test/unit/devices/test_default.py 2020-08-09
00:09:16.000000000 +0200
@@ -37,6 +37,24 @@
def test_handle_connection_exceptions(self):
self.assertFalse(self.obj.handle_connection_exceptions(None))
+ def test_is_rpc_error_exempt_1(self):
+ self.assertFalse(self.obj.is_rpc_error_exempt(None))
+
+ def test_is_rpc_error_exempt_2(self):
+ self.obj._exempt_errors_exact_match = ["test_exempt"]
+ self.assertTrue(self.obj.is_rpc_error_exempt(" Test_Exempt"))
+
+ def test_is_rpc_error_exempt_3(self):
+ self.obj._exempt_errors_startwith_wildcard_match = ["test_exempt"]
+ self.assertTrue(self.obj.is_rpc_error_exempt("*Test_Exempt"))
+
+ def test_is_rpc_error_exempt_4(self):
+ self.obj._exempt_errors_endwith_wildcard_match = ["test_exempt"]
+ self.assertTrue(self.obj.is_rpc_error_exempt("Test_Exempt*"))
+
+ def test_is_rpc_error_exempt_5(self):
+ self.obj._exempt_errors_full_wildcard_match = ["test_exempt"]
+ self.assertTrue(self.obj.is_rpc_error_exempt("*Test_Exempt*"))
suite = unittest.TestSuite()
unittest.TextTestRunner().run(suite)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/ncclient-0.6.7/test/unit/devices/test_get_supported_devices.py
new/ncclient-0.6.9/test/unit/devices/test_get_supported_devices.py
--- old/ncclient-0.6.7/test/unit/devices/test_get_supported_devices.py
1970-01-01 01:00:00.000000000 +0100
+++ new/ncclient-0.6.9/test/unit/devices/test_get_supported_devices.py
2020-08-09 00:09:16.000000000 +0200
@@ -0,0 +1,33 @@
+import unittest
+from ncclient import devices
+
+class TestGetSupportedDevices(unittest.TestCase):
+
+ def test_get_supported_devices(self):
+ supported_devices = devices.get_supported_devices()
+ self.assertEqual(sorted(supported_devices), sorted(('junos',
+ 'csr',
+ 'nexus',
+ 'iosxr',
+ 'iosxe',
+ 'huawei',
+ 'huaweiyang',
+ 'alu',
+ 'h3c',
+ 'hpcomware',
+ 'default')))
+
+ def test_get_supported_device_labels(self):
+ supported_device_labels = devices.get_supported_device_labels()
+ self.assertEqual(supported_device_labels, {'junos':'Juniper',
+ 'csr':'Cisco CSR1000v',
+ 'nexus':'Cisco Nexus',
+ 'iosxr':'Cisco IOS XR',
+ 'iosxe':'Cisco IOS XE',
+ 'huawei':'Huawei',
+ 'huaweiyang':'Huawei',
+ 'alu':'Alcatel Lucent',
+ 'h3c':'H3C',
+ 'hpcomware':'HP Comware',
+ 'default':'Server or
anything not in above'})
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/test/unit/operations/test_edit.py
new/ncclient-0.6.9/test/unit/operations/test_edit.py
--- old/ncclient-0.6.7/test/unit/operations/test_edit.py 2019-12-21
20:16:07.000000000 +0100
+++ new/ncclient-0.6.9/test/unit/operations/test_edit.py 2020-08-09
00:09:16.000000000 +0200
@@ -52,12 +52,16 @@
host-name foo-bar;
}
"""
- obj.request(copy.deepcopy(root), format="text", target="running",
error_option="rollback-on-error",
- default_operation="default", test_option="test")
+ obj.request(copy.deepcopy(root),
+ format="text",
+ target="running",
+ error_option="rollback-on-error",
+ default_operation="merge",
+ test_option="test-then-set")
node = new_ele("edit-config")
node.append(util.datastore_or_url("target", "running"))
- sub_ele(node, "default-operation").text = "default"
- sub_ele(node, "test-option").text = "test"
+ sub_ele(node, "default-operation").text = "merge"
+ sub_ele(node, "test-option").text = "test-then-set"
sub_ele(node, "error-option").text = "rollback-on-error"
config_text = sub_ele(node, "config-text")
sub_ele(config_text, "configuration-text").text = root
@@ -66,6 +70,63 @@
call = ElementTree.tostring(call)
self.assertEqual(call, xml)
+ def test_edit_config_invalid_arguments_exception(self):
+ session = ncclient.transport.SSHSession(self.device_handler)
+ session._server_capabilities = [":rollback-on-error", ":validate",
":validate:1.1"]
+ obj = EditConfig(
+ session,
+ self.device_handler,
+ raise_mode=RaiseMode.ALL)
+ root = """
+ system {
+ host-name foo-bar;
+ }
+ """
+ #invalid argument "default_operation"
+ self.assertRaises(OperationError, obj.request,
+ copy.deepcopy(root),
+ format="xml",
+ target="running",
+ error_option="stop-on-error",
+ default_operation="create",
+ test_option="test-then-set")
+ #invalid argument "error_option"
+ self.assertRaises(OperationError, obj.request,
+ copy.deepcopy(root),
+ format="xml",
+ target="running",
+ error_option="commit-on-error",
+ default_operation="merge",
+ test_option="test-then-set")
+ #invalid argument "test_option"
+ self.assertRaises(OperationError, obj.request,
+ copy.deepcopy(root),
+ format="xml",
+ target="running",
+ error_option="stop-on-error",
+ default_operation="merge",
+ test_option="test")
+
+ def test_edit_config_validate_capability_exception(self):
+ session = ncclient.transport.SSHSession(self.device_handler)
+ session._server_capabilities = [":validate"]
+ obj = EditConfig(
+ session,
+ self.device_handler,
+ raise_mode=RaiseMode.ALL)
+ root = """
+ system {
+ host-name foo-bar;
+ }
+ """
+ self.assertRaises(MissingCapabilityError, obj.request,
+ copy.deepcopy(root),
+ format="xml",
+ target="running",
+ error_option="stop-on-error",
+ default_operation="merge",
+ test_option="test-only")
+
@patch('ncclient.operations.RPC._request')
def test_delete_config(self, mock_request):
session = ncclient.transport.SSHSession(self.device_handler)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/test/unit/operations/test_retrieve.py
new/ncclient-0.6.9/test/unit/operations/test_retrieve.py
--- old/ncclient-0.6.7/test/unit/operations/test_retrieve.py 2019-12-21
20:16:07.000000000 +0100
+++ new/ncclient-0.6.9/test/unit/operations/test_retrieve.py 2020-08-09
00:09:16.000000000 +0200
@@ -220,3 +220,43 @@
call = mock_request.call_args_list[0][0][0]
call = ElementTree.tostring(call)
self.assertEqual(call, xml)
+
+ @patch('ncclient.operations.retrieve.RPC._request')
+ def test_get_with_multi_subtree_filters(self, mock_request):
+ result = '''
+ <?xml version="1.0" encoding="UTF-8"?>
+ <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"
+ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <cont1 xmlns="urn:mod1">
+ <le1>test_mod1_001</le1>
+ <le2>this is a test-one example</le2>
+ </cont1>
+ <cont2 xmlns="urn:mod2">
+ <le1>test_mod2_002</le1>
+ <le2>this is a test-two example</le2>
+ <lst>
+ <le3>a list of mod2</le3>
+ </lst>
+ </cont2>
+ </data>'''
+ mock_request.return_value = result
+ session = ncclient.transport.SSHSession(self.device_handler)
+ obj = Get(session, self.device_handler, raise_mode=RaiseMode.ALL)
+
+ multi_subtree_filters = [
+ '<cont1 xmlns="urn:mod1"> \
+ <le1/> \
+ <le2/> \
+ </cont1>',
+ '<cont2 xmlns="urn:mod2"/>'
+ ]
+
+ ret = obj.request(copy.deepcopy(multi_subtree_filters))
+ node = new_ele("get")
+ node.append(util.build_filter(multi_subtree_filters))
+ xml = ElementTree.tostring(node)
+ call = mock_request.call_args_list[0][0][0]
+ call = ElementTree.tostring(call)
+ self.assertEqual(call, xml)
+ self.assertEqual(ret, result)
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/test/unit/operations/test_rpc.py
new/ncclient-0.6.9/test/unit/operations/test_rpc.py
--- old/ncclient-0.6.7/test/unit/operations/test_rpc.py 2019-12-21
20:16:07.000000000 +0100
+++ new/ncclient-0.6.9/test/unit/operations/test_rpc.py 2020-08-09
00:09:16.000000000 +0200
@@ -89,6 +89,31 @@
<configuration-text
xmlns="http://xml.juniper.net/xnm/1.1/xnm">%s</configuration-text>
</rpc-reply>""" % escape(huge_configuration_text)
+xml6 = """<rpc-error xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <error-type>application</error-type>
+ <error-tag>invalid-value</error-tag>
+ <error-severity>error</error-severity>
+ <error-path>path/to/node</error-path>
+ <error-info>
+ <bad-element>system1</bad-element>
+ </error-info>
+ <error-app-tag>app-tag1</error-app-tag>
+ <error-message>syntax error</error-message>
+ </rpc-error>
+"""
+
+xml7 = """<rpc-error xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <error-type>protocol</error-type>
+ <error-tag>missing-element</error-tag>
+ <error-severity>error</error-severity>
+ <error-path>path/to/different/node</error-path>
+ <error-info>
+ <bad-element>system2</bad-element>
+ </error-info>
+ <error-app-tag>app-tag2</error-app-tag>
+ <error-message>missing element error</error-message>
+ </rpc-error>
+"""
class TestRPC(unittest.TestCase):
@@ -180,6 +205,50 @@
obj.deliver_error(err)
self.assertRaises(RPCError, obj._request, node)
+ def test_rpc_rpcerror_tag_to_attr(self):
+ '''All elements in <rpc-error> extracted.'''
+ err = RPCError(to_ele(xml6))
+
+ self.assertEqual(None, err.errlist)
+
+ self.assertEqual("application", err.type)
+ self.assertEqual("invalid-value", err.tag)
+ self.assertEqual("error", err.severity)
+ self.assertEqual("path/to/node", err.path)
+ self.assertEqual("app-tag1", err.app_tag)
+ self.assertEqual("syntax error", err.message)
+ self.assertIn("<bad-element>system1</bad-element>", err.info)
+
+ def test_rpc_rpcerror_multiple_errors(self):
+ '''Multiple errors in <rpc-reply> extracted correctly'''
+ errlist = [RPCError(to_ele(xml6)), RPCError(to_ele(xml7))]
+
+ multiple_xml = (
+ '<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">' +
+ xml6 + xml7 +
+ "</rpc-reply>")
+
+ multiple_err = RPCError(to_ele(multiple_xml), errs=errlist)
+ errs = multiple_err.errlist
+
+ self.assertEqual(2, len(errs))
+
+ self.assertEqual("application", errs[0].type)
+ self.assertEqual("invalid-value", errs[0].tag)
+ self.assertEqual("error", errs[0].severity)
+ self.assertEqual("path/to/node", errs[0].path)
+ self.assertEqual("app-tag1", errs[0].app_tag)
+ self.assertEqual("syntax error", errs[0].message)
+ self.assertIn("<bad-element>system1</bad-element>", errs[0].info)
+
+ self.assertEqual("protocol", errs[1].type)
+ self.assertEqual("missing-element", errs[1].tag)
+ self.assertEqual("error", errs[1].severity)
+ self.assertEqual("path/to/different/node", errs[1].path)
+ self.assertEqual("app-tag2", errs[1].app_tag)
+ self.assertEqual("missing element error", errs[1].message)
+ self.assertIn("<bad-element>system2</bad-element>", errs[1].info)
+
@patch('ncclient.transport.Session.send')
@patch(patch_str)
def test_rpc_capability_error(self, mock_thread, mock_send):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/test/unit/operations/test_utils.py
new/ncclient-0.6.9/test/unit/operations/test_utils.py
--- old/ncclient-0.6.7/test/unit/operations/test_utils.py 2019-12-21
20:16:07.000000000 +0100
+++ new/ncclient-0.6.9/test/unit/operations/test_utils.py 2020-08-09
00:09:16.000000000 +0200
@@ -57,7 +57,7 @@
call = ElementTree.tostring(reply)
self.assertEqual(call, ElementTree.tostring(to_ele(xml)))
- def test_build_filter_2(self):
+ def test_build_filter_xpath(self):
criteria = "configuration/system"
filter = ("xpath", criteria)
reply = build_filter(filter)
@@ -66,7 +66,18 @@
node.attrib["select"] = criteria
self.assertEqual(call, ElementTree.tostring(node))
- def test_build_filter_3(self):
+ def test_build_filter_xpath_ns(self):
+ select = "configuration/system"
+ ns = {"ns0": "http://www.xxx.org"}
+ criteria = (ns, select)
+ filter = ("xpath", criteria)
+ reply = build_filter(filter)
+ call = ElementTree.tostring(reply)
+ node = new_ele_nsmap("filter", ns, type="xpath")
+ node.attrib["select"] = select
+ self.assertEqual(call, ElementTree.tostring(node))
+
+ def test_build_filter_subtree(self):
criteria = """<configuration>
<system>
<services/>
@@ -79,7 +90,7 @@
node.append(to_ele(criteria))
self.assertEqual(call, ElementTree.tostring(node))
- def test_build_filter_4(self):
+ def test_build_filter_other(self):
criteria = """<configuration>
<system>
<services/>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/test/unit/test_manager.py
new/ncclient-0.6.9/test/unit/test_manager.py
--- old/ncclient-0.6.7/test/unit/test_manager.py 2019-12-21
20:16:07.000000000 +0100
+++ new/ncclient-0.6.9/test/unit/test_manager.py 2020-08-09
00:09:16.000000000 +0200
@@ -26,6 +26,60 @@
manager.connect(host='host')
mock_ssh.assert_called_once_with(host='host')
+ @patch('ncclient.transport.SSHSession.load_known_hosts')
+ @patch('ncclient.transport.SSHSession.connect')
+ def test_connect_ssh1(self, mock_ssh, mock_load_known_hosts):
+ manager.connect(host='host')
+ mock_ssh.assert_called_once_with(host='host')
+ mock_load_known_hosts.assert_called_once_with()
+
+ @patch('ncclient.transport.SSHSession.connect')
+ @patch('ncclient.transport.SSHSession.transport')
+ @patch('ncclient.transport.SSHSession.close')
+ def test_connect_exception(self, mock_close, mock_transport, mock_ssh):
+ mock_ssh.side_effect = Exception
+ try:
+ manager.connect(host='host')
+ except Exception:
+ Exception("connect occured exception")
+ mock_ssh.assert_called_once_with(host='host')
+
+ @patch('ncclient.transport.SSHSession.connect')
+ @patch('ncclient.transport.SSHSession.take_notification')
+ def test_manager_take_notification(self, mock_take_notification, mock_ssh):
+ mock_take_notification.return_value = "test_take_notification"
+ conn = self._mock_manager()
+ ret = conn.take_notification()
+ mock_take_notification.assert_called_once_with(True, None)
+ self.assertEqual(ret, "test_take_notification")
+
+ @patch('ncclient.transport.SSHSession.connect')
+ @patch('ncclient.operations.retrieve.GetConfig._request')
+ def test_manager_getattr(self, mock_request, mock_ssh):
+ conn = self._mock_manager()
+ conn.get_config("running")
+ mock_ssh.assert_called_once_with(host='10.10.10.10',
+ port=22,
+ username='user',
+ password='password',
+ timeout=3,
+ hostkey_verify=False,
+ allow_agent=False)
+
+ @patch('ncclient.transport.SSHSession.connect')
+
@patch('ncclient.operations.third_party.juniper.rpc.GetConfiguration._request')
+ @patch('ncclient.operations.third_party.juniper.rpc.ExecuteRpc._request')
+ def test_manager_getattr2(self, mock_rpc, mock_request, mock_ssh):
+ conn = self._mock_manager()
+ conn.get_edit('config')
+ mock_ssh.assert_called_once_with(host='10.10.10.10',
+ port=22,
+ username='user',
+ password='password',
+ timeout=3,
+ hostkey_verify=False,
+ allow_agent=False)
+
@patch('ncclient.manager.connect_ssh')
def test_connect_ssh_with_hostkey_ed25519(self, mock_ssh):
hostkey =
'AAAAC3NzaC1lZDI1NTE5AAAAIIiHpGSf8fla6tCwLpwshvMGmUK+B/0v5CsRu+5v4uT7'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/test/unit/test_xml_.py
new/ncclient-0.6.9/test/unit/test_xml_.py
--- old/ncclient-0.6.7/test/unit/test_xml_.py 2019-12-21 20:16:07.000000000
+0100
+++ new/ncclient-0.6.9/test/unit/test_xml_.py 2020-08-09 00:09:16.000000000
+0200
@@ -176,3 +176,16 @@
result_xml = result.data_xml
self.assertRaises(XMLError,
validated_element, result_xml, tags=["rpc"])
+
+ def test_sub_ele_inherit_parent_namespace(self):
+ device_params = {'name': 'junos'}
+ device_handler = manager.make_device_handler(device_params)
+ transform_reply = device_handler.transform_reply()
+ result = NCElement(self.reply, transform_reply)
+ ele = new_ele_ns(result.find("./cli").tag, "http://www.xxx.org")
+ child = sub_ele(ele, "child")
+ sibling = sub_ele(ele, "sibling")
+ grandchild = sub_ele(child, "grandchild")
+ self.assertEqual(child.tag, "{http://www.xxx.org}child")
+ self.assertEqual(sibling.tag, "{http://www.xxx.org}sibling")
+ self.assertEqual(grandchild.tag, "{http://www.xxx.org}grandchild")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/test/unit/transport/test_session.py
new/ncclient-0.6.9/test/unit/transport/test_session.py
--- old/ncclient-0.6.7/test/unit/transport/test_session.py 2019-12-21
20:16:07.000000000 +0100
+++ new/ncclient-0.6.9/test/unit/transport/test_session.py 2020-08-09
00:09:16.000000000 +0200
@@ -76,6 +76,26 @@
self.assertNotEqual(
mock_log.call_args_list[0][0][0].find("error parsing dispatch
message"), -1)
+ @patch('ncclient.transport.session.parse_root')
+ @patch('ncclient.devices.junos.JunosDeviceHandler.handle_raw_dispatch')
+ @patch('ncclient.transport.session.HelloHandler.errback')
+ @patch('ncclient.logging_.SessionLoggerAdapter.debug')
+ def test_dispatch_message_error2(self, mock_log, mock_errback,
+ mock_handle_raw_dispatch,
mock_parse_root):
+ mock_parse_root.side_effect = Exception
+ mock_handle_raw_dispatch.return_value = Exception()
+ mock_errback.side_effect = Exception
+ cap = [':candidate']
+ obj = Session(cap)
+ device_handler = JunosDeviceHandler({'name': 'junos'})
+ obj._device_handler = device_handler
+ listener = HelloHandler(None, None)
+ obj._listeners.add(listener)
+ obj._dispatch_message(rpc_reply)
+ mock_handle_raw_dispatch.assert_called_once_with(rpc_reply)
+ self.assertEqual(
+ mock_log.call_args_list[0][0][0].find("error dispatching to"), -1)
+
@patch('ncclient.transport.session.HelloHandler.errback')
def test_dispatch_error(self, mock_handler):
cap = [':candidate']
@@ -105,6 +125,26 @@
log_args[0].find("server_capabilities="), -1)
self.assertEqual(log_args[2], [':candidate'])
+ @patch('ncclient.logging_.SessionLoggerAdapter.info')
+ @patch('ncclient.transport.session.Thread.start')
+ @patch('ncclient.transport.session.Event')
+ def test_post_connect2(self, mock_lock, mock_handler, mock_log):
+ cap = ['urn:ietf:params:netconf:base:1.1']
+ obj = Session(cap)
+ device_handler = JunosDeviceHandler({'name': 'junos'})
+ obj._device_handler = device_handler
+ obj._connected = True
+ obj._id = 100
+ obj._server_capabilities = cap
+ obj._post_connect()
+ log_args = mock_log.call_args_list[0][0]
+ self.assertNotEqual(log_args[0].find("initialized"), -1)
+ self.assertNotEqual(log_args[0].find("session-id="), -1)
+ self.assertEqual(log_args[1], 100)
+ self.assertNotEqual(
+ log_args[0].find("server_capabilities="), -1)
+ self.assertEqual(log_args[2], ['urn:ietf:params:netconf:base:1.1'])
+
def test_add_listener(self):
cap = [':candidate']
obj = Session(cap)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ncclient-0.6.7/test/unit/transport/test_ssh.py
new/ncclient-0.6.9/test/unit/transport/test_ssh.py
--- old/ncclient-0.6.7/test/unit/transport/test_ssh.py 2019-12-21
20:16:07.000000000 +0100
+++ new/ncclient-0.6.9/test/unit/transport/test_ssh.py 2020-08-09
00:09:16.000000000 +0200
@@ -267,6 +267,16 @@
obj.load_known_hosts()
mock_load.assert_called_once_with("file_name")
+ @patch('os.path.expanduser')
+ @patch('paramiko.hostkeys.HostKeys.load')
+ def test_load_host_key_IOError(self, mock_load, mock_os):
+ mock_os.return_value = "file_name"
+ mock_load.side_effect = IOError
+ device_handler = JunosDeviceHandler({'name': 'junos'})
+ obj = SSHSession(device_handler)
+ obj.load_known_hosts()
+ mock_load.assert_called_with("file_name")
+
@unittest.skipIf(sys.version_info.major == 2, "test not supported <
Python3")
@patch('ncclient.transport.ssh.SSHSession.close')
@patch('paramiko.channel.Channel.recv')