Example #1
0
    def commit(self, **kvargs):
        """
        Commit a configuration.

        :param str comment: If provide logs this comment with the commit.
        :param int confirm: If provided activates confirm safeguard with
                            provided value as timeout (minutes).

        :returns:
            * ``True`` when successful

        :raises CommitError: When errors detected in candidate configuration.
                             You can use the Exception variable (XML)
                             to identify the specific problems
        """
        rpc_args = {}

        # if a comment is provided, then include that in the RPC

        comment = kvargs.get('comment')
        if comment:
            rpc_args['log'] = comment

        # if confirm is provided, then setup the RPC args
        # so that Junos will either use the default confirm
        # timeout (confirm=True) or a specific timeout
        # (confirm=<minutes>)

        confirm = kvargs.get('confirm')
        if confirm:
            rpc_args['confirmed'] = True
            confirm_val = str(confirm)
            if 'True' != confirm_val:
                rpc_args['confirm-timeout'] = confirm_val

        # dbl-splat the rpc_args since we want to pass key/value to metaexec
        # if there is a commit/check error, this will raise an execption

        try:
            self.rpc.commit_configuration(**rpc_args)
        except RpcError as err:        # jnpr.junos exception
            if err.rsp.find('ok') is not None:
                # this means there are warnings, but no errors
                return True
            else:
                raise CommitError(cmd=err.cmd, rsp=err.rsp)
        except ConnectTimeoutError as err:
           # err is a TimeoutExpiredError from ncclient,
           # which has no such attribute as xml.
           raise
        except Exception as err:
            # so the ncclient gives us something I don't want.  I'm going to
            # convert it and re-raise the commit error
            JXML.remove_namespaces(err.xml)
            raise CommitError(rsp=err.xml)

        return True
Example #2
0
    def commit(self, **kvargs):
        """
        Commit a configuration.

        :param str comment: If provide logs this comment with the commit.
        :param int confirm: If provided activates confirm safeguard with
                            provided value as timeout (minutes).

        :returns:
            * ``True`` when successful

        :raises CommitError: When errors detected in candidate configuraiton.
                             You can use the Exception variable (XML)
                             to identify the specific problems
        """
        rpc_args = {}

        # if a comment is provided, then include that in the RPC

        comment = kvargs.get('comment')
        if comment:
            rpc_args['log'] = comment

        # if confirm is provided, then setup the RPC args
        # so that Junos will either use the default confirm
        # timeout (confirm=True) or a specific timeout
        # (confirm=<minutes>)

        confirm = kvargs.get('confirm')
        if confirm:
            rpc_args['confirmed'] = True
            confirm_val = str(confirm)
            if 'True' != confirm_val:
                rpc_args['confirm-timeout'] = confirm_val

        # dbl-splat the rpc_args since we want to pass key/value to metaexec
        # if there is a commit/check error, this will raise an execption

        try:
            self.rpc.commit_configuration(**rpc_args)
        except RpcError as err:  # jnpr.junos exception
            if err.rsp.find('ok') is not None:
                # this means there are warnings, but no errors
                return True
            else:
                raise CommitError(cmd=err.cmd, rsp=err.rsp)
        except Exception as err:
            # so the ncclient gives us something I don't want.  I'm going to
            # convert it and re-raise the commit error
            JXML.remove_namespaces(err.xml)
            raise CommitError(rsp=err.xml)

        return True
Example #3
0
    def __init__(self,
                 cmd=None,
                 rsp=None,
                 errs=None,
                 dev=None,
                 timeout=None,
                 re=None):
        """
          :cmd: is the rpc command
          :rsp: is the rpc response (after <rpc-reply>)
          :errs: is a list of dictionaries of extracted <rpc-error> elements.
          :dev: is the device rpc was executed on
          :timeout: is the timeout value of the device
          :re: is the RE or member exception occured on
        """
        self.cmd = cmd
        self.rsp = rsp
        self.dev = dev
        self.timeout = timeout
        self.re = re
        self.rpc_error = None
        self.xml = rsp
        # To handle errors coming from ncclient, Here errs is list of RPCError
        if isinstance(errs, RPCError) and hasattr(errs, 'errors'):
            self.errs = [JXML.rpc_error(error.xml) for error in errs.errors]
            for error in errs.errors:
                if error.severity == 'error':
                    self.rsp = JXML.remove_namespaces(error.xml)
                    break
            else:
                if errs.severity == 'warning':
                    for error in errs.errors:
                        if error.severity == 'warning':
                            self.rsp = JXML.remove_namespaces(error.xml)
                            break
            self.message = errs.message
        else:
            self.errs = errs
            self.message = "\n".join(["%s: %s" % (err['severity'].strip(),
                                                  err['message'].strip())
                                      for err in errs
                                      if err['message'] is not None and
                                      err['severity'] is not None]) \
                if isinstance(errs, list) else ''

        if isinstance(self.rsp, _Element):
            self.rpc_error = jxml.rpc_error(self.rsp)
            self.message = self.message or self.rpc_error['message']
            if self.errs is None or not isinstance(self.errs, list):
                self.errs = [self.rpc_error]
Example #4
0
    def commit(self, **kvargs):
        """
        commit a configuration.  returns either :True: or
        raises an RPCError exception

        kvargs
          confirm = [True | <timeout-minutes>]
          comment = <comment log string>
        """
        rpc_args = {}

        # if a comment is provided, then include that in the RPC

        comment = kvargs.get('comment')
        if comment:
            rpc_args['log'] = comment

        # if confirm is provided, then setup the RPC args
        # so that Junos will either use the default confirm
        # timeout (confirm=True) or a specific timeout
        # (confirm=<minutes>)

        confirm = kvargs.get('confirm')
        if confirm:
            rpc_args['confirmed'] = True
            confirm_val = str(confirm)
            if 'True' != confirm_val:
                rpc_args['confirm-timeout'] = confirm_val

        # dbl-splat the rpc_args since we want to pass key/value to metaexec
        # if there is a commit/check error, this will raise an execption

        try:
            self.rpc.commit_configuration(**rpc_args)
        except RpcError as err:        # jnpr.junos exception
            if err.rsp.find('ok') is not None:
                # this means there are warnings, but no errors
                return True
            else:
                raise CommitError(cmd=err.cmd, rsp=err.rsp)
        except Exception as err:
            # so the ncclient gives us something I don't want.  I'm going to
            # convert it and re-raise the commit error
            JXML.remove_namespaces(err.xml)
            raise CommitError(rsp=err.xml)

        return True
