Add simple visualization
This commit is contained in:
parent
a79aac5cfd
commit
81fa412202
11
app.py
11
app.py
|
@ -4,7 +4,7 @@ import json
|
|||
import logging
|
||||
import os
|
||||
|
||||
from flask import (Flask, request, jsonify, abort)
|
||||
from flask import (Flask, request, jsonify, abort, render_template)
|
||||
|
||||
from ltsdb_json import LTS
|
||||
|
||||
|
@ -108,3 +108,12 @@ def verify_node(d):
|
|||
else:
|
||||
abort(409, "timestamp out of sync")
|
||||
abort(401, "auth failed")
|
||||
|
||||
@app.get("/v")
|
||||
def visualize():
|
||||
timeseries_ids = request.args.getlist("ts")
|
||||
timeseries_data = []
|
||||
for id in timeseries_ids:
|
||||
ts = LTS(id=id)
|
||||
timeseries_data.append(ts)
|
||||
return render_template("visualize.html", ts=timeseries_data)
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import argparse
|
||||
import hmac
|
||||
import json
|
||||
import os
|
||||
import socket
|
||||
import ssl
|
||||
import time
|
||||
|
||||
import requests
|
||||
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("hostname")
|
||||
ap.add_argument("port", type=int, default=443, nargs="?")
|
||||
args = ap.parse_args()
|
||||
|
||||
# It's a bit weird that this works.
|
||||
myhostname = socket.gethostbyaddr(socket.gethostname())[0]
|
||||
|
||||
now = time.time()
|
||||
report0 = []
|
||||
|
||||
with socket.create_connection((args.hostname, args.port)) as sock:
|
||||
context = ssl.create_default_context()
|
||||
with context.wrap_socket(sock, server_hostname=args.hostname) as ssock:
|
||||
cert = ssock.getpeercert()
|
||||
not_after = ssl.cert_time_to_seconds(cert["notAfter"])
|
||||
delta = not_after - now
|
||||
report0.append({ "measure": "tls_cert_ttl", "unit": "s", "value": delta })
|
||||
|
||||
report = [
|
||||
{
|
||||
"description": {
|
||||
"hostname": args.hostname,
|
||||
"port": args.port,
|
||||
"measure": r["measure"],
|
||||
"unit": r["unit"]
|
||||
},
|
||||
"data": [
|
||||
[now, r["value"]]
|
||||
]
|
||||
}
|
||||
for r in report0
|
||||
]
|
||||
|
||||
for dir in (".", os.environ["HOME"] + "/.config/ltsdb", "/etc/ltsdb"):
|
||||
try:
|
||||
with open(dir + "/config.json") as fh:
|
||||
client_config = json.load(fh)
|
||||
baseurl = client_config["server"]
|
||||
break
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
while True:
|
||||
for r in report:
|
||||
node = myhostname
|
||||
timestamp = time.time()
|
||||
msg = (node + " " + str(timestamp)).encode("UTF-8")
|
||||
digest = hmac.new(client_config["key"].encode("UTF-8"), msg, "SHA256").hexdigest()
|
||||
r["auth"] = {
|
||||
"node": node,
|
||||
"timestamp": timestamp,
|
||||
"hmac": digest,
|
||||
}
|
||||
#pprint.pp(report)
|
||||
r = requests.post(baseurl + "report", json=report)
|
||||
print(r)
|
||||
if r.status_code == 200:
|
||||
exit(0)
|
||||
elif r.status_code == 409:
|
||||
time.sleep(0.5 + random.random())
|
||||
continue
|
||||
else:
|
||||
exit(1)
|
|
@ -90,3 +90,12 @@ class LTS:
|
|||
result &= ts
|
||||
return result
|
||||
|
||||
def data_json_by_row(self):
|
||||
d = []
|
||||
for dp in self.data:
|
||||
d.append({
|
||||
"t": dp[0],
|
||||
"v": dp[1],
|
||||
"utc": time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime(dp[0])),
|
||||
})
|
||||
return json.dumps(d)
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width; initial-scale=1">
|
||||
<meta charset="utf-8">
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/vega@5.22.1"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vega-lite@5.6.0"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vega-embed@6.21.0"></script>
|
||||
<style>
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
.vega {
|
||||
width: min(90vw, 1000px);
|
||||
}
|
||||
th {
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
{% for t in ts %}
|
||||
<table>
|
||||
{% for k, v in t.description.items() %}
|
||||
<tr>
|
||||
<th> {{ k }} </th>
|
||||
<td> {{ v }} </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<th> period </th>
|
||||
<td>
|
||||
{{ t.data[0][0] }} .. {{ t.data[-1][0] }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div id="vis{{loop.index}}" class="vega">
|
||||
|
||||
</div>
|
||||
<script>
|
||||
{
|
||||
const d = {
|
||||
width: "container",
|
||||
data: {
|
||||
values: {{ t.data_json_by_row() | safe }}
|
||||
},
|
||||
mark: "point",
|
||||
encoding: {
|
||||
x: {
|
||||
field: "utc",
|
||||
// type: "quantitative",
|
||||
type: "temporal",
|
||||
//scale: { domain: [{{t.data[0][0]}}, {{t.data[-1][0]}}] },
|
||||
},
|
||||
y: { field: "v", type: "quantitative" },
|
||||
},
|
||||
}
|
||||
vegaEmbed("#vis{{loop.index}}", d)
|
||||
}
|
||||
</script>
|
||||
{% endfor %}
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue