Ejemplo n.º 1
0
def device(mock_connect, *args, **kwargs):
    """Juniper PyEZ Device Mock"""

    def get_facts():
        dev._facts = device_facts

    def mock_manager(*args, **kwargs):
        if 'device_params' in kwargs:
            # open connection
            device_params = kwargs['device_params']
            device_handler = make_device_handler(device_params)
            session = SSHSession(device_handler)
            return Manager(session, device_handler)
        elif args:
            # rpc request
            rpc_request = args[0].tag
            if rpc_request == "command":
                # CLI commands
                rpc_request = "%s_%s" % (rpc_request, args[0].text.replace(" ", "_"))
            if rpc_request in rpc_reply_dict:
                # result for rpc request is in dict
                reply = rpc_reply_dict[rpc_request]
                if isinstance(reply, Exception):
                    raise reply
                else:
                    xml = reply
            else:
                # get rpc result from file
                fname = os.path.join(os.getcwd(), 'tests', 'rpc-reply', rpc_request + '.xml')
                with open(fname, 'r') as f:
                    xml = f.read()
            rpc_reply = NCElement(xml, dev._conn._device_handler.transform_reply())
            return rpc_reply

    mock_connect.side_effect = mock_manager
    dev = Device(*args, **kwargs)
    dev.facts_refresh = get_facts
    dev.open()
    dev._conn.rpc = MagicMock(side_effect=mock_manager)
    # replace open/close with mock objects
    dev.open = MagicMock()
    dev.close = MagicMock()
    return dev
Ejemplo n.º 2
0
class Netconf(object):

    def __init__(self):
        if not HAS_PYEZ:
            raise NetworkError(
                msg='junos-eznc >= 1.2.2 is required but does not appear to be installed.  '
                'It can be installed using `pip install junos-eznc`'
            )
        if not HAS_JXMLEASE:
            raise NetworkError(
                msg='jxmlease is required but does not appear to be installed.  '
                'It can be installed using `pip install jxmlease`'
            )
        self.device = None
        self.config = None
        self._locked = False
        self._connected = False
        self.default_output = 'xml'

    def raise_exc(self, msg):
        if self.device:
            if self._locked:
                self.config.unlock()
            self.disconnect()
        raise NetworkError(msg)

    def connect(self, params, **kwargs):
        host = params['host']

        kwargs = dict()
        kwargs['port'] = params.get('port') or 830

        kwargs['user'] = params['username']

        if params['password']:
            kwargs['passwd'] = params['password']

        if params['ssh_keyfile']:
            kwargs['ssh_private_key_file'] = params['ssh_keyfile']

        kwargs['gather_facts'] = False

        try:
            self.device = Device(host, **kwargs)
            self.device.open()
        except ConnectError:
            exc = get_exception()
            self.raise_exc('unable to connect to %s: %s' % (host, str(exc)))

        self.config = Config(self.device)
        self._connected = True

    def disconnect(self):
        try:
            self.device.close()
        except AttributeError:
            pass
        self._connected = False

    ### Command methods ###

    def run_commands(self, commands):
        responses = list()

        for cmd in commands:
            meth = getattr(self, cmd.args.get('command_type'))
            responses.append(meth(str(cmd), output=cmd.output))

        for index, cmd in enumerate(commands):
            if cmd.output == 'xml':
                responses[index] = xml_to_json(responses[index])
            elif cmd.args.get('command_type') == 'rpc':
                responses[index] = str(responses[index].text).strip()
            elif 'RpcError' in responses[index]:
                raise NetworkError(responses[index])


        return responses

    def cli(self, commands, output='xml'):
        '''Send commands to the device.'''
        try:
            return self.device.cli(commands, format=output, warning=False)
        except (ValueError, RpcError):
            exc = get_exception()
            self.raise_exc('Unable to get cli output: %s' % str(exc))

    def rpc(self, command, output='xml'):
        name, kwargs = rpc_args(command)
        meth = getattr(self.device.rpc, name)
        reply = meth({'format': output}, **kwargs)
        return reply

    ### Config methods ###

    def get_config(self, config_format="text"):
        if config_format not in SUPPORTED_CONFIG_FORMATS:
            self.raise_exc(msg='invalid config format.  Valid options are '
                               '%s' % ', '.join(SUPPORTED_CONFIG_FORMATS))

        ele = self.rpc('get_configuration', output=config_format)

        if config_format == 'text':
            return unicode(ele.text).strip()
        else:
            return ele

    def load_config(self, config, commit=False, replace=False, confirm=None,
                    comment=None, config_format='text', overwrite=False):

        if all([replace, overwrite]):
            self.raise_exc('setting both replace and overwrite to True is invalid')

        if replace:
            merge = False
            overwrite = False
        elif overwrite:
            merge = True
            overwrite = False
        else:
            merge = True
            overwrite = False

        if overwrite and config_format == 'set':
            self.raise_exc('replace cannot be True when config_format is `set`')

        self.lock_config()

        try:
            candidate = '\n'.join(config)
            self.config.load(candidate, format=config_format, merge=merge,
                             overwrite=overwrite)

        except ConfigLoadError:
            exc = get_exception()
            self.raise_exc('Unable to load config: %s' % str(exc))

        diff = self.config.diff()

        self.check_config()

        if all((commit, diff)):
            self.commit_config(comment=comment, confirm=confirm)

        self.unlock_config()

        return diff

    def save_config(self):
        raise NotImplementedError

    ### end of Config ###

    def get_facts(self, refresh=True):
        if refresh:
            self.device.facts_refresh()
        return self.device.facts

    def unlock_config(self):
        try:
            self.config.unlock()
            self._locked = False
        except UnlockError:
            exc = get_exception()
            raise NetworkError('unable to unlock config: %s' % str(exc))

    def lock_config(self):
        try:
            self.config.lock()
            self._locked = True
        except LockError:
            exc = get_exception()
            raise NetworkError('unable to lock config: %s' % str(exc))

    def check_config(self):
        if not self.config.commit_check():
            self.raise_exc(msg='Commit check failed')

    def commit_config(self, comment=None, confirm=None):
        try:
            kwargs = dict(comment=comment)
            if confirm and confirm > 0:
                kwargs['confirm'] = confirm
            return self.config.commit(**kwargs)
        except CommitError:
            exc = get_exception()
            raise NetworkError('unable to commit config: %s' % str(exc))

    def confirm_commit(self, checkonly=False):
        try:
            resp = self.rpc('get_commit_information')
            needs_confirm = 'commit confirmed, rollback' in resp[0][4].text
            if checkonly:
                return needs_confirm
            return self.commit_config()
        except IndexError:
            # if there is no comment tag, the system is not in a commit
            # confirmed state so just return
            pass

    def rollback_config(self, identifier, commit=True, comment=None):

        self.lock_config()

        try:
            self.config.rollback(identifier)
        except ValueError:
            exc = get_exception()
            self.raise_exc('Unable to rollback config: $s' % str(exc))

        diff = self.config.diff()
        if commit:
            self.commit_config(comment=comment)

        self.unlock_config()
        return diff
Ejemplo n.º 3
0
    def __init__(self, **kvargs):
        """
        NoobDevice object constructor.

        :param str host:
            **REQUIRED** host-name or ipaddress of target device

        :param str user:
            *OPTIONAL* login user-name, uses root if not provided

        :param str passwd:
            *OPTIONAL* in console connection for device at zeroized state
            password is not required

        :param int port:
            *OPTIONAL*  port, default is telnet port `23`

        :param int baud:
            *OPTIONAL*  baud, default baud rate is 9600

        :param str mode:
            *OPTIONAL*  mode, mode of connection (telnet/serial/ssh)
            default is telnet

        :param int timeout:
            *OPTIONAL*  timeout, default is 0.5

        :param int attempts:
            *OPTIONAL*  attempts, default is 10

        :param str ssh_config:
            *OPTIONAL* The path to the SSH configuration file.
            This can be used to load SSH information from a configuration file.
            By default ~/.ssh/config is queried it will be used by SCP class.
            So its assumed ssh is enabled by the time we use SCP functionality.

        :param bool gather_facts:
            *OPTIONAL* default is ``False``.  If ``False`` then the
            facts are not gathered on call to :meth:`open`

        """

        # ----------------------------------------
        # setup instance connection/open variables
        # ----------------------------------------

        self._tty = None
        self._facts = {}
        self.connected = False
        self._skip_logout = False
        self.results = dict(changed=False, failed=False, errmsg=None)

        # hostname is not required in serial mode connection
        self._hostname = kvargs.get('host')
        self._auth_user = kvargs.get('user', 'root')
        self._auth_password = kvargs.get(
            'password',
            '') or kvargs.get(
            'passwd',
            '')
        self._port = kvargs.get('port', '23')
        self._baud = kvargs.get('baud', '9600')
        self._mode = kvargs.get('mode', 'telnet')
        self._timeout = kvargs.get('timeout', '0.5')
        # self.timeout needed by PyEZ utils
        self.timeout = self._timeout
        self._attempts = kvargs.get('attempts', 10)
        self.gather_facts = kvargs.get('gather_facts', False)
        self.rpc = _RpcMetaExec(self)
        from jnpr.junos import Device
        if sys.version < '3':
            self.cli = lambda cmd, format='text', warning=True: \
                Device.cli.im_func(self, cmd, format, warning)
            self._sshconf_path = lambda: Device._sshconf_lkup.im_func(self)
            self.facts_refresh = lambda exception_on_failure=False: \
                Device.facts_refresh.im_func(self, exception_on_failure)
        else:
            self.cli = lambda cmd, format='text', warning=True: \
                Device.cli(self, cmd, format, warning)
            self._sshconf_path = lambda: Device._sshconf_lkup(self)
            self.facts_refresh = lambda exception_on_failure=False: \
                Device.facts_refresh(self, exception_on_failure)
        self._ssh_config = kvargs.get('ssh_config')
Ejemplo n.º 4
0
class TestDevice(unittest.TestCase):

    @patch('ncclient.manager.connect')
    def setUp(self, mock_connect):
        mock_connect.side_effect = self._mock_manager
        self.dev = Device(host='1.1.1.1', user='******', password='******',
                          gather_facts=False)
        self.dev.open()

    @patch('ncclient.operations.session.CloseSession.request')
    def tearDown(self, mock_session):
        self.dev.close()

    @patch('jnpr.junos.device.netconf_ssh')
    def test_device_ConnectAuthError(self, mock_manager):
        mock_manager.connect.side_effect = NcErrors.AuthenticationError
        self.assertRaises(EzErrors.ConnectAuthError, self.dev.open)

    @patch('jnpr.junos.device.netconf_ssh')
    def test_device_ConnectRefusedError(self, mock_manager):
        mock_manager.connect.side_effect = NcErrors.SSHError
        self.assertRaises(EzErrors.ConnectRefusedError, self.dev.open)

    @patch('jnpr.junos.device.netconf_ssh')
    @patch('jnpr.junos.device.datetime')
    def test_device_ConnectTimeoutError(self, mock_datetime, mock_manager):
        NcErrors.SSHError.message = 'cannot open'
        mock_manager.connect.side_effect = NcErrors.SSHError
        from datetime import timedelta, datetime
        currenttime = datetime.now()
        mock_datetime.datetime.now.side_effect = [currenttime,
                                                  currenttime + timedelta(minutes=4)]
        self.assertRaises(EzErrors.ConnectTimeoutError, self.dev.open)

    @patch('jnpr.junos.device.netconf_ssh')
    @patch('jnpr.junos.device.datetime')
    def test_device_diff_err_message(self, mock_datetime, mock_manager):
        NcErrors.SSHError.message = 'why are you trying :)'
        mock_manager.connect.side_effect = NcErrors.SSHError
        from datetime import timedelta, datetime
        currenttime = datetime.now()
        mock_datetime.datetime.now.side_effect = [currenttime,
                                                  currenttime + timedelta(minutes=4)]
        self.assertRaises(EzErrors.ConnectError, self.dev.open)

    @patch('jnpr.junos.device.netconf_ssh')
    def test_device_ConnectUnknownHostError(self, mock_manager):
        import socket
        mock_manager.connect.side_effect = socket.gaierror
        self.assertRaises(EzErrors.ConnectUnknownHostError, self.dev.open)

    @patch('jnpr.junos.device.netconf_ssh')
    def test_device_other_error(self, mock_manager):
        mock_manager.connect.side_effect = TypeError
        self.assertRaises(EzErrors.ConnectError, self.dev.open)

    def test_device_property_logfile_isinstance(self):
        mock = MagicMock()
        with patch('__builtin__.open', mock):
            with patch('__builtin__.file', MagicMock):
                handle = open('filename', 'r')
                self.dev.logfile = handle
                self.assertEqual(self.dev.logfile, handle)

    def test_device_host_mand_param(self):
        self.assertRaises(ValueError, Device, user='******',
                          password='******',
                          gather_facts=False)

    def test_device_property_logfile_close(self):
        self.dev._logfile = MagicMock()
        self.dev._logfile.close.return_value = 0
        self.dev.logfile = None
        self.assertFalse(self.dev._logfile)

    def test_device_property_logfile_exception(self):
        try:
            self.dev.logfile = True
        except Exception as ex:
            self.assertEqual(type(ex), ValueError)

    def test_device_repr(self):
        localdev = Device(host='1.1.1.1', user='******', password='******',
                          gather_facts=False)
        self.assertEqual(repr(localdev), 'Device(1.1.1.1)')

    @patch('jnpr.junos.device.os')
    @patch('__builtin__.open')
    @patch('paramiko.config.SSHConfig.lookup')
    def test_device__sshconf_lkup(self, os_mock, open_mock, mock_paramiko):
        os_mock.path.exists.return_value = True
        self.dev._sshconf_lkup()
        mock_paramiko.assert_called_any()

    @patch('os.getenv')
    def test_device__sshconf_lkup_path_not_exists(self, mock_env):
        mock_env.return_value = '/home/test'
        self.assertEqual(self.dev._sshconf_lkup(), None)

    @patch('os.getenv')
    def test_device__sshconf_lkup_home_not_defined(self, mock_env):
        mock_env.return_value = None
        self.assertEqual(self.dev._sshconf_lkup(), None)
        mock_env.assert_called_with('HOME')

    @patch('ncclient.manager.connect')
    @patch('jnpr.junos.Device.execute')
    def test_device_open(self, mock_connect, mock_execute):
        with patch('jnpr.junos.utils.fs.FS.cat') as mock_cat:
            mock_cat.return_value = """

    domain jls.net

            """
            mock_connect.side_effect = self._mock_manager
            mock_execute.side_effect = self._mock_manager
            self.dev2 = Device(host='2.2.2.2', user='******', password='******')
            self.dev2.open()
            self.assertEqual(self.dev2.connected, True)

    @patch('jnpr.junos.Device.execute')
    def test_device_facts(self, mock_execute):
        with patch('jnpr.junos.utils.fs.FS.cat') as mock_cat:
            mock_execute.side_effect = self._mock_manager
            mock_cat.return_value = """

    domain jls.net

            """
            self.dev.facts_refresh()
            assert self.dev.facts['version'] == facts['version']

    def test_device_hostname(self):
        self.assertEqual(self.dev.hostname, '1.1.1.1')

    def test_device_user(self):
        self.assertEqual(self.dev.user, 'rick')

    def test_device_get_password(self):
        self.assertEqual(self.dev.password, None)

    def test_device_set_password(self):
        self.dev.password = '******'
        self.assertEqual(self.dev._password, 'secret')

    def test_device_get_timeout(self):
        self.assertEqual(self.dev.timeout, 30)

    def test_device_set_timeout(self):
        self.dev.timeout = 10
        self.assertEqual(self.dev.timeout, 10)

    def test_device_manages(self):
        self.assertEqual(self.dev.manages, [],
                         'By default manages will be empty list')

    def test_device_set_facts_exception(self):
        try:
            self.dev.facts = 'test'
        except RuntimeError as ex:
            self.assertEqual(RuntimeError, type(ex))

    @patch('jnpr.junos.Device.execute')
    def test_device_cli(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertEqual(self.dev.cli('show cli directory').tag, 'cli')

    @patch('jnpr.junos.Device.execute')
    def test_device_cli_conf_info(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertTrue('ge-0/0/0' in self.dev.cli('show configuration'))

    @patch('jnpr.junos.Device.execute')
    def test_device_cli_output(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertTrue('Alarm' in self.dev.cli('show system alarms'))

    @patch('jnpr.junos.Device.execute')
    def test_device_cli_rpc(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertEqual(self.dev.cli('show system uptime | display xml rpc')\
                         .tag, 'get-system-uptime-information')

    def test_device_cli_exception(self):
        self.dev.rpc.cli = MagicMock(side_effect=AttributeError)
        val = self.dev.cli('show version')
        self.assertEqual(val, 'invalid command: show version')

    def test_device_execute(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertEqual(self.dev.execute('<get-system-core-dumps/>').tag,
                         'directory-list')

    def test_device_execute_topy(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertEqual(self.dev.execute('<get-system-core-dumps/>',
                                          to_py=self._do_nothing), 'Nothing')

    def test_device_execute_exception(self):
        class MyException(Exception):
            rpc_err = """
<rpc-error xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:junos="http://xml.juniper.net/junos/12.1X46/junos" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
<error-severity>error</error-severity>
<error-info>
<bad-element>get-bgp-summary-information</bad-element>
</error-info>
<error-message>permission denied</error-message>
</rpc-error>                
            """
            xml = etree.XML(rpc_err)

        self.dev._conn.rpc = MagicMock(side_effect=MyException)
        self.assertRaises(RpcError, self.dev.execute, 
            '<get-software-information/>')

    def test_device_execute_rpc_error(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertRaises(RpcError, self.dev.rpc.get_rpc_error)

    def test_device_execute_index_error(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertTrue(self.dev.rpc.get_index_error())

    def test_device_execute_ValueError(self):
        self.assertRaises(ValueError, self.dev.execute, None)

    def test_device_rpcmeta(self):
        self.assertEqual(self.dev.rpc.get_software_information.func_doc,
                         'get-software-information')

    def test_device_probe_timeout_zero(self):
        with patch('jnpr.junos.device.socket'):
            self.assertFalse(self.dev.probe(0))

    def test_device_probe_timeout_gt_zero(self):
        with patch('jnpr.junos.device.socket'):
            self.assertTrue(self.dev.probe(1),
                            'probe fn is not working for'
                            ' timeout greater than zero')

    def test_device_probe_timeout_exception(self):
        with patch('jnpr.junos.device.socket') as mock_socket:
            with patch('jnpr.junos.device.time.sleep') as mock_time:
                mock_socket.socket.return_value.close.side_effect \
                    = RuntimeError
                mock_time.return_value = None
                self.assertFalse(self.dev.probe(.01))

    def test_device_bind_varg(self):
        self.dev.bind()
        mock = MagicMock()
        mock.__name__ = 'magic_mock'
        self.dev.bind(mock)
        self.assertEqual(self.dev.magic_mock.__name__, 'magic_mock')

    def test_device_bind_kvarg(self):
        self.dev.bind()
        mock = MagicMock()
        mock.return_value = 'Test'
        self.dev.bind(kw=mock)
        self.assertEqual(self.dev.kw, 'Test')

    def test_device_bind_varg_exception(self):
        def varg():
            self.dev.bind()
            mock = MagicMock()
            mock.__name__ = 'magic mock'
            #for *args
            self.dev.bind(mock)
            self.dev.bind(mock)
        self.assertRaises(ValueError, varg)

    def test_device_bind_kvarg_exception(self):
        def kve():
            self.dev.bind()
            mock = MagicMock()
            mock.__name__ = 'magic mock'
            #for **kwargs
            self.dev.bind(kw=mock)
            self.dev.bind(kw=mock)
        self.assertRaises(ValueError, kve)

    def test_device_template(self):
        # Try to load the template relative to module base
        try:
            template = self.dev.Template('tests/unit/templates/config-example')
        except:
            # Try to load the template relative to test base
            try:
                template = self.dev.Template('templates/config-example')
            except:
                raise
        self.assertEqual(template.render({'host_name': '1',
                               'domain_name': '2'}),
                               'system {\n  host-name 1;\n  domain-name 2;\n}')

    def test_device_close(self):
        def close_conn():
            self.dev.connected = False
        self.dev.close = MagicMock(name='close')
        self.dev.close.side_effect = close_conn
        self.dev.close()
        self.assertEqual(self.dev.connected, False)

    def _read_file(self, fname):
        from ncclient.xml_ import NCElement

        fpath = os.path.join(os.path.dirname(__file__),
                             'rpc-reply', fname)
        foo = open(fpath).read()

        if (fname == 'get-rpc-error.xml' or
                fname == 'get-index-error.xml' or
                fname == 'get-system-core-dumps.xml'):
            rpc_reply = NCElement(foo, self.dev._conn._device_handler
                                  .transform_reply())
        elif (fname == 'show-configuration.xml' or
              fname == 'show-system-alarms.xml'):
            rpc_reply = NCElement(foo, self.dev._conn._device_handler
                                  .transform_reply())._NCElement__doc
        else:
            rpc_reply = NCElement(foo, self.dev._conn._device_handler
                                  .transform_reply())._NCElement__doc[0]
        return rpc_reply

    def _mock_manager(self, *args, **kwargs):
        if kwargs:
            device_params = kwargs['device_params']
            device_handler = make_device_handler(device_params)
            session = SSHSession(device_handler)
            return Manager(session, device_handler)

        elif args:
            if args[0].tag == 'command':
                if args[0].text == 'show cli directory':
                    return self._read_file('show-cli-directory.xml')
                elif args[0].text == 'show configuration':
                    return self._read_file('show-configuration.xml')
                elif args[0].text == 'show system alarms':
                    return self._read_file('show-system-alarms.xml')
                elif args[0].text == 'show system uptime | display xml rpc':
                    return self._read_file('show-system-uptime-rpc.xml')
                else:
                    raise RpcError

            else:
                return self._read_file(args[0].tag + '.xml')

    def _do_nothing(self, *args, **kwargs):
        return 'Nothing'
Ejemplo n.º 5
0
from jnpr.junos import Device
import sys
from getpass import getpass

dev = Device('host', user='******', password='******')

#dev = Device('10.209.16.236')
try:
    dev.open()
except Exception as err:
    print "Unable to connect to host:", err
    sys.exit(1)

print dev.facts
dev.facts_refresh()
print dev.facts

print dev.cli("show version | display xml rpc")
dev.close()
Ejemplo n.º 6
0
class TestDevice(unittest.TestCase):

    @patch('ncclient.manager.connect')
    def setUp(self, mock_connect):
        mock_connect.side_effect = self._mock_manager

        self.dev = Device(host='1.1.1.1', user='******', password='******',
                          gather_facts=False)
        self.dev.open()

    @patch('ncclient.operations.session.CloseSession.request')
    def tearDown(self, mock_session):
        self.dev.close()

    def test_new_console_return(self):
        dev = Device(host='1.1.1.1', user='******', password='******',
                     port=23, gather_facts=False)
        self.assertTrue(isinstance(dev, Console))

    @patch('jnpr.junos.device.netconf_ssh')
    def test_device_ConnectAuthError(self, mock_manager):
        mock_manager.connect.side_effect = NcErrors.AuthenticationError
        self.assertRaises(EzErrors.ConnectAuthError, self.dev.open)

    @patch('jnpr.junos.device.netconf_ssh')
    def test_device_ConnectRefusedError(self, mock_manager):
        mock_manager.connect.side_effect = NcErrors.SSHError
        self.assertRaises(EzErrors.ConnectRefusedError, self.dev.open)

    @patch('jnpr.junos.device.netconf_ssh')
    @patch('jnpr.junos.device.datetime')
    def test_device_ConnectTimeoutError(self, mock_datetime, mock_manager):
        mock_manager.connect.side_effect = NcErrors.SSHError(
            "Could not open socket to 1.1.1.1:830")
        from datetime import timedelta, datetime
        currenttime = datetime.now()
        mock_datetime.datetime.now.side_effect = [currenttime,
                                                  currenttime +
                                                  timedelta(minutes=4)]
        self.assertRaises(EzErrors.ConnectTimeoutError, self.dev.open)

    @patch('jnpr.junos.device.netconf_ssh')
    @patch('jnpr.junos.device.datetime')
    def test_device_diff_err_message(self, mock_datetime, mock_manager):
        NcErrors.SSHError.message = 'why are you trying :)'
        mock_manager.connect.side_effect = NcErrors.SSHError
        from datetime import timedelta, datetime
        currenttime = datetime.now()
        mock_datetime.datetime.now.side_effect = [currenttime,
                                                  currenttime +
                                                  timedelta(minutes=4)]
        self.assertRaises(EzErrors.ConnectError, self.dev.open)

    @patch('jnpr.junos.device.netconf_ssh')
    def test_device_ConnectUnknownHostError(self, mock_manager):
        import socket
        mock_manager.connect.side_effect = socket.gaierror
        self.assertRaises(EzErrors.ConnectUnknownHostError, self.dev.open)

    @patch('jnpr.junos.device.netconf_ssh')
    def test_device_other_error(self, mock_manager):
        mock_manager.connect.side_effect = TypeError
        self.assertRaises(EzErrors.ConnectError, self.dev.open)

    def test_device_probe_error(self):
        mock_probe = MagicMock()
        mock_probe.return_value = None
        self.dev.probe = mock_probe

        def fn():
            self.dev.open(auto_probe=1)
        self.assertRaises(EzErrors.ProbeError, fn)

    def test_device_property_logfile_isinstance(self):
        mock = MagicMock()
        with patch(builtin_string + '.open', mock):
            if sys.version > '3':
                builtin_file = 'io.TextIOWrapper'
            else:
                builtin_file = builtin_string + '.file'
            with patch(builtin_file, MagicMock):
                handle = open('filename', 'r')
                self.dev.logfile = handle
                self.assertEqual(self.dev.logfile, handle)

    def test_device_host_mand_param(self):
        self.assertRaises(ValueError, Device, user='******',
                          password='******',
                          gather_facts=False)

    def test_device_property_logfile_close(self):
        self.dev._logfile = MagicMock()
        self.dev._logfile.close.return_value = 0
        self.dev.logfile = None
        self.assertFalse(self.dev._logfile)

    def test_device_property_logfile_exception(self):
        try:
            self.dev.logfile = True
        except Exception as ex:
            self.assertEqual(type(ex), ValueError)

    def test_device_master_is_master(self):
        localdev = Device(host='1.1.1.1', user='******', password='******',
                          gather_facts=False)
        localdev.facts._cache['current_re'] = ['re1', 'master', 'node',
                                               'fwdd', 'member', 'pfem']
        self.assertEqual(localdev.master, True)

    def test_device_master_is_backup(self):
        localdev = Device(host='1.1.1.1', user='******', password='******',
                          gather_facts=False)
        localdev.facts._cache['current_re'] = ['re0', 'backup']
        self.assertEqual(localdev.master, False)

    def test_device_master_is_re0_only(self):
        localdev = Device(host='1.1.1.1', user='******', password='******',
                          gather_facts=False)
        localdev.facts._cache['2RE'] = False
        localdev.facts._cache['RE_hw_mi'] = False
        localdev.facts._cache['current_re'] = ['re0']
        self.assertEqual(localdev.master, True)

    def test_device_master_is_multi_chassis_non_master1(self):
        localdev = Device(host='1.1.1.1', user='******', password='******',
                          gather_facts=False)
        localdev.facts._cache['2RE'] = True
        localdev.facts._cache['current_re'] = ['lcc1-re1', 'member1-re1',
                                               'lcc1-backup', 'member1-backup']
        self.assertEqual(localdev.master, False)

    def test_device_master_is_multi_chassis_non_master2(self):
        localdev = Device(host='1.1.1.1', user='******', password='******',
                          gather_facts=False)
        localdev.facts._cache['2RE'] = True
        localdev.facts._cache['current_re'] = ['lcc1-re0', 'member1-re0',
                                               'lcc1-master', 'member1-master',
                                               'member1']
        self.assertEqual(localdev.master, False)

    def test_device_master_is_none1(self):
        localdev = Device(host='1.1.1.1', user='******', password='******',
                          gather_facts=False)
        localdev.facts._cache['current_re'] = None
        self.assertEqual(localdev.master, None)

    def test_device_master_is_none2(self):
        localdev = Device(host='1.1.1.1', user='******', password='******',
                          gather_facts=False)
        localdev.facts._cache['2RE'] = True
        localdev.facts._cache['current_re'] = ['foo', 'bar']
        self.assertEqual(localdev.master, None)

    @patch('jnpr.junos.device.warnings')
    def test_device_master_is_old_facts(self, mock_warn):
        localdev = Device(host='1.1.1.1', user='******', password='******',
                          fact_style='old', gather_facts=False)
        mock_warn.assert_has_calls([call.warn('fact-style old will be removed '
                                              'in a future release.',
                                              RuntimeWarning)])
        self.assertEqual(localdev.master, None)

    def test_device_master_setter(self):
        localdev = Device(host='1.1.1.1', user='******', password='******',
                          gather_facts=False)
        with self.assertRaises(RuntimeError):
            localdev.master = 'foo'

    def test_device_re_name_is_re0(self):
        localdev = Device(host='1.1.1.1', user='******', password='******',
                          gather_facts=False)
        localdev.facts._cache['current_re'] = ['re0', 'backup']
        localdev.facts._cache['hostname_info'] = {'re0': 'tapir',
                                                  're1': 'tapir1'}
        self.assertEqual(localdev.re_name, 're0')

    def test_device_re_name_is_lcc_re1(self):
        localdev = Device(host='1.1.1.1', user='******', password='******',
                          gather_facts=False)
        localdev.facts._cache['current_re'] = ['lcc1-re1', 'member1-re1',
                                               'lcc1-backup', 'member1-backup']
        localdev.facts._cache['hostname_info'] = {'re0': 'mj1'}
        self.assertEqual(localdev.re_name, 'lcc1-re1')

    def test_device_re_name_is_re0_only(self):
        localdev = Device(host='1.1.1.1', user='******', password='******',
                          gather_facts=False)
        localdev.facts._cache['current_re'] = ['foo']
        localdev.facts._cache['hostname_info'] = {'re0': 'mj1'}
        self.assertEqual(localdev.re_name, 're0')

    def test_device_re_name_is_none1(self):
        localdev = Device(host='1.1.1.1', user='******', password='******',
                          gather_facts=False)
        localdev.facts._cache['current_re'] = None
        self.assertEqual(localdev.re_name, None)

    def test_device_re_name_is_none2(self):
        localdev = Device(host='1.1.1.1', user='******', password='******',
                          gather_facts=False)
        localdev.facts._cache['current_re'] = ['re1', 'master', 'node',
                                               'fwdd', 'member', 'pfem']
        localdev.facts._cache['hostname_info'] = None
        self.assertEqual(localdev.re_name, None)

    @patch('jnpr.junos.device.warnings')
    def test_device_re_name_is_old_facts(self, mock_warn):
        localdev = Device(host='1.1.1.1', user='******', password='******',
                          fact_style='old', gather_facts=False)
        mock_warn.assert_has_calls([call.warn('fact-style old will be removed '
                                              'in a future release.',
                                              RuntimeWarning)])
        self.assertEqual(localdev.re_name, None)

    def test_device_re_name_setter(self):
        localdev = Device(host='1.1.1.1', user='******', password='******',
                          gather_facts=False)
        with self.assertRaises(RuntimeError):
            localdev.re_name = 'foo'

    def test_device_repr(self):
        localdev = Device(host='1.1.1.1', user='******', password='******',
                          gather_facts=False)
        self.assertEqual(repr(localdev), 'Device(1.1.1.1)')

    def test_device_local(self):
        Device.ON_JUNOS = True
        localdev = Device()
        self.assertEqual(localdev._hostname, 'localhost')

    @patch('jnpr.junos.device.os')
    @patch(builtin_string + '.open')
    @patch('paramiko.config.SSHConfig.lookup')
    def test_device__sshconf_lkup(self, mock_paramiko, open_mock, os_mock):
        os_mock.path.exists.return_value = True
        self.dev._sshconf_lkup()
        mock_paramiko.assert_called_once_with('1.1.1.1')

    @patch('jnpr.junos.device.os')
    @patch(builtin_string + '.open')
    @patch('paramiko.config.SSHConfig.lookup')
    def test_device__sshconf_lkup_def(self, mock_paramiko, open_mock, os_mock):
        os_mock.path.exists.return_value = True
        self.dev._ssh_config = '/home/rsherman/.ssh/config'
        self.dev._sshconf_lkup()
        mock_paramiko.assert_called_once_with('1.1.1.1')

    @patch('os.getenv')
    def test_device__sshconf_lkup_path_not_exists(self, mock_env):
        mock_env.return_value = '/home/test'
        self.assertEqual(self.dev._sshconf_lkup(), None)

    @patch('os.getenv')
    def test_device__sshconf_lkup_home_not_defined(self, mock_env):
        mock_env.return_value = None
        self.assertEqual(self.dev._sshconf_lkup(), None)
        mock_env.assert_called_with('HOME')

    @patch('ncclient.manager.connect')
    @patch('jnpr.junos.Device.execute')
    def test_device_open(self, mock_connect, mock_execute):
        with patch('jnpr.junos.utils.fs.FS.cat') as mock_cat:
            mock_cat.return_value = """

    domain jls.net

            """
            mock_connect.side_effect = self._mock_manager
            mock_execute.side_effect = self._mock_manager
            self.dev2 = Device(
                host='2.2.2.2',
                user='******',
                password='******')
            self.dev2.open()
            self.assertEqual(self.dev2.connected, True)

    @patch('jnpr.junos.Device.execute')
    def test_device_facts(self, mock_execute):
        with patch('jnpr.junos.utils.fs.FS.cat') as mock_cat:
            mock_execute.side_effect = self._mock_manager
            mock_cat.return_value = """

    domain jls.net

            """
            self.dev.facts_refresh()
            self.dev.facts._cache['current_re'] = ['re0']
            assert self.dev.facts['version'] == facts['version']

    @patch('jnpr.junos.Device.execute')
    @patch('jnpr.junos.factcache.warnings')
    def test_device_facts_error(self, mock_warnings, mock_execute):
        with patch('jnpr.junos.utils.fs.FS.cat') as mock_cat:
            mock_execute.side_effect = self._mock_manager
            mock_cat.side_effect = IOError('File cant be handled')
            self.dev.facts_refresh(warnings_on_failure=True)
            self.assertTrue(mock_warnings.warn.called)

    @patch('jnpr.junos.Device.execute')
    @patch('jnpr.junos.device.warnings')
    def test_device_facts_error_exception_on_error(self, mock_warnings,
                                                   mock_execute):
        with patch('jnpr.junos.utils.fs.FS.cat') as mock_cat:
            mock_execute.side_effect = self._mock_manager
            mock_cat.side_effect = IOError('File cant be handled')
            self.assertRaises(IOError, self.dev.facts_refresh,
                              exception_on_failure=True)

    @patch('jnpr.junos.Device.execute')
    @patch('jnpr.junos.device.warnings')
    def test_device_old_style_facts_error_exception_on_error(self,
                                                             mock_warnings,
                                                             mock_execute):
        self.dev._fact_style = 'old'
        with patch('jnpr.junos.utils.fs.FS.cat') as mock_cat:
            mock_execute.side_effect = self._mock_manager
            mock_cat.side_effect = IOError('File cant be handled')
            self.assertRaises(IOError, self.dev.facts_refresh,
                              exception_on_failure=True)

    def test_device_facts_refresh_unknown_fact_style(self):
        self.dev._fact_style = 'bad'
        with self.assertRaises(RuntimeError):
            self.dev.facts_refresh()

    def test_device_facts_refresh_old_fact_style_with_keys(self):
        self.dev._fact_style = 'old'
        with self.assertRaises(RuntimeError):
            self.dev.facts_refresh(keys='domain')

    def test_device_hostname(self):
        self.assertEqual(self.dev.hostname, '1.1.1.1')

    def test_device_user(self):
        self.assertEqual(self.dev.user, 'test')

    def test_device_get_password(self):
        self.assertEqual(self.dev.password, None)

    def test_device_set_password(self):
        self.dev.password = '******'
        self.assertEqual(self.dev._auth_password, 'secret')

    def test_device_get_timeout(self):
        self.assertEqual(self.dev.timeout, 30)

    def test_device_set_timeout(self):
        self.dev.timeout = 10
        self.assertEqual(self.dev.timeout, 10)

    def test_device_manages(self):
        self.assertEqual(self.dev.manages, [],
                         'By default manages will be empty list')

    @patch('ncclient.manager.connect')
    @patch('jnpr.junos.Device.execute')
    def test_device_open_normalize(self, mock_connect, mock_execute):
        mock_connect.side_effect = self._mock_manager
        self.dev2 = Device(host='2.2.2.2', user='******', password='******')
        self.dev2.open(gather_facts=False, normalize=True)
        self.assertEqual(self.dev2.transform, self.dev2._norm_transform)

    def test_device_set_facts_exception(self):
        try:
            self.dev.facts = 'test'
        except RuntimeError as ex:
            self.assertEqual(RuntimeError, type(ex))

    def test_device_ofacts_exception(self):
        with self.assertRaises(RuntimeError):
            ofacts = self.dev.ofacts

    def test_device_set_ofacts_exception(self):
        with self.assertRaises(RuntimeError):
            self.dev.ofacts = False

    @patch('jnpr.junos.Device.execute')
    def test_device_cli(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertEqual(self.dev.cli('show cli directory',
                                      warning=False).tag, 'cli')

    @patch('jnpr.junos.device.json.loads')
    def test_device_rpc_json_ex(self, mock_json_loads):
        self.dev.facts = facts
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        ex = ValueError('Extra data ')
        ex.message = 'Extra data '  # for py3 as we dont have message thr
        mock_json_loads.side_effect = [
            ex,
            self._mock_manager(etree.fromstring(
                '<get-route-information format="json"/>'))]
        self.dev.rpc.get_route_information({'format': 'json'})
        self.assertEqual(mock_json_loads.call_count, 2)

    @patch('jnpr.junos.Device.execute')
    def test_device_cli_to_rpc_string(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        data = self.dev.cli_to_rpc_string('show system uptime')
        self.assertEqual("rpc.get_system_uptime_information()", data)

    @patch('jnpr.junos.Device.execute')
    def test_device_cli_to_rpc_string_strip_pipes(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        data = self.dev.cli_to_rpc_string(
            'show system uptime | match foo | count')
        self.assertEqual("rpc.get_system_uptime_information()", data)

    @patch('jnpr.junos.Device.execute')
    def test_device_cli_to_rpc_string_complex(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        data = self.dev.cli_to_rpc_string(
            'show interfaces ge-0/0/0.0 routing-instance all media')
        self.assertEqual("rpc.get_interface_information("
                         "routing_instance='all', media=True, "
                         "interface_name='ge-0/0/0.0')", data)

    @patch('jnpr.junos.Device.execute')
    def test_device_cli_to_rpc_string_invalid(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        data = self.dev.cli_to_rpc_string('foo')
        self.assertEqual(None, data)

    @patch('jnpr.junos.Device.execute')
    def test_device_cli_format_json(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        data = self.dev.cli('show interface terse',
                            warning=False, format='json')
        self.assertEqual(type(data), dict)
        self.assertEqual(data['interface-information'][0]
                         ['physical-interface'][0]['oper-status'][0]['data'],
                         'up')

    @patch('jnpr.junos.Device.execute')
    def test_device_cli_conf_info(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertTrue('ge-0/0/0' in self.dev.cli('show configuration',
                                                   warning=False))

    @patch('jnpr.junos.Device.execute')
    def test_device_cli_output(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertTrue('Alarm' in self.dev.cli('show system alarms',
                                                warning=False))

    @patch('jnpr.junos.Device.execute')
    @patch('jnpr.junos.device.warnings')
    def test_device_cli_output_warning(self, mock_warnings, mock_execute):
        mock_execute.side_effect = self._mock_manager
        data = self.dev.cli('show interfaces ge-0/0/0.0 routing-instance '
                            'all media', format='xml')
        ip = data.findtext('logical-interface[name="ge-0/0/0.0"]/'
                           'address-family[address-family-name="inet"]/'
                           'interface-address/ifa-local')
        self.assertTrue('192.168.100.1' in ip)
        self.assertTrue(mock_warnings.warn.called)
        rpc_string = "rpc.get_interface_information(routing_instance='all', "\
                     "media=True, interface_name='ge-0/0/0.0')"
        self.assertIn(rpc_string, mock_warnings.warn.call_args[0][0])

    def test_device_cli_blank_output(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertEqual('', self.dev.cli('show configuration interfaces',
                                          warning=False))

    def test_device_cli_rpc_reply_with_message(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertEqual(
            '\nprotocol: operation-failed\nerror: device asdf not found\n',
            self.dev.cli('show interfaces terse asdf',
                         warning=False))

    @patch('jnpr.junos.Device.execute')
    def test_device_cli_rpc(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertEqual(self.dev.cli('show system uptime| display xml rpc',
                                      warning=False)
                         .tag, 'get-system-uptime-information')

    def test_device_cli_exception(self):
        self.dev.rpc.cli = MagicMock(side_effect=AttributeError)
        val = self.dev.cli('show version')
        self.assertEqual(val, 'invalid command: show version')

    @patch('jnpr.junos.Device.execute')
    def test_device_cli_rpc_exception(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        val = self.dev.cli('foo')
        self.assertEqual(val, 'invalid command: foo: RpcError')

    @patch('jnpr.junos.Device.execute')
    def test_device_display_xml_rpc(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertEqual(
            self.dev.display_xml_rpc('show system uptime').tag,
            'get-system-uptime-information')

    @patch('jnpr.junos.Device.execute')
    def test_device_display_xml_rpc_text(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertIn(
            '<get-system-uptime-information>',
            self.dev.display_xml_rpc(
                'show system uptime',
                format='text'))

    @patch('jnpr.junos.Device.execute')
    def test_device_display_xml_exception(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertEqual(
            self.dev.display_xml_rpc('show foo'),
            'invalid command: show foo| display xml rpc')

    def test_device_execute(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertEqual(self.dev.execute('<get-system-core-dumps/>').tag,
                         'directory-list')

    def test_device_execute_topy(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertEqual(self.dev.execute('<get-system-core-dumps/>',
                                          to_py=self._do_nothing), 'Nothing')

# This test is for the commented out rpc-error code
#     def test_device_execute_exception(self):
#         self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
#         self.assertRaises(RpcError, self.dev.execute,
#                           '<load-configuration-error/>')

    @patch('jnpr.junos.device.warnings')
    def test_device_execute_unknown_exception(self, mock_warnings):
        class MyException(Exception):
            pass
        self.dev._conn.rpc = MagicMock(side_effect=MyException)
        self.assertRaises(MyException, self.dev.execute,
                          '<get-software-information/>')

    def test_device_execute_rpc_error(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertRaises(RpcError, self.dev.rpc.get_rpc_error)

    def test_device_execute_permission_error(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertRaises(
            EzErrors.PermissionError,
            self.dev.rpc.get_permission_denied)

    def test_device_execute_index_error(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertTrue(self.dev.rpc.get_index_error())

    def test_device_execute_ValueError(self):
        self.assertRaises(ValueError, self.dev.execute, None)

    def test_device_execute_unopened(self):
        self.dev.connected = False
        self.assertRaises(EzErrors.ConnectClosedError, self.dev.execute, None)

    def test_device_execute_timeout(self):
        self.dev._conn.rpc = MagicMock(side_effect=TimeoutExpiredError)
        self.assertRaises(
            EzErrors.RpcTimeoutError,
            self.dev.rpc.get_rpc_timeout)

    def test_device_execute_closed(self):
        self.dev._conn.rpc = MagicMock(side_effect=NcErrors.TransportError)
        self.assertRaises(
            EzErrors.ConnectClosedError,
            self.dev.rpc.get_rpc_close)
        self.assertFalse(self.dev.connected)

    def test_device_rpcmeta(self):
        self.assertEqual(self.dev.rpc.get_software_information.__doc__,
                         'get-software-information')

    def test_device_probe_timeout_zero(self):
        with patch('jnpr.junos.device.socket'):
            self.assertFalse(self.dev.probe(0))

    def test_device_probe_timeout_gt_zero(self):
        with patch('jnpr.junos.device.socket'):
            self.assertTrue(self.dev.probe(1),
                            'probe fn is not working for'
                            ' timeout greater than zero')

    def test_device_probe_timeout_exception(self):
        with patch('jnpr.junos.device.socket') as mock_socket:
            with patch('jnpr.junos.device.time.sleep') as mock_time:
                mock_socket.socket.return_value.close.side_effect \
                    = RuntimeError
                mock_time.return_value = None
                self.assertFalse(self.dev.probe(.01))

    def test_device_bind_varg(self):
        self.dev.bind()
        mock = MagicMock()
        mock.__name__ = 'magic_mock'
        self.dev.bind(mock)
        self.assertEqual(self.dev.magic_mock.__name__, 'magic_mock')

    def test_device_bind_kvarg(self):
        self.dev.bind()
        mock = MagicMock()
        mock.return_value = 'Test'
        self.dev.bind(kw=mock)
        self.assertEqual(self.dev.kw, 'Test')

    def test_device_bind_varg_exception(self):
        def varg():
            self.dev.bind()
            mock = MagicMock()
            mock.__name__ = 'magic mock'
            # for *args
            self.dev.bind(mock)
            self.dev.bind(mock)
        self.assertRaises(ValueError, varg)

    def test_device_bind_kvarg_exception(self):
        def kve():
            self.dev.bind()
            mock = MagicMock()
            mock.__name__ = 'magic mock'
            # for **kwargs
            self.dev.bind(kw=mock)
            self.dev.bind(kw=mock)
        self.assertRaises(ValueError, kve)

    def test_device_template(self):
        # Try to load the template relative to module base
        try:
            template = self.dev.Template(
                'tests/unit/templates/config-example.xml')
        except:
            # Try to load the template relative to test base
            try:
                template = self.dev.Template('templates/config-example.xml')
            except:
                raise
        self.assertEqual(template.render({'host_name': '1',
                                          'domain_name': '2'}),
                         'system {\n  host-name 1;\n  domain-name 2;\n}')

    def test_device_close(self):
        def close_conn():
            self.dev.connected = False
        self.dev.close = MagicMock(name='close')
        self.dev.close.side_effect = close_conn
        self.dev.close()
        self.assertEqual(self.dev.connected, False)

    @patch('ncclient.manager.connect')
    def test_device_context_manager(self, mock_connect):
        mock_connect.side_effect = self._mock_manager
        try:
            with Device(host='3.3.3.3', user='******',
                        password='******', gather_facts=False) as dev:
                self.assertTrue(dev.connected)
                dev._conn = MagicMock(name='_conn')
                dev._conn.connected = True

                def close_conn():
                    dev.connected = False
                dev.close = MagicMock(name='close')
                dev.close.side_effect = close_conn
                raise RpcError
        except Exception as e:
            self.assertIsInstance(e, RpcError)
        self.assertFalse(dev.connected)

    def _read_file(self, fname):
        from ncclient.xml_ import NCElement

        fpath = os.path.join(os.path.dirname(__file__),
                             'rpc-reply', fname)
        with open(fpath) as fp:
            foo = fp.read()

            if fname == 'get-rpc-error.xml':
                # Raise ncclient exception for error
                raise RPCError(etree.XML(foo))
            elif fname == 'get-permission-denied.xml':
                # Raise ncclient exception for error
                raise RPCError(etree.XML(foo))
            elif (fname == 'get-index-error.xml' or
                    fname == 'get-system-core-dumps.xml' or
                    fname == 'load-configuration-error.xml' or
                    fname == 'show-configuration-interfaces.xml' or
                  fname == 'show-interfaces-terse-asdf.xml'):
                rpc_reply = NCElement(foo, self.dev._conn._device_handler
                                      .transform_reply())
            elif (fname == 'show-configuration.xml' or
                  fname == 'show-system-alarms.xml'):
                rpc_reply = NCElement(foo, self.dev._conn._device_handler
                                      .transform_reply())._NCElement__doc
            elif fname == 'show-interface-terse.json':
                rpc_reply = json.loads(foo)
            elif fname == 'get-route-information.json':
                rpc_reply = NCElement(foo, self.dev._conn._device_handler
                                      .transform_reply())
            else:
                rpc_reply = NCElement(foo, self.dev._conn._device_handler
                                      .transform_reply())._NCElement__doc[0]
        return rpc_reply

    def _mock_manager(self, *args, **kwargs):
        if kwargs and 'normalize' not in kwargs:
            device_params = kwargs['device_params']
            device_handler = make_device_handler(device_params)
            session = SSHSession(device_handler)
            return Manager(session, device_handler)

        elif args:
            if args[0].tag == 'command':
                if args[0].text == 'show cli directory':
                    return self._read_file('show-cli-directory.xml')
                if args[0].text == 'show interface terse':
                    return self._read_file('show-interface-terse.json')
                elif args[0].text == 'show configuration':
                    return self._read_file('show-configuration.xml')
                elif args[0].text == 'show system alarms':
                    return self._read_file('show-system-alarms.xml')
                elif args[0].text == 'show system uptime| display xml rpc':
                    return self._read_file('show-system-uptime-rpc.xml')
                elif args[0].text == 'show configuration interfaces':
                    return self._read_file('show-configuration-interfaces.xml')
                elif args[0].text == 'show interfaces terse asdf':
                    return self._read_file('show-interfaces-terse-asdf.xml')
                elif args[0].text == 'show interfaces ge-0/0/0.0 ' \
                                     'routing-instance all media':
                    return self._read_file(
                        'show-interfaces-routing-instance-media.xml')
                elif args[0].text == 'show interfaces ge-0/0/0.0 ' \
                                     'routing-instance all media| display ' \
                                     'xml rpc':
                    return self._read_file(
                        'show-interfaces-routing-instance-media-rpc.xml')
                else:
                    raise RpcError

            else:
                if args[0].attrib.get('format') == 'json':
                    return self._read_file(args[0].tag + '.json')
                return self._read_file(args[0].tag + '.xml')

    def _do_nothing(self, *args, **kwargs):
        return 'Nothing'
Ejemplo n.º 7
0
class TestDevice(unittest.TestCase):
    @patch("ncclient.manager.connect")
    def setUp(self, mock_connect):
        mock_connect.side_effect = self._mock_manager

        self.dev = Device(host="1.1.1.1", user="******", password="******", gather_facts=False)
        self.dev.open()

    @patch("ncclient.operations.session.CloseSession.request")
    def tearDown(self, mock_session):
        self.dev.close()

    @patch("jnpr.junos.device.netconf_ssh")
    def test_device_ConnectAuthError(self, mock_manager):
        mock_manager.connect.side_effect = NcErrors.AuthenticationError
        self.assertRaises(EzErrors.ConnectAuthError, self.dev.open)

    @patch("jnpr.junos.device.netconf_ssh")
    def test_device_ConnectRefusedError(self, mock_manager):
        mock_manager.connect.side_effect = NcErrors.SSHError
        self.assertRaises(EzErrors.ConnectRefusedError, self.dev.open)

    @patch("jnpr.junos.device.netconf_ssh")
    @patch("jnpr.junos.device.datetime")
    def test_device_ConnectTimeoutError(self, mock_datetime, mock_manager):
        mock_manager.connect.side_effect = NcErrors.SSHError("Could not open socket to 1.1.1.1:830")
        from datetime import timedelta, datetime

        currenttime = datetime.now()
        mock_datetime.datetime.now.side_effect = [currenttime, currenttime + timedelta(minutes=4)]
        self.assertRaises(EzErrors.ConnectTimeoutError, self.dev.open)

    @patch("jnpr.junos.device.netconf_ssh")
    @patch("jnpr.junos.device.datetime")
    def test_device_diff_err_message(self, mock_datetime, mock_manager):
        NcErrors.SSHError.message = "why are you trying :)"
        mock_manager.connect.side_effect = NcErrors.SSHError
        from datetime import timedelta, datetime

        currenttime = datetime.now()
        mock_datetime.datetime.now.side_effect = [currenttime, currenttime + timedelta(minutes=4)]
        self.assertRaises(EzErrors.ConnectError, self.dev.open)

    @patch("jnpr.junos.device.netconf_ssh")
    def test_device_ConnectUnknownHostError(self, mock_manager):
        import socket

        mock_manager.connect.side_effect = socket.gaierror
        self.assertRaises(EzErrors.ConnectUnknownHostError, self.dev.open)

    @patch("jnpr.junos.device.netconf_ssh")
    def test_device_other_error(self, mock_manager):
        mock_manager.connect.side_effect = TypeError
        self.assertRaises(EzErrors.ConnectError, self.dev.open)

    def test_device_probe_error(self):
        mock_probe = MagicMock()
        mock_probe.return_value = None
        self.dev.probe = mock_probe

        def fn():
            self.dev.open(auto_probe=1)

        self.assertRaises(EzErrors.ProbeError, fn)

    def test_device_property_logfile_isinstance(self):
        mock = MagicMock()
        with patch("__builtin__.open", mock):
            with patch("__builtin__.file", MagicMock):
                handle = open("filename", "r")
                self.dev.logfile = handle
                self.assertEqual(self.dev.logfile, handle)

    def test_device_host_mand_param(self):
        self.assertRaises(ValueError, Device, user="******", password="******", gather_facts=False)

    def test_device_property_logfile_close(self):
        self.dev._logfile = MagicMock()
        self.dev._logfile.close.return_value = 0
        self.dev.logfile = None
        self.assertFalse(self.dev._logfile)

    def test_device_property_logfile_exception(self):
        try:
            self.dev.logfile = True
        except Exception as ex:
            self.assertEqual(type(ex), ValueError)

    def test_device_repr(self):
        localdev = Device(host="1.1.1.1", user="******", password="******", gather_facts=False)
        self.assertEqual(repr(localdev), "Device(1.1.1.1)")

    def test_device_local(self):
        Device.ON_JUNOS = True
        localdev = Device()
        self.assertEqual(localdev._hostname, "localhost")

    @patch("jnpr.junos.device.os")
    @patch("__builtin__.open")
    @patch("paramiko.config.SSHConfig.lookup")
    def test_device__sshconf_lkup(self, os_mock, open_mock, mock_paramiko):
        os_mock.path.exists.return_value = True
        self.dev._sshconf_lkup()
        mock_paramiko.assert_called_any()

    @patch("jnpr.junos.device.os")
    @patch("__builtin__.open")
    @patch("paramiko.config.SSHConfig.lookup")
    def test_device__sshconf_lkup_def(self, os_mock, open_mock, mock_paramiko):
        os_mock.path.exists.return_value = True
        self.dev._ssh_config = "/home/rsherman/.ssh/config"
        self.dev._sshconf_lkup()
        mock_paramiko.assert_called_any()

    @patch("os.getenv")
    def test_device__sshconf_lkup_path_not_exists(self, mock_env):
        mock_env.return_value = "/home/test"
        self.assertEqual(self.dev._sshconf_lkup(), None)

    @patch("os.getenv")
    def test_device__sshconf_lkup_home_not_defined(self, mock_env):
        mock_env.return_value = None
        self.assertEqual(self.dev._sshconf_lkup(), None)
        mock_env.assert_called_with("HOME")

    @patch("ncclient.manager.connect")
    @patch("jnpr.junos.Device.execute")
    def test_device_open(self, mock_connect, mock_execute):
        with patch("jnpr.junos.utils.fs.FS.cat") as mock_cat:
            mock_cat.return_value = """

    domain jls.net

            """
            mock_connect.side_effect = self._mock_manager
            mock_execute.side_effect = self._mock_manager
            self.dev2 = Device(host="2.2.2.2", user="******", password="******")
            self.dev2.open()
            self.assertEqual(self.dev2.connected, True)

    @patch("jnpr.junos.Device.execute")
    def test_device_facts(self, mock_execute):
        with patch("jnpr.junos.utils.fs.FS.cat") as mock_cat:
            mock_execute.side_effect = self._mock_manager
            mock_cat.return_value = """

    domain jls.net

            """
            self.dev.facts_refresh()
            assert self.dev.facts["version"] == facts["version"]

    @patch("jnpr.junos.Device.execute")
    @patch("jnpr.junos.device.warnings")
    def test_device_facts_error(self, mock_warnings, mock_execute):
        with patch("jnpr.junos.utils.fs.FS.cat") as mock_cat:
            mock_execute.side_effect = self._mock_manager
            mock_cat.side_effect = IOError("File cant be handled")
            self.dev.facts_refresh()
            self.assertTrue(mock_warnings.warn.called)

    def test_device_hostname(self):
        self.assertEqual(self.dev.hostname, "1.1.1.1")

    def test_device_user(self):
        self.assertEqual(self.dev.user, "rick")

    def test_device_get_password(self):
        self.assertEqual(self.dev.password, None)

    def test_device_set_password(self):
        self.dev.password = "******"
        self.assertEqual(self.dev._auth_password, "secret")

    def test_device_get_timeout(self):
        self.assertEqual(self.dev.timeout, 30)

    def test_device_set_timeout(self):
        self.dev.timeout = 10
        self.assertEqual(self.dev.timeout, 10)

    def test_device_manages(self):
        self.assertEqual(self.dev.manages, [], "By default manages will be empty list")

    @patch("ncclient.manager.connect")
    @patch("jnpr.junos.Device.execute")
    def test_device_open_normalize(self, mock_connect, mock_execute):
        mock_connect.side_effect = self._mock_manager
        self.dev2 = Device(host="2.2.2.2", user="******", password="******")
        self.dev2.open(gather_facts=False, normalize=True)
        self.assertEqual(self.dev2.transform, self.dev2._norm_transform)

    def test_device_set_facts_exception(self):
        try:
            self.dev.facts = "test"
        except RuntimeError as ex:
            self.assertEqual(RuntimeError, type(ex))

    @patch("jnpr.junos.Device.execute")
    def test_device_cli(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertEqual(self.dev.cli("show cli directory").tag, "cli")

    @patch("jnpr.junos.Device.execute")
    def test_device_cli_conf_info(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertTrue("ge-0/0/0" in self.dev.cli("show configuration"))

    @patch("jnpr.junos.Device.execute")
    def test_device_cli_output(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertTrue("Alarm" in self.dev.cli("show system alarms"))

    @patch("jnpr.junos.Device.execute")
    def test_device_cli_rpc(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertEqual(self.dev.cli("show system uptime | display xml rpc").tag, "get-system-uptime-information")

    def test_device_cli_exception(self):
        self.dev.rpc.cli = MagicMock(side_effect=AttributeError)
        val = self.dev.cli("show version")
        self.assertEqual(val, "invalid command: show version")

    @patch("jnpr.junos.Device.execute")
    def test_device_display_xml_rpc(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertEqual(self.dev.display_xml_rpc("show system uptime ").tag, "get-system-uptime-information")

    @patch("jnpr.junos.Device.execute")
    def test_device_display_xml_rpc_text(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertIn("<get-system-uptime-information>", self.dev.display_xml_rpc("show system uptime ", format="text"))

    @patch("jnpr.junos.Device.execute")
    def test_device_display_xml_exception(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertEqual(self.dev.display_xml_rpc("show foo"), "invalid command: show foo| display xml rpc")

    def test_device_execute(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertEqual(self.dev.execute("<get-system-core-dumps/>").tag, "directory-list")

    def test_device_execute_topy(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertEqual(self.dev.execute("<get-system-core-dumps/>", to_py=self._do_nothing), "Nothing")

    # This test is for the commented out rpc-error code
    #     def test_device_execute_exception(self):
    #         self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
    #         self.assertRaises(RpcError, self.dev.execute,
    #                           '<load-configuration-error/>')

    def test_device_execute_unknown_exception(self):
        class MyException(Exception):
            pass

        self.dev._conn.rpc = MagicMock(side_effect=MyException)
        self.assertRaises(MyException, self.dev.execute, "<get-software-information/>")

    def test_device_execute_rpc_error(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertRaises(RpcError, self.dev.rpc.get_rpc_error)

    def test_device_execute_permission_error(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertRaises(EzErrors.PermissionError, self.dev.rpc.get_permission_denied)

    def test_device_execute_index_error(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertTrue(self.dev.rpc.get_index_error())

    def test_device_execute_ValueError(self):
        self.assertRaises(ValueError, self.dev.execute, None)

    def test_device_execute_unopened(self):
        self.dev.connected = False
        self.assertRaises(EzErrors.ConnectClosedError, self.dev.execute, None)

    def test_device_execute_timeout(self):
        self.dev._conn.rpc = MagicMock(side_effect=TimeoutExpiredError)
        self.assertRaises(EzErrors.RpcTimeoutError, self.dev.rpc.get_rpc_timeout)

    def test_device_execute_closed(self):
        self.dev._conn.rpc = MagicMock(side_effect=NcErrors.TransportError)
        self.assertRaises(EzErrors.ConnectClosedError, self.dev.rpc.get_rpc_close)
        self.assertFalse(self.dev.connected)

    def test_device_rpcmeta(self):
        self.assertEqual(self.dev.rpc.get_software_information.func_doc, "get-software-information")

    def test_device_probe_timeout_zero(self):
        with patch("jnpr.junos.device.socket"):
            self.assertFalse(self.dev.probe(0))

    def test_device_probe_timeout_gt_zero(self):
        with patch("jnpr.junos.device.socket"):
            self.assertTrue(self.dev.probe(1), "probe fn is not working for" " timeout greater than zero")

    def test_device_probe_timeout_exception(self):
        with patch("jnpr.junos.device.socket") as mock_socket:
            with patch("jnpr.junos.device.time.sleep") as mock_time:
                mock_socket.socket.return_value.close.side_effect = RuntimeError
                mock_time.return_value = None
                self.assertFalse(self.dev.probe(0.01))

    def test_device_bind_varg(self):
        self.dev.bind()
        mock = MagicMock()
        mock.__name__ = "magic_mock"
        self.dev.bind(mock)
        self.assertEqual(self.dev.magic_mock.__name__, "magic_mock")

    def test_device_bind_kvarg(self):
        self.dev.bind()
        mock = MagicMock()
        mock.return_value = "Test"
        self.dev.bind(kw=mock)
        self.assertEqual(self.dev.kw, "Test")

    def test_device_bind_varg_exception(self):
        def varg():
            self.dev.bind()
            mock = MagicMock()
            mock.__name__ = "magic mock"
            # for *args
            self.dev.bind(mock)
            self.dev.bind(mock)

        self.assertRaises(ValueError, varg)

    def test_device_bind_kvarg_exception(self):
        def kve():
            self.dev.bind()
            mock = MagicMock()
            mock.__name__ = "magic mock"
            # for **kwargs
            self.dev.bind(kw=mock)
            self.dev.bind(kw=mock)

        self.assertRaises(ValueError, kve)

    def test_device_template(self):
        # Try to load the template relative to module base
        try:
            template = self.dev.Template("tests/unit/templates/config-example.xml")
        except:
            # Try to load the template relative to test base
            try:
                template = self.dev.Template("templates/config-example.xml")
            except:
                raise
        self.assertEqual(
            template.render({"host_name": "1", "domain_name": "2"}), "system {\n  host-name 1;\n  domain-name 2;\n}"
        )

    def test_device_close(self):
        def close_conn():
            self.dev.connected = False

        self.dev.close = MagicMock(name="close")
        self.dev.close.side_effect = close_conn
        self.dev.close()
        self.assertEqual(self.dev.connected, False)

    @patch("ncclient.manager.connect")
    def test_device_context_manager(self, mock_connect):
        mock_connect.side_effect = self._mock_manager
        try:
            with Device(host="3.3.3.3", user="******", password="******", gather_facts=False) as dev:
                self.assertTrue(dev.connected)
                dev._conn = MagicMock(name="_conn")
                dev._conn.connected = True

                def close_conn():
                    dev.connected = False

                dev.close = MagicMock(name="close")
                dev.close.side_effect = close_conn
                raise RpcError
        except Exception as e:
            self.assertIsInstance(e, RpcError)
        self.assertFalse(dev.connected)

    def _read_file(self, fname):
        from ncclient.xml_ import NCElement

        fpath = os.path.join(os.path.dirname(__file__), "rpc-reply", fname)
        foo = open(fpath).read()

        if fname == "get-rpc-error.xml":
            # Raise ncclient exception for error
            raise RPCError(etree.XML(foo))
        elif fname == "get-permission-denied.xml":
            # Raise ncclient exception for error
            raise RPCError(etree.XML(foo))
        elif (
            fname == "get-index-error.xml"
            or fname == "get-system-core-dumps.xml"
            or fname == "load-configuration-error.xml"
        ):
            rpc_reply = NCElement(foo, self.dev._conn._device_handler.transform_reply())
        elif fname == "show-configuration.xml" or fname == "show-system-alarms.xml":
            rpc_reply = NCElement(foo, self.dev._conn._device_handler.transform_reply())._NCElement__doc
        else:
            rpc_reply = NCElement(foo, self.dev._conn._device_handler.transform_reply())._NCElement__doc[0]
        return rpc_reply

    def _mock_manager(self, *args, **kwargs):
        if kwargs:
            device_params = kwargs["device_params"]
            device_handler = make_device_handler(device_params)
            session = SSHSession(device_handler)
            return Manager(session, device_handler)

        elif args:
            if args[0].tag == "command":
                if args[0].text == "show cli directory":
                    return self._read_file("show-cli-directory.xml")
                elif args[0].text == "show configuration":
                    return self._read_file("show-configuration.xml")
                elif args[0].text == "show system alarms":
                    return self._read_file("show-system-alarms.xml")
                elif args[0].text == "show system uptime | display xml rpc":
                    return self._read_file("show-system-uptime-rpc.xml")
                else:
                    raise RpcError

            else:
                return self._read_file(args[0].tag + ".xml")

    def _do_nothing(self, *args, **kwargs):
        return "Nothing"
Ejemplo n.º 8
0
class Netconf(object):

    def __init__(self, module):
        self.module = module
        self.device = None
        self.config = None
        self._locked = False

    def _fail(self, msg):
        if self.device:
            if self._locked:
                self.config.unlock()
            self.disconnect()
        self.module.fail_json(msg=msg)

    def connect(self, **kwargs):
        try:
            host = self.module.params['host']
            port = self.module.params['port'] or 830

            user = self.module.params['username']
            passwd = self.module.params['password']
            key_filename = self.module.params['ssh_keyfile']

            self.device = Device(host, user=user, passwd=passwd, port=port,
                    gather_facts=False, ssh_private_key_file=key_filename).open()

            self.config = Config(self.device)

        except Exception:
            exc = get_exception()
            self._fail('unable to connect to %s: %s' % (host, str(exc)))

    def run_commands(self, commands, **kwargs):
        response = list()
        fmt = kwargs.get('format') or 'xml'

        for cmd in to_list(commands):
            try:
                resp = self.device.cli(command=cmd, format=fmt)
                response.append(resp)
            except (ValueError, RpcError):
                exc = get_exception()
                self._fail('Unable to get cli output: %s' % str(exc))
            except Exception:
                exc = get_exception()
                self._fail('Uncaught exception - please report: %s' % str(exc))

        return response

    def unlock_config(self):
        try:
            self.config.unlock()
            self._locked = False
        except UnlockError:
            exc = get_exception()
            self.module.log('unable to unlock config: {0}'.format(str(exc)))

    def lock_config(self):
        try:
            self.config.lock()
            self._locked = True
        except LockError:
            exc = get_exception()
            self.module.log('unable to lock config: {0}'.format(str(exc)))

    def check_config(self):
        if not self.config.commit_check():
            self._fail(msg='Commit check failed')

    def commit_config(self, comment=None, confirm=None):
        try:
            kwargs = dict(comment=comment)
            if confirm and confirm > 0:
                kwargs['confirm'] = confirm
            return self.config.commit(**kwargs)
        except CommitError:
            exc = get_exception()
            msg = 'Unable to commit configuration: {0}'.format(str(exc))
            self._fail(msg=msg)

    def load_config(self, candidate, action='replace', comment=None,
            confirm=None, format='text', commit=True):

        merge = action == 'merge'
        overwrite = action == 'overwrite'

        self.lock_config()

        try:
            self.config.load(candidate, format=format, merge=merge,
                    overwrite=overwrite)
        except ConfigLoadError:
            exc = get_exception()
            msg = 'Unable to load config: {0}'.format(str(exc))
            self._fail(msg=msg)

        diff = self.config.diff()
        self.check_config()
        if commit and diff:
            self.commit_config(comment=comment, confirm=confirm)

        self.unlock_config()

        return diff

    def rollback_config(self, identifier, commit=True, comment=None):

        self.lock_config()

        try:
            result = self.config.rollback(identifier)
        except Exception:
            exc = get_exception()
            msg = 'Unable to rollback config: {0}'.format(str(exc))
            self._fail(msg=msg)

        diff = self.config.diff()
        if commit:
            self.commit_config(comment=comment)

        self.unlock_config()
        return diff

    def disconnect(self):
        if self.device:
            self.device.close()

    def get_facts(self, refresh=True):
        if refresh:
            self.device.facts_refresh()
        return self.device.facts

    def get_config(self, config_format="text"):
        if config_format not in ['text', 'set', 'xml']:
            msg = 'invalid config format... must be one of xml, text, set'
            self._fail(msg=msg)

        ele = self.rpc('get_configuration', format=config_format)
        if config_format in ['text', 'set']:
           return str(ele.text).strip()
        elif config_format == "xml":
            return ele

    def rpc(self, name, format='xml', **kwargs):
        meth = getattr(self.device.rpc, name)
        reply = meth({'format': format}, **kwargs)
        return reply
Ejemplo n.º 9
0
class TestDevice(unittest.TestCase):

    @patch('ncclient.manager.connect')
    def setUp(self, mock_connect):
        mock_connect.side_effect = self._mock_manager

        self.dev = Device(host='1.1.1.1', user='******', password='******',
                          gather_facts=False)
        self.dev.open()

    @patch('ncclient.operations.session.CloseSession.request')
    def tearDown(self, mock_session):
        self.dev.close()

    @patch('jnpr.junos.device.netconf_ssh')
    def test_device_ConnectAuthError(self, mock_manager):
        mock_manager.connect.side_effect = NcErrors.AuthenticationError
        self.assertRaises(EzErrors.ConnectAuthError, self.dev.open)

    @patch('jnpr.junos.device.netconf_ssh')
    def test_device_ConnectRefusedError(self, mock_manager):
        mock_manager.connect.side_effect = NcErrors.SSHError
        self.assertRaises(EzErrors.ConnectRefusedError, self.dev.open)

    @patch('jnpr.junos.device.netconf_ssh')
    @patch('jnpr.junos.device.datetime')
    def test_device_ConnectTimeoutError(self, mock_datetime, mock_manager):
        mock_manager.connect.side_effect = NcErrors.SSHError(
            "Could not open socket to 1.1.1.1:830")
        from datetime import timedelta, datetime
        currenttime = datetime.now()
        mock_datetime.datetime.now.side_effect = [currenttime,
                                                  currenttime + timedelta(minutes=4)]
        self.assertRaises(EzErrors.ConnectTimeoutError, self.dev.open)

    @patch('jnpr.junos.device.netconf_ssh')
    @patch('jnpr.junos.device.datetime')
    def test_device_diff_err_message(self, mock_datetime, mock_manager):
        NcErrors.SSHError.message = 'why are you trying :)'
        mock_manager.connect.side_effect = NcErrors.SSHError
        from datetime import timedelta, datetime
        currenttime = datetime.now()
        mock_datetime.datetime.now.side_effect = [currenttime,
                                                  currenttime + timedelta(minutes=4)]
        self.assertRaises(EzErrors.ConnectError, self.dev.open)

    @patch('jnpr.junos.device.netconf_ssh')
    def test_device_ConnectUnknownHostError(self, mock_manager):
        import socket
        mock_manager.connect.side_effect = socket.gaierror
        self.assertRaises(EzErrors.ConnectUnknownHostError, self.dev.open)

    @patch('jnpr.junos.device.netconf_ssh')
    def test_device_other_error(self, mock_manager):
        mock_manager.connect.side_effect = TypeError
        self.assertRaises(EzErrors.ConnectError, self.dev.open)

    def test_device_probe_error(self):
        mock_probe = MagicMock()
        mock_probe.return_value = None
        self.dev.probe = mock_probe

        def fn():
            self.dev.open(auto_probe=1)
        self.assertRaises(EzErrors.ProbeError, fn)

    def test_device_property_logfile_isinstance(self):
        mock = MagicMock()
        with patch(builtin_string + '.open', mock):
            if sys.version >'3':
                builtin_file = 'io.TextIOWrapper'
            else:
                builtin_file = builtin_string + '.file'
            with patch(builtin_file, MagicMock):
                handle = open('filename', 'r')
                self.dev.logfile = handle
                self.assertEqual(self.dev.logfile, handle)

    def test_device_host_mand_param(self):
        self.assertRaises(ValueError, Device, user='******',
                          password='******',
                          gather_facts=False)

    def test_device_property_logfile_close(self):
        self.dev._logfile = MagicMock()
        self.dev._logfile.close.return_value = 0
        self.dev.logfile = None
        self.assertFalse(self.dev._logfile)

    def test_device_property_logfile_exception(self):
        try:
            self.dev.logfile = True
        except Exception as ex:
            self.assertEqual(type(ex), ValueError)

    def test_device_repr(self):
        localdev = Device(host='1.1.1.1', user='******', password='******',
                          gather_facts=False)
        self.assertEqual(repr(localdev), 'Device(1.1.1.1)')

    def test_device_local(self):
        Device.ON_JUNOS = True
        localdev = Device()
        self.assertEqual(localdev._hostname, 'localhost')

    @patch('jnpr.junos.device.os')
    @patch(builtin_string + '.open')
    @patch('paramiko.config.SSHConfig.lookup')
    def test_device__sshconf_lkup(self, os_mock, open_mock, mock_paramiko):
        os_mock.path.exists.return_value = True
        self.dev._sshconf_lkup()
        mock_paramiko.assert_called_any()

    @patch('jnpr.junos.device.os')
    @patch(builtin_string + '.open')
    @patch('paramiko.config.SSHConfig.lookup')
    def test_device__sshconf_lkup_def(self, os_mock, open_mock, mock_paramiko):
        os_mock.path.exists.return_value = True
        self.dev._ssh_config = '/home/rsherman/.ssh/config'
        self.dev._sshconf_lkup()
        mock_paramiko.assert_called_any()

    @patch('os.getenv')
    def test_device__sshconf_lkup_path_not_exists(self, mock_env):
        mock_env.return_value = '/home/test'
        self.assertEqual(self.dev._sshconf_lkup(), None)

    @patch('os.getenv')
    def test_device__sshconf_lkup_home_not_defined(self, mock_env):
        mock_env.return_value = None
        self.assertEqual(self.dev._sshconf_lkup(), None)
        mock_env.assert_called_with('HOME')

    @patch('ncclient.manager.connect')
    @patch('jnpr.junos.Device.execute')
    def test_device_open(self, mock_connect, mock_execute):
        with patch('jnpr.junos.utils.fs.FS.cat') as mock_cat:
            mock_cat.return_value = """

    domain jls.net

            """
            mock_connect.side_effect = self._mock_manager
            mock_execute.side_effect = self._mock_manager
            self.dev2 = Device(
                host='2.2.2.2',
                user='******',
                password='******')
            self.dev2.open()
            self.assertEqual(self.dev2.connected, True)

    @patch('jnpr.junos.Device.execute')
    def test_device_facts(self, mock_execute):
        with patch('jnpr.junos.utils.fs.FS.cat') as mock_cat:
            mock_execute.side_effect = self._mock_manager
            mock_cat.return_value = """

    domain jls.net

            """
            self.dev.facts_refresh()
            assert self.dev.facts['version'] == facts['version']

    @patch('jnpr.junos.Device.execute')
    @patch('jnpr.junos.device.warnings')
    def test_device_facts_error(self, mock_warnings, mock_execute):
        with patch('jnpr.junos.utils.fs.FS.cat') as mock_cat:
            mock_execute.side_effect = self._mock_manager
            mock_cat.side_effect = IOError('File cant be handled')
            self.dev.facts_refresh()
            self.assertTrue(mock_warnings.warn.called)

    def test_device_hostname(self):
        self.assertEqual(self.dev.hostname, '1.1.1.1')

    def test_device_user(self):
        self.assertEqual(self.dev.user, 'rick')

    def test_device_get_password(self):
        self.assertEqual(self.dev.password, None)

    def test_device_set_password(self):
        self.dev.password = '******'
        self.assertEqual(self.dev._auth_password, 'secret')

    def test_device_get_timeout(self):
        self.assertEqual(self.dev.timeout, 30)

    def test_device_set_timeout(self):
        self.dev.timeout = 10
        self.assertEqual(self.dev.timeout, 10)

    def test_device_manages(self):
        self.assertEqual(self.dev.manages, [],
                         'By default manages will be empty list')

    @patch('ncclient.manager.connect')
    @patch('jnpr.junos.Device.execute')
    def test_device_open_normalize(self, mock_connect, mock_execute):
        mock_connect.side_effect = self._mock_manager
        self.dev2 = Device(host='2.2.2.2', user='******', password='******')
        self.dev2.open(gather_facts=False, normalize=True)
        self.assertEqual(self.dev2.transform, self.dev2._norm_transform)

    def test_device_set_facts_exception(self):
        try:
            self.dev.facts = 'test'
        except RuntimeError as ex:
            self.assertEqual(RuntimeError, type(ex))

    @patch('jnpr.junos.Device.execute')
    def test_device_cli(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertEqual(self.dev.cli('show cli directory').tag, 'cli')

    @patch('jnpr.junos.Device.execute')
    def test_device_cli_conf_info(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertTrue('ge-0/0/0' in self.dev.cli('show configuration'))

    @patch('jnpr.junos.Device.execute')
    def test_device_cli_output(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertTrue('Alarm' in self.dev.cli('show system alarms'))

    @patch('jnpr.junos.Device.execute')
    def test_device_cli_rpc(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertEqual(self.dev.cli('show system uptime | display xml rpc')
                         .tag, 'get-system-uptime-information')

    def test_device_cli_exception(self):
        self.dev.rpc.cli = MagicMock(side_effect=AttributeError)
        val = self.dev.cli('show version')
        self.assertEqual(val, 'invalid command: show version')

    @patch('jnpr.junos.Device.execute')
    def test_device_display_xml_rpc(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertEqual(
            self.dev.display_xml_rpc('show system uptime ').tag,
            'get-system-uptime-information')

    @patch('jnpr.junos.Device.execute')
    def test_device_display_xml_rpc_text(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertIn(
            '<get-system-uptime-information>',
            self.dev.display_xml_rpc(
                'show system uptime ',
                format='text').decode('utf-8'))

    @patch('jnpr.junos.Device.execute')
    def test_device_display_xml_exception(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertEqual(
            self.dev.display_xml_rpc('show foo'),
            'invalid command: show foo| display xml rpc')

    def test_device_execute(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        print (self.dev.execute('<get-system-core-dumps/>').tag)
        self.assertEqual(self.dev.execute('<get-system-core-dumps/>').tag,
                         'directory-list')

    def test_device_execute_topy(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertEqual(self.dev.execute('<get-system-core-dumps/>',
                                          to_py=self._do_nothing), 'Nothing')

# This test is for the commented out rpc-error code
#     def test_device_execute_exception(self):
#         self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
#         self.assertRaises(RpcError, self.dev.execute,
#                           '<load-configuration-error/>')

    def test_device_execute_unknown_exception(self):
        class MyException(Exception):
            pass
        self.dev._conn.rpc = MagicMock(side_effect=MyException)
        self.assertRaises(MyException, self.dev.execute,
                          '<get-software-information/>')

    def test_device_execute_rpc_error(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertRaises(RpcError, self.dev.rpc.get_rpc_error)

    def test_device_execute_permission_error(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertRaises(
            EzErrors.PermissionError,
            self.dev.rpc.get_permission_denied)

    def test_device_execute_index_error(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertTrue(self.dev.rpc.get_index_error())

    def test_device_execute_ValueError(self):
        self.assertRaises(ValueError, self.dev.execute, None)

    def test_device_execute_unopened(self):
        self.dev.connected = False
        self.assertRaises(EzErrors.ConnectClosedError, self.dev.execute, None)

    def test_device_execute_timeout(self):
        self.dev._conn.rpc = MagicMock(side_effect=TimeoutExpiredError)
        self.assertRaises(
            EzErrors.RpcTimeoutError,
            self.dev.rpc.get_rpc_timeout)

    def test_device_execute_closed(self):
        self.dev._conn.rpc = MagicMock(side_effect=NcErrors.TransportError)
        self.assertRaises(
            EzErrors.ConnectClosedError,
            self.dev.rpc.get_rpc_close)
        self.assertFalse(self.dev.connected)

    def test_device_rpcmeta(self):
        self.assertEqual(self.dev.rpc.get_software_information.__doc__,
                         'get-software-information')

    def test_device_probe_timeout_zero(self):
        with patch('jnpr.junos.device.socket'):
            self.assertFalse(self.dev.probe(0))

    def test_device_probe_timeout_gt_zero(self):
        with patch('jnpr.junos.device.socket'):
            self.assertTrue(self.dev.probe(1),
                            'probe fn is not working for'
                            ' timeout greater than zero')

    def test_device_probe_timeout_exception(self):
        with patch('jnpr.junos.device.socket') as mock_socket:
            with patch('jnpr.junos.device.time.sleep') as mock_time:
                mock_socket.socket.return_value.close.side_effect \
                    = RuntimeError
                mock_time.return_value = None
                self.assertFalse(self.dev.probe(.01))

    def test_device_bind_varg(self):
        self.dev.bind()
        mock = MagicMock()
        mock.__name__ = 'magic_mock'
        self.dev.bind(mock)
        self.assertEqual(self.dev.magic_mock.__name__, 'magic_mock')

    def test_device_bind_kvarg(self):
        self.dev.bind()
        mock = MagicMock()
        mock.return_value = 'Test'
        self.dev.bind(kw=mock)
        self.assertEqual(self.dev.kw, 'Test')

    def test_device_bind_varg_exception(self):
        def varg():
            self.dev.bind()
            mock = MagicMock()
            mock.__name__ = 'magic mock'
            # for *args
            self.dev.bind(mock)
            self.dev.bind(mock)
        self.assertRaises(ValueError, varg)

    def test_device_bind_kvarg_exception(self):
        def kve():
            self.dev.bind()
            mock = MagicMock()
            mock.__name__ = 'magic mock'
            # for **kwargs
            self.dev.bind(kw=mock)
            self.dev.bind(kw=mock)
        self.assertRaises(ValueError, kve)

    def test_device_template(self):
        # Try to load the template relative to module base
        try:
            template = self.dev.Template(
                'tests/unit/templates/config-example.xml')
        except:
            # Try to load the template relative to test base
            try:
                template = self.dev.Template('templates/config-example.xml')
            except:
                raise
        self.assertEqual(template.render({'host_name': '1',
                                          'domain_name': '2'}),
                         'system {\n  host-name 1;\n  domain-name 2;\n}')

    def test_device_close(self):
        def close_conn():
            self.dev.connected = False
        self.dev.close = MagicMock(name='close')
        self.dev.close.side_effect = close_conn
        self.dev.close()
        self.assertEqual(self.dev.connected, False)

    @patch('ncclient.manager.connect')
    def test_device_context_manager(self, mock_connect):
        mock_connect.side_effect = self._mock_manager
        try:
            with Device(host='3.3.3.3', user='******',
                        password='******', gather_facts=False) as dev:
                self.assertTrue(dev.connected)
                dev._conn = MagicMock(name='_conn')
                dev._conn.connected = True

                def close_conn():
                    dev.connected = False
                dev.close = MagicMock(name='close')
                dev.close.side_effect = close_conn
                raise RpcError
        except Exception as e:
            self.assertIsInstance(e, RpcError)
        self.assertFalse(dev.connected)

    def _read_file(self, fname):
        from ncclient.xml_ import NCElement

        fpath = os.path.join(os.path.dirname(__file__),
                             'rpc-reply', fname)
        with open(fpath) as fp:
            foo = fp.read()

            if fname == 'get-rpc-error.xml':
                # Raise ncclient exception for error
                raise RPCError(etree.XML(foo))
            elif fname == 'get-permission-denied.xml':
                # Raise ncclient exception for error
                raise RPCError(etree.XML(foo))
            elif (fname == 'get-index-error.xml' or
                    fname == 'get-system-core-dumps.xml' or
                    fname == 'load-configuration-error.xml'):
                rpc_reply = NCElement(foo, self.dev._conn._device_handler
                                  .transform_reply())
            elif (fname == 'show-configuration.xml' or
                  fname == 'show-system-alarms.xml'):
                rpc_reply = NCElement(foo, self.dev._conn._device_handler
                                  .transform_reply())._NCElement__doc
            else:
                rpc_reply = NCElement(foo, self.dev._conn._device_handler
                                  .transform_reply())._NCElement__doc[0]
        return rpc_reply

    def _mock_manager(self, *args, **kwargs):
        if kwargs:
            device_params = kwargs['device_params']
            device_handler = make_device_handler(device_params)
            session = SSHSession(device_handler)
            return Manager(session, device_handler)

        elif args:
            if args[0].tag == 'command':
                if args[0].text == 'show cli directory':
                    return self._read_file('show-cli-directory.xml')
                elif args[0].text == 'show configuration':
                    return self._read_file('show-configuration.xml')
                elif args[0].text == 'show system alarms':
                    return self._read_file('show-system-alarms.xml')
                elif args[0].text == 'show system uptime | display xml rpc':
                    return self._read_file('show-system-uptime-rpc.xml')
                else:
                    raise RpcError

            else:
                return self._read_file(args[0].tag + '.xml')

    def _do_nothing(self, *args, **kwargs):
        return 'Nothing'
Ejemplo n.º 10
0
import json
#import yaml
import sys
from jnpr.junos import Device
from jnpr.junos.exception import ConnectError
from pprint import pprint

dev = Device('host', user='******', password='******')

try:
    dev.open()
except Exception as err:
    print "Unable to connect to host:", err
    sys.exit(1)

dev.facts_refresh(exception_on_failure=True)
#print yaml.dump(dev.facts)
print json.dumps(dev.facts)
op = json.dumps(dev.facts)
pprint (op)
dev.close()
Ejemplo n.º 11
0
class TestDevice(unittest.TestCase):
    @patch('ncclient.manager.connect')
    def setUp(self, mock_connect):
        mock_connect.side_effect = self._mock_manager
        self.dev = Device(host='1.1.1.1',
                          user='******',
                          password='******',
                          gather_facts=False)
        self.dev.open()

    @patch('ncclient.operations.session.CloseSession.request')
    def tearDown(self, mock_session):
        self.dev.close()

    @patch('jnpr.junos.device.netconf_ssh')
    def test_device_ConnectAuthError(self, mock_manager):
        mock_manager.connect.side_effect = NcErrors.AuthenticationError
        self.assertRaises(EzErrors.ConnectAuthError, self.dev.open)

    @patch('jnpr.junos.device.netconf_ssh')
    def test_device_ConnectRefusedError(self, mock_manager):
        mock_manager.connect.side_effect = NcErrors.SSHError
        self.assertRaises(EzErrors.ConnectRefusedError, self.dev.open)

    @patch('jnpr.junos.device.netconf_ssh')
    @patch('jnpr.junos.device.datetime')
    def test_device_ConnectTimeoutError(self, mock_datetime, mock_manager):
        NcErrors.SSHError.message = 'cannot open'
        mock_manager.connect.side_effect = NcErrors.SSHError
        from datetime import timedelta, datetime
        currenttime = datetime.now()
        mock_datetime.datetime.now.side_effect = [
            currenttime, currenttime + timedelta(minutes=4)
        ]
        self.assertRaises(EzErrors.ConnectTimeoutError, self.dev.open)

    @patch('jnpr.junos.device.netconf_ssh')
    @patch('jnpr.junos.device.datetime')
    def test_device_diff_err_message(self, mock_datetime, mock_manager):
        NcErrors.SSHError.message = 'why are you trying :)'
        mock_manager.connect.side_effect = NcErrors.SSHError
        from datetime import timedelta, datetime
        currenttime = datetime.now()
        mock_datetime.datetime.now.side_effect = [
            currenttime, currenttime + timedelta(minutes=4)
        ]
        self.assertRaises(EzErrors.ConnectError, self.dev.open)

    @patch('jnpr.junos.device.netconf_ssh')
    def test_device_ConnectUnknownHostError(self, mock_manager):
        import socket
        mock_manager.connect.side_effect = socket.gaierror
        self.assertRaises(EzErrors.ConnectUnknownHostError, self.dev.open)

    @patch('jnpr.junos.device.netconf_ssh')
    def test_device_other_error(self, mock_manager):
        mock_manager.connect.side_effect = TypeError
        self.assertRaises(EzErrors.ConnectError, self.dev.open)

    def test_device_probe_error(self):
        mock_probe = MagicMock()
        mock_probe.return_value = None
        self.dev.probe = mock_probe

        def fn():
            self.dev.open(auto_probe=1)

        self.assertRaises(EzErrors.ProbeError, fn)

    def test_device_property_logfile_isinstance(self):
        mock = MagicMock()
        with patch('__builtin__.open', mock):
            with patch('__builtin__.file', MagicMock):
                handle = open('filename', 'r')
                self.dev.logfile = handle
                self.assertEqual(self.dev.logfile, handle)

    def test_device_host_mand_param(self):
        self.assertRaises(ValueError,
                          Device,
                          user='******',
                          password='******',
                          gather_facts=False)

    def test_device_property_logfile_close(self):
        self.dev._logfile = MagicMock()
        self.dev._logfile.close.return_value = 0
        self.dev.logfile = None
        self.assertFalse(self.dev._logfile)

    def test_device_property_logfile_exception(self):
        try:
            self.dev.logfile = True
        except Exception as ex:
            self.assertEqual(type(ex), ValueError)

    def test_device_repr(self):
        localdev = Device(host='1.1.1.1',
                          user='******',
                          password='******',
                          gather_facts=False)
        self.assertEqual(repr(localdev), 'Device(1.1.1.1)')

    def test_device_local(self):
        Device.ON_JUNOS = True
        localdev = Device()
        self.assertEqual(localdev._hostname, 'localhost')

    @patch('jnpr.junos.device.os')
    @patch('__builtin__.open')
    @patch('paramiko.config.SSHConfig.lookup')
    def test_device__sshconf_lkup(self, os_mock, open_mock, mock_paramiko):
        os_mock.path.exists.return_value = True
        self.dev._sshconf_lkup()
        mock_paramiko.assert_called_any()

    @patch('jnpr.junos.device.os')
    @patch('__builtin__.open')
    @patch('paramiko.config.SSHConfig.lookup')
    def test_device__sshconf_lkup_def(self, os_mock, open_mock, mock_paramiko):
        os_mock.path.exists.return_value = True
        self.dev._ssh_config = '/home/rsherman/.ssh/config'
        self.dev._sshconf_lkup()
        mock_paramiko.assert_called_any()

    @patch('os.getenv')
    def test_device__sshconf_lkup_path_not_exists(self, mock_env):
        mock_env.return_value = '/home/test'
        self.assertEqual(self.dev._sshconf_lkup(), None)

    @patch('os.getenv')
    def test_device__sshconf_lkup_home_not_defined(self, mock_env):
        mock_env.return_value = None
        self.assertEqual(self.dev._sshconf_lkup(), None)
        mock_env.assert_called_with('HOME')

    @patch('ncclient.manager.connect')
    @patch('jnpr.junos.Device.execute')
    def test_device_open(self, mock_connect, mock_execute):
        with patch('jnpr.junos.utils.fs.FS.cat') as mock_cat:
            mock_cat.return_value = """

    domain jls.net

            """
            mock_connect.side_effect = self._mock_manager
            mock_execute.side_effect = self._mock_manager
            self.dev2 = Device(host='2.2.2.2',
                               user='******',
                               password='******')
            self.dev2.open()
            self.assertEqual(self.dev2.connected, True)

    @patch('jnpr.junos.Device.execute')
    def test_device_facts(self, mock_execute):
        with patch('jnpr.junos.utils.fs.FS.cat') as mock_cat:
            mock_execute.side_effect = self._mock_manager
            mock_cat.return_value = """

    domain jls.net

            """
            self.dev.facts_refresh()
            assert self.dev.facts['version'] == facts['version']

    def test_device_hostname(self):
        self.assertEqual(self.dev.hostname, '1.1.1.1')

    def test_device_user(self):
        self.assertEqual(self.dev.user, 'rick')

    def test_device_get_password(self):
        self.assertEqual(self.dev.password, None)

    def test_device_set_password(self):
        self.dev.password = '******'
        self.assertEqual(self.dev._password, 'secret')

    def test_device_get_timeout(self):
        self.assertEqual(self.dev.timeout, 30)

    def test_device_set_timeout(self):
        self.dev.timeout = 10
        self.assertEqual(self.dev.timeout, 10)

    def test_device_manages(self):
        self.assertEqual(self.dev.manages, [],
                         'By default manages will be empty list')

    def test_device_set_facts_exception(self):
        try:
            self.dev.facts = 'test'
        except RuntimeError as ex:
            self.assertEqual(RuntimeError, type(ex))

    @patch('jnpr.junos.Device.execute')
    def test_device_cli(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertEqual(self.dev.cli('show cli directory').tag, 'cli')

    @patch('jnpr.junos.Device.execute')
    def test_device_cli_conf_info(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertTrue('ge-0/0/0' in self.dev.cli('show configuration'))

    @patch('jnpr.junos.Device.execute')
    def test_device_cli_output(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertTrue('Alarm' in self.dev.cli('show system alarms'))

    @patch('jnpr.junos.Device.execute')
    def test_device_cli_rpc(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertEqual(
            self.dev.cli('show system uptime | display xml rpc').tag,
            'get-system-uptime-information')

    def test_device_cli_exception(self):
        self.dev.rpc.cli = MagicMock(side_effect=AttributeError)
        val = self.dev.cli('show version')
        self.assertEqual(val, 'invalid command: show version')

    @patch('jnpr.junos.Device.execute')
    def test_device_display_xml_rpc(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertEqual(
            self.dev.display_xml_rpc('show system uptime ').tag,
            'get-system-uptime-information')

    @patch('jnpr.junos.Device.execute')
    def test_device_display_xml_rpc_text(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertIn(
            '<get-system-uptime-information>',
            self.dev.display_xml_rpc('show system uptime ', format='text'))

    @patch('jnpr.junos.Device.execute')
    def test_device_display_xml_exception(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertEqual(self.dev.display_xml_rpc('show foo'),
                         'invalid command: show foo| display xml rpc')

    def test_device_execute(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertEqual(
            self.dev.execute('<get-system-core-dumps/>').tag, 'directory-list')

    def test_device_execute_topy(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertEqual(
            self.dev.execute('<get-system-core-dumps/>',
                             to_py=self._do_nothing), 'Nothing')

# This test is for the commented out rpc-error code
#     def test_device_execute_exception(self):
#         self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
#         self.assertRaises(RpcError, self.dev.execute,
#                           '<load-configuration-error/>')

    def test_device_execute_unknown_exception(self):
        class MyException(Exception):
            pass

        self.dev._conn.rpc = MagicMock(side_effect=MyException)
        self.assertRaises(MyException, self.dev.execute,
                          '<get-software-information/>')

    def test_device_execute_rpc_error(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertRaises(RpcError, self.dev.rpc.get_rpc_error)

    def test_device_execute_index_error(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertTrue(self.dev.rpc.get_index_error())

    def test_device_execute_ValueError(self):
        self.assertRaises(ValueError, self.dev.execute, None)

    def test_device_rpcmeta(self):
        self.assertEqual(self.dev.rpc.get_software_information.func_doc,
                         'get-software-information')

    def test_device_probe_timeout_zero(self):
        with patch('jnpr.junos.device.socket'):
            self.assertFalse(self.dev.probe(0))

    def test_device_probe_timeout_gt_zero(self):
        with patch('jnpr.junos.device.socket'):
            self.assertTrue(
                self.dev.probe(1), 'probe fn is not working for'
                ' timeout greater than zero')

    def test_device_probe_timeout_exception(self):
        with patch('jnpr.junos.device.socket') as mock_socket:
            with patch('jnpr.junos.device.time.sleep') as mock_time:
                mock_socket.socket.return_value.close.side_effect \
                    = RuntimeError
                mock_time.return_value = None
                self.assertFalse(self.dev.probe(.01))

    def test_device_bind_varg(self):
        self.dev.bind()
        mock = MagicMock()
        mock.__name__ = 'magic_mock'
        self.dev.bind(mock)
        self.assertEqual(self.dev.magic_mock.__name__, 'magic_mock')

    def test_device_bind_kvarg(self):
        self.dev.bind()
        mock = MagicMock()
        mock.return_value = 'Test'
        self.dev.bind(kw=mock)
        self.assertEqual(self.dev.kw, 'Test')

    def test_device_bind_varg_exception(self):
        def varg():
            self.dev.bind()
            mock = MagicMock()
            mock.__name__ = 'magic mock'
            # for *args
            self.dev.bind(mock)
            self.dev.bind(mock)

        self.assertRaises(ValueError, varg)

    def test_device_bind_kvarg_exception(self):
        def kve():
            self.dev.bind()
            mock = MagicMock()
            mock.__name__ = 'magic mock'
            # for **kwargs
            self.dev.bind(kw=mock)
            self.dev.bind(kw=mock)

        self.assertRaises(ValueError, kve)

    def test_device_template(self):
        # Try to load the template relative to module base
        try:
            template = self.dev.Template(
                'tests/unit/templates/config-example.xml')
        except:
            # Try to load the template relative to test base
            try:
                template = self.dev.Template('templates/config-example.xml')
            except:
                raise
        self.assertEqual(
            template.render({
                'host_name': '1',
                'domain_name': '2'
            }), 'system {\n  host-name 1;\n  domain-name 2;\n}')

    def test_device_close(self):
        def close_conn():
            self.dev.connected = False

        self.dev.close = MagicMock(name='close')
        self.dev.close.side_effect = close_conn
        self.dev.close()
        self.assertEqual(self.dev.connected, False)

    def _read_file(self, fname):
        from ncclient.xml_ import NCElement

        fpath = os.path.join(os.path.dirname(__file__), 'rpc-reply', fname)
        foo = open(fpath).read()

        if fname == 'get-rpc-error.xml':
            # Raise ncclient exception for error
            raise RPCError(etree.XML(foo))
        elif (fname == 'get-index-error.xml'
              or fname == 'get-system-core-dumps.xml'
              or fname == 'load-configuration-error.xml'):
            rpc_reply = NCElement(
                foo, self.dev._conn._device_handler.transform_reply())
        elif (fname == 'show-configuration.xml'
              or fname == 'show-system-alarms.xml'):
            rpc_reply = NCElement(
                foo, self.dev._conn._device_handler.transform_reply()
            )._NCElement__doc
        else:
            rpc_reply = NCElement(
                foo, self.dev._conn._device_handler.transform_reply()
            )._NCElement__doc[0]
        return rpc_reply

    def _mock_manager(self, *args, **kwargs):
        if kwargs:
            device_params = kwargs['device_params']
            device_handler = make_device_handler(device_params)
            session = SSHSession(device_handler)
            return Manager(session, device_handler)

        elif args:
            if args[0].tag == 'command':
                if args[0].text == 'show cli directory':
                    return self._read_file('show-cli-directory.xml')
                elif args[0].text == 'show configuration':
                    return self._read_file('show-configuration.xml')
                elif args[0].text == 'show system alarms':
                    return self._read_file('show-system-alarms.xml')
                elif args[0].text == 'show system uptime | display xml rpc':
                    return self._read_file('show-system-uptime-rpc.xml')
                else:
                    raise RpcError

            else:
                return self._read_file(args[0].tag + '.xml')

    def _do_nothing(self, *args, **kwargs):
        return 'Nothing'
Ejemplo n.º 12
0
class Netconf(object):
    def __init__(self, module):
        self.module = module
        self.device = None
        self.config = None
        self._locked = False

    def _fail(self, msg):
        if self.device:
            if self._locked:
                self.config.unlock()
            self.disconnect()
        self.module.fail_json(msg=msg)

    def connect(self, **kwargs):
        try:
            host = self.module.params['host']
            port = self.module.params['port'] or 830

            user = self.module.params['username']
            passwd = self.module.params['password']
            key_filename = self.module.params['ssh_keyfile']

            self.device = Device(host,
                                 user=user,
                                 passwd=passwd,
                                 port=port,
                                 gather_facts=False,
                                 ssh_private_key_file=key_filename).open()

            self.config = Config(self.device)

        except Exception:
            exc = get_exception()
            self._fail('unable to connect to %s: %s' % (host, str(exc)))

    def run_commands(self, commands, **kwargs):
        response = list()
        fmt = kwargs.get('format') or 'xml'

        for cmd in to_list(commands):
            try:
                resp = self.device.cli(command=cmd, format=fmt)
                response.append(resp)
            except (ValueError, RpcError):
                exc = get_exception()
                self._fail('Unable to get cli output: %s' % str(exc))
            except Exception:
                exc = get_exception()
                self._fail('Uncaught exception - please report: %s' % str(exc))

        return response

    def unlock_config(self):
        try:
            self.config.unlock()
            self._locked = False
        except UnlockError:
            exc = get_exception()
            self.module.log('unable to unlock config: {0}'.format(str(exc)))

    def lock_config(self):
        try:
            self.config.lock()
            self._locked = True
        except LockError:
            exc = get_exception()
            self.module.log('unable to lock config: {0}'.format(str(exc)))

    def check_config(self):
        if not self.config.commit_check():
            self._fail(msg='Commit check failed')

    def commit_config(self, comment=None, confirm=None):
        try:
            kwargs = dict(comment=comment)
            if confirm and confirm > 0:
                kwargs['confirm'] = confirm
            return self.config.commit(**kwargs)
        except CommitError:
            exc = get_exception()
            msg = 'Unable to commit configuration: {0}'.format(str(exc))
            self._fail(msg=msg)

    def load_config(self,
                    candidate,
                    action='replace',
                    comment=None,
                    confirm=None,
                    format='text',
                    commit=True):

        merge = action == 'merge'
        overwrite = action == 'overwrite'

        self.lock_config()

        try:
            self.config.load(candidate,
                             format=format,
                             merge=merge,
                             overwrite=overwrite)
        except ConfigLoadError:
            exc = get_exception()
            msg = 'Unable to load config: {0}'.format(str(exc))
            self._fail(msg=msg)

        diff = self.config.diff()
        self.check_config()
        if commit and diff:
            self.commit_config(comment=comment, confirm=confirm)

        self.unlock_config()

        return diff

    def rollback_config(self, identifier, commit=True, comment=None):

        self.lock_config()

        try:
            result = self.config.rollback(identifier)
        except Exception:
            exc = get_exception()
            msg = 'Unable to rollback config: {0}'.format(str(exc))
            self._fail(msg=msg)

        diff = self.config.diff()
        if commit:
            self.commit_config(comment=comment)

        self.unlock_config()
        return diff

    def disconnect(self):
        if self.device:
            self.device.close()

    def get_facts(self, refresh=True):
        if refresh:
            self.device.facts_refresh()
        return self.device.facts

    def get_config(self, config_format="text"):
        if config_format not in ['text', 'set', 'xml']:
            msg = 'invalid config format... must be one of xml, text, set'
            self._fail(msg=msg)

        ele = self.rpc('get_configuration', format=config_format)
        if config_format in ['text', 'set']:
            return str(ele.text).strip()
        elif config_format == "xml":
            return ele

    def rpc(self, name, format='xml', **kwargs):
        meth = getattr(self.device.rpc, name)
        reply = meth({'format': format}, **kwargs)
        return reply
Ejemplo n.º 13
0
class RunUpgrade(object):
    def __init__(self):
        self.arch = ''
        self.host = ''
        self.auth = ltoken()
        self.config = {}
        self.configfile = '/opt/ipeng/scripts/jtishey/junos_upgrade/config.yml'
        self.force = False
        self.yes_all = False
        self.no_install = False
        self.set_enhanced_ip = False
        self.pim_nonstop = False
        self.two_stage = False

    def get_arguments(self):
        """ Handle input from CLI """
        p = argparse.ArgumentParser(
            description='Parse and compare before/after baseline files.',
            formatter_class=lambda prog: argparse.HelpFormatter(
                prog, max_help_position=32))
        p.add_argument('-d',
                       '--device',
                       help='Specify an IP or hostname to upgrade',
                       required=True,
                       metavar='DEV')
        p.add_argument('-c',
                       '--config',
                       help='Specify an alternate config file',
                       metavar='CFG')
        p.add_argument('-f',
                       '--force',
                       action='count',
                       default=0,
                       help='Use "force" option on all package adds (DANGER!)')
        p.add_argument(
            '-n',
            '--noinstall',
            action='count',
            default=0,
            help='Do a dry-run, check for files and copying them only')
        p.add_argument(
            '-y',
            '--yes_all',
            action='count',
            default=0,
            help='Answer "y" to all questions during the upgrade (DANGER!)')
        args = vars(p.parse_args())
        self.host = args['device']
        if args['config']:
            self.configfile = args['config']
        if args['force']:
            self.force - True
        if args['noinstall']:
            self.no_install = True
        if args['yes_all']:
            self.yes_all = True

    def initial_setup(self):
        """ Setup logging, load config and check for the images on the server """
        logfile = self.host + '_upgrade.log'
        logging.basicConfig(filename=logfile,
                            level=logging.WARN,
                            format='%(asctime)s:%(name)s: %(message)s')
        logging.getLogger().name = self.host
        logging.getLogger().addHandler(logging.StreamHandler())
        logging.warn('Information logged in {0}'.format(logfile))

        # Open config file
        try:
            with open(self.configfile) as f:
                self.config = yaml.load(f)
        except:
            logging.warn('ERROR: Issues opening config file "{0}"'.format(
                self.configfile))
            exit(1)

        # verify needed packages exist on local server
        for pkg in [
                'CODE_IMAGE32', 'CODE_IMAGE64', 'CODE_2STAGE32',
                'CODE_2STAGE64', 'CODE_JSU32', 'CODE_JSU64'
        ]:
            if self.config[pkg]:
                if not (os.path.isfile(self.config['CODE_FOLDER'] +
                                       self.config[pkg])):
                    msg = 'Software package does not exist locally: {0}'.format(
                        self.config['CODE_FOLDER'] + self.config[pkg])
                    logging.error(msg)
                    if not self.yes_all:
                        cont = self.input_parse('Continue? (n/n): ')
                        if cont == 'n':
                            exit()

    def open_connection(self):
        """ Open a NETCONF connection to the device """
        if self.no_install:
            logging.warn('Running with no_install option - copy files only...')
        try:
            logging.warn('Connecting to ' + self.host + '...')
            self.dev = Device(host=self.host,
                              user=self.auth['username'],
                              password=self.auth['password'],
                              gather_facts=True)
            self.dev.open()
        except ConnectError as e:
            logging.error('Cannot connect to device: {0}'.format(e))
            exit(1)

    def collect_re_info(self):
        """ Print info on each RE: """
        if self.dev.facts['RE0']:
            logging.warn('' + self.host + ' ' + self.dev.facts['model'])
            logging.warn('-' * 24)
            if self.dev.facts['version_RE0']:
                logging.warn('            RE0   \t RE1')
                logging.warn('Mastership: {0} \t {1}'.format(
                    self.dev.facts['RE0']['mastership_state'],
                    self.dev.facts['RE1']['mastership_state']))
                logging.warn('Status:     {0} \t\t {1}'.format(
                    self.dev.facts['RE0']['status'],
                    self.dev.facts['RE1']['status']))
                logging.warn('Model:      {0} \t {1}'.format(
                    self.dev.facts['RE0']['model'],
                    self.dev.facts['RE1']['model']))
                logging.warn('Version:    {0} \t {1}'.format(
                    self.dev.facts['version_RE0'],
                    self.dev.facts['version_RE1']))
            else:
                logging.warn('              RE0  ')
                logging.warn('Mastership: {0}'.format(
                    self.dev.facts['RE0']['mastership_state'] + ''))
                logging.warn(
                    'Status:     {0}'.format(self.dev.facts['RE0']['status'] +
                                             ''))
                logging.warn(
                    'Model:      {0}'.format(self.dev.facts['RE0']['model'] +
                                             ''))
                logging.warn(
                    'Version:    {0}'.format(self.dev.facts['version'] + ''))
            logging.warn("")

            # Check for redundant REs
            logging.warn('Checking for redundant routing-engines...')
            if not self.dev.facts['2RE']:
                if not self.yes_all:
                    re_stop = input(
                        "Redundant RE's not found, Continue? (y/n): ")
                    if re_stop.lower() != 'y':
                        self.end_script()
                else:
                    logging.warn("Redundant RE's not found...")

    def copy_image(self, source, dest):
        """ Copy files via SCP """
        logging.warn("Image not found on active RE, copying now...")
        try:
            with SCP(self.dev, progress=True) as scp:
                logging.warn("Copying image to " + dest + "...")
                scp.put(source, remote_path=dest)
        except Exception as e:
            logging.warn(str(e))
            self.end_script()

    def copy_to_other_re(self, source, dest):
        """Use netmiko to copy files from one RE to the other because PyEZ doesnt allow this"""
        logging.warn("Image not found on backup RE, copying now...")
        d = {
            'device_type': 'juniper',
            'ip': self.host,
            'username': self.auth['username'],
            'password': self.auth['password'],
            'timeout': 3600
        }
        try:
            net_connect = ConnectHandler(**d)
            net_connect.send_command("file copy " + source + " " + dest)
            net_connect.disconnect()
        except Exception as e:
            logging.warn(str(e))
            logging.warn(
                "Error copying file to other RE, Please login and do this manually"
            )
            logging.warn("CMD: file copy " + source + " " + dest)

    def recursive_search(self, obj, key):
        """ recursively search dict for a key value
        https://stackoverflow.com/questions/14962485/finding-a-key-recursively-in-a-dictionary 
        """
        if key in obj: return obj[key]
        for v in obj.values():
            if isinstance(v, dict):
                item = self.recursive_search(v, key)
                if item is not None:
                    return item

    def image_check(self):
        """ Check to make sure needed files are on the device and copy if needed,
            Currently only able to copy to the active RE
        """
        # List of 64-bit capable RE's:
        RE_64 = [
            'RE-S-1800x2-8G', 'RE-S-1800x2-16G', 'RE-S-1800x4-8G',
            'RE-S-1800x4-16G'
        ]

        if self.dev.facts['RE0']['model'] in RE_64:
            self.arch = '64-bit'
        else:
            # Determine 32-bit or 64-bit:
            logging.warn('Checking for 32 or 64-bit code...')
            ver = xmltodict.parse(
                etree.tostring(
                    self.dev.rpc.get_software_information(detail=True)))
            version_info = json.dumps(ver)
            if '64-bit' in version_info:
                self.arch = '64-bit'
                logging.warn("Using 64-bit Image...")
            else:
                self.arch = '32-bit'
                logging.warn("Using 32-bit Image...")

        # Are we doing a two-stage upgrade? (Reqd for >3 major version change)
        if self.config['CODE_2STAGE32'] or self.config['CODE_2STAGE64']:
            if (int(self.config['CODE_NAME'][:2]) -
                    int(self.dev.facts['version'][:2])) > 3:
                logging.warn('Two-Stage Upgrade will be performed...')
                self.two_stage = True
        # Define all the file names / paths
        if self.arch == '32-bit':
            source = self.config['CODE_FOLDER'] + self.config['CODE_IMAGE32']
            source_2stg = self.config['CODE_FOLDER'] + self.config[
                'CODE_2STAGE32']
            source_jsu = self.config['CODE_FOLDER'] + self.config['CODE_JSU32']
            if self.two_stage:
                dest = self.config['CODE_PRESERVE'] + self.config[
                    'CODE_2STAGE32']
                dest_2stg = self.config['CODE_DEST'] + self.config[
                    'CODE_IMAGE32']
                dest_jsu = self.config['CODE_PRESERVE'] + self.config[
                    'CODE_JSU32']
            else:
                dest = self.config['CODE_DEST'] + self.config['CODE_IMAGE32']
                dest_jsu = self.config['CODE_DEST'] + self.config['CODE_JSU32']
        elif self.arch == '64-bit':
            source = self.config['CODE_FOLDER'] + self.config['CODE_IMAGE64']
            source_2stg = self.config['CODE_FOLDER'] + self.config[
                'CODE_2STAGE64']
            source_jsu = self.config['CODE_FOLDER'] + self.config['CODE_JSU64']
            if self.two_stage:
                dest = self.config['CODE_PRESERVE'] + self.config[
                    'CODE_2STAGE64']
                dest_2stg = self.config['CODE_DEST'] + self.config[
                    'CODE_IMAGE64']
                dest_jsu = self.config['CODE_PRESERVE'] + self.config[
                    'CODE_JSU64']
            else:
                dest = self.config['CODE_DEST'] + self.config['CODE_IMAGE64']
                dest_jsu = self.config['CODE_DEST'] + self.config['CODE_JSU64']

        # Check for final software image on the device
        logging.warn('Checking for image on the active RE...')
        img = xmltodict.parse(etree.tostring(
            self.dev.rpc.file_list(path=dest)))
        img_output = json.dumps(img)
        if 'No such file' in img_output:
            self.copy_image(source, dest)

        # If dual RE - Check backup RE too
        if self.dev.facts['2RE']:
            if self.dev.facts['master'] == 'RE0':
                active_RE = 're0:'
                backup_RE = 're1:'
            else:
                active_RE = 're1:'
                backup_RE = 're0:'
            logging.warn('Checking for image on the backup RE...')
            img = xmltodict.parse(
                etree.tostring(self.dev.rpc.file_list(path=backup_RE + dest)))
            img_output = json.dumps(img)
            if 'No such file' in img_output:
                self.copy_to_other_re(active_RE + dest, backup_RE + dest)
                img = xmltodict.parse(
                    etree.tostring(
                        self.dev.rpc.file_list(path=backup_RE + dest)))
                img_output = json.dumps(img)
                if 'No such file' in img_output:
                    msg = 'file copy ' + dest + ' ' + backup_RE + dest
                    logging.warn(
                        'ERROR: Copy the image to the backup RE, then re-run script'
                    )
                    logging.warn('CMD  : ' + msg)
                    self.end_script()

        # If 2 stage upgrade, look for intermediate image
        if self.two_stage:
            logging.warn('Checking for 2-stage image on the active RE...')
            img = xmltodict.parse(
                etree.tostring(self.dev.rpc.file_list(path=dest_2stg)))
            img_output = json.dumps(img)
            if 'No such file' in img_output:
                self.copy_image(source_2stg, dest_2stg)

            # Check for intermediate image file on backup RE
            if self.dev.facts['2RE']:
                logging.warn('Checking for 2-stage image on the backup RE...')
                img = xmltodict.parse(
                    etree.tostring(
                        self.dev.rpc.file_list(path=backup_RE + dest_2stg)))
                img_output = json.dumps(img)
                if 'No such file' in img_output:
                    self.copy_to_other_re(active_RE + dest_2stg,
                                          backup_RE + dest_2stg)
                    # Check again
                    img = xmltodict.parse(
                        etree.tostring(
                            self.dev.rpc.file_list(path=backup_RE +
                                                   dest_2stg)))
                    img_output = json.dumps(img)
                    if 'No such file' in img_output:
                        msg = 'file copy ' + active_RE + dest_2stg + ' ' + backup_RE + dest_2stg
                        logging.warn(
                            'ERROR: Copy the image to the backup RE, then re-run script'
                        )
                        logging.warn('CMD  : ' + msg)
                        self.end_script()

        # Check if JSU Install is requested (present in config.yml)
        if self.config['CODE_JSU32'] or self.config['CODE_JSU64']:
            # Check for the JSU on the active RE
            logging.warn('Checking for JSU on the active RE...')
            img = xmltodict.parse(
                etree.tostring(self.dev.rpc.file_list(path=dest_jsu)))
            img_output = json.dumps(img)
            if 'No such file' in img_output:
                self.copy_image(source_jsu, dest_jsu)

            # Check for the JSU on the backup RE
            if self.dev.facts['2RE']:
                logging.warn('Checking for JSU on the backup RE...')
                img = xmltodict.parse(
                    etree.tostring(
                        self.dev.rpc.file_list(path=backup_RE + dest_jsu)))
                img_output = json.dumps(img)
                if 'No such file' in img_output:
                    self.copy_to_other_re(active_RE + dest_jsu,
                                          backup_RE + dest_jsu)
                    img = xmltodict.parse(
                        etree.tostring(
                            self.dev.rpc.file_list(path=backup_RE + dest_jsu)))
                    img_output = json.dumps(img)
                    if 'No such file' in img_output:
                        msg = 'file copy ' + active_RE + dest_jsu + ' ' + backup_RE + dest_jsu
                        logging.warn(
                            'ERROR: Copy the image to the backup RE, then re-run script'
                        )
                        logging.warn('CMD  : ' + msg)
                        self.end_script()

    def system_snapshot(self):
        """ Performs [request system snapshot] on the device """
        logging.warn('Requesting system snapshot on RE0...')
        self.dev.timeout = 360
        try:
            snap = xmltodict.parse(
                etree.tostring(self.dev.rpc.request_snapshot(re0=True)))
            err = self.recursive_search(snap, 'error')
            if err:
                logging.warn("Error taking snapshot... {0}".format(
                    err['message']))

            if self.dev.facts['2RE']:
                logging.warn('Requesting system snapshot on RE1...')
                snap = xmltodict.parse(
                    etree.tostring(self.dev.rpc.request_snapshot(re1=True)))
                err = self.recursive_search(snap, 'error')
                if err:
                    logging.warn("Error taking snapshot... {0}".format(
                        err['message']))
        except Exception as e:
            logging.warn('ERROR: Problem with snapshots')
            logging.warn(str(e))
            if not self.yes_all:
                cont = self.input_parse("Contine with upgrade? (y/n): ")
                if cont == 'n':
                    self.end_script()

    def remove_traffic(self):
        """ Execute the PRE_UPGRADE_CMDS from the self.config['py file to remove traffic """
        config_cmds = self.config['PRE_UPGRADE_CMDS']
        # Network Service check on MX Platform
        if self.dev.facts['model'][:2] == 'MX':
            logging.warn("Checking for network-services enhanced-ip...")
            dpc_flag = False
            net_mode = xmltodict.parse(
                etree.tostring(self.dev.rpc.network_services()))
            cur_mode = net_mode['network-services'][
                'network-services-information']['name']
            if cur_mode != 'Enhanced-IP':
                # Check for DPCs
                logging.warn("Checking for any installed DPCs...")
                hw = xmltodict.parse(
                    etree.tostring(
                        self.dev.rpc.get_chassis_inventory(models=True)))
                for item in hw['chassis-inventory']['chassis'][
                        'chassis-module']:
                    if item['description'][:3] == 'DPC':
                        dpc_flag = True

                if dpc_flag:
                    logging.warn(
                        "Chassis has DPCs installed, skipping network-services change"
                    )
                else:
                    logging.warn('Network Services mode is ' + cur_mode + '')
                    if not self.yes_all:
                        cont = self.input_parse(
                            'Change Network Services Mode to Enhanced-IP? (y/n): '
                        )
                        if cont == 'y':
                            # Set a flag to recheck at the end and reboot if needed:
                            self.set_enhanced_ip = True
                    else:
                        self.set_enhanced_ip = True

        # PIM nonstop-routing (if configured) must be removed to deactivate GRES
        pim = self.dev.rpc.get_config(
            filter_xml='<protocols><pim><nonstop-routing/></pim></protocols>')
        if len(pim) > 0:
            config_cmds.append('deactivate protocols pim nonstop-routing')
            # set a flag so we konw to turn it back on at the end
            self.pim_nonstop = True

        # Make configuration changes
        if config_cmds:
            logging.warn('Entering Configuration Mode...')
            logging.warn('-' * 24)
            success = True
            try:
                with Config(self.dev, mode='exclusive') as cu:
                    for cmd in config_cmds:
                        cu.load(cmd, merge=True, ignore_warning=True)
                    logging.warn("Configuration Changes:")
                    logging.warn('-' * 24)
                    cu.pdiff()
                    if cu.diff():
                        if not self.yes_all:
                            cont = self.input_parse('Commit Changes? (y/n): ')
                            if cont == 'y':
                                try:
                                    cu.commit()
                                except Exception as e:
                                    logging.warn(str(e))
                                    logging.warn(
                                        "Error occurred during commit")
                                    success = False
                            else:
                                logging.warn('Rolling back changes...')
                                cu.rollback(rb_id=0)
                                success = False
                        else:
                            logging.warn('Committing changes...')
                            try:
                                cu.commit()
                            except Exception as e:
                                logging.warn(str(e))
                                logging.warn("Error occurred during commit")
                                success = False
                    else:
                        logging.warn('No changes found to commit...')
            except RuntimeError as e:
                if "Ex: format='set'" in str(e):
                    logging.warn('ERROR: Unable to parse the PRE_UPGRADE_CMDS')
                    logging.warn(
                        '       Make sure they are formatted correctly.')
                else:
                    logging.warn('ERROR: {0}'.format(e))
                success = False
            if not success:
                self.end_script()
        else:
            logging.warn("No pre-upgrade commands in CONFIG file")

    def upgrade_backup_re(self):
        """ Cycle through installing packcages for Dual RE systems """
        if self.dev.facts['master'] == 'RE0':
            backup_RE = 'RE1'
        else:
            backup_RE = 'RE0'

        # First Stage Upgrade
        if self.two_stage:
            # Only upgrade if the current version is not the 2stage, or final version:
            if self.dev.facts['version_' + backup_RE] != self.config['CODE_2STAGE_NAME'] and \
                    self.dev.facts['version_' + backup_RE] != self.config['CODE_NAME']:
                # Perform the upgrade
                self.backup_re_pkg_add(self.config['CODE_2STAGE32'],
                                       self.config['CODE_2STAGE64'],
                                       self.config['CODE_PRESERVE'])
        # Second Stage Upgrade
        # Only upgrade if the current version is not already the final version:
        if self.dev.facts['version_' + backup_RE] != self.config['CODE_NAME']:
            self.backup_re_pkg_add(self.config['CODE_IMAGE32'],
                                   self.config['CODE_IMAGE64'],
                                   self.config['CODE_DEST'])
        # JSU Upgrade
        # Only upgrade if the JSU is not already applied:
        if self.config['CODE_JSU32'] or self.config['CODE_JSU64']:
            if backup_RE == 'RE0':
                current_version = etree.tostring(
                    self.dev.rpc.get_software_information(re0=True))
            else:
                current_version = etree.tostring(
                    self.dev.rpc.get_software_information(re1=True))
            if self.config['CODE_JSU_NAME'] not in str(current_version):
                if self.two_stage:
                    self.backup_re_pkg_add(self.config['CODE_JSU32'],
                                           self.config['CODE_JSU64'],
                                           self.config['CODE_PRESERVE'])
                else:
                    self.backup_re_pkg_add(self.config['CODE_JSU32'],
                                           self.config['CODE_JSU64'],
                                           self.config['CODE_DEST'])
            else:
                logging.warn('JSU appears to already be applied on {0}'.format(
                    backup_RE))

    def backup_re_pkg_add(self, PKG32, PKG64, R_PATH):
        """ Perform software add and reboot the back RE """
        self.dev.timeout = 3600
        # Figure which RE is the current backup
        RE0, RE1 = False, False
        if self.dev.facts['master'] == 'RE0' and \
                    'backup' in self.dev.facts['RE1'].values():
            active_RE = 'RE0'
            backup_RE = 'RE1'
            RE1 = True
        elif self.dev.facts['master'] == 'RE1' and \
                    'backup' in self.dev.facts['RE0'].values():
            active_RE = 'RE1'
            backup_RE = 'RE0'
            RE0 = True
        else:
            logging.warn("Trouble finding the backup RE...")
            self.end_script()

        # Assign package path and name
        if self.arch == '32-bit':
            PACKAGE = R_PATH + PKG32
        else:
            PACKAGE = R_PATH + PKG64

        # Add package and reboot the backup RE
        # Had issues w/utils.sw install, so im using the rpc call instead
        startTime = datetime.now()
        logging.warn('Installing ' + PACKAGE + ' on ' + backup_RE + '...')
        # Change flags for JSU vs JINSTALL Package:
        if 'jselective' in PACKAGE:
            # JSU installs are failing with RPC call
            logging.warn(
                "Unable to instsall the JSU remotely, please do it manually..."
            )
            logging.warn("CMD: request routing-engine login backup")
            logging.warn(
                "CMD: request system software add {0}".format(PACKAGE))
            self.input_parse(
                "Once the JSU is installed, enter [Y] to continue...")
        else:
            rsp = self.dev.rpc.request_package_add(reboot=True,
                                                   no_validate=True,
                                                   package_name=PACKAGE,
                                                   re0=RE0,
                                                   re1=RE1,
                                                   force=self.force)
        # Check to see if the package add succeeded:
        logging.warn('-----------------START PKG ADD OUTPUT-----------------')
        ok = True
        for o in rsp.getparent().findall('output'):
            logging.warn(o.text)
        for result in rsp.getparent().findall('package-result'):
            if result.text != '0':
                logging.warn('Pkgadd result ' + result.text)
                ok = False
        logging.warn('------------------END PKG ADD OUTPUT------------------')
        if not ok:
            self.dev.timeout = 60
            logging.warn('Encountered issues with software add...  Exiting')
            if not self.yes_all:
                cont = self.input_parse(
                    'Rollback configuration changes? (y/n): ')
                if cont == 'y':
                    self.restore_traffic()
            else:
                self.restore_traffic()
            logging.warn(
                "Script complete, please check the package add errors manually"
            )
            self.end_script()

        logging.warn('Rebooting, please wait...')
        # Wait 2 minutes for package to install / reboot, then start checking every 30s
        time.sleep(120)
        re_state = 'Present'
        while re_state == 'Present':
            time.sleep(30)
            re_state = xmltodict.parse(etree.tostring(
                    self.dev.rpc.get_route_engine_information()))['route-engine-information']\
                    ['route-engine'][int(backup_RE[-1])]['mastership-state']

        # Give it 20 seconds, then check status again
        time.sleep(20)
        re_status = xmltodict.parse(etree.tostring(
                self.dev.rpc.get_route_engine_information()))['route-engine-information']\
                ['route-engine'][int(backup_RE[-1])]['status']
        if re_status != 'OK':
            logging.warn('Backup RE state  = ' + re_state)
            logging.warn('Backup RE status = ' + re_status)

        logging.warn(
            "Package " + PACKAGE +
            " took {0}".format(str(datetime.now() - startTime).split('.')[0]))

        # Grab core dump and SW version info
        self.dev.facts_refresh()
        core_dump = xmltodict.parse(
            etree.tostring(self.dev.rpc.get_system_core_dumps(re0=RE0,
                                                              re1=RE1)))
        sw_version = xmltodict.parse(
            etree.tostring(
                self.dev.rpc.get_software_information(re0=RE0, re1=RE1)))

        # Check for core dumps:
        logging.warn("Checking for core dumps...")
        if 'directory' in core_dump['multi-routing-engine-results'][
                'multi-routing-engine-item']['directory-list'].keys():
            logging.warn('Found Core Dumps!  Please investigate.')
            cont = self.input_parse("Continue with upgrade? (y/n): ")
            if cont == 'n':
                cont = self.input_parse("Revert config changes? (y/n): ")
                if cont == 'y':
                    self.restore_traffic()
                self.end_script()
        # Check SW Version:
        logging.warn(backup_RE + ' software version = ' + \
            sw_version['multi-routing-engine-results']['multi-routing-engine-item']['software-information']['junos-version'])

        # Copy the final image back to the RE if needed after installing
        if self.arch == '64-bit':
            final_image = self.config['CODE_DEST'] + self.config['CODE_IMAGE64']
        else:
            final_image = self.config['CODE_DEST'] + self.config['CODE_IMAGE32']

        img = xmltodict.parse(
            etree.tostring(
                self.dev.rpc.file_list(path=backup_RE.lower() + ':' +
                                       final_image)))
        img_output = json.dumps(img)
        if 'No such file' in img_output:
            self.copy_to_other_re(active_RE.lower() + ':' + final_image,
                                  backup_RE.lower() + ':' + final_image)
            img = xmltodict.parse(
                etree.tostring(
                    self.dev.rpc.file_list(path=backup_RE.lower() + ':' +
                                           final_image)))
            img_output = json.dumps(img)
            if 'No such file' in img_output:
                msg = 'file copy ' + active_RE.lower(
                ) + ':' + final_image + ' ' + backup_RE + ':' + final_image
                logging.warn('ERROR: Copy the image to the backup RE manually')
                logging.warn('CMD  : ' + msg)

    def upgrade_single_re(self):
        """ Cycle through installing packcages for single RE systems """
        logging.warn(
            "------------------------WARNING-----------------------------")
        logging.warn(
            "Ready to upgrade, THIS WILL BE SERVICE IMPACTING!!!        ")
        logging.warn(
            "-----------------------------------------------------------")
        if not self.yes_all:
            cont = self.input_parse(
                "Continue with software add / reboot? (y/n): ")
            if cont != 'y':
                self.restore_traffic()
                self.end_script()

        # First Stage Upgrade
        if self.two_stage:
            self.single_re_pkg_add(self.config['CODE_2STAGE32'],
                                   self.config['CODE_2STAGE64'],
                                   self.config['CODE_PRESERVE'])
        # Second Stage Upgrade
        self.single_re_pkg_add(self.config['CODE_IMAGE32'],
                               self.config['CODE_IMAGE64'],
                               self.config['CODE_DEST'])
        # JSU Upgrade
        if self.config['CODE_JSU32'] or self.config['CODE_JSU64']:
            if self.two_stage:
                self.single_re_pkg_add(self.config['CODE_JSU32'],
                                       self.config['CODE_JSU64'],
                                       self.config['CODE_PRESERVE'])
            else:
                self.single_re_pkg_add(self.config['CODE_JSU32'],
                                       self.config['CODE_JSU64'],
                                       self.config['CODE_DEST'])

    def single_re_pkg_add(self, PKG32, PKG64, R_PATH):
        """ Perform software add and reboot the RE / Device """
        self.dev.timeout = 3600
        if self.arch == '32-bit':
            PACKAGE = self.config['CODE_DEST'] + PKG32
        else:
            PACKAGE = self.config['CODE_DEST'] + PKG64
        # Had issues w/utils.sw install, so im using the rpc call instead
        startTime = datetime.now()
        logging.warn('Upgrading device... Please Wait...')
        # Change flags for JSU vs JINSTALL Package:
        if 'jselective' in PACKAGE:
            # JSU installs are failing with RPC call
            logging.warn(
                "Unable to instsall the JSU remotely, please do it manually..."
            )
            logging.warn(
                "CMD: request system software add {0}".format(PACKAGE))
            self.input_parse(
                "Once the JSU is installed, enter [Y] to continue...")
        else:
            rsp = self.dev.rpc.request_package_add(reboot=True,
                                                   no_validate=True,
                                                   package_name=PACKAGE,
                                                   force=self.force)

        # Check to see if the package add succeeded:
        logging.warn('-----------------START PKG ADD OUTPUT-----------------')
        ok = True
        got = rsp.getparent()
        for o in got.findall('output'):
            logging.warn(o.text)
        package_result = got.findall('package-result')
        for result in package_result:
            if result.text != '0':
                logging.warn('Pkgadd result ' + result.text)
                ok = False
        self.dev.timeout = 120
        logging.warn('------------------END PKG ADD OUTPUT------------------')
        if not ok:
            logging.warn('Encountered issues with software add...  Exiting')
            if not self.yes_all:
                cont = self.input_parse(
                    "Restore configuration before exiting? (y/n): ")
                if cont == 'y':
                    self.restore_traffic()
                self.end_script()
            else:
                logging.warn('Restoring configuration before exiting...')
                self.restore_traffic()
                self.end_script()

        logging.warn('Rebooting, please wait...')
        # Wait 2 minutes for package to install and reboot, then start checking every 30s
        time.sleep(120)
        while self.dev.probe() is False:
            time.sleep(30)
        logging.warn(
            "Package " + PACKAGE +
            " took {0}".format(str(datetime.now() - startTime).split('.')[0]))
        # Once dev is reachable, re-open connection (refresh facts first to kill conn)
        self.dev.facts_refresh()
        self.dev.open()
        self.dev.facts_refresh()

        # Check for core dumps:
        logging.warn("Checking for core dumps...")
        core_dump = xmltodict.parse(
            etree.tostring(self.dev.rpc.get_system_core_dumps()))
        for item in core_dump['multi-routing-engine-results'][
                'multi-routing-engine-item']['directory-list']['output']:
            if 'No such file' not in item:
                logging.warn('Found Core Dumps!  Please investigate.')
                logging.warn(item)
                if not self.yes_all:
                    cont = self.input_parse("Continue with upgrade? (y/n): ")
                    if cont.lower() != 'y':
                        self.end_script()
        # Check SW Version:
        logging.warn('SW Version: ' + self.dev.facts['version'] + '')

    def switchover_RE(self):
        """ Issue RE switchover """
        if self.dev.facts['2RE']:
            # Add a check for GRES / NSR
            x = self.dev.rpc.get_nonstop_routing_information()
            for item in x.getparent().iter():
                if item.findtext('nonstop-routing-enabled'):
                    nsr = item.findtext('nonstop-routing-enabled')
            if nsr != 'Enabled':
                logging.warn(
                    "----------------------WARNING----------------------------"
                )
                logging.warn(
                    'Nonstop-Routing is {0}, switchover will be impacting!'.
                    format(nsr))
                logging.warn(
                    "---------------------------------------------------------"
                )
            if not self.yes_all:
                cont = self.input_parse('Continue with switchover? (y/n): ')
                if cont != 'y':
                    self.end_script()
            # Using dev.cli because I couldn't find an RPC call for switchover
            self.dev.timeout = 20
            logging.warn("Performing routing-engine switchover...")
            try:
                r = self.dev.cli(
                    'request chassis routing-engine master switch no-confirm')
            except:
                time.sleep(10)

            if 'not ready' in str(r).lower():
                logging.warn(str(r))
                logging.warn("Waiting 2 minutes to stabilize...")
                time.sleep(120)
                try:
                    r = self.dev.cli(
                        'request chassis routing-engine master switch no-confirm'
                    )
                except:
                    time.sleep(5)
                if 'Not ready' in str(r):
                    logging.warn(str(r))
                    cont = self.input_parse(
                        'Please switchover manually and enter "y" to continue: '
                    )
                    if cont == 'n':
                        self.end_script
            try:
                self.dev.close()
            except:
                pass
            time.sleep(15)
            while self.dev.probe() is False:
                time.sleep(10)
            # Once dev is reachable, re-open connection (refresh facts first to kill conn)
            self.dev.open()

    def mx_network_services(self):
        """ Check if network-services mode enhanced-ip was requested, and set, reboot if not
            The reboot of both RE's was deemed nessicary by several issues where RE's were
            rebooted one at a time and did not sync network-services mode properly        """
        if self.dev.facts['model'][:2] == 'MX':
            if self.set_enhanced_ip:
                logging.warn("Setting chassis network-servies enhanced-ip...")
                try:
                    with Config(self.dev, mode='exclusive') as cu:
                        cu.load('set chassis network-services enhanced-ip',
                                merge=True,
                                ignore_warning=True)
                        cu.commit(sync=True, full=True)
                except Exception as e:
                    logging.warn(str(e))
                    logging.warn(
                        'Error commtitting "set chassis network-services enhanced-ip"'
                    )
                    logging.warn(
                        'Device will not be rebooted, please check error configuring enhanced-ip'
                    )

                logging.warn(
                    "-----------------------WARNING------------------------------"
                )
                logging.warn("SERVICE IMPACTING REBOOT WARNING")
                logging.warn(
                    "-----------------------------------------------------------"
                )

                cont = 'y'
                if not self.yes_all:
                    cont = self.input_parse(
                        'Reboot both REs now to set network-services mode enhanced-ip? (y/n): '
                    )
                if cont != 'y':
                    logging.warn(
                        "Skipping reboot of both RE's for network-services mode..."
                    )
                else:
                    logging.warn('Rebooting ' + self.host +
                                 '... Please wait...')
                    self.dev.timeout = 600
                    try:
                        self.dev.rpc.request_reboot(
                            routing_engine='both-routing-engines')
                        # Wait 2 minutes for reboot, then start checking every 30s
                        time.sleep(120)
                        while self.dev.probe() is False:
                            time.sleep(30)
                        self.dev.facts_refresh()
                        self.dev.open()
                        self.dev.facts_refresh()
                    except:
                        self.dev.open()

    def input_parse(self, msg):
        """ Prompt for input """
        q = ''
        while q.lower() != 'y' and q.lower() != 'n':
            q = input(msg)
        return q.lower()

    def restore_traffic(self):
        """ Verify version, restore config, and wait for replication on dualRE """
        # Check SW Version:
        self.dev.facts_refresh()
        if self.dev.facts['2RE']:
            if self.dev.facts['version_RE0'] == self.dev.facts['version_RE1']:
                logging.warn('Version matches on both routing engines.')
            else:
                logging.warn(
                    'ERROR: Versions do not match on both routing engines')
                logging.warn(
                    'Exiting script, please check device status manually.')
                self.end_script()

        logging.warn('Restoring configruation...')
        config_cmds = self.config['POST_UPGRADE_CMDS']

        # If pim nonstop-routing was deactivated, re-activate it
        if self.pim_nonstop:
            config_cmds.append('activate protocols pim nonstop-routing')

        if config_cmds:
            success = True
            with Config(self.dev, mode='exclusive') as cu:
                for cmd in config_cmds:
                    cu.load(cmd, merge=True, ignore_warning=True)
                logging.warn("Configuration Changes:")
                logging.warn('-' * 24)
                cu.pdiff()
                if cu.diff():
                    if not self.yes_all:
                        cont = self.input_parse('Commit Changes? (y/n): ')
                        if cont != 'y':
                            logging.warn('Rolling back changes...')
                            cu.rollback(rb_id=0)
                            success = False
                        else:
                            try:
                                if self.dev.facts['2RE']:
                                    cu.commit(sync=True, full=True)
                                else:
                                    cu.commit(full=True)
                            except Exception as e:
                                logging.warn("Error occurred during commit")
                                print(str(e))
                                success = False
                    else:
                        logging.warn('Committing Changes...')
                        try:
                            if self.dev.facts['2RE']:
                                cu.commit(sync=True, full=True)
                            else:
                                cu.commit(full=True)
                        except Exception as e:
                            logging.warn(str(e))
                            logging.warn("Error committing changes")
            if not success:
                self.end_script()
        else:
            logging.warn("No post-upgrade commands in CONFIG file")

    def switch_to_master(self):
        """ Switch back to the default master - RE0 """
        if self.dev.facts['2RE']:
            # Add a check for task replication
            logging.warn('Checking task replication...')
            task_sync = False
            waiting_on = ''
            while task_sync is False:
                rep = xmltodict.parse(
                    etree.tostring(
                        self.dev.rpc.get_routing_task_replication_state()))
                task_sync = True
                for i, item in enumerate(rep['task-replication-state']
                                         ['task-protocol-replication-state']):
                    if item != 'Complete':
                        task_sync = False
                        proto = rep['task-replication-state'][
                            'task-protocol-replication-name'][i]
                        if waiting_on != proto:
                            waiting_on = proto
                            logging.warn(proto + ': ' + item + '...')
                if task_sync is False:
                    time.sleep(60)
            # Check which RE is active and switchover if needed
            if self.dev.facts['RE0']['mastership_state'] != 'master':
                self.switchover_RE()

    def end_script(self):
        """ Close the connection to the device and exit the script """
        try:
            logging.warn("Disconnecting from {0}...".format(self.host))
            self.dev.close()
        except:
            logging.warn("Did not disconnect cleanly.")
        exit()
Ejemplo n.º 14
0
class TestDevice(unittest.TestCase):
    @patch('ncclient.manager.connect')
    def setUp(self, mock_connect):
        mock_connect.side_effect = self._mock_manager

        self.dev = Device(host='1.1.1.1',
                          user='******',
                          password='******',
                          gather_facts=False)
        self.dev.open()

    @patch('ncclient.operations.session.CloseSession.request')
    def tearDown(self, mock_session):
        self.dev.close()

    def test_new_console_return(self):
        dev = Device(host='1.1.1.1',
                     user='******',
                     password='******',
                     port=23,
                     gather_facts=False)
        self.assertTrue(isinstance(dev, Console))

    @patch('jnpr.junos.device.netconf_ssh')
    def test_device_ConnectAuthError(self, mock_manager):
        mock_manager.connect.side_effect = NcErrors.AuthenticationError
        self.assertRaises(EzErrors.ConnectAuthError, self.dev.open)

    @patch('jnpr.junos.device.netconf_ssh')
    def test_device_ConnectRefusedError(self, mock_manager):
        mock_manager.connect.side_effect = NcErrors.SSHError
        self.assertRaises(EzErrors.ConnectRefusedError, self.dev.open)

    @patch('jnpr.junos.device.netconf_ssh')
    @patch('jnpr.junos.device.datetime')
    def test_device_ConnectTimeoutError(self, mock_datetime, mock_manager):
        mock_manager.connect.side_effect = NcErrors.SSHError(
            "Could not open socket to 1.1.1.1:830")
        from datetime import timedelta, datetime
        currenttime = datetime.now()
        mock_datetime.datetime.now.side_effect = [
            currenttime, currenttime + timedelta(minutes=4)
        ]
        self.assertRaises(EzErrors.ConnectTimeoutError, self.dev.open)

    @patch('jnpr.junos.device.netconf_ssh')
    @patch('jnpr.junos.device.datetime')
    def test_device_diff_err_message(self, mock_datetime, mock_manager):
        NcErrors.SSHError.message = 'why are you trying :)'
        mock_manager.connect.side_effect = NcErrors.SSHError
        from datetime import timedelta, datetime
        currenttime = datetime.now()
        mock_datetime.datetime.now.side_effect = [
            currenttime, currenttime + timedelta(minutes=4)
        ]
        self.assertRaises(EzErrors.ConnectError, self.dev.open)

    @patch('jnpr.junos.device.netconf_ssh')
    def test_device_ConnectUnknownHostError(self, mock_manager):
        import socket
        mock_manager.connect.side_effect = socket.gaierror
        self.assertRaises(EzErrors.ConnectUnknownHostError, self.dev.open)

    @patch('jnpr.junos.device.netconf_ssh')
    def test_device_other_error(self, mock_manager):
        mock_manager.connect.side_effect = TypeError
        self.assertRaises(EzErrors.ConnectError, self.dev.open)

    def test_device_probe_error(self):
        mock_probe = MagicMock()
        mock_probe.return_value = None
        self.dev.probe = mock_probe

        def fn():
            self.dev.open(auto_probe=1)

        self.assertRaises(EzErrors.ProbeError, fn)

    def test_device_property_logfile_isinstance(self):
        mock = MagicMock()
        with patch(builtin_string + '.open', mock):
            if sys.version > '3':
                builtin_file = 'io.TextIOWrapper'
            else:
                builtin_file = builtin_string + '.file'
            with patch(builtin_file, MagicMock):
                handle = open('filename', 'r')
                self.dev.logfile = handle
                self.assertEqual(self.dev.logfile, handle)

    def test_device_host_mand_param(self):
        self.assertRaises(ValueError,
                          Device,
                          user='******',
                          password='******',
                          gather_facts=False)

    def test_device_property_logfile_close(self):
        self.dev._logfile = MagicMock()
        self.dev._logfile.close.return_value = 0
        self.dev.logfile = None
        self.assertFalse(self.dev._logfile)

    def test_device_property_logfile_exception(self):
        try:
            self.dev.logfile = True
        except Exception as ex:
            self.assertEqual(type(ex), ValueError)

    def test_device_repr(self):
        localdev = Device(host='1.1.1.1',
                          user='******',
                          password='******',
                          gather_facts=False)
        self.assertEqual(repr(localdev), 'Device(1.1.1.1)')

    def test_device_local(self):
        Device.ON_JUNOS = True
        localdev = Device()
        self.assertEqual(localdev._hostname, 'localhost')

    @patch('jnpr.junos.device.os')
    @patch(builtin_string + '.open')
    @patch('paramiko.config.SSHConfig.lookup')
    def test_device__sshconf_lkup(self, os_mock, open_mock, mock_paramiko):
        os_mock.path.exists.return_value = True
        self.dev._sshconf_lkup()
        mock_paramiko.assert_called_any()

    @patch('jnpr.junos.device.os')
    @patch(builtin_string + '.open')
    @patch('paramiko.config.SSHConfig.lookup')
    def test_device__sshconf_lkup_def(self, os_mock, open_mock, mock_paramiko):
        os_mock.path.exists.return_value = True
        self.dev._ssh_config = '/home/rsherman/.ssh/config'
        self.dev._sshconf_lkup()
        mock_paramiko.assert_called_any()

    @patch('os.getenv')
    def test_device__sshconf_lkup_path_not_exists(self, mock_env):
        mock_env.return_value = '/home/test'
        self.assertEqual(self.dev._sshconf_lkup(), None)

    @patch('os.getenv')
    def test_device__sshconf_lkup_home_not_defined(self, mock_env):
        mock_env.return_value = None
        self.assertEqual(self.dev._sshconf_lkup(), None)
        mock_env.assert_called_with('HOME')

    @patch('ncclient.manager.connect')
    @patch('jnpr.junos.Device.execute')
    def test_device_open(self, mock_connect, mock_execute):
        with patch('jnpr.junos.utils.fs.FS.cat') as mock_cat:
            mock_cat.return_value = """

    domain jls.net

            """
            mock_connect.side_effect = self._mock_manager
            mock_execute.side_effect = self._mock_manager
            self.dev2 = Device(host='2.2.2.2',
                               user='******',
                               password='******')
            self.dev2.open()
            self.assertEqual(self.dev2.connected, True)

    @patch('jnpr.junos.Device.execute')
    def test_device_facts(self, mock_execute):
        with patch('jnpr.junos.utils.fs.FS.cat') as mock_cat:
            mock_execute.side_effect = self._mock_manager
            mock_cat.return_value = """

    domain jls.net

            """
            self.dev.facts_refresh()
            assert self.dev.facts['version'] == facts['version']

    @patch('jnpr.junos.Device.execute')
    @patch('jnpr.junos.device.warnings')
    def test_device_facts_error(self, mock_warnings, mock_execute):
        with patch('jnpr.junos.utils.fs.FS.cat') as mock_cat:
            mock_execute.side_effect = self._mock_manager
            mock_cat.side_effect = IOError('File cant be handled')
            self.dev.facts_refresh()
            self.assertTrue(mock_warnings.warn.called)

    def test_device_hostname(self):
        self.assertEqual(self.dev.hostname, '1.1.1.1')

    def test_device_user(self):
        self.assertEqual(self.dev.user, 'test')

    def test_device_get_password(self):
        self.assertEqual(self.dev.password, None)

    def test_device_set_password(self):
        self.dev.password = '******'
        self.assertEqual(self.dev._auth_password, 'secret')

    def test_device_get_timeout(self):
        self.assertEqual(self.dev.timeout, 30)

    def test_device_set_timeout(self):
        self.dev.timeout = 10
        self.assertEqual(self.dev.timeout, 10)

    def test_device_manages(self):
        self.assertEqual(self.dev.manages, [],
                         'By default manages will be empty list')

    @patch('ncclient.manager.connect')
    @patch('jnpr.junos.Device.execute')
    def test_device_open_normalize(self, mock_connect, mock_execute):
        mock_connect.side_effect = self._mock_manager
        self.dev2 = Device(host='2.2.2.2', user='******', password='******')
        self.dev2.open(gather_facts=False, normalize=True)
        self.assertEqual(self.dev2.transform, self.dev2._norm_transform)

    def test_device_set_facts_exception(self):
        try:
            self.dev.facts = 'test'
        except RuntimeError as ex:
            self.assertEqual(RuntimeError, type(ex))

    @patch('jnpr.junos.Device.execute')
    def test_device_cli(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertEqual(
            self.dev.cli('show cli directory', warning=False).tag, 'cli')

    @patch('jnpr.junos.device.json.loads')
    def test_device_rpc_json_ex(self, mock_json_loads):
        self.dev._facts = facts
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        ex = ValueError('Extra data ')
        ex.message = 'Extra data '  # for py3 as we dont have message thr
        mock_json_loads.side_effect = [
            ex,
            self._mock_manager(
                etree.fromstring('<get-route-information format="json"/>'))
        ]
        self.dev.rpc.get_route_information({'format': 'json'})
        self.assertEqual(mock_json_loads.call_count, 2)

    @patch('jnpr.junos.Device.execute')
    def test_device_cli_format_json(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        data = self.dev.cli('show interface terse',
                            warning=False,
                            format='json')
        self.assertEqual(type(data), dict)
        self.assertEqual(
            data['interface-information'][0]['physical-interface'][0]
            ['oper-status'][0]['data'], 'up')

    @patch('jnpr.junos.Device.execute')
    def test_device_cli_conf_info(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertTrue(
            'ge-0/0/0' in self.dev.cli('show configuration', warning=False))

    @patch('jnpr.junos.Device.execute')
    def test_device_cli_output(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertTrue(
            'Alarm' in self.dev.cli('show system alarms', warning=False))

    def test_device_cli_blank_output(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertEqual(
            '', self.dev.cli('show configuration interfaces', warning=False))

    #@patch('jnpr.junos.Device.execute')
    def test_device_cli_rpc_reply_with_message(self):  # , mock_execute):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertEqual(
            '\nprotocol: operation-failed\nerror: device asdf not found\n',
            self.dev.cli('show interfaces terse asdf', warning=False))

    @patch('jnpr.junos.Device.execute')
    def test_device_cli_rpc(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertEqual(
            self.dev.cli('show system uptime | display xml rpc',
                         warning=False).tag, 'get-system-uptime-information')

    def test_device_cli_exception(self):
        self.dev.rpc.cli = MagicMock(side_effect=AttributeError)
        val = self.dev.cli('show version')
        self.assertEqual(val, 'invalid command: show version')

    @patch('jnpr.junos.Device.execute')
    def test_device_display_xml_rpc(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertEqual(
            self.dev.display_xml_rpc('show system uptime ').tag,
            'get-system-uptime-information')

    @patch('jnpr.junos.Device.execute')
    def test_device_display_xml_rpc_text(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertIn(
            '<get-system-uptime-information>',
            self.dev.display_xml_rpc('show system uptime ', format='text'))

    @patch('jnpr.junos.Device.execute')
    def test_device_display_xml_exception(self, mock_execute):
        mock_execute.side_effect = self._mock_manager
        self.assertEqual(self.dev.display_xml_rpc('show foo'),
                         'invalid command: show foo| display xml rpc')

    def test_device_execute(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertEqual(
            self.dev.execute('<get-system-core-dumps/>').tag, 'directory-list')

    def test_device_execute_topy(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertEqual(
            self.dev.execute('<get-system-core-dumps/>',
                             to_py=self._do_nothing), 'Nothing')

# This test is for the commented out rpc-error code
#     def test_device_execute_exception(self):
#         self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
#         self.assertRaises(RpcError, self.dev.execute,
#                           '<load-configuration-error/>')

    def test_device_execute_unknown_exception(self):
        class MyException(Exception):
            pass

        self.dev._conn.rpc = MagicMock(side_effect=MyException)
        self.assertRaises(MyException, self.dev.execute,
                          '<get-software-information/>')

    def test_device_execute_rpc_error(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertRaises(RpcError, self.dev.rpc.get_rpc_error)

    def test_device_execute_permission_error(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertRaises(EzErrors.PermissionError,
                          self.dev.rpc.get_permission_denied)

    def test_device_execute_index_error(self):
        self.dev._conn.rpc = MagicMock(side_effect=self._mock_manager)
        self.assertTrue(self.dev.rpc.get_index_error())

    def test_device_execute_ValueError(self):
        self.assertRaises(ValueError, self.dev.execute, None)

    def test_device_execute_unopened(self):
        self.dev.connected = False
        self.assertRaises(EzErrors.ConnectClosedError, self.dev.execute, None)

    def test_device_execute_timeout(self):
        self.dev._conn.rpc = MagicMock(side_effect=TimeoutExpiredError)
        self.assertRaises(EzErrors.RpcTimeoutError,
                          self.dev.rpc.get_rpc_timeout)

    def test_device_execute_closed(self):
        self.dev._conn.rpc = MagicMock(side_effect=NcErrors.TransportError)
        self.assertRaises(EzErrors.ConnectClosedError,
                          self.dev.rpc.get_rpc_close)
        self.assertFalse(self.dev.connected)

    def test_device_rpcmeta(self):
        self.assertEqual(self.dev.rpc.get_software_information.__doc__,
                         'get-software-information')

    def test_device_probe_timeout_zero(self):
        with patch('jnpr.junos.device.socket'):
            self.assertFalse(self.dev.probe(0))

    def test_device_probe_timeout_gt_zero(self):
        with patch('jnpr.junos.device.socket'):
            self.assertTrue(
                self.dev.probe(1), 'probe fn is not working for'
                ' timeout greater than zero')

    def test_device_probe_timeout_exception(self):
        with patch('jnpr.junos.device.socket') as mock_socket:
            with patch('jnpr.junos.device.time.sleep') as mock_time:
                mock_socket.socket.return_value.close.side_effect \
                    = RuntimeError
                mock_time.return_value = None
                self.assertFalse(self.dev.probe(.01))

    def test_device_bind_varg(self):
        self.dev.bind()
        mock = MagicMock()
        mock.__name__ = 'magic_mock'
        self.dev.bind(mock)
        self.assertEqual(self.dev.magic_mock.__name__, 'magic_mock')

    def test_device_bind_kvarg(self):
        self.dev.bind()
        mock = MagicMock()
        mock.return_value = 'Test'
        self.dev.bind(kw=mock)
        self.assertEqual(self.dev.kw, 'Test')

    def test_device_bind_varg_exception(self):
        def varg():
            self.dev.bind()
            mock = MagicMock()
            mock.__name__ = 'magic mock'
            # for *args
            self.dev.bind(mock)
            self.dev.bind(mock)

        self.assertRaises(ValueError, varg)

    def test_device_bind_kvarg_exception(self):
        def kve():
            self.dev.bind()
            mock = MagicMock()
            mock.__name__ = 'magic mock'
            # for **kwargs
            self.dev.bind(kw=mock)
            self.dev.bind(kw=mock)

        self.assertRaises(ValueError, kve)

    def test_device_template(self):
        # Try to load the template relative to module base
        try:
            template = self.dev.Template(
                'tests/unit/templates/config-example.xml')
        except:
            # Try to load the template relative to test base
            try:
                template = self.dev.Template('templates/config-example.xml')
            except:
                raise
        self.assertEqual(
            template.render({
                'host_name': '1',
                'domain_name': '2'
            }), 'system {\n  host-name 1;\n  domain-name 2;\n}')

    def test_device_close(self):
        def close_conn():
            self.dev.connected = False

        self.dev.close = MagicMock(name='close')
        self.dev.close.side_effect = close_conn
        self.dev.close()
        self.assertEqual(self.dev.connected, False)

    @patch('ncclient.manager.connect')
    def test_device_context_manager(self, mock_connect):
        mock_connect.side_effect = self._mock_manager
        try:
            with Device(host='3.3.3.3',
                        user='******',
                        password='******',
                        gather_facts=False) as dev:
                self.assertTrue(dev.connected)
                dev._conn = MagicMock(name='_conn')
                dev._conn.connected = True

                def close_conn():
                    dev.connected = False

                dev.close = MagicMock(name='close')
                dev.close.side_effect = close_conn
                raise RpcError
        except Exception as e:
            self.assertIsInstance(e, RpcError)
        self.assertFalse(dev.connected)

    def _read_file(self, fname):
        from ncclient.xml_ import NCElement

        fpath = os.path.join(os.path.dirname(__file__), 'rpc-reply', fname)
        with open(fpath) as fp:
            foo = fp.read()

            if fname == 'get-rpc-error.xml':
                # Raise ncclient exception for error
                raise RPCError(etree.XML(foo))
            elif fname == 'get-permission-denied.xml':
                # Raise ncclient exception for error
                raise RPCError(etree.XML(foo))
            elif (fname == 'get-index-error.xml'
                  or fname == 'get-system-core-dumps.xml'
                  or fname == 'load-configuration-error.xml'
                  or fname == 'show-configuration-interfaces.xml'
                  or fname == 'show-interfaces-terse-asdf.xml'):
                rpc_reply = NCElement(
                    foo, self.dev._conn._device_handler.transform_reply())
            elif (fname == 'show-configuration.xml'
                  or fname == 'show-system-alarms.xml'):
                rpc_reply = NCElement(
                    foo, self.dev._conn._device_handler.transform_reply()
                )._NCElement__doc
            elif fname == 'show-interface-terse.json':
                rpc_reply = json.loads(foo)
            elif fname == 'get-route-information.json':
                rpc_reply = NCElement(
                    foo, self.dev._conn._device_handler.transform_reply())
            else:
                rpc_reply = NCElement(
                    foo, self.dev._conn._device_handler.transform_reply()
                )._NCElement__doc[0]
        return rpc_reply

    def _mock_manager(self, *args, **kwargs):
        if kwargs:
            device_params = kwargs['device_params']
            device_handler = make_device_handler(device_params)
            session = SSHSession(device_handler)
            return Manager(session, device_handler)

        elif args:
            if args[0].tag == 'command':
                if args[0].text == 'show cli directory':
                    return self._read_file('show-cli-directory.xml')
                if args[0].text == 'show interface terse':
                    return self._read_file('show-interface-terse.json')
                elif args[0].text == 'show configuration':
                    return self._read_file('show-configuration.xml')
                elif args[0].text == 'show system alarms':
                    return self._read_file('show-system-alarms.xml')
                elif args[0].text == 'show system uptime | display xml rpc':
                    return self._read_file('show-system-uptime-rpc.xml')
                elif args[0].text == 'show configuration interfaces':
                    return self._read_file('show-configuration-interfaces.xml')
                elif args[0].text == 'show interfaces terse asdf':
                    return self._read_file('show-interfaces-terse-asdf.xml')
                else:
                    raise RpcError

            else:
                if args[0].attrib.get('format') == 'json':
                    return self._read_file(args[0].tag + '.json')
                return self._read_file(args[0].tag + '.xml')

    def _do_nothing(self, *args, **kwargs):
        return 'Nothing'
Ejemplo n.º 15
0
class Netconf(object):

    def __init__(self):
        self.device = None
        self.config = None
        self._locked = False
        self._connected = False
        self.default_output = 'xml'

    def raise_exc(self, msg):
        if self.device:
            if self._locked:
                self.config.unlock()
            self.disconnect()
        raise NetworkError(msg)

    def connect(self, params, **kwargs):
        host = params['host']
        port = params.get('port') or 830

        user = params['username']
        passwd = params['password']

        try:
            self.device = Device(host, user=user, passwd=passwd, port=port,
                                 gather_facts=False)
            self.device.open()
        except ConnectError:
            exc = get_exception()
            self.raise_exc('unable to connect to %s: %s' % (host, str(exc)))

        self.config = Config(self.device)
        self._connected = True

    def disconnect(self):
        if self.device:
            self.device.close()
        self._connected = False

    ### Command methods ###

    def run_commands(self, commands):
        responses = list()

        for cmd in commands:
            meth = getattr(self, cmd.args.get('command_type'))
            responses.append(meth(str(cmd), output=cmd.output))

        for index, cmd in enumerate(commands):
            if cmd.output == 'xml':
                responses[index] = etree.tostring(responses[index])
            elif cmd.args.get('command_type') == 'rpc':
                responses[index] = str(responses[index].text).strip()

        return responses

    def cli(self, commands, output='xml'):
        '''Send commands to the device.'''
        try:
            return self.device.cli(commands, format=output, warning=False)
        except (ValueError, RpcError):
            exc = get_exception()
            self.raise_exc('Unable to get cli output: %s' % str(exc))

    def rpc(self, command, output='xml'):
        name, kwargs = rpc_args(command)
        meth = getattr(self.device.rpc, name)
        reply = meth({'format': output}, **kwargs)
        return reply

    ### Config methods ###

    def get_config(self, config_format="text"):
        if config_format not in SUPPORTED_CONFIG_FORMATS:
            self.raise_exc(msg='invalid config format.  Valid options are '
                               '%s' % ', '.join(SUPPORTED_CONFIG_FORMATS))

        ele = self.rpc('get_configuration', output=config_format)

        if config_format in ['text', 'set']:
            return str(ele.text).strip()
        else:
            return ele

    def load_config(self, candidate, update='merge', comment=None,
                    confirm=None, format='text', commit=True):

        merge = update == 'merge'
        overwrite = update == 'overwrite'

        self.lock_config()

        try:
            candidate = '\n'.join(candidate)
            self.config.load(candidate, format=format, merge=merge,
                             overwrite=overwrite)
        except ConfigLoadError:
            exc = get_exception()
            self.raise_exc('Unable to load config: %s' % str(exc))

        diff = self.config.diff()

        self.check_config()

        if all((commit, diff)):
            self.commit_config(comment=comment, confirm=confirm)

        self.unlock_config()

        return diff

    def save_config(self):
        raise NotImplementedError

    ### end of Config ###

    def get_facts(self, refresh=True):
        if refresh:
            self.device.facts_refresh()
        return self.device.facts

    def unlock_config(self):
        try:
            self.config.unlock()
            self._locked = False
        except UnlockError:
            exc = get_exception()
            raise NetworkError('unable to unlock config: %s' % str(exc))

    def lock_config(self):
        try:
            self.config.lock()
            self._locked = True
        except LockError:
            exc = get_exception()
            raise NetworkError('unable to lock config: %s' % str(exc))

    def check_config(self):
        if not self.config.commit_check():
            self.raise_exc(msg='Commit check failed')

    def commit_config(self, comment=None, confirm=None):
        try:
            kwargs = dict(comment=comment)
            if confirm and confirm > 0:
                kwargs['confirm'] = confirm
            return self.config.commit(**kwargs)
        except CommitError:
            exc = get_exception()
            raise NetworkError('unable to commit config: %s' % str(exc))

    def rollback_config(self, identifier, commit=True, comment=None):

        self.lock_config()

        try:
            self.config.rollback(identifier)
        except ValueError:
            exc = get_exception()
            self._error('Unable to rollback config: $s' % str(exc))

        diff = self.config.diff()
        if commit:
            self.commit_config(comment=comment)

        self.unlock_config()
        return diff