Example #5
0
    def commit(self, **kvargs):
        """
        commit a configuration.  returns either :True: or
        raises an RPCError exception

        kvargs
          confirm = [True | <timeout-minutes>]
          comment = <comment log string>
        """
        rpc_args = {}

        # if a comment is provided, then include that in the RPC

        comment = kvargs.get('comment')
        if comment:
            rpc_args['log'] = comment

        # if confirm is provided, then setup the RPC args
        # so that Junos will either use the default confirm
        # timeout (confirm=True) or a specific timeout
        # (confirm=<minutes>)

        confirm = kvargs.get('confirm')
        if confirm:
            rpc_args['confirmed'] = True
            confirm_val = str(confirm)
            if 'True' != confirm_val:
                rpc_args['confirm-timeout'] = confirm_val

        # dbl-splat the rpc_args since we want to pass key/value to metaexec
        # if there is a commit/check error, this will raise an execption

        try:
            self.rpc.commit_configuration(**rpc_args)
        except RpcError as err:  # jnpr.junos exception
            if err.rsp.find('ok') is not None:
                # this means there are warnings, but no errors
                return True
            else:
                raise CommitError(cmd=err.cmd, rsp=err.rsp)
        except Exception as err:
            # so the ncclient gives us something I don't want.  I'm going to
            # convert it and re-raise the commit error
            JXML.remove_namespaces(err.xml)
            raise CommitError(rsp=err.xml)

        return True
Example #6
0
    def __init__(self, cmd=None, rsp=None, errs=None, dev=None,
                 timeout=None, re=None):
        """
          :cmd: is the rpc command
          :rsp: is the rpc response (after <rpc-reply>)
          :errs: is a list of dictionaries of extracted <rpc-error> elements.
          :dev: is the device rpc was executed on
          :timeout: is the timeout value of the device
          :re: is the RE or member exception occured on
        """
        self.cmd = cmd
        self.rsp = rsp
        self.dev = dev
        self.timeout = timeout
        self.re = re
        self.rpc_error = None
        self.xml = rsp
        # To handle errors coming from ncclient, Here errs is list of RPCError
        if isinstance(errs, RPCError) and hasattr(errs, 'errors'):
            self.errs = [JXML.rpc_error(error.xml) for error in errs.errors]
            for error in errs.errors:
                if error.severity == 'error':
                    self.rsp = JXML.remove_namespaces(error.xml)
                    break
            else:
                if errs.severity == 'warning':
                    for error in errs.errors:
                        if error.severity == 'warning':
                            self.rsp = JXML.remove_namespaces(error.xml)
                            break
            self.message = errs.message
        else:
            self.errs = errs
            self.message = "\n".join(["%s: %s" % (err['severity'].strip(),
                                                  err['message'].strip())
                                      for err in errs
                                      if err['message'] is not None and
                                      err['severity'] is not None]) \
                if isinstance(errs, list) else ''

        if isinstance(self.rsp, _Element):
            self.rpc_error = jxml.rpc_error(self.rsp)
            self.message = self.message or self.rpc_error['message']
            if self.errs is None or not isinstance(self.errs, list):
                self.errs = [self.rpc_error]
Example #7
0
    def get(self, *vargs, **kvargs):
        """
        Retrieve the XML table data from the Device instance and
        returns back the Table instance - for call-chaining purposes.

        If the Table was created with a :path: rather than a Device,
        then this method will load the XML from that file.  In this
        case, the \*vargs, and \**kvargs are not used.

        ALIAS: __call__

        :vargs:
          [0] is the table :arg_key: value.  This is used so that
          the caller can retrieve just one item from the table without
          having to know the Junos RPC argument.

        :kvargs:
          these are the name/value pairs relating to the specific Junos
          XML command attached to the table.  For example, if the RPC
          is 'get-route-information', there are parameters such as
          'table' and 'destination'.  Any valid RPC argument can be
          passed to :kvargs: to further filter the results of the :get():
          operation.  neato!

        NOTES:
          If you need to create a 'stub' for unit-testing
          purposes, you want to create a subclass of your table and
          overload this methods.
        """
        self._clearkeys()

        if self._path is not None:
            # for loading from local file-path
            self.xml = remove_namespaces(etree.parse(self._path).getroot())
            return self

        if self._lxml is not None:
            return self

        argkey = vargs[0] if len(vargs) else None

        rpc_args = {'normalize': True}    # create default <dict>
        rpc_args.update(self.GET_ARGS)    # copy default args
        rpc_args.update(kvargs)           # copy caller provided args

        if hasattr(self, 'GET_KEY') and argkey is not None:
            rpc_args.update({self.GET_KEY: argkey})

        # execute the Junos RPC to retrieve the table
        self.xml = getattr(self.RPC, self.GET_RPC)(**rpc_args)

        # returning self for call-chaining purposes, yo!
        return self
Example #8
0
    def get(self, *vargs, **kvargs):
        """
        Retrieve the XML table data from the Device instance and
        returns back the Table instance - for call-chaining purposes.

        If the Table was created with a :path: rather than a Device,
        then this method will load the XML from that file.  In this
        case, the \*vargs, and \**kvargs are not used.

        ALIAS: __call__

        :vargs:
          [0] is the table :arg_key: value.  This is used so that
          the caller can retrieve just one item from the table without
          having to know the Junos RPC argument.

        :kvargs:
          these are the name/value pairs relating to the specific Junos
          XML command attached to the table.  For example, if the RPC
          is 'get-route-information', there are parameters such as
          'table' and 'destination'.  Any valid RPC argument can be
          passed to :kvargs: to further filter the results of the :get():
          operation.  neato!

        NOTES:
          If you need to create a 'stub' for unit-testing
          purposes, you want to create a subclass of your table and
          overload this methods.
        """
        self._clearkeys()

        if self._path is not None:
            # for loading from local file-path
            self.xml = remove_namespaces(etree.parse(self._path).getroot())
            return self

        if self._lxml is not None:
            return self

        argkey = vargs[0] if len(vargs) else None

        rpc_args = {'normalize': True}  # create default <dict>
        rpc_args.update(self.GET_ARGS)  # copy default args
        rpc_args.update(kvargs)  # copy caller provided args

        if hasattr(self, 'GET_KEY') and argkey is not None:
            rpc_args.update({self.GET_KEY: argkey})

        # execute the Junos RPC to retrieve the table
        self.xml = getattr(self.RPC, self.GET_RPC)(**rpc_args)

        # returning self for call-chaining purposes, yo!
        return self
