def _process_set(self, req_rec, req): """Process an incoming Set and generate a SetResp""" resp_rec = usp_record.Record() resp = usp.Msg() path_to_set_dict = {} update_obj_result_list = [] set_failure_param_err_list = [] # Populate the Response's Header information self._populate_resp_header(req_rec, req, resp_rec, resp, usp.Header.SET_RESP) # Validate the Set Request and populate the dictionaries and lists appropriately self._validate_set(req, path_to_set_dict, update_obj_result_list, set_failure_param_err_list) # Finished with all validation, process the errors or make the updates if len(set_failure_param_err_list) > 0: usp_err_msg = utils.UspErrMsg(req.header.msg_id, req_rec.from_id, self._id) err_msg = "Invalid Path Found, Allow Partial Updates = False :: Fail the entire Set" resp_rec, resp = usp_err_msg.generate_error(9000, err_msg) resp.body.error.param_errs.extend(set_failure_param_err_list) else: # Process the Updates against the database for param_path in path_to_set_dict: self._db.update(param_path, path_to_set_dict[param_path]) resp.body.response.set_resp.updated_obj_results.extend( update_obj_result_list) return resp_rec, resp
def __init__(self, msg_id, to_id, from_id): """Initialize the USP Message Header""" self._msg_id = msg_id self._to_id = to_id self._from_id = from_id self._msg = usp.Msg() self._rec = usp_record.Record()
def _process_get(self, req_rec, req): """Process an incoming Get and generate a GetResp""" resp_rec = usp_record.Record() resp = usp.Msg() path_result_list = [] self._logger.info("Processing a Get Request...") # Populate the Response's Header information self._populate_resp_header(req_rec, req, resp_rec, resp, usp.Header.GET_RESP) # Process the Parameter Paths in the Get Request for req_path in req.body.request.get.param_paths: path_result = usp.GetResp.RequestedPathResult() path_result.requested_path = req_path try: resolved_path_list = [] partial_path, param_name = self._split_path(req_path) self._logger.debug("Split into [%s] and [%s]", partial_path, param_name) affected_path_list = self._get_affected_paths_for_get( partial_path) for affected_path in affected_path_list: self._logger.debug("Requested Path [%s] resolved to: %s", req_path, affected_path) resolved_path_result = usp.GetResp.ResolvedPathResult() resolved_path_result.resolved_path = affected_path if param_name is None: items = self._db.find_params(affected_path) for item in items: param_path = self._diff_paths(affected_path, item) resolved_path_result.result_params[ param_path] = str(self._db.get(item)) else: param = affected_path + param_name resolved_path_result.result_params[param_name] = str( self._db.get(param)) resolved_path_list.append(resolved_path_result) path_result.resolved_path_results.extend(resolved_path_list) except agent_db.NoSuchPathError: self._logger.warning("Invalid Path encountered: %s", req_path) path_result.err_code = 11002 path_result.err_msg = "Invalid Path: " + req_path + " is not a part of the supported data model" path_result_list.append(path_result) resp.body.response.get_resp.req_path_results.extend(path_result_list) return resp_rec, resp
def generate_notif_msg(self): """Generate an appropriate USP Notification""" rec = usp_record.Record() notif = usp.Msg() self._init_notif(rec, notif) notif.body.request.notify.event.obj_path = "Device.LocalAgent." notif.body.request.notify.event.event_name = "Periodic!" rec.no_session_context.payload = notif.SerializeToString() return rec, notif
def generate_notif_msg(self): """Generate an appropriate USP Notification""" rec = usp_record.Record() notif = usp.Msg() self._init_notif(rec, notif) notif.body.request.notify.value_change.param_path = self._param notif.body.request.notify.value_change.param_value = str(self._value) rec.no_session_context.payload = notif.SerializeToString() return rec, notif
def wrap_notif_in_record(self, notif_msg): """Wrap the Notification USP Message in a USP Record""" notif_record = usp_record.Record() notif_record.version = "1.0" notif_record.to_id = self._to_id notif_record.from_id = self._from_id notif_record.payload_security = usp_record.Record.PLAINTEXT notif_record.no_session_context.payload = notif_msg.SerializeToString() return notif_record
def _handle_usp_record(self, msg_payload): """Deserialize the USP Record in the Incoming Request""" req_as_record = usp_record.Record() # De-Serialize the payload into a USP Record req_as_record.ParseFromString(msg_payload) self._logger.debug("Incoming payload parsed as a USP Record via Protocol Buffers") if self._debug: debug_msg = "Incoming USP Record:\n{}".format(req_as_record) self._logger.debug("%s", debug_msg) return req_as_record
def _process_operation(self, req_rec, req): """Process an incoming Operate and generate a OperateResp""" resp_rec = usp_record.Record() resp = usp.Msg() op_result_list = [] command = req.body.request.operate.command product_class = self._db.get("Device.DeviceInfo.ProductClass") self._logger.info("Processing an Operate Request...") #TODO: This is hard-coded for the Camera, but needs to be dynamic # Populate the Response's Header information self._populate_resp_header(req_rec, req, resp_rec, resp, usp.Header.OPERATE_RESP) if product_class == "RPi_Camera" or product_class == "RPiZero_Camera": # Validate that the Operate.command is supported if command == TAKE_PICTURE_CAMERA_OP: op_result = usp.OperateResp.OperationResult() op_result.executed_command = req.body.request.operate.command out_arg_map = op_result.req_output_args.output_args camera = self._service_map[product_class] param_map = camera.take_picture() for param in param_map: out_arg_map[param] = param_map[param] op_result_list.append(op_result) resp.body.response.operate_resp.operation_results.extend( op_result_list) else: # Invalid Command - return an Error to_id = req_rec.from_id err_msg = "Operate Failure: invalid command - {}".format( command) usp_err_msg = utils.UspErrMsg(req.header.msg_id, to_id, self._id) resp_rec, resp = usp_err_msg.generate_error(9000, err_msg) else: # Unknown agent product class - return an Error to_id = req_rec.from_id err_msg = "Operate Failure: unknown product class - {}".format( product_class) usp_err_msg = utils.UspErrMsg(req.header.msg_id, to_id, self._id) resp_rec, resp = usp_err_msg.generate_error(9000, err_msg) return resp_rec, resp
def generate_notif_msg(self): """Generate an appropriate USP Notification""" map_as_str = "" rec = usp_record.Record() notif = usp.Msg() first_entry = True self._init_notif(rec, notif) # TODO: Replace hard-coded list with data model driven list boot_param_list = ["Device.DeviceInfo.ManufacturerOUI", "Device.DeviceInfo.ProductClass", "Device.DeviceInfo.SerialNumber", "Device.LocalAgent.X_ARRIS-COM_IPAddr"] notif.body.request.notify.event.obj_path = "Device.LocalAgent." notif.body.request.notify.event.event_name = "Boot!" notif.body.request.notify.event.params["CommandKey"] = "" notif.body.request.notify.event.params["Cause"] = "LocalReboot" for path in boot_param_list: value = self._db.get(path) if first_entry: first_entry = False else: map_as_str += "," map_as_str += "\"" + path + "\"" map_as_str += " : " if value is not None: map_as_str += "\"" + str(value) + "\"" else: map_as_str += "\"\"" self._logger.warning("Boot Param [%s] is None", path) notif.body.request.notify.event.params["BootParameterMap"] = map_as_str rec.no_session_context.payload = notif.SerializeToString() return rec, notif
def _process_get_supported_protocol(self, req_rec, req): """Process an incoming GetSupportedProtocol and generate a GetSupportedProtocolResp""" resp_rec = usp_record.Record() resp = usp.Msg() self._logger.info("Processing a GetSupportedProtocol Request...") # Populate the Response's Header information self._populate_resp_header(req_rec, req, resp_rec, resp, usp.Header.GET_SUPPORTED_PROTO_RESP) # Process the supported versions in the GetSupportedProtocol Request if not ("1.0" in req.body.request.get_supported_protocol. controller_supported_protocol_versions.split(",")): to_id = req_rec.from_id err_msg = "GetSupportedProtocol Failure: incompatible versions" usp_err_msg = utils.UspErrMsg(req.header.msg_id, to_id, self._id) resp_rec, resp = usp_err_msg.generate_error(9000, err_msg) return resp_rec, resp resp.body.response.get_supported_protocol_resp.agent_supported_protocol_versions = "1.0" return resp_rec, resp
def _process_request(self, req_as_record, req_as_msg): """Processing the incoming Message and return a Response""" to_id = req_as_record.from_id resp_record = usp_record.Record() err_msg = "Message Failure: Request body does not match Header msg_type" usp_err_msg = utils.UspErrMsg(req_as_msg.header.msg_id) resp_msg = usp_err_msg.generate_error(9000, err_msg) if req_as_msg.header.msg_type == usp_msg.Header.GET: # Validate that the Request body matches the Header's msg_type if req_as_msg.body.request.WhichOneof("req_type") == "get": NUM_GET_MSGS_METRIC.inc() resp_msg = self._process_get(req_as_msg) elif req_as_msg.header.msg_type == usp_msg.Header.SET: # Validate that the Request body matches the Header's msg_type if req_as_msg.body.request.WhichOneof("req_type") == "set": NUM_SET_MSGS_METRIC.inc() resp_msg = self._process_set(req_as_msg) elif req_as_msg.header.msg_type == usp_msg.Header.OPERATE: # Validate that the Request body matches the Header's msg_type if req_as_msg.body.request.WhichOneof("req_type") == "operate": NUM_OPERATE_MSGS_METRIC.inc() resp_msg = self._process_operation(req_as_msg) else: err_msg = "Invalid USP Message: unknown command" resp_msg = usp_err_msg.generate_error(9000, err_msg) NUM_UNKNOWN_MSGS_METRIC.inc() # Wrap the USP Message response into a USP Record resp_record.version = "1.0" resp_record.to_id = to_id resp_record.from_id = self._id resp_record.payload_security = usp_record.Record.PLAINTEXT resp_record.no_session_context.payload = resp_msg.SerializeToString() return resp_msg, resp_record
def handle_request(self, record_payload): """Handle a Request/Response interaction""" req_rec = usp_record.Record() # De-Serialize the record req_rec.ParseFromString(record_payload) req = usp.Msg() # De-Serialize the payload req.ParseFromString(req_rec.no_session_context.payload) self._logger.debug("Incoming payload parsed via Protocol Buffers") if self._debug: print("Incoming Record:\n{}".format(req_rec)) print("Incoming Request:\n{}".format(req)) try: # Validate the payload before processing it self._validate_request(req_rec, req) self._logger.info("Received a [%s] Request", req.body.request.WhichOneof("req_type")) resp_rec, resp = self._process_request(req_rec, req) if self._debug: print("Outgoing Record:\n{}".format(resp_rec)) print("Outgoing Response:\n{}".format(resp)) except ProtocolValidationError as err: err_msg = "USP Message validation failed: {}".format(err) self._logger.error("%s", err_msg) raise ProtocolViolationError(err_msg) resp_rec.no_session_context.payload = resp.SerializeToString() return req_rec, req, resp_rec, resp, resp_rec.SerializeToString()