Exemplo n.º 1
0
def _get_selection(elm, select):
    if select is None or len(select) == 0:
        return

    # Add non-default namespaces to filter element
    nsmap = {key: value for key, value in NSMAP.items() if key and key != "nc"}
    felm = util.subelm(elm, "nc:filter", nsmap=nsmap)

    if hasattr(select, "nsmap"):
        felm.attrib[qmap("nc") + "type"] = "subtree"
        felm.append(select)
    elif _is_filter(select):
        felm.attrib[qmap("nc") + "type"] = "subtree"
        felm.append(etree.fromstring(select))
    else:
        felm.attrib[qmap("nc") + "type"] = "xpath"
        felm.attrib[qmap("nc") + "select"] = select
Exemplo n.º 2
0
    def _reader_handle_message(self, msg):
        """This function is called from the session reader thread to process a received
        framed netconf message.
        """
        try:
            tree = etree.parse(io.BytesIO(msg.encode('utf-8')))
            if not tree:
                raise SessionError(msg, "Invalid XML from server.")
        except etree.XMLSyntaxError:
            raise SessionError(msg, "Invalid XML from server.")

        replies = tree.xpath("/nc:rpc-reply", namespaces=NSMAP)
        if not replies:
            raise SessionError(msg, "No rpc-reply found")

        for reply in replies:
            try:
                msg_id = int(reply.get(qmap("nc") + 'message-id'))
            except (TypeError, ValueError):
                try:
                    # Deal with servers not properly setting attribute namespace.
                    msg_id = int(reply.get('message-id'))
                except (TypeError, ValueError):
                    # # Cisco is returning errors without message-id attribute which
                    # # is non-rfc-conforming it is doing this for any malformed XML
                    # # not simply missing message-id attribute.
                    # error = reply.xpath("nc:rpc-error", namespaces=self.nsmap)
                    # if error:
                    #     raise RPCError(received, tree, error[0])
                    raise SessionError(msg,
                                       "No valid message-id attribute found")

            # Queue the message
            with self.cv:
                try:
                    if msg_id not in self.rpc_out:
                        if self.debug:
                            logger.debug(
                                "Ignoring unwanted reply for message-id %s",
                                str(msg_id))
                        return
                    elif self.rpc_out[msg_id] is not None:
                        logger.warning(
                            "Received multiple replies for message-id %s:"
                            " before: %s now: %s", str(msg_id),
                            str(self.rpc_out[msg_id]), str(msg))

                    if self.debug:
                        logger.debug("%s: Received rpc-reply message-id: %s",
                                     str(self), str(msg_id))
                    self.rpc_out[msg_id] = tree, reply, msg
                except Exception as error:
                    logger.debug("%s: Unexpected exception: %s", str(self),
                                 str(error))
                    raise
                finally:
                    self.cv.notify_all()
Exemplo n.º 3
0
 def send_rpc_reply(self, rpc_reply, origmsg):
     reply = etree.Element(qmap("nc") + "rpc-reply", attrib=origmsg.attrib, nsmap=origmsg.nsmap)
     try:
         rpc_reply.getchildren  # pylint: disable=W0104
         reply.append(rpc_reply)
     except AttributeError:
         reply.extend(rpc_reply)
     ucode = etree.tounicode(reply, pretty_print=True)
     if self.debug:
         logger.debug("%s: Sending RPC-Reply: %s", str(self), str(ucode))
     self.send_message(ucode)
 def send_rpc_reply (self, rpc_reply, origmsg):
     reply = etree.Element(qmap('nc') + "rpc-reply", attrib=origmsg.attrib, nsmap=origmsg.nsmap)
     try:
         rpc_reply.getchildren                           # pylint: disable=W0104
         reply.append(rpc_reply)
     except AttributeError:
         reply.extend(rpc_reply)
     ucode = etree.tounicode(reply, pretty_print=True)
     if self.debug:
         logger.debug("%s: Sending RPC-Reply: %s", str(self), str(ucode))
     self.send_message(ucode)
Exemplo n.º 5
0
def filter_results(rpc, data, filter_or_none, debug=False):
    """Check for a user filter and prune the result data accordingly.

    :param rpc: An RPC message element.
    :param data: The data to filter.
    :param filter_or_none: Filter element or None.
    :type filter_or_none: `lxml.Element`
    """
    if filter_or_none is None:
        return data

    type_attr_name = qmap("nc") + "type"
    select_attr_name = qmap("nc") + "select"

    if type_attr_name not in filter_or_none.attrib or filter_or_none.attrib[
            type_attr_name] == "subtree":
        # Check for the pathalogical case of empty filter since that's easy to implement.
        if not filter_or_none.getchildren():
            return elm("nc:data")

        xpf = filter_to_xpath(filter_or_none)

    elif filter_or_none.attrib[type_attr_name] == "xpath":
        if select_attr_name not in filter_or_none.attrib:
            raise error.MissingAttributeProtoError(rpc, filter_or_none,
                                                   select_attr_name)
        xpf = filter_or_none.attrib[select_attr_name]
    else:
        msg = "unexpected type: " + str(filter_or_none.attrib[type_attr_name])
        raise error.BadAttributeProtoError(rpc,
                                           filter_or_none,
                                           type_attr_name,
                                           message=msg)

    logger.debug("Filtering on xpath expression: %s", str(xpf))
    return xpath_filter_result(data, xpf)
Exemplo n.º 6
0
 def _send_rpc_reply(self, rpc_reply, origmsg):
     """Send an rpc-reply to the client. This is should normally not be called
     externally the return value from the rpc_* methods will be returned
     using this method.
     """
     reply = etree.Element(qmap('nc') + "rpc-reply", attrib=origmsg.attrib, nsmap=origmsg.nsmap)
     try:
         rpc_reply.getchildren  # pylint: disable=W0104
         reply.append(rpc_reply)
     except AttributeError:
         reply.extend(rpc_reply)
     ucode = etree.tounicode(reply, pretty_print=True)
     if self.debug:
         logger.debug("%s: Sending RPC-Reply: %s", str(self), str(ucode))
     self.send_message(ucode)