Example #9
0
    def unlock(self):
        """
        unlocks the candidate configuration
        """
        try:
            self.rpc.unlock_configuration()
        except Exception as err:
            if isinstance(err, RpcError):
                raise LockError(rsp=err.rsp)
            else:
                # :err: is from ncclient
                raise UnlockError(rsp=JXML.remove_namespaces(err.xml))

        return True
Example #10
0
    def unlock(self):
        """
        unlocks the candidate configuration
        """
        try:
            self.rpc.unlock_configuration()
        except Exception as err:
            if isinstance(err, RpcError):
                raise LockError(rsp=err.rsp)
            else:
            # :err: is from ncclient
                raise UnlockError(rsp=JXML.remove_namespaces(err.xml))

        return True
def test_isis_dynamic(device):
    """isis with dynamic reply"""
    # read rpc-reply from file
    rpc_request = 'get-isis-adjacency-information'
    fname = os.path.join(os.path.dirname(__file__), 'rpc-reply', rpc_request + '.xml')
    with open(fname, 'r') as f:
        xml = etree.fromstring(f.read())
        xml = JXML.remove_namespaces(xml)
    # updated rpc-reply (delete first adjacency)
    xml.find('.//isis-adjacency-information').remove(xml.find('.//isis-adjacency'))
    # store in rpc_reply_dict dict (fixture)
    rpc_reply_dict[rpc_request] = etree.tostring(xml)
    # get isis adjacencys and check if number has decreased from 3 to 2
    isis = device.neighbors.isis
    assert len(isis) == 2
Example #12
0
 def test_remove_namespaces(self):
     xmldata = \
         """<xsl:stylesheet xmlns:xsl="http://xml.juniper.net/junos">
                 <xsl:template>
                     <xsl:attribute name="{myname}">
                     </xsl:attribute>
                 </xsl:template>
             </xsl:stylesheet>"""
     import xml.etree.ElementTree as ET
     root = ET.fromstring(xmldata)
     test = remove_namespaces(root)
     for elem in test.getiterator():
         i = elem.tag.find('}')
         if i > 0:
             i = i + 1
     self.assertTrue(i <= 0)
Example #13
0
 def test_remove_namespaces(self):
     xmldata = \
         """<xsl:stylesheet xmlns:xsl="http://xml.juniper.net/junos">
                 <xsl:template>
                     <xsl:attribute name="{myname}">
                     </xsl:attribute>
                 </xsl:template>
             </xsl:stylesheet>"""
     import xml.etree.ElementTree as ET
     root = ET.fromstring(xmldata)
     test = remove_namespaces(root)
     for elem in test.getiterator():
         i = elem.tag.find('}')
         if i > 0:
             i = i + 1
     self.assertLessEqual(i, 0)
def _get_software_information(device):
    # See if device understands "invoke-on all-routing-engines"
    try:
        return device.rpc.cli("show version invoke-on all-routing-engines",
                              format='xml',
                              normalize=True)
    except RpcError as err:
        # See if device is VC Capable
        if device.facts['vc_capable'] is True:
            try:
                return device.rpc.cli("show version all-members",
                                      format='xml',
                                      normalize=True)
            except Exception:
                pass
        # check if rpc-reply got 2 child element, one rpc-error and another
        # software information
        elif hasattr(err, 'rpc_error') and err.rpc_error is not None and \
                        'Could not connect to ' in err.rpc_error.get('message'):
            logger.debug(err.rpc_error.get('message'))
            # getparent as rpc-reply got software-information in 2nd element
            # and dev.cli return just 1st element.
            rsp = err.xml.getparent()
            rsp = JXML.remove_namespaces(rsp)
            if rsp.xpath(".//software-information"):
                return rsp
        try:
            # JDM for Junos Node Slicing
            return device.rpc.get_software_information(all_servers=True,
                                                       format='xml',
                                                       normalize=True)
        except Exception:
            pass
        try:
            sw_info = device.rpc.get_software_information(normalize=True)
        except Exception:
            sw_info = True
        try:
            if sw_info is True:
                # Possibly an NFX which requires 'local' and 'detail' args.
                sw_info = device.rpc.get_software_information(local=True,
                                                              detail=True,
                                                              normalize=True)
            return sw_info
        except Exception:
            pass
Example #15
0
 def test_remove_namespaces(self):
     xmldata = \
         u"""<xsl:stylesheet xmlns:xsl="http://xml.juniper.net/junos">
                 <xsl:template>
                     <!-- Handle comments properly -->
                     <xsl:attribute name="{myname}">
                     </xsl:attribute>
                 </xsl:template>
             </xsl:stylesheet>"""
     import xml.etree.ElementTree as ET
     parser = ET.XMLParser()
     root = ET.parse(StringIO(xmldata), parser)
     test = remove_namespaces(root)
     for elem in test.getiterator():
         i = elem.tag.find('}')
         if i > 0:
             i = i + 1
     self.assertTrue(i <= 0)
Example #16
0
 def test_remove_namespaces(self):
     xmldata = \
         u"""<xsl:stylesheet xmlns:xsl="http://xml.juniper.net/junos">
                 <xsl:template>
                     <!-- Handle comments properly -->
                     <xsl:attribute name="{myname}">
                     </xsl:attribute>
                 </xsl:template>
             </xsl:stylesheet>"""
     import xml.etree.ElementTree as ET
     parser = ET.XMLParser()
     root   = ET.parse(StringIO(xmldata), parser)
     test = remove_namespaces(root)
     for elem in test.getiterator():
         i = elem.tag.find('}')
         if i > 0:
             i = i + 1
     self.assertTrue(i <= 0)
Example #17
0
    def lock(self):
        """
        Attempts an exclusive lock on the candidate configuration.  This
        is a non-blocking call.

        :returns:
            ``True`` always when successful

        :raises LockError: When the lock cannot be obtained
        """
        try:
            self.rpc.lock_configuration()
        except Exception as err:
            if isinstance(err, RpcError):
                raise LockError(rsp=err.rsp)
            else:
                # :err: is from ncclient
                raise LockError(rsp=JXML.remove_namespaces(err.xml))

        return True
Example #18
0
    def unlock(self):
        """
        Unlocks the candidate configuration.

        :returns:
            ``True`` always when successful

        :raises UnlockError: If you attempt to unlock a configuration
                             when you do not own the lock
        """
        try:
            self.rpc.unlock_configuration()
        except Exception as err:
            if isinstance(err, RpcError):
                raise UnlockError(rsp=err.rsp)
            else:
                # :err: is from ncclient
                raise UnlockError(rsp=JXML.remove_namespaces(err.xml))

        return True
