From ecafc5a48a9eb335b245f5d6e180950b6505aa7d Mon Sep 17 00:00:00 2001 From: Christoph Gasser Date: Tue, 19 May 2026 18:02:03 +0200 Subject: [PATCH] Remove players deleted from Yodeck instead of showing them as offline Poll loop now deletes DB rows for players no longer returned by the Yodeck API, and Zabbix sync deletes the corresponding hosts from the Yodeck Players group. Both actions are reflected in the activity log. Co-Authored-By: Claude Sonnet 4.6 --- app/database.py | 12 ++++++++++++ app/scheduler.py | 6 +++++- app/zabbix.py | 18 +++++++++++++++++- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/app/database.py b/app/database.py index c7ac77d..208f943 100644 --- a/app/database.py +++ b/app/database.py @@ -115,6 +115,18 @@ def upsert_player(p): conn.close() +def delete_players_not_in(ids): + if not ids: + return 0 + placeholders = ','.join('?' * len(ids)) + conn = _conn() + cur = conn.execute(f'DELETE FROM players WHERE id NOT IN ({placeholders})', ids) + deleted = cur.rowcount + conn.commit() + conn.close() + return deleted + + def get_all_players(): conn = _conn() rows = conn.execute('SELECT * FROM players ORDER BY name').fetchall() diff --git a/app/scheduler.py b/app/scheduler.py index 3ad49ea..9780acb 100644 --- a/app/scheduler.py +++ b/app/scheduler.py @@ -14,8 +14,12 @@ def poll_yodeck(): players = yd.get_all_screens() for p in players: db.upsert_player(p) + current_ids = [p['id'] for p in players] + removed = db.delete_players_not_in(current_ids) msg = f"Fetched {len(players)} players from Yodeck API" - db.add_log('yodeck_fetch', msg, {'count': len(players)}) + if removed: + msg += f", removed {removed} deleted player(s)" + db.add_log('yodeck_fetch', msg, {'count': len(players), 'removed': removed}) log.info(msg) # Sync host list to Zabbix after a successful fetch sync_to_zabbix(players, db.add_log) diff --git a/app/zabbix.py b/app/zabbix.py index 23622bc..02ae6cd 100644 --- a/app/zabbix.py +++ b/app/zabbix.py @@ -117,6 +117,9 @@ class ZabbixClient: def update_host_name(self, hostid, visible_name): self._call('host.update', {'hostid': hostid, 'name': visible_name}) + def delete_hosts(self, hostids): + self._call('host.delete', hostids) + # ------------------------------------------------------------------ templates def get_template_id(self, name): @@ -260,10 +263,23 @@ def sync_to_zabbix(players, add_log_fn): log.warning("Skipped host %s: %s", hostname, exc) skipped += 1 + current_hostnames = {f"yodeck-{p['id']}" for p in players} + stale = [h for h in existing.values() if h['host'] not in current_hostnames] + deleted = 0 + for h in stale: + try: + zbx.delete_hosts([h['hostid']]) + deleted += 1 + log.info("Deleted stale Zabbix host: %s", h['host']) + except Exception as exc: + log.warning("Could not delete host %s: %s", h['host'], exc) + skipped += 1 + msg = (f"Zabbix sync complete: {created} created, {updated} updated" + + (f", {deleted} deleted" if deleted else "") + (f", {skipped} skipped" if skipped else "") + f" ({len(players)} total)") - add_log_fn('zabbix_sync', msg, {'created': created, 'updated': updated, 'total': len(players)}) + add_log_fn('zabbix_sync', msg, {'created': created, 'updated': updated, 'deleted': deleted, 'total': len(players)}) log.info(msg) except Exception as exc: