2021-01-02 23:10:01 +00:00
|
|
|
|
|
|
|
from flask import Blueprint
|
|
|
|
from flask import current_app
|
|
|
|
from flask import request
|
|
|
|
from werkzeug.exceptions import abort
|
|
|
|
|
2021-01-04 19:32:52 +00:00
|
|
|
from capsulflask.db import get_model
|
|
|
|
from capsulflask.shared import my_exec_info_message, authorized_as_hub
|
2021-01-02 23:10:01 +00:00
|
|
|
|
2021-01-03 01:07:43 +00:00
|
|
|
bp = Blueprint("hub", __name__, url_prefix="/hub")
|
2021-01-02 23:10:01 +00:00
|
|
|
|
|
|
|
def authorized_for_host(id):
|
2021-01-04 19:32:52 +00:00
|
|
|
if request.headers.get('Authorization'):
|
|
|
|
auth_header_value = request.headers.get('Authorization').replace("Bearer ", "")
|
|
|
|
return get_model().authorized_for_host(id, auth_header_value)
|
|
|
|
return False
|
2021-01-02 23:10:01 +00:00
|
|
|
|
2021-01-04 19:32:52 +00:00
|
|
|
@bp.route("/heartbeat-task", methods=("POST",))
|
|
|
|
def ping_all_hosts_task():
|
|
|
|
if authorized_as_hub(request.headers):
|
|
|
|
all_hosts = get_model().get_all_hosts()
|
2021-01-04 23:20:03 +00:00
|
|
|
current_app.logger.debug(f"pinging {len(all_hosts)} hosts...")
|
2021-01-04 19:32:52 +00:00
|
|
|
authorization_header = f"Bearer {current_app.config['HUB_TOKEN']}"
|
|
|
|
results = current_app.config["HTTP_CLIENT"].make_requests_sync(all_hosts, "/spoke/heartbeat", None, authorization_header=authorization_header)
|
|
|
|
for i in range(len(all_hosts)):
|
|
|
|
host = all_hosts[i]
|
|
|
|
result = results[i]
|
2021-01-04 23:20:03 +00:00
|
|
|
current_app.logger.debug(f"response from {host.id} ({host.url}): {result.status_code} {result.body}")
|
2021-01-04 19:32:52 +00:00
|
|
|
if result.status_code == 200:
|
|
|
|
get_model().host_heartbeat(host.id)
|
|
|
|
|
|
|
|
return "ok"
|
|
|
|
else:
|
2021-01-04 23:20:03 +00:00
|
|
|
current_app.logger.warning(f"/hub/heartbeat-task returned 401: invalid hub token")
|
2021-01-04 19:32:52 +00:00
|
|
|
return abort(401, "invalid hub token")
|
|
|
|
|
|
|
|
|
|
|
|
@bp.route("/heartbeat/<string:host_id>", methods=("POST",))
|
2021-01-04 01:17:30 +00:00
|
|
|
def heartbeat(host_id):
|
|
|
|
if authorized_for_host(host_id):
|
2021-01-04 19:32:52 +00:00
|
|
|
return "ok"
|
2021-01-02 23:10:01 +00:00
|
|
|
else:
|
2021-01-04 23:20:03 +00:00
|
|
|
current_app.logger.warning(f"/hub/heartbeat/{host_id} returned 401: invalid token")
|
2021-01-04 01:17:30 +00:00
|
|
|
return abort(401, "invalid host id or token")
|
|
|
|
|
2021-01-04 19:32:52 +00:00
|
|
|
@bp.route("/claim-operation/<int:operation_id>/<string:host_id>", methods=("POST",))
|
2021-01-04 01:17:30 +00:00
|
|
|
def claim_operation(operation_id: int, host_id: str):
|
|
|
|
if authorized_for_host(host_id):
|
|
|
|
exists = get_model().host_operation_exists(operation_id, host_id)
|
|
|
|
if not exists:
|
|
|
|
return abort(404, "host operation not found")
|
|
|
|
claimed = get_model().claim_operation(operation_id, host_id)
|
|
|
|
if claimed:
|
|
|
|
return "ok"
|
|
|
|
else:
|
|
|
|
return abort(409, "operation was already assigned to another host")
|
|
|
|
else:
|
2021-01-04 23:20:03 +00:00
|
|
|
current_app.logger.warning(f"/hub/claim-operation/{operation_id}/{host_id} returned 401: invalid token")
|
2021-01-02 23:10:01 +00:00
|
|
|
return abort(401, "invalid host id or token")
|
|
|
|
|