def register_app_with_blockchain(): """call the conductor service to register this app (bcdash catalog) on the supply chain network """ data = { "uuid": "520e7ee6-26f6-4cd0-6710-49c3579086f4", "api_url": "", "type": "website", "label": "Blockchain Dashboard" } if app.config["BYPASS_API_CALLS"]: return response = requests.post(API_SERVER + "/app/register", data=json.dumps(data), \ headers={'Content-type': 'application/json'}, timeout=app.config["DEFAULT_API_TIMEOUT"]) if response.status_code != 200: raise APIError("Failed to register app with blockchain. Server responded with " \ + "HTTP " + str(response.status_code)) try: result = response.json() except: raise APIError("Failed to register app with blockchain. Invalid JSON return data " \ + "'" + str(response.content)) + "'" if "status" not in result: raise APIError("Failed to register app with blockchain. Invalid JSON return data " \ + ": Missing required field 'status'.") if result["status"] != "success": raise APIError("Failed to register app with blockchain. Server returned status '" \ + str(result["status"]) + "'.")
def get_blockchain_apps(): """get a list of nodes running the ledger and their status from the conductor API """ try: return call_conductor_api("get", "/apps") except APIError as error: raise APIError("Failed to get list of blockchain apps. " + str(error))
def call_ledger_api(method, url, data={}): """ call the blockchain ledger service with the given method (post or get), url, and data. """ try: return call_api_service(method, get_ledger_address() + url, data) except APIError as error: raise APIError("Failed to call ledger API service. " + str(error))
def call_conductor_api(method, url, data={}): """call the conductor service """ try: return call_api_service(method, app.config["BLOCKCHAIN_API"] + url, data) except APIError as error: raise APIError("Failed to call the conductor API service. " + str(error))
def get_ledger_address(): """get the address of the ledger service from the conductor """ try: ledger_address = call_conductor_api("get", "/ledger/address") return "http://" + str(ledger_address["ip_address"]) + ":" + str(ledger_address["port"]) \ + "/api/sparts" except APIError as error: raise APIError("Failed to get the ledger API address. " + str(error))
def get_node_api_address(uuid): """Find the node with the given UUID and return its api_address""" selected_node = None for node in get_blockchain_nodes(): if node["uuid"] == uuid: selected_node = node break if selected_node is None: raise APIError("Node UUID was not found on the network.") if "api_address" not in selected_node: raise APIError("Invalid conductor response. Mising 'api_address'.") if not selected_node["api_address"]: raise APIError("Node did not provide a ledger service API URL.") return selected_node["api_address"]
def get_ledger_address(): """get the address of the ledger service from the conductor """ try: if app.config["BYPASS_API_CALLS"]: return "API calls are disabled." ledger_address = call_conductor_api("get", "/ledger/address") return "http://" + str(ledger_address["ip_address"]) + ":" + str(ledger_address["port"]) \ + "/api/sparts" except APIError as error: raise APIError("Failed to get the ledger API address. " + str(error))
def ping_node(uuid, timeout=app.config["DEFAULT_API_TIMEOUT"]): """ping a blockchain node and return its status """ node_api_url = get_node_api_address(uuid) try: response = requests.get(node_api_url + "/api/sparts/ping", timeout=timeout) except ReadTimeout: raise APIError("Timed out.") except ConnectionError: raise APIError("Connection refused.") if response.status_code != 200: raise APIError("(HTTP " + str(response.status_code) + ")") try: data = response.json() except: raise APIError("Returns invalid JSON.") if "status" not in data: raise APIError("Returns invalid JSON: missing 'status'") if data["status"] != "success": raise APIError("Status: '" + str(data["status"]) + "'") return "Running"
def get_blockchain_nodes(): """get a list of nodes running the ledger and their status from the conductor API """ response = requests.get(API_SERVER + "/ledger_nodes", timeout=app.config["DEFAULT_API_TIMEOUT"]) print(API_SERVER + "/ledger/nodes") if response.status_code != 200: raise APIError("Failed to call the conductor service to get list of blockchain nodes. " \ + "Server responded with status " + response.status_code) try: nodes = response.json() except: raise APIError("Failed to parse the JSON in the call to the conductor service " \ + "to retrieve list of running blockchain nodes.") if "status" in nodes and nodes["status"] != "success": raise APIError("Failed to call the conductor service to get list of blockchain nodes. " \ + "Server returned status '" + nodes["status"] + "'." ) return nodes
def get_ledger_api_address(): """get the address of the ledger service from the conductor Returns: (tuple) ip, port """ response = requests.get(API_SERVER + "/ledger/address", \ timeout=app.config["DEFAULT_API_TIMEOUT"]) if response.status_code != 200: raise APIError("Failed to retrieve the blockchain API server address.") try: ledger_address = response.json() except: raise APIError("Failed to parse the JSON response of the blockchain API server. Got:" \ + " <br><br><pre>" + str(response.content) + "</pre>") if "ip_address" not in ledger_address or ledger_address[ "ip_address"] == "0.0.0.0": raise APIError("Failed to retrieve the blockchain API server address. " \ + "Could not read a valid IP address. Got '" + str(ledger_address) + "'.") return ledger_address["ip_address"], ledger_address["port"]
def register_app_with_blockchain(): """call the conductor service to register this app """ print("Registering app with blockchain...") data = { "uuid": "520e7ee6-26f6-4cd0-6710-49c3579086f4", "name": "Blockchain Dashboard", "label": "Blockchain Dashboard", "api_address": "http://blockchain.open.windriver.com", "app_type": "website", "description": "Blockchain Dashboard" } try: return call_conductor_api("post", "/apps/register", data) except APIError as error: raise APIError("Failed to register app with blockchain. " + str(error))
def call_api_service(method, url, data): """call the API service at url with given HTTP method and parameters """ if app.config["BYPASS_API_CALLS"]: return {} try: print("Calling [" + method + "] " + url) print("with " + str(data)) if method == "get": response = requests.get(url, params=data, \ timeout=app.config["DEFAULT_API_TIMEOUT"]) elif method == "post": response = requests.post(url, data=json.dumps(data), \ headers={'Content-type': 'application/json'}, \ timeout=app.config["DEFAULT_API_TIMEOUT"]) else: raise APIError("Bad method passed to function `call_api()`. Got `" + method \ + "`; expected 'get' or 'post'.") if response.status_code != 200: raise APIError("The call to " + url + " resulted in HTTP status " \ + str(response.status_code)) try: json_response = response.json() except: raise APIError("Failed to parse the JSON data in the response of API service at " \ + url + ". The response was `" + str(response.content) + "`.") if "status" in json_response and json_response["status"] != "success": raise APIError("API service at '" + url + "' returned status '" \ + str(json_response["status"]) + "', with the following details: " \ + str(json_response)) return json_response except ReadTimeout: raise APIError("Connection to " + url + " timed out.") except ConnectionError: raise APIError("API service at " + url + " refused connection.") except Exception as error: raise APIError("Failed to call the API service at " + url + ". " + str(error))
def call_blockchain_api(method, url, data={}): """ call the blockchain ledger service with the given method (post or get), url, and data. """ if app.config["BYPASS_API_CALLS"]: return {} bc_server_ip, bc_server_port = get_ledger_api_address() request_url = "http://" + bc_server_ip + ":" + str( bc_server_port) + "/api/sparts" + url print("[" + method + "] " + request_url) result = None try: if method == "get": result = requests.get(request_url, params=data, timeout=app.config["DEFAULT_API_TIMEOUT"]) elif method == "post": result = requests.post(request_url, data=json.dumps(data), \ headers={'Content-type': 'application/json'}, timeout=app.config["DEFAULT_API_TIMEOUT"]) else: raise APIError( "Bad method passed to function 'call_blockchain_api") except ReadTimeout: raise APIError("Blockchain ledger service timed out.") except ConnectionError: raise APIError("Blockchain ledger service refused connection.") if result.status_code != 200: raise APIError("The blockchain API server responeded with HTTP " + \ str(result.status_code) + ".") json_result = None try: json_result = result.json() except: raise APIError("Failed to parse the following JSON data in the response of the blockchain" \ +" API server.<br><br><pre>" + str(result.content) + "</pre>") if "status" in json_result: # raise APIError("Invalid JSON in the response of the ledger service at " + url \ # + "Missing required field 'status'") if json_result["status"] == "failed": if "error_message" in json_result: raise APIError("Leger service call to '" + url + "' failed. " \ + "The API server provided the following reason: '" \ + json_result["error_message"] + "'.") else: raise APIError("Leger service call to '" + url + "' failed." + \ "No error_message was provided by the server.") if json_result["status"] != "success": raise APIError("Leger service call to '" + url + "' returned 'status' = '" \ + json_result["status"] + "'.") return json_result