Example #19
0
    def lock(self):
        """
        Attempts an exclusive lock on the candidate configuration.  This
        is a non-blocking call.

        :returns:
            ``True`` always when successful

        :raises LockError: When the lock cannot be obtained
        """
        try:
            self.rpc.lock_configuration()
        except Exception as err:
            if isinstance(err, RpcError):
                raise LockError(rsp=err.rsp)
            else:
                # :err: is from ncclient
                raise LockError(rsp=JXML.remove_namespaces(err.xml))

        return True
Example #20
0
    def unlock(self):
        """
        Unlocks the candidate configuration.

        :returns:
            ``True`` always when successful

        :raises UnlockError: If you attempt to unlock a configuration
                             when you do not own the lock
        """
        try:
            self.rpc.unlock_configuration()
        except Exception as err:
            if isinstance(err, RpcError):
                raise UnlockError(rsp=err.rsp)
            else:
                # :err: is from ncclient
                raise UnlockError(rsp=JXML.remove_namespaces(err.xml))

        return True
Example #21
0
    def rpc(self, cmd):
        """
        Write the XML cmd and return the response as XML object.

        :cmd:
          <str> of the XML command.  if the :cmd: is not XML, then
          this routine will perform the brackets; i.e. if given
          'get-software-information', this routine will turn
          it into '<get-software-information/>'

        NOTES:
          The return XML object is the first child element after
          the <rpc-reply>.  There is also no error-checking
          performing by this routine.
        """
        if not cmd.startswith('<'):
            cmd = '<{0}/>'.format(cmd)
        rpc = six.b('<rpc>{0}</rpc>'.format(cmd))
        logger.info('Calling rpc: %s' % rpc)
        self._tty.rawwrite(rpc)

        rsp = self._receive()
        try:
            rsp = remove_namespaces(
                rsp[0])  # return first child after the <rpc-reply>
        except IndexError:
            if rsp.text.strip() is not '':
                return rsp
            # no children, so assume it means we are OK
            return True
        except:
            return etree.XML('<error-in-receive/>')
        err_msg = rsp.findtext('error-message')
        if err_msg:
            if err_msg == 'permission denied':
                e = EzErrors.PermissionError
            else:
                e = EzErrors.RpcError
            raise e(cmd=cmd, rsp=rsp)
        return rsp
Example #22
0
    def rpc(self, cmd):
        """
        Write the XML cmd and return the response as XML object.

        :cmd:
          <str> of the XML command.  if the :cmd: is not XML, then
          this routine will perform the brackets; i.e. if given
          'get-software-information', this routine will turn
          it into '<get-software-information/>'

        NOTES:
          The return XML object is the first child element after
          the <rpc-reply>.  There is also no error-checking
          performing by this routine.
        """
        if not cmd.startswith('<'):
            cmd = '<{0}/>'.format(cmd)
        rpc = six.b('<rpc>{0}</rpc>'.format(cmd))
        logger.info('Calling rpc: %s' % rpc)
        self._tty.rawwrite(rpc)

        rsp = self._receive()
        try:
            rsp = remove_namespaces(
                rsp[0])  # return first child after the <rpc-reply>
        except IndexError:
            if rsp.text.strip() is not '':
                return rsp
            # no children, so assume it means we are OK
            return True
        except:
            return etree.XML('<error-in-receive/>')
        err_msg = rsp.findtext('error-message')
        if err_msg:
            if err_msg == 'permission denied':
                e = EzErrors.PermissionError
            else:
                e = EzErrors.RpcError
            raise e(cmd=cmd, rsp=rsp)
        return rsp
Example #23
0
 def wrapper(*args, **kwargs):
     if 'ignore_warning' in kwargs:
         ignore_warn = kwargs.pop('ignore_warning')
         try:
             result = function(*args, **kwargs)
             return result
         except RpcError as ex:
             ex.rpc_xml = JXML.remove_namespaces(ex.rpc_xml)
             if hasattr(ex, 'rpc_error') and\
                     ex.rpc_error['severity'] == 'warning':
                 if ignore_warn is True:
                     return ex.rpc_xml
                 elif isinstance(ignore_warn, (str, unicode)):
                     if re.search(ignore_warn, ex.message, re.I):
                         return ex.rpc_xml
                 elif isinstance(ignore_warn, list):
                     for warn_msg in ignore_warn:
                         if re.search(warn_msg, ex.message, re.I):
                             return ex.rpc_xml
                 raise ex
             else:
                 raise ex
     else:
         return function(*args, **kwargs)
Example #24
0
    def execute(self, rpc_cmd, **kvargs):
        """
        Executes an XML RPC and returns results as either XML or native python

        rpc_cmd
          can either be an XML Element or xml-as-string.  In either case
          the command starts with the specific command element, i.e., not the
          <rpc> element itself

        kvargs['to_py']
          is a caller provided function that takes the response and
          will convert the results to native python types.  all kvargs
          will be passed to this function as well in the form:
          :to_py:( self, rpc_rsp, \**kvargs )
        """

        if isinstance(rpc_cmd, str):
            rpc_cmd_e = etree.XML(rpc_cmd)
        elif isinstance(rpc_cmd, etree._Element):
            rpc_cmd_e = rpc_cmd
        else:
            raise ValueError(
                "Dont know what to do with rpc of type %s" %
                rpc_cmd.__class__.__name__)

        # invoking a bad RPC will cause a connection object exception
        # will will be raised directly to the caller ... for now ...
        # @@@ need to trap this and re-raise accordingly.

        try:
            rpc_rsp_e = self._conn.rpc(rpc_cmd_e)._NCElement__doc
        except Exception as err:
            # err is an NCError from ncclient
            rsp = JXML.remove_namespaces(err.xml)
            # see if this is a permission error
            e = EzErrors.PermissionError if rsp.findtext('error-message') == 'permission denied' else EzErrors.RpcError
            raise e(cmd=rpc_cmd_e, rsp=rsp)

        # for RPCs that have embedded rpc-errors, need to check for those now

        rpc_errs = rpc_rsp_e.xpath('.//rpc-error')
        if len(rpc_errs):
            raise EzErrors.RpcError(rpc_cmd_e, rpc_rsp_e, rpc_errs)

        # skip the <rpc-reply> element and pass the caller first child element
        # generally speaking this is what they really want. If they want to
        # uplevel they can always call the getparent() method on it.

        try:
            ret_rpc_rsp = rpc_rsp_e[0]
        except IndexError:
            # no children, so assume it means we are OK
            return True

        # if the caller provided a "to Python" conversion function, then invoke
        # that now and return the results of that function.  otherwise just
        # return the RPC results as XML

        if kvargs.get('to_py'):
            return kvargs['to_py'](self, ret_rpc_rsp, **kvargs)
        else:
            return ret_rpc_rsp
