From 44738c78a92cc644819151242bc2ff9f40966813 Mon Sep 17 00:00:00 2001 From: forest Date: Thu, 10 Dec 2020 20:32:43 -0600 Subject: [PATCH] first steps towards multiple hosts -- schema & heartbeat --- capsulflask/db_model.py | 21 ++++++++++++ capsulflask/hosts_api.py | 22 +++++++++++++ .../09_down_introduce_hosts.sql | 11 +++++++ .../09_up_introduce_hosts.sql | 33 +++++++++++++++++++ 4 files changed, 87 insertions(+) create mode 100644 capsulflask/hosts_api.py create mode 100644 capsulflask/schema_migrations/09_down_introduce_hosts.sql create mode 100644 capsulflask/schema_migrations/09_up_introduce_hosts.sql diff --git a/capsulflask/db_model.py b/capsulflask/db_model.py index 9017977..93b07ff 100644 --- a/capsulflask/db_model.py +++ b/capsulflask/db_model.py @@ -8,6 +8,10 @@ class DBModel: self.connection = connection self.cursor = cursor + + # ------ LOGIN --------- + + def login(self, email): self.cursor.execute("SELECT * FROM accounts WHERE email = %s", (email, )) if len(self.cursor.fetchall()) == 0: @@ -33,6 +37,10 @@ class DBModel: return email return None + + # ------ VM & ACCOUNT MANAGEMENT --------- + + def all_non_deleted_vm_ids(self,): self.cursor.execute("SELECT id FROM vms WHERE deleted IS NULL") return list(map(lambda x: x[0], self.cursor.fetchall())) @@ -144,6 +152,10 @@ class DBModel: return vm + + # ------ PAYMENTS & ACCOUNT BALANCE --------- + + def list_payments_for_account(self, email): self.cursor.execute(""" SELECT id, dollars, invalidated, created @@ -253,6 +265,15 @@ class DBModel: return list(map(lambda row: dict(email=row[0], account_balance_warning=row[1]), self.cursor.fetchall())) + # ------ HOSTS --------- + + def authorized_for_host(self, id, token): + self.cursor.execute("SELECT id FROM hosts WHERE id = %s token = %s", (id, token)) + return self.cursor.fetchone() != None + + def host_heartbeat(self, id): + self.cursor.execute("UPDATE hosts SET last_health_check = NOW() WHERE id = %s", (id,)) + self.connection.commit() diff --git a/capsulflask/hosts_api.py b/capsulflask/hosts_api.py new file mode 100644 index 0000000..592687a --- /dev/null +++ b/capsulflask/hosts_api.py @@ -0,0 +1,22 @@ + +from flask import Blueprint +from flask import current_app +from flask import request +from werkzeug.exceptions import abort + +from capsulflask.db import get_model, my_exec_info_message + +bp = Blueprint("hosts", __name__, url_prefix="/hosts") + +def authorized_for_host(id): + auth_header_value = request.headers.get('Authorization').replace("Bearer ", "") + return get_model().authorized_for_host(id, auth_header_value) + +@bp.route("/heartbeat/", methods=("POST")) +def heartbeat(id): + if authorized_for_host(id): + get_model().host_heartbeat(id) + else: + current_app.logger.info(f"/hosts/heartbeat/{id} returned 401: invalid token") + return abort(401, "invalid host id or token") + diff --git a/capsulflask/schema_migrations/09_down_introduce_hosts.sql b/capsulflask/schema_migrations/09_down_introduce_hosts.sql new file mode 100644 index 0000000..d2b4343 --- /dev/null +++ b/capsulflask/schema_migrations/09_down_introduce_hosts.sql @@ -0,0 +1,11 @@ + +DROP TABLE host_operation; + +DROP TABLE operations; + +ALTER TABLE vms DROP COLUMN host; + +DROP TABLE hosts; + + +UPDATE schemaversion SET version = 8; \ No newline at end of file diff --git a/capsulflask/schema_migrations/09_up_introduce_hosts.sql b/capsulflask/schema_migrations/09_up_introduce_hosts.sql new file mode 100644 index 0000000..b75bec8 --- /dev/null +++ b/capsulflask/schema_migrations/09_up_introduce_hosts.sql @@ -0,0 +1,33 @@ + + +CREATE TABLE hosts ( + id TEXT PRIMARY KEY NOT NULL, + last_health_check TIMESTAMP NOT NULL DEFAULT NOW(), + token TEXT NOT NULL +); + +INSERT INTO hosts (id, token) VALUES ('baikal', 'changeme'); + +ALTER TABLE vms +ADD COLUMN host TEXT REFERENCES hosts(id) ON DELETE RESTRICT DEFAULT 'baikal'; + +CREATE TABLE operations ( + id TEXT PRIMARY KEY NOT NULL, + email TEXT REFERENCES accounts(email) ON DELETE RESTRICT, + assigned_host TEXT NULL, + host_status TEXT NULL, + created TIMESTAMP NOT NULL DEFAULT NOW(), + assigned TIMESTAMP NULL, + completed TIMESTAMP NULL, + payload TEXT NOT NULL, +); + +CREATE TABLE host_operation ( + host TEXT NOT NULL, + operation TEXT NOT NULL, + assignment_status TEXT NULL, + assignment_status_timestamp TIMESTAMP, + PRIMARY KEY (host, operation) +); + +UPDATE schemaversion SET version = 9; \ No newline at end of file