BE+FE: Unstable devices list (3 status changes in 1h)

Signed-off-by: jokob-sk <jokob.sk@gmail.com>
This commit is contained in:
jokob-sk
2026-02-22 23:12:46 +11:00
parent a26137800d
commit 2f1e5068e3
28 changed files with 207 additions and 87 deletions

View File

@@ -14,22 +14,28 @@ from const import NULL_EQUIVALENTS_SQL # noqa: E402 [flake8 lint suppression]
def get_device_conditions():
network_dev_types = ",".join("'" + v.replace("'", "''") + "'" for v in get_setting_value("NETWORK_DEVICE_TYPES"))
# DO NOT CHANGE ORDER
# Base archived condition
base_active = "devIsArchived=0"
# DO NOT CHANGE ORDER - if you add or change something update graphql endpoint as well
conditions = {
"all": "WHERE devIsArchived=0",
"my": "WHERE devIsArchived=0",
"all": f"WHERE {base_active}",
"my": f"WHERE {base_active}",
"connected": "WHERE devPresentLastScan=1",
"favorites": "WHERE devIsArchived=0 AND devFavorite=1",
"new": "WHERE devIsArchived=0 AND devIsNew=1",
"down": "WHERE devIsArchived=0 AND devAlertDown != 0 AND devPresentLastScan=0",
"offline": "WHERE devIsArchived=0 AND devPresentLastScan=0",
"favorites": f"WHERE {base_active} AND devFavorite=1",
"new": f"WHERE {base_active} AND devIsNew=1",
"down": f"WHERE {base_active} AND devAlertDown != 0 AND devPresentLastScan=0",
"offline": f"WHERE {base_active} AND devPresentLastScan=0",
"archived": "WHERE devIsArchived=1",
"network_devices": f"WHERE devIsArchived=0 AND devType in ({network_dev_types})",
"network_devices_down": f"WHERE devIsArchived=0 AND devType in ({network_dev_types}) AND devPresentLastScan=0",
"unknown": f"WHERE devIsArchived=0 AND devName in ({NULL_EQUIVALENTS_SQL})",
"known": f"WHERE devIsArchived=0 AND devName not in ({NULL_EQUIVALENTS_SQL})",
"favorites_offline": "WHERE devIsArchived=0 AND devFavorite=1 AND devPresentLastScan=0",
"new_online": "WHERE devIsArchived=0 AND devIsNew=1 AND devPresentLastScan=0",
"network_devices": f"WHERE {base_active} AND devType IN ({network_dev_types})",
"network_devices_down": f"WHERE {base_active} AND devType IN ({network_dev_types}) AND devPresentLastScan=0",
"unknown": f"WHERE {base_active} AND devName IN ({NULL_EQUIVALENTS_SQL})",
"known": f"WHERE {base_active} AND devName NOT IN ({NULL_EQUIVALENTS_SQL})",
"favorites_offline": f"WHERE {base_active} AND devFavorite=1 AND devPresentLastScan=0",
"new_online": f"WHERE {base_active} AND devIsNew=1 AND devPresentLastScan=0",
"unstable_devices": f"WHERE {base_active} AND devFlapping=1",
"unstable_favorites": f"WHERE {base_active} AND devFavorite=1 AND devFlapping=1",
"unstable_network_devices": f"WHERE {base_active} AND devType IN ({network_dev_types}) AND devFlapping=1",
}
return conditions

View File

@@ -232,6 +232,87 @@ def ensure_views(sql) -> bool:
""")
FLAP_THRESHOLD = 3
FLAP_WINDOW_HOURS = 1
sql.execute(""" DROP VIEW IF EXISTS DevicesView;""")
sql.execute(f""" CREATE VIEW DevicesView AS
SELECT
rowid,
IFNULL(devMac, '') AS devMac,
IFNULL(devName, '') AS devName,
IFNULL(devOwner, '') AS devOwner,
IFNULL(devType, '') AS devType,
IFNULL(devVendor, '') AS devVendor,
IFNULL(devFavorite, '') AS devFavorite,
IFNULL(devGroup, '') AS devGroup,
IFNULL(devComments, '') AS devComments,
IFNULL(devFirstConnection, '') AS devFirstConnection,
IFNULL(devLastConnection, '') AS devLastConnection,
IFNULL(devLastIP, '') AS devLastIP,
IFNULL(devPrimaryIPv4, '') AS devPrimaryIPv4,
IFNULL(devPrimaryIPv6, '') AS devPrimaryIPv6,
IFNULL(devVlan, '') AS devVlan,
IFNULL(devForceStatus, '') AS devForceStatus,
IFNULL(devStaticIP, '') AS devStaticIP,
IFNULL(devScan, '') AS devScan,
IFNULL(devLogEvents, '') AS devLogEvents,
IFNULL(devAlertEvents, '') AS devAlertEvents,
IFNULL(devAlertDown, '') AS devAlertDown,
IFNULL(devSkipRepeated, '') AS devSkipRepeated,
IFNULL(devLastNotification, '') AS devLastNotification,
IFNULL(devPresentLastScan, 0) AS devPresentLastScan,
IFNULL(devIsNew, '') AS devIsNew,
IFNULL(devLocation, '') AS devLocation,
IFNULL(devIsArchived, '') AS devIsArchived,
IFNULL(devParentMAC, '') AS devParentMAC,
IFNULL(devParentPort, '') AS devParentPort,
IFNULL(devIcon, '') AS devIcon,
IFNULL(devGUID, '') AS devGUID,
IFNULL(devSite, '') AS devSite,
IFNULL(devSSID, '') AS devSSID,
IFNULL(devSyncHubNode, '') AS devSyncHubNode,
IFNULL(devSourcePlugin, '') AS devSourcePlugin,
IFNULL(devCustomProps, '') AS devCustomProps,
IFNULL(devFQDN, '') AS devFQDN,
IFNULL(devParentRelType, '') AS devParentRelType,
IFNULL(devReqNicsOnline, '') AS devReqNicsOnline,
IFNULL(devMacSource, '') AS devMacSource,
IFNULL(devNameSource, '') AS devNameSource,
IFNULL(devFQDNSource, '') AS devFQDNSource,
IFNULL(devLastIPSource, '') AS devLastIPSource,
IFNULL(devVendorSource, '') AS devVendorSource,
IFNULL(devSSIDSource, '') AS devSSIDSource,
IFNULL(devParentMACSource, '') AS devParentMACSource,
IFNULL(devParentPortSource, '') AS devParentPortSource,
IFNULL(devParentRelTypeSource, '') AS devParentRelTypeSource,
IFNULL(devVlanSource, '') AS devVlanSource,
CASE
WHEN devIsNew = 1 THEN 'New'
WHEN devPresentLastScan = 1 THEN 'On-line'
WHEN devPresentLastScan = 0 AND devAlertDown != 0 THEN 'Down'
WHEN devIsArchived = 1 THEN 'Archived'
WHEN devPresentLastScan = 0 THEN 'Off-line'
ELSE 'Unknown status'
END AS devStatus,
CASE
WHEN EXISTS (
SELECT 1
FROM Events e
WHERE e.eve_MAC = Devices.devMac
AND e.eve_EventType IN ('Connected','Disconnected','Device Down','Down Reconnected')
AND e.eve_DateTime >= datetime('now', '-{FLAP_WINDOW_HOURS} hours')
GROUP BY e.eve_MAC
HAVING COUNT(*) >= {FLAP_THRESHOLD}
)
THEN 1
ELSE 0
END AS devFlapping
FROM Devices
""")
return True