Example #25
0
    def commit(self, **kvargs):
        """
        Commit a configuration.

        :param str comment: If provided logs this comment with the commit.
        :param int confirm: If provided activates confirm safeguard with
                            provided value as timeout (minutes).
        :param int timeout: If provided the command will wait for completion
                            using the provided value as timeout (seconds).
                            By default the device timeout is used.
        :param bool sync: On dual control plane systems, requests that
                            the candidate configuration on one control plane be
                            copied to the other control plane, checked for
                            correct syntax, and committed on both Routing Engines.
        :param bool force_sync: On dual control plane systems, forces the candidate
                            configuration on one control plane to be copied to the
                            other control plane.
        :param bool full: When true requires all the daemons to check and evaluate
                            the new configuration.
        :param bool detail: When true return commit detail as XML


        :returns:
            * ``True`` when successful
            * Commit detail XML (when detail is True)

        :raises CommitError: When errors detected in candidate configuration.
                             You can use the Exception errs variable
                             to identify the specific problems

        .. warning::
            If the function does not receive a reply prior to the timeout
            a RpcTimeoutError will be raised.  It is possible the commit
            was successful.  Manual verification may be required.
        """
        rpc_args = {}

        # if a comment is provided, then include that in the RPC

        comment = kvargs.get('comment')
        if comment:
            rpc_args['log'] = comment

        # if confirm is provided, then setup the RPC args
        # so that Junos will either use the default confirm
        # timeout (confirm=True) or a specific timeout
        # (confirm=<minutes>)

        confirm = kvargs.get('confirm')
        if confirm:
            rpc_args['confirmed'] = True
            confirm_val = str(confirm)
            if 'True' != confirm_val:
                rpc_args['confirm-timeout'] = confirm_val

        # if a timeout is provided, then include that in the RPC

        timeout = kvargs.get('timeout')
        if timeout:
            rpc_args['dev_timeout'] = timeout

        # Check for force_sync and sync
        if kvargs.get('force_sync'):
            rpc_args['synchronize'] = True
            rpc_args['force-synchronize'] = True
        elif kvargs.get('sync'):
            rpc_args['synchronize'] = True

        # Check for full
        if kvargs.get('full'):
            rpc_args['full'] = True

        rpc_varg = []
        detail = kvargs.get('detail')
        if detail:
            rpc_varg = [{'detail': 'detail'}]

        # dbl-splat the rpc_args since we want to pass key/value to metaexec
        # if there is a commit/check error, this will raise an execption

        try:
            rsp = self.rpc.commit_configuration(*rpc_varg, **rpc_args)
        except RpcTimeoutError:
            raise
        except RpcError as err:        # jnpr.junos exception
            if err.rsp.find('ok') is not None:
                # this means there are warnings, but no errors
                return True
            else:
                raise CommitError(cmd=err.cmd, rsp=err.rsp)
        except Exception as err:
            # so the ncclient gives us something I don't want.  I'm going to
            # convert it and re-raise the commit error
            JXML.remove_namespaces(err.xml)
            raise CommitError(rsp=err.xml)

        if detail:
            return rsp
        else:
            return True
Example #26
0
    def execute(self, rpc_cmd, **kvargs):
        """
        Executes an XML RPC and returns results as either XML or native python

        :param rpc_cmd:
          can either be an XML Element or xml-as-string.  In either case
          the command starts with the specific command element, i.e., not the
          <rpc> element itself

        :param func to_py:
          Is a caller provided function that takes the response and
          will convert the results to native python types.  all kvargs
          will be passed to this function as well in the form::

            to_py( self, rpc_rsp, **kvargs )

        :raises ValueError:
            When the **rpc_cmd** is of unknown origin

        :raises PermissionError:
            When the requested RPC command is not allowed due to
            user-auth class privilege controls on Junos

        :raises RpcError:
            When an ``rpc-error`` element is contained in the RPC-reply

        :returns:
            RPC-reply as XML object.  If **to_py** is provided, then
            that function is called, and return of that function is
            provided back to the caller; presumably to convert the XML to
            native python data-types (e.g. ``dict``).
        """

        if self.connected is not True:
            raise EzErrors.ConnectClosedError(self)

        if isinstance(rpc_cmd, str):
            rpc_cmd_e = etree.XML(rpc_cmd)
        elif isinstance(rpc_cmd, etree._Element):
            rpc_cmd_e = rpc_cmd
        else:
            raise ValueError(
                "Dont know what to do with rpc of type %s" %
                rpc_cmd.__class__.__name__)

        # invoking a bad RPC will cause a connection object exception
        # will will be raised directly to the caller ... for now ...
        # @@@ need to trap this and re-raise accordingly.

        try:
            rpc_rsp_e = self._rpc_reply(rpc_cmd_e)
        except NcOpErrors.TimeoutExpiredError:
            # err is a TimeoutExpiredError from ncclient,
            # which has no such attribute as xml.
            raise EzErrors.RpcTimeoutError(self, rpc_cmd_e.tag, self.timeout)
        except NcErrors.TransportError:
            raise EzErrors.ConnectClosedError(self)
        except RPCError as err:
            rsp = JXML.remove_namespaces(err.xml)
            # see if this is a permission error
            e = EzErrors.PermissionError if rsp.findtext('error-message') == \
                'permission denied' \
                else EzErrors.RpcError
            raise e(cmd=rpc_cmd_e, rsp=rsp, errs=err)
        # Something unexpected happened - raise it up
        except Exception as err:
            warnings.warn("An unknown exception occured - please report.",
                          RuntimeWarning)
            raise

        # From 14.2 onward, junos supports JSON, so now code can be written as
        # dev.rpc.get_route_engine_information({'format': 'json'})

        if rpc_cmd_e.attrib.get('format') in ['json', 'JSON']:
            ver_info = self.facts.get('version_info')
            if ver_info and ver_info.major[0] >= 15 or \
                    (ver_info.major[0] == 14 and ver_info.major[1] >= 2):
                try:
                    return json.loads(rpc_rsp_e.text)
                except ValueError as ex:
                    # when data is {}{.*} types
                    if str(ex).startswith('Extra data'):
                        return json.loads(
                            re.sub('\s?{\s?}\s?', '', rpc_rsp_e.text))
            else:
                warnings.warn("Native JSON support is only from 14.2 onwards",
                              RuntimeWarning)

        # This section is here for the possible use of something other than
        # ncclient for RPCs that have embedded rpc-errors, need to check for
        # those now.
        # rpc_errs = rpc_rsp_e.xpath('.//rpc-error')
        # if len(rpc_errs):
        #     raise EzErrors.RpcError(cmd=rpc_cmd_e, rsp=rpc_errs[0])

        # skip the <rpc-reply> element and pass the caller first child element
        # generally speaking this is what they really want. If they want to
        # uplevel they can always call the getparent() method on it.

        try:
            ret_rpc_rsp = rpc_rsp_e[0]
        except IndexError:
            # For cases where reply are like
            # <rpc-reply>
            #    protocol: operation-failed
            #    error: device asdf not found
            # </rpc-reply>
            if rpc_rsp_e.text is not None and rpc_rsp_e.text.strip() is not '':
                return rpc_rsp_e
            # no children, so assume it means we are OK
            return True

        # if the caller provided a "to Python" conversion function, then invoke
        # that now and return the results of that function.  otherwise just
        # return the RPC results as XML

        if kvargs.get('to_py'):
            return kvargs['to_py'](self, ret_rpc_rsp, **kvargs)
        else:
            return ret_rpc_rsp