Exemplo n.º 7
0
    def __init__(self, origmsg, etype, tag, **kwargs):
        # Add attrib and nsmap from original message.
        self.reply = etree.Element(qmap("nc") + "rpc-reply",
                                   attrib=origmsg.attrib,
                                   nsmap=origmsg.nsmap)

        rpcerr = etree.SubElement(self.reply, qmap("nc") + "rpc-error")

        # We require a type, tag, and severity assuming error for severity.
        if etype in RPCERR_TYPE_ENUM:
            etype = RPCERR_TYPE_ENUM[etype]
        etree.SubElement(rpcerr, qmap("nc") + "error-type").text = str(etype)

        etree.SubElement(rpcerr, qmap("nc") + "error-tag").text = tag

        if "severity" not in kwargs:
            etree.SubElement(rpcerr,
                             qmap("nc") + "error-severity").text = "error"

        # Now convert any other arguments to xml
        for key, value in kwargs.items():
            # Allow info to be a dictionary we convert to sub-elements
            if key == "info" and hasattr(value, "items"):
                infoelm = etree.SubElement(rpcerr, qmap("nc") + "error-info")
                for ikey, ivalue in value.items():
                    ikey = ikey.replace('_', '-')
                    etree.SubElement(infoelm,
                                     "{}".format(ikey)).text = str(ivalue)
            else:
                key = key.replace('_', '-')
                etree.SubElement(rpcerr,
                                 qmap("nc") +
                                 "error-{}".format(key)).text = str(value)

        # This sort of sucks for humans
        super(RPCServerError, self).__init__(self.get_reply_msg())
Exemplo n.º 8
0
    def reader_handle_message(self, msg):
        """Handle a message, lock is already held"""
        if not self.session_open:
            return

        # Any error with XML encoding here is going to cause a session close
        # Technically we should be able to return malformed message I think.
        try:
            tree = etree.parse(io.BytesIO(msg.encode("utf-8")))
            if not tree:
                raise ncerror.SessionError(msg, "Invalid XML from client.")
        except etree.XMLSyntaxError:
            logger.warning("Closing session due to malformed message")
            raise ncerror.SessionError(msg, "Invalid XML from client.")

        rpcs = tree.xpath("/nc:rpc", namespaces=NSMAP)
        if not rpcs:
            raise ncerror.SessionError(msg, "No rpc found")

        for rpc in rpcs:
            try:
                msg_id = rpc.get("message-id")
                if self.debug:
                    logger.debug("%s: Received rpc message-id: %s", str(self), msg_id)
            except (TypeError, ValueError):
                raise ncerror.SessionError(msg, "No valid message-id attribute found")

            try:
                # Get the first child of rpc as the method name
                rpc_method = rpc.getchildren()
                if len(rpc_method) != 1:
                    if self.debug:
                        logger.debug("%s: Bad Msg: msg-id: %s", str(self), msg_id)
                    raise ncerror.RPCSvrErrBadMsg(rpc)
                rpc_method = rpc_method[0]

                rpcname = rpc_method.tag.replace(qmap("nc"), "")
                params = rpc_method.getchildren()
                paramslen = len(params)

                if rpcname == "close-session":
                    # XXX should be RPC-unlocking if need be
                    if self.debug:
                        logger.debug("%s: Received close-session msg-id: %s", str(self), msg_id)
                    self.send_rpc_reply(etree.Element("ok"), rpc)
                    self.close()
                    # XXX should we also call the user method if it exists?
                    return
                elif rpcname == "kill-session":
                    # XXX we are supposed to cleanly abort anything underway
                    if self.debug:
                        logger.debug("%s: Received kill-session msg-id: %s", str(self), msg_id)
                    self.send_rpc_reply(etree.Element("ok"), rpc)
                    self.close()
                    # XXX should we also call the user method if it exists?
                    return
                elif rpcname == "get":
                    # Validate GET parameters

                    if paramslen > 1:
                        # XXX need to specify all elements not known
                        raise ncerror.RPCSvrErrBadMsg(rpc)
                    if params and not util.filter_tag_match(params[0], "nc:filter"):
                        raise ncerror.RPCSvrUnknownElement(rpc, params[0])
                    if not params:
                        params = [None]
                elif rpcname == "get-config":
                    # Validate GET-CONFIG parameters

                    # XXX verify that the source parameter is present
                    if paramslen > 2:
                        # XXX need to specify all elements not known
                        raise ncerror.RPCSvrErrBadMsg(rpc)
                    source_param = rpc_method.find("nc:source", namespaces=NSMAP)
                    if source_param is None:
                        raise ncerror.RPCSvrMissingElement(rpc, util.elm("nc:source"))
                    filter_param = None
                    if paramslen == 2:
                        filter_param = rpc_method.find("nc:filter", namespaces=NSMAP)
                        if filter_param is None:
                            unknown_elm = params[0] if params[0] != source_param else params[1]
                            raise ncerror.RPCSvrUnknownElement(rpc, unknown_elm)
                    params = [source_param, filter_param]

                # ------------------
                # Call the method.
                # ------------------

                try:
                    # Handle any namespaces or prefixes in the tag, other than
                    # "nc" which was removed above. Of course, this does not handle
                    # namespace collisions, but that seems reasonable for now.
                    rpcname = rpcname.rpartition("}")[-1]
                    method_name = "rpc_" + rpcname.replace("-", "_")
                    method = getattr(self.methods, method_name, self._rpc_not_implemented)
                    # logger.debug("%s: Calling method: %s", str(self), str(methodname))
                    reply = method(self, rpc, *params)
                    self.send_rpc_reply(reply, rpc)
                except NotImplementedError:
                    raise ncerror.RPCSvrErrNotImpl(rpc)
            except ncerror.RPCSvrErrBadMsg as msgerr:
                if self.new_framing:
                    self.send_message(msgerr.get_reply_msg())
                else:
                    # If we are 1.0 we have to simply close the connection
                    # as we are not allowed to send this error
                    logger.warning("Closing 1.0 session due to malformed message")
                    raise ncerror.SessionError(msg, "Malformed message")
            except ncerror.RPCServerError as error:
                self.send_message(error.get_reply_msg())
            except EOFError:
                if self.debug:
                    logger.debug("Got EOF in reader_handle_message")
            except Exception as exception:
                error = ncerror.RPCSvrException(rpc, exception)
                self.send_message(error.get_reply_msg())
Exemplo n.º 9
0
    def _reader_handle_message(self, msg):
        if not self.session_open:
            return

        msg = msg.replace('\n', '').replace('\r', '').replace('\t', '')

        # Any error with XML encoding here is going to cause a session close
        # Technically we should be able to return malformed message I think.
        try:
            tree = etree.parse(io.BytesIO(msg.encode('utf-8')))
            if not tree:
                raise ncerror.SessionError(msg, "Invalid XML from client.")
        except etree.XMLSyntaxError:
            logger.warning("Closing session due to malformed message")
            raise ncerror.SessionError(msg, "Invalid XML from client.")

        if self.debug and msg.find('message-id="-1"') == -1:
            logger.debug("%s: Recieved RPC message:\n%s", str(self),
                         str(etree.tounicode(tree, pretty_print=True)))

        rpcs = tree.xpath("/nc:rpc", namespaces=NSMAP)
        if not rpcs:
            raise ncerror.SessionError(msg, "No rpc found")

        for rpc in rpcs:
            try:
                msg_id = rpc.get('message-id')
                if self.debug:
                    logger.debug("%s: Received rpc message-id: %s", str(self),
                                 msg_id)
            except (TypeError, ValueError):
                raise ncerror.SessionError(
                    msg, "No valid message-id attribute found")

            try:
                # Get the first child of rpc as the method name
                rpc_method = rpc.getchildren()
                if len(rpc_method) != 1:
                    if self.debug:
                        logger.debug("%s: Bad Msg: msg-id: %s", str(self),
                                     msg_id)
                    raise ncerror.MalformedMessageRPCError(rpc)
                rpc_method = rpc_method[0]

                rpcname = rpc_method.tag.replace(qmap('nc'), "")
                params = rpc_method.getchildren()
                paramslen = len(params)
                lock_target = None

                if self.debug:
                    logger.debug("%s: RPC: %s: paramslen: %s", str(self),
                                 rpcname, str(paramslen))

                if rpcname == "close-session":
                    # XXX should be RPC-unlocking if need be
                    if self.debug:
                        logger.debug("%s: Received close-session msg-id: %s",
                                     str(self), msg_id)
                    self._send_rpc_reply(etree.Element("ok"), rpc)
                    self.close()
                    # XXX should we also call the user method if it exists?
                    return
                elif rpcname == "kill-session":
                    # XXX we are supposed to cleanly abort anything underway
                    if self.debug:
                        logger.debug("%s: Received kill-session msg-id: %s",
                                     str(self), msg_id)
                    self._send_rpc_reply(etree.Element("ok"), rpc)
                    self.close()
                    # XXX should we also call the user method if it exists?
                    return
                elif rpcname == "get":
                    # Validate GET parameters

                    if paramslen > 1:
                        # XXX need to specify all elements not known
                        raise ncerror.MalformedMessageRPCError(rpc)
                    if params and not util.filter_tag_match(
                            params[0], "nc:filter"):
                        raise ncerror.UnknownElementProtoError(rpc, params[0])
                    if not params:
                        params = [None]
                elif rpcname == "get-config":
                    # Validate GET-CONFIG parameters

                    if paramslen > 2:
                        # XXX Should be ncerror.UnknownElementProtoError? for each?
                        raise ncerror.MalformedMessageRPCError(rpc)
                    source_param = rpc_method.find("nc:source",
                                                   namespaces=NSMAP)
                    if source_param is None:
                        raise ncerror.MissingElementProtoError(
                            rpc, util.qname("nc:source"))
                    filter_param = None
                    if paramslen == 2:
                        filter_param = rpc_method.find("nc:filter",
                                                       namespaces=NSMAP)
                        if filter_param is None:
                            unknown_elm = params[
                                0] if params[0] != source_param else params[1]
                            raise ncerror.UnknownElementProtoError(
                                rpc, unknown_elm)
                    params = [source_param, filter_param]
                elif rpcname == "lock" or rpcname == "unlock":
                    if paramslen != 1:
                        raise ncerror.MalformedMessageRPCError(rpc)
                    target_param = rpc_method.find("nc:target",
                                                   namespaces=NSMAP)
                    if target_param is None:
                        raise ncerror.MissingElementProtoError(
                            rpc, util.qname("nc:target"))
                    elms = target_param.getchildren()
                    if len(elms) != 1:
                        raise ncerror.MissingElementProtoError(
                            rpc, util.qname("nc:target"))
                    lock_target = elms[0].tag.replace(qmap('nc'), "")
                    if lock_target not in ["running", "candidate"]:
                        raise ncerror.BadElementProtoError(
                            rpc, util.qname("nc:target"))
                    params = [lock_target]

                    if rpcname == "lock":
                        logger.error("%s: Lock Target: %s", str(self),
                                     lock_target)
                        # Try and obtain the lock.
                        locksid = self.server.lock_target(self, lock_target)
                        if locksid:
                            raise ncerror.LockDeniedProtoError(rpc, locksid)
                    elif rpcname == "unlock":
                        logger.error("%s: Unlock Target: %s", str(self),
                                     lock_target)
                        # Make sure we have the lock.
                        locksid = self.server.is_target_locked(lock_target)
                        if locksid != self.session_id:
                            # An odd error to return
                            raise ncerror.LockDeniedProtoError(rpc, locksid)

                #------------------
                # Call the method.
                #------------------

                try:
                    # Handle any namespaces or prefixes in the tag, other than
                    # "nc" which was removed above. Of course, this does not handle
                    # namespace collisions, but that seems reasonable for now.
                    rpcname = rpcname.rpartition("}")[-1]
                    method_name = "rpc_" + rpcname.replace('-', '_')
                    method = getattr(self.methods, method_name, None)

                    if method is None:
                        if rpcname in self.handled_rpc_methods:
                            self._send_rpc_reply(etree.Element("ok"), rpc)
                            method = None
                        else:
                            method = self._rpc_not_implemented

                    if method is not None:
                        if self.debug:
                            logger.debug("%s: Calling method: %s", str(self),
                                         method_name)
                        reply = method(self, rpc, *params)
                        self._send_rpc_reply(reply, rpc)
                except Exception:
                    # If user raised error unlock if this was lock
                    if rpcname == "lock" and lock_target:
                        self.server.unlock_target(self, lock_target)
                    raise

                # If this was unlock and we're OK, release the lock.
                if rpcname == "unlock":
                    self.server.unlock_target(self, lock_target)

            except ncerror.MalformedMessageRPCError as msgerr:
                if self.new_framing:
                    if self.debug:
                        logger.debug("%s: MalformedMessageRPCError: %s",
                                     str(self), str(msgerr))
                    self.send_message(msgerr.get_reply_msg())
                else:
                    # If we are 1.0 we have to simply close the connection
                    # as we are not allowed to send this error
                    logger.warning(
                        "Closing 1.0 session due to malformed message")
                    raise ncerror.SessionError(msg, "Malformed message")
            except ncerror.RPCServerError as error:
                if self.debug:
                    logger.debug("%s: RPCServerError: %s", str(self),
                                 str(error))
                self._send_rpc_reply_error(error)
            except EOFError:
                if self.debug:
                    logger.debug("%s: Got EOF in reader_handle_message",
                                 str(self))
                error = ncerror.RPCSvrException(rpc, EOFError("EOF"))
                self._send_rpc_reply_error(error)
            except Exception as exception:
                if self.debug:
                    logger.debug(
                        "%s: Got unexpected exception in reader_handle_message: %s",
                        str(self), str(exception))
                error = ncerror.RPCSvrException(rpc, exception)
                self._send_rpc_reply_error(error)
