def start_enclave_manager(config): """ Instantiate KvStorage, Execute boot flow and run time flow """ global enclave_data if config.get("KvStorage") is None: logger.error("Kv Storage path is missing") sys.exit(-1) try: logger.debug("initialize the enclave") # Extended measurements is a list of enclave basename and enclave measurement extended_measurements = enclave_helper.initialize_enclave(config.get("EnclaveModule")) except Exception as e: logger.exception("failed to initialize enclave; %s", str(e)) sys.exit(-1) logger.info("creating a new enclave") enclave_signup_data = create_enclave_signup_data() logger.info("initialize enclave_manager") enclave_manager = EnclaveManager(config, enclave_signup_data, extended_measurements) logger.info("Enclave manager started") try: kv_helper = KvStorage() kv_helper.open(TCFHOME + "/" + config["KvStorage"]["StoragePath"]) except: logger.error("Failed to open KV storage interface, Exiting SGX Enclave manager...") exit(1) try: logger.info("----------------------- Starting Boot time flow -----------------------") enclave_manager.manager_on_boot(kv_helper) logger.info("----------------------- Boot time flow Complete -----------------------") except: logger.error("Failed to execute boot time flow, Exiting SGX Enclave manager...") exit(1) try: sleep_interval = int(config["EnclaveManager"]["sleep_interval"]) except: logger.error("Failed to get sleep interval from config file. setting sleep interval to 10 secs") sleep_interval = 10 try: while True: # Poll KV storage for new work-order requests and process enclave_manager.process_work_orders(kv_helper) logger.info("Enclave manager sleeping for %d secs", sleep_interval) time.sleep(sleep_interval) except: logger.error("Error while processing work-order. Shutting down enclave manager") exit(1)
def main(): logger.info("Testing Direct registry bridge functionality.") eth_direct_registry = dir_registry.EthereumDirectRegistry("0x8c99670a15047248403a3E5A38eb8FBE7a12533e", '../contracts/WorkerRegistryList.sol') kv_storage = KvStorage() kv_storage.open("kv_storage") logger.info("------------------- test_sync_to_lmdb ---------------------- \n") test_sync_to_lmdb(eth_direct_registry, kv_storage) logger.info("\n------------------- test_sync_to_smart_contract ---------------------- \n") test_sync_to_smart_contract(eth_direct_registry, kv_storage)
def main(args=None): logger.info( "Starting synchronization between Smart contract and KvStorage.") # Smart contract address is the address where smart contract is deployed. # TODO: Add mechanism to read the address from config file. eth_direct_registry = registry.EthereumDirectRegistry("0x8c99670a15047248403a3E5A38eb8FBE7a12533e", \ '../connectors/contracts/WorkerRegistryList.sol') kv_storage = KvStorage() kv_storage.open("kv_storage") while True: sync_contract_and_lmdb(eth_direct_registry, kv_storage) logger.info("Direct registry bridge is Sleeping off..") time.sleep(10)
def open(config): """ @dev open implements a generic API for opening connections to a LMDB database where it's local or remote @return (conn, type), where - conn is the connection helper to interact with db - type is 1 for the local LMDB, 2 for the remote LMDB """ kv_config = config.get('KvStorage') if kv_config is None: raise ValueError("config for KvStorage is missing") # employ the remote version if remote_url is set if kv_config.get("remote_url") is not None: database_url = kv_config["remote_url"] logger.info(f"connect to remote LMDB @{database_url}") return (LMDBHelperProxy(database_url), 2) # otherwise, use the local one storage_path = TCFHOME + '/' + kv_config['StoragePath'] storage_size = kv_config['StorageSize'] conn = KvStorage() if not conn.open(storage_path, storage_size): raise ValueError("Failed to open KV Storage DB") logger.info(f"employ the local LMDB @{storage_path}") return (conn, 1)
class LMDBRequestHandler(resource.Resource): """ LMDBRequestHandler is comprised of HTTP interface which listens for calls to LMDB """ # The isLeaf instance variable describes whether or not # a resource will have children and only leaf resources get rendered. # LMDBRequestHandler is the most derived class hence isLeaf is required. isLeaf = True ## ----------------------------------------------------------------- def __init__(self, config): if config.get('KvStorage') is None: logger.error("Kv Storage path is missing") sys.exit(-1) self.kv_helper = KvStorage() storage_path = TCFHOME + '/' + config['KvStorage']['StoragePath'] if not self.kv_helper.open(storage_path): logger.error("Failed to open KV Storage DB") sys.exit(-1) def __del__(self): self.kv_helper.close() def _process_request(self, request): response = "" logger.info(request.encode('utf-8')) args = request.split('\n') for i in range(len(args)): args[i] = unescape(args[i]) logger.info(args) cmd = args[0] # Lookup if (cmd == "L"): if len(args) == 2: result_list = self.kv_helper.lookup(args[1]) result = "" for key in result_list: if result == "": result = key else: result = result + "," + key # Lookup result found if result != "": response = "l\n" + escape(result) # No result found else: response = "n" # Error else: logger.error("Invalid args for cmd Lookup") response = "e\nInvalid args for cmd Lookup" # Get elif (cmd == "G"): if len(args) == 3: result = self.kv_helper.get(args[1], args[2]) # Value found if result is not None: response = "v\n" + escape(result) # Value not found else: response = "n" # Error else: logger.error("Invalid args for cmd Get") response = "e\nInvalid args for cmd Get" # Set elif (cmd == "S"): if len(args) == 4: result = self.kv_helper.set(args[1], args[2], args[3]) # Set successful (returned True) if result: response = "t" # Set unsuccessful (returned False) else: response = "f" # Error else: logger.error("Invalid args for cmd Set") response = "e\nInvalid args for cmd Set" # Remove elif (cmd == "R"): if len(args) == 3 or len(args) == 4: if len(args) == 3: result = self.kv_helper.remove(args[1], args[2]) else: result = self.kv_helper.remove(args[1], args[2], value=args[3]) # Remove successful (returned True) if result: response = "t" # Remove unsuccessful (returned False) else: response = "f" # Error else: logger.error("Invalid args for cmd Remove") response = "e\nInvalid args for cmd Remove" # Error else: logger.error("Unknown cmd") response = "e\nUnknown cmd" return response def render_GET(self, request): response = 'Only POST request is supported' logger.error("GET request is not supported." + \ " Only POST request is supported") return response def render_POST(self, request): response = "" logger.info('Received a new request from the client') try: # Process the message encoding encoding = request.getHeader('Content-Type') data = request.content.read().decode('utf-8') if encoding == 'text/plain; charset=utf-8': response = self._process_request(data) else: response = 'UNKNOWN_ERROR: unknown message encoding' return response except: logger.exception('exception while decoding http request %s', request.path) response = 'UNKNOWN_ERROR: unable to decode incoming request ' return response # Send back the results try: logger.info('response[%s]: %s', encoding, response.encode('utf-8')) request.setHeader('content-type', encoding) request.setResponseCode(http.OK) return response.encode('utf-8') except: logger.exception('unknown exception while processing request %s', request.path) response = 'UNKNOWN_ERROR: unknown exception processing ' + \ 'http request {0}'.format(request.path) return response
class TCSListener(resource.Resource): """ TCSListener Class is comprised of HTTP interface which listens for the end user requests, Worker Registry Handler, Work Order Handler and Work Order Receipts Handler . """ # The isLeaf instance variable describes whether or not a resource will have children and only leaf resources get rendered. # TCSListener is the most derived class hence isLeaf is required. isLeaf = True ## ----------------------------------------------------------------- def __init__(self, config): if config.get('KvStorage') is None: logger.error("Kv Storage path is missing") sys.exit(-1) storage_path = TCFHOME + '/' + config['KvStorage']['StoragePath'] self.kv_helper = KvStorage() if not self.kv_helper.open(storage_path): logger.error("Failed to open KV Storage DB") sys.exit(-1) # Worker registry handler needs to be instantiated before Work order handler. Otherwise, LMDB operations don't operate on updated values. # TODO: Needs further investigation on what is causing the above behavior. self.worker_registry_handler = TCSWorkerRegistryHandler(self.kv_helper) self.workorder_handler = TCSWorkOrderHandler( self.kv_helper, config["Listener"]["max_work_order_count"]) self.workorder_receipt_handler = TCSWorkOrderReceiptHandler( self.kv_helper) self.worker_encryption_key_handler = WorkerEncryptionKeyHandler( self.kv_helper) def _process_request(self, input_json_str): response = {} response['error'] = {} response['error'][ 'code'] = WorkorderError.INVALID_PARAMETER_FORMAT_OR_VALUE try: input_json = json.loads(input_json_str) except: response['error'][ 'message'] = 'Error: Improper Json. Unable to load' return response if ('jsonrpc' not in input_json or 'id' not in input_json or 'method' not in input_json or 'params' not in input_json): response['error'][ 'message'] = 'Error: Json does not have the required field' return response if not isinstance(input_json['id'], int): response['error'][ 'message'] = 'Error: Id should be of type integer' return response response['jsonrpc'] = input_json['jsonrpc'] response['id'] = input_json['id'] if not isinstance(input_json['method'], str): response['error'][ 'message'] = 'Error: Method has to be of type string' return response if ((input_json['method'] == "WorkOrderSubmit") or (input_json['method'] == "WorkOrderGetResult")): return self.workorder_handler.process_work_order(input_json_str) elif ("WorkOrderReceipt" in input_json['method']): return self.workorder_receipt_handler.workorder_receipt_handler( input_json_str) elif ("Worker" in input_json['method']): return self.worker_registry_handler.worker_registry_handler( input_json_str) elif ("EncryptionKey" in input_json['method']): return self.worker_encryption_key_handler.process_encryption_key( input_json_str) else: response['error']['message'] = 'Error: Invalid method field' return response def render_GET(self, request): # JRPC response with id 0 is returned because id parameter # will not be found in GET request response = utility.create_error_response( WorkorderError.INVALID_PARAMETER_FORMAT_OR_VALUE, "0", "Only POST request is supported") logger.error( "GET request is not supported. Only POST request is supported") return response def render_POST(self, request): response = {} logger.info('Received a new request from the client') try: # process the message encoding encoding = request.getHeader('Content-Type') data = request.content.read() if encoding == 'application/json': try: input_json_str = json.loads(data.decode('utf-8')) input_json = json.loads(input_json_str) jrpc_id = input_json["id"] response = self._process_request(input_json_str) except AttributeError: logger.error("Error while loading input json") response = utility.create_error_response( WorkorderError.UNKNOWN_ERROR, jrpc_id, "UNKNOWN_ERROR: Error while loading the input JSON file" ) return response else: # JRPC response with 0 as id is returned because id can't be fecthed # from a request with unknown encoding response = utility.create_error_response( WorkorderError.UNKNOWN_ERROR, 0, "UNKNOWN_ERROR: unknown message encoding") return response except: logger.exception('exception while decoding http request %s', request.path) # JRPC response with 0 as id is returned because id can't be # fetched from improper request response = utility.create_error_response( WorkorderError.UNKNOWN_ERROR, 0, "UNKNOWN_ERROR: unable to decode incoming request") return response # send back the results try: if encoding == 'application/json': response = json.dumps(response) logger.info('response[%s]: %s', encoding, response) request.setHeader('content-type', encoding) request.setResponseCode(http.OK) return response.encode('utf8') except: logger.exception('unknown exception while processing request %s', request.path) response = utility.create_error_response( WorkorderError.UNKNOWN_ERROR, jrpc_id, "UNKNOWN_ERROR: unknown exception processing http \ request {0}".format(request.path)) return response
def LocalMain(config) : if config.get('KvStorage') is None: logger.error("Kv Storage path is missing") sys.exit(-1) KvHelper = KvStorage() KvHelper.open((TCFHOME + '/' + config['KvStorage']['StoragePath'])) if not input_json_str and not input_json_dir: logger.error("JSON input file is not provided") exit(1) if not output_json_file_name: logger.error("JSON output file is not provided") exit(1) if not server_uri: logger.error("Server URI is not provided") exit(1) logger.info('execute work order') uri_client = GenericServiceClient(server_uri) if input_json_dir: directory = os.fsencode(input_json_dir) files = os.listdir(directory) for file in sorted(files) : logger.info("------------------Input file name: %s ---------------\n",file.decode("utf-8")) input_json_str1 = enclave_helper.read_json_file((directory.decode("utf-8") + file.decode("utf-8"))) logger.info("*********Request Json********* \n%s\n", input_json_str1) response = uri_client._postmsg(input_json_str1) logger.info("**********Received Response*********\n%s\n", response) else : j=json.loads(input_json_str) if(j['method'] == "WorkOrderGetResult"): response = {} response['id'] = j['params']['workOrderId'] response["outData"] = "Processed response" KvHelper.set("wo-responses", str(j['params']['workOrderId']), json.dumps(response)) input_str = json.dumps(j) logger.info('input str %s', input_str) response = uri_client._postmsg(input_str) logger.info("Received Response : %s , \n \n ", response) j['params']['workOrderId'] = "101" input_str = json.dumps(j) logger.info('input str %s', input_str) response = uri_client._postmsg(input_str) logger.info("Received Response : %s , \n \n ", response) j['params']['workOrderId'] = "121" input_str = json.dumps(j) logger.info('input str %s', input_str) response = uri_client._postmsg(input_str) logger.info("Received Response : %s , \n \n ", response) else: id = 100 logger.info("time stamp lookup : %s", KvHelper.lookup("wo-timestamps")) logger.info("Test adding new time stamps entries") for x in range(5): j['params']['workOrderId'] = id + x input_str = json.dumps(j) logger.info('input str %s', input_str) response = uri_client._postmsg(input_str) logger.info("Received Response : %s , \n \n ", response) logger.info("time stamp lookup : %s", KvHelper.lookup("wo-timestamps")) logger.info("Work order id exists") id = 100 for x in range(5): j['params']['workOrderId'] = id + x input_str = json.dumps(j) logger.info('input str %s', input_str) response = uri_client._postmsg(input_str) logger.info("Received Response : %s , \n \n ", response); logger.info("time stamp lookup : %s", KvHelper.lookup("wo-timestamps")) logger.info("Test max count reached and buys status") id = 105 for x in range(10): j['params']['workOrderId'] = id + x input_str = json.dumps(j) logger.info('input str %s', input_str) response = uri_client._postmsg(input_str) logger.info("Received Response : %s , \n \n ", response); logger.info("time stamp lookup : %s", KvHelper.lookup("wo-timestamps")) logger.info("Adding a work order id 109 into processed table") KvHelper.set("wo-processed", "109", "109") logger.info("Sending a new request with work order id %s", id + x) j['params']['workOrderId'] = id + x input_str = json.dumps(j) logger.info('input str %s', input_str) response = uri_client._postmsg(input_str) logger.info("Received Response : %s , \n \n ", response); logger.info("time stamp lookup : %s", KvHelper.lookup("wo-timestamps")) work_orders = KvHelper.lookup("wo-scheduled") for wo_id in work_orders: KvHelper.remove("wo-scheduled", wo_id) logger.info("adding 3 entries into processing scheduled and processed table to test boot flow") KvHelper.set("wo-scheduled", "100", input_str) KvHelper.set("wo-processing", "101", input_str) KvHelper.set("wo-processed", "102", input_str) logger.info("restart tcf listener and verify it adds to its internal list during boot up") exit(0)
def LocalMain(config): if config.get('KvStorage') is None: logger.error("Kv Storage path is missing") sys.exit(-1) KvHelper = KvStorage() KvHelper.open((TCFHOME + '/' + config['KvStorage']['StoragePath'])) if not input_json_str and not input_json_dir: logger.error("JSON input file is not provided") exit(1) if not output_json_file_name: logger.error("JSON output file is not provided") exit(1) if not server_uri: logger.error("Server URI is not provided") exit(1) logger.info('Execute work order') uri_client = GenericServiceClient(server_uri) response = None if input_json_dir: directory = os.fsencode(input_json_dir) files = os.listdir(directory) for file in sorted(files): input_json_str1 = enclave_helper.read_json_file( (directory.decode("utf-8") + file.decode("utf-8"))) #---------------------------------------------------------------------------------- #If Client request is WorkOrderSubmit,a requester payload’s signature with the requester private signing key is generated. if "WorkOrderSubmit" in input_json_str1: input_json_str1 = signature_generate(input_json_str1) if input_json_str1 is None: continue #---------------------------------------------------------------------------------- # Update the worker ID if response: if "workerId" in input_json_str1: #Retrieving the worker id from the "WorkerRetrieve" response and update the worker id information for further json requests if 'result' in response and 'ids' in response[ "result"].keys(): input_json_final = json.loads(input_json_str1) input_json_final['params']['workerId'] = response[ 'result']['ids'][0] input_json_str1 = json.dumps(input_json_final) logger.info( "**********Worker details Updated with Worker ID*********\n%s\n", response['result']['ids'][0]) #----------------------------------------------------------------------------------- logger.info("*********Request Json********* \n%s\n", input_json_str1) response = uri_client._postmsg(input_json_str1) logger.info("**********Received Response*********\n%s\n", response) #----------------------------------------------------------------------------------- #Worker details are loaded into Worker_Obj if "WorkerRetrieve" in input_json_str1: worker_obj.load_worker(response) #---------------------------------------------------------------------------------- # Key already exist test scenario "test_wo_submit_key_already_exist" response = uri_client._postmsg(input_json_str1) if 'WorkOrderSubmit' in input_json_str1 and 'result' not in response: logger.info("*****key already exist *****") assert response['error']['message'], 'key already exist' assert response['error']['code'], 8 #---------------------------------------------------------------------------------- # Polling for the "WorkOrderGetResult" and break when you get the result while ('WorkOrderGetResult' in input_json_str1 and 'result' not in response): response = uri_client._postmsg(input_json_str1) logger.info(" Received Response : %s, \n \n ", response) time.sleep(3) #---------------------------------------------------------------------------------- #Verify the signature if ('WorkOrderGetResult' in input_json_str1): sig_bool = verify_signature(json.dumps(response)) #---------------------------------------------------------------------------------- else: logger.info('Input Request %s', input_json_str) input_json_str_1 = signature_generate(input_json_str) response = uri_client._postmsg(input_json_str_1) logger.info("Received Response : %s , \n \n ", response) sig_bool = verify_signature(json.dumps(response)) exit(0)