From 090d056e53945886772c9c43a7592b9eba948742 Mon Sep 17 00:00:00 2001 From: BaoNguyen09 Date: Mon, 5 May 2025 10:16:03 -0700 Subject: [PATCH 01/17] feat: create a script that will do queries on servers --- get_servers.py | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 get_servers.py diff --git a/get_servers.py b/get_servers.py new file mode 100644 index 0000000..39271e0 --- /dev/null +++ b/get_servers.py @@ -0,0 +1,48 @@ +from utils import get_db_connection + +def get_all_servers(user: str) -> list[dict]: + db = get_db_connection() + cursor = db.cursor() + # return all instances in database + cursor.execute("SELECT * FROM servers WHERE owner = %s;", (user,)) + rows = cursor.fetchall() + db.commit() + cursor.close() + db.close() + + resp = [] + for row in rows: + resp.append( + { + "id": row[0], + "owner": row[1], + "description": row[2], + "instance_id": row[3], + "public_ip": row[4], + "ready": row[5] + } + ) + return resp + +def get_server(primary_key: int, user: str) -> dict: + db = get_db_connection() + cursor = db.cursor() + # return a single instance in db + cursor.execute("SELECT * FROM servers WHERE id = %s AND owner = %s;", (primary_key, user,)) + row = cursor.fetchone() + db.commit() + cursor.close() + db.close() + + if row == None: + return {} + + resp = { + "id": row[0], + "owner": row[1], + "description": row[2], + "instance_id": row[3], + "public_ip": row[4], + "ready": row[5] + } + return resp \ No newline at end of file From fb5df8920a054207405304fb5d8c8cbbc76b1a56 Mon Sep 17 00:00:00 2001 From: BaoNguyen09 Date: Mon, 5 May 2025 10:16:29 -0700 Subject: [PATCH 02/17] feat: this module has all common methods used by other scripts --- utils.py | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 utils.py diff --git a/utils.py b/utils.py new file mode 100644 index 0000000..a0e60ea --- /dev/null +++ b/utils.py @@ -0,0 +1,54 @@ +import os +import config +import json +import MySQLdb +from http.cookies import SimpleCookie + +def print_json_200(data: any): + # respond with json data + print("Status: 200 OK") + print("Content-Type: application/json\n") + print(json.dumps(data)) + +def print_redirect_300(location: str): + print("Status: 303 See Other") + print(f"Location: {config.ROOT_URL}/{location}") + print() + +def print_status_400(body: str): + print("Status: 400 Bad Request") + print("Content-Type: text/plain\n") + print(f"Invalid Request: {body}") + +def print_status_405(extra_path: str, allowed_method: str): + print("Status 405: Method Not Allowed") + print("Content-Type: text/plain\n") + print(f"Method '{allowed_method}' isn't allowed for path: '{extra_path}'\n \ + Allowed method: POST") + +def print_status_500(body: str): + print("Status: 500 Internal Server Error") + print("Content-Type: text/plain\n") + print(f"Database Connection Error: {body}") + +def get_db_connection(): + try: + db = MySQLdb.connect( + host=config.DB_HOST, + user=config.DB_USER, + passwd=config.DB_PASSWORD, + db=config.DB_NAME, + port=config.DB_PORT, + ssl={"ssl": {}} + ) + return db + + except MySQLdb.Error as e: + print_status_500(str(e)) + exit(1) + +def get_cookie() -> str | None: + # Get user field from cookie + cookie_string = os.environ.get("HTTP_COOKIE", "") + parsed = SimpleCookie(cookie_string) + return parsed.get("user").value if "user" in parsed else None \ No newline at end of file From c577f06878981785743117a18a0882d21665e672 Mon Sep 17 00:00:00 2001 From: BaoNguyen09 Date: Mon, 5 May 2025 10:17:02 -0700 Subject: [PATCH 03/17] refactor: use methods from get_servers and utils module --- api/servers | 94 +++++++++++------------------------------------------ 1 file changed, 19 insertions(+), 75 deletions(-) diff --git a/api/servers b/api/servers index 71c755c..16e39d5 100644 --- a/api/servers +++ b/api/servers @@ -2,99 +2,43 @@ import os, sys sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -import MySQLdb -import config -import json - -def print_json_200(data): - # respond with json data - print("Status: 200 OK") - print("Content-Type: application/json\n") - print(json.dumps(data)) - -def print_status_400(body: str): - print("Status: 400 Bad Request") - print("Content-Type: text/plain\n") - print(f"Invalid Request: {body}") - -def print_status_405(extra_path: str, allowed_method: str): - print("Status 405: Method Not Allowed") - print("Content-Type: text/plain\n") - print(f"Method '{allowed_method}' isn't allowed for path: '{extra_path}'\n \ - Allowed method: POST") - -def print_status_500(body: str): - print("Status: 500 Internal Server Error") - print("Content-Type: text/plain\n") - print(f"Database Connection Error: {body}") - -def get_db_connection(): - try: - db = MySQLdb.connect( - host=config.DB_HOST, - user=config.DB_USER, - passwd=config.DB_PASSWORD, - db=config.DB_NAME, - port=config.DB_PORT, - ssl={"ssl": {}} - ) - return db - - except MySQLdb.Error as e: - print_status_500(str(e)) - exit(1) +from http.cookies import SimpleCookie +from get_servers import get_all_servers, get_server +from utils import * def main(): # extract basic request info request_method = os.environ["REQUEST_METHOD"] extra_path = os.environ.get("PATH_INFO", "") - path_component = extra_path.split("/") + + # Get user field from cookie + cookie_string = os.environ.get("HTTP_COOKIE", "") + parsed = SimpleCookie(cookie_string) + user = parsed.get("user").value if "user" in parsed else None + + if not user: # Redirect to login + print_redirect_300(f"login.html") + return + if request_method == "GET": - db = get_db_connection() - cursor = db.cursor() if extra_path == "" or extra_path == "/": # return all instances in database - cursor.execute("SELECT * FROM servers;") - rows = cursor.fetchall() - resp = [] - for row in rows: - resp.append( - { - "id": row[0], - "owner": row[1], - "description": row[2], - "instance_id": row[3], - "public_ip": row[4], - "ready": row[5] - } - ) + resp = get_all_servers(user) print_json_200(resp) elif extra_path.startswith("/") and extra_path[1:].isnumeric(): # /api/servers/ # return a single instance in db primary_key = int(extra_path[1:]) - cursor.execute("SELECT * FROM servers WHERE id = %s;", (primary_key,)) - row = cursor.fetchone() - - if row == None: + resp = get_server(primary_key, user) + if resp == {}: print_status_400("can't find server with this id in the database") - return - - resp = { - "id": row[0], - "owner": row[1], - "description": row[2], - "instance_id": row[3], - "public_ip": row[4], - "ready": row[5] - } - print_json_200(resp) - + else: print_status_400("Page not found: " + extra_path) + else: print_status_405(extra_path, "GET") - + if __name__ == "__main__": main() \ No newline at end of file From 067d43ce3555fcfd94a9595344417263387ce995 Mon Sep 17 00:00:00 2001 From: BaoNguyen09 Date: Mon, 5 May 2025 10:17:31 -0700 Subject: [PATCH 04/17] feat: this is the main page UI script --- var/www/html/home | 89 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 var/www/html/home diff --git a/var/www/html/home b/var/www/html/home new file mode 100644 index 0000000..1e0c6ad --- /dev/null +++ b/var/www/html/home @@ -0,0 +1,89 @@ +#! /usr/bin/python3 + +from get_servers import get_all_servers +from utils import print_redirect_300, get_cookie + +def generate_html(user: str, servers: list[dict]): + print("Content-Type: text/html\n") + print(f""" + + + + {user} Cloud Servers + + + + +

Welcome, {user}

+

Create New Server

+
+ + Create +
+

Your Servers

+ + + + + + + + + + + + """) + + for server in servers: + sid = server["id"] + desc = server["description"] + ip = server["ip"] + ready = server["ready"] + + status = "Ready" if ready else "Pending" + ip_display = ip if ip else "N/A" + print(f""" + + + + + + + + """) + + print(""" + +
IDDescriptionStatusIPActions
{sid}{desc}{status}{ip_display} +
+ + +
+
+ + + """) + + +def main(): + # Get user field from cookie + user = get_cookie() + if not user: # Redirect to login + print_redirect_300("login.html") + return + + # Fetch user's servers + servers = get_all_servers(user) + + # Generate HTML + generate_html(user, servers) + +if __name__ == "__main__": + main() From 8e8a24c41c5bba87b2c8ddd1313dc63b5a5b3ebb Mon Sep 17 00:00:00 2001 From: BaoNguyen09 Date: Mon, 5 May 2025 10:18:01 -0700 Subject: [PATCH 05/17] fix: aim for simplicity --- create_server | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/create_server b/create_server index e040c9d..f6973ee 100644 --- a/create_server +++ b/create_server @@ -12,11 +12,7 @@ config_commands = """#cloud-config - apt update - apt install apache2 -y - systemctl enable apache2 - - mkdir -p /etc/systemd/system/apache2.service.d/ - - bash -c 'echo -e "[Unit]\nAfter=network-online.target\nWants=network-online.target" > /etc/systemd/system/apache2.service.d/override.conf' - - systemctl daemon-reload - - systemctl restart apache2 - - echo "hello, world" > /root/dummy.txt + - systemctl start apache2 """ def print_status_400(body: str): From aab5ecd46654a80d01e4949c6e9cf93ca96703aa Mon Sep 17 00:00:00 2001 From: BaoNguyen09 Date: Mon, 5 May 2025 10:20:14 -0700 Subject: [PATCH 06/17] refactor: move all files into correponding folder as in the VM --- {api => user/lib/cgi-bin/api}/servers | 0 create_server => user/lib/cgi-bin/create_server | 0 get_servers.py => user/lib/cgi-bin/get_servers.py | 0 login => user/lib/cgi-bin/login | 0 monitor_new_VM => user/lib/cgi-bin/monitor_new_VM | 0 terminate_server => user/lib/cgi-bin/terminate_server | 0 utils.py => user/lib/cgi-bin/utils.py | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename {api => user/lib/cgi-bin/api}/servers (100%) rename create_server => user/lib/cgi-bin/create_server (100%) rename get_servers.py => user/lib/cgi-bin/get_servers.py (100%) rename login => user/lib/cgi-bin/login (100%) rename monitor_new_VM => user/lib/cgi-bin/monitor_new_VM (100%) rename terminate_server => user/lib/cgi-bin/terminate_server (100%) rename utils.py => user/lib/cgi-bin/utils.py (100%) diff --git a/api/servers b/user/lib/cgi-bin/api/servers similarity index 100% rename from api/servers rename to user/lib/cgi-bin/api/servers diff --git a/create_server b/user/lib/cgi-bin/create_server similarity index 100% rename from create_server rename to user/lib/cgi-bin/create_server diff --git a/get_servers.py b/user/lib/cgi-bin/get_servers.py similarity index 100% rename from get_servers.py rename to user/lib/cgi-bin/get_servers.py diff --git a/login b/user/lib/cgi-bin/login similarity index 100% rename from login rename to user/lib/cgi-bin/login diff --git a/monitor_new_VM b/user/lib/cgi-bin/monitor_new_VM similarity index 100% rename from monitor_new_VM rename to user/lib/cgi-bin/monitor_new_VM diff --git a/terminate_server b/user/lib/cgi-bin/terminate_server similarity index 100% rename from terminate_server rename to user/lib/cgi-bin/terminate_server diff --git a/utils.py b/user/lib/cgi-bin/utils.py similarity index 100% rename from utils.py rename to user/lib/cgi-bin/utils.py From d29c95078a14db25da4b8fe8ac371156cb8e994d Mon Sep 17 00:00:00 2001 From: BaoNguyen09 Date: Mon, 5 May 2025 10:20:44 -0700 Subject: [PATCH 07/17] update gitignore list --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index dd19c04..8dcd535 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ config.py -__pycache__ \ No newline at end of file +__pycache__ +user/lib/cgi-bin/api/README.md \ No newline at end of file From 5966b9ed4ea8d020fc60895b8bf7ca185d1e5356 Mon Sep 17 00:00:00 2001 From: BaoNguyen09 Date: Mon, 5 May 2025 10:21:27 -0700 Subject: [PATCH 08/17] Revert "refactor: move all files into correponding folder as in the VM" This reverts commit aab5ecd46654a80d01e4949c6e9cf93ca96703aa. --- {user/lib/cgi-bin/api => api}/servers | 0 user/lib/cgi-bin/create_server => create_server | 0 user/lib/cgi-bin/get_servers.py => get_servers.py | 0 user/lib/cgi-bin/login => login | 0 user/lib/cgi-bin/monitor_new_VM => monitor_new_VM | 0 user/lib/cgi-bin/terminate_server => terminate_server | 0 user/lib/cgi-bin/utils.py => utils.py | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename {user/lib/cgi-bin/api => api}/servers (100%) rename user/lib/cgi-bin/create_server => create_server (100%) rename user/lib/cgi-bin/get_servers.py => get_servers.py (100%) rename user/lib/cgi-bin/login => login (100%) rename user/lib/cgi-bin/monitor_new_VM => monitor_new_VM (100%) rename user/lib/cgi-bin/terminate_server => terminate_server (100%) rename user/lib/cgi-bin/utils.py => utils.py (100%) diff --git a/user/lib/cgi-bin/api/servers b/api/servers similarity index 100% rename from user/lib/cgi-bin/api/servers rename to api/servers diff --git a/user/lib/cgi-bin/create_server b/create_server similarity index 100% rename from user/lib/cgi-bin/create_server rename to create_server diff --git a/user/lib/cgi-bin/get_servers.py b/get_servers.py similarity index 100% rename from user/lib/cgi-bin/get_servers.py rename to get_servers.py diff --git a/user/lib/cgi-bin/login b/login similarity index 100% rename from user/lib/cgi-bin/login rename to login diff --git a/user/lib/cgi-bin/monitor_new_VM b/monitor_new_VM similarity index 100% rename from user/lib/cgi-bin/monitor_new_VM rename to monitor_new_VM diff --git a/user/lib/cgi-bin/terminate_server b/terminate_server similarity index 100% rename from user/lib/cgi-bin/terminate_server rename to terminate_server diff --git a/user/lib/cgi-bin/utils.py b/utils.py similarity index 100% rename from user/lib/cgi-bin/utils.py rename to utils.py From a6253ac67a317a216e9f1b16e7f8beb88b14cb53 Mon Sep 17 00:00:00 2001 From: BaoNguyen09 Date: Mon, 5 May 2025 10:22:47 -0700 Subject: [PATCH 09/17] Reapply "refactor: move all files into correponding folder as in the VM" This reverts commit 5966b9ed4ea8d020fc60895b8bf7ca185d1e5356. --- {api => user/lib/cgi-bin/api}/servers | 0 create_server => user/lib/cgi-bin/create_server | 0 get_servers.py => user/lib/cgi-bin/get_servers.py | 0 login => user/lib/cgi-bin/login | 0 monitor_new_VM => user/lib/cgi-bin/monitor_new_VM | 0 terminate_server => user/lib/cgi-bin/terminate_server | 0 utils.py => user/lib/cgi-bin/utils.py | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename {api => user/lib/cgi-bin/api}/servers (100%) rename create_server => user/lib/cgi-bin/create_server (100%) rename get_servers.py => user/lib/cgi-bin/get_servers.py (100%) rename login => user/lib/cgi-bin/login (100%) rename monitor_new_VM => user/lib/cgi-bin/monitor_new_VM (100%) rename terminate_server => user/lib/cgi-bin/terminate_server (100%) rename utils.py => user/lib/cgi-bin/utils.py (100%) diff --git a/api/servers b/user/lib/cgi-bin/api/servers similarity index 100% rename from api/servers rename to user/lib/cgi-bin/api/servers diff --git a/create_server b/user/lib/cgi-bin/create_server similarity index 100% rename from create_server rename to user/lib/cgi-bin/create_server diff --git a/get_servers.py b/user/lib/cgi-bin/get_servers.py similarity index 100% rename from get_servers.py rename to user/lib/cgi-bin/get_servers.py diff --git a/login b/user/lib/cgi-bin/login similarity index 100% rename from login rename to user/lib/cgi-bin/login diff --git a/monitor_new_VM b/user/lib/cgi-bin/monitor_new_VM similarity index 100% rename from monitor_new_VM rename to user/lib/cgi-bin/monitor_new_VM diff --git a/terminate_server b/user/lib/cgi-bin/terminate_server similarity index 100% rename from terminate_server rename to user/lib/cgi-bin/terminate_server diff --git a/utils.py b/user/lib/cgi-bin/utils.py similarity index 100% rename from utils.py rename to user/lib/cgi-bin/utils.py From 08cc581b8d11c578c889476c494b464801bdd219 Mon Sep 17 00:00:00 2001 From: BaoNguyen09 Date: Mon, 5 May 2025 10:23:12 -0700 Subject: [PATCH 10/17] Revert "update gitignore list" This reverts commit d29c95078a14db25da4b8fe8ac371156cb8e994d. --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 8dcd535..dd19c04 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ config.py -__pycache__ -user/lib/cgi-bin/api/README.md \ No newline at end of file +__pycache__ \ No newline at end of file From d6628d6010fcf5c014643c1a1aa4a6df6d2cb74c Mon Sep 17 00:00:00 2001 From: BaoNguyen09 Date: Mon, 5 May 2025 10:49:52 -0700 Subject: [PATCH 11/17] refactor+fix: move this script to cgi-bin, and strip user field to to avoid bugs with whitespace --- {var/www/html => user/lib/cgi-bin}/home | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename {var/www/html => user/lib/cgi-bin}/home (94%) diff --git a/var/www/html/home b/user/lib/cgi-bin/home similarity index 94% rename from var/www/html/home rename to user/lib/cgi-bin/home index 1e0c6ad..6085dfa 100644 --- a/var/www/html/home +++ b/user/lib/cgi-bin/home @@ -24,7 +24,7 @@ def generate_html(user: str, servers: list[dict]):

Create New Server

-

Your Servers

@@ -44,7 +44,7 @@ def generate_html(user: str, servers: list[dict]): for server in servers: sid = server["id"] desc = server["description"] - ip = server["ip"] + ip = server["public_ip"] ready = server["ready"] status = "Ready" if ready else "Pending" @@ -78,10 +78,10 @@ def main(): if not user: # Redirect to login print_redirect_300("login.html") return - + user = user.strip() # Fetch user's servers servers = get_all_servers(user) - + print(f"servers: {servers}") # Generate HTML generate_html(user, servers) From 9c9b73c25a654d5b43c2406c6e65927d49af9de5 Mon Sep 17 00:00:00 2001 From: BaoNguyen09 Date: Mon, 5 May 2025 10:50:49 -0700 Subject: [PATCH 12/17] minor_feat: update redirect location to main UI --- user/lib/cgi-bin/create_server | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user/lib/cgi-bin/create_server b/user/lib/cgi-bin/create_server index f6973ee..72de512 100644 --- a/user/lib/cgi-bin/create_server +++ b/user/lib/cgi-bin/create_server @@ -95,7 +95,7 @@ def add_server_to_db(user: str, desc: str, instance_id: int, ready: bool): os.system(f"./monitor_new_VM {instance_id} {new_server_id} 1>/dev/null 2>/dev/null &") print("Status: 303 See Other") - print(f"Location: {config.ROOT_URL}/cgi-bin/api/servers/{new_server_id}") + print(f"Location: {config.ROOT_URL}/cgi-bin/home") print() except Exception as e: From 59f31cfe4f1c4e36b914a5e048529e34fd752151 Mon Sep 17 00:00:00 2001 From: BaoNguyen09 Date: Mon, 5 May 2025 11:01:00 -0700 Subject: [PATCH 13/17] minor_feat: make public_ip a link to quickly check new server --- user/lib/cgi-bin/home | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user/lib/cgi-bin/home b/user/lib/cgi-bin/home index 6085dfa..41afb76 100644 --- a/user/lib/cgi-bin/home +++ b/user/lib/cgi-bin/home @@ -54,7 +54,7 @@ def generate_html(user: str, servers: list[dict]): {sid} {desc} {status} - {ip_display} + {ip_display}
From 963f3c27c2c428e37b841a4af88f936bf19f161d Mon Sep 17 00:00:00 2001 From: BaoNguyen09 Date: Mon, 5 May 2025 11:01:43 -0700 Subject: [PATCH 14/17] minor_improv: no need for commit since it's just select operation --- user/lib/cgi-bin/get_servers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/user/lib/cgi-bin/get_servers.py b/user/lib/cgi-bin/get_servers.py index 39271e0..81a5e2a 100644 --- a/user/lib/cgi-bin/get_servers.py +++ b/user/lib/cgi-bin/get_servers.py @@ -6,7 +6,7 @@ def get_all_servers(user: str) -> list[dict]: # return all instances in database cursor.execute("SELECT * FROM servers WHERE owner = %s;", (user,)) rows = cursor.fetchall() - db.commit() + cursor.close() db.close() @@ -30,11 +30,11 @@ def get_server(primary_key: int, user: str) -> dict: # return a single instance in db cursor.execute("SELECT * FROM servers WHERE id = %s AND owner = %s;", (primary_key, user,)) row = cursor.fetchone() - db.commit() + cursor.close() db.close() - if row == None: + if row is None: return {} resp = { From 9012f76c75db5f253c1b79ad363fae4bc5977e52 Mon Sep 17 00:00:00 2001 From: BaoNguyen09 Date: Mon, 5 May 2025 11:02:14 -0700 Subject: [PATCH 15/17] minor_change: update redirect location to main UI --- user/lib/cgi-bin/terminate_server | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user/lib/cgi-bin/terminate_server b/user/lib/cgi-bin/terminate_server index 981d460..2abd246 100644 --- a/user/lib/cgi-bin/terminate_server +++ b/user/lib/cgi-bin/terminate_server @@ -96,7 +96,7 @@ def remove_server_from_db(primary_key: str): db.close() print("Status: 303 See Other") - print(f"Location: {config.ROOT_URL}/cgi-bin/api/servers") + print(f"Location: {config.ROOT_URL}/cgi-bin/home") print() except Exception as e: From 71e335c2038c5a966a91dbf31d1fd3b9d29b7178 Mon Sep 17 00:00:00 2001 From: BaoNguyen09 Date: Tue, 6 May 2025 16:20:03 -0700 Subject: [PATCH 16/17] feat: add another method in util for 403 status code --- user/lib/cgi-bin/utils.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/user/lib/cgi-bin/utils.py b/user/lib/cgi-bin/utils.py index a0e60ea..6917b27 100644 --- a/user/lib/cgi-bin/utils.py +++ b/user/lib/cgi-bin/utils.py @@ -20,6 +20,11 @@ def print_status_400(body: str): print("Content-Type: text/plain\n") print(f"Invalid Request: {body}") +def print_status_403(body: str): + print("Status: 403 Forbidden") + print("Content-Type: text/plain\n") + print(f"Forbidden: {body}") + def print_status_405(extra_path: str, allowed_method: str): print("Status 405: Method Not Allowed") print("Content-Type: text/plain\n") From e4f5fa5b96e271dc1b00f544b262196921195980 Mon Sep 17 00:00:00 2001 From: BaoNguyen09 Date: Tue, 6 May 2025 16:30:27 -0700 Subject: [PATCH 17/17] refactor: reduce code duplication with utils' methods --- user/lib/cgi-bin/create_server | 46 +++------------------------- user/lib/cgi-bin/login | 21 ++----------- user/lib/cgi-bin/monitor_new_VM | 17 +---------- user/lib/cgi-bin/terminate_server | 51 +++---------------------------- 4 files changed, 11 insertions(+), 124 deletions(-) diff --git a/user/lib/cgi-bin/create_server b/user/lib/cgi-bin/create_server index 72de512..097ba5c 100644 --- a/user/lib/cgi-bin/create_server +++ b/user/lib/cgi-bin/create_server @@ -6,6 +6,7 @@ import MySQLdb import config from pydo import Client from http.cookies import SimpleCookie +from utils import * config_commands = """#cloud-config runcmd: @@ -15,38 +16,6 @@ config_commands = """#cloud-config - systemctl start apache2 """ -def print_status_400(body: str): - print("Status: 400 Bad Request") - print("Content-Type: text/plain\n") - print(f"Invalid Request: {body}") - -def print_status_405(extra_path: str, allowed_method: str): - print("Status 405: Method Not Allowed") - print("Content-Type: text/plain\n") - print(f"Method '{allowed_method}' isn't allowed for path: '{extra_path}'\n \ - Allowed method: POST") - -def print_status_500(body: str): - print("Status: 500 Internal Server Error") - print("Content-Type: text/plain\n") - print(f"Database Connection Error: {body}") - -def get_db_connection(): - try: - db = MySQLdb.connect( - host=config.DB_HOST, - user=config.DB_USER, - passwd=config.DB_PASSWORD, - db=config.DB_NAME, - port=config.DB_PORT, - ssl={"ssl": {}} - ) - return db - - except MySQLdb.Error as e: - print_status_500(str(e)) - exit(1) - def create_server(user: str, desc: str) -> int: try: if (user == "" and desc is None): @@ -94,9 +63,7 @@ def add_server_to_db(user: str, desc: str, instance_id: int, ready: bool): # run background script os.system(f"./monitor_new_VM {instance_id} {new_server_id} 1>/dev/null 2>/dev/null &") - print("Status: 303 See Other") - print(f"Location: {config.ROOT_URL}/cgi-bin/home") - print() + print_redirect_300("cgi-bin/home") except Exception as e: print_status_500(str(e)) @@ -105,17 +72,12 @@ def main(): # extract basic request info request_method = os.environ["REQUEST_METHOD"] extra_path = os.environ.get("PATH_INFO", "").lstrip("/") - path_component = extra_path.split("/") if request_method == "POST" or request_method == "GET": # read query parameter case of GET/POST method form = cgi.FieldStorage() # Get user field from cookie - cookie_string = os.environ.get("HTTP_COOKIE", "") - parsed = SimpleCookie(cookie_string) - user = parsed.get("user").value if "user" in parsed else None + user = get_cookie() if not user: # Redirect to login - print("Status: 303 See Other") - print(f"Location: {config.ROOT_URL}/login.html") - print() + print_redirect_300("login.html") return # Get desc field from query param desc = form.getvalue("desc", None) diff --git a/user/lib/cgi-bin/login b/user/lib/cgi-bin/login index 5e2c721..e68de66 100644 --- a/user/lib/cgi-bin/login +++ b/user/lib/cgi-bin/login @@ -3,22 +3,7 @@ import os import cgi import config - -def print_status_400(body: str): - print("Status: 400 Bad Request") - print("Content-Type: text/plain\n") - print(f"Invalid Request: {body}") - -def print_status_405(extra_path: str, allowed_method: str): - print("Status 405: Method Not Allowed") - print("Content-Type: text/plain\n") - print(f"Method '{allowed_method}' isn't allowed for path: '{extra_path}'\n \ - Allowed method: POST") - -def print_status_500(body: str): - print("Status: 500 Internal Server Error") - print("Content-Type: text/plain\n") - print(f"Database Connection Error: {body}") +from utils import * def main(): # extract basic request info @@ -34,9 +19,7 @@ def main(): print(f"Set-Cookie: user={user}; Path=/; HttpOnly; SameSite=Lax") - print("Status: 303 See Other") - print(f"Location: {config.ROOT_URL}/index.html") - print() + print_redirect_300("cgi-bin/home") else: print_status_405(extra_path, request_method) diff --git a/user/lib/cgi-bin/monitor_new_VM b/user/lib/cgi-bin/monitor_new_VM index e8b8f31..0e84fac 100644 --- a/user/lib/cgi-bin/monitor_new_VM +++ b/user/lib/cgi-bin/monitor_new_VM @@ -5,22 +5,7 @@ from pydo import Client import time import MySQLdb import config - -def get_db_connection(): - try: - db = MySQLdb.connect( - host=config.DB_HOST, - user=config.DB_USER, - passwd=config.DB_PASSWORD, - db=config.DB_NAME, - port=config.DB_PORT, - ssl={"ssl": {}} - ) - return db - - except MySQLdb.Error as e: - print(str(e)) - exit(1) +from utils import * def main(): try: diff --git a/user/lib/cgi-bin/terminate_server b/user/lib/cgi-bin/terminate_server index 2abd246..9bdba82 100644 --- a/user/lib/cgi-bin/terminate_server +++ b/user/lib/cgi-bin/terminate_server @@ -2,47 +2,10 @@ import cgi import os -import MySQLdb import config from pydo import Client from http.cookies import SimpleCookie - -def print_status_400(body: str): - print("Status: 400 Bad Request") - print("Content-Type: text/plain\n") - print(f"Invalid Request: {body}") - -def print_status_403(body: str): - print("Status: 403 Forbidden") - print("Content-Type: text/plain\n") - print(f"Forbidden: {body}") - -def print_status_405(extra_path: str, allowed_method: str): - print("Status 405: Method Not Allowed") - print("Content-Type: text/plain\n") - print(f"Method '{allowed_method}' isn't allowed for path: '{extra_path}'\n \ - Allowed method: POST") - -def print_status_500(body: str): - print("Status: 500 Internal Server Error") - print("Content-Type: text/plain\n") - print(f"Database Connection Error: {body}") - -def get_db_connection(): - try: - db = MySQLdb.connect( - host=config.DB_HOST, - user=config.DB_USER, - passwd=config.DB_PASSWORD, - db=config.DB_NAME, - port=config.DB_PORT, - ssl={"ssl": {}} - ) - return db - - except MySQLdb.Error as e: - print_status_500(str(e)) - exit(1) +from utils import * def terminate_server(primary_key: str, user: str): try: @@ -95,9 +58,7 @@ def remove_server_from_db(primary_key: str): cursor.close() db.close() - print("Status: 303 See Other") - print(f"Location: {config.ROOT_URL}/cgi-bin/home") - print() + print_redirect_300("cgi-bin/home") except Exception as e: print_status_500(str(e)) @@ -108,13 +69,9 @@ def main(): extra_path = os.environ.get("PATH_INFO", "").lstrip("/") # Check user field in cookie - cookie_string = os.environ.get("HTTP_COOKIE", "") - parsed = SimpleCookie(cookie_string) - user = parsed.get("user").value if "user" in parsed else None + user = get_cookie() if not user: # Redirect to login - print("Status: 303 See Other") - print(f"Location: {config.ROOT_URL}/login.html") - print() + print_redirect_300("login.html") return if request_method == "POST" or request_method == "GET": # read query parameter case of GET/POST method