Exemplo n.º 10
0
class MockMethods(object):
    NCFILTER = qmap("nc") + "filter"
    """This is an abstract class that is used to document the server methods functionality

    The server return not-implemented if the method is not found in the methods object,
    so feel free to use duck-typing here (i.e., no need to inherit)
    """

    def nc_append_capabilities(self, capabilities):  # pylint: disable=W0613
        """The server should append any capabilities it supports to capabilities"""
        ncutil.subelm(capabilities, "capability").text = mock_module
        ncutil.subelm(capabilities,
                      "capability").text = "urn:ietf:params:netconf:capability:xpath:1.0"

    def rpc_get(self, session, rpc, filter_or_none):  # pylint: disable=W0613
        data = ncutil.elm("data")
        cont = ncutil.subelm(data, "interfaces")
        listval = ncutil.subelm(cont, "interface")
        listval.append(ncutil.leaf_elm("name", "Ethernet0/0"))
        listval.append(ncutil.leaf_elm("shutdown", "true"))
        listval.append(ncutil.leaf_elm("state", "down"))
        listval = ncutil.subelm(cont, "interface")
        listval.append(ncutil.leaf_elm("name", "Ethernet0/1"))
        listval.append(ncutil.leaf_elm("shutdown", "false"))
        listval.append(ncutil.leaf_elm("state", "down"))
        listval = ncutil.subelm(cont, "interface")
        listval.append(ncutil.leaf_elm("name", "FastEthernet1/0"))
        listval.append(ncutil.leaf_elm("shutdown", "false"))
        listval.append(ncutil.leaf_elm("state", "up"))
        listval = ncutil.subelm(cont, "interface")
        listval.append(ncutil.leaf_elm("name", "FastEthernet1/1"))
        listval.append(ncutil.leaf_elm("shutdown", "false"))
        listval.append(ncutil.leaf_elm("state", "down"))

        return ncutil.filter_results(rpc, data, filter_or_none)

    def rpc_get_config(self, session, rpc, source_elm, filter_or_none):  # pylint: disable=W0613
        assert source_elm is not None
        if source_elm.find("nc:running", namespaces=NSMAP) is None:
            # Really this should be a different error its a bad value for source not missing
            raise ncerror.MissingElementProtoError(rpc, ncutil.qname("nc:running"))

        data = ncutil.elm("data")
        cont = ncutil.subelm(data, "interfaces")
        listval = ncutil.subelm(cont, "interface")
        listval.append(ncutil.leaf_elm("name", "Ethernet0/0"))
        listval.append(ncutil.leaf_elm("shutdown", "true"))
        listval = ncutil.subelm(cont, "interface")
        listval.append(ncutil.leaf_elm("name", "Ethernet0/1"))
        listval.append(ncutil.leaf_elm("shutdown", "false"))
        listval = ncutil.subelm(cont, "interface")
        listval.append(ncutil.leaf_elm("name", "FastEthernet1/0"))
        listval.append(ncutil.leaf_elm("shutdown", "false"))
        listval = ncutil.subelm(cont, "interface")
        listval.append(ncutil.leaf_elm("name", "FastEthernet1/1"))
        listval.append(ncutil.leaf_elm("shutdown", "false"))
        # Missing from operational
        listval.append(ncutil.leaf_elm("name", "GigabitEthernet2/0"))
        listval.append(ncutil.leaf_elm("shutdown", "false"))

        return ncutil.filter_results(rpc, data, filter_or_none)

    #---------------------------------------------------------------------------
    # These definitions will change to include required parameters like get and
    # get-config
    #---------------------------------------------------------------------------

    # XXX The API WILL CHANGE consider unfinished
    def rpc_copy_config(self, unused_session, rpc, *unused_params):
        raise ncerror.OperationNotSupportedProtoError(rpc)

    # XXX The API WILL CHANGE consider unfinished
    def rpc_delete_config(self, unused_session, rpc, *unused_params):
        raise ncerror.OperationNotSupportedProtoError(rpc)

    # XXX The API WILL CHANGE consider unfinished
    def rpc_edit_config(self, unused_session, rpc, *unused_params):
        raise ncerror.OperationNotSupportedProtoError(rpc)

    # XXX The API WILL CHANGE consider unfinished
    def rpc_lock(self, unused_session, rpc, *unused_params):
        raise ncerror.OperationNotSupportedProtoError(rpc)

    # XXX The API WILL CHANGE consider unfinished
    def rpc_unlock(self, unused_session, rpc, *unused_params):
        raise ncerror.OperationNotSupportedProtoError(rpc)
