[Python-modules-commits] [pyiosxr] 01/03: Imported Upstream version 0.14

Vincent Bernat bernat at moszumanska.debian.org
Sat May 28 15:29:45 UTC 2016


This is an automated email from the git hooks/post-receive script.

bernat pushed a commit to branch master
in repository pyiosxr.

commit 39a7c8dad65c2a0a2f07848429c7246ff18edbf5
Author: Vincent Bernat <bernat at debian.org>
Date:   Sat May 28 17:25:06 2016 +0200

    Imported Upstream version 0.14
---
 MANIFEST.in                           |   1 +
 PKG-INFO                              |  12 +
 pyIOSXR.egg-info/PKG-INFO             |  12 +
 pyIOSXR.egg-info/SOURCES.txt          |  13 +
 pyIOSXR.egg-info/dependency_links.txt |   1 +
 pyIOSXR.egg-info/requires.txt         |   1 +
 pyIOSXR.egg-info/top_level.txt        |   1 +
 pyIOSXR/__init__.py                   |  15 ++
 pyIOSXR/exceptions.py                 |  31 +++
 pyIOSXR/iosxr.py                      | 338 ++++++++++++++++++++++++
 requirements.txt                      |   1 +
 setup.cfg                             |   8 +
 setup.py                              |  42 +++
 test/test.py                          | 467 ++++++++++++++++++++++++++++++++++
 14 files changed, 943 insertions(+)

diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..f9bd145
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1 @@
+include requirements.txt
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..93eaa0b
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,12 @@
+Metadata-Version: 1.1
+Name: pyIOSXR
+Version: 0.14
+Summary: Python API to interact with network devices running IOS-XR
+Home-page: https://github.com/fooelisa/pyiosxr/
+Author: Elisa Jasinska
+Author-email: elisa at bigwaveit.org
+License: UNKNOWN
+Download-URL: https://github.com/fooelisa/pyiosxr/tarball/0.14
+Description: UNKNOWN
+Keywords: IOS-XR,IOSXR,Cisco,networking
+Platform: UNKNOWN
diff --git a/pyIOSXR.egg-info/PKG-INFO b/pyIOSXR.egg-info/PKG-INFO
new file mode 100644
index 0000000..93eaa0b
--- /dev/null
+++ b/pyIOSXR.egg-info/PKG-INFO
@@ -0,0 +1,12 @@
+Metadata-Version: 1.1
+Name: pyIOSXR
+Version: 0.14
+Summary: Python API to interact with network devices running IOS-XR
+Home-page: https://github.com/fooelisa/pyiosxr/
+Author: Elisa Jasinska
+Author-email: elisa at bigwaveit.org
+License: UNKNOWN
+Download-URL: https://github.com/fooelisa/pyiosxr/tarball/0.14
+Description: UNKNOWN
+Keywords: IOS-XR,IOSXR,Cisco,networking
+Platform: UNKNOWN
diff --git a/pyIOSXR.egg-info/SOURCES.txt b/pyIOSXR.egg-info/SOURCES.txt
new file mode 100644
index 0000000..a29ed30
--- /dev/null
+++ b/pyIOSXR.egg-info/SOURCES.txt
@@ -0,0 +1,13 @@
+MANIFEST.in
+requirements.txt
+setup.cfg
+setup.py
+pyIOSXR/__init__.py
+pyIOSXR/exceptions.py
+pyIOSXR/iosxr.py
+pyIOSXR.egg-info/PKG-INFO
+pyIOSXR.egg-info/SOURCES.txt
+pyIOSXR.egg-info/dependency_links.txt
+pyIOSXR.egg-info/requires.txt
+pyIOSXR.egg-info/top_level.txt
+test/test.py
\ No newline at end of file
diff --git a/pyIOSXR.egg-info/dependency_links.txt b/pyIOSXR.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/pyIOSXR.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/pyIOSXR.egg-info/requires.txt b/pyIOSXR.egg-info/requires.txt
new file mode 100644
index 0000000..808fb07
--- /dev/null
+++ b/pyIOSXR.egg-info/requires.txt
@@ -0,0 +1 @@
+pexpect
diff --git a/pyIOSXR.egg-info/top_level.txt b/pyIOSXR.egg-info/top_level.txt
new file mode 100644
index 0000000..ba20151
--- /dev/null
+++ b/pyIOSXR.egg-info/top_level.txt
@@ -0,0 +1 @@
+pyIOSXR
diff --git a/pyIOSXR/__init__.py b/pyIOSXR/__init__.py
new file mode 100644
index 0000000..0c5f704
--- /dev/null
+++ b/pyIOSXR/__init__.py
@@ -0,0 +1,15 @@
+# Copyright 2015 Netflix. All rights reserved.
+#
+# The contents of this file are licensed under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with the
+# License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+from iosxr import IOSXR
diff --git a/pyIOSXR/exceptions.py b/pyIOSXR/exceptions.py
new file mode 100644
index 0000000..d19abf5
--- /dev/null
+++ b/pyIOSXR/exceptions.py
@@ -0,0 +1,31 @@
+# Copyright 2015 Netflix. All rights reserved.
+#
+# The contents of this file are licensed under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with the
+# License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+class UnknownError(Exception):
+    pass
+
+class InvalidInputError(Exception):
+    pass
+
+class XMLCLIError(Exception):
+    pass
+
+class TimeoutError(Exception):
+    pass
+
+class EOFError(Exception):
+    pass
+
+class IteratorIDError(Exception):
+	pass
diff --git a/pyIOSXR/iosxr.py b/pyIOSXR/iosxr.py
new file mode 100644
index 0000000..4bfd3a9
--- /dev/null
+++ b/pyIOSXR/iosxr.py
@@ -0,0 +1,338 @@
+# Copyright 2015 Netflix. All rights reserved.
+#
+# The contents of this file are licensed under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with the
+# License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+import re
+import sys
+import difflib
+import pexpect
+from exceptions import XMLCLIError, InvalidInputError, TimeoutError, EOFError, IteratorIDError
+
+import xml.etree.ElementTree as ET
+
+
+# Build and execute xml requests.
+def __execute_rpc__(device, rpc_command, timeout):
+    rpc_command = '<?xml version="1.0" encoding="UTF-8"?><Request MajorVersion="1" MinorVersion="0">'+rpc_command+'</Request>'
+    try:
+        device.sendline(rpc_command)
+        index = device.expect_exact(["</Response>","ERROR: 0xa240fe00"], timeout = timeout)
+        if index == 1:
+            raise XMLCLIError('The XML document is not well-formed')
+    except pexpect.TIMEOUT as e:
+        raise TimeoutError("pexpect timeout error")
+    except pexpect.EOF as e:
+        raise EOFError("pexpect EOF error")
+
+    #remove leading XML-agent prompt
+    response_assembled = device.before+device.match
+    response = re.sub('^[^<]*', '', response_assembled)
+
+    root = ET.fromstring(response)
+    if 'IteratorID' in root.attrib:
+        raise IteratorIDError("Non supported IteratorID in Response object. \
+Turn iteration off on your XML agent by configuring 'xml agent [tty | ssl] iteration off'. \
+For more information refer to http://www.cisco.com/c/en/us/td/docs/ios_xr_sw/iosxr_r4-1/xml/programming/guide/xl41apidoc.pdf, \
+7-99.Turn iteration off on your XML agent.")
+
+    childs = [x.tag for x in list(root)]
+
+    result_summary = root.find('ResultSummary')
+
+    if result_summary is not None and int(result_summary.get('ErrorCount', 0)) > 0:
+
+        if 'CLI' in childs:
+            error_msg = root.find('CLI').get('ErrorMsg') or ''
+        elif 'Commit' in childs:
+            error_msg = root.find('Commit').get('ErrorMsg') or ''
+        else:
+            error_msg = root.get('ErrorMsg') or ''
+
+        error_msg += '\nOriginal call was: %s' % rpc_command
+        raise XMLCLIError(error_msg)
+
+    if 'CLI' in childs:
+        cli_childs = [x.tag for x in list(root.find('CLI'))]
+        if 'Configuration' in cli_childs:
+            output = root.find('CLI').find('Configuration').text
+            if output is None:
+                output = ''
+            elif 'Invalid input detected' in output:
+                raise InvalidInputError('Invalid input entered:\n%s' % output)
+
+    return root
+
+# Ecexute show commands not in config context.
+def __execute_show__(device, show_command, timeout):
+    rpc_command = '<CLI><Exec>'+show_command+'</Exec></CLI>'
+    response = __execute_rpc__(device, rpc_command, timeout)
+    return response.find('CLI').find('Exec').text.lstrip()
+
+# Ecexute show commands not in config context.
+def __execute_config_show__(device, show_command, timeout):
+    rpc_command = '<CLI><Configuration>'+show_command+'</Configuration></CLI>'
+    response = __execute_rpc__(device, rpc_command, timeout)
+    return response.find('CLI').find('Configuration').text.lstrip()
+
+
+class IOSXR:
+
+    def __init__(self, hostname, username, password, port=22, timeout=60, logfile=None, lock=True):
+        """
+        A device running IOS-XR.
+
+        :param hostname:  (str) IP or FQDN of the device you want to connect to
+        :param username:  (str) Username
+        :param password:  (str) Password
+        :param port:      (int) SSH Port (default: 22)
+        :param timeout:   (int) Timeout (default: 60 sec)
+        :param logfile:   File-like object to save device communication to or None to disable logging
+        :param lock:      (bool) Auto-lock config upon open() if set to True, connect without locking if False (default: True)
+        """
+        self.hostname = str(hostname)
+        self.username = str(username)
+        self.password = str(password)
+        self.port     = int(port)
+        self.timeout  = int(timeout)
+        self.logfile  = logfile
+        self.lock_on_connect = lock
+        self.locked   = False
+
+    def __getattr__(self, item):
+        """
+        Ok, David came up with this kind of dynamic method. It takes
+        calls with show commands encoded in the name. I'll replacs the
+        underscores for spaces and issues the show command... pretty neat!
+
+        non keyword params for show command:
+          all non keyword arguments is added to the command to allow dynamic parameters:
+          eks: .show_interface("GigabitEthernet0/0/0/0")
+
+        keyword params for show command:
+          config=True/False :   set True to run show command in config mode
+          eks: .show_configuration_merge(config=True)
+
+        """
+        def wrapper(*args, **kwargs):
+            cmd = item.replace('_', ' ')
+            for arg in args:
+                cmd += " %s" % arg
+
+            if kwargs.get("config"):
+                response = __execute_config_show__(self.device, cmd, self.timeout)
+            else:
+                response = __execute_show__(self.device, cmd, self.timeout)
+
+            match = re.search(".*(!! IOS XR Configuration.*)</Exec>",response,re.DOTALL)
+
+            if match is not None:
+                response = match.group(1)
+            return response
+
+        if item.startswith('show'):
+            return wrapper
+        else:
+            raise AttributeError("type object '%s' has no attribute '%s'" % (self.__class__.__name__, item))
+
+    def make_rpc_call(self, rpc_command):
+        """
+        Allow a user to query a device directly using XML-requests
+        """
+        result = __execute_rpc__(self.device, rpc_command, self.timeout)
+        return ET.tostring(result)
+
+    def open(self):
+        """
+        Opens a connection to an IOS-XR device.
+        """
+        device = pexpect.spawn('ssh -o ConnectTimeout={} -p {} {}@{}'.format(self.timeout, self.port, self.username, self.hostname), logfile=self.logfile)
+        try:
+            index = device.expect(['\(yes\/no\)\?', 'password:', '#', pexpect.EOF], timeout = self.timeout)
+            if index == 0:
+                device.sendline('yes')
+                index = device.expect(['\(yes\/no\)\?', 'password:', '#', pexpect.EOF], timeout = self.timeout)
+            if index == 1:
+                device.sendline(self.password)
+            elif index == 3:
+                pass
+            if index != 2:
+                device.expect('#', timeout = self.timeout)
+            device.sendline('xml')
+            index = device.expect(['XML>', 'ERROR: 0x24319600'], timeout = self.timeout)
+            if index == 1:
+                raise XMLCLIError('XML TTY agent has not been started. Please configure \'xml agent tty\'.')
+        except pexpect.TIMEOUT as e:
+            raise TimeoutError("pexpect timeout error")
+        except pexpect.EOF as e:
+            raise EOFError("pexpect EOF error")
+        self.device = device
+        if self.lock_on_connect:
+            self.lock()
+
+    def close(self):
+        """
+        Closes the connection to the IOS-XR device.
+        """
+        if self.lock_on_connect or self.locked:
+            self.unlock()
+        self.device.close()
+
+    def lock(self):
+        """
+        Locks the IOS-XR device config.
+        """
+        if not self.locked:
+            rpc_command = '<Lock/>'
+            response = __execute_rpc__(self.device, rpc_command, self.timeout)
+            self.locked = True
+
+    def unlock(self):
+        """
+        Unlocks the IOS-XR device config.
+        """
+        if self.locked:
+            rpc_command = '<Unlock/>'
+            response = __execute_rpc__(self.device, rpc_command, self.timeout)
+            self.locked = False
+
+    def load_candidate_config(self, filename=None, config=None):
+        """
+        Populates the attribute candidate_config with the desired
+        configuration and loads it into the router. You can populate it from
+        a file or from a string. If you send both a filename and a string
+        containing the configuration, the file takes precedence.
+
+        :param filename:  Path to the file containing the desired
+                          configuration. By default is None.
+        :param config:    String containing the desired configuration.
+        """
+        configuration = ''
+
+        if filename is None:
+            configuration = config
+        else:
+            with open(filename) as f:
+                configuration = f.read()
+
+        rpc_command = '<CLI><Configuration>'+configuration+'</Configuration></CLI>'
+
+        try:
+            __execute_rpc__(self.device, rpc_command, self.timeout)
+        except InvalidInputError as e:
+            self.discard_config()
+            raise InvalidInputError(e.message)
+
+    def get_candidate_config(self, merge=False, formal=False):
+        """
+        Retrieve the configuration loaded as candidate config in your configuration session
+
+        :param merge:  Merge candidate config with running config to return
+                       the complete configuration including all changed
+        :param formal: Return configuration in IOS-XR formal config format
+        """
+        command="show configuration"
+        if merge:
+            command+=" merge"
+        if formal:
+            command+=" formal"
+        response =  __execute_config_show__(self.device, command, self.timeout)
+
+        match = re.search(".*(!! IOS XR Configuration.*)$",response,re.DOTALL)
+        if match is not None:
+            response = match.group(1)
+
+        return response
+
+    def compare_config(self):
+        """
+        Compares executed candidate config with the running config and
+        returns a diff, assuming the loaded config will be merged with the
+        existing one.
+
+        :return:  Config diff.
+        """
+        show_merge = __execute_config_show__(self.device, 'show configuration merge', self.timeout)
+        show_run = __execute_config_show__(self.device, 'show running-config', self.timeout)
+
+        diff = difflib.unified_diff(show_run.splitlines(1)[2:-2],show_merge.splitlines(1)[2:-2],n=0)
+        diff = ''.join([x.replace('\r', '') for x in diff])
+        return diff
+
+    def compare_replace_config(self):
+        """
+        Compares executed candidate config with the running config and
+        returns a diff, assuming the entire config will be replaced.
+
+        :return:  Config diff.
+        """
+        diff = __execute_config_show__(self.device, 'show configuration changes diff', self.timeout)
+
+        return ''.join(diff.splitlines(1)[2:-2])
+
+    def commit_config(self, label=None, comment=None, confirmed=None):
+        """
+        Commits the candidate config to the device, by merging it with the
+        existing one.
+
+        :param label:     Commit comment, displayed in the commit entry on the device.
+        :param comment:   Commit label, displayed instead of the commit ID on the device.
+        :param confirmed: Commit with auto-rollback if new commit is not made in 30 to 300 sec
+        """
+        rpc_command = '<Commit'
+        if label:
+            rpc_command += ' Label="%s"' % label
+        if comment:
+            rpc_command += ' Comment="%s"' % comment
+        if confirmed:
+            if 30 <= int(confirmed) <= 300:
+                rpc_command += ' Confirmed="%d"' % int(confirmed)
+            else: raise InvalidInputError('confirmed needs to be between 30 and 300')
+        rpc_command += '/>'
+
+        response = __execute_rpc__(self.device, rpc_command, self.timeout)
+
+    def commit_replace_config(self, label=None, comment=None, confirmed=None):
+        """
+        Commits the candidate config to the device, by replacing the existing
+        one.
+
+        :param comment:   User comment saved on this commit on the device
+        :param label:     User label saved on this commit on the device
+        :param confirmed: Commit with auto-rollback if new commit is not made in 30 to 300 sec
+        """
+        rpc_command = '<Commit Replace="true"'
+        if label:
+            rpc_command += ' Label="%s"' % label
+        if comment:
+            rpc_command += ' Comment="%s"' % comment
+        if confirmed:
+            if 30 <= int(confirmed) <= 300:
+                rpc_command += ' Confirmed="%d"' % int(confirmed)
+            else: raise InvalidInputError('confirmed needs to be between 30 and 300')
+        rpc_command += '/>'
+        response = __execute_rpc__(self.device, rpc_command, self.timeout)
+
+    def discard_config(self):
+        """
+        Clears uncommited changes in the current session.
+        """
+        rpc_command = '<Clear/>'
+        response = __execute_rpc__(self.device, rpc_command, self.timeout)
+
+    def rollback(self):
+        """
+        Used after a commit, the configuration will be reverted to the
+        previous committed state.
+        """
+        rpc_command = '<Unlock/><Rollback><Previous>1</Previous></Rollback><Lock/>'
+        response = __execute_rpc__(self.device, rpc_command, self.timeout)
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..808fb07
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1 @@
+pexpect
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..8c9157d
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,8 @@
+[metadata]
+description-file = README.md
+
+[egg_info]
+tag_build = 
+tag_date = 0
+tag_svn_revision = 0
+
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..e674e3a
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,42 @@
+# Copyright 2015 Netflix. All rights reserved.
+#
+# The contents of this file are licensed under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with the
+# License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+from setuptools import setup, find_packages
+from pip.req import parse_requirements
+import uuid
+
+# parse_requirements() returns generator of pip.req.InstallRequirement objects
+install_reqs = parse_requirements('requirements.txt', session=uuid.uuid1())
+
+# reqs is a list of requirement
+# e.g. ['django==1.5.1', 'mezzanine==1.4.6']
+reqs = [str(ir.req) for ir in install_reqs]
+
+version = '0.14'
+
+setup(
+    name='pyIOSXR',
+    version=version,
+    py_modules=['pyIOSXR'],
+    packages=find_packages(),
+    install_requires=reqs,
+    include_package_data=True,
+    description = 'Python API to interact with network devices running IOS-XR',
+    author = 'Elisa Jasinska',
+    author_email = 'elisa at bigwaveit.org',
+    url = 'https://github.com/fooelisa/pyiosxr/', # use the URL to the github repo
+    download_url = 'https://github.com/fooelisa/pyiosxr/tarball/%s' % version,
+    keywords = ['IOS-XR', 'IOSXR', 'Cisco', 'networking'],
+    classifiers = [],
+)
diff --git a/test/test.py b/test/test.py
new file mode 100755
index 0000000..bfbff9f
--- /dev/null
+++ b/test/test.py
@@ -0,0 +1,467 @@
+#!/usr/bin/env python
+
+import sys
+import mock
+import unittest
+import xml.etree.ElementTree as ET
+
+import pexpect
+from pyIOSXR import IOSXR
+from pyIOSXR.exceptions import XMLCLIError, InvalidInputError, TimeoutError, EOFError, IteratorIDError
+
+
+## XXX TODO
+
+# def __execute_rpc__(device, rpc_command, timeout):
+# def __execute_show__(device, show_command, timeout):
+# def __execute_config_show__(device, show_command, timeout):
+
+# test class IOSXR
+#     def __getattr__(self, item):
+
+## XXX
+
+
+#     def __init__(self, hostname, username, password, port=22, timeout=60, logfile=None, lock=True):
+
+class TestInit(unittest.TestCase):
+
+    def test_init(self):
+        '''
+        Test pyiosxr class init
+        Should return True
+        '''
+        self.assertTrue(IOSXR(hostname='hostname', username='ejasinska', password='passwd'))
+
+    def test_init_no_lock(self):
+        '''
+        Test pyiosxr class init - woithout locking
+        Should return True
+        '''
+        self.assertTrue(IOSXR(hostname='hostname', username='ejasinska', password='passwd', lock=False))
+
+    def test_init_log_stdout(self):
+        '''
+        Test pyiosxr class init - log to stdout
+        Should return True
+        '''
+        self.assertTrue(IOSXR(hostname='hostname', username='ejasinska', password='passwd', logfile=sys.stdout))
+
+    def test_init_log_file(self):
+        '''
+        Test pyiosxr class init - log to file
+        Should return True
+        '''
+        self.assertTrue(IOSXR(hostname='hostname', username='ejasinska', password='passwd', logfile='filehandle'))
+
+    def test_init_port(self):
+        '''
+        Test pyiosxr class init - pass port number
+        Should return True
+        '''
+        self.assertTrue(IOSXR(hostname='hostname', username='ejasinska', password='passwd', port=22))
+
+    def test_init_timeout(self):
+        '''
+        Test pyiosxr class init - pass timeout
+        Should return True
+        '''
+        self.assertTrue(IOSXR(hostname='hostname', username='ejasinska', password='passwd', timeout=120))
+
+
+#     def open(self):
+
+class TestOpen(unittest.TestCase):
+
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn')
+    @mock.patch('pyIOSXR.iosxr.IOSXR.lock')
+    def test_open(self, mock_lock, mock_spawn):
+        '''
+        Test pyiosxr class open
+        Should return None
+        '''
+        device = IOSXR(hostname='hostname', username='ejasinska', password='passwd', port=22, timeout=60, logfile=None, lock=True)
+        self.assertIsNone(device.open())
+
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn')
+    def test_open_no_lock(self, mock_spawn):
+        '''
+        Test pyiosxr class open - without lock
+        Should return None
+        '''
+        device = IOSXR(hostname='hostname', username='ejasinska', password='passwd', port=22, timeout=60, logfile=None, lock=False)
+        self.assertIsNone(device.open())
+
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.__init__')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.expect')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.sendline')
+    def test_open_ssh_key_yes(self, mock_sendline, mock_expect, mock_spawn):
+        '''
+        Test pyiosxr class open - with ssh key warning
+        Should return Nona
+        '''
+        device = IOSXR(hostname='hostname', username='ejasinska', password='passwd', port=22, timeout=60, logfile=None, lock=False)
+        mock_spawn.return_value = None
+        mock_expect.return_value = 0
+        self.assertIsNone(device.open())
+
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.__init__')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.expect')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.sendline')
+    def test_open_no_passwd(self, mock_sendline, mock_expect, mock_spawn):
+        '''
+        Test pyiosxr class open - pexpect.EOF
+        Should return Nona
+        '''
+        device = IOSXR(hostname='hostname', username='ejasinska', password='passwd', port=22, timeout=60, logfile=None, lock=False)
+        mock_spawn.return_value = None
+        mock_expect.return_value = 3
+        self.assertIsNone(device.open())
+
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.__init__')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.expect')
+    def test_open_TimeoutError(self, mock_expect, mock_spawn):
+        '''
+        Test pyiosxr class open - raising pexpect.TIMEOUT
+        Should return TimeoutError
+        '''
+        device = IOSXR(hostname='hostname', username='ejasinska', password='passwd', port=22, timeout=60, logfile=None, lock=True)
+        mock_spawn.return_value = None
+        mock_expect.side_effect = pexpect.TIMEOUT('error')
+        self.assertRaises(TimeoutError, device.open)
+
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.__init__')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.expect')
+    def test_open_EOFError(self, mock_expect, mock_spawn):
+        '''
+        Test pyiosxr class open - raising pexpect.EOF
+        Should return EOFError
+        '''
+        device = IOSXR(hostname='hostname', username='ejasinska', password='passwd', port=22, timeout=60, logfile=None, lock=True)
+        mock_spawn.return_value = None
+        mock_expect.side_effect = pexpect.EOF('error')
+        self.assertRaises(EOFError, device.open)
+
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.__init__')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.expect')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.sendline')
+    def test_open_XMLCLIError(self, mock_sendline, mock_expect, mock_spawn):
+        '''
+        Test pyiosxr class open - error as if XML not enabled on device: ERROR: 0x24319600
+        Should return XMLCLIError
+        '''
+        device = IOSXR(hostname='hostname', username='ejasinska', password='passwd', port=22, timeout=60, logfile=None, lock=True)
+        mock_spawn.return_value = None
+        # expect returns 1 to raise XMLCLIError
+        mock_expect.return_value = 1
+        self.assertRaises(XMLCLIError, device.open)
+
+
+#     def close(self):
+
+class TestClose(unittest.TestCase):
+
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.__init__')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.expect')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.sendline')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.close')
+    def test_close(self, mock_close, mock_sendline, mock_expect, mock_spawn):
+        '''
+        Test pyiosxr class close
+        Should return None
+        '''
+        device = IOSXR(hostname='hostname', username='ejasinska', password='passwd', port=22, timeout=60, logfile=None, lock=False)
+        mock_spawn.return_value = None
+        device.open()
+        self.assertIsNone(device.close())
+
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.__init__')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.expect')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.sendline')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.close')
+    @mock.patch('pyIOSXR.iosxr.IOSXR.lock')
+    @mock.patch('pyIOSXR.iosxr.__execute_rpc__')
+    def test_close_locked(self, mock_rpc, mock_lock, mock_close, mock_sendline, mock_expect, mock_spawn):
+        '''
+        Test pyiosxr class close with lock
+        Should return None
+        '''
+        device = IOSXR(hostname='hostname', username='ejasinska', password='passwd', port=22, timeout=60, logfile=None, lock=True)
+        mock_spawn.return_value = None
+        device.open()
+        self.assertIsNone(device.close())
+
+
+#     def lock(self):
+
+class TestLock(unittest.TestCase):
+
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.__init__')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.expect')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.sendline')
+    @mock.patch('pyIOSXR.iosxr.__execute_rpc__')
+    def test_lock(self, mock_rpc, mock_sendline, mock_expect, mock_spawn):
+        '''
+        Test pyiosxr class lock
+        Should return None
+        '''
+        device = IOSXR(hostname='hostname', username='ejasinska', password='passwd', port=22, timeout=60, logfile=None, lock=False)
+        mock_spawn.return_value = None
+        device.open()
+        self.assertIsNone(device.lock())
+
+
+#     def unlock(self):
+
+class TestUnlock(unittest.TestCase):
+
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.__init__')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.expect')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.sendline')
+    @mock.patch('pyIOSXR.iosxr.IOSXR.lock')
+    @mock.patch('pyIOSXR.iosxr.__execute_rpc__')
+    def test_unlock(self, mock_rpc, mock_lock, mock_sendline, mock_expect, mock_spawn):
+        '''
+        Test pyiosxr class unlock
+        Should return None
+        '''
+        device = IOSXR(hostname='hostname', username='ejasinska', password='passwd', port=22, timeout=60, logfile=None, lock=True)
+        mock_spawn.return_value = None
+        device.open()
+        device.locked = True
+        self.assertIsNone(device.unlock())
+
+
+#     def discard_config(self):
+
+class TestDiscardConfig(unittest.TestCase):
+
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.__init__')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.expect')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.sendline')
+    @mock.patch('pyIOSXR.iosxr.__execute_rpc__')
+    def test_discard_config(self, mock_rpc, mock_sendline, mock_expect, mock_spawn):
+        '''
+        Test pyiosxr class discard_config
+        Should return None
+        '''
+        device = IOSXR(hostname='hostname', username='ejasinska', password='passwd', port=22, timeout=60, logfile=None, lock=False)
+        mock_spawn.return_value = None
+        device.open()
+        self.assertIsNone(device.discard_config())
+
+
+#     def rollback(self):
+
+class TestRollback(unittest.TestCase):
+
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.__init__')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.expect')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.sendline')
+    @mock.patch('pyIOSXR.iosxr.__execute_rpc__')
+    def test_rollback(self, mock_rpc, mock_sendline, mock_expect, mock_spawn):
+        '''
+        Test pyiosxr class rollback
+        Should return None
+        '''
+        device = IOSXR(hostname='hostname', username='ejasinska', password='passwd', port=22, timeout=60, logfile=None, lock=False)
+        mock_spawn.return_value = None
+        device.open()
+        self.assertIsNone(device.rollback())
+
+
+#     def make_rpc_call(self, rpc_command):
+
+class TestMakeRpcCall(unittest.TestCase):
+
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.__init__')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.expect')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.sendline')
+    @mock.patch('pyIOSXR.iosxr.__execute_rpc__')
+    def test_make_rpc_call(self, mock_rpc, mock_sendline, mock_expect, mock_spawn):
+        '''
+        Test pyiosxr class make_rpc_call
+        Should return True
+        '''
+        device = IOSXR(hostname='hostname', username='ejasinska', password='passwd', port=22, timeout=60, logfile=None, lock=False)
+        mock_spawn.return_value = None
+        mock_rpc.return_value = ET.fromstring('<xml></xml>')
+        device.open()
+        self.assertTrue(device.make_rpc_call("<Get><Operational><LLDP><NodeTable></NodeTable></LLDP></Operational></Get>"))
+
+
+#     def load_candidate_config(self, filename=None, config=None):
+
+class TestLoadCandidateConfig(unittest.TestCase):
+
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.__init__')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.expect')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.sendline')
+    @mock.patch('pyIOSXR.iosxr.__execute_rpc__')
+    def test_load_candidate_config_file(self, mock_rpc, mock_sendline, mock_expect, mock_spawn):
+        '''
+        Test pyiosxr class load_candidate_config
+        Should return None
+        '''
+        device = IOSXR(hostname='hostname', username='ejasinska', password='passwd', port=22, timeout=60, logfile=None, lock=False)
+        mock_spawn.return_value = None
+        device.open()
+        self.assertIsNone(device.load_candidate_config(filename='test/config.txt'))
+
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.__init__')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.expect')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.sendline')
+    @mock.patch('pyIOSXR.iosxr.__execute_rpc__')
+    def test_load_candidate_config(self, mock_rpc, mock_sendline, mock_expect, mock_spawn):
+        '''
+        Test pyiosxr class load_candidate_config
+        Should return None
+        '''
+        device = IOSXR(hostname='hostname', username='ejasinska', password='passwd', port=22, timeout=60, logfile=None, lock=False)
+        mock_spawn.return_value = None
+        device.open()
+        self.assertIsNone(device.load_candidate_config(config='config'))
+
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.__init__')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.expect')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.sendline')
+    @mock.patch('pyIOSXR.iosxr.IOSXR.discard_config')
+    @mock.patch('pyIOSXR.iosxr.__execute_rpc__')
+    def test_load_candidate_config_InvalidInputError(self, mock_rpc, mock_discard, mock_sendline, mock_expect, mock_spawn):
+        '''
+        Test pyiosxr class load_candidate_config
+        Should return InvalidInputError
+        '''
+        device = IOSXR(hostname='hostname', username='ejasinska', password='passwd', port=22, timeout=60, logfile=None, lock=False)
+        mock_spawn.return_value = None
+        mock_rpc.side_effect = InvalidInputError('error')
+        device.open()
+        self.assertRaises(InvalidInputError, device.load_candidate_config, config='config')
+
+
+#     def get_candidate_config(self, merge=False, formal=False):
+
+class TestGetCandidateConfig(unittest.TestCase):
+
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.__init__')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.expect')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.sendline')
+    @mock.patch('pyIOSXR.iosxr.__execute_config_show__')
+    def test_get_candidate_config(self, mock_config, mock_sendline, mock_expect, mock_spawn):
+        '''
+        Test pyiosxr class get_candidate_config
+        Should return True
+        '''
+        device = IOSXR(hostname='hostname', username='ejasinska', password='passwd', port=22, timeout=60, logfile=None, lock=False)
+        mock_spawn.return_value = None
+        device.open()
+        mock_config.return_value = '!! IOS XR Configuration'
+        self.assertTrue(device.get_candidate_config(merge=True, formal=True))
+
+
+#     def compare_config(self):
+
+class TestCompareConfig(unittest.TestCase):
+
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.__init__')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.expect')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.sendline')
+    @mock.patch('pyIOSXR.iosxr.__execute_config_show__')
+    def test_compare_config(self, mock_config, mock_sendline, mock_expect, mock_spawn):
+        '''
+        Test pyiosxr class compare_config
+        Should return True
+        '''
+        device = IOSXR(hostname='hostname', username='ejasinska', password='passwd', port=22, timeout=60, logfile=None, lock=False)
+        mock_spawn.return_value = None
+        device.open()
+        mock_config.return_value = ''
+        self.assertEqual('', device.compare_config())
+
+
+#     def compare_replace_config(self):
+
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.__init__')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.expect')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.sendline')
+    @mock.patch('pyIOSXR.iosxr.__execute_config_show__')
+    def test_compare_replace_config(self, mock_config, mock_sendline, mock_expect, mock_spawn):
+        '''
+        Test pyiosxr class compare_replace_config
+        Should return True
+        '''
+        device = IOSXR(hostname='hostname', username='ejasinska', password='passwd', port=22, timeout=60, logfile=None, lock=False)
+        mock_spawn.return_value = None
+        device.open()
+        mock_config.return_value = ''
+        self.assertEqual('', device.compare_replace_config())
+
+
+#     def commit_config(self, label=None, comment=None, confirmed=None):
+
+class TestCommitConfig(unittest.TestCase):
+
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.__init__')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.expect')
+    @mock.patch('pyIOSXR.iosxr.pexpect.spawn.sendline')
+    @mock.patch('pyIOSXR.iosxr.__execute_rpc__')
+    def test_commit_config(self, mock_rpc, mock_sendline, mock_expect, mock_spawn):
+        '''
+        Test pyiosxr class commit_config
+        Should return None
+        '''
+        device = IOSXR(hostname='hostname', username='ejasinska', password='passwd', port=22, timeout=60, logfile=None, lock=False)
+        mock_spawn.return_value = None
+        device.open()
+        self.assertIsNone(device.commit_config(label='label', comment='comment', confirmed=30))
+
... 50 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/pyiosxr.git



More information about the Python-modules-commits mailing list