Example #27
0
    def execute(self, rpc_cmd, **kvargs):
        """
        Executes an XML RPC and returns results as either XML or native python

        :param rpc_cmd:
          can either be an XML Element or xml-as-string.  In either case
          the command starts with the specific command element, i.e., not the
          <rpc> element itself

        :param func to_py':
          Is a caller provided function that takes the response and
          will convert the results to native python types.  all kvargs
          will be passed to this function as well in the form::

            to_py( self, rpc_rsp, **kvargs )

        :raises ValueError:
            When the **rpc_cmd** is of unknown origin

        :raises PermissionError:
            When the requested RPC command is not allowed due to
            user-auth class privledge controls on Junos

        :raises RpcError:
            When an ``rpc-error`` element is contained in the RPC-reply

        :returns:
            RPC-reply as XML object.  If **to_py** is provided, then
            that function is called, and return of that function is
            provided back to the caller; presuably to convert the XML to
            native python data-types (e.g. ``dict``).
        """

        if isinstance(rpc_cmd, str):
            rpc_cmd_e = etree.XML(rpc_cmd)
        elif isinstance(rpc_cmd, etree._Element):
            rpc_cmd_e = rpc_cmd
        else:
            raise ValueError("Dont know what to do with rpc of type %s" %
                             rpc_cmd.__class__.__name__)

        # invoking a bad RPC will cause a connection object exception
        # will will be raised directly to the caller ... for now ...
        # @@@ need to trap this and re-raise accordingly.

        try:
            rpc_rsp_e = self._conn.rpc(rpc_cmd_e)._NCElement__doc
        except Exception as err:
            # err is an NCError from ncclient
            rsp = JXML.remove_namespaces(err.xml)
            # see if this is a permission error
            e = EzErrors.PermissionError if rsp.findtext(
                'error-message') == 'permission denied' else EzErrors.RpcError
            raise e(cmd=rpc_cmd_e, rsp=rsp)

        # for RPCs that have embedded rpc-errors, need to check for those now

        rpc_errs = rpc_rsp_e.xpath('.//rpc-error')
        if len(rpc_errs):
            raise EzErrors.RpcError(rpc_cmd_e, rpc_rsp_e, rpc_errs)

        # skip the <rpc-reply> element and pass the caller first child element
        # generally speaking this is what they really want. If they want to
        # uplevel they can always call the getparent() method on it.

        try:
            ret_rpc_rsp = rpc_rsp_e[0]
        except IndexError:
            # no children, so assume it means we are OK
            return True

        # if the caller provided a "to Python" conversion function, then invoke
        # that now and return the results of that function.  otherwise just
        # return the RPC results as XML

        if kvargs.get('to_py'):
            return kvargs['to_py'](self, ret_rpc_rsp, **kvargs)
        else:
            return ret_rpc_rsp
Example #28
0
    def commit(self, **kvargs):
        """
        Commit a configuration.

        :param str comment: If provided logs this comment with the commit.
        :param int confirm: If provided activates confirm safeguard with
                            provided value as timeout (minutes).
        :param int timeout: If provided the command will wait for completion
                            using the provided value as timeout (seconds).
                            By default the device timeout is used.
        :param bool sync: On dual control plane systems, requests that
                            the candidate configuration on one control plane be
                            copied to the other control plane, checked for
                            correct syntax, and committed on both Routing Engines.
        :param bool force_sync: On dual control plane systems, forces the candidate
                            configuration on one control plane to be copied to the
                            other control plane.
        :param bool full: When true requires all the daemons to check and evaluate
                            the new configuration.
        :param bool detail: When true return commit detail as XML


        :returns:
            * ``True`` when successful
            * Commit detail XML (when detail is True)

        :raises CommitError: When errors detected in candidate configuration.
                             You can use the Exception errs variable
                             to identify the specific problems

        .. warning::
            If the function does not receive a reply prior to the timeout
            a RpcTimeoutError will be raised.  It is possible the commit
            was successful.  Manual verification may be required.
        """
        rpc_args = {}

        # if a comment is provided, then include that in the RPC

        comment = kvargs.get('comment')
        if comment:
            rpc_args['log'] = comment

        # if confirm is provided, then setup the RPC args
        # so that Junos will either use the default confirm
        # timeout (confirm=True) or a specific timeout
        # (confirm=<minutes>)

        confirm = kvargs.get('confirm')
        if confirm:
            rpc_args['confirmed'] = True
            confirm_val = str(confirm)
            if 'True' != confirm_val:
                rpc_args['confirm-timeout'] = confirm_val

        # if a timeout is provided, then include that in the RPC

        timeout = kvargs.get('timeout')
        if timeout:
            rpc_args['dev_timeout'] = timeout

        # Check for force_sync and sync
        if kvargs.get('force_sync'):
            rpc_args['synchronize'] = True
            rpc_args['force-synchronize'] = True
        elif kvargs.get('sync'):
            rpc_args['synchronize'] = True

        # Check for full
        if kvargs.get('full'):
            rpc_args['full'] = True

        rpc_varg = []
        detail = kvargs.get('detail')
        if detail:
            rpc_varg = [{'detail': 'detail'}]

        # dbl-splat the rpc_args since we want to pass key/value to metaexec
        # if there is a commit/check error, this will raise an execption

        try:
            rsp = self.rpc.commit_configuration(*rpc_varg, **rpc_args)
        except RpcTimeoutError:
            raise
        except RpcError as err:  # jnpr.junos exception
            if err.rsp.find('ok') is not None:
                # this means there are warnings, but no errors
                return True
            else:
                raise CommitError(cmd=err.cmd, rsp=err.rsp)
        except Exception as err:
            # so the ncclient gives us something I don't want.  I'm going to
            # convert it and re-raise the commit error
            JXML.remove_namespaces(err.xml)
            raise CommitError(rsp=err.xml)

        if detail:
            return rsp
        else:
            return True