Exemplo n.º 11
0
    def _handle_message(self, msg):
        '''
        'Handle a message, lock is already held
        '''
        if not self.session_open:
            return

        try:
            tree = etree.parse(io.BytesIO(msg.encode('utf-8')))
            if not tree:
                raise ncerror.SessionError(msg, "Invalid XML from client.")
        except etree.XMLSyntaxError:
            GlobalModule.EM_LOGGER.warning(
                "202010 Closing session due to malformed message")
            raise ncerror.SessionError(msg, "Invalid XML from client.")

        rpcs = tree.xpath("/nc:rpc", namespaces=NSMAP)
        if not rpcs:
            raise ncerror.SessionError(msg, "No rpc found")

        for rpc in rpcs:
            try:
                msg_id = rpc.get('message-id')
                if self.debug:
                    GlobalModule.EM_LOGGER.debug(
                        "%s: Received rpc message-id: %s", str(self), msg_id)
            except (TypeError, ValueError):
                raise ncerror.SessionError(
                    msg, "No valid message-id attribute found")

            try:
                rpc_method = rpc.getchildren()
                if len(rpc_method) != 1:
                    if self.debug:
                        GlobalModule.EM_LOGGER.debug("%s: Bad Msg: msg-id: %s",
                                                     str(self), msg_id)
                    raise ncerror.RPCSvrErrBadMsg(rpc)
                rpc_method = rpc_method[0]

                rpcname = rpc_method.tag.replace(qmap('nc'), "")
                params = rpc_method.getchildren()
                paramslen = len(params)

                if rpcname == "close-session":
                    if self.debug:
                        GlobalModule.EM_LOGGER.debug(
                            "%s: Received close-session msg-id: %s", str(self),
                            msg_id)
                    GlobalModule.EM_LOGGER.info("102007 Connection Closed: %s",
                                                str(self))
                    EmNetconfSessionDate.del_session_date(self.session_id)
                    self.send_rpc_reply(etree.Element("ok"), rpc)
                    self.close()
                    return
                elif rpcname == "kill-session":
                    if self.debug:
                        GlobalModule.EM_LOGGER.debug(
                            "%s: Received kill-session msg-id: %s", str(self),
                            msg_id)
                    self.send_rpc_reply(etree.Element("ok"), rpc)
                    self.close()
                    return
                elif rpcname == "get":

                    if paramslen > 1:
                        raise ncerror.RPCSvrErrBadMsg(rpc)
                    if params and not util.filter_tag_match(
                            params[0], "nc:filter"):
                        raise ncerror.RPCSvrUnknownElement(rpc, params[0])
                    if not params:
                        params = [None]
                elif rpcname == "get-config":

                    GlobalModule.EM_LOGGER.info("102004 Receiving get-config")

                    if paramslen > 2:
                        raise ncerror.RPCSvrErrBadMsg(rpc)
                    source_param = rpc_method.find("nc:source",
                                                   namespaces=NSMAP)
                    if source_param is None:
                        raise ncerror.RPCSvrMissingElement(
                            rpc, util.elm("nc:source"))
                    filter_param = None
                    if paramslen == 2:
                        filter_param = rpc_method.find("nc:filter",
                                                       namespaces=NSMAP)
                        if filter_param is None:
                            unknown_elm = params[
                                0] if params[0] != source_param else params[1]
                            raise ncerror.RPCSvrUnknownElement(
                                rpc, unknown_elm)
                    params = [source_param, filter_param]

                elif rpcname == "edit-config":
                    GlobalModule.EM_LOGGER.info("102008 Receiving edit-config")

                    if paramslen > 2:
                        raise ncerror.RPCSvrErrBadMsg(rpc)

                    target_param = rpc_method.find("nc:target",
                                                   namespaces=NSMAP)
                    if target_param is None:
                        raise ncerror.RPCSvrMissingElement(
                            rpc, util.elm("nc:target"))

                    config_param = None
                    if paramslen == 2:
                        config_param = rpc_method.find("nc:config",
                                                       namespaces=NSMAP)
                        if config_param is None:
                            unknown_elm = params[
                                0] if params[0] != config_param else params[1]
                            raise ncerror.RPCSvrUnknownElement(
                                rpc, unknown_elm)
                    params = [target_param, config_param]

                try:
                    rpcname = rpcname.rpartition("}")[-1]
                    method_name = "rpc_" + rpcname.replace('-', '_')
                    method = getattr(self.methods, method_name,
                                     self._rpc_not_implemented)
                    result, reply = method(self.session_id, rpc, *params)

                    if result is not True:
                        self.send_rpc_reply(reply, rpc)

                except NotImplementedError:
                    raise ncerror.RPCSvrErrNotImpl(rpc)
            except ncerror.RPCSvrErrBadMsg as msgerr:
                if self.new_framing:
                    self.send_message(msgerr.get_reply_msg())
                else:
                    GlobalModule.EM_LOGGER.warning(
                        "Closing 1.0 session due to malformed message")
                    raise ncerror.SessionError(msg, "Malformed message")
            except ncerror.RPCServerError as error:
                self.send_message(error.get_reply_msg())
            except Exception as exception:
                GlobalModule.EM_LOGGER.debug(traceback.format_exc())
                error = ncerror.RPCSvrException(rpc, exception)
                self.send_message(error.get_reply_msg())
