@oneuptime/common 11.4.0 → 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/AIAgentTaskAPI.ts +10 -24
- 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/API/TelemetryAPI.ts +4 -3
- 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/AIAgentTaskService.ts +62 -0
- package/Server/Services/AIRunService.ts +58 -0
- package/Server/Services/AIService.ts +101 -0
- package/Server/Services/AnalyticsDatabaseService.ts +27 -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/LogAggregationService.ts +29 -11
- package/Server/Services/MetricService.ts +603 -13
- 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/README.md +10 -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/APIRequestCriteria.ts +44 -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 +195 -2
- 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/AIAgentTaskServiceClaim.test.ts +146 -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/Services/LogAggregationService.test.ts +22 -0
- package/Tests/Server/Services/MetricServiceAggregate.test.ts +194 -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/AI/AIAgentTaskStatus.test.ts +86 -0
- package/Tests/Types/BaseDatabase/AggregationIntervalUtil.test.ts +127 -0
- package/Tests/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.test.ts +152 -0
- package/Tests/Types/Monitor/MonitorType.test.ts +1 -1
- package/Tests/Types/Trace/TraceRecordingRuleDefinition.test.ts +308 -0
- package/Tests/UI/Components/Dropdown.test.tsx +17 -0
- package/Tests/UI/Components/EntityDropdown.test.tsx +130 -0
- package/Tests/UI/Components/Modal.test.tsx +144 -2
- package/Tests/UI/Components/TelemetrySearchBar.test.tsx +90 -0
- package/Tests/UI/Utils/Theme.test.ts +161 -0
- package/Tests/Utils/Monitor/LatencyMatrixUtil.test.ts +111 -0
- package/Types/AI/AIRunStatus.ts +9 -0
- package/Types/BaseDatabase/AggregateBy.ts +12 -0
- package/Types/Dashboard/DashboardComponentType.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardLogChartComponent.ts +24 -0
- package/Types/Dashboard/DashboardTemplates.ts +9 -1
- package/Types/LlmLogStatus.ts +1 -0
- package/Types/Monitor/CriteriaFilter.ts +9 -0
- package/Types/Monitor/HttpPhaseTimings.ts +16 -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 +27 -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/PingMonitor/PingMonitorResponse.ts +20 -0
- 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 +22 -0
- package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +8 -5
- package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +4 -1
- package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +6 -3
- package/UI/Components/CodeBlock/CodeBlock.tsx +2 -1
- package/UI/Components/CodeEditor/CodeEditor.tsx +3 -0
- package/UI/Components/Divider/Divider.tsx +1 -1
- package/UI/Components/Dropdown/Dropdown.tsx +13 -4
- package/UI/Components/EntityDropdown/EntityDropdown.tsx +110 -2
- package/UI/Components/ErrorBoundary.tsx +2 -1
- package/UI/Components/EventItem/EventItem.tsx +2 -2
- package/UI/Components/GanttChart/Bar/Index.tsx +1 -1
- package/UI/Components/Graphs/UptimeBarTooltip.tsx +30 -23
- package/UI/Components/Header/Header.tsx +7 -0
- package/UI/Components/Header/HeaderIconDropdownButton.tsx +2 -0
- package/UI/Components/Icon/Icon.tsx +8 -6
- package/UI/Components/Label/Label.tsx +2 -2
- package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +22 -10
- package/UI/Components/LogsViewer/components/LogsHistogram.tsx +9 -3
- package/UI/Components/Markdown.tsx/MarkdownEditor.tsx +8 -8
- package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +44 -20
- package/UI/Components/Modal/ConfirmModal.tsx +1 -1
- package/UI/Components/Modal/Modal.tsx +213 -121
- package/UI/Components/Modal/ModalFooter.tsx +33 -22
- package/UI/Components/ModelTable/TableView.tsx +1 -1
- package/UI/Components/MonitorGraphs/UptimeBarDayModal.tsx +20 -12
- package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +2 -2
- package/UI/Components/Pill/Pill.tsx +21 -13
- package/UI/Components/StatusBubble/StatusBubble.tsx +3 -3
- package/UI/Components/Tabs/Tabs.tsx +10 -1
- package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +7 -1
- package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +9 -3
- package/UI/Components/TelemetryViewer/components/TelemetrySearchBar.tsx +62 -4
- package/UI/Components/Workflow/Component.tsx +53 -33
- package/UI/Components/Workflow/ComponentPortViewer.tsx +6 -6
- package/UI/Components/Workflow/ComponentReturnValueViewer.tsx +8 -8
- package/UI/Components/Workflow/ComponentsModal.tsx +16 -9
- package/UI/Components/Workflow/Workflow.tsx +13 -11
- package/UI/Utils/Navigation.ts +10 -1
- package/UI/Utils/Theme.ts +140 -0
- package/Utils/Dashboard/Components/DashboardLogChartComponent.ts +99 -0
- package/Utils/Dashboard/Components/Index.ts +7 -0
- package/Utils/Monitor/LatencyMatrixUtil.ts +162 -0
- package/Utils/Monitor/MonitorMetricType.ts +141 -3
- 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/AIAgentTaskAPI.js +8 -23
- package/build/dist/Server/API/AIAgentTaskAPI.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/API/TelemetryAPI.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/AIAgentTaskService.js +59 -0
- package/build/dist/Server/Services/AIAgentTaskService.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/AnalyticsDatabaseService.js +19 -0
- package/build/dist/Server/Services/AnalyticsDatabaseService.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/LogAggregationService.js +21 -7
- package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
- package/build/dist/Server/Services/MetricService.js +449 -7
- package/build/dist/Server/Services/MetricService.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/APIRequestCriteria.js +29 -0
- package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.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 +155 -5
- 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/DashboardComponentType.js +1 -0
- package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardLogChartComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardLogChartComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js +9 -1
- package/build/dist/Types/Dashboard/DashboardTemplates.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 +9 -0
- package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
- package/build/dist/Types/Monitor/HttpPhaseTimings.js +2 -0
- package/build/dist/Types/Monitor/HttpPhaseTimings.js.map +1 -0
- 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 +24 -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/PingMonitor/PingMonitorResponse.js +2 -0
- package/build/dist/Types/Monitor/PingMonitor/PingMonitorResponse.js.map +1 -0
- 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/Charts/ChartLibrary/AreaChart/AreaChart.js +7 -4
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +4 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +6 -3
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
- package/build/dist/UI/Components/CodeBlock/CodeBlock.js +1 -1
- package/build/dist/UI/Components/CodeBlock/CodeBlock.js.map +1 -1
- package/build/dist/UI/Components/CodeEditor/CodeEditor.js +3 -1
- package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
- package/build/dist/UI/Components/Divider/Divider.js +1 -1
- package/build/dist/UI/Components/Divider/Divider.js.map +1 -1
- package/build/dist/UI/Components/Dropdown/Dropdown.js +10 -4
- package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
- package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js +76 -3
- package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js.map +1 -1
- package/build/dist/UI/Components/ErrorBoundary.js +2 -1
- package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
- package/build/dist/UI/Components/EventItem/EventItem.js +2 -2
- package/build/dist/UI/Components/EventItem/EventItem.js.map +1 -1
- package/build/dist/UI/Components/GanttChart/Bar/Index.js +1 -1
- package/build/dist/UI/Components/GanttChart/Bar/Index.js.map +1 -1
- package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js +29 -23
- package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js.map +1 -1
- package/build/dist/UI/Components/Header/Header.js +1 -0
- package/build/dist/UI/Components/Header/Header.js.map +1 -1
- package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +1 -1
- package/build/dist/UI/Components/Header/HeaderIconDropdownButton.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/Label/Label.js +2 -2
- package/build/dist/UI/Components/Label/Label.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +20 -8
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js +8 -2
- package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js +8 -8
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +40 -20
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
- package/build/dist/UI/Components/Modal/ConfirmModal.js +1 -1
- package/build/dist/UI/Components/Modal/ConfirmModal.js.map +1 -1
- package/build/dist/UI/Components/Modal/Modal.js +109 -51
- package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
- package/build/dist/UI/Components/Modal/ModalFooter.js +13 -10
- package/build/dist/UI/Components/Modal/ModalFooter.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/TableView.js +1 -1
- package/build/dist/UI/Components/ModelTable/TableView.js.map +1 -1
- package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js +17 -12
- package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.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/Pill/Pill.js +12 -13
- package/build/dist/UI/Components/Pill/Pill.js.map +1 -1
- package/build/dist/UI/Components/StatusBubble/StatusBubble.js +3 -3
- package/build/dist/UI/Components/StatusBubble/StatusBubble.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/Components/TelemetryViewer/TelemetryViewer.js +1 -1
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +8 -2
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetrySearchBar.js +36 -6
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetrySearchBar.js.map +1 -1
- package/build/dist/UI/Components/Workflow/Component.js +43 -33
- package/build/dist/UI/Components/Workflow/Component.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ComponentPortViewer.js +6 -6
- package/build/dist/UI/Components/Workflow/ComponentPortViewer.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ComponentReturnValueViewer.js +8 -8
- package/build/dist/UI/Components/Workflow/ComponentReturnValueViewer.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ComponentsModal.js +15 -9
- package/build/dist/UI/Components/Workflow/ComponentsModal.js.map +1 -1
- package/build/dist/UI/Components/Workflow/Workflow.js +13 -11
- package/build/dist/UI/Components/Workflow/Workflow.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/UI/Utils/Theme.js +106 -0
- package/build/dist/UI/Utils/Theme.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardLogChartComponent.js +89 -0
- package/build/dist/Utils/Dashboard/Components/DashboardLogChartComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/Index.js +4 -0
- package/build/dist/Utils/Dashboard/Components/Index.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 +138 -4
- 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
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { JSONObject } from "../../../Types/JSON";
|
|
2
|
+
import SnmpInterface from "../../../Types/Monitor/SnmpMonitor/SnmpInterface";
|
|
3
|
+
import ProbeMonitorResponse from "../../../Types/Probe/ProbeMonitorResponse";
|
|
4
|
+
import OneUptimeDate from "../../../Types/Date";
|
|
5
|
+
import logger from "../Logger";
|
|
6
|
+
|
|
7
|
+
/*
|
|
8
|
+
* Computes per-interface rates (bandwidth, utilization, errors) for SNMP
|
|
9
|
+
* monitors by comparing the cumulative IF-MIB counters of the current check
|
|
10
|
+
* against the previous check stored in MonitorProbe.lastMonitoringLog.
|
|
11
|
+
*
|
|
12
|
+
* Probes stay stateless — the delta is computed here, on ingest, before the
|
|
13
|
+
* response is persisted. Negative deltas (counter wrap or device reboot) are
|
|
14
|
+
* skipped for that interface; rates resume on the following check.
|
|
15
|
+
*/
|
|
16
|
+
export default class SnmpInterfaceRateUtil {
|
|
17
|
+
public static attachInterfaceRates(data: {
|
|
18
|
+
probeMonitorResponse: ProbeMonitorResponse;
|
|
19
|
+
previousStepLog: JSONObject | undefined;
|
|
20
|
+
}): void {
|
|
21
|
+
const interfaces: Array<SnmpInterface> | undefined =
|
|
22
|
+
data.probeMonitorResponse.snmpResponse?.interfaces;
|
|
23
|
+
|
|
24
|
+
if (!interfaces || interfaces.length === 0) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!data.previousStepLog) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const previousSnmpResponse: JSONObject | undefined = data.previousStepLog[
|
|
33
|
+
"snmpResponse"
|
|
34
|
+
] as JSONObject | undefined;
|
|
35
|
+
|
|
36
|
+
const previousInterfaces: Array<JSONObject> | undefined =
|
|
37
|
+
previousSnmpResponse?.["interfaces"] as Array<JSONObject> | undefined;
|
|
38
|
+
|
|
39
|
+
const previousMonitoredAtValue: unknown =
|
|
40
|
+
data.previousStepLog["monitoredAt"];
|
|
41
|
+
|
|
42
|
+
if (
|
|
43
|
+
!previousInterfaces ||
|
|
44
|
+
previousInterfaces.length === 0 ||
|
|
45
|
+
!previousMonitoredAtValue
|
|
46
|
+
) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const previousMonitoredAt: Date = new Date(
|
|
51
|
+
previousMonitoredAtValue as string,
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
if (isNaN(previousMonitoredAt.getTime())) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/*
|
|
59
|
+
* lastMonitoringLog stores server receipt time as monitoredAt, so the
|
|
60
|
+
* current side of the delta uses server time too.
|
|
61
|
+
*/
|
|
62
|
+
const elapsedSeconds: number =
|
|
63
|
+
(OneUptimeDate.getCurrentDate().getTime() -
|
|
64
|
+
previousMonitoredAt.getTime()) /
|
|
65
|
+
1000;
|
|
66
|
+
|
|
67
|
+
if (elapsedSeconds <= 0) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const counterDelta: (
|
|
72
|
+
currentValue: number | undefined,
|
|
73
|
+
previousValue: unknown,
|
|
74
|
+
) => number | undefined = (
|
|
75
|
+
currentValue: number | undefined,
|
|
76
|
+
previousValue: unknown,
|
|
77
|
+
) => {
|
|
78
|
+
if (
|
|
79
|
+
currentValue === undefined ||
|
|
80
|
+
typeof previousValue !== "number" ||
|
|
81
|
+
!isFinite(previousValue)
|
|
82
|
+
) {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const delta: number = currentValue - previousValue;
|
|
87
|
+
|
|
88
|
+
// Negative delta: counter wrapped or the device rebooted.
|
|
89
|
+
return delta >= 0 ? delta : undefined;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const round: (value: number) => number = (value: number) => {
|
|
93
|
+
return Math.round(value * 100) / 100;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const previousByIndex: Map<number, JSONObject> = new Map();
|
|
97
|
+
for (const previousInterface of previousInterfaces) {
|
|
98
|
+
const index: unknown = previousInterface["interfaceIndex"];
|
|
99
|
+
if (typeof index === "number") {
|
|
100
|
+
previousByIndex.set(index, previousInterface);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
for (const currentInterface of interfaces) {
|
|
105
|
+
const previousInterface: JSONObject | undefined = previousByIndex.get(
|
|
106
|
+
currentInterface.interfaceIndex,
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
if (!previousInterface) {
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const inOctetsDelta: number | undefined = counterDelta(
|
|
114
|
+
currentInterface.inOctets,
|
|
115
|
+
previousInterface["inOctets"],
|
|
116
|
+
);
|
|
117
|
+
const outOctetsDelta: number | undefined = counterDelta(
|
|
118
|
+
currentInterface.outOctets,
|
|
119
|
+
previousInterface["outOctets"],
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
if (inOctetsDelta !== undefined) {
|
|
123
|
+
currentInterface.inBitsPerSecond = round(
|
|
124
|
+
(inOctetsDelta * 8) / elapsedSeconds,
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (outOctetsDelta !== undefined) {
|
|
129
|
+
currentInterface.outBitsPerSecond = round(
|
|
130
|
+
(outOctetsDelta * 8) / elapsedSeconds,
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (
|
|
135
|
+
currentInterface.speedInBitsPerSecond &&
|
|
136
|
+
currentInterface.speedInBitsPerSecond > 0 &&
|
|
137
|
+
(currentInterface.inBitsPerSecond !== undefined ||
|
|
138
|
+
currentInterface.outBitsPerSecond !== undefined)
|
|
139
|
+
) {
|
|
140
|
+
const busiestDirectionBps: number = Math.max(
|
|
141
|
+
currentInterface.inBitsPerSecond || 0,
|
|
142
|
+
currentInterface.outBitsPerSecond || 0,
|
|
143
|
+
);
|
|
144
|
+
currentInterface.utilizationPercent = round(
|
|
145
|
+
(busiestDirectionBps / currentInterface.speedInBitsPerSecond) * 100,
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const inErrorsDelta: number | undefined = counterDelta(
|
|
150
|
+
currentInterface.inErrors,
|
|
151
|
+
previousInterface["inErrors"],
|
|
152
|
+
);
|
|
153
|
+
const outErrorsDelta: number | undefined = counterDelta(
|
|
154
|
+
currentInterface.outErrors,
|
|
155
|
+
previousInterface["outErrors"],
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
if (inErrorsDelta !== undefined || outErrorsDelta !== undefined) {
|
|
159
|
+
currentInterface.errorsPerSecond = round(
|
|
160
|
+
((inErrorsDelta || 0) + (outErrorsDelta || 0)) / elapsedSeconds,
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
logger.debug(
|
|
166
|
+
`Attached SNMP interface rates for monitor ${data.probeMonitorResponse.monitorId.toString()} over ${round(elapsedSeconds)}s window`,
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import AIAgentTaskService from "../../../Server/Services/AIAgentTaskService";
|
|
2
|
+
import Model from "../../../Models/DatabaseModels/AIAgentTask";
|
|
3
|
+
import AIAgentTaskStatus from "../../../Types/AI/AIAgentTaskStatus";
|
|
4
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
5
|
+
import { describe, expect, test, afterEach } from "@jest/globals";
|
|
6
|
+
|
|
7
|
+
/*
|
|
8
|
+
* claimNextScheduledTask is the atomic-claim fix for the get-pending-task
|
|
9
|
+
* double-processing race: multiple KEDA-scaled AIAgent workers poll the same
|
|
10
|
+
* endpoint, and the old plain findOneBy returned the oldest Scheduled task
|
|
11
|
+
* without mutating it, so two workers could both receive — and both execute —
|
|
12
|
+
* the same task.
|
|
13
|
+
*
|
|
14
|
+
* The claim collapses the read-then-take into findOneBy + a status-guarded
|
|
15
|
+
* updateOneBy (Scheduled -> InProgress). updateOneBy returns the number of
|
|
16
|
+
* rows changed: 1 means this caller won the claim; 0 means another worker
|
|
17
|
+
* already took the task, and the loop retries with the next candidate.
|
|
18
|
+
*
|
|
19
|
+
* These tests mock the two inherited persistence helpers (no Postgres) to
|
|
20
|
+
* lock in:
|
|
21
|
+
* (a) a won claim returns the task, with the guard and the InProgress
|
|
22
|
+
* transition on the exact row that was read;
|
|
23
|
+
* (b) a lost claim (0 rows) is never returned — the loop moves to the
|
|
24
|
+
* next candidate;
|
|
25
|
+
* (c) no Scheduled tasks => null, with no write at all;
|
|
26
|
+
* (d) the retry loop is bounded, so a pathological all-losses storm
|
|
27
|
+
* terminates.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
function fakeTask(id: ObjectID): Model {
|
|
31
|
+
return {
|
|
32
|
+
id,
|
|
33
|
+
_id: id.toString(),
|
|
34
|
+
projectId: ObjectID.generate(),
|
|
35
|
+
taskType: "FixException",
|
|
36
|
+
} as unknown as Model;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
describe("AIAgentTaskService.claimNextScheduledTask", () => {
|
|
40
|
+
const aiAgentId: ObjectID = ObjectID.generate();
|
|
41
|
+
|
|
42
|
+
afterEach(() => {
|
|
43
|
+
jest.restoreAllMocks();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("returns the task when the claim wins, guarding on Scheduled status", async () => {
|
|
47
|
+
const task: Model = fakeTask(ObjectID.generate());
|
|
48
|
+
|
|
49
|
+
const findOneBy: jest.SpyInstance = jest
|
|
50
|
+
.spyOn(AIAgentTaskService, "findOneBy")
|
|
51
|
+
.mockResolvedValue(task);
|
|
52
|
+
const updateOneBy: jest.SpyInstance = jest
|
|
53
|
+
.spyOn(AIAgentTaskService, "updateOneBy")
|
|
54
|
+
.mockResolvedValue(1);
|
|
55
|
+
|
|
56
|
+
const claimed: Model | null =
|
|
57
|
+
await AIAgentTaskService.claimNextScheduledTask({
|
|
58
|
+
aiAgentId: aiAgentId,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
expect(claimed).toBe(task);
|
|
62
|
+
expect(findOneBy).toHaveBeenCalledTimes(1);
|
|
63
|
+
expect(findOneBy).toHaveBeenCalledWith(
|
|
64
|
+
expect.objectContaining({
|
|
65
|
+
query: { status: AIAgentTaskStatus.Scheduled },
|
|
66
|
+
}),
|
|
67
|
+
);
|
|
68
|
+
expect(updateOneBy).toHaveBeenCalledTimes(1);
|
|
69
|
+
expect(updateOneBy).toHaveBeenCalledWith(
|
|
70
|
+
expect.objectContaining({
|
|
71
|
+
query: {
|
|
72
|
+
_id: task.id!.toString(),
|
|
73
|
+
status: AIAgentTaskStatus.Scheduled,
|
|
74
|
+
},
|
|
75
|
+
data: expect.objectContaining({
|
|
76
|
+
status: AIAgentTaskStatus.InProgress,
|
|
77
|
+
aiAgentId: aiAgentId,
|
|
78
|
+
startedAt: expect.any(Date),
|
|
79
|
+
}),
|
|
80
|
+
}),
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test("retries with the next candidate when another worker wins the race", async () => {
|
|
85
|
+
const lostTask: Model = fakeTask(ObjectID.generate());
|
|
86
|
+
const wonTask: Model = fakeTask(ObjectID.generate());
|
|
87
|
+
|
|
88
|
+
const findOneBy: jest.SpyInstance = jest
|
|
89
|
+
.spyOn(AIAgentTaskService, "findOneBy")
|
|
90
|
+
.mockResolvedValueOnce(lostTask)
|
|
91
|
+
.mockResolvedValueOnce(wonTask);
|
|
92
|
+
const updateOneBy: jest.SpyInstance = jest
|
|
93
|
+
.spyOn(AIAgentTaskService, "updateOneBy")
|
|
94
|
+
.mockResolvedValueOnce(0)
|
|
95
|
+
.mockResolvedValueOnce(1);
|
|
96
|
+
|
|
97
|
+
const claimed: Model | null =
|
|
98
|
+
await AIAgentTaskService.claimNextScheduledTask({
|
|
99
|
+
aiAgentId: aiAgentId,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
expect(claimed).toBe(wonTask);
|
|
103
|
+
expect(findOneBy).toHaveBeenCalledTimes(2);
|
|
104
|
+
expect(updateOneBy).toHaveBeenCalledTimes(2);
|
|
105
|
+
expect(updateOneBy).toHaveBeenLastCalledWith(
|
|
106
|
+
expect.objectContaining({
|
|
107
|
+
query: {
|
|
108
|
+
_id: wonTask.id!.toString(),
|
|
109
|
+
status: AIAgentTaskStatus.Scheduled,
|
|
110
|
+
},
|
|
111
|
+
}),
|
|
112
|
+
);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("returns null without writing when no Scheduled task exists", async () => {
|
|
116
|
+
jest.spyOn(AIAgentTaskService, "findOneBy").mockResolvedValue(null);
|
|
117
|
+
const updateOneBy: jest.SpyInstance = jest
|
|
118
|
+
.spyOn(AIAgentTaskService, "updateOneBy")
|
|
119
|
+
.mockResolvedValue(1);
|
|
120
|
+
|
|
121
|
+
const claimed: Model | null =
|
|
122
|
+
await AIAgentTaskService.claimNextScheduledTask({
|
|
123
|
+
aiAgentId: aiAgentId,
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
expect(claimed).toBeNull();
|
|
127
|
+
expect(updateOneBy).not.toHaveBeenCalled();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("gives up after a bounded number of lost claims", async () => {
|
|
131
|
+
const findOneBy: jest.SpyInstance = jest
|
|
132
|
+
.spyOn(AIAgentTaskService, "findOneBy")
|
|
133
|
+
.mockImplementation(async () => {
|
|
134
|
+
return fakeTask(ObjectID.generate());
|
|
135
|
+
});
|
|
136
|
+
jest.spyOn(AIAgentTaskService, "updateOneBy").mockResolvedValue(0);
|
|
137
|
+
|
|
138
|
+
const claimed: Model | null =
|
|
139
|
+
await AIAgentTaskService.claimNextScheduledTask({
|
|
140
|
+
aiAgentId: aiAgentId,
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
expect(claimed).toBeNull();
|
|
144
|
+
expect(findOneBy).toHaveBeenCalledTimes(5);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import AIService, {
|
|
2
|
+
AUTONOMOUS_AI_FEATURES,
|
|
3
|
+
AutonomousBudgetStatus,
|
|
4
|
+
} from "../../../Server/Services/AIService";
|
|
5
|
+
import SentinelInvestigationQueue from "../../../Server/Utils/AI/Sentinel/InvestigationQueue";
|
|
6
|
+
import LlmLogService from "../../../Server/Services/LlmLogService";
|
|
7
|
+
import ProjectService from "../../../Server/Services/ProjectService";
|
|
8
|
+
import AIRunService from "../../../Server/Services/AIRunService";
|
|
9
|
+
import Project from "../../../Models/DatabaseModels/Project";
|
|
10
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
11
|
+
import PositiveNumber from "../../../Types/PositiveNumber";
|
|
12
|
+
import { describe, expect, test, afterEach } from "@jest/globals";
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
* G4 daily budget: Project.aiDailyAutonomousTokenLimit bounds the tokens the
|
|
16
|
+
* AUTONOMOUS_AI_FEATURES may consume per UTC day. The engine skips new
|
|
17
|
+
* investigations quietly when the budget is exhausted (no Error run created);
|
|
18
|
+
* AIService.executeWithLogging is the hard backstop mid-run. Interactive chat
|
|
19
|
+
* is never blocked — its features are not in AUTONOMOUS_AI_FEATURES.
|
|
20
|
+
*
|
|
21
|
+
* These tests mock the persistence layer and lock in:
|
|
22
|
+
* (a) no limit configured => never exhausted, and no usage query is run;
|
|
23
|
+
* (b) usage below the limit => not exhausted;
|
|
24
|
+
* (c) usage at/over the limit => exhausted, with the numbers reported;
|
|
25
|
+
* (d) the engine skips run creation when the budget is exhausted.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
function fakeProject(limit: number | undefined): Project {
|
|
29
|
+
return {
|
|
30
|
+
id: ObjectID.generate(),
|
|
31
|
+
aiDailyAutonomousTokenLimit: limit,
|
|
32
|
+
} as unknown as Project;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
describe("AIService.getAutonomousDailyBudgetStatus", () => {
|
|
36
|
+
const projectId: ObjectID = ObjectID.generate();
|
|
37
|
+
|
|
38
|
+
afterEach(() => {
|
|
39
|
+
jest.restoreAllMocks();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("no configured limit means never exhausted and no usage query", async () => {
|
|
43
|
+
jest
|
|
44
|
+
.spyOn(ProjectService, "findOneById")
|
|
45
|
+
.mockResolvedValue(fakeProject(undefined));
|
|
46
|
+
const getTokens: jest.SpyInstance = jest.spyOn(
|
|
47
|
+
LlmLogService,
|
|
48
|
+
"getTotalTokensUsedSince",
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const status: AutonomousBudgetStatus =
|
|
52
|
+
await AIService.getAutonomousDailyBudgetStatus(projectId);
|
|
53
|
+
|
|
54
|
+
expect(status.exhausted).toBe(false);
|
|
55
|
+
expect(status.limitInTokens).toBeNull();
|
|
56
|
+
expect(getTokens).not.toHaveBeenCalled();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("a limit of 0 pauses autonomous runs without querying usage", async () => {
|
|
60
|
+
jest.spyOn(ProjectService, "findOneById").mockResolvedValue(fakeProject(0));
|
|
61
|
+
const getTokens: jest.SpyInstance = jest.spyOn(
|
|
62
|
+
LlmLogService,
|
|
63
|
+
"getTotalTokensUsedSince",
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const status: AutonomousBudgetStatus =
|
|
67
|
+
await AIService.getAutonomousDailyBudgetStatus(projectId);
|
|
68
|
+
|
|
69
|
+
expect(status.exhausted).toBe(true);
|
|
70
|
+
expect(status.limitInTokens).toBe(0);
|
|
71
|
+
expect(getTokens).not.toHaveBeenCalled();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("usage below the limit is not exhausted", async () => {
|
|
75
|
+
jest
|
|
76
|
+
.spyOn(ProjectService, "findOneById")
|
|
77
|
+
.mockResolvedValue(fakeProject(100_000));
|
|
78
|
+
jest
|
|
79
|
+
.spyOn(LlmLogService, "getTotalTokensUsedSince")
|
|
80
|
+
.mockResolvedValue(99_999);
|
|
81
|
+
|
|
82
|
+
const status: AutonomousBudgetStatus =
|
|
83
|
+
await AIService.getAutonomousDailyBudgetStatus(projectId);
|
|
84
|
+
|
|
85
|
+
expect(status.exhausted).toBe(false);
|
|
86
|
+
expect(status.limitInTokens).toBe(100_000);
|
|
87
|
+
expect(status.usedTokensToday).toBe(99_999);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("usage at the limit is exhausted, scoped to autonomous features", async () => {
|
|
91
|
+
jest
|
|
92
|
+
.spyOn(ProjectService, "findOneById")
|
|
93
|
+
.mockResolvedValue(fakeProject(100_000));
|
|
94
|
+
const getTokens: jest.SpyInstance = jest
|
|
95
|
+
.spyOn(LlmLogService, "getTotalTokensUsedSince")
|
|
96
|
+
.mockResolvedValue(100_000);
|
|
97
|
+
|
|
98
|
+
const status: AutonomousBudgetStatus =
|
|
99
|
+
await AIService.getAutonomousDailyBudgetStatus(projectId);
|
|
100
|
+
|
|
101
|
+
expect(status.exhausted).toBe(true);
|
|
102
|
+
expect(getTokens).toHaveBeenCalledWith(
|
|
103
|
+
expect.objectContaining({
|
|
104
|
+
features: AUTONOMOUS_AI_FEATURES,
|
|
105
|
+
}),
|
|
106
|
+
);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
describe("SentinelInvestigationQueue budget skip", () => {
|
|
111
|
+
afterEach(() => {
|
|
112
|
+
jest.restoreAllMocks();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("does not enqueue when the daily budget is exhausted", async () => {
|
|
116
|
+
jest.spyOn(AIService, "getAutonomousDailyBudgetStatus").mockResolvedValue({
|
|
117
|
+
exhausted: true,
|
|
118
|
+
limitInTokens: 100_000,
|
|
119
|
+
usedTokensToday: 120_000,
|
|
120
|
+
});
|
|
121
|
+
const create: jest.SpyInstance = jest.spyOn(AIRunService, "create");
|
|
122
|
+
|
|
123
|
+
await SentinelInvestigationQueue.enqueue({
|
|
124
|
+
projectId: ObjectID.generate(),
|
|
125
|
+
subjectAlertId: ObjectID.generate(),
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
expect(create).not.toHaveBeenCalled();
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test("does not enqueue when the budget check itself fails", async () => {
|
|
132
|
+
jest
|
|
133
|
+
.spyOn(AIService, "getAutonomousDailyBudgetStatus")
|
|
134
|
+
.mockRejectedValue(new Error("db down"));
|
|
135
|
+
const create: jest.SpyInstance = jest.spyOn(AIRunService, "create");
|
|
136
|
+
|
|
137
|
+
await SentinelInvestigationQueue.enqueue({
|
|
138
|
+
projectId: ObjectID.generate(),
|
|
139
|
+
subjectAlertId: ObjectID.generate(),
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
expect(create).not.toHaveBeenCalled();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test("leaves a queued run unclaimed when the budget is exhausted at claim time", async () => {
|
|
146
|
+
// No per-project cap override; concurrency cap passes…
|
|
147
|
+
jest
|
|
148
|
+
.spyOn(ProjectService, "findOneById")
|
|
149
|
+
.mockResolvedValue(fakeProject(undefined));
|
|
150
|
+
jest
|
|
151
|
+
.spyOn(AIRunService, "countBy")
|
|
152
|
+
.mockResolvedValue(new PositiveNumber(0));
|
|
153
|
+
// …but the budget is exhausted.
|
|
154
|
+
jest.spyOn(AIService, "getAutonomousDailyBudgetStatus").mockResolvedValue({
|
|
155
|
+
exhausted: true,
|
|
156
|
+
limitInTokens: 100_000,
|
|
157
|
+
usedTokensToday: 120_000,
|
|
158
|
+
});
|
|
159
|
+
const claim: jest.SpyInstance = jest.spyOn(
|
|
160
|
+
AIRunService,
|
|
161
|
+
"attemptStatusTransition",
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
await SentinelInvestigationQueue.processRun({
|
|
165
|
+
id: ObjectID.generate(),
|
|
166
|
+
projectId: ObjectID.generate(),
|
|
167
|
+
attemptCount: 0,
|
|
168
|
+
triggeredByAlertId: ObjectID.generate(),
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
expect(claim).not.toHaveBeenCalled();
|
|
172
|
+
});
|
|
173
|
+
});
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import IncidentInternalNoteService from "../../../Server/Services/IncidentInternalNoteService";
|
|
2
|
+
import IncidentFeedService from "../../../Server/Services/IncidentFeedService";
|
|
3
|
+
import IncidentService from "../../../Server/Services/IncidentService";
|
|
4
|
+
import Model from "../../../Models/DatabaseModels/IncidentInternalNote";
|
|
5
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
6
|
+
import URL from "../../../Types/API/URL";
|
|
7
|
+
import { describe, expect, test, afterEach } from "@jest/globals";
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
* IncidentInternalNoteService.onCreateSuccess announces every new note with a
|
|
11
|
+
* "posted private note" feed item + workspace ping — INCLUDING user-less
|
|
12
|
+
* system notes: the SLA note-reminder job (SendNoteReminders.ts) creates notes
|
|
13
|
+
* with no createdByUserId and relies entirely on this hook for its feed entry
|
|
14
|
+
* and Slack/Teams ping (it sets isOwnerNotified itself, so the hook is its
|
|
15
|
+
* only push channel).
|
|
16
|
+
*
|
|
17
|
+
* Callers that must NOT announce (Sentinel's RCA note, which has its own
|
|
18
|
+
* quiet-mode-gated RootCause feed item) opt out explicitly with
|
|
19
|
+
* props.ignoreHooks — see IncidentInvestigationRunner. These tests lock in
|
|
20
|
+
* that the hook announces for both user-authored and user-less notes, so the
|
|
21
|
+
* SLA flow can't be silenced again by a "system notes are quiet" shortcut.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
function fakeNote(userId?: ObjectID | undefined): Model {
|
|
25
|
+
return {
|
|
26
|
+
id: ObjectID.generate(),
|
|
27
|
+
incidentId: ObjectID.generate(),
|
|
28
|
+
projectId: ObjectID.generate(),
|
|
29
|
+
note: "test note",
|
|
30
|
+
createdByUserId: userId,
|
|
31
|
+
createdByUser: undefined,
|
|
32
|
+
} as unknown as Model;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
describe("IncidentInternalNoteService.onCreateSuccess", () => {
|
|
36
|
+
afterEach(() => {
|
|
37
|
+
jest.restoreAllMocks();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
function mockAnnouncementDeps(): jest.SpyInstance {
|
|
41
|
+
const createFeedItem: jest.SpyInstance = jest
|
|
42
|
+
.spyOn(IncidentFeedService, "createIncidentFeedItem")
|
|
43
|
+
.mockResolvedValue(undefined as never);
|
|
44
|
+
jest.spyOn(IncidentService, "getIncidentNumber").mockResolvedValue({
|
|
45
|
+
number: 42,
|
|
46
|
+
numberWithPrefix: "INC-42",
|
|
47
|
+
});
|
|
48
|
+
jest
|
|
49
|
+
.spyOn(IncidentService, "getIncidentLinkInDashboard")
|
|
50
|
+
.mockResolvedValue(URL.fromString("https://oneuptime.example/incident"));
|
|
51
|
+
// No attachments on these notes.
|
|
52
|
+
jest
|
|
53
|
+
.spyOn(IncidentInternalNoteService, "findOneById")
|
|
54
|
+
.mockResolvedValue(null);
|
|
55
|
+
return createFeedItem;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
test("user-authored note announces with a feed item attributed to the user", async () => {
|
|
59
|
+
const createFeedItem: jest.SpyInstance = mockAnnouncementDeps();
|
|
60
|
+
const userId: ObjectID = ObjectID.generate();
|
|
61
|
+
const note: Model = fakeNote(userId);
|
|
62
|
+
|
|
63
|
+
await IncidentInternalNoteService.onCreateSuccess(
|
|
64
|
+
{ createBy: { data: note, props: { isRoot: true } }, carryForward: null },
|
|
65
|
+
note,
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
expect(createFeedItem).toHaveBeenCalledTimes(1);
|
|
69
|
+
expect(createFeedItem).toHaveBeenCalledWith(
|
|
70
|
+
expect.objectContaining({
|
|
71
|
+
userId,
|
|
72
|
+
workspaceNotification: expect.objectContaining({
|
|
73
|
+
sendWorkspaceNotification: true,
|
|
74
|
+
}),
|
|
75
|
+
}),
|
|
76
|
+
);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("user-less system note (e.g. SLA reminder) still announces", async () => {
|
|
80
|
+
const createFeedItem: jest.SpyInstance = mockAnnouncementDeps();
|
|
81
|
+
const note: Model = fakeNote(undefined);
|
|
82
|
+
|
|
83
|
+
await IncidentInternalNoteService.onCreateSuccess(
|
|
84
|
+
{ createBy: { data: note, props: { isRoot: true } }, carryForward: null },
|
|
85
|
+
note,
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
expect(createFeedItem).toHaveBeenCalledTimes(1);
|
|
89
|
+
expect(createFeedItem).toHaveBeenCalledWith(
|
|
90
|
+
expect.objectContaining({
|
|
91
|
+
workspaceNotification: expect.objectContaining({
|
|
92
|
+
sendWorkspaceNotification: true,
|
|
93
|
+
}),
|
|
94
|
+
}),
|
|
95
|
+
);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
@@ -278,3 +278,57 @@ describe("IoTDeviceService.bulkUpdateLatestMetrics — sanitation matches the up
|
|
|
278
278
|
expect(params).not.toContain(10);
|
|
279
279
|
});
|
|
280
280
|
});
|
|
281
|
+
|
|
282
|
+
describe("IoTDeviceService.deleteStaleForFleet — registered devices survive", () => {
|
|
283
|
+
const CUTOFF: Date = new Date("2026-06-13T00:00:00.000Z");
|
|
284
|
+
|
|
285
|
+
test("marks registered devices offline and deletes only unregistered ones", async () => {
|
|
286
|
+
const query: jest.Mock = mockQueryRunner();
|
|
287
|
+
query
|
|
288
|
+
.mockResolvedValueOnce([[], 2]) // UPDATE (registered -> isUp=false)
|
|
289
|
+
.mockResolvedValueOnce([[], 5]); // DELETE (unregistered)
|
|
290
|
+
|
|
291
|
+
const result: { deleted: number; markedOffline: number } =
|
|
292
|
+
await IoTDeviceService.deleteStaleForFleet({
|
|
293
|
+
iotFleetId: FLEET_ID,
|
|
294
|
+
olderThan: CUTOFF,
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
expect(query).toHaveBeenCalledTimes(2);
|
|
298
|
+
|
|
299
|
+
const [updateSql, updateParams] = query.mock.calls[0] as QueryCall;
|
|
300
|
+
expect(updateSql).toContain('UPDATE "IoTDevice" SET "isUp" = false');
|
|
301
|
+
// Registered = credential on the same project + fleet + externalId.
|
|
302
|
+
expect(updateSql).toContain('EXISTS (SELECT 1 FROM "IoTDeviceCredential"');
|
|
303
|
+
expect(updateSql).toContain('c."externalId" = "IoTDevice"."externalId"');
|
|
304
|
+
expect(updateSql).toContain('c."projectId" = "IoTDevice"."projectId"');
|
|
305
|
+
// The credential correlation itself is kind-agnostic.
|
|
306
|
+
expect(updateSql).not.toContain('c."kind"');
|
|
307
|
+
// Reconnect recovery depends on lastSeenAt staying untouched.
|
|
308
|
+
expect(updateSql).not.toContain('"lastSeenAt" =');
|
|
309
|
+
// Idempotent across cron ticks: already-down rows are not rewritten.
|
|
310
|
+
expect(updateSql).toContain('"isUp" IS DISTINCT FROM false');
|
|
311
|
+
// Stale duplicate-kind rows self-heal instead of being pinned offline.
|
|
312
|
+
expect(updateSql).toContain("NOT EXISTS");
|
|
313
|
+
expect(updateParams).toEqual([FLEET_ID.toString(), CUTOFF]);
|
|
314
|
+
|
|
315
|
+
const [deleteSql, deleteParams] = query.mock.calls[1] as QueryCall;
|
|
316
|
+
expect(deleteSql).toContain('DELETE FROM "IoTDevice"');
|
|
317
|
+
expect(deleteSql).toContain("NOT EXISTS");
|
|
318
|
+
expect(deleteParams).toEqual([FLEET_ID.toString(), CUTOFF]);
|
|
319
|
+
|
|
320
|
+
expect(result).toEqual({ deleted: 5, markedOffline: 2 });
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
test("normalizes a driver result without an affected count to zero", async () => {
|
|
324
|
+
mockQueryRunner([]);
|
|
325
|
+
|
|
326
|
+
const result: { deleted: number; markedOffline: number } =
|
|
327
|
+
await IoTDeviceService.deleteStaleForFleet({
|
|
328
|
+
iotFleetId: FLEET_ID,
|
|
329
|
+
olderThan: CUTOFF,
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
expect(result).toEqual({ deleted: 0, markedOffline: 0 });
|
|
333
|
+
});
|
|
334
|
+
});
|
|
@@ -98,6 +98,7 @@ describe("LogAggregationService", () => {
|
|
|
98
98
|
).buildHistogramStatement({
|
|
99
99
|
...defaultRequest,
|
|
100
100
|
facetKey: undefined,
|
|
101
|
+
bucketSizeInMinutes: 60,
|
|
101
102
|
attributes: { requestid: "uuid-123" },
|
|
102
103
|
});
|
|
103
104
|
|
|
@@ -110,4 +111,25 @@ describe("LogAggregationService", () => {
|
|
|
110
111
|
expect(Object.values(statement.query_params)).toContain("requestid");
|
|
111
112
|
expect(Object.values(statement.query_params)).toContain("uuid-123");
|
|
112
113
|
});
|
|
114
|
+
|
|
115
|
+
test("histogram supports multi-value dashboard attribute filters", () => {
|
|
116
|
+
const statement: Statement = (
|
|
117
|
+
LogAggregationService as any
|
|
118
|
+
).buildHistogramStatement({
|
|
119
|
+
...defaultRequest,
|
|
120
|
+
facetKey: undefined,
|
|
121
|
+
bucketSizeInMinutes: 60,
|
|
122
|
+
attributes: { region: ["eu-west-1", "us-east-1"] },
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
expect(statement.query).toContain(
|
|
126
|
+
"arrayExists((k, v) -> lowerUTF8(k) = lowerUTF8(",
|
|
127
|
+
);
|
|
128
|
+
expect(statement.query).toContain("AND v IN (");
|
|
129
|
+
expect(Object.values(statement.query_params)).toContain("region");
|
|
130
|
+
expect(Object.values(statement.query_params)).toContainEqual([
|
|
131
|
+
"eu-west-1",
|
|
132
|
+
"us-east-1",
|
|
133
|
+
]);
|
|
134
|
+
});
|
|
113
135
|
});
|