Esempio n. 1
0
    def add_in_data(self,
                    data,
                    data_hash=None,
                    encrypted_data_encryption_key=None,
                    data_iv=None):
        """Add inData work order parameter."""
        if data is None:
            return util.create_error_response(
                WorkOrderStatus.INVALID_PARAMETER_FORMAT_OR_VALUE, 0,
                "Invalid data format for in data")

        in_data_copy = self.params_obj["inData"]
        new_data_list = self.__add_data_params(in_data_copy, data, data_hash,
                                               encrypted_data_encryption_key,
                                               data_iv)

        self.params_obj["inData"] = new_data_list

        code, err_msg = WOcheck.schema_validation("sdk_inData",
                                                  self.params_obj["inData"])
        if not code:
            return util.create_error_response(
                WorkOrderStatus.INVALID_PARAMETER_FORMAT_OR_VALUE, 0, err_msg)

        return None
Esempio n. 2
0
    def _process_request(self, input_json_str):
        """
        Handles incoming requests or rather dispatches to appropriate
        rpc method

        Parameters :
            input_json_str - JSON formatted str of the request
        Returns :
            response - data field from the response received which is a dict
        """
        response = {}
        response['error'] = {}
        response['error']['code'] = \
            JRPCErrorCodes.INVALID_PARAMETER_FORMAT_OR_VALUE

        try:
            input_json = json.loads(input_json_str)
            valid, err_msg = \
                Validator.schema_validation("tc_methods", input_json)
            if not valid:
                raise ValueError(err_msg)
            valid, err_msg = \
                Validator.schema_validation(
                    input_json["method"],
                    input_json["params"])
            if not valid:
                raise ValueError(err_msg)
        except Exception as err:
            logger.error("Exception while processing Json: %s", str(err))
            response["error"]["message"] = \
                "{}".format(str(err))
            return response

        # save the full json for WorkOrderSubmit
        input_json["params"]["raw"] = input_json_str
        data = json.dumps(input_json).encode('utf-8')
        response = JSONRPCResponseManager.handle(data, self.dispatcher)
        return response.data
 def WorkerLookUpNext(self, **params):
     """
     Function to look the set of worker newly added
     Parameters:
         - param is the 'param' object in the a worker request as per TCF
             API 5.3.5 Worker Lookup Next JSON Payload
     """
     input_json_str = params["raw"]
     input_value_json = json.loads(input_json_str)
     valid, err_msg = \
         Validator.schema_validation(
             "WorkerLookUpNext",
             input_value_json["params"])
     if not valid:
         raise JSONRPCDispatchException(
             WorkerError.INVALID_PARAMETER_FORMAT_OR_VALUE, err_msg)
     return self.__lookup_basic(True, params)
    def WorkerRetrieve(self, **params):
        """
        Function to retrieve the details of worker
        Parameters:
            - param is the 'param' object in the a worker request as per
                Trusted Compute EEA API 5.3.7 Worker Retrieve JSON Payload
        """

        input_json_str = params["raw"]
        input_value_json = json.loads(input_json_str)
        valid, err_msg = \
            Validator.schema_validation(
                "WorkerRetrieve",
                input_value_json["params"])
        if not valid:
            raise JSONRPCDispatchException(
                WorkerError.INVALID_PARAMETER_FORMAT_OR_VALUE, err_msg)
        # value retrieved is 'result' field as per Spec 5.3.8 Worker Retrieve
        # Response Payload
        worker_id = str(params['workerId'])
        value = self.kv_helper.get("workers", worker_id)

        if value is None:
            raise JSONRPCDispatchException(
                WorkerError.INVALID_PARAMETER_FORMAT_OR_VALUE,
                "Worker Id not found in the database. Hence invalid parameter")

        json_dict = json.loads(value)

        result = {
            "workerType": json_dict["workerType"],
            "organizationId": json_dict["organizationId"],
            "applicationTypeId": json_dict["applicationTypeId"],
            "details": json_dict["details"],
            "status": json_dict["status"],
        }

        return result
    def WorkOrderSubmit(self, **params):
        """
        Function to process work order request
        Parameters:
            - params is variable-length argument list containing work request
              as defined in EEA spec 6.1.1
        Returns jrpc response as defined in EEA spec 6.1.3
        """
        wo_id = params["workOrderId"]
        input_json_str = params["raw"]
        input_value_json = json.loads(input_json_str)

        # Work order status payload should have
        # data filed with work order id as defined in EEA spec section 6.
        data = {"workOrderId": wo_id}
        valid, err_msg = \
            Validator.schema_validation(
                "WorkOrderSubmit",
                input_value_json["params"])
        if not valid:
            raise JSONRPCDispatchException(JsonRpcErrorCode.INVALID_PARAMETER,
                                           err_msg, data)

        worker_id = input_value_json["params"]["workerId"]
        # Check if workerId is exists in avalon
        if not self._is_worker_exists(worker_id):
            raise JSONRPCDispatchException(
                JsonRpcErrorCode.INVALID_PARAMETER,
                "worker {} doesn't exists".format(worker_id), data)
        if ((self.workorder_count + 1) > self.max_workorder_count):

            # wo_ids is a csv of work order ids retrieved from database
            wo_ids = self.kv_helper.get("wo-worker-processed", worker_id)
            processed_wo_ids = [] if wo_ids is None else wo_ids.split(",")

            # if max count reached clear a processed entry
            work_orders = self.kv_helper.lookup("wo-timestamps")
            for id in work_orders:
                # If work order is processed then remove from table
                if id in processed_wo_ids:
                    self.kv_helper.csv_search_delete("wo-worker-processed",
                                                     worker_id, id)
                    self.kv_helper.remove("wo-requests", id)
                    self.kv_helper.remove("wo-responses", id)
                    self.kv_helper.remove("wo-receipts", id)
                    self.kv_helper.remove("wo-timestamps", id)

                    self.workorder_list.remove(id)
                    self.workorder_count -= 1
                    break

            # If no work order is processed then return busy
            if ((self.workorder_count + 1) > self.max_workorder_count):
                raise JSONRPCDispatchException(
                    WorkOrderStatus.BUSY,
                    "Work order handler is busy updating the result", data)

        if (self.kv_helper.get("wo-timestamps", wo_id) is None):
            # Create a new work order entry.
            # Don't change the order of table updates.
            # The order is important for clean up if the TCS is restarted in
            # the middle.
            # Add entry to wo-worker-scheduled which holds all the work order
            # id separated by comma(csv) to be processed by corresponding
            # worker. i.e. - <worker_id> -> <wo_id>,<wo_id>,<wo_id>...
            epoch_time = str(time.time())

            # Update the tables
            self.kv_helper.set("wo-timestamps", wo_id, epoch_time)
            self.kv_helper.set("wo-requests", wo_id, input_json_str)
            self.kv_helper.csv_append("wo-worker-scheduled", worker_id, wo_id)
            # Add to the internal FIFO
            self.workorder_list.append(wo_id)
            self.workorder_count += 1
            # ZeroMQ for sync workorder processing
            try:
                socket = context.socket(zmq.REQ)
                socket.connect(self.zmq_url)
                socket.send_string(wo_id, flags=0, encoding='utf-8')
                replymessage = socket.recv()
                logger.info(replymessage)
                socket.disconnect(self.zmq_url)
            except Exception as er:
                raise JSONRPCDispatchException(
                    WorkOrderStatus.UNKNOWN_ERROR,
                    "Failed to connect with enclave-manager socket: " + er,
                    data)
            # Work order is processed. Fetch result from wo-response table
            value = self.kv_helper.get("wo-responses", wo_id)
            if value:
                response = json.loads(value)
                if 'result' in response:
                    return response['result']

                # response without result should have an error
                # return error
                err_code = response["error"]["code"]
                err_msg = response["error"]["message"]
                if err_code == EnclaveError.ENCLAVE_ERR_VALUE:
                    err_code = \
                            WorkOrderStatus.INVALID_PARAMETER_FORMAT_OR_VALUE
                elif err_code == EnclaveError.ENCLAVE_ERR_UNKNOWN:
                    err_code = WorkOrderStatus.UNKNOWN_ERROR
                else:
                    err_code = WorkOrderStatus.FAILED
                raise JSONRPCDispatchException(err_code, err_msg, data)
        else:
            # Workorder id already exists
            raise JSONRPCDispatchException(
                WorkOrderStatus.INVALID_PARAMETER_FORMAT_OR_VALUE,
                "Work order id already exists in the database. \
                Hence invalid parameter", data)