Exemplo n.º 12
0
class NetconfServer(object):
    NCFILTER = qmap("nc") + "filter"

    def __init__(self,
                 device,
                 host_key,
                 ssh_port=830,
                 username=None,
                 password=None,
                 debug=False):
        #-----------------
        # Open the device
        #-----------------
        self.debug = debug

        host_key_path = os.path.expanduser(host_key)
        assert os.path.exists(host_key_path)

        idn = device.get_idn_data()

        # XXX Is this where we get the port count?
        assert idn[4] == "cal04" or idn[4] == "cal02"
        if idn[4] == "cal04":
            self.nports = 4
            self.is_tfm = False
        else:
            self.nports = 1
            self.is_tfm = True

        self.device = device
        self.device_lock = threading.Lock()

        #-----------------------
        # Start the server.
        #-----------------------

        self.controller = server.SSHUserPassController(username=username,
                                                       password=password)

        self.server = server.NetconfSSHServer(server_ctl=self.controller,
                                              port=ssh_port,
                                              host_key=host_key_path,
                                              server_methods=self,
                                              debug=debug)
        logger.info("Listening on port %d", self.server.port)

    def join(self):
        "Wait on server to terminate"
        self.server.join()

    def nc_append_capabilities(self, caps):
        ncutil.subelm(caps, "capability").text = NSMAP['j']

    def _run_device_method(self, rpc, method, *args, **kwargs):
        try:
            with self.device_lock:
                return method(*args, **kwargs)
        except jerror.OCMError as err:
            raise ncerror.RPCServerError(rpc,
                                         ncerror.RPCERR_TYPE_APPLICATION,
                                         ncerror.RPCERR_TAG_OPERATION_FAILED,
                                         message=str(err))
        except Exception as ex:
            raise ncerror.RPCServerError(rpc,
                                         ncerror.RPCERR_TYPE_APPLICATION,
                                         ncerror.RPCERR_TAG_OPERATION_FAILED,
                                         app_tag="unexpected-error",
                                         message=str(ex))

    def _rpc_param_get_frequency(self, rpc, params):
        for param in params:
            if ncutil.filter_tag_match("j:frequency", param.tag):
                break
        else:
            raise ncerror.RPCSvrMissingElement(rpc, ncutil.elm("j:frequency"))

        freq = param.strip()
        try:
            freq = int(freq.text)
            if not (190000 <= freq <= 198000):
                raise ncerror.RPCSvrBadElement(
                    rpc,
                    freq,
                    message="Frequency not in range [190000, 198000]")
        except ValueError:
            raise ncerror.RPCSvrBadElement(rpc,
                                           freq,
                                           message="Frequency not an integer")

    def _rpc_param_get_boolean(self, rpc, tag, default, params):
        for param in params:
            if ncutil.filter_tag_match(tag, param.tag):
                if param is None:
                    raise ncerror.RPCSvrBadElement(
                        rpc, param, message="invalid boolean value for " + tag)
                bval = param.text.strip().lower()
                if bval in ["false", "no", "0"]:
                    return False
                elif bval in ["true", "yes", "1"]:
                    return True
                raise ncerror.RPCSvrBadElement(
                    rpc, param, message="invalid boolean value for " + tag)
        if default is None:
            raise ncerror.RPCSvrMissingElement(rpc, ncutil.elm(tag))
        return default

    def rpc_activate(self, unused, rpc, *params):
        # Input values
        if params:
            raise ncerror.RPCSvrErrBadMsg(rpc)

        self._run_device_method(rpc, self.device.activate)
        return ncutil.elm("ok")

    def rpc_self_test(self, unused, rpc, *params):
        # Input values
        if params:
            raise ncerror.RPCSvrErrBadMsg(rpc)

        self._run_device_method(rpc, self.device.self_test)
        return ncutil.elm("ok")

    def rpc_reset(self, unused, rpc, *params):
        # Input values
        if params:
            raise ncerror.RPCSvrErrBadMsg(rpc)

        self._run_device_method(rpc, self.device.reset)
        return ncutil.elm("ok")

    def rpc_frequency_power(self, unused, rpc, *params):
        if len(params) > 1:
            # XXX need a function to look for unknown elements and raise exc for those.
            # XXX really need a better error for not handled params
            raise ncerror.RPCSvrInvalidValue(rpc, message="Too many parameter")

        freq = self._rpc_param_get_frequency(rpc, params)
        power = self._run_device_method(rpc, self.device.get_freq_power, freq)
        result = ncutil.elm("data")
        result.append(ncutil.leaf_elm("j:power", "{:.2f}".format(power.dBm)))
        return result

    def rpc_full_itu_scan(self, unused_session, rpc, *params):
        # No input values yet
        try:
            if len(params) > 2:
                raise ncerror.RPCSvrInvalidValue(rpc,
                                                 message="Too many parameters")
            # XXX Should be able to use "j:high-resolution" but it fails
            hires = self._rpc_param_get_boolean(rpc, "high-resolution", False,
                                                params)
            power_only = not self._rpc_param_get_boolean(
                rpc, "detect-presence", False, params)
            if power_only:
                points = self._run_device_method(
                    rpc, self.device.get_itu_power_scan, hires)
            else:
                points = self._run_device_method(rpc, self.device.get_itu_scan,
                                                 hires)

            result = ncutil.elm("data")
            for tup in points:
                ptelm = ncutil.subelm(result, "j:point")
                ptelm.append(ncutil.leaf_elm("j:frequency", tup[0]))
                if power_only:
                    ptelm.append(
                        ncutil.leaf_elm("j:power",
                                        "{:.2f}".format(tup[1].dBm)))
                else:
                    ptelm.append(
                        ncutil.leaf_elm("j:power",
                                        "{:.2f}".format(tup[2].dBm)))
                    ptelm.append(ncutil.leaf_elm("j:channel-presence", tup[1]))
            return result
        except jerror.OCMError as ocmerr:
            logger.error("Got OCM error in full itu scan: %s: %s", str(ocmerr),
                         traceback.format_exc())
        except Exception as err:
            logger.error("Got error in full itu scan: %s: %s", str(err),
                         traceback.format_exc())
            raise

    def _rpc_full_scan(self, method, rpc, *params):
        # No input values yet
        if params:
            logging.error("%s: _rpc_full_scan got unexpected params",
                          str(self))
            raise ncerror.RPCSvrErrBadMsg(rpc)

        rv = self._run_device_method(rpc, method)

        result = ncutil.elm("data")
        for port, points in rv:
            portelm = ncutil.elm("j:port")
            result.append(portelm)
            portelm.append(ncutil.leaf_elm("j:port-index", port))
            for freq, power in points:
                ptelm = ncutil.subelm(portelm, "j:point")
                ptelm.append(ncutil.leaf_elm("j:frequency", freq))
                ptelm.append(
                    ncutil.leaf_elm("j:power", "{:.2f}".format(power.dBm)))
        return result

    def rpc_full_scan(self, unused_session, rpc, *params):
        return self._rpc_full_scan(self.device.get_full_scan, rpc, *params)
        # No input values yet
        if params:
            raise ncerror.RPCSvrErrBadMsg(rpc)

    def rpc_full_125_scan(self, unused_session, rpc, *params):
        return self._rpc_full_scan(self.device.get_full_125_scan, rpc, *params)

    def rpc_get_config(self, unused_session, rpc, source_elm,
                       unused_filter_elm):
        assert source_elm is not None
        if source_elm.find("nc:running", namespaces=NSMAP) is None:
            raise ncerror.RPCSvrMissingElement(rpc, ncutil.elm("nc:running"))

        config = ncutil.elm("data")

        if self.is_tfm:
            profile_elm = ncutil.elm("j:scan-profile")
            config.append(profile_elm)
            profile_elm.append(
                ncutil.leaf_elm("j:channel-spacing",
                                self.device.get_channel_spacing()))
            profile_elm.append(
                ncutil.leaf_elm("j:frequency-start",
                                self.device.get_start_freq()))
            profile_elm.append(
                ncutil.leaf_elm("j:frequency-end",
                                self.device.get_stop_freq()))
        else:
            for idx in range(1, 17):
                profile_elm = ncutil.elm("j:channel-profile")
                config.append(profile_elm)
                profile_elm.append(ncutil.leaf_elm("j:profile-index", idx))

                channels = self.device.get_channel_profile(idx)
                for freqs, freqe in channels:
                    channel_elm = ncutil.subelm(profile_elm, "j:channel")
                    range_elm = ncutil.subelm(channel_elm, "j:range")
                    range_elm.append(
                        ncutil.leaf_elm("j:frequency-start", freqs))
                    range_elm.append(ncutil.leaf_elm("j:frequency-end", freqe))
        return config

    def rpc_get(self, unused_session, unused_rpc, filter_elm):
        data = ncutil.elm("data")

        get_data_methods = {
            ncutil.qname("j:ocm-type").text: self.device.get_device_type,
            ncutil.qname("j:oper-mode").text: self.device.get_oper_mode,
            ncutil.qname("j:ident-data").text: self.device.get_idn_string,
            ncutil.qname("j:device-info").text: self.device.get_module_info,
            ncutil.qname("j:application-version").text:
            self.device.get_app_version,
            ncutil.qname("j:temp").text: self.device.get_temp_int,
        }
        if not self.device.get_device_type().startswith("tf"):
            get_data_methods[ncutil.qname(
                "j:safe-version").text] = self.device.get_safe_version

        infonode = ncutil.elm("j:info")
        # infonode = etree.Element(ncutil.qname("j:info"), nsmap={ 'j': NSMAP['j'] })

        # Get filter children
        children = []
        if filter_elm is not None:
            children = filter_elm.getchildren(
            ) if filter_elm is not None else []

        def get_all_values():
            leaf_elms = []
            for key, valuef in get_data_methods.items():
                leaf_elms.append(ncutil.leaf_elm(key, valuef()))
            return leaf_elms

        # No filter children return info only
        if not children:
            ncutil.filter_leaf_values(None, infonode, get_all_values(), data)
            return data

        # Look for info filter.
        finfo = filter_elm.find("info") or filter_elm.find("j:info",
                                                           namespaces=NSMAP)
        if finfo is not None:
            children = finfo.getchildren()
            if not children:
                leaf_elms = get_all_values()
            else:
                leaf_elms = []
                for felm in children:
                    tag = felm.tag
                    if tag in get_data_methods:
                        leaf_elms.append(
                            ncutil.leaf_elm(tag, get_data_methods[tag]()))
                        rv = ncutil.filter_leaf_values(finfo, infonode,
                                                       leaf_elms, data)
                        # Some selector doesn't match return empty.
            if rv is False:
                logger.error("XXX returning False")
                return data

        return data
