initial version
This commit is contained in:
@@ -1,3 +1,7 @@
|
|||||||
# host_session
|
# host-session
|
||||||
|
|
||||||
host session table relateed scripts
|
Stores one row per finished session of the host in the custom table `host_session` (schema 0.0.1): start and end time, duration, mean and max of CPU, RAM and disk percentage, and coverage (share of the session's minutes with a CPU sample). The hub adds the gateway as `spoke_id`.
|
||||||
|
|
||||||
|
Runs every minute. The current boot comes from `/proc/uptime`. The previous session is found in the history of the uptime signal (63) before that boot: its last sample is the end, end minus that sample's uptime is the start. A session already stored (start within two minutes) is skipped, so repeated runs write nothing twice. The first row appears after the first reboot that follows the uptime signal's creation (2026-11-06 18:38).
|
||||||
|
|
||||||
|
Signal ids are deb13-kde's in the home core. Needs only `requests` in the image.
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
SIDECAR_URL = os.getenv("SIDECAR_URL", "http://sidecar:80")
|
||||||
|
DB_URL = os.getenv("DB_CONTROLLER_URL", "http://sidecar:8081")
|
||||||
|
TABLE = "host_session"
|
||||||
|
UPTIME, CPU, RAM, DISK = 63, 21, 22, 23
|
||||||
|
MINUTE_MS = 60000
|
||||||
|
HOUR_MS = 60 * MINUTE_MS
|
||||||
|
LOOKBACK_MS = 60 * 24 * HOUR_MS
|
||||||
|
MATCH_MS = 2 * MINUTE_MS
|
||||||
|
|
||||||
|
|
||||||
|
def read_history(signals, start_ms, end_ms, resolution):
|
||||||
|
names = ",".join(str(signal) for signal in signals)
|
||||||
|
path = f"/api/history/?signals={names}&start={int(start_ms)}&end={int(end_ms)}&resolution={resolution}"
|
||||||
|
response = requests.get(SIDECAR_URL + path, timeout=(5, 80))
|
||||||
|
response.raise_for_status()
|
||||||
|
return {item["signalId"]: item for item in response.json()["data"]["series"]}
|
||||||
|
|
||||||
|
|
||||||
|
def samples(series):
|
||||||
|
start, step = series["startMs"], series["stepMs"]
|
||||||
|
return [(start + i * step, value) for i, value in enumerate(series["values"]) if value is not None]
|
||||||
|
|
||||||
|
|
||||||
|
def last_samples(signal, start_ms, end_ms, resolution):
|
||||||
|
if end_ms <= start_ms:
|
||||||
|
return []
|
||||||
|
found = samples(read_history([signal], start_ms, end_ms, resolution)[signal])
|
||||||
|
return [(t, v) for t, v in found if t < end_ms]
|
||||||
|
|
||||||
|
|
||||||
|
def current_boot_ms():
|
||||||
|
with open("/proc/uptime") as file:
|
||||||
|
uptime_s = float(file.read().split()[0])
|
||||||
|
return int(time.time() * 1000 - uptime_s * 1000)
|
||||||
|
|
||||||
|
|
||||||
|
def previous_session(boot_ms):
|
||||||
|
hours = last_samples(UPTIME, boot_ms - LOOKBACK_MS, boot_ms, "1hr")
|
||||||
|
if not hours:
|
||||||
|
return None
|
||||||
|
minutes = last_samples(UPTIME, hours[-1][0], min(hours[-1][0] + HOUR_MS, boot_ms), "1min")
|
||||||
|
if not minutes:
|
||||||
|
return None
|
||||||
|
seconds = last_samples(UPTIME, minutes[-1][0], min(minutes[-1][0] + MINUTE_MS, boot_ms), "1s")
|
||||||
|
end_ms, uptime_s = (seconds or minutes)[-1]
|
||||||
|
return int(end_ms - uptime_s * 1000), int(end_ms)
|
||||||
|
|
||||||
|
|
||||||
|
def db_call(method, path, payload):
|
||||||
|
response = requests.request(method, DB_URL + path, json=payload, timeout=(5, 30))
|
||||||
|
response.raise_for_status()
|
||||||
|
body = response.json()
|
||||||
|
if body.get("statusCode", 200) != 200:
|
||||||
|
raise RuntimeError(f"db-controller {body.get('statusCode')}: {body.get('errorMessage')}")
|
||||||
|
return body.get("data")
|
||||||
|
|
||||||
|
|
||||||
|
def already_stored(start_ms):
|
||||||
|
rows = db_call("POST", f"/api/db-query/{TABLE}/", {"filters": [], "orderBy": ["start_time"], "limit": 1000}) or []
|
||||||
|
return any(abs(row["start_time"] - start_ms) < MATCH_MS for row in rows)
|
||||||
|
|
||||||
|
|
||||||
|
def mean_max(series, start_ms, end_ms):
|
||||||
|
values = [v for t, v in samples(series) if start_ms <= t < end_ms]
|
||||||
|
if not values:
|
||||||
|
return None, None
|
||||||
|
return sum(values) / len(values), max(values)
|
||||||
|
|
||||||
|
|
||||||
|
def coverage(series, start_ms, end_ms):
|
||||||
|
total = max(1, (end_ms - start_ms) // MINUTE_MS)
|
||||||
|
present = sum(1 for t, _ in samples(series) if start_ms <= t < end_ms)
|
||||||
|
return min(1.0, present / total)
|
||||||
|
|
||||||
|
|
||||||
|
def build_row(start_ms, end_ms):
|
||||||
|
history = read_history([CPU, RAM, DISK], start_ms, end_ms, "1min")
|
||||||
|
row = {"start_time": start_ms, "end_time": end_ms, "duration_s": (end_ms - start_ms) // 1000}
|
||||||
|
for prefix, signal in (("cpu", CPU), ("ram", RAM), ("disk", DISK)):
|
||||||
|
row[f"{prefix}_mean"], row[f"{prefix}_max"] = mean_max(history[signal], start_ms, end_ms)
|
||||||
|
row["coverage"] = coverage(history[CPU], start_ms, end_ms)
|
||||||
|
return row
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
session = previous_session(current_boot_ms())
|
||||||
|
if session is None:
|
||||||
|
print("no previous session in the uptime history", flush=True)
|
||||||
|
return
|
||||||
|
if already_stored(session[0]):
|
||||||
|
print("previous session already stored", session[0], flush=True)
|
||||||
|
return
|
||||||
|
row = build_row(*session)
|
||||||
|
print("stored", db_call("POST", f"/api/db/{TABLE}/", row), row, flush=True)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
name: host-session
|
||||||
|
active: true
|
||||||
|
schedule: "* * * * *"
|
||||||
|
action: run
|
||||||
|
runOnStartup: true
|
||||||
|
timeoutSeconds: 120
|
||||||
|
imageName: docker.izazpi.cloud/infra/infra-python:0.1.12
|
||||||
|
command: ["python", "-u", "/app/main.py"]
|
||||||
|
maxCpuCores: 0.25
|
||||||
|
maxMemoryMb: 128
|
||||||
|
autoremove: false
|
||||||
|
logOption: 1
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
- { id: 21, name: 'deb13kde-cpu', read: 1, write: 0 }
|
||||||
|
- { id: 22, name: 'deb13kde-ram', read: 1, write: 0 }
|
||||||
|
- { id: 23, name: 'deb13kde-disk', read: 1, write: 0 }
|
||||||
|
- { id: 63, name: 'deb13kde-uptime', read: 1, write: 0 }
|
||||||
Reference in New Issue
Block a user