Esempio n. 6
0
    def create_request(self,
                       work_order_id,
                       worker_id,
                       workload_id,
                       requester_id,
                       session_key,
                       session_iv,
                       requester_nonce,
                       verifying_key=None,
                       payload_format="JSON-RPC",
                       response_timeout_msecs=6000,
                       result_uri=None,
                       notify_uri=None,
                       worker_encryption_key=None,
                       data_encryption_algorithm=None,
                       encrypted_session_key=None):
        """validate and creates workorder request with received values"""
        if work_order_id:
            self.set_work_order_id(work_order_id)
        self.set_response_timeout_msecs(response_timeout_msecs)
        self.set_payload_format(payload_format)
        self.set_requester_nonce(requester_nonce)
        self.session_key = session_key
        self.set_workload_id(workload_id)
        self.set_worker_id(worker_id)
        if requester_id is not None:
            self.set_requester_id(requester_id)
        if session_iv:
            self.set_session_key_iv(
                crypto_utility.byte_array_to_hex(session_iv))
        if result_uri:
            self.set_result_uri(result_uri)
        if notify_uri:
            self.set_notify_uri(notify_uri)
        if worker_encryption_key:
            self.set_worker_encryption_key(worker_encryption_key)
        if data_encryption_algorithm:
            self.set_data_encryption_algorithm(data_encryption_algorithm)

        self.set_encrypted_session_key(encrypted_session_key)

        code, err_msg = WOcheck.schema_validation("sdk_WorkOrderSubmit",
                                                  self.params_obj)

        # When the WorkorderSubmit request fails basic Json Validation
        # the init object created is deleted to avoid futhur processing
        # on that object by the user.
        if not code:
            return util.create_error_response(
                WorkOrderStatus.INVALID_PARAMETER_FORMAT_OR_VALUE, 0, err_msg)

        self.set_worker_encryption_key(
            worker_encryption_key.encode("UTF-8").hex())

        self.session_iv = session_iv
        self.params_obj["encryptedRequestHash"] = ""
        self.params_obj["requesterSignature"] = ""
        self.params_obj["inData"] = list()
        if encrypted_session_key is None:
            try:
                encrypted_session_key = crypto_utility.generate_encrypted_key(
                    session_key, worker_encryption_key)
                self.set_encrypted_session_key(
                    crypto_utility.byte_array_to_hex(encrypted_session_key))
            except Exception as err:
                return util.create_error_response(
                    WorkOrderStatus.INVALID_PARAMETER_FORMAT_OR_VALUE, 0, err)
        return None
Esempio n. 7
0
    def WorkOrderSubmit(self, **params):
        """
        Function to process work order request
        Parameters:
            - params is variable-length argument list containing work request
              as defined in EEA spec 6.1.1
        Returns jrpc response as defined in EEA spec 6.1.3
        """
        wo_id = params["workOrderId"]
        input_json_str = params["raw"]
        input_value_json = json.loads(input_json_str)
        # Work order status payload should have
        # data filed with work order id as defined in EEA spec section 6.
        data = {"workOrderId": wo_id}
        valid, err_msg = \
            Validator.schema_validation(
                "WorkOrderSubmit",
                input_value_json["params"])
        if not valid:
            raise JSONRPCDispatchException(JsonRpcErrorCode.INVALID_PARAMETER,
                                           err_msg, data)

        worker_id = input_value_json["params"]["workerId"]

        # Check if workerId is exists in avalon
        if not self._is_worker_exists(worker_id):
            raise JSONRPCDispatchException(
                JsonRpcErrorCode.INVALID_PARAMETER,
                "worker {} doesn't exists".format(worker_id), data)
        if "requesterSignature" in params:
            try:
                decoded_str = base64.b64decode(params["requesterSignature"],
                                               validate=True)
            except Exception:
                raise JSONRPCDispatchException(
                    JsonRpcErrorCode.INVALID_PARAMETER,
                    "Invalid data format for requesterSignature", data)
        if ((self.workorder_count + 1) > self.max_workorder_count):
            # Lookup all workers.
            workers = self.kv_helper.lookup("worker-pool")
            wo_worker_map = dict()
            processed_wo_ids = []
            for worker in workers:
                # wo_ids_csv is a csv of work order ids retrieved from database
                wo_ids_csv = self.kv_helper.get("wo-worker-processed", worker)
                wo_ids = [] if wo_ids_csv is None else wo_ids_csv.split(",")
                # Create a reverse map for search delete in wo-worker-processed
                for w in wo_ids:
                    wo_worker_map[w] = worker
                processed_wo_ids.extend(wo_ids)

            # if max count reached clear a processed entry
            work_orders = self.kv_helper.lookup("wo-timestamps")
            for id in work_orders:
                # If work order is processed then remove from table
                if id in processed_wo_ids:
                    self.kv_helper.csv_search_delete("wo-worker-processed",
                                                     wo_worker_map[id], id)
                    self.kv_helper.remove("wo-requests", id)
                    self.kv_helper.remove("wo-responses", id)
                    self.kv_helper.remove("wo-receipts", id)
                    self.kv_helper.remove("wo-timestamps", id)

                    self.workorder_list.remove(id)
                    logger.info(
                        "Purged work order {} from database".format(id))
                    self.workorder_count -= 1
                    # @TODO : Need to rethink if deleting just one entry
                    # suffices as the operations performed are costly
                    break

            # If no work order is processed then return busy
            if ((self.workorder_count + 1) > self.max_workorder_count):
                raise JSONRPCDispatchException(
                    WorkOrderStatus.BUSY,
                    "Work order handler is busy updating the result", data)

        if (self.kv_helper.get("wo-timestamps", wo_id) is None):

            # Create a new work order entry.
            # Don't change the order of table updation.
            # The order is important for clean up if the TCS is restarted in
            # the middle.
            # Add entry to wo-worker-scheduled which holds all the work order
            # id separated by comma(csv) to be processed by corresponding
            # worker. i.e. - <worker_id> -> <wo_id>,<wo_id>,<wo_id>...
            epoch_time = str(time.time())

            # Update the tables
            self.kv_helper.set("wo-timestamps", wo_id, epoch_time)
            self.kv_helper.set("wo-requests", wo_id, input_json_str)
            self.kv_helper.csv_append("wo-worker-scheduled", worker_id, wo_id)
            # Add to the internal FIFO
            self.workorder_list.append(wo_id)
            self.workorder_count += 1
            raise JSONRPCDispatchException(
                WorkOrderStatus.PENDING,
                "Work order is computing. Please query for WorkOrderGetResult"
                + " to view the result", data)

        # Workorder id already exists
        raise JSONRPCDispatchException(
            WorkOrderStatus.INVALID_PARAMETER_FORMAT_OR_VALUE,
            "Work order id already exists in the database. " +
            "Hence invalid parameter", data)
Esempio n. 8
0
    def WorkOrderGetResult(self, **params):
        """
        Function to process work order get result.
        This API corresponds to Trusted Compute EEA API 6.1.4
        Work Order Pull Request Payload
        Parameters:
            - params is variable-length argument list containing work request
              as defined in EEA spec 6.1.4
        Returns jrpc response as defined in EEA spec 6.1.2
        """

        input_json_str = params["raw"]
        input_value_json = json.loads(input_json_str)
        valid, err_msg = \
            Validator.schema_validation(
                "WorkOrderGetResult",
                input_value_json["params"])
        if not valid:
            raise JSONRPCDispatchException(
                WorkOrderStatus.INVALID_PARAMETER_FORMAT_OR_VALUE, err_msg)

        wo_id = params["workOrderId"]
        # Work order status payload should have
        # data field with work order id as defined in EEA spec section 6.
        data = {"workOrderId": wo_id}

        # Work order is processed if it is in wo-response table
        value = self.kv_helper.get("wo-responses", wo_id)

        # Work order not in 'wo-timestamps' table
        if not value:
            if (self.kv_helper.get("wo-timestamps", wo_id) is not None):
                # work order is yet to be processed
                raise JSONRPCDispatchException(
                    WorkOrderStatus.PENDING,
                    "Work order result is yet to be updated", data)

            raise JSONRPCDispatchException(
                WorkOrderStatus.INVALID_PARAMETER_FORMAT_OR_VALUE,
                "Work order Id not found in the database. " +
                "Hence invalid parameter", data)

        # Worker order is processed and result is avalibale
        response = json.loads(value)
        if 'result' in response:
            return response['result']

        # response without a result should have an error
        err_code = response["error"]["code"]
        err_msg = response["error"]["message"]

        if err_code == EnclaveError.ENCLAVE_ERR_VALUE:
            err_code = \
                WorkOrderStatus.INVALID_PARAMETER_FORMAT_OR_VALUE
        elif err_code == EnclaveError.ENCLAVE_ERR_UNKNOWN:
            err_code = WorkOrderStatus.UNKNOWN_ERROR
        elif err_code == EnclaveError.ENCLAVE_ERR_INVALID_WORKLOAD:
            err_code = WorkOrderStatus.INVALID_WORKLOAD
        else:
            err_code = WorkOrderStatus.FAILED

        raise JSONRPCDispatchException(err_code, err_msg, data)