Exemplo n.º 13
0
 def _rpc_not_implemented(self, unused_session, rpc, *unused_params):
     if self.debug:
         msg_id = rpc.get(qmap("nc") + 'message-id')
         logger.debug("%s: Not Impl msg-id: %s", str(self), msg_id)
     raise ncerror.OperationNotSupportedProtoError(rpc)
Exemplo n.º 14
0
    def reader_handle_message(self, msg):
        """Handle a message, lock is already held"""
        print('stpe 1')
        print(msg)
        if not self.session_open:
            return

        # Any error with XML encoding here is going to cause a session close
        # Technically we should be able to return malformed message I think.
        try:
            tree = etree.parse(io.BytesIO(msg.encode('utf-8')))
            print('step 1.5')
            print(etree.tostring(tree, pretty_print=True))
            if not tree:
                raise ncerror.SessionError(msg, "Invalid XML from client.")
        except etree.XMLSyntaxError:
            logger.warning("Closing session due to malformed message")
            raise ncerror.SessionError(msg, "Invalid XML from client.")

        rpcs = tree.xpath("/nc:rpc", namespaces=NSMAP)
        print('step 2')
        print(rpcs)
        if not rpcs:
            raise ncerror.SessionError(msg, "No rpc found")

        for rpc in rpcs:
            try:
                msg_id = rpc.get('message-id')
                print('step 3')
                print(msg_id)
                if self.debug:
                    logger.debug("%s: Received rpc message-id: %s", str(self),
                                 msg_id)
            except (TypeError, ValueError):
                raise ncerror.SessionError(
                    msg, "No valid message-id attribute found")

            try:
                # Get the first child of rpc as the method name
                rpc_method = rpc.getchildren()
                print('step 4')
                print(rpc_method)

                if len(rpc_method) != 1:
                    if self.debug:
                        logger.debug("%s: Bad Msg: msg-id: %s", str(self),
                                     msg_id)
                    raise ncerror.RPCSvrErrBadMsg(rpc)
                rpc_method = rpc_method[0]
                print('step 5')
                print(rpc_method)

                rpcname = rpc_method.tag.replace(qmap('nc'), "")
                print('stpe 6')
                print(rpcname)
                params = rpc_method.getchildren()
                print('stpe 7')
                print(params)
                paramslen = len(params)

                if self.debug:
                    logger.debug("%s: RPC: %s: paramslen: %s", str(self),
                                 rpcname, str(paramslen))

                if rpcname == "close-session":
                    # XXX should be RPC-unlocking if need be
                    if self.debug:
                        logger.debug("%s: Received close-session msg-id: %s",
                                     str(self), msg_id)
                    self.send_rpc_reply(etree.Element("ok"), rpc)
                    self.close()
                    # XXX should we also call the user method if it exists?
                    return
                elif rpcname == "kill-session":
                    # XXX we are supposed to cleanly abort anything underway
                    if self.debug:
                        logger.debug("%s: Received kill-session msg-id: %s",
                                     str(self), msg_id)
                    self.send_rpc_reply(etree.Element("ok"), rpc)
                    self.close()
                    # XXX should we also call the user method if it exists?
                    return
                elif rpcname == "get":
                    # Validate GET parameters

                    if paramslen > 1:
                        # XXX need to specify all elements not known
                        raise ncerror.RPCSvrErrBadMsg(rpc)
                    if params and not util.filter_tag_match(
                            params[0], "nc:filter"):
                        raise ncerror.RPCSvrUnknownElement(rpc, params[0])
                    if not params:
                        params = [None]
                elif rpcname == "get-config":
                    # Validate GET-CONFIG parameters

                    # XXX verify that the source parameter is present
                    if paramslen > 2:
                        # XXX need to specify all elements not known
                        raise ncerror.RPCSvrErrBadMsg(rpc)
                    source_param = rpc_method.find("nc:source",
                                                   namespaces=NSMAP)
                    if source_param is None:
                        raise ncerror.RPCSvrMissingElement(
                            rpc, util.elm("nc:source"))
                    filter_param = None
                    if paramslen == 2:
                        filter_param = rpc_method.find("nc:filter",
                                                       namespaces=NSMAP)
                        if filter_param is None:
                            unknown_elm = params[
                                0] if params[0] != source_param else params[1]
                            raise ncerror.RPCSvrUnknownElement(
                                rpc, unknown_elm)
                    params = [source_param, filter_param]

                #------------------
                # Call the method.
                #------------------

                try:
                    # Handle any namespaces or prefixes in the tag, other than
                    # "nc" which was removed above. Of course, this does not handle
                    # namespace collisions, but that seems reasonable for now.
                    rpcname = rpcname.rpartition("}")[-1]
                    print('step 8')
                    print(rpcname)
                    method_name = "rpc_" + rpcname.replace('-', '_')
                    method = getattr(self.methods, method_name,
                                     self._rpc_not_implemented)
                    if self.debug:
                        logger.debug("%s: Calling method: %s", str(self),
                                     method_name)
                    reply = method(self, rpc, *params)
                    print('stpe 9')
                    print(reply)
                    self.send_rpc_reply(reply, rpc)
                except NotImplementedError:
                    raise ncerror.RPCSvrErrNotImpl(rpc)
            except ncerror.RPCSvrErrBadMsg as msgerr:
                if self.new_framing:
                    if self.debug:
                        logger.debug("%s: RPCSvrErrBadMsg: %s", str(self),
                                     str(msgerr))
                    self.send_message(msgerr.get_reply_msg())
                else:
                    # If we are 1.0 we have to simply close the connection
                    # as we are not allowed to send this error
                    logger.warning(
                        "Closing 1.0 session due to malformed message")
                    raise ncerror.SessionError(msg, "Malformed message")
            except ncerror.RPCServerError as error:
                if self.debug:
                    logger.debug("%s: RPCServerError: %s", str(self),
                                 str(error))
                self.send_message(error.get_reply_msg())
            except EOFError:
                if self.debug:
                    logger.debug("%s: Got EOF in reader_handle_message",
                                 str(self))
                error = ncerror.RPCSvrException(rpc, EOFError("EOF"))
                self.send_message(error.get_reply_msg())
            except EOFError:
                if self.debug:
                    logger.debug("Got EOF in reader_handle_message")
            except Exception as exception:
                if self.debug:
                    logger.debug(
                        "%s: Got unexpected exception in reader_handle_message: %s",
                        str(self), str(exception))
                error = ncerror.RPCSvrException(rpc, exception)
                self.send_message(error.get_reply_msg())
