mirror of
https://github.com/hanzoai/bootnode.git
synced 2026-10-25 02:31:30 +00:00
186 lines
5.3 KiB
Python
186 lines
5.3 KiB
Python
from threading import Thread
|
|
from functools import wraps
|
|
from quart import jsonify, Quart, request
|
|
from quart_cors import cors
|
|
from bootnode import Bootnode
|
|
from util import asynctools, convert
|
|
from pymongo import MongoClient
|
|
import datetime
|
|
import asyncio
|
|
|
|
app = Quart(__name__)
|
|
cors(app)
|
|
|
|
SUPPORTED_ZONES = ['us-central1-a', 'europe-west6-a', 'asia-east2-a']
|
|
|
|
# connect to mongo and set up database vars
|
|
mongo_client = MongoClient()
|
|
bootnode_db = mongo_client.bootnode
|
|
nodes_collection = bootnode_db.nodes
|
|
updates_collection = bootnode_db.updates
|
|
|
|
# set up system update loop
|
|
def update_nodes_lambda():
|
|
print('updating nodes')
|
|
try:
|
|
date = datetime.datetime.utcnow()
|
|
zones = SUPPORTED_ZONES
|
|
|
|
for zone in zones:
|
|
print('getting nodes in zone: ' + zone)
|
|
bootnode = Bootnode('casper', 'testnet', zone)
|
|
|
|
deployments = [d.to_dict() for d in bootnode.list_deployments()]
|
|
services = [s.to_dict() for s in bootnode.list_services()]
|
|
pods = [p.to_dict() for p in bootnode.list_pods()]
|
|
|
|
nodes = convert.to_nodes(deployments, services, pods, zone)
|
|
|
|
for node in nodes:
|
|
node['lateUpdated'] = date
|
|
nodes_collection.insert_one(node)
|
|
|
|
except Exception as e:
|
|
print('update nodes loop' + str(e))
|
|
finally:
|
|
updates_collection.update_one(
|
|
{
|
|
'name': 'nodes',
|
|
},
|
|
{
|
|
'$set': {
|
|
'date': date
|
|
},
|
|
},
|
|
True
|
|
)
|
|
|
|
# function to spin off thread
|
|
async def update_nodes_loop():
|
|
while True:
|
|
update_nodes_lambda()
|
|
await asyncio.sleep(1)
|
|
|
|
def update_nodes_daemon():
|
|
loop = asyncio.new_event_loop()
|
|
task = loop.create_task(update_nodes_loop())
|
|
loop.run_until_complete(task)
|
|
|
|
Thread(target=update_nodes_daemon, daemon=True).start()
|
|
|
|
def auth_required(fn):
|
|
@wraps(fn)
|
|
async def wrapped_fn(*args, **kwargs):
|
|
print(request.headers.get('Authorization'))
|
|
if request.headers.get('Authorization') != 'Bearer fLcLu7OLD81aR9jf':
|
|
return jsonify({
|
|
'status': 'failed',
|
|
'error': 'authorization required',
|
|
})
|
|
return await fn(*args, **kwargs)
|
|
return wrapped_fn
|
|
|
|
@app.route('/nodes', methods=['GET'])
|
|
@auth_required
|
|
async def get_nodes():
|
|
try:
|
|
update = updates_collection.find_one({ 'name': 'nodes' })
|
|
print(update)
|
|
print('getting node data as of ' + str(update['date']))
|
|
nodes = nodes_collection.find({'lateUpdated': update['date']})
|
|
|
|
ns = []
|
|
for node in nodes:
|
|
node.pop('_id')
|
|
ns.append(node)
|
|
|
|
return jsonify(ns)
|
|
|
|
except Exception as e:
|
|
return jsonify({
|
|
'status': 'failed',
|
|
'error': 'could not get nodes: ' + str(e),
|
|
})
|
|
|
|
@app.route('/nodes', methods=['PUT'])
|
|
@auth_required
|
|
async def put_node():
|
|
try:
|
|
json = await request.get_json()
|
|
print('launching ' + str(json['number']) + ' nodes in ' + str(json['zone']))
|
|
|
|
if json['zone'] not in SUPPORTED_ZONES:
|
|
return jsonify({
|
|
'status': 'failed',
|
|
'error': json['zone'] + ' is not a valid zone',
|
|
})
|
|
|
|
bootnode = Bootnode('casper', 'testnet', json['zone'])
|
|
|
|
number = 1
|
|
if json['number'] is not None:
|
|
number = int(json['number'])
|
|
|
|
def create_deployment():
|
|
try:
|
|
bootnode.create_deployment()
|
|
except Exception as e:
|
|
print('could not create deployment: ' + str(e))
|
|
|
|
nodes = []
|
|
for i in range(number):
|
|
asyncio.get_event_loop().run_in_executor(None,
|
|
create_deployment())
|
|
|
|
return jsonify({
|
|
'status': 'success',
|
|
'nodes-starting': number,
|
|
})
|
|
except Exception as e:
|
|
return jsonify({
|
|
'status': 'failed',
|
|
'error': 'could not create a node: ' + str(e)
|
|
})
|
|
|
|
@app.route('/nodes/<node_id>', methods=['GET'])
|
|
@auth_required
|
|
async def get_node(node_id, zone='us-central1-a'):
|
|
try:
|
|
bootnode = Bootnode('casper', 'testnet', zone)
|
|
|
|
deployment = bootnode.get_deployment(node_id)
|
|
service = bootnode.get_service(node_id)
|
|
pods = [p.to_dict() for p in bootnode.list_pods(label_selector='app=' + node_id)]
|
|
|
|
return jsonify(convert.to_nodes([deployment.to_dict()],
|
|
[service.to_dict()], pods, zone))
|
|
except Exception as e:
|
|
return jsonify({
|
|
'status': 'failed',
|
|
'error': 'node not found: ' + str(e)
|
|
})
|
|
|
|
@app.route('/nodes/<node_id>', methods=['DELETE'])
|
|
@auth_required
|
|
async def delete_node(node_id, zone='us-central1-a'):
|
|
try:
|
|
json = await request.get_json()
|
|
print('deleting ' + node_id + ' from zone ' + json['zone'])
|
|
|
|
zone = json['zone']
|
|
|
|
bootnode = Bootnode('casper', 'testnet', zone)
|
|
bootnode.delete_deployment(node_id)
|
|
return jsonify({
|
|
'status': 'ok',
|
|
})
|
|
except Exception as e:
|
|
return jsonify({
|
|
'status': 'failed',
|
|
'error': 'could not delete: ' + str(e)
|
|
})
|
|
|
|
|
|
if __name__ == '__main__':
|
|
app.run(debug=True, host='0.0.0.0', port='4000')
|