voc.infobeamer-cms: add infobeamer-monitor

This commit is contained in:
Franzi 2023-12-26 14:50:24 +01:00
parent 2670d60906
commit b5475df467
Signed by: kunsi
GPG key ID: 12E3D2136B818350
5 changed files with 217 additions and 0 deletions

View file

@ -0,0 +1,4 @@
<%
from tomlkit import dumps as toml_dumps
from bundlewrap.utils.text import toml_clean
%>${toml_clean(toml_dumps(repo.libs.faults.resolve_faults(config), sort_keys=True))}

View file

@ -0,0 +1,15 @@
[Unit]
Description=infobeamer-monitor
After=network.target
[Service]
Type=exec
Restart=always
RestartSec=5s
ExecStart=/opt/infobeamer-cms/venv/bin/python monitor.py
User=infobeamer-cms
Group=infobeamer-cms
WorkingDirectory=/opt/infobeamer-monitor/
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,155 @@
#!/usr/bin/env python3
import logging
from json import dumps
from time import sleep
import paho.mqtt.client as mqtt
from requests import RequestException, get
try:
# python 3.11
from tomllib import loads as toml_load
except ImportError:
from rtoml import load as toml_load
with open("config.toml") as f:
CONFIG = toml_load(f.read())
logging.basicConfig(
format="[%(levelname)s %(name)s] %(message)s",
level=logging.INFO,
)
LOG = logging.getLogger("main")
MLOG = logging.getLogger("mqtt")
state = None
client = mqtt.Client()
client.username_pw_set(CONFIG["mqtt"]["user"], CONFIG["mqtt"]["password"])
client.connect(CONFIG["mqtt"]["host"], 1883, 60)
client.loop_start()
def mqtt_out(message, level="INFO", device=None):
key = "infobeamer"
if device:
key += f"/{device['id']}"
message = f"[{device['description']}] {message}"
client.publish(
CONFIG["mqtt"]["topic"],
dumps(
{
"level": level,
"component": key,
"msg": message,
}
),
)
def mqtt_dump_state(device):
mqtt_out(
"Sync status: {} - Location: {} - Running Setup: {} ({}) - Resolution: {}".format(
"yes" if device["is_synced"] else "unknown",
device["location"],
device["setup"]["name"],
device["setup"]["id"],
device["run"].get("resolution", "unknown"),
),
device=device,
)
mqtt_out("Monitor starting up")
while True:
try:
try:
r = get("https://info-beamer.com/api/v1/device/list", auth=("", CONFIG["api_key"]))
r.raise_for_status()
ib_state = r.json()["devices"]
except RequestException as e:
LOG.exception("Could not get data from info-beamer")
mqtt_out(
f"Could not get data from info-beamer: {e!r}",
level="WARN",
)
else:
new_state = {}
for device in ib_state:
did = str(device["id"])
if did in new_state:
mqtt_out("DUPLICATE DETECTED!", level="ERROR", device=device)
continue
new_state[did] = device
must_dump_state = False
if state is not None:
if did not in state:
LOG.info(
"new device found: {} [{}]".format(
did,
device["description"],
)
)
mqtt_out(
'new device found with name "{}"!'.format(
device["description"]
),
device=device,
)
if device["is_online"]:
must_dump_state = True
else:
if device["is_online"] != state[did]["is_online"]:
online_status = (
"online from {}".format(device["run"]["public_addr"])
if device["is_online"]
else "offline"
)
LOG.info("device {} is now {}".format(did, online_status))
mqtt_out(
f"online status changed to {online_status}",
device=device,
)
if device["is_online"]:
must_dump_state = True
if device["is_online"]:
if device["maintenance"]:
mqtt_out(
"maintenance required: {}".join(
sorted(device["maintenance"])
),
level="WARN",
device=device,
)
if (
device["is_synced"] != state[did]["is_synced"]
or device["location"] != state[did]["location"]
or device["setup"]["name"] != state[did]["setup"]["name"]
or device["run"].get("resolution")
!= state[did]["run"].get("resolution")
):
must_dump_state = True
if must_dump_state:
mqtt_dump_state(device)
else:
LOG.info("adding device {} to empty state".format(device["id"]))
state = new_state
sleep(30)
except KeyboardInterrupt:
break
mqtt_out("Monitor exiting")

View file

@ -0,0 +1,33 @@
assert node.has_bundle('infobeamer-cms') # uses same venv
files['/opt/infobeamer-monitor/config.toml'] = {
'content_type': 'mako',
'context': {
'config': node.metadata.get('infobeamer-monitor'),
},
'triggers': {
'svc_systemd:infobeamer-monitor:restart',
},
}
files['/opt/infobeamer-monitor/monitor.py'] = {
'mode': '0755',
'triggers': {
'svc_systemd:infobeamer-monitor:restart',
},
}
files['/usr/local/lib/systemd/system/infobeamer-monitor.service'] = {
'triggers': {
'action:systemd-reload',
'svc_systemd:infobeamer-monitor:restart',
},
}
svc_systemd['infobeamer-monitor'] = {
'needs': {
'file:/opt/infobeamer-monitor/config.toml',
'file:/opt/infobeamer-monitor/monitor.py',
'file:/usr/local/lib/systemd/system/infobeamer-monitor.service',
},
}

View file

@ -2,6 +2,7 @@ nodes['voc.infobeamer-cms'] = {
'hostname': 'infobeamer-cms.c3voc.de', 'hostname': 'infobeamer-cms.c3voc.de',
'bundles': { 'bundles': {
'infobeamer-cms', 'infobeamer-cms',
'infobeamer-monitor',
'redis', 'redis',
}, },
'groups': { 'groups': {
@ -68,6 +69,15 @@ nodes['voc.infobeamer-cms'] = {
'Translations': 'translations', 'Translations': 'translations',
}, },
}, },
'infobeamer-monitor': {
'api_key': vault.decrypt('encrypt$gAAAAABlitmDR1duKo_4KuMJBF_HbPO2GFo_gdoT1rvUKQ2kkugPbe2RljM4bxW5bmwhs5avjxiaSAvjnOBte9ioyPEr7cIh79WFEfMnsHeexlCHwMt6NV_t-8EAhuuEQEf3Py93g8zQ'),
'mqtt': {
'password': vault.decrypt('encrypt$gAAAAABhxakfhhwWn0vxhoO1FiMEpdCkomWvo0dHIuBrqDKav8WDpI6dXpb0hoXiWRsPV6p5m-8RlbfFbjPhz47AY-nFOOAAW6Yis3-IVD-U-InKJo9dvms='),
'host': 'mqtt.c3voc.de',
'topic': '/voc/alert',
'user': vault.decrypt('encrypt$gAAAAABhxakKHC_kHmHP2mFHorb4niuNTH4F24w1D6m5JUxl117N7znlZA6fpMmY3_NcmBr2Ihw4hL3FjZr9Fm_1oUZ1ZQdADA=='),
},
},
'nginx': { 'nginx': {
'vhosts': { 'vhosts': {
'redirect': { 'redirect': {