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 logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from flask import (Flask, request, jsonify, abort)
|
from flask import (Flask, request, jsonify, abort, render_template)
|
||||||
|
|
||||||
from ltsdb_json import LTS
|
from ltsdb_json import LTS
|
||||||
|
|
||||||
|
@ -108,3 +108,12 @@ def verify_node(d):
|
||||||
else:
|
else:
|
||||||
abort(409, "timestamp out of sync")
|
abort(409, "timestamp out of sync")
|
||||||
abort(401, "auth failed")
|
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
|
result &= ts
|
||||||
return result
|
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