mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2026-04-02 16:22:20 -07:00
BE+FE: Unstable devices list (3 status changes in 1h)
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
This commit is contained in:
@@ -338,7 +338,7 @@ class DeviceInstance:
|
||||
for key, condition in conditions.items():
|
||||
# Make sure the alias is SQL-safe (no spaces or special chars)
|
||||
alias = key.replace(" ", "_").lower()
|
||||
sub_queries.append(f'(SELECT COUNT(*) FROM Devices {condition}) AS "{alias}"')
|
||||
sub_queries.append(f'(SELECT COUNT(*) FROM DevicesView {condition}) AS "{alias}"')
|
||||
|
||||
# Join all sub-selects with commas
|
||||
query = "SELECT\n " + ",\n ".join(sub_queries)
|
||||
@@ -360,7 +360,7 @@ class DeviceInstance:
|
||||
for key, condition in conditions.items():
|
||||
# Make sure the alias is SQL-safe (no spaces or special chars)
|
||||
alias = key.replace(" ", "_").lower()
|
||||
sub_queries.append(f'(SELECT COUNT(*) FROM Devices {condition}) AS "{alias}"')
|
||||
sub_queries.append(f'(SELECT COUNT(*) FROM DevicesView {condition}) AS "{alias}"')
|
||||
|
||||
# Join all sub-selects with commas
|
||||
query = "SELECT\n " + ",\n ".join(sub_queries)
|
||||
@@ -381,7 +381,8 @@ class DeviceInstance:
|
||||
# Build condition for SQL
|
||||
condition = get_device_condition_by_status(status) if status else ""
|
||||
|
||||
query = f"SELECT * FROM Devices {condition}"
|
||||
# Only DevicesView has devFlapping
|
||||
query = f"SELECT * FROM DevicesView {condition}"
|
||||
sql.execute(query)
|
||||
|
||||
table_data = []
|
||||
|
||||
@@ -218,3 +218,50 @@ class EventInstance:
|
||||
|
||||
# Return as list
|
||||
return [row[0], row[1], row[2], row[3], row[4], row[5]]
|
||||
|
||||
def get_unstable_devices(self, hours: int = 1, threshold: int = 3, macs_only: bool = True):
|
||||
"""
|
||||
Return unstable devices based on flap detection.
|
||||
|
||||
A device is considered unstable if it has >= threshold events within the last `hours`.
|
||||
|
||||
Events considered:
|
||||
- Connected
|
||||
- Disconnected
|
||||
- Device Down
|
||||
- Down Reconnected
|
||||
|
||||
Args:
|
||||
hours (int): Time window in hours (default: 1)
|
||||
threshold (int): Minimum number of events to be considered unstable (default: 3)
|
||||
macs_only (bool): If True, return only MAC addresses (set). Otherwise return full rows.
|
||||
|
||||
Returns:
|
||||
set[str] OR list[dict]
|
||||
"""
|
||||
|
||||
if hours <= 0 or threshold <= 0:
|
||||
mylog("warn", f"[Events] get_unstable_devices invalid params: hours={hours}, threshold={threshold}")
|
||||
return set() if macs_only else []
|
||||
|
||||
conn = self._conn()
|
||||
|
||||
sql = """
|
||||
SELECT eve_MAC, COUNT(*) as event_count
|
||||
FROM Events
|
||||
WHERE eve_EventType IN ('Connected','Disconnected','Device Down','Down Reconnected')
|
||||
AND eve_DateTime >= datetime('now', ?)
|
||||
GROUP BY eve_MAC
|
||||
HAVING COUNT(*) >= ?
|
||||
"""
|
||||
|
||||
# SQLite expects "-1 hours" format
|
||||
window = f"-{hours} hours"
|
||||
|
||||
rows = conn.execute(sql, (window, threshold)).fetchall()
|
||||
conn.close()
|
||||
|
||||
if macs_only:
|
||||
return {row["eve_MAC"] for row in rows}
|
||||
|
||||
return [dict(row) for row in rows]
|
||||
|
||||
@@ -49,7 +49,7 @@ class PluginObjectInstance:
|
||||
"SELECT * FROM Plugins_Objects WHERE Plugin = ?", (plugin,)
|
||||
)
|
||||
|
||||
def getLastNCreatedPerPLugin(self, plugin, entries=1):
|
||||
def getLastNCreatedPerPlugin(self, plugin, entries=1):
|
||||
return self._fetchall(
|
||||
"""
|
||||
SELECT *
|
||||
|
||||
Reference in New Issue
Block a user