Exemplo n.º 15
0
    def _reader_handle_message(self, msg):
        """This function is called from the session reader thread to process a received
        framed netconf message.
        """
        try:
            tree = etree.parse(io.BytesIO(msg.encode('utf-8')))
            if not tree:
                raise SessionError(msg, "Invalid XML from server.")
        except etree.XMLSyntaxError:
            raise SessionError(msg, "Invalid XML from server.")

        replies = tree.xpath("/nc:rpc-reply", namespaces=NSMAP)
        tmp_NS = {'tmp': 'urn:ietf:params:xml:ns:netconf:notification:1.0'}
        notifications = tree.xpath("/tmp:notification", namespaces=tmp_NS)
        if not replies and not notifications:
            raise SessionError(msg, "No rpc-reply found")

        for reply in replies:
            try:
                msg_id = int(reply.get(qmap("nc") + 'message-id'))
            except (TypeError, ValueError):
                try:
                    # Deal with servers not properly setting attribute namespace.
                    msg_id = int(reply.get('message-id'))
                except (TypeError, ValueError):
                    # # Cisco is returning errors without message-id attribute which
                    # # is non-rfc-conforming it is doing this for any malformed XML
                    # # not simply missing message-id attribute.
                    # error = reply.xpath("nc:rpc-error", namespaces=self.nsmap)
                    # if error:
                    #     raise RPCError(received, tree, error[0])
                    raise SessionError(msg,
                                       "No valid message-id attribute found")

            # Queue the message
            with self.cv:
                try:
                    if msg_id not in self.rpc_out:
                        if self.debug:
                            logger.debug(
                                "Ignoring unwanted reply for message-id %s",
                                str(msg_id))
                        return
                    elif self.rpc_out[msg_id] is not None:
                        logger.warning(
                            "Received multiple replies for message-id %s:"
                            " before: %s now: %s", str(msg_id),
                            str(self.rpc_out[msg_id]), str(msg))

                    if self.debug:
                        logger.debug("%s: Received rpc-reply message-id: %s",
                                     str(self), str(msg_id))
                    self.rpc_out[msg_id] = tree, reply, msg
                except Exception as error:
                    logger.debug("%s: Unexpected exception: %s", str(self),
                                 str(error))
                    raise
                finally:
                    self.cv.notify_all()

        for notif in notifications:
            push_update_node = notif.find("yp:push-update", namespaces=NSMAP)
            id_node = push_update_node.find("tmp:id", namespaces=tmp_NS)
            subscription_id = int(id_node.text)

            with self.notification_queues_lock:
                if subscription_id not in self.notification_queues:
                    tmp_queue = self.tmp_notification_queues.get(
                        subscription_id, Queue())
                    tmp_queue.put(notif)
                    self.tmp_notification_queues[subscription_id] = tmp_queue
                else:
                    self.notification_queues[subscription_id].put(notif)
Exemplo n.º 16
0
def subtree_filter(data, rpc):

    # Aqui estan los distintos componentes de la base de datos
    for filter_item in rpc.iter(qmap('nc') + 'filter'):
        filter_tree = filter_item

    unprunned_toreturn = data
    filter_elm = filter_tree

    logging.info(etree.tostring(unprunned_toreturn, pretty_print=True))
    logging.info(etree.tostring(filter_elm, pretty_print=True))

    def check_content_match(data):
        response = False
        for child in data:
            if not (child.text == '' or child.text is None):
                response = True
        return response

    def prune_descendants(data, filter):
        logging.info("The child " + filter.tag + " is a content match: " +
                     str(check_content_match(filter)))
        if check_content_match(filter):

            # logging.info("Elements of the content match: ------------------")
            # logging.info(etree.tostring(data,pretty_print=True))
            # logging.info(etree.tostring(filter, pretty_print=True))

            #find content match element
            for child in filter:
                if not (child.text is '' or child.text is None):
                    matching_elem = child
            # logging.info("Looking for the element " + matching_elem.tag + " , " + matching_elem.text)

            # Checking if the current elem matches the seached one
            if data.find(matching_elem.tag) is not None and data.find(
                    matching_elem.tag).text == matching_elem.text:
                # logging.info("This element matches")
                #logging.info(etree.tostring(data,pretty_print=True))
                #logging.info(etree.tostring(filter, pretty_print=True))
                if len(list(filter)) > 1:
                    matching_elem.text = ''
                    logging.info("Containment nodes inside")
                    logging.info(etree.tostring(data, pretty_print=True))
                    logging.info(etree.tostring(filter, pretty_print=True))
                    prune_descendants(data, filter)
            else:
                # logging.info("This element doesnt match")
                data.getparent().remove(data)

        else:
            for child in data:

                if len(list(filter)) is not 0:
                    if filter.find(child.tag) is not None:
                        logging.info("Element " + child.tag +
                                     " found in data, so persisting it")
                        prune_descendants(child, filter[0])

                    else:
                        logging.info("Element " + child.tag +
                                     " missing in data, deleting it")
                        data.remove(child)

    prune_descendants(unprunned_toreturn, filter_elm)

    #logging.info(etree.tostring(unprunned_toreturn,pretty_print=True))

    return unprunned_toreturn