@oneuptime/common 11.4.1 → 11.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Models/DatabaseModels/AIRun.ts +50 -0
- package/Models/DatabaseModels/AlertSeverity.ts +6 -0
- package/Models/DatabaseModels/IncidentSeverity.ts +6 -0
- package/Models/DatabaseModels/Index.ts +16 -0
- package/Models/DatabaseModels/IoTDeviceCredential.ts +471 -0
- package/Models/DatabaseModels/LlmLog.ts +56 -0
- package/Models/DatabaseModels/LlmProvider.ts +33 -0
- package/Models/DatabaseModels/NetworkDevice.ts +1385 -0
- package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +717 -0
- package/Models/DatabaseModels/NetworkDeviceLabelRule.ts +514 -0
- package/Models/DatabaseModels/NetworkDeviceOwnerRule.ts +596 -0
- package/Models/DatabaseModels/NetworkDeviceOwnerTeam.ts +487 -0
- package/Models/DatabaseModels/NetworkDeviceOwnerUser.ts +486 -0
- package/Models/DatabaseModels/NetworkInterface.ts +563 -0
- package/Models/DatabaseModels/Project.ts +145 -0
- package/Models/DatabaseModels/TelemetryEntityRelationship.ts +54 -0
- package/Server/API/AIInvestigationAPI.ts +131 -63
- package/Server/API/AlertAPI.ts +5 -0
- package/Server/API/IncidentAPI.ts +10 -0
- package/Server/API/IncidentEpisodeAPI.ts +5 -0
- package/Server/API/LlmProviderAPI.ts +4 -0
- package/Server/API/ScheduledMaintenanceAPI.ts +5 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783650000000-AddAdditionalParamsToLlmProvider.ts +19 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783695782697-AddCacheTokenColumnsToLlmLog.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783701585317-AddAlertInvestigationGating.ts +31 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783702431535-AddAiDailyAutonomousTokenLimitToProject.ts +19 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783720000000-AddNetworkDeviceTables.ts +105 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783721121260-AddAttemptCountToAIRun.ts +15 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783730000000-AddNetworkDeviceOwnersAndRules.ts +192 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783740000000-AddNetworkDeviceDiscoveryScan.ts +37 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783750000000-AddLldpNeighborsToNetworkDevice.ts +19 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783760576655-AddInvestigationTuningToProject.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783762505482-AddTelemetryEntityRelationshipMetrics.ts +31 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783780000000-AddIoTDeviceCredentialTable.ts +79 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1783790000000-AddSnmpV3AuthColumnsToNetworkDevice.ts +49 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +24 -0
- package/Server/Services/AIRunService.ts +58 -0
- package/Server/Services/AIService.ts +101 -0
- package/Server/Services/IncidentService.ts +14 -41
- package/Server/Services/Index.ts +14 -0
- package/Server/Services/IoTDeviceCredentialService.ts +351 -0
- package/Server/Services/IoTDeviceService.ts +64 -21
- package/Server/Services/LlmLogService.ts +26 -0
- package/Server/Services/LlmProviderService.ts +3 -0
- package/Server/Services/MonitorService.ts +4 -1
- package/Server/Services/NetworkDeviceDiscoveryScanService.ts +10 -0
- package/Server/Services/NetworkDeviceLabelRuleEngineService.ts +204 -0
- package/Server/Services/NetworkDeviceLabelRuleService.ts +14 -0
- package/Server/Services/NetworkDeviceOwnerRuleEngineService.ts +222 -0
- package/Server/Services/NetworkDeviceOwnerRuleService.ts +14 -0
- package/Server/Services/NetworkDeviceOwnerTeamService.ts +10 -0
- package/Server/Services/NetworkDeviceOwnerUserService.ts +10 -0
- package/Server/Services/NetworkDeviceService.ts +50 -0
- package/Server/Services/NetworkInterfaceService.ts +10 -0
- package/Server/Services/TelemetryEntityRelationshipService.ts +23 -0
- package/Server/Services/TelemetryEntityService.ts +72 -2
- package/Server/Utils/AI/Sentinel/AlertInvestigationRunner.ts +244 -12
- package/Server/Utils/AI/Sentinel/IncidentInvestigationRunner.ts +92 -19
- package/Server/Utils/AI/Sentinel/InvestigationQueue.ts +493 -0
- package/Server/Utils/AI/Sentinel/SentinelInvestigationEngine.ts +88 -68
- package/Server/Utils/AI/Toolbox/Index.ts +2 -1
- package/Server/Utils/AI/Toolbox/MetricTools.ts +391 -0
- package/Server/Utils/LLM/LLMService.ts +21 -0
- package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +170 -2
- package/Server/Utils/Monitor/IoTDeviceAbsenceSeries.ts +101 -0
- package/Server/Utils/Monitor/MonitorAlert.ts +15 -3
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +1 -1
- package/Server/Utils/Monitor/MonitorIncident.ts +19 -3
- package/Server/Utils/Monitor/MonitorMetricUtil.ts +87 -0
- package/Server/Utils/Monitor/MonitorResource.ts +77 -21
- package/Server/Utils/Monitor/MonitorTemplateUtil.ts +1 -1
- package/Server/Utils/Monitor/NetworkDeviceHydrationUtil.ts +201 -0
- package/Server/Utils/Monitor/NetworkInventoryUtil.ts +215 -0
- package/Server/Utils/Monitor/SnmpInterfaceRateUtil.ts +169 -0
- package/Tests/Server/Services/AIServiceDailyBudget.test.ts +173 -0
- package/Tests/Server/Services/IncidentInternalNoteAnnouncement.test.ts +97 -0
- package/Tests/Server/Services/IoTDeviceService.test.ts +54 -0
- package/Tests/Server/Utils/AI/BaselineAnomalyTool.test.ts +253 -0
- package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +44 -0
- package/Tests/Server/Utils/AI/SentinelAlertGating.test.ts +360 -0
- package/Tests/Server/Utils/AI/SentinelInvestigationQueue.test.ts +295 -0
- package/Tests/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.test.ts +59 -0
- package/Tests/Server/Utils/Monitor/IoTDeviceAbsenceSeries.test.ts +113 -0
- package/Tests/Server/Utils/Monitor/PerSeriesRecoveryResolution.test.ts +198 -0
- package/Tests/Types/Monitor/MonitorType.test.ts +1 -1
- package/Tests/Utils/Monitor/LatencyMatrixUtil.test.ts +111 -0
- package/Types/AI/AIRunStatus.ts +9 -0
- package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +0 -1
- package/Types/Dashboard/DashboardComponents/DashboardLogChartComponent.ts +8 -3
- package/Types/LlmLogStatus.ts +1 -0
- package/Types/Monitor/CriteriaFilter.ts +5 -0
- package/Types/Monitor/IotAlertTemplates.ts +22 -3
- package/Types/Monitor/LatencyMatrix.ts +27 -0
- package/Types/Monitor/MonitorCriteriaInstance.ts +2 -2
- package/Types/Monitor/MonitorMetricType.ts +10 -0
- package/Types/Monitor/MonitorStep.ts +36 -11
- package/Types/Monitor/MonitorStepNetworkDeviceMonitor.ts +55 -0
- package/Types/Monitor/MonitorStepSnmpMonitor.ts +8 -0
- package/Types/Monitor/MonitorType.ts +14 -9
- package/Types/Monitor/SnmpMonitor/LldpNeighbor.ts +12 -0
- package/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.ts +116 -0
- package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +29 -0
- package/Types/Monitor/SnmpMonitor/SnmpInterface.ts +31 -0
- package/Types/Monitor/SnmpMonitor/SnmpMonitorResponse.ts +24 -0
- package/Types/Monitor/SnmpMonitor/SnmpTrap.ts +20 -0
- package/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.ts +173 -0
- package/Types/Permission.ts +314 -0
- package/Types/Probe/ProbeMonitorResponse.ts +8 -0
- package/UI/Components/Icon/Icon.tsx +8 -6
- package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +2 -2
- package/UI/Components/Tabs/Tabs.tsx +10 -1
- package/UI/Utils/Navigation.ts +10 -1
- package/Utils/Dashboard/Components/DashboardLogChartComponent.ts +16 -21
- package/Utils/Monitor/LatencyMatrixUtil.ts +162 -0
- package/Utils/Monitor/MonitorMetricType.ts +71 -1
- package/Utils/Monitor/NetworkTopologyUtil.ts +159 -0
- package/Utils/Telemetry/EntityRelationship.ts +11 -0
- package/build/dist/Models/DatabaseModels/AIRun.js +52 -0
- package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertSeverity.js +6 -0
- package/build/dist/Models/DatabaseModels/AlertSeverity.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentSeverity.js +6 -0
- package/build/dist/Models/DatabaseModels/IncidentSeverity.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +16 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IoTDeviceCredential.js +493 -0
- package/build/dist/Models/DatabaseModels/IoTDeviceCredential.js.map +1 -0
- package/build/dist/Models/DatabaseModels/LlmLog.js +58 -0
- package/build/dist/Models/DatabaseModels/LlmLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/LlmProvider.js +33 -0
- package/build/dist/Models/DatabaseModels/LlmProvider.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +1426 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +738 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceLabelRule.js +522 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceLabelRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerRule.js +603 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerTeam.js +503 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerTeam.js.map +1 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerUser.js +502 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerUser.js.map +1 -0
- package/build/dist/Models/DatabaseModels/NetworkInterface.js +589 -0
- package/build/dist/Models/DatabaseModels/NetworkInterface.js.map +1 -0
- package/build/dist/Models/DatabaseModels/Project.js +147 -0
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TelemetryEntityRelationship.js +57 -0
- package/build/dist/Models/DatabaseModels/TelemetryEntityRelationship.js.map +1 -1
- package/build/dist/Server/API/AIInvestigationAPI.js +95 -55
- package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
- package/build/dist/Server/API/AlertAPI.js +5 -0
- package/build/dist/Server/API/AlertAPI.js.map +1 -1
- package/build/dist/Server/API/IncidentAPI.js +10 -0
- package/build/dist/Server/API/IncidentAPI.js.map +1 -1
- package/build/dist/Server/API/IncidentEpisodeAPI.js +5 -0
- package/build/dist/Server/API/IncidentEpisodeAPI.js.map +1 -1
- package/build/dist/Server/API/LlmProviderAPI.js +5 -7
- package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
- package/build/dist/Server/API/ScheduledMaintenanceAPI.js +5 -0
- package/build/dist/Server/API/ScheduledMaintenanceAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783650000000-AddAdditionalParamsToLlmProvider.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783650000000-AddAdditionalParamsToLlmProvider.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783695782697-AddCacheTokenColumnsToLlmLog.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783695782697-AddCacheTokenColumnsToLlmLog.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783701585317-AddAlertInvestigationGating.js +18 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783701585317-AddAlertInvestigationGating.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783702431535-AddAiDailyAutonomousTokenLimitToProject.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783702431535-AddAiDailyAutonomousTokenLimitToProject.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783720000000-AddNetworkDeviceTables.js +51 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783720000000-AddNetworkDeviceTables.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783721121260-AddAttemptCountToAIRun.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783721121260-AddAttemptCountToAIRun.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783730000000-AddNetworkDeviceOwnersAndRules.js +101 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783730000000-AddNetworkDeviceOwnersAndRules.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783740000000-AddNetworkDeviceDiscoveryScan.js +18 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783740000000-AddNetworkDeviceDiscoveryScan.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783750000000-AddLldpNeighborsToNetworkDevice.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783750000000-AddLldpNeighborsToNetworkDevice.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783760576655-AddInvestigationTuningToProject.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783760576655-AddInvestigationTuningToProject.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783762505482-AddTelemetryEntityRelationshipMetrics.js +16 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783762505482-AddTelemetryEntityRelationshipMetrics.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783780000000-AddIoTDeviceCredentialTable.js +38 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783780000000-AddIoTDeviceCredentialTable.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783790000000-AddSnmpV3AuthColumnsToNetworkDevice.js +22 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783790000000-AddSnmpV3AuthColumnsToNetworkDevice.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +24 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AIRunService.js +33 -0
- package/build/dist/Server/Services/AIRunService.js.map +1 -1
- package/build/dist/Server/Services/AIService.js +82 -9
- package/build/dist/Server/Services/AIService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +14 -25
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +14 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/IoTDeviceCredentialService.js +321 -0
- package/build/dist/Server/Services/IoTDeviceCredentialService.js.map +1 -0
- package/build/dist/Server/Services/IoTDeviceService.js +49 -15
- package/build/dist/Server/Services/IoTDeviceService.js.map +1 -1
- package/build/dist/Server/Services/LlmLogService.js +29 -0
- package/build/dist/Server/Services/LlmLogService.js.map +1 -1
- package/build/dist/Server/Services/LlmProviderService.js +3 -0
- package/build/dist/Server/Services/LlmProviderService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +2 -1
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +9 -0
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -0
- package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js +166 -0
- package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/NetworkDeviceLabelRuleService.js +13 -0
- package/build/dist/Server/Services/NetworkDeviceLabelRuleService.js.map +1 -0
- package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js +186 -0
- package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/NetworkDeviceOwnerRuleService.js +13 -0
- package/build/dist/Server/Services/NetworkDeviceOwnerRuleService.js.map +1 -0
- package/build/dist/Server/Services/NetworkDeviceOwnerTeamService.js +9 -0
- package/build/dist/Server/Services/NetworkDeviceOwnerTeamService.js.map +1 -0
- package/build/dist/Server/Services/NetworkDeviceOwnerUserService.js +9 -0
- package/build/dist/Server/Services/NetworkDeviceOwnerUserService.js.map +1 -0
- package/build/dist/Server/Services/NetworkDeviceService.js +52 -0
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -0
- package/build/dist/Server/Services/NetworkInterfaceService.js +9 -0
- package/build/dist/Server/Services/NetworkInterfaceService.js.map +1 -0
- package/build/dist/Server/Services/TelemetryEntityRelationshipService.js +22 -0
- package/build/dist/Server/Services/TelemetryEntityRelationshipService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryEntityService.js +64 -2
- package/build/dist/Server/Services/TelemetryEntityService.js.map +1 -1
- package/build/dist/Server/Utils/AI/Sentinel/AlertInvestigationRunner.js +189 -9
- package/build/dist/Server/Utils/AI/Sentinel/AlertInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/Sentinel/IncidentInvestigationRunner.js +84 -17
- package/build/dist/Server/Utils/AI/Sentinel/IncidentInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/Sentinel/InvestigationQueue.js +428 -0
- package/build/dist/Server/Utils/AI/Sentinel/InvestigationQueue.js.map +1 -0
- package/build/dist/Server/Utils/AI/Sentinel/SentinelInvestigationEngine.js +63 -47
- package/build/dist/Server/Utils/AI/Sentinel/SentinelInvestigationEngine.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/Index.js +2 -1
- package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/MetricTools.js +300 -0
- package/build/dist/Server/Utils/AI/Toolbox/MetricTools.js.map +1 -1
- package/build/dist/Server/Utils/LLM/LLMService.js +16 -0
- package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +130 -2
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/IoTDeviceAbsenceSeries.js +81 -0
- package/build/dist/Server/Utils/Monitor/IoTDeviceAbsenceSeries.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +18 -7
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +25 -10
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +69 -3
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +76 -30
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js +147 -0
- package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +167 -0
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/SnmpInterfaceRateUtil.js +93 -0
- package/build/dist/Server/Utils/Monitor/SnmpInterfaceRateUtil.js.map +1 -0
- package/build/dist/Types/AI/AIRunStatus.js +9 -0
- package/build/dist/Types/AI/AIRunStatus.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +0 -1
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
- package/build/dist/Types/LlmLogStatus.js +1 -0
- package/build/dist/Types/LlmLogStatus.js.map +1 -1
- package/build/dist/Types/Monitor/CriteriaFilter.js +5 -0
- package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
- package/build/dist/Types/Monitor/IotAlertTemplates.js +7 -7
- package/build/dist/Types/Monitor/IotAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/LatencyMatrix.js +2 -0
- package/build/dist/Types/Monitor/LatencyMatrix.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +2 -2
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorMetricType.js +9 -0
- package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +22 -9
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepNetworkDeviceMonitor.js +36 -0
- package/build/dist/Types/Monitor/MonitorStepNetworkDeviceMonitor.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorStepSnmpMonitor.js +3 -0
- package/build/dist/Types/Monitor/MonitorStepSnmpMonitor.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorType.js +14 -9
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/Types/Monitor/SnmpMonitor/LldpNeighbor.js +2 -0
- package/build/dist/Types/Monitor/SnmpMonitor/LldpNeighbor.js.map +1 -0
- package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js +89 -0
- package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js.map +1 -0
- package/build/dist/Types/Monitor/SnmpMonitor/NetworkTopology.js +2 -0
- package/build/dist/Types/Monitor/SnmpMonitor/NetworkTopology.js.map +1 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpInterface.js +2 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpInterface.js.map +1 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpTrap.js +2 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpTrap.js.map +1 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.js +137 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.js.map +1 -0
- package/build/dist/Types/Permission.js +280 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/UI/Components/Icon/Icon.js +8 -6
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +2 -2
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
- package/build/dist/UI/Components/Tabs/Tabs.js +3 -1
- package/build/dist/UI/Components/Tabs/Tabs.js.map +1 -1
- package/build/dist/UI/Utils/Navigation.js +11 -1
- package/build/dist/UI/Utils/Navigation.js.map +1 -1
- package/build/dist/Utils/Dashboard/Components/DashboardLogChartComponent.js +17 -20
- package/build/dist/Utils/Dashboard/Components/DashboardLogChartComponent.js.map +1 -1
- package/build/dist/Utils/Monitor/LatencyMatrixUtil.js +89 -0
- package/build/dist/Utils/Monitor/LatencyMatrixUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitorMetricType.js +68 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +112 -0
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -0
- package/build/dist/Utils/Telemetry/EntityRelationship.js.map +1 -1
- package/package.json +1 -1
|
@@ -207,6 +207,65 @@ describe("SnmpMonitorCriteria.isMonitorInstanceCriteriaFilterMet", () => {
|
|
|
207
207
|
expect(result).toBeTruthy();
|
|
208
208
|
expect(result).toContain("equal to OK");
|
|
209
209
|
});
|
|
210
|
+
|
|
211
|
+
test("empty OctetString is NOT coerced to numeric 0 for an 'equal to 0' filter", async () => {
|
|
212
|
+
/*
|
|
213
|
+
* Regression: Number("") === 0, so an empty value used to spuriously
|
|
214
|
+
* satisfy a numeric "== 0" criterion. It must fall through to a string
|
|
215
|
+
* comparison ("" !== "0") and not match.
|
|
216
|
+
*/
|
|
217
|
+
const criteriaFilter: CriteriaFilter = {
|
|
218
|
+
checkOn: CheckOn.SnmpOidValue,
|
|
219
|
+
filterType: FilterType.EqualTo,
|
|
220
|
+
value: "0",
|
|
221
|
+
snmpMonitorOptions: { oid: PSU_OID },
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
const dataToProcess: ProbeMonitorResponse = buildDataToProcess({
|
|
225
|
+
oidResponses: [
|
|
226
|
+
{
|
|
227
|
+
oid: PSU_OID,
|
|
228
|
+
value: "",
|
|
229
|
+
type: SnmpDataType.OctetString,
|
|
230
|
+
},
|
|
231
|
+
],
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
const result: string | null =
|
|
235
|
+
await SnmpMonitorCriteria.isMonitorInstanceCriteriaFilterMet({
|
|
236
|
+
dataToProcess,
|
|
237
|
+
criteriaFilter,
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
expect(result).toBeNull();
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
test("whitespace-only OctetString is NOT coerced to numeric 0", async () => {
|
|
244
|
+
const criteriaFilter: CriteriaFilter = {
|
|
245
|
+
checkOn: CheckOn.SnmpOidValue,
|
|
246
|
+
filterType: FilterType.EqualTo,
|
|
247
|
+
value: "0",
|
|
248
|
+
snmpMonitorOptions: { oid: PSU_OID },
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
const dataToProcess: ProbeMonitorResponse = buildDataToProcess({
|
|
252
|
+
oidResponses: [
|
|
253
|
+
{
|
|
254
|
+
oid: PSU_OID,
|
|
255
|
+
value: " ",
|
|
256
|
+
type: SnmpDataType.OctetString,
|
|
257
|
+
},
|
|
258
|
+
],
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
const result: string | null =
|
|
262
|
+
await SnmpMonitorCriteria.isMonitorInstanceCriteriaFilterMet({
|
|
263
|
+
dataToProcess,
|
|
264
|
+
criteriaFilter,
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
expect(result).toBeNull();
|
|
268
|
+
});
|
|
210
269
|
});
|
|
211
270
|
|
|
212
271
|
describe("SnmpOidValue guards", () => {
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IOT_DEVICE_ID_ATTRIBUTE_KEY,
|
|
3
|
+
buildAbsentIoTDeviceSeries,
|
|
4
|
+
getIoTDeviceAbsenceGroupByKey,
|
|
5
|
+
} from "../../../../Server/Utils/Monitor/IoTDeviceAbsenceSeries";
|
|
6
|
+
import MetricSeriesResult from "../../../../Types/Monitor/MetricMonitor/MetricSeriesResult";
|
|
7
|
+
import MetricSeriesFingerprint from "../../../../Utils/Metrics/MetricSeriesFingerprint";
|
|
8
|
+
import { describe, expect, test } from "@jest/globals";
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
* The absence-series helpers are what turn a silent registered device
|
|
12
|
+
* into a per-device offline incident — pin down the gating and the
|
|
13
|
+
* synthetic-series shape (which must match what the device's real
|
|
14
|
+
* series would carry so incidents dedupe and auto-resolve).
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
function presentSeries(deviceIds: Array<string>): Array<MetricSeriesResult> {
|
|
18
|
+
return deviceIds.map((id: string) => {
|
|
19
|
+
return {
|
|
20
|
+
fingerprint: MetricSeriesFingerprint.computeFingerprint({
|
|
21
|
+
[IOT_DEVICE_ID_ATTRIBUTE_KEY]: id,
|
|
22
|
+
}),
|
|
23
|
+
labels: { [IOT_DEVICE_ID_ATTRIBUTE_KEY]: id },
|
|
24
|
+
// present series carry samples; the builder only reads labels.
|
|
25
|
+
aggregatedResults: [],
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
describe("getIoTDeviceAbsenceGroupByKey", () => {
|
|
31
|
+
test("returns the key only for a pure device.id group-by", () => {
|
|
32
|
+
expect(getIoTDeviceAbsenceGroupByKey(["device.id"])).toBe("device.id");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test.each([
|
|
36
|
+
[[]],
|
|
37
|
+
[["iot.device.type"]],
|
|
38
|
+
[["device.id", "iot.device.type"]],
|
|
39
|
+
[["resource.iot.fleet.name"]],
|
|
40
|
+
])("returns null for %j", (keys: Array<string>) => {
|
|
41
|
+
expect(getIoTDeviceAbsenceGroupByKey(keys)).toBeNull();
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe("buildAbsentIoTDeviceSeries", () => {
|
|
46
|
+
test("emits one empty series per registered-but-absent device", () => {
|
|
47
|
+
const absent: Array<MetricSeriesResult> = buildAbsentIoTDeviceSeries({
|
|
48
|
+
presentSeries: presentSeries(["sensor-1"]),
|
|
49
|
+
expectedDeviceExternalIds: ["sensor-1", "sensor-2", "sensor-3"],
|
|
50
|
+
deviceKey: IOT_DEVICE_ID_ATTRIBUTE_KEY,
|
|
51
|
+
slotCount: 2,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
expect(absent).toHaveLength(2);
|
|
55
|
+
const ids: Array<string> = absent.map((s: MetricSeriesResult) => {
|
|
56
|
+
return String(s.labels["device.id"]);
|
|
57
|
+
});
|
|
58
|
+
expect(ids.sort()).toEqual(["sensor-2", "sensor-3"]);
|
|
59
|
+
|
|
60
|
+
for (const series of absent) {
|
|
61
|
+
// One empty slot per query+formula so criteria alias resolution lines up.
|
|
62
|
+
expect(series.aggregatedResults).toHaveLength(2);
|
|
63
|
+
for (const slot of series.aggregatedResults) {
|
|
64
|
+
expect(slot.data).toEqual([]);
|
|
65
|
+
}
|
|
66
|
+
// Fingerprint must match what the device's REAL series would carry.
|
|
67
|
+
expect(series.fingerprint).toBe(
|
|
68
|
+
MetricSeriesFingerprint.computeFingerprint(series.labels),
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test("device ids are compared byte-exact — no canonicalization", () => {
|
|
74
|
+
/*
|
|
75
|
+
* device.id labels are stored verbatim (unlike host.name). A
|
|
76
|
+
* registered id differing only in case is a DIFFERENT device and
|
|
77
|
+
* must be treated as absent; lowercasing would fork the
|
|
78
|
+
* fingerprint from the real series and break dedupe.
|
|
79
|
+
*/
|
|
80
|
+
const absent: Array<MetricSeriesResult> = buildAbsentIoTDeviceSeries({
|
|
81
|
+
presentSeries: presentSeries(["Sensor-A"]),
|
|
82
|
+
expectedDeviceExternalIds: ["Sensor-A", "sensor-a"],
|
|
83
|
+
deviceKey: IOT_DEVICE_ID_ATTRIBUTE_KEY,
|
|
84
|
+
slotCount: 1,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
expect(absent).toHaveLength(1);
|
|
88
|
+
expect(absent[0]?.labels["device.id"]).toBe("sensor-a");
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("dedupes duplicate registered ids and skips empties", () => {
|
|
92
|
+
const absent: Array<MetricSeriesResult> = buildAbsentIoTDeviceSeries({
|
|
93
|
+
presentSeries: [],
|
|
94
|
+
expectedDeviceExternalIds: ["sensor-1", "sensor-1", ""],
|
|
95
|
+
deviceKey: IOT_DEVICE_ID_ATTRIBUTE_KEY,
|
|
96
|
+
slotCount: 0, // clamps to 1
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
expect(absent).toHaveLength(1);
|
|
100
|
+
expect(absent[0]?.aggregatedResults).toHaveLength(1);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test("returns nothing when every registered device is present", () => {
|
|
104
|
+
const absent: Array<MetricSeriesResult> = buildAbsentIoTDeviceSeries({
|
|
105
|
+
presentSeries: presentSeries(["a", "b"]),
|
|
106
|
+
expectedDeviceExternalIds: ["a", "b"],
|
|
107
|
+
deviceKey: IOT_DEVICE_ID_ATTRIBUTE_KEY,
|
|
108
|
+
slotCount: 1,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
expect(absent).toHaveLength(0);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import MonitorIncident from "../../../../Server/Utils/Monitor/MonitorIncident";
|
|
2
|
+
import MonitorAlert from "../../../../Server/Utils/Monitor/MonitorAlert";
|
|
3
|
+
import Incident from "../../../../Models/DatabaseModels/Incident";
|
|
4
|
+
import Alert from "../../../../Models/DatabaseModels/Alert";
|
|
5
|
+
import MonitorCriteriaInstance from "../../../../Types/Monitor/MonitorCriteriaInstance";
|
|
6
|
+
import Dictionary from "../../../../Types/Dictionary";
|
|
7
|
+
import { describe, expect, it } from "@jest/globals";
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
* Regression tests for per-series offline/online auto-resolve.
|
|
11
|
+
*
|
|
12
|
+
* Per-series offline monitors (Host / Proxmox / Ceph / IoTDevice) pair
|
|
13
|
+
* an OFFLINE criteria that creates incidents (e.g. Min(device_up) < 1)
|
|
14
|
+
* with a RECOVERY criteria that does not (Min(device_up) >= 1), grouped
|
|
15
|
+
* by a device/host key. Exactly one criteria wins per evaluation tick,
|
|
16
|
+
* and the breaching-series set handed to shouldClose{Incident,Alert} is
|
|
17
|
+
* that winning criteria's per-series matches.
|
|
18
|
+
*
|
|
19
|
+
* On the recovery tick the RECOVERY criteria wins, so its matches are
|
|
20
|
+
* the healthy series — NOT breaches. The bug: membership in that set was
|
|
21
|
+
* treated as "still breaching", so the open offline incident's own
|
|
22
|
+
* fingerprint kept it pinned open forever once no other series was down.
|
|
23
|
+
* The fix only counts membership when the matched criteria actually
|
|
24
|
+
* creates incidents/alerts.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
const CREATED_CRITERIA_ID: string = "offline-criteria";
|
|
28
|
+
const TEMPLATE_ID: string = "template-1";
|
|
29
|
+
const DEVICE_FP: string = "fp-device-1";
|
|
30
|
+
|
|
31
|
+
const INCIDENT_AUTO_RESOLVE: Dictionary<Array<string>> = {
|
|
32
|
+
[CREATED_CRITERIA_ID]: [TEMPLATE_ID],
|
|
33
|
+
};
|
|
34
|
+
const ALERT_AUTO_RESOLVE: Dictionary<Array<string>> = {
|
|
35
|
+
[CREATED_CRITERIA_ID]: [TEMPLATE_ID],
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
function incident(fingerprint: string): Incident {
|
|
39
|
+
const i: Incident = new Incident();
|
|
40
|
+
i.createdCriteriaId = CREATED_CRITERIA_ID;
|
|
41
|
+
i.createdIncidentTemplateId = TEMPLATE_ID;
|
|
42
|
+
i.seriesFingerprint = fingerprint;
|
|
43
|
+
return i;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function alert(fingerprint: string): Alert {
|
|
47
|
+
const a: Alert = new Alert();
|
|
48
|
+
a.createdCriteriaId = CREATED_CRITERIA_ID;
|
|
49
|
+
a.seriesFingerprint = fingerprint;
|
|
50
|
+
return a;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function criteria(id: string, creates: boolean): MonitorCriteriaInstance {
|
|
54
|
+
const c: MonitorCriteriaInstance = new MonitorCriteriaInstance();
|
|
55
|
+
c.data!.id = id;
|
|
56
|
+
// Same flag drives both — the templates set createIncidents/createAlerts together.
|
|
57
|
+
c.data!.createIncidents = creates;
|
|
58
|
+
c.data!.createAlerts = creates;
|
|
59
|
+
return c;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function shouldCloseIncident(input: Record<string, unknown>): boolean {
|
|
63
|
+
return (
|
|
64
|
+
MonitorIncident as unknown as {
|
|
65
|
+
shouldCloseIncident: (i: Record<string, unknown>) => boolean;
|
|
66
|
+
}
|
|
67
|
+
).shouldCloseIncident(input);
|
|
68
|
+
}
|
|
69
|
+
function shouldCloseAlert(input: Record<string, unknown>): boolean {
|
|
70
|
+
return (
|
|
71
|
+
MonitorAlert as unknown as {
|
|
72
|
+
shouldCloseAlert: (i: Record<string, unknown>) => boolean;
|
|
73
|
+
}
|
|
74
|
+
).shouldCloseAlert(input);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
describe("Per-series offline/online auto-resolve", () => {
|
|
78
|
+
describe("MonitorIncident.shouldCloseIncident", () => {
|
|
79
|
+
it("RESOLVES on the recovery tick even though the recovered series is in the matched (recovery) criteria's set", () => {
|
|
80
|
+
/*
|
|
81
|
+
* The device is back up: the RECOVERY criteria won, its match set
|
|
82
|
+
* contains the now-healthy device. It must NOT keep the incident open.
|
|
83
|
+
*/
|
|
84
|
+
expect(
|
|
85
|
+
shouldCloseIncident({
|
|
86
|
+
openIncident: incident(DEVICE_FP),
|
|
87
|
+
autoResolveCriteriaInstanceIdIncidentIdsDictionary:
|
|
88
|
+
INCIDENT_AUTO_RESOLVE,
|
|
89
|
+
criteriaInstance: criteria("recovery-criteria", false),
|
|
90
|
+
breachingSeriesFingerprints: new Set<string>([DEVICE_FP]),
|
|
91
|
+
disableSeriesAbsenceResolution: false,
|
|
92
|
+
}),
|
|
93
|
+
).toBe(true);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("keeps the incident open while the device is still down (offline criteria won, series still breaching)", () => {
|
|
97
|
+
expect(
|
|
98
|
+
shouldCloseIncident({
|
|
99
|
+
openIncident: incident(DEVICE_FP),
|
|
100
|
+
autoResolveCriteriaInstanceIdIncidentIdsDictionary:
|
|
101
|
+
INCIDENT_AUTO_RESOLVE,
|
|
102
|
+
criteriaInstance: criteria(CREATED_CRITERIA_ID, true),
|
|
103
|
+
breachingSeriesFingerprints: new Set<string>([DEVICE_FP]),
|
|
104
|
+
disableSeriesAbsenceResolution: false,
|
|
105
|
+
}),
|
|
106
|
+
).toBe(false);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("resolves when this device recovered but another device is still down (offline criteria won, fp absent)", () => {
|
|
110
|
+
expect(
|
|
111
|
+
shouldCloseIncident({
|
|
112
|
+
openIncident: incident(DEVICE_FP),
|
|
113
|
+
autoResolveCriteriaInstanceIdIncidentIdsDictionary:
|
|
114
|
+
INCIDENT_AUTO_RESOLVE,
|
|
115
|
+
criteriaInstance: criteria(CREATED_CRITERIA_ID, true),
|
|
116
|
+
// Only some OTHER device is still breaching the offline criteria.
|
|
117
|
+
breachingSeriesFingerprints: new Set<string>(["fp-device-2"]),
|
|
118
|
+
disableSeriesAbsenceResolution: false,
|
|
119
|
+
}),
|
|
120
|
+
).toBe(true);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("does not resolve on recovery when the creating criteria did not opt into auto-resolve", () => {
|
|
124
|
+
expect(
|
|
125
|
+
shouldCloseIncident({
|
|
126
|
+
openIncident: incident(DEVICE_FP),
|
|
127
|
+
autoResolveCriteriaInstanceIdIncidentIdsDictionary: {}, // not configured
|
|
128
|
+
criteriaInstance: criteria("recovery-criteria", false),
|
|
129
|
+
breachingSeriesFingerprints: new Set<string>([DEVICE_FP]),
|
|
130
|
+
disableSeriesAbsenceResolution: false,
|
|
131
|
+
}),
|
|
132
|
+
).toBe(false);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("still respects the event-driven guard (incoming-request) over recovery resolution", () => {
|
|
136
|
+
expect(
|
|
137
|
+
shouldCloseIncident({
|
|
138
|
+
openIncident: incident(DEVICE_FP),
|
|
139
|
+
autoResolveCriteriaInstanceIdIncidentIdsDictionary:
|
|
140
|
+
INCIDENT_AUTO_RESOLVE,
|
|
141
|
+
criteriaInstance: criteria("recovery-criteria", false),
|
|
142
|
+
breachingSeriesFingerprints: new Set<string>([DEVICE_FP]),
|
|
143
|
+
disableSeriesAbsenceResolution: true,
|
|
144
|
+
}),
|
|
145
|
+
).toBe(false);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
describe("MonitorAlert.shouldCloseAlert", () => {
|
|
150
|
+
it("RESOLVES on the recovery tick even though the recovered series is in the matched (recovery) criteria's set", () => {
|
|
151
|
+
expect(
|
|
152
|
+
shouldCloseAlert({
|
|
153
|
+
openAlert: alert(DEVICE_FP),
|
|
154
|
+
autoResolveCriteriaInstanceIdAlertIdsDictionary: ALERT_AUTO_RESOLVE,
|
|
155
|
+
criteriaInstance: criteria("recovery-criteria", false),
|
|
156
|
+
breachingSeriesFingerprints: new Set<string>([DEVICE_FP]),
|
|
157
|
+
disableSeriesAbsenceResolution: false,
|
|
158
|
+
}),
|
|
159
|
+
).toBe(true);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("keeps the alert open while the device is still down", () => {
|
|
163
|
+
expect(
|
|
164
|
+
shouldCloseAlert({
|
|
165
|
+
openAlert: alert(DEVICE_FP),
|
|
166
|
+
autoResolveCriteriaInstanceIdAlertIdsDictionary: ALERT_AUTO_RESOLVE,
|
|
167
|
+
criteriaInstance: criteria(CREATED_CRITERIA_ID, true),
|
|
168
|
+
breachingSeriesFingerprints: new Set<string>([DEVICE_FP]),
|
|
169
|
+
disableSeriesAbsenceResolution: false,
|
|
170
|
+
}),
|
|
171
|
+
).toBe(false);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it("resolves when this device recovered but another is still down", () => {
|
|
175
|
+
expect(
|
|
176
|
+
shouldCloseAlert({
|
|
177
|
+
openAlert: alert(DEVICE_FP),
|
|
178
|
+
autoResolveCriteriaInstanceIdAlertIdsDictionary: ALERT_AUTO_RESOLVE,
|
|
179
|
+
criteriaInstance: criteria(CREATED_CRITERIA_ID, true),
|
|
180
|
+
breachingSeriesFingerprints: new Set<string>(["fp-device-2"]),
|
|
181
|
+
disableSeriesAbsenceResolution: false,
|
|
182
|
+
}),
|
|
183
|
+
).toBe(true);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it("still respects the event-driven guard over recovery resolution", () => {
|
|
187
|
+
expect(
|
|
188
|
+
shouldCloseAlert({
|
|
189
|
+
openAlert: alert(DEVICE_FP),
|
|
190
|
+
autoResolveCriteriaInstanceIdAlertIdsDictionary: ALERT_AUTO_RESOLVE,
|
|
191
|
+
criteriaInstance: criteria("recovery-criteria", false),
|
|
192
|
+
breachingSeriesFingerprints: new Set<string>([DEVICE_FP]),
|
|
193
|
+
disableSeriesAbsenceResolution: true,
|
|
194
|
+
}),
|
|
195
|
+
).toBe(false);
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
});
|
|
@@ -120,7 +120,7 @@ describe("MonitorTypeHelper", () => {
|
|
|
120
120
|
MonitorType.SSLCertificate,
|
|
121
121
|
MonitorType.SyntheticMonitor,
|
|
122
122
|
MonitorType.CustomJavaScriptCode,
|
|
123
|
-
MonitorType.
|
|
123
|
+
MonitorType.NetworkDevice,
|
|
124
124
|
MonitorType.DNS,
|
|
125
125
|
MonitorType.DNSSEC,
|
|
126
126
|
MonitorType.Domain,
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import LatencyMatrixUtil from "../../../Utils/Monitor/LatencyMatrixUtil";
|
|
2
|
+
import LatencyMatrix, {
|
|
3
|
+
LatencyMatrixCell,
|
|
4
|
+
} from "../../../Types/Monitor/LatencyMatrix";
|
|
5
|
+
|
|
6
|
+
describe("LatencyMatrixUtil.buildMatrix", () => {
|
|
7
|
+
const now: Date = new Date("2026-07-11T12:00:00Z");
|
|
8
|
+
|
|
9
|
+
it("builds a dense grid seeded with no-data cells", () => {
|
|
10
|
+
const matrix: LatencyMatrix = LatencyMatrixUtil.buildMatrix({
|
|
11
|
+
monitors: [{ id: "m1", name: "Ping A" }],
|
|
12
|
+
probes: [
|
|
13
|
+
{ id: "p1", name: "US East" },
|
|
14
|
+
{ id: "p2", name: "EU West" },
|
|
15
|
+
],
|
|
16
|
+
results: [],
|
|
17
|
+
now,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
expect(matrix.monitors).toHaveLength(1);
|
|
21
|
+
expect(matrix.probes).toHaveLength(2);
|
|
22
|
+
expect(matrix.cells["m1"]!["p1"]!.hasData).toBe(false);
|
|
23
|
+
expect(matrix.cells["m1"]!["p2"]!.hasData).toBe(false);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("fills latency, online state, and age from the latest step", () => {
|
|
27
|
+
const matrix: LatencyMatrix = LatencyMatrixUtil.buildMatrix({
|
|
28
|
+
monitors: [{ id: "m1", name: "Ping A" }],
|
|
29
|
+
probes: [{ id: "p1", name: "US East" }],
|
|
30
|
+
results: [
|
|
31
|
+
{
|
|
32
|
+
monitorId: "m1",
|
|
33
|
+
probeId: "p1",
|
|
34
|
+
lastMonitoringLog: {
|
|
35
|
+
step1: {
|
|
36
|
+
responseTimeInMs: 42,
|
|
37
|
+
isOnline: true,
|
|
38
|
+
monitoredAt: "2026-07-11T11:59:00Z",
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
now,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const cell: LatencyMatrixCell = matrix.cells["m1"]!["p1"]!;
|
|
47
|
+
expect(cell.hasData).toBe(true);
|
|
48
|
+
expect(cell.latencyInMs).toBe(42);
|
|
49
|
+
expect(cell.isOnline).toBe(true);
|
|
50
|
+
expect(cell.ageInSeconds).toBe(60);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("picks the most recently monitored step across multiple steps", () => {
|
|
54
|
+
const matrix: LatencyMatrix = LatencyMatrixUtil.buildMatrix({
|
|
55
|
+
monitors: [{ id: "m1", name: "Ping A" }],
|
|
56
|
+
probes: [{ id: "p1", name: "US East" }],
|
|
57
|
+
results: [
|
|
58
|
+
{
|
|
59
|
+
monitorId: "m1",
|
|
60
|
+
probeId: "p1",
|
|
61
|
+
lastMonitoringLog: {
|
|
62
|
+
older: {
|
|
63
|
+
responseTimeInMs: 100,
|
|
64
|
+
isOnline: true,
|
|
65
|
+
monitoredAt: "2026-07-11T10:00:00Z",
|
|
66
|
+
},
|
|
67
|
+
newer: {
|
|
68
|
+
responseTimeInMs: 25,
|
|
69
|
+
isOnline: true,
|
|
70
|
+
monitoredAt: "2026-07-11T11:59:30Z",
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
now,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
expect(matrix.cells["m1"]!["p1"]!.latencyInMs).toBe(25);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("ignores results for unknown monitor/probe pairs", () => {
|
|
82
|
+
const matrix: LatencyMatrix = LatencyMatrixUtil.buildMatrix({
|
|
83
|
+
monitors: [{ id: "m1", name: "Ping A" }],
|
|
84
|
+
probes: [{ id: "p1", name: "US East" }],
|
|
85
|
+
results: [
|
|
86
|
+
{
|
|
87
|
+
monitorId: "ghost",
|
|
88
|
+
probeId: "p1",
|
|
89
|
+
lastMonitoringLog: {
|
|
90
|
+
step1: { responseTimeInMs: 5, monitoredAt: now.toISOString() },
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
now,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
expect(matrix.cells["m1"]!["p1"]!.hasData).toBe(false);
|
|
98
|
+
expect(matrix.cells["ghost"]).toBeUndefined();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("treats an empty log as no data", () => {
|
|
102
|
+
const matrix: LatencyMatrix = LatencyMatrixUtil.buildMatrix({
|
|
103
|
+
monitors: [{ id: "m1", name: "Ping A" }],
|
|
104
|
+
probes: [{ id: "p1", name: "US East" }],
|
|
105
|
+
results: [{ monitorId: "m1", probeId: "p1", lastMonitoringLog: {} }],
|
|
106
|
+
now,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
expect(matrix.cells["m1"]!["p1"]!.hasData).toBe(false);
|
|
110
|
+
});
|
|
111
|
+
});
|
package/Types/AI/AIRunStatus.ts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
enum AIRunStatus {
|
|
2
|
+
/*
|
|
3
|
+
* Durable intent: the run has been recorded but no worker has claimed it
|
|
4
|
+
* yet. Queued runs survive pod restarts — the enqueueing pod tries to
|
|
5
|
+
* process immediately, and the queue poller picks up whatever is left
|
|
6
|
+
* (claims are CAS-guarded, so double-processing is impossible). Not
|
|
7
|
+
* terminal, not consuming compute; the queue's own TTL expires runs that
|
|
8
|
+
* sit here too long to still be useful.
|
|
9
|
+
*/
|
|
10
|
+
Queued = "Queued",
|
|
2
11
|
Running = "Running",
|
|
3
12
|
/*
|
|
4
13
|
* The run paused mid-turn to wait for the user to approve pending tool
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import ObjectID from "../../ObjectID";
|
|
2
2
|
import DashboardComponentType from "../DashboardComponentType";
|
|
3
|
+
import DashboardChartType from "../Chart/ChartType";
|
|
3
4
|
import BaseComponent from "./DashboardBaseComponent";
|
|
4
5
|
|
|
5
6
|
export default interface DashboardLogChartComponent extends BaseComponent {
|
|
@@ -7,12 +8,16 @@ export default interface DashboardLogChartComponent extends BaseComponent {
|
|
|
7
8
|
componentId: ObjectID;
|
|
8
9
|
arguments: {
|
|
9
10
|
title?: string | undefined;
|
|
10
|
-
|
|
11
|
+
chartType?: DashboardChartType | undefined;
|
|
11
12
|
severityFilters?: Array<string> | undefined;
|
|
12
13
|
bodyContains?: string | undefined;
|
|
13
14
|
/*
|
|
14
|
-
* Exact attribute matches
|
|
15
|
-
|
|
15
|
+
* Exact attribute matches stored by the structured key/value editor.
|
|
16
|
+
*/
|
|
17
|
+
attributeFilters?: Record<string, string | number | boolean> | undefined;
|
|
18
|
+
/*
|
|
19
|
+
* Legacy log-search syntax retained as a read-only fallback for widgets
|
|
20
|
+
* saved before the structured attribute editor was introduced.
|
|
16
21
|
*/
|
|
17
22
|
attributeFilterQuery?: string | undefined;
|
|
18
23
|
};
|
package/Types/LlmLogStatus.ts
CHANGED
|
@@ -71,6 +71,10 @@ export enum CheckOn {
|
|
|
71
71
|
SnmpOidExists = "SNMP OID Exists",
|
|
72
72
|
SnmpResponseTime = "SNMP Response Time (in ms)",
|
|
73
73
|
SnmpIsOnline = "SNMP Device Is Online",
|
|
74
|
+
SnmpInterfaceIsDown = "SNMP Interface Is Down",
|
|
75
|
+
SnmpTrapReceived = "SNMP Trap Received (Trap OID)",
|
|
76
|
+
SnmpInterfaceUtilizationPercent = "SNMP Interface Utilization (in %)",
|
|
77
|
+
SnmpInterfaceErrorsPerSecond = "SNMP Interface Errors (per second)",
|
|
74
78
|
|
|
75
79
|
// DNS monitors.
|
|
76
80
|
DnsResponseTime = "DNS Response Time (in ms)",
|
|
@@ -287,6 +291,7 @@ export class CriteriaFilterUtil {
|
|
|
287
291
|
if (
|
|
288
292
|
checkOn === CheckOn.IsOnline ||
|
|
289
293
|
checkOn === CheckOn.SnmpIsOnline ||
|
|
294
|
+
checkOn === CheckOn.SnmpInterfaceIsDown ||
|
|
290
295
|
checkOn === CheckOn.DnsIsOnline ||
|
|
291
296
|
checkOn === CheckOn.DomainIsExpired ||
|
|
292
297
|
checkOn === CheckOn.DnssecChainValid ||
|
|
@@ -3,7 +3,12 @@ import MonitorStep from "./MonitorStep";
|
|
|
3
3
|
import MonitorCriteria from "./MonitorCriteria";
|
|
4
4
|
import MonitorCriteriaInstance from "./MonitorCriteriaInstance";
|
|
5
5
|
import FilterCondition from "../Filter/FilterCondition";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
CheckOn,
|
|
8
|
+
FilterType,
|
|
9
|
+
EvaluateOverTimeType,
|
|
10
|
+
NoDataPolicy,
|
|
11
|
+
} from "./CriteriaFilter";
|
|
7
12
|
import MonitorStepIoTMonitor from "./MonitorStepIoTMonitor";
|
|
8
13
|
import RollingTime from "../RollingTime/RollingTime";
|
|
9
14
|
import MetricsAggregationType from "../Metrics/MetricsAggregationType";
|
|
@@ -102,6 +107,16 @@ export function buildIoTOfflineCriteriaInstance(args: {
|
|
|
102
107
|
incidentDescription?: string;
|
|
103
108
|
criteriaName?: string;
|
|
104
109
|
criteriaDescription?: string;
|
|
110
|
+
/*
|
|
111
|
+
* Evaluate an empty (no data) series as 0 instead of skipping it.
|
|
112
|
+
* This is what lets REGISTERED devices that go completely silent
|
|
113
|
+
* trip the criteria: monitor evaluation injects an empty synthetic
|
|
114
|
+
* series per registered-but-silent device, TreatAsZero folds it to
|
|
115
|
+
* 0, and e.g. Min(iot_device_up) < 1 fires. Only the Device Offline
|
|
116
|
+
* template opts in — treating no-data as zero on a battery or
|
|
117
|
+
* temperature threshold would false-alarm for silent devices.
|
|
118
|
+
*/
|
|
119
|
+
treatNoDataAsZero?: boolean;
|
|
105
120
|
}): MonitorCriteriaInstance {
|
|
106
121
|
const instance: MonitorCriteriaInstance = new MonitorCriteriaInstance();
|
|
107
122
|
|
|
@@ -122,6 +137,9 @@ export function buildIoTOfflineCriteriaInstance(args: {
|
|
|
122
137
|
metricMonitorOptions: {
|
|
123
138
|
metricAggregationType: EvaluateOverTimeType.AnyValue,
|
|
124
139
|
metricAlias: args.metricAlias,
|
|
140
|
+
...(args.treatNoDataAsZero
|
|
141
|
+
? { onNoDataPolicy: NoDataPolicy.TreatAsZero }
|
|
142
|
+
: {}),
|
|
125
143
|
},
|
|
126
144
|
value: args.value,
|
|
127
145
|
},
|
|
@@ -356,10 +374,11 @@ const deviceOfflineTemplate: IoTAlertTemplate = {
|
|
|
356
374
|
filterType: FilterType.LessThan,
|
|
357
375
|
value: 1,
|
|
358
376
|
incidentTitle: `[IoT] Device Offline - ${args.monitorName}`,
|
|
359
|
-
incidentDescription: `An IoT device is reporting as down (iot_device_up = 0). The device is unreachable, powered off, or has lost connectivity to its gateway. Check the root cause for the affected device id, verify the device's power and network state, and confirm its gateway is forwarding telemetry.`,
|
|
377
|
+
incidentDescription: `An IoT device is reporting as down (iot_device_up = 0) or has stopped reporting entirely. The device is unreachable, powered off, or has lost connectivity to its gateway. Check the root cause for the affected device id, verify the device's power and network state, and confirm its gateway is forwarding telemetry.`,
|
|
360
378
|
criteriaName: "Device Offline - iot_device_up < 1",
|
|
361
379
|
criteriaDescription:
|
|
362
|
-
"Triggers when any device reports iot_device_up below 1 over the monitoring window.",
|
|
380
|
+
"Triggers when any device reports iot_device_up below 1 over the monitoring window, or when a registered device goes silent.",
|
|
381
|
+
treatNoDataAsZero: true,
|
|
363
382
|
}),
|
|
364
383
|
onlineCriteriaInstance: buildIoTOnlineCriteriaInstance({
|
|
365
384
|
onlineMonitorStatusId: args.onlineMonitorStatusId,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* A probes × targets latency grid. Each cell is the latest response time a
|
|
3
|
+
* probe measured for a monitor, so operators can see at a glance which
|
|
4
|
+
* probe locations are slow to which targets. Built from each monitor's
|
|
5
|
+
* per-probe last-check snapshot; no new data collection.
|
|
6
|
+
*/
|
|
7
|
+
export interface LatencyMatrixAxisItem {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface LatencyMatrixCell {
|
|
13
|
+
monitorId: string;
|
|
14
|
+
probeId: string;
|
|
15
|
+
hasData: boolean;
|
|
16
|
+
latencyInMs?: number | undefined;
|
|
17
|
+
isOnline?: boolean | undefined;
|
|
18
|
+
// Age of the measurement in seconds, so the UI can dim stale cells.
|
|
19
|
+
ageInSeconds?: number | undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default interface LatencyMatrix {
|
|
23
|
+
monitors: Array<LatencyMatrixAxisItem>;
|
|
24
|
+
probes: Array<LatencyMatrixAxisItem>;
|
|
25
|
+
// Keyed cells[monitorId][probeId].
|
|
26
|
+
cells: Record<string, Record<string, LatencyMatrixCell>>;
|
|
27
|
+
}
|
|
@@ -415,7 +415,7 @@ export default class MonitorCriteriaInstance extends DatabaseProperty {
|
|
|
415
415
|
return monitorCriteriaInstance;
|
|
416
416
|
}
|
|
417
417
|
|
|
418
|
-
if (arg.monitorType === MonitorType.
|
|
418
|
+
if (arg.monitorType === MonitorType.NetworkDevice) {
|
|
419
419
|
const monitorCriteriaInstance: MonitorCriteriaInstance =
|
|
420
420
|
new MonitorCriteriaInstance();
|
|
421
421
|
|
|
@@ -616,7 +616,7 @@ export default class MonitorCriteriaInstance extends DatabaseProperty {
|
|
|
616
616
|
};
|
|
617
617
|
}
|
|
618
618
|
|
|
619
|
-
if (arg.monitorType === MonitorType.
|
|
619
|
+
if (arg.monitorType === MonitorType.NetworkDevice) {
|
|
620
620
|
monitorCriteriaInstance.data = {
|
|
621
621
|
id: ObjectID.generate().toString(),
|
|
622
622
|
monitorStatusId: arg.monitorStatusId,
|