From 18d89bb62ac8c0bbec3f03d04792f7ba57b63169 Mon Sep 17 00:00:00 2001 From: jprochazka Date: Thu, 1 Aug 2024 16:03:16 -0400 Subject: [PATCH] Added system information endpoints. --- build/portal/backend/backend/__init__.py | 2 + build/portal/backend/backend/db.py | 8 +- .../portal/backend/backend/routes/monitors.py | 46 ------ build/portal/backend/backend/routes/system.py | 152 ++++++++++++++++++ 4 files changed, 158 insertions(+), 50 deletions(-) delete mode 100644 build/portal/backend/backend/routes/monitors.py create mode 100644 build/portal/backend/backend/routes/system.py diff --git a/build/portal/backend/backend/__init__.py b/build/portal/backend/backend/__init__.py index 5a704c6..3eca55f 100644 --- a/build/portal/backend/backend/__init__.py +++ b/build/portal/backend/backend/__init__.py @@ -12,6 +12,7 @@ from backend.routes.flights import flights from backend.routes.links import links from backend.routes.notifications import notifications from backend.routes.settings import settings +from backend.routes.system import system from backend.routes.tokens import tokens from backend.routes.users import users @@ -41,6 +42,7 @@ def create_app(test_config=None): app.register_blueprint(links) app.register_blueprint(notifications) app.register_blueprint(settings) + app.register_blueprint(system) app.register_blueprint(tokens) app.register_blueprint(users) diff --git a/build/portal/backend/backend/db.py b/build/portal/backend/backend/db.py index 4336286..ad5eedf 100644 --- a/build/portal/backend/backend/db.py +++ b/build/portal/backend/backend/db.py @@ -25,10 +25,10 @@ def get_db(): ) case 'postgresql': g.db = psycopg2.connect( - host=config['database']['mysql']['host'], - user=config['database']['mysql']['user'], - password=config['database']['mysql']['password'], - database=config['database']['mysql']['database'] + host=config['database']['postgresql']['host'], + user=config['database']['postgresql']['user'], + password=config['database']['postgresql']['password'], + database=config['database']['postgresql']['database'] ) case 'sqlite': g.db = sqlite3.connect(os.path.join(current_app.instance_path, 'adsbportal.sqlite3')) diff --git a/build/portal/backend/backend/routes/monitors.py b/build/portal/backend/backend/routes/monitors.py deleted file mode 100644 index 0d71b4c..0000000 --- a/build/portal/backend/backend/routes/monitors.py +++ /dev/null @@ -1,46 +0,0 @@ -import logging -import psutil - -from flask import abort, Blueprint -from backend.db import get_db - - -monitors = Blueprint('monitors', __name__) - -@monitors.route("/api/monitors/cpu", methods=["POST"]) -def cpu(): - memory = psutil.virtual_memory() - cpu_data = { - 'cpu_percent': psutil.cpu_percent(1), - 'cpu_count': psutil.cpu_count(), - 'cpu_freq': psutil.cpu_freq(), - 'cpu_mem_total': memory.total, - 'cpu_mem_avail': memory.available, - 'cpu_mem_used': memory.used, - 'cpu_mem_free': memory.free, - 'sensor_temperatures': psutil.sensors_temperatures()['cpu-thermal'][0].current - } - return cpu_data - -@monitors.route("/api/monitors/disk", methods=["POST"]) -def disk(): - disk = psutil.disk_usage('/') - cpu_data = { - 'disk_usage_total': disk.total, - 'disk_usage_used': disk.used, - 'disk_usage_free': disk.free, - 'disk_usage_percent': disk.percent, - } - return cpu_data - -@monitors.route("/api/monitors/database", methods=["POST"]) -def disk(): - try: - db=get_db() - cursor=db.cursor() - cursor.execute("SELECT table_schema AS name, ROUND(SUM(data_length + index_length) / 1024 / 1024, 1) AS size_in_mb FROM information_schema.tables ROUP BY table_schema;") - count=cursor.fetchone()[0] - except Exception as ex: - logging.error('Error encountered while trying to get flight count', exc_info=ex) - abort(500, description="Internal Server Error") - return \ No newline at end of file diff --git a/build/portal/backend/backend/routes/system.py b/build/portal/backend/backend/routes/system.py new file mode 100644 index 0000000..6a1f11c --- /dev/null +++ b/build/portal/backend/backend/routes/system.py @@ -0,0 +1,152 @@ +import logging +import os +import psutil +import yaml + +from flask import abort, Blueprint, current_app, jsonify +from backend.db import get_db + +config=yaml.safe_load(open("config.yml")) + + +system = Blueprint('system', __name__) + +@system.route("/api/system/cpu", methods=["GET"]) +def cpu(): + frequency = psutil.cpu_freq() + stats = psutil.cpu_stats() + cpu_data = { + 'cpu_count': psutil.cpu_count(), + 'cpu_count_logical': psutil.cpu_count(True), + 'cpu_frequency_current': frequency.current, + 'cpu_frequency_max': frequency.max, + 'cpu_frequency_min': frequency.min, + 'cpu_load_averages': psutil.getloadavg(), + 'cpu_percent': psutil.cpu_percent(1), + 'cpu_stats_context_switches_since_boot': stats.ctx_switches, + 'cpu_stats_interupts_since_boot': stats.interrupts, + 'cpu_stats_soft_interupts_since_boot': stats.soft_interrupts, + 'cpu_stats_system_calls_since_boot': stats.syscalls, + 'cpu_times': psutil.cpu_times(), + 'cpu_times_percent': psutil.cpu_times_percent(1) + } + + response=jsonify(cpu_data) + response.headers.add('Access-Control-Allow-Origin', '*') + return response, 200 + +@system.route("/api/system/memory", methods=["GET"]) +def memory(): + virtual = psutil.virtual_memory() + swap = psutil.swap_memory() + memory_data = { + 'memory_virtual_total': virtual.total, + 'memory_virtual_available': virtual.available, + 'memory_virtual_percent': virtual.available, + 'memory_virtual_used': virtual.used, + 'memory_virtual_free': virtual.free, + 'memory_swap_total': swap.total, + 'memory_swap_used': swap.used, + 'memory_swap_free': swap.free, + 'memory_swap_percent': swap.percent, + 'memory_swap_sin': swap.sin, + 'memory_swap_sout': swap.sout, + } + response=jsonify(memory_data) + response.headers.add('Access-Control-Allow-Origin', '*') + return response, 200 + +@system.route("/api/system/disk", methods=["GET"]) +def disk(): + usage = psutil.disk_usage('/') + io = psutil.disk_io_counters() + disk_data = { + 'disk_usage_total': usage.total, + 'disk_usage_used': usage.used, + 'disk_usage_free': usage.free, + 'disk_usage_percent': usage.percent, + 'disk_io_read_count': io.read_count, + 'disk_usage_percent': io.write_count, + 'disk_usage_percent': io.read_bytes, + 'disk_usage_percent': io.write_bytes, + 'disk_usage_percent': io.read_count, + 'disk_partitions': psutil.disk_partitions(), + } + + response=jsonify(disk_data) + response.headers.add('Access-Control-Allow-Origin', '*') + return response, 200 + +@system.route("/api/system/network", methods=["GET"]) +def network(): + io = psutil.net_io_counters() + network_data = { + 'network_io_bytes_sent': io.bytes_sent, + 'network_io_bytes_received': io.bytes_recv, + 'network_io_packets_sent': io.packets_sent, + 'network_io_packets_received': io.packets_recv, + 'network_io_errors_in': io.errin, + 'network_io_errors_out': io.errout, + 'network_io_dropped_in': io.dropin, + 'network_io_dropped_out': io.dropout, + 'network_connections': psutil.net_connections(), + 'network_interface_addresses': psutil.net_if_addrs(), + 'network_interface_stats': psutil.net_if_stats() + } + + response=jsonify(network_data) + response.headers.add('Access-Control-Allow-Origin', '*') + return response, 200 + +@system.route("/api/system/sensors", methods=["GET"]) +def sensors(): + sensor_data = { + #'sensors_temperature': psutil.sensors_temperatures(True), + #'sensors_fans': psutil.sensors_fans(), + 'sensors_battery': psutil.sensors_battery(), + #'sensor_temperatures': psutil.sensors_temperatures()['cpu-thermal'][0].current + } + + response=jsonify(sensor_data) + response.headers.add('Access-Control-Allow-Origin', '*') + return response, 200 + +@system.route("/api/system/other", methods=["GET"]) +def other(): + other_data = { + 'other_boot_time': psutil.boot_time(), + 'other_users': psutil.users() + } + + response=jsonify(other_data) + response.headers.add('Access-Control-Allow-Origin', '*') + return response, 200 + +@system.route("/api/system/database", methods=["GET"]) +def database(): + match config['database']['use'].lower(): + case 'mysql': + try: + db=get_db() + cursor=db.cursor() + cursor.execute("SELECT SUM(data_length + index_length) AS size FROM information_schema.tables WHERE table_schema = %s GROUP BY table_schema;", (config['database']['mysql']['database'],)) + db_size=cursor.fetchone()[0] + except Exception as ex: + logging.error('Error encountered while trying to get MySQL database size', exc_info=ex) + abort(500, description="Internal Server Error") + case 'postgresql': + try: + db=get_db() + cursor=db.cursor() + cursor.execute("SELECT pg_database_size(?);", (config['database']['postgresql']['database'],)) + db_size=cursor.fetchone()[0] + except Exception as ex: + logging.error('Error encountered while trying to get PostgreSQL database size', exc_info=ex) + abort(500, description="Internal Server Error") + case 'sqlite': + db_size=os.path.getsize(os.path.join(current_app.instance_path, 'adsbportal.sqlite3')) + + response=jsonify(size=db_size) + response.headers.add('Access-Control-Allow-Origin', '*') + return response, 200 +