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)
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
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
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)
def _reader_handle_message(self, 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'))) 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.MalformedMessageRPCError(rpc) rpc_method = rpc_method[0] rpcname = rpc_method.tag.replace(qmap('nc'), "") params = rpc_method.getchildren() 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.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] #------------------ # 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) 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 NotImplementedError: raise ncerror.OperationNotSupportedProtoError(rpc) 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)