From 8437fa6d9c3baedb450bebc94befdf86fea95d10 Mon Sep 17 00:00:00 2001
From: Matt
Date: Sun, 19 Apr 2026 18:13:34 -0700
Subject: [PATCH] lots of php proofreading and html tab tidying up
---
files/api/DriveServer.py | 4 -
files/api/StorageApi.py | 6 -
files/api/new_descriptors.json | 3 +-
files/{api => archive}/archive.py | 0
files/{ => archive}/vizz/docker/Dockerfile | 0
.../vizz/docker/apache_ports.conf | 0
.../vizz/docker/apache_vhost.conf | 0
.../vizz/docker/supervisord.conf | 0
.../vizz/docker/web/html/index.php | 0
.../vizz/docker/web/html/src/redis.js | 0
.../vizz/docker/web/html/src/styles.css | 0
.../docker/web/html/src/system_metrics.js | 0
.../vizz/docker/web/html/test.php | 0
.../vizz/docker/web/node_server/package.json | 0
.../vizz/docker/web/node_server/server.js | 0
.../vizz/docker/web/proxy/nginx.conf | 0
files/docker/apis/StorageSummary/Routes.py | 49 +-
.../__pycache__/Routes.cpython-313.pyc | Bin 5706 -> 5538 bytes
.../__pycache__/Storage.cpython-313.pyc | Bin 7493 -> 7493 bytes
files/docker/apis/StorageSummary/app.py | 1 +
.../apis/StorageSummary/storage_api_state.pkl | Bin 0 -> 8528 bytes
files/docker/web/html/index.php | 184 ++++---
files/docker/web/html/src/styles.css | 147 +++++-
files/docker/web/html/test.php | 477 ------------------
files/scripts/check_cosmostat.sh | 2 +
25 files changed, 248 insertions(+), 625 deletions(-)
delete mode 100644 files/api/DriveServer.py
delete mode 100644 files/api/StorageApi.py
rename files/{api => archive}/archive.py (100%)
rename files/{ => archive}/vizz/docker/Dockerfile (100%)
rename files/{ => archive}/vizz/docker/apache_ports.conf (100%)
rename files/{ => archive}/vizz/docker/apache_vhost.conf (100%)
rename files/{ => archive}/vizz/docker/supervisord.conf (100%)
rename files/{ => archive}/vizz/docker/web/html/index.php (100%)
rename files/{ => archive}/vizz/docker/web/html/src/redis.js (100%)
rename files/{ => archive}/vizz/docker/web/html/src/styles.css (100%)
rename files/{ => archive}/vizz/docker/web/html/src/system_metrics.js (100%)
rename files/{ => archive}/vizz/docker/web/html/test.php (100%)
rename files/{ => archive}/vizz/docker/web/node_server/package.json (100%)
rename files/{ => archive}/vizz/docker/web/node_server/server.js (100%)
rename files/{ => archive}/vizz/docker/web/proxy/nginx.conf (100%)
create mode 100644 files/docker/apis/StorageSummary/storage_api_state.pkl
delete mode 100644 files/docker/web/html/test.php
diff --git a/files/api/DriveServer.py b/files/api/DriveServer.py
deleted file mode 100644
index 9a269b9..0000000
--- a/files/api/DriveServer.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# This is the class definition for the remote Storage Systems
-# There will be a StorageLinux and StorageWindows Class, as well as the LocalServer Class
-# The LocalServer class will mostly be a List of Storage server objects and Class functions for interacting with them
-# The actual Storage server Classes will mostly just be collections of variables
diff --git a/files/api/StorageApi.py b/files/api/StorageApi.py
deleted file mode 100644
index b06fc69..0000000
--- a/files/api/StorageApi.py
+++ /dev/null
@@ -1,6 +0,0 @@
-### This file contains the flask routes for interfacing with the DriveServer objects
-### I need routes for adding/updating windows/linux hosts, as well as a query route
-### There needs to also be a Redis handler, meaning also that this will render with PHP
-### but have javascript to update if any Redis data happens
-### This won't happen a lot, but it will happen occasionally
-
diff --git a/files/api/new_descriptors.json b/files/api/new_descriptors.json
index b7f3250..1c4caba 100644
--- a/files/api/new_descriptors.json
+++ b/files/api/new_descriptors.json
@@ -1,6 +1,7 @@
[
{
- "notes:": "this is both a scratch file and a reference for new component descriptors"
+ "notes:": "this is both a scratch file and a reference for new component descriptors",
+ "descriptor descriptor": "the reference descriptor is the next key"
},
{
"name": "",
diff --git a/files/api/archive.py b/files/archive/archive.py
similarity index 100%
rename from files/api/archive.py
rename to files/archive/archive.py
diff --git a/files/vizz/docker/Dockerfile b/files/archive/vizz/docker/Dockerfile
similarity index 100%
rename from files/vizz/docker/Dockerfile
rename to files/archive/vizz/docker/Dockerfile
diff --git a/files/vizz/docker/apache_ports.conf b/files/archive/vizz/docker/apache_ports.conf
similarity index 100%
rename from files/vizz/docker/apache_ports.conf
rename to files/archive/vizz/docker/apache_ports.conf
diff --git a/files/vizz/docker/apache_vhost.conf b/files/archive/vizz/docker/apache_vhost.conf
similarity index 100%
rename from files/vizz/docker/apache_vhost.conf
rename to files/archive/vizz/docker/apache_vhost.conf
diff --git a/files/vizz/docker/supervisord.conf b/files/archive/vizz/docker/supervisord.conf
similarity index 100%
rename from files/vizz/docker/supervisord.conf
rename to files/archive/vizz/docker/supervisord.conf
diff --git a/files/vizz/docker/web/html/index.php b/files/archive/vizz/docker/web/html/index.php
similarity index 100%
rename from files/vizz/docker/web/html/index.php
rename to files/archive/vizz/docker/web/html/index.php
diff --git a/files/vizz/docker/web/html/src/redis.js b/files/archive/vizz/docker/web/html/src/redis.js
similarity index 100%
rename from files/vizz/docker/web/html/src/redis.js
rename to files/archive/vizz/docker/web/html/src/redis.js
diff --git a/files/vizz/docker/web/html/src/styles.css b/files/archive/vizz/docker/web/html/src/styles.css
similarity index 100%
rename from files/vizz/docker/web/html/src/styles.css
rename to files/archive/vizz/docker/web/html/src/styles.css
diff --git a/files/vizz/docker/web/html/src/system_metrics.js b/files/archive/vizz/docker/web/html/src/system_metrics.js
similarity index 100%
rename from files/vizz/docker/web/html/src/system_metrics.js
rename to files/archive/vizz/docker/web/html/src/system_metrics.js
diff --git a/files/vizz/docker/web/html/test.php b/files/archive/vizz/docker/web/html/test.php
similarity index 100%
rename from files/vizz/docker/web/html/test.php
rename to files/archive/vizz/docker/web/html/test.php
diff --git a/files/vizz/docker/web/node_server/package.json b/files/archive/vizz/docker/web/node_server/package.json
similarity index 100%
rename from files/vizz/docker/web/node_server/package.json
rename to files/archive/vizz/docker/web/node_server/package.json
diff --git a/files/vizz/docker/web/node_server/server.js b/files/archive/vizz/docker/web/node_server/server.js
similarity index 100%
rename from files/vizz/docker/web/node_server/server.js
rename to files/archive/vizz/docker/web/node_server/server.js
diff --git a/files/vizz/docker/web/proxy/nginx.conf b/files/archive/vizz/docker/web/proxy/nginx.conf
similarity index 100%
rename from files/vizz/docker/web/proxy/nginx.conf
rename to files/archive/vizz/docker/web/proxy/nginx.conf
diff --git a/files/docker/apis/StorageSummary/Routes.py b/files/docker/apis/StorageSummary/Routes.py
index 2fe819b..a574430 100644
--- a/files/docker/apis/StorageSummary/Routes.py
+++ b/files/docker/apis/StorageSummary/Routes.py
@@ -12,7 +12,6 @@ from requests import RequestException, Response
# import needed Class Libraries
from Storage import *
from Helpers import *
-#SummaryServer = DriveHealthServer(get_hostname())
SummaryServer = load_state()
@@ -20,12 +19,12 @@ if SummaryServer is None:
SummaryServer = DriveHealthServer(get_hostname())
print("Created new SummaryServer")
-# declare flask apps
+# declare flask app
app = Flask(__name__)
-#scheduler = APScheduler()
-
+############################
# Flask routes
+############################
# client update
@app.route('/storage_client_update', methods=['POST'])
@@ -49,7 +48,6 @@ def storage_client_delete():
print(result)
return jsonify(result)
-
# client details
@app.route('/client_details', methods=['GET'])
def client_details():
@@ -86,20 +84,15 @@ def test_route():
"DriveHealthServer": f"{SummaryServer}"
})
-
# test route 2
@app.route('/test_storage_summary', methods=['GET'])
def test_storage_summary():
- return jsonify({
- "message": "Hello world!",
- "hostname": get_hostname(),
- "DriveHealthServer": f"{SummaryServer}"
- })
-
-
+ return test_route()
+############################
# Route Helpers
+############################
# helper function for client_update route
# handles the submission data from the flask route
@@ -112,6 +105,12 @@ def client_update_helper(payload: dict):
result = client_processor(processed_payload)
return result
+# client processing function, add/update logic in Class Methods
+def client_processor(client_dict: dict):
+ result = SummaryServer.process_client_data(client_dict)
+ save_state(SummaryServer)
+ return result
+
# handle submission from remove route
def client_remove_helper(payload: dict):
result = None
@@ -147,30 +146,12 @@ def post_processor(client_dict: dict, required_keys: dict):
client_dict["processed_at"] = time.time()
return client_dict
-# Main functions
-
-# client processing function, add/update logic in Class Methods
-def client_processor(client_dict: dict):
- result = SummaryServer.process_client_data(client_dict)
- save_state(SummaryServer)
- return result
-
-def background_loop():
- return True
+############################
+# Main function
+############################
def run_main():
- #if SummaryServer is none:
-
- #atexit.register(lambda: save_state(SummaryServer)) test
- # Flask scheduler for background loop, run if requested
- #scheduler.add_job(id='background_loop',
- # func=background_loop,
- # trigger='interval',
- # seconds=60)
- #scheduler.init_app(app)
- #scheduler.start()
# Flask API
- background_loop()
app.run(debug=False, host='0.0.0.0', port=5001)
diff --git a/files/docker/apis/StorageSummary/__pycache__/Routes.cpython-313.pyc b/files/docker/apis/StorageSummary/__pycache__/Routes.cpython-313.pyc
index 36b9b84a9f29339a06ec344d5904c702f83b6e8b..ed1dd4fae1cf647f4246fa89f918d1c774c7a50e 100644
GIT binary patch
delta 655
zcmXv~&ubG=5Z>8MVwz-=O|skku!-9=wg!y{S+&$Olr}aOiHBA6Pz<3-rD9@uYZ0Mf
zq~H$(wag`Yv3M$opyUteRRke7A%}{fXIB!u>bwm;nD6^$-pres_xaS@lfj`Z`vf{q
zH-2uu3GW8uu<>!u5YH#qW(?6hniOui*l{!NcvFryYto&WqKL~(JCQl_SW;joZb~`5
z*A<_LknT;p-vQ)$Up#F9qgV8n01CaGiCusaYW`1r%#ZZ^;!vemR>#&Z0Wdr9!
zGB(0py-aB=!wdN9y3VF}p!6S_n2O}l2<~{7DU_4g3LXUGsf*-TE&`p-xMZ4_aIkO`
zEQxHjR}O^$mhqaB@i<*p@qtqDt?)b!+xS&^fiD9ZoW||&4E~9nlf{8lYqtjy+iKB1
z#b{i;L7A`ktCIvBVdN3qUTjA-`k+VAZt?;}S%HI2Fz{BZty;5Dt+F+oSF@L#k6Ge3
zuKMQsU6vp@Ud|cUnT2;?iyYD%`2GWLp?Rmib-PhyEpma(dXDeay!2g3;y2X-74K}a*RB8cwCiHC{4KeK;zzuZam!T2o##D|g~p0&BM)gutu%Z>yhTb0I|$PReMn#hjC
VAhzeS1)>jEMx2HV5*W@<{{UKbl(YZ<
delta 803
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
literal 0
HcmV?d00001
diff --git a/files/docker/web/html/index.php b/files/docker/web/html/index.php
index bfe7cf4..fe07203 100644
--- a/files/docker/web/html/index.php
+++ b/files/docker/web/html/index.php
@@ -9,7 +9,7 @@ date_default_timezone_set('America/Los_Angeles');
$remove_hosts = [];
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
if ($_POST['action'] === 'remove') {
- // The Remove form sends a comma‑separated string of short_id’s
+ // The Remove form sends a comma-separated string of short_id’s
if (!empty($_POST['remove_hosts'])) {
$remove_hosts = array_filter(
explode(',', $_POST['remove_hosts']),
@@ -156,7 +156,7 @@ if (!in_array($mode, $validModes, true)) {
$apiConfig = [
'cosmostat' => ['bind' => '10.200.27.20', 'port' => '5000'],
/*'gali' => ['bind' => '10.200.27.20', 'port' => '5000'], // same as cosmostat*/
- 'drive_health' => ['bind' => '0.0.0.0', 'port' => '5001'], // new API
+ 'drive_health' => ['bind' => '172.25.1.18', 'port' => '5001'], // new API
];
/* ---------- Helper: fetch client details ---------- */
@@ -237,9 +237,6 @@ $systemComponents = $properties['system_components'] ?? [];
$selectedHost = $clients[$selectedIdx]['hostname'] ?? 'Unknown';
-
-/* ---- ---- */
-
/* ---- Sidebar Renderer ---- */
function renderSidebar(string $mode){
@@ -255,74 +252,54 @@ function renderSidebar(string $mode){
';
}
- ?>
-
- Hosts
-
-
-
-
-
+ ?>
+
-
-
-
- Endpoints
-
-
-
-
-
- Shuttle Gali
-
-
+
+
+
+
+
+
+
+
+
+
+
+ Shuttle Gali
+
@@ -344,7 +321,8 @@ function renderMainContent(string $mode){
echo '';
return;
}
- echo '';
+ echo '
+
';
foreach ($selectedHosts as $sid) {
// Find the client that matches this short_id
$c = null;
@@ -357,41 +335,49 @@ function renderMainContent(string $mode){
if ($c === null) continue; // safety
$hostname = $c['name'] ?? 'Unknown';
- echo '
- ';
- echo '
Drive Health - ' . h($hostname) . '
-
IP: '.h($c['ip']).'
- Timestamp: '.date('F j, Y g:i a', (int) $c['timestamp']).'
- ';
+ echo '
+
+
Drive Health - ' . h($hostname) . '
+
IP: '.h($c['ip']).'
+ Timestamp: '.date('F j, Y g:i a', (int) $c['timestamp']).'
+ ';
if (isset($c['drives']) && is_array($c['drives']) && count($c['drives']) > 0) {
- echo '
';
- echo '| Drive Letter | Disk ID | Health Status | Model | Capacity | Power On Hours | Host Writes | Wear Level |
- ';
- echo '
- ';
+ echo '
+
+
+ | Drive Letter | Disk ID | Health Metrics | Model | Serial | Capacity |
+
+ ';
foreach ($c['drives'] as $drive) {
- echo '
- ';
- echo '| ' . h($drive['drive_letter'] ?? '') . ' | ';
- echo '' . h("".$drive['disk_id'] ?? '') . ' | ';
- echo '' . h($drive['health_status'] ?? '') . ' | ';
- echo '' . h($drive['model'] ?? '') . ' | ';
- echo '' . h($drive['capacity'] ?? '') . ' | ';
- echo '' . h($drive['power_on_hours'] ?? '') . ' | ';
- echo '' . h($drive['host_writes'] ?? '') . ' | ';
- echo '' . h($drive['wear_level'] ?? '') . ' | ';
- echo '
- ';
+ $wear_gb = '';
+ if (isset($drive['host_writes'])){
+ $wear_gb = $drive['host_writes'].' wear';
+ }
+ echo '
+
+ | ' . h($drive['drive_letter'] ?? '') . ' |
+ ' . h("".$drive['disk_id'] ?? '') . ' |
+ ' .
+ h($drive['health_status'] ?? '').' '.
+ h($drive['power_on_hours'] ?? '').' '.
+ h($wear_gb ?? '').
+ ' |
+ ' . h($drive['model'] ?? '') . ' |
+ ' . h($drive['serial'] ?? '') . ' |
+ ' . h($drive['capacity'] ?? '') . ' |
+
';
}
- echo '
- ';
+ echo '
+
';
} else {
echo '
No drive data available for this host.
';
}
- echo '
';
+ echo '
+
';
}
- echo '
';
+ echo '
+
';
return;
}
?>
@@ -477,10 +463,12 @@ function renderMainContent(string $mode){
-
-
-
-
+
+
+
+
+
+
@@ -507,11 +495,11 @@ function renderMainContent(string $mode){
diff --git a/files/docker/web/html/src/styles.css b/files/docker/web/html/src/styles.css
index 0140e04..221f96a 100644
--- a/files/docker/web/html/src/styles.css
+++ b/files/docker/web/html/src/styles.css
@@ -6,12 +6,25 @@
--bg-body: #2c3e50; /* main page background */
--bg-card: #34495e; /* card / panel background */
--bg-sidebar: #3d566e; /* sidebar background (slightly lighter) */
- /* Accent / link colour */
+ /* Accent / link color */
--clr-accent: #3498db; /* blue accent for links */
- /* Text colour */
+ /* Text color */
--clr-text: #ecf0f1; /* light whiteish text */
/* Borders / accents */
- --clr-border: #1f2b38; /* dark border colour */
+ --clr-border: #1f2b38; /* dark border color */
+ /* button colors*/
+ --clr-btn-bg: var(--bg-card); /* default button background */
+ --clr-btn-text: var(--clr-text); /* button text color */
+ --clr-btn-border: var(--clr-border); /* border color */
+ --clr-btn-accent: var(--clr-accent); /* hover/focus color */
+ --clr-btn-shadow: rgba(0,0,0,0.3);
+ /* select colors */
+ --clr-select-bg: var(--bg-card); /* dropdown background */
+ --clr-select-text: var(--clr-text); /* option text colour */
+ --clr-select-border: var(--clr-border);
+ --clr-select-accent: var(--clr-accent);/* focus / hover border */
+ --clr-select-shadow: rgba(0,0,0,.3);
+
}
* { box-sizing: border-box; }
@@ -84,7 +97,7 @@ table, th, td {
}
th, td { padding: 10px; }
-/* Alternate row colour for metrics table */
+/* Alternate row color for metrics table */
#host_metrics_table tbody tr td:nth-of-type(even) {
background: #3e5c78; /* slight contrast */
}
@@ -154,7 +167,7 @@ li { margin-bottom: 10px; color: var(--clr-text); }
margin-left: 6px;
margin-right: 8px;
vertical-align: middle;
- background: #808080; /* default – unknown / no timestamp */
+ background: #808080; /* default - unknown / no timestamp */
transition: background-color 1s linear; /* smooth fade */
}
@@ -258,3 +271,127 @@ li { margin-bottom: 10px; color: var(--clr-text); }
}
+/* lets make buttons nice*/
+
+/* 2. Base button style */
+.btn {
+ display: inline-block;
+ padding: .55rem 1.25rem;
+ font-size: .9rem;
+ font-weight: 500;
+ line-height: 1.4;
+ color: var(--clr-btn-text);
+ background: var(--clr-btn-bg);
+ border: 1px solid var(--clr-btn-border);
+ border-radius: .25rem;
+ cursor: pointer;
+ transition: background .15s ease, box-shadow .15s ease, transform .075s ease;
+ text-align: center;
+ user-select: none;
+ vertical-align: middle;
+}
+
+/* 3. Primary button - accent color */
+.btn-primary {
+ background: var(--clr-btn-accent);
+ border-color: var(--clr-btn-accent);
+ color: #fff; /* brighter text for dark button */
+}
+
+/* 4. Secondary button - subtle background */
+.btn-secondary {
+ background: transparent;
+ border-color: var(--clr-btn-accent);
+ color: var(--clr-btn-accent);
+}
+
+/* 5. Hover & focus states */
+.btn:hover,
+.btn:focus-visible {
+ background: #2b3f4c; /* a slightly darker shade of card bg */
+ box-shadow: 0 3px 8px var(--clr-btn-shadow);
+ transform: translateY(-1px);
+ outline: 0;
+}
+
+/* 6. Disabled state */
+.btn:disabled,
+.btn[aria-disabled="true"] {
+ opacity: .55;
+ cursor: not-allowed;
+ background: var(--bg-card);
+ border-color: var(--clr-border);
+}
+
+/* 7. Extra - block‑level button */
+.btn-block {
+ display: block;
+ width: 100%;
+ text-align: center;
+}
+
+/* let's also make the