Example #29
0
    def commit(self, **kvargs):
        """
        Commit a configuration.

        :param str comment: If provide logs this comment with the commit.
        :param int confirm: If provided activates confirm safeguard with
                            provided value as timeout (minutes).
        :param int timeout: If provided the command will wait for completion
                            using the provided value as timeout (seconds).
                            By default the device timeout is used.

        :returns:
            * ``True`` when successful

        :raises CommitError: When errors detected in candidate configuration.
                             You can use the Exception errs variable
                             to identify the specific problems

        .. warning::
            If the function does not receive a reply prior to the timeout
            a RpcTimeoutError will be raised.  It is possible the commit
            was successful.  Manual verification may be required.
        """
        rpc_args = {}

        # if a comment is provided, then include that in the RPC

        comment = kvargs.get('comment')
        if comment:
            rpc_args['log'] = comment

        # if confirm is provided, then setup the RPC args
        # so that Junos will either use the default confirm
        # timeout (confirm=True) or a specific timeout
        # (confirm=<minutes>)

        confirm = kvargs.get('confirm')
        if confirm:
            rpc_args['confirmed'] = True
            confirm_val = str(confirm)
            if 'True' != confirm_val:
                rpc_args['confirm-timeout'] = confirm_val

        # if a timeout is provided, then include that in the RPC

        timeout = kvargs.get('timeout')
        if timeout:
            rpc_args['dev_timeout'] = timeout

        # dbl-splat the rpc_args since we want to pass key/value to metaexec
        # if there is a commit/check error, this will raise an execption

        try:
            self.rpc.commit_configuration(**rpc_args)
        except RpcTimeoutError:
            raise
        except RpcError as err:        # jnpr.junos exception
            if err.rsp.find('ok') is not None:
                # this means there are warnings, but no errors
                return True
            else:
                raise CommitError(cmd=err.cmd, rsp=err.rsp)
        except Exception as err:
            # so the ncclient gives us something I don't want.  I'm going to
            # convert it and re-raise the commit error
            JXML.remove_namespaces(err.xml)
            raise CommitError(rsp=err.xml)

        return True
def _get_software_information(device):
    # See if device understands "invoke-on all-routing-engines"
    try:
        return device.rpc.cli("show version invoke-on all-routing-engines",
                              format='xml', normalize=True)
    except RpcError as err:
        # See if device runs on a linux kernel
        if device.facts['_is_linux']:
            sw_info_all = device.rpc.get_software_information(normalize=True,
                                                              node='all')
            sw_info_re0 = device.rpc.get_software_information(normalize=True,
                                                              node='re0')
            sw_info_re1 = device.rpc.get_software_information(normalize=True,
                                                              node='re1')
            re0_hostname = sw_info_re0.findtext('./host-name')
            re1_hostname = sw_info_re1.findtext('./host-name')
            for current_hostname in sw_info_all.findall(
                './multi-routing-engine-result/software-information/host-name'):
                if current_hostname.text == re0_hostname:
                    current_hostname.getparent().getparent().append(
                        JXML('<re-name>re0</re-name>'))
                elif current_hostname.text == re1_hostname:
                    current_hostname.getparent().getparent().append(
                        JXML('<re-name>re1</re-name>'))
            return sw_info_all
        # See if device is VC Capable
        if device.facts['vc_capable'] is True:
            try:
                return device.rpc.cli("show version all-members", format='xml',
                                      normalize=True)
            except Exception:
                pass
        # check if rpc-reply got 2 child element, one rpc-error and another
        # software information
        elif hasattr(err, 'rpc_error') and err.rpc_error is not None and \
                        'Could not connect to ' in err.rpc_error.get('message'):
            logger.debug(err.rpc_error.get('message'))
            # getparent as rpc-reply got software-information in 2nd element
            # and dev.cli return just 1st element.
            rsp = err.xml.getparent()
            rsp = JXML.remove_namespaces(rsp)
            if rsp.xpath(".//software-information"):
                return rsp
        try:
            # JDM for Junos Node Slicing
            return device.rpc.get_software_information(all_servers=True,
                                                       format='xml',
                                                       normalize=True)
        except Exception:
            pass
        try:
            sw_info = device.rpc.get_software_information(normalize=True)
        except Exception:
            sw_info = True
        try:
            if sw_info is True:
                # Possibly an NFX which requires 'local' and 'detail' args.
                sw_info = device.rpc.get_software_information(local=True,
                                                              detail=True,
                                                              normalize=True)
            return sw_info
        except Exception:
            pass
Example #31
0
    def get(self, *vargs, **kvargs):
        """
        Retrieve the XML table data from the Device instance and
        returns back the Table instance - for call-chaining purposes.

        If the Table was created with a :path: rather than a Device,
        then this method will load the XML from that file.  In this
        case, the \*vargs, and \**kvargs are not used.

        ALIAS: __call__

        :vargs:
          [0] is the table :arg_key: value.  This is used so that
          the caller can retrieve just one item from the table without
          having to know the Junos RPC argument.

        :kvargs:
          these are the name/value pairs relating to the specific Junos
          XML command attached to the table.  For example, if the RPC
          is 'get-route-information', there are parameters such as
          'table' and 'destination'.  Any valid RPC argument can be
          passed to :kvargs: to further filter the results of the :get():
          operation.  neato!

        NOTES:
          If you need to create a 'stub' for unit-testing
          purposes, you want to create a subclass of your table and
          overload this methods.
        """
        self._clearkeys()

        if self._path is not None:
            # for loading from local file-path
            self.xml = remove_namespaces(etree.parse(self._path).getroot())
            return self

        if self._lxml is not None:
            return self

        argkey = vargs[0] if len(vargs) else None

        rpc_args = {}

        if self._use_filter:
            try:
                filter_xml = generate_sax_parser_input(self)
                rpc_args["filter_xml"] = filter_xml
            except Exception as ex:
                logger.debug("Not able to create SAX parser input due to " "'%s'" % ex)

        self.D.transform = lambda: remove_namespaces_and_spaces
        rpc_args.update(self.GET_ARGS)  # copy default args
        # saltstack get_table pass args as named keyword
        if "args" in kvargs and isinstance(kvargs["args"], dict):
            rpc_args.update(kvargs.pop("args"))
        rpc_args.update(kvargs)  # copy caller provided args

        if hasattr(self, "GET_KEY") and argkey is not None:
            rpc_args.update({self.GET_KEY: argkey})

        # execute the Junos RPC to retrieve the table
        self.xml = getattr(self.RPC, self.GET_RPC)(**rpc_args)

        # returning self for call-chaining purposes, yo!
        return self
Example #32
0
    def execute(self, rpc_cmd, **kvargs):
        """
        Executes an XML RPC and returns results as either XML or native python

        :param rpc_cmd:
          can either be an XML Element or xml-as-string.  In either case
          the command starts with the specific command element, i.e., not the
          <rpc> element itself

        :param func to_py':
          Is a caller provided function that takes the response and
          will convert the results to native python types.  all kvargs
          will be passed to this function as well in the form::

            to_py( self, rpc_rsp, **kvargs )

        :raises ValueError:
            When the **rpc_cmd** is of unknown origin

        :raises PermissionError:
            When the requested RPC command is not allowed due to
            user-auth class privilege controls on Junos

        :raises RpcError:
            When an ``rpc-error`` element is contained in the RPC-reply

        :returns:
            RPC-reply as XML object.  If **to_py** is provided, then
            that function is called, and return of that function is
            provided back to the caller; presumably to convert the XML to
            native python data-types (e.g. ``dict``).
        """

        if self.connected is not True:
            raise EzErrors.ConnectClosedError(self)

        if isinstance(rpc_cmd, str):
            rpc_cmd_e = etree.XML(rpc_cmd)
        elif isinstance(rpc_cmd, etree._Element):
            rpc_cmd_e = rpc_cmd
        else:
            raise ValueError(
                "Dont know what to do with rpc of type %s" %
                rpc_cmd.__class__.__name__)

        # invoking a bad RPC will cause a connection object exception
        # will will be raised directly to the caller ... for now ...
        # @@@ need to trap this and re-raise accordingly.

        try:
            rpc_rsp_e = self._conn.rpc(rpc_cmd_e)._NCElement__doc
        except NcOpErrors.TimeoutExpiredError:
            # err is a TimeoutExpiredError from ncclient,
            # which has no such attribute as xml.
            raise EzErrors.RpcTimeoutError(self, rpc_cmd_e.tag, self.timeout)
        except NcErrors.TransportError:
            raise EzErrors.ConnectClosedError(self)
        except RPCError as err:
            # err is an NCError from ncclient
            rsp = JXML.remove_namespaces(err.xml)
            # see if this is a permission error
            e = EzErrors.PermissionError if rsp.findtext('error-message') == 'permission denied' else EzErrors.RpcError
            raise e(cmd=rpc_cmd_e, rsp=rsp)
        # Something unexpected happened - raise it up
        except Exception as err:
            warnings.warn("An unknown exception occured - please report.", RuntimeWarning)
            raise

        # This section is here for the possible use of something other than ncclient
        # for RPCs that have embedded rpc-errors, need to check for those now

        # rpc_errs = rpc_rsp_e.xpath('.//rpc-error')
        # if len(rpc_errs):
        #     raise EzErrors.RpcError(cmd=rpc_cmd_e, rsp=rpc_errs[0])

        # skip the <rpc-reply> element and pass the caller first child element
        # generally speaking this is what they really want. If they want to
        # uplevel they can always call the getparent() method on it.

        try:
            ret_rpc_rsp = rpc_rsp_e[0]
        except IndexError:
            # no children, so assume it means we are OK
            return True

        # if the caller provided a "to Python" conversion function, then invoke
        # that now and return the results of that function.  otherwise just
        # return the RPC results as XML

        if kvargs.get('to_py'):
            return kvargs['to_py'](self, ret_rpc_rsp, **kvargs)
        else:
            return ret_rpc_rsp
def _get_software_information(device):
    # See if device understands "invoke-on all-routing-engines"
    try:
        return device.rpc.cli("show version invoke-on all-routing-engines",
                              format='xml',
                              normalize=True)
    except RpcError as err:
        # See if device runs on a linux kernel
        if device.facts['_is_linux']:
            sw_info_all = device.rpc.get_software_information(normalize=True,
                                                              node='all')
            sw_info_re0 = device.rpc.get_software_information(normalize=True,
                                                              node='re0')
            sw_info_re1 = device.rpc.get_software_information(normalize=True,
                                                              node='re1')
            re0_hostname = sw_info_re0.findtext('./host-name')
            re1_hostname = sw_info_re1.findtext('./host-name')
            for current_hostname in sw_info_all.findall(
                    './multi-routing-engine-result/software-information/host-name'
            ):
                if current_hostname.text == re0_hostname:
                    current_hostname.getparent().getparent().append(
                        JXML('<re-name>re0</re-name>'))
                elif current_hostname.text == re1_hostname:
                    current_hostname.getparent().getparent().append(
                        JXML('<re-name>re1</re-name>'))
            return sw_info_all
        # See if device is VC Capable
        if device.facts['vc_capable'] is True:
            try:
                return device.rpc.cli("show version all-members",
                                      format='xml',
                                      normalize=True)
            except Exception:
                pass
        # check if rpc-reply got 2 child element, one rpc-error and another
        # software information
        elif hasattr(err, 'rpc_error') and err.rpc_error is not None and \
                        'Could not connect to ' in err.rpc_error.get('message'):
            logger.debug(err.rpc_error.get('message'))
            # getparent as rpc-reply got software-information in 2nd element
            # and dev.cli return just 1st element.
            rsp = err.xml.getparent()
            rsp = JXML.remove_namespaces(rsp)
            if rsp.xpath(".//software-information"):
                return rsp
        try:
            # JDM for Junos Node Slicing
            return device.rpc.get_software_information(all_servers=True,
                                                       format='xml',
                                                       normalize=True)
        except Exception:
            pass
        try:
            sw_info = device.rpc.get_software_information(normalize=True)
        except Exception:
            sw_info = True
        try:
            if sw_info is True:
                # Possibly an NFX which requires 'local' and 'detail' args.
                sw_info = device.rpc.get_software_information(local=True,
                                                              detail=True,
                                                              normalize=True)
            return sw_info
        except Exception:
            pass