@oneuptime/common 11.7.3 → 11.7.4
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/AlertEpisodeStateTimeline.ts +1 -0
- package/Models/DatabaseModels/AlertStateTimeline.ts +1 -0
- package/Models/DatabaseModels/IncidentEpisodeStateTimeline.ts +1 -0
- package/Models/DatabaseModels/IncidentStateTimeline.ts +1 -0
- package/Models/DatabaseModels/Index.ts +5 -0
- package/Models/DatabaseModels/LogDropFilter.ts +89 -0
- package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +13 -3
- package/Models/DatabaseModels/RecommendationDismissal.ts +463 -0
- package/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.ts +1 -0
- package/Models/DatabaseModels/StatusPageGroup.ts +95 -0
- package/Models/DatabaseModels/TraceDropFilter.ts +89 -0
- package/Models/DatabaseModels/WorkflowVariable.ts +5 -1
- package/Server/API/AlertAPI.ts +32 -17
- package/Server/API/BaseAPI.ts +31 -2
- package/Server/API/BaseAnalyticsAPI.ts +36 -2
- package/Server/API/CommonAPI.ts +57 -0
- package/Server/API/IncidentAPI.ts +60 -33
- package/Server/API/IncidentEpisodeAPI.ts +31 -16
- package/Server/API/MonitorAPI.ts +30 -0
- package/Server/API/MonitorTemplateAPI.ts +8 -0
- package/Server/API/ProbeAPI.ts +196 -15
- package/Server/API/ProjectAPI.ts +79 -1
- package/Server/API/ScheduledMaintenanceAPI.ts +33 -18
- package/Server/API/StatusPageAPI.ts +74 -37
- package/Server/API/WorkspaceNotificationRuleAPI.ts +34 -4
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.ts +527 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.ts +31 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.ts +55 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.ts +53 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
- package/Server/Services/AlertEpisodeService.ts +47 -0
- package/Server/Services/AlertService.ts +125 -0
- package/Server/Services/BillingService.ts +98 -0
- package/Server/Services/DatabaseService.ts +184 -20
- package/Server/Services/IncidentEpisodeService.ts +47 -0
- package/Server/Services/IncidentService.ts +123 -0
- package/Server/Services/IncidentTemplateService.ts +123 -1
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/LogDropFilterService.ts +133 -0
- package/Server/Services/MonitorProbeService.ts +94 -4
- package/Server/Services/MonitorService.ts +48 -43
- package/Server/Services/NetworkDeviceDiscoveryScanService.ts +70 -0
- package/Server/Services/ProbeService.ts +66 -0
- package/Server/Services/ProjectService.ts +131 -7
- package/Server/Services/RecommendationDismissalService.ts +52 -0
- package/Server/Services/RunbookAgentJobService.ts +68 -7
- package/Server/Services/ScheduledMaintenanceService.ts +103 -0
- package/Server/Services/ScheduledMaintenanceTemplateService.ts +90 -0
- package/Server/Services/StatusPageGroupService.ts +186 -0
- package/Server/Services/TraceDropFilterService.ts +133 -0
- package/Server/Types/Workflow/Components/API/Delete.ts +12 -0
- package/Server/Types/Workflow/Components/API/Get.ts +12 -0
- package/Server/Types/Workflow/Components/API/Patch.ts +12 -0
- package/Server/Types/Workflow/Components/API/Post.ts +12 -0
- package/Server/Types/Workflow/Components/API/Put.ts +13 -0
- package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +212 -0
- package/Server/Utils/DropFilterValidation.ts +127 -0
- package/Server/Utils/Errors.ts +5 -0
- package/Server/Utils/Monitor/MonitorAlert.ts +28 -1
- package/Server/Utils/Monitor/MonitorIncident.ts +31 -2
- package/Server/Utils/Telemetry/AppMetrics.ts +31 -0
- package/Tests/Models/DatabaseModels/MonitorProbeColumnAccessControl.test.ts +196 -0
- package/Tests/Models/RecommendationDismissalModel.test.ts +269 -0
- package/Tests/Server/API/BaseAPIUpdatePayloadValidation.test.ts +320 -0
- package/Tests/Server/API/BaseAnalyticsAPIUpdatePayloadValidation.test.ts +293 -0
- package/Tests/Server/API/CommonAPIAuthGuard.test.ts +164 -0
- package/Tests/Server/API/ProbeAPI.test.ts +422 -53
- package/Tests/Server/API/ProjectAPI.test.ts +180 -0
- package/Tests/Server/API/ProjectAPIExtendTrialBillingDisabled.test.ts +138 -0
- package/Tests/Server/API/ProjectScopedCustomRouteAuth.test.ts +458 -0
- package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +359 -0
- package/Tests/Server/Infrastructure/ProcessSignalDelivery.test.ts +427 -0
- package/Tests/Server/Services/BillingServiceExtendTrial.test.ts +439 -0
- package/Tests/Server/Services/CrossProjectReferenceWriteGuard.test.ts +810 -0
- package/Tests/Server/Services/DatabaseServiceAtomicAddToColumns.test.ts +269 -0
- package/Tests/Server/Services/DatabaseServiceEmptyUpdate.test.ts +277 -0
- package/Tests/Server/Services/DatabaseServiceSortColumnSelect.test.ts +201 -0
- package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +81 -23
- package/Tests/Server/Services/DropFilterSaveValidation.test.ts +398 -0
- package/Tests/Server/Services/MonitorProbeDeleteHooks.test.ts +280 -0
- package/Tests/Server/Services/MonitorProbeServiceProbeTenancy.test.ts +304 -0
- package/Tests/Server/Services/NetworkDeviceDiscoveryScanService.test.ts +262 -0
- package/Tests/Server/Services/ProjectServiceExtendTrial.test.ts +614 -0
- package/Tests/Server/Services/RecommendationDismissalService.test.ts +306 -0
- package/Tests/Server/Services/RepairCrossProjectIncidentReferencesMigration.test.ts +528 -0
- package/Tests/Server/Services/StatusPageGroupNesting.test.ts +395 -0
- package/Tests/Server/TestingUtils/Services/BillingServiceHelper.ts +26 -21
- package/Tests/Server/Types/Database/Permissions/WorkflowVariableColumnPermission.test.ts +227 -0
- package/Tests/Server/Types/Workflow/Components/ApiComponentErrorPort.test.ts +285 -0
- package/Tests/Server/Utils/Database/ProjectScopedReferenceValidator.test.ts +463 -0
- package/Tests/Server/Utils/DropFilterValidation.test.ts +269 -0
- package/Tests/Server/Utils/Telemetry/SpanUtil.test.ts +94 -0
- package/Tests/Types/DateUserTimezone.test.ts +52 -0
- package/Tests/Types/Monitor/KubernetesAlertTemplates.test.ts +177 -9
- package/Tests/Types/Monitor/MonitorStepDnsMonitor.test.ts +105 -0
- package/Tests/Types/Monitor/MonitorStepDnssecMonitor.test.ts +131 -0
- package/Tests/Types/Monitor/MonitorStepDomainMonitor.test.ts +60 -0
- package/Tests/Types/Monitor/MonitorStepExternalStatusPageMonitor.test.ts +82 -0
- package/Tests/Types/Monitor/MonitorStepInfrastructureMonitors.test.ts +268 -0
- package/Tests/Types/Monitor/MonitorStepMetricMonitor.test.ts +386 -0
- package/Tests/Types/Monitor/MonitorStepProfileMonitor.test.ts +185 -0
- package/Tests/Types/Monitor/MonitorStepSnmpMonitor.test.ts +156 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +371 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +901 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +607 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.test.ts +754 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +960 -0
- package/Tests/Types/RollingTime/RollingTimeUtil.test.ts +186 -0
- package/Tests/Types/Runbook/RunbookStepTimeout.test.ts +410 -0
- package/Tests/Types/Telemetry/DropFilterSampling.test.ts +241 -0
- package/Tests/Types/Workspace/NotificationRuleConditionUtil.test.ts +353 -0
- package/Tests/Types/Workspace/NotificationRuleUtil.test.ts +566 -0
- package/Tests/UI/Components/CodeEditor.test.tsx +174 -0
- package/Tests/UI/Components/ErrorBoundary.test.tsx +555 -24
- package/Tests/UI/Components/InfoCard.test.tsx +358 -0
- package/Tests/UI/Components/LogTimeRangePicker.test.tsx +138 -0
- package/Tests/UI/Components/Modal.test.tsx +43 -5
- package/Tests/UI/Components/ModelTable/BaseModelTableSearchLabels.test.tsx +397 -0
- package/Tests/UI/Components/ModelTable/ColumnCustomizationModal.test.tsx +427 -0
- package/Tests/UI/Components/Runbook/StepTimeoutInput.test.tsx +386 -0
- package/Tests/UI/Components/StatusPage/ResourceGroupSection.test.tsx +671 -0
- package/Tests/UI/Components/TelemetryTimeRangePicker.test.tsx +404 -0
- package/Tests/UI/Utils/DropdownAlignment.test.ts +306 -0
- package/Tests/UI/Utils/TableFilterUrlState.test.ts +292 -0
- package/Tests/Utils/Monitor/MonitorSummaryProbeUtil.test.ts +263 -0
- package/Tests/Utils/NetworkDiscovery/ScanTargetUtil.test.ts +583 -0
- package/Tests/Utils/StatusPage/GroupNestingLayout.test.ts +1072 -0
- package/Tests/Utils/StatusPage/GroupTree.test.ts +583 -0
- package/Tests/Utils/StatusPage/ResourceUptime.test.ts +411 -0
- package/Types/Date.ts +15 -6
- package/Types/Monitor/KubernetesAlertTemplates.ts +205 -0
- package/Types/Monitor/MonitorStep.ts +10 -1
- package/Types/Monitor/MonitorStepMetricMonitor.ts +46 -1
- package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +413 -0
- package/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.ts +168 -0
- package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +175 -0
- package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +743 -0
- package/Types/Permission.ts +45 -0
- package/Types/Recommendation/RecommendationType.ts +20 -0
- package/Types/Runbook/RunbookExecutionDeadline.ts +129 -0
- package/Types/Runbook/RunbookStepTimeout.ts +202 -0
- package/Types/Telemetry/DropFilterSampling.ts +92 -0
- package/UI/Components/AI/GenerateFromAIModal.tsx +0 -2
- package/UI/Components/Accordion/Accordion.tsx +10 -2
- package/UI/Components/BulkUpdate/BulkLabelActions.tsx +0 -1
- package/UI/Components/CodeEditor/CodeEditor.tsx +34 -20
- package/UI/Components/Date/RangeStartAndEndDateView.tsx +0 -1
- package/UI/Components/EditionLabel/EditionLabel.tsx +1 -27
- package/UI/Components/Error/PageError.tsx +0 -4
- package/UI/Components/ErrorBoundary.tsx +252 -15
- package/UI/Components/InfoCard/InfoCard.tsx +58 -1
- package/UI/Components/LogsViewer/components/LogTimeRangePicker.tsx +34 -1
- package/UI/Components/Modal/Modal.tsx +16 -60
- package/UI/Components/ModelFormModal/ModelFormModal.tsx +0 -8
- package/UI/Components/ModelTable/BaseModelTable.tsx +116 -67
- package/UI/Components/ModelTable/ColumnCustomizationModal.tsx +150 -47
- package/UI/Components/Runbook/StepTimeoutInput.tsx +173 -0
- package/UI/Components/StatusPage/ResourceGroupSection.tsx +231 -0
- package/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.tsx +34 -1
- package/UI/Utils/DropdownAlignment.ts +162 -0
- package/UI/Utils/TableFilterUrlState.ts +59 -20
- package/Utils/API.ts +106 -2
- package/Utils/Monitor/MonitorSummaryProbeUtil.ts +130 -0
- package/Utils/NetworkDiscovery/ScanTargetUtil.ts +434 -0
- package/Utils/StatusPage/GroupNestingLayout.ts +343 -0
- package/Utils/StatusPage/GroupTree.ts +307 -0
- package/Utils/StatusPage/ResourceUptime.ts +90 -17
- package/build/dist/Models/DatabaseModels/AlertEpisodeStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/AlertEpisodeStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/AlertStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/LogDropFilter.js +91 -0
- package/build/dist/Models/DatabaseModels/LogDropFilter.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +14 -4
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RecommendationDismissal.js +484 -0
- package/build/dist/Models/DatabaseModels/RecommendationDismissal.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageGroup.js +94 -0
- package/build/dist/Models/DatabaseModels/StatusPageGroup.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TraceDropFilter.js +91 -0
- package/build/dist/Models/DatabaseModels/TraceDropFilter.js.map +1 -1
- package/build/dist/Models/DatabaseModels/WorkflowVariable.js +5 -1
- package/build/dist/Models/DatabaseModels/WorkflowVariable.js.map +1 -1
- package/build/dist/Server/API/AlertAPI.js +22 -13
- package/build/dist/Server/API/AlertAPI.js.map +1 -1
- package/build/dist/Server/API/BaseAPI.js +22 -1
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/BaseAnalyticsAPI.js +24 -1
- package/build/dist/Server/API/BaseAnalyticsAPI.js.map +1 -1
- package/build/dist/Server/API/CommonAPI.js +42 -0
- package/build/dist/Server/API/CommonAPI.js.map +1 -1
- package/build/dist/Server/API/IncidentAPI.js +43 -26
- package/build/dist/Server/API/IncidentAPI.js.map +1 -1
- package/build/dist/Server/API/IncidentEpisodeAPI.js +21 -12
- package/build/dist/Server/API/IncidentEpisodeAPI.js.map +1 -1
- package/build/dist/Server/API/MonitorAPI.js +23 -0
- package/build/dist/Server/API/MonitorAPI.js.map +1 -1
- package/build/dist/Server/API/MonitorTemplateAPI.js +4 -0
- package/build/dist/Server/API/MonitorTemplateAPI.js.map +1 -1
- package/build/dist/Server/API/ProbeAPI.js +131 -15
- package/build/dist/Server/API/ProbeAPI.js.map +1 -1
- package/build/dist/Server/API/ProjectAPI.js +62 -3
- package/build/dist/Server/API/ProjectAPI.js.map +1 -1
- package/build/dist/Server/API/ScheduledMaintenanceAPI.js +23 -14
- package/build/dist/Server/API/ScheduledMaintenanceAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +61 -33
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/WorkspaceNotificationRuleAPI.js +26 -2
- package/build/dist/Server/API/WorkspaceNotificationRuleAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.js +397 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.js +16 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.js +30 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.js +34 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeService.js +39 -0
- package/build/dist/Server/Services/AlertEpisodeService.js.map +1 -1
- package/build/dist/Server/Services/AlertService.js +95 -0
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/BillingService.js +71 -0
- package/build/dist/Server/Services/BillingService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +140 -17
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeService.js +39 -0
- package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +100 -0
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/IncidentTemplateService.js +97 -0
- package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +2 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/LogDropFilterService.js +93 -0
- package/build/dist/Server/Services/LogDropFilterService.js.map +1 -1
- package/build/dist/Server/Services/MonitorProbeService.js +73 -5
- package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +34 -39
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +71 -0
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -1
- package/build/dist/Server/Services/ProbeService.js +64 -0
- package/build/dist/Server/Services/ProbeService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +103 -7
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/RecommendationDismissalService.js +50 -0
- package/build/dist/Server/Services/RecommendationDismissalService.js.map +1 -0
- package/build/dist/Server/Services/RunbookAgentJobService.js +63 -5
- package/build/dist/Server/Services/RunbookAgentJobService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceService.js +83 -0
- package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js +65 -0
- package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageGroupService.js +136 -0
- package/build/dist/Server/Services/StatusPageGroupService.js.map +1 -1
- package/build/dist/Server/Services/TraceDropFilterService.js +93 -0
- package/build/dist/Server/Services/TraceDropFilterService.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Delete.js +11 -0
- package/build/dist/Server/Types/Workflow/Components/API/Delete.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Get.js +11 -0
- package/build/dist/Server/Types/Workflow/Components/API/Get.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Patch.js +11 -0
- package/build/dist/Server/Types/Workflow/Components/API/Patch.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Post.js +11 -0
- package/build/dist/Server/Types/Workflow/Components/API/Post.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Put.js +12 -0
- package/build/dist/Server/Types/Workflow/Components/API/Put.js.map +1 -1
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +132 -0
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -0
- package/build/dist/Server/Utils/DropFilterValidation.js +80 -0
- package/build/dist/Server/Utils/DropFilterValidation.js.map +1 -0
- package/build/dist/Server/Utils/Errors.js +3 -0
- package/build/dist/Server/Utils/Errors.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +30 -12
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +38 -18
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/AppMetrics.js +26 -0
- package/build/dist/Server/Utils/Telemetry/AppMetrics.js.map +1 -1
- package/build/dist/Types/Date.js +14 -4
- package/build/dist/Types/Date.js.map +1 -1
- package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +192 -0
- package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +6 -1
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepMetricMonitor.js +32 -1
- package/build/dist/Types/Monitor/MonitorStepMetricMonitor.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +294 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js +110 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js.map +1 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +58 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +451 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -0
- package/build/dist/Types/Permission.js +40 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Recommendation/RecommendationType.js +21 -0
- package/build/dist/Types/Recommendation/RecommendationType.js.map +1 -0
- package/build/dist/Types/Runbook/RunbookExecutionDeadline.js +93 -0
- package/build/dist/Types/Runbook/RunbookExecutionDeadline.js.map +1 -0
- package/build/dist/Types/Runbook/RunbookStepTimeout.js +142 -0
- package/build/dist/Types/Runbook/RunbookStepTimeout.js.map +1 -0
- package/build/dist/Types/Telemetry/DropFilterSampling.js +75 -0
- package/build/dist/Types/Telemetry/DropFilterSampling.js.map +1 -0
- package/build/dist/UI/Components/AI/GenerateFromAIModal.js +1 -2
- package/build/dist/UI/Components/AI/GenerateFromAIModal.js.map +1 -1
- package/build/dist/UI/Components/Accordion/Accordion.js +9 -2
- package/build/dist/UI/Components/Accordion/Accordion.js.map +1 -1
- package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js +1 -1
- package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js.map +1 -1
- package/build/dist/UI/Components/CodeEditor/CodeEditor.js +27 -14
- package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
- package/build/dist/UI/Components/Date/RangeStartAndEndDateView.js +1 -1
- package/build/dist/UI/Components/Date/RangeStartAndEndDateView.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +2 -20
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/Error/PageError.js +1 -3
- package/build/dist/UI/Components/Error/PageError.js.map +1 -1
- package/build/dist/UI/Components/ErrorBoundary.js +145 -11
- package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
- package/build/dist/UI/Components/InfoCard/InfoCard.js +28 -1
- package/build/dist/UI/Components/InfoCard/InfoCard.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js +13 -2
- package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js.map +1 -1
- package/build/dist/UI/Components/Modal/Modal.js +4 -32
- package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
- package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +69 -33
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js +73 -32
- package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js.map +1 -1
- package/build/dist/UI/Components/Runbook/StepTimeoutInput.js +101 -0
- package/build/dist/UI/Components/Runbook/StepTimeoutInput.js.map +1 -0
- package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js +73 -0
- package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js +13 -2
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js.map +1 -1
- package/build/dist/UI/Utils/DropdownAlignment.js +98 -0
- package/build/dist/UI/Utils/DropdownAlignment.js.map +1 -0
- package/build/dist/UI/Utils/TableFilterUrlState.js +48 -15
- package/build/dist/UI/Utils/TableFilterUrlState.js.map +1 -1
- package/build/dist/Utils/API.js +39 -2
- package/build/dist/Utils/API.js.map +1 -1
- package/build/dist/Utils/Monitor/MonitorSummaryProbeUtil.js +97 -0
- package/build/dist/Utils/Monitor/MonitorSummaryProbeUtil.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js +330 -0
- package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js.map +1 -0
- package/build/dist/Utils/StatusPage/GroupNestingLayout.js +280 -0
- package/build/dist/Utils/StatusPage/GroupNestingLayout.js.map +1 -0
- package/build/dist/Utils/StatusPage/GroupTree.js +214 -0
- package/build/dist/Utils/StatusPage/GroupTree.js.map +1 -0
- package/build/dist/Utils/StatusPage/ResourceUptime.js +60 -16
- package/build/dist/Utils/StatusPage/ResourceUptime.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import StatusPageResourceUptimeUtil from "../../../Utils/StatusPage/ResourceUptime";
|
|
2
2
|
import { Green, Red, Yellow } from "../../../Types/BrandColors";
|
|
3
3
|
import ObjectID from "../../../Types/ObjectID";
|
|
4
|
+
import OneUptimeDate from "../../../Types/Date";
|
|
4
5
|
import Dictionary from "../../../Types/Dictionary";
|
|
6
|
+
import UptimePrecision from "../../../Types/StatusPage/UptimePrecision";
|
|
7
|
+
import { UptimeWindow } from "../../../Utils/Uptime/UptimeUtil";
|
|
8
|
+
import Monitor from "../../../Models/DatabaseModels/Monitor";
|
|
5
9
|
import MonitorStatus from "../../../Models/DatabaseModels/MonitorStatus";
|
|
6
10
|
import MonitorStatusTimeline from "../../../Models/DatabaseModels/MonitorStatusTimeline";
|
|
7
11
|
import StatusPageResource from "../../../Models/DatabaseModels/StatusPageResource";
|
|
@@ -260,4 +264,411 @@ describe("StatusPageResourceUptimeUtil", () => {
|
|
|
260
264
|
expect(result).toHaveLength(0);
|
|
261
265
|
});
|
|
262
266
|
});
|
|
267
|
+
|
|
268
|
+
/*
|
|
269
|
+
* Groups can be nested (Corporate Unit -> Region -> Market -> Site), and the
|
|
270
|
+
* whole point of the hierarchy is that every level reports a rolled up
|
|
271
|
+
* number. These cases pin down what "rolled up" means:
|
|
272
|
+
*
|
|
273
|
+
* - a group's status / uptime covers its own resources AND everything in
|
|
274
|
+
* the groups below it,
|
|
275
|
+
* - the hierarchy is opt in: without the group list the helpers behave
|
|
276
|
+
* exactly as they did before nesting existed,
|
|
277
|
+
* - and the page-wide average counts each resource once, however deep it
|
|
278
|
+
* sits (a parent already averages its subtree, so descending past it
|
|
279
|
+
* would count its children twice).
|
|
280
|
+
*
|
|
281
|
+
* A monitor that is operational for the whole window is 100%, a monitor that
|
|
282
|
+
* is offline for the whole window is 0% - so the expected averages below are
|
|
283
|
+
* exact rather than time-dependent.
|
|
284
|
+
*/
|
|
285
|
+
describe("nested groups", () => {
|
|
286
|
+
const PARENT_GROUP: ObjectID = new ObjectID(
|
|
287
|
+
"cccccccc-cccc-4ccc-8ccc-cccccccccccc",
|
|
288
|
+
);
|
|
289
|
+
const CHILD_GROUP: ObjectID = new ObjectID(
|
|
290
|
+
"dddddddd-dddd-4ddd-8ddd-dddddddddddd",
|
|
291
|
+
);
|
|
292
|
+
const OPERATIONAL_STATUS: ObjectID = new ObjectID(
|
|
293
|
+
"eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee",
|
|
294
|
+
);
|
|
295
|
+
const OFFLINE_STATUS: ObjectID = new ObjectID(
|
|
296
|
+
"ffffffff-ffff-4fff-8fff-ffffffffffff",
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
const uptimeWindow: UptimeWindow = {
|
|
300
|
+
startDate: OneUptimeDate.getSomeDaysAgo(10),
|
|
301
|
+
endDate: OneUptimeDate.getCurrentDate(),
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
function operationalStatus(): MonitorStatus {
|
|
305
|
+
const status: MonitorStatus = new MonitorStatus();
|
|
306
|
+
status._id = OPERATIONAL_STATUS.toString();
|
|
307
|
+
status.name = "Operational";
|
|
308
|
+
status.priority = 1;
|
|
309
|
+
status.color = Green;
|
|
310
|
+
status.isOperationalState = true;
|
|
311
|
+
return status;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function offlineStatus(): MonitorStatus {
|
|
315
|
+
const status: MonitorStatus = new MonitorStatus();
|
|
316
|
+
status._id = OFFLINE_STATUS.toString();
|
|
317
|
+
status.name = "Offline";
|
|
318
|
+
status.priority = 3;
|
|
319
|
+
status.color = Red;
|
|
320
|
+
return status;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// an open timeline row covering the whole reporting window.
|
|
324
|
+
function makeTimeline(data: {
|
|
325
|
+
monitorId: ObjectID;
|
|
326
|
+
status: MonitorStatus;
|
|
327
|
+
}): MonitorStatusTimeline {
|
|
328
|
+
const timeline: MonitorStatusTimeline = new MonitorStatusTimeline();
|
|
329
|
+
timeline.monitorId = data.monitorId;
|
|
330
|
+
timeline.monitorStatus = data.status;
|
|
331
|
+
timeline.monitorStatusId = data.status.id!;
|
|
332
|
+
timeline.startsAt = uptimeWindow.startDate;
|
|
333
|
+
return timeline;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function makeGroup(data: {
|
|
337
|
+
id: ObjectID;
|
|
338
|
+
name: string;
|
|
339
|
+
parentId?: ObjectID | undefined;
|
|
340
|
+
showUptimePercent: boolean;
|
|
341
|
+
}): StatusPageGroup {
|
|
342
|
+
const group: StatusPageGroup = new StatusPageGroup();
|
|
343
|
+
group._id = data.id.toString();
|
|
344
|
+
group.name = data.name;
|
|
345
|
+
group.showUptimePercent = data.showUptimePercent;
|
|
346
|
+
group.uptimePercentPrecision = UptimePrecision.TWO_DECIMAL;
|
|
347
|
+
|
|
348
|
+
if (data.parentId) {
|
|
349
|
+
group.parentStatusPageGroupId = data.parentId;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return group;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function makeResource(data: {
|
|
356
|
+
monitorId: ObjectID;
|
|
357
|
+
currentStatusId: ObjectID;
|
|
358
|
+
groupId?: ObjectID | undefined;
|
|
359
|
+
}): StatusPageResource {
|
|
360
|
+
const resource: StatusPageResource = new StatusPageResource();
|
|
361
|
+
resource.monitorId = data.monitorId;
|
|
362
|
+
resource.showUptimePercent = true;
|
|
363
|
+
|
|
364
|
+
const monitor: Monitor = new Monitor();
|
|
365
|
+
monitor._id = data.monitorId.toString();
|
|
366
|
+
monitor.currentMonitorStatusId = data.currentStatusId;
|
|
367
|
+
resource.monitor = monitor;
|
|
368
|
+
|
|
369
|
+
if (data.groupId) {
|
|
370
|
+
resource.statusPageGroupId = data.groupId;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
return resource;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/*
|
|
377
|
+
* Parent (2 healthy resources) -> Child (1 offline resource).
|
|
378
|
+
* Parent on its own is 100%, the subtree is (100 + 100 + 0) / 3 = 66.66%.
|
|
379
|
+
*/
|
|
380
|
+
function makeFixture(data?: {
|
|
381
|
+
parentShowsUptimePercent?: boolean | undefined;
|
|
382
|
+
}): {
|
|
383
|
+
groups: Array<StatusPageGroup>;
|
|
384
|
+
resources: Array<StatusPageResource>;
|
|
385
|
+
timelines: Array<MonitorStatusTimeline>;
|
|
386
|
+
statuses: Array<MonitorStatus>;
|
|
387
|
+
} {
|
|
388
|
+
const parent: StatusPageGroup = makeGroup({
|
|
389
|
+
id: PARENT_GROUP,
|
|
390
|
+
name: "Corporate Units",
|
|
391
|
+
showUptimePercent: data?.parentShowsUptimePercent ?? true,
|
|
392
|
+
});
|
|
393
|
+
const child: StatusPageGroup = makeGroup({
|
|
394
|
+
id: CHILD_GROUP,
|
|
395
|
+
name: "Region 1000",
|
|
396
|
+
parentId: PARENT_GROUP,
|
|
397
|
+
showUptimePercent: true,
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
return {
|
|
401
|
+
groups: [parent, child],
|
|
402
|
+
resources: [
|
|
403
|
+
makeResource({
|
|
404
|
+
monitorId: MONITOR_A,
|
|
405
|
+
currentStatusId: OPERATIONAL_STATUS,
|
|
406
|
+
groupId: PARENT_GROUP,
|
|
407
|
+
}),
|
|
408
|
+
makeResource({
|
|
409
|
+
monitorId: MONITOR_B,
|
|
410
|
+
currentStatusId: OPERATIONAL_STATUS,
|
|
411
|
+
groupId: PARENT_GROUP,
|
|
412
|
+
}),
|
|
413
|
+
makeResource({
|
|
414
|
+
monitorId: MONITOR_C,
|
|
415
|
+
currentStatusId: OFFLINE_STATUS,
|
|
416
|
+
groupId: CHILD_GROUP,
|
|
417
|
+
}),
|
|
418
|
+
],
|
|
419
|
+
timelines: [
|
|
420
|
+
makeTimeline({ monitorId: MONITOR_A, status: operationalStatus() }),
|
|
421
|
+
makeTimeline({ monitorId: MONITOR_B, status: operationalStatus() }),
|
|
422
|
+
makeTimeline({ monitorId: MONITOR_C, status: offlineStatus() }),
|
|
423
|
+
],
|
|
424
|
+
statuses: [operationalStatus(), offlineStatus()],
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
describe("getResourcesInStatusPageGroupAndDescendants", () => {
|
|
429
|
+
test("a parent covers its own resources and its children's", () => {
|
|
430
|
+
const fixture: ReturnType<typeof makeFixture> = makeFixture();
|
|
431
|
+
|
|
432
|
+
expect(
|
|
433
|
+
StatusPageResourceUptimeUtil.getResourcesInStatusPageGroupAndDescendants(
|
|
434
|
+
{
|
|
435
|
+
statusPageGroup: fixture.groups[0]!,
|
|
436
|
+
statusPageResources: fixture.resources,
|
|
437
|
+
allStatusPageGroups: fixture.groups,
|
|
438
|
+
},
|
|
439
|
+
),
|
|
440
|
+
).toHaveLength(3);
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
test("a child covers only its own resources", () => {
|
|
444
|
+
const fixture: ReturnType<typeof makeFixture> = makeFixture();
|
|
445
|
+
|
|
446
|
+
const resources: Array<StatusPageResource> =
|
|
447
|
+
StatusPageResourceUptimeUtil.getResourcesInStatusPageGroupAndDescendants(
|
|
448
|
+
{
|
|
449
|
+
statusPageGroup: fixture.groups[1]!,
|
|
450
|
+
statusPageResources: fixture.resources,
|
|
451
|
+
allStatusPageGroups: fixture.groups,
|
|
452
|
+
},
|
|
453
|
+
);
|
|
454
|
+
|
|
455
|
+
expect(resources).toHaveLength(1);
|
|
456
|
+
expect(resources[0]!.monitorId?.toString()).toBe(MONITOR_C.toString());
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
test("without the group list it falls back to the group's own resources", () => {
|
|
460
|
+
const fixture: ReturnType<typeof makeFixture> = makeFixture();
|
|
461
|
+
|
|
462
|
+
expect(
|
|
463
|
+
StatusPageResourceUptimeUtil.getResourcesInStatusPageGroupAndDescendants(
|
|
464
|
+
{
|
|
465
|
+
statusPageGroup: fixture.groups[0]!,
|
|
466
|
+
statusPageResources: fixture.resources,
|
|
467
|
+
},
|
|
468
|
+
),
|
|
469
|
+
).toHaveLength(2);
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
test("never picks up ungrouped resources", () => {
|
|
473
|
+
const fixture: ReturnType<typeof makeFixture> = makeFixture();
|
|
474
|
+
|
|
475
|
+
const ungrouped: StatusPageResource = makeResource({
|
|
476
|
+
monitorId: MONITOR_A,
|
|
477
|
+
currentStatusId: OPERATIONAL_STATUS,
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
expect(
|
|
481
|
+
StatusPageResourceUptimeUtil.getResourcesInStatusPageGroupAndDescendants(
|
|
482
|
+
{
|
|
483
|
+
statusPageGroup: fixture.groups[0]!,
|
|
484
|
+
statusPageResources: [...fixture.resources, ungrouped],
|
|
485
|
+
allStatusPageGroups: fixture.groups,
|
|
486
|
+
},
|
|
487
|
+
),
|
|
488
|
+
).toHaveLength(3);
|
|
489
|
+
});
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
describe("calculateAvgUptimePercentOfStatusPageGroup", () => {
|
|
493
|
+
test("a parent averages every resource in its subtree", () => {
|
|
494
|
+
const fixture: ReturnType<typeof makeFixture> = makeFixture();
|
|
495
|
+
|
|
496
|
+
expect(
|
|
497
|
+
StatusPageResourceUptimeUtil.calculateAvgUptimePercentOfStatusPageGroup(
|
|
498
|
+
{
|
|
499
|
+
statusPageGroup: fixture.groups[0]!,
|
|
500
|
+
monitorStatusTimelines: fixture.timelines,
|
|
501
|
+
precision: UptimePrecision.TWO_DECIMAL,
|
|
502
|
+
downtimeMonitorStatuses: [offlineStatus()],
|
|
503
|
+
statusPageResources: fixture.resources,
|
|
504
|
+
monitorsInGroup: {},
|
|
505
|
+
uptimeWindow: uptimeWindow,
|
|
506
|
+
allStatusPageGroups: fixture.groups,
|
|
507
|
+
},
|
|
508
|
+
),
|
|
509
|
+
).toBe(66.66);
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
test("a child reports only its own resources", () => {
|
|
513
|
+
const fixture: ReturnType<typeof makeFixture> = makeFixture();
|
|
514
|
+
|
|
515
|
+
expect(
|
|
516
|
+
StatusPageResourceUptimeUtil.calculateAvgUptimePercentOfStatusPageGroup(
|
|
517
|
+
{
|
|
518
|
+
statusPageGroup: fixture.groups[1]!,
|
|
519
|
+
monitorStatusTimelines: fixture.timelines,
|
|
520
|
+
precision: UptimePrecision.TWO_DECIMAL,
|
|
521
|
+
downtimeMonitorStatuses: [offlineStatus()],
|
|
522
|
+
statusPageResources: fixture.resources,
|
|
523
|
+
monitorsInGroup: {},
|
|
524
|
+
uptimeWindow: uptimeWindow,
|
|
525
|
+
allStatusPageGroups: fixture.groups,
|
|
526
|
+
},
|
|
527
|
+
),
|
|
528
|
+
).toBe(0);
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
test("without the group list a parent reports only its own resources", () => {
|
|
532
|
+
const fixture: ReturnType<typeof makeFixture> = makeFixture();
|
|
533
|
+
|
|
534
|
+
expect(
|
|
535
|
+
StatusPageResourceUptimeUtil.calculateAvgUptimePercentOfStatusPageGroup(
|
|
536
|
+
{
|
|
537
|
+
statusPageGroup: fixture.groups[0]!,
|
|
538
|
+
monitorStatusTimelines: fixture.timelines,
|
|
539
|
+
precision: UptimePrecision.TWO_DECIMAL,
|
|
540
|
+
downtimeMonitorStatuses: [offlineStatus()],
|
|
541
|
+
statusPageResources: fixture.resources,
|
|
542
|
+
monitorsInGroup: {},
|
|
543
|
+
uptimeWindow: uptimeWindow,
|
|
544
|
+
},
|
|
545
|
+
),
|
|
546
|
+
).toBe(100);
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
test("a group that does not show uptime percent reports nothing", () => {
|
|
550
|
+
const fixture: ReturnType<typeof makeFixture> = makeFixture({
|
|
551
|
+
parentShowsUptimePercent: false,
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
expect(
|
|
555
|
+
StatusPageResourceUptimeUtil.calculateAvgUptimePercentOfStatusPageGroup(
|
|
556
|
+
{
|
|
557
|
+
statusPageGroup: fixture.groups[0]!,
|
|
558
|
+
monitorStatusTimelines: fixture.timelines,
|
|
559
|
+
precision: UptimePrecision.TWO_DECIMAL,
|
|
560
|
+
downtimeMonitorStatuses: [offlineStatus()],
|
|
561
|
+
statusPageResources: fixture.resources,
|
|
562
|
+
monitorsInGroup: {},
|
|
563
|
+
uptimeWindow: uptimeWindow,
|
|
564
|
+
allStatusPageGroups: fixture.groups,
|
|
565
|
+
},
|
|
566
|
+
),
|
|
567
|
+
).toBeNull();
|
|
568
|
+
});
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
describe("getCurrentStatusPageGroupStatus", () => {
|
|
572
|
+
test("a parent takes the worst status in its subtree", () => {
|
|
573
|
+
const fixture: ReturnType<typeof makeFixture> = makeFixture();
|
|
574
|
+
|
|
575
|
+
const status: MonitorStatus =
|
|
576
|
+
StatusPageResourceUptimeUtil.getCurrentStatusPageGroupStatus({
|
|
577
|
+
statusPageGroup: fixture.groups[0]!,
|
|
578
|
+
monitorStatusTimelines: fixture.timelines,
|
|
579
|
+
statusPageResources: fixture.resources,
|
|
580
|
+
monitorStatuses: fixture.statuses,
|
|
581
|
+
monitorGroupCurrentStatuses: {},
|
|
582
|
+
allStatusPageGroups: fixture.groups,
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
expect(status.name).toBe("Offline");
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
test("without the group list a parent only sees its own resources", () => {
|
|
589
|
+
const fixture: ReturnType<typeof makeFixture> = makeFixture();
|
|
590
|
+
|
|
591
|
+
const status: MonitorStatus =
|
|
592
|
+
StatusPageResourceUptimeUtil.getCurrentStatusPageGroupStatus({
|
|
593
|
+
statusPageGroup: fixture.groups[0]!,
|
|
594
|
+
monitorStatusTimelines: fixture.timelines,
|
|
595
|
+
statusPageResources: fixture.resources,
|
|
596
|
+
monitorStatuses: fixture.statuses,
|
|
597
|
+
monitorGroupCurrentStatuses: {},
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
expect(status.name).toBe("Operational");
|
|
601
|
+
});
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
describe("calculateAvgUptimePercentageOfAllResources", () => {
|
|
605
|
+
test("counts a nested resource once, through its top most reporting ancestor", () => {
|
|
606
|
+
const fixture: ReturnType<typeof makeFixture> = makeFixture();
|
|
607
|
+
|
|
608
|
+
/*
|
|
609
|
+
* The parent already averages all three resources (66.66%). Averaging
|
|
610
|
+
* the parent and the child together would count the offline resource
|
|
611
|
+
* twice and land on 33.33%.
|
|
612
|
+
*/
|
|
613
|
+
expect(
|
|
614
|
+
StatusPageResourceUptimeUtil.calculateAvgUptimePercentageOfAllResources(
|
|
615
|
+
{
|
|
616
|
+
monitorStatusTimelines: fixture.timelines,
|
|
617
|
+
precision: UptimePrecision.TWO_DECIMAL,
|
|
618
|
+
downtimeMonitorStatuses: [offlineStatus()],
|
|
619
|
+
statusPageResources: fixture.resources,
|
|
620
|
+
resourceGroups: fixture.groups,
|
|
621
|
+
monitorsInGroup: {},
|
|
622
|
+
uptimeWindow: uptimeWindow,
|
|
623
|
+
},
|
|
624
|
+
),
|
|
625
|
+
).toBe(66.66);
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
test("descends past a parent that does not report uptime percent", () => {
|
|
629
|
+
const fixture: ReturnType<typeof makeFixture> = makeFixture({
|
|
630
|
+
parentShowsUptimePercent: false,
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
// only the child reports, and everything in the child is offline.
|
|
634
|
+
expect(
|
|
635
|
+
StatusPageResourceUptimeUtil.calculateAvgUptimePercentageOfAllResources(
|
|
636
|
+
{
|
|
637
|
+
monitorStatusTimelines: fixture.timelines,
|
|
638
|
+
precision: UptimePrecision.TWO_DECIMAL,
|
|
639
|
+
downtimeMonitorStatuses: [offlineStatus()],
|
|
640
|
+
statusPageResources: fixture.resources,
|
|
641
|
+
resourceGroups: fixture.groups,
|
|
642
|
+
monitorsInGroup: {},
|
|
643
|
+
uptimeWindow: uptimeWindow,
|
|
644
|
+
},
|
|
645
|
+
),
|
|
646
|
+
).toBe(0);
|
|
647
|
+
});
|
|
648
|
+
|
|
649
|
+
test("still includes resources that are in no group at all", () => {
|
|
650
|
+
const fixture: ReturnType<typeof makeFixture> = makeFixture();
|
|
651
|
+
|
|
652
|
+
const ungrouped: StatusPageResource = makeResource({
|
|
653
|
+
monitorId: MONITOR_C,
|
|
654
|
+
currentStatusId: OFFLINE_STATUS,
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
// parent subtree 66.66%, ungrouped offline resource 0% -> 33.33%.
|
|
658
|
+
expect(
|
|
659
|
+
StatusPageResourceUptimeUtil.calculateAvgUptimePercentageOfAllResources(
|
|
660
|
+
{
|
|
661
|
+
monitorStatusTimelines: fixture.timelines,
|
|
662
|
+
precision: UptimePrecision.TWO_DECIMAL,
|
|
663
|
+
downtimeMonitorStatuses: [offlineStatus()],
|
|
664
|
+
statusPageResources: [...fixture.resources, ungrouped],
|
|
665
|
+
resourceGroups: fixture.groups,
|
|
666
|
+
monitorsInGroup: {},
|
|
667
|
+
uptimeWindow: uptimeWindow,
|
|
668
|
+
},
|
|
669
|
+
),
|
|
670
|
+
).toBe(33.33);
|
|
671
|
+
});
|
|
672
|
+
});
|
|
673
|
+
});
|
|
263
674
|
});
|
package/Types/Date.ts
CHANGED
|
@@ -341,7 +341,10 @@ export default class OneUptimeDate {
|
|
|
341
341
|
const local: moment.Moment = this.inCurrentTimezone(date);
|
|
342
342
|
return (
|
|
343
343
|
local.format(formatString) +
|
|
344
|
-
(data.onlyShowDate
|
|
344
|
+
(data.onlyShowDate
|
|
345
|
+
? ""
|
|
346
|
+
: // Same DST-aware lookup the explicit-timezone branch below uses.
|
|
347
|
+
" " + this.getZoneAbbrByTimezone(this.getCurrentTimezone(), date))
|
|
345
348
|
).trim();
|
|
346
349
|
}
|
|
347
350
|
|
|
@@ -1746,11 +1749,17 @@ export default class OneUptimeDate {
|
|
|
1746
1749
|
|
|
1747
1750
|
const momentDate: moment.Moment = this.inCurrentTimezone(date);
|
|
1748
1751
|
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1752
|
+
/*
|
|
1753
|
+
* The abbreviation has to describe THIS date's offset, not today's. Asking
|
|
1754
|
+
* for it without the date labelled every January timestamp "EDT" all
|
|
1755
|
+
* summer — a wall clock paired with the wrong zone names a different
|
|
1756
|
+
* instant, which is worse than printing no zone at all.
|
|
1757
|
+
*/
|
|
1758
|
+
const zoneAbbr: string = onlyShowDate
|
|
1759
|
+
? ""
|
|
1760
|
+
: this.getZoneAbbrByTimezone(this.getCurrentTimezone(), date);
|
|
1761
|
+
|
|
1762
|
+
return (momentDate.format(formatstring) + " " + zoneAbbr).trim();
|
|
1754
1763
|
}
|
|
1755
1764
|
|
|
1756
1765
|
public static getDayInSeconds(days?: number | undefined): number {
|
|
@@ -959,6 +959,208 @@ const nodeMemoryRequestUtilizationTemplate: KubernetesAlertTemplate = {
|
|
|
959
959
|
},
|
|
960
960
|
};
|
|
961
961
|
|
|
962
|
+
/*
|
|
963
|
+
* --- Autoscaling / limit-saturation templates ---
|
|
964
|
+
*
|
|
965
|
+
* These three close the detection gap for the classic "under-resourced
|
|
966
|
+
* workload behind an autoscaler" failure: limits are set too low, so the
|
|
967
|
+
* containers sit pinned against them (OOMKilled on memory, CFS-throttled
|
|
968
|
+
* on CPU), the resulting latency/restarts drive the HPA up, and the HPA
|
|
969
|
+
* fills the cluster until nodes go NotReady.
|
|
970
|
+
*
|
|
971
|
+
* The node-side templates above catch the END of that chain (high node
|
|
972
|
+
* CPU/memory, NotReady, pending pods) — by which point the RCA is several
|
|
973
|
+
* hops from the cause. These catch the START: the HPA running out of
|
|
974
|
+
* headroom, and the containers pinned at their own limits.
|
|
975
|
+
*
|
|
976
|
+
* All three are per-series ratios, grouped by the ClickHouse-stored
|
|
977
|
+
* `resource.`-prefixed attribute (see buildKubernetesRatioMonitorConfig).
|
|
978
|
+
*/
|
|
979
|
+
|
|
980
|
+
const hpaAtMaxReplicasTemplate: KubernetesAlertTemplate = {
|
|
981
|
+
id: "k8s-hpa-at-max-replicas",
|
|
982
|
+
name: "HPA Saturated at Max Replicas",
|
|
983
|
+
description:
|
|
984
|
+
"Alert when a HorizontalPodAutoscaler is running at 90% or more of its maxReplicas. Computed per HPA as k8s.hpa.current_replicas ÷ k8s.hpa.max_replicas × 100. An HPA at its ceiling has no headroom left: load it cannot absorb by scaling turns straight into latency and errors, and a workload that reaches the ceiling and stays there is usually under-resourced per pod rather than genuinely at capacity.",
|
|
985
|
+
category: "Workload",
|
|
986
|
+
severity: "Critical",
|
|
987
|
+
getMonitorStep: (args: KubernetesAlertTemplateArgs): MonitorStep => {
|
|
988
|
+
const metricAlias: string = "hpa_replica_saturation";
|
|
989
|
+
|
|
990
|
+
return buildKubernetesMonitorStep({
|
|
991
|
+
kubernetesMonitor: buildKubernetesRatioMonitorConfig({
|
|
992
|
+
clusterIdentifier: args.clusterIdentifier,
|
|
993
|
+
numeratorMetricName: "k8s.hpa.current_replicas",
|
|
994
|
+
denominatorMetricName: "k8s.hpa.max_replicas",
|
|
995
|
+
groupByAttributeKey: "resource.k8s.hpa.name",
|
|
996
|
+
numeratorAlias: "current_replicas",
|
|
997
|
+
denominatorAlias: "max_replicas",
|
|
998
|
+
resultAlias: metricAlias,
|
|
999
|
+
resultLegend: "HPA Replica Saturation (%)",
|
|
1000
|
+
resourceScope: KubernetesResourceScope.Workload,
|
|
1001
|
+
rollingTime: RollingTime.Past5Minutes,
|
|
1002
|
+
/*
|
|
1003
|
+
* ONE series per HPA on both sides (they are the same object's
|
|
1004
|
+
* status/spec fields), so Avg gives the representative per-minute
|
|
1005
|
+
* ratio independent of scrape count. Both come from the same
|
|
1006
|
+
* k8s_cluster scrape, so Sum would also cancel — but Avg stays
|
|
1007
|
+
* correct across restarts and missed scrapes. See
|
|
1008
|
+
* buildKubernetesRatioMonitorConfig.
|
|
1009
|
+
*/
|
|
1010
|
+
aggregationType: MetricsAggregationType.Avg,
|
|
1011
|
+
}),
|
|
1012
|
+
offlineCriteriaInstance: buildOfflineCriteriaInstance({
|
|
1013
|
+
offlineMonitorStatusId: args.offlineMonitorStatusId,
|
|
1014
|
+
incidentSeverityId: args.defaultIncidentSeverityId,
|
|
1015
|
+
alertSeverityId: args.defaultAlertSeverityId,
|
|
1016
|
+
monitorName: args.monitorName,
|
|
1017
|
+
metricAlias,
|
|
1018
|
+
filterType: FilterType.GreaterThanOrEqualTo,
|
|
1019
|
+
value: 90,
|
|
1020
|
+
incidentTitle: `[K8s] HPA Saturated at Max Replicas (>=90%) - ${args.monitorName}`,
|
|
1021
|
+
incidentDescription: `A HorizontalPodAutoscaler is running at 90% or more of its maxReplicas and has effectively no scaling headroom left. Any further load cannot be absorbed by scaling out, so it will surface as latency and errors instead. Check whether the workload is genuinely at capacity or whether its per-pod CPU/memory limits are set too low — an under-resourced pod gets throttled or OOMKilled, which inflates the metric the HPA scales on and drives it to the ceiling. Check the root cause for the specific HPA, its target workload, and current vs max replicas.`,
|
|
1022
|
+
criteriaName: "HPA Saturation - Current/Max Replicas >= 90%",
|
|
1023
|
+
criteriaDescription:
|
|
1024
|
+
"Triggers when any HPA's current replica count reaches 90% or more of its configured maxReplicas.",
|
|
1025
|
+
}),
|
|
1026
|
+
onlineCriteriaInstance: buildOnlineCriteriaInstance({
|
|
1027
|
+
onlineMonitorStatusId: args.onlineMonitorStatusId,
|
|
1028
|
+
metricAlias,
|
|
1029
|
+
filterType: FilterType.LessThan,
|
|
1030
|
+
value: 90,
|
|
1031
|
+
}),
|
|
1032
|
+
});
|
|
1033
|
+
},
|
|
1034
|
+
};
|
|
1035
|
+
|
|
1036
|
+
const podMemoryLimitSaturationTemplate: KubernetesAlertTemplate = {
|
|
1037
|
+
id: "k8s-pod-memory-limit-saturation",
|
|
1038
|
+
name: "Pod Memory Saturating Container Limit",
|
|
1039
|
+
description:
|
|
1040
|
+
"Alert when a pod's memory usage exceeds 90% of its configured container memory limit — the state immediately preceding an OOMKill. Computed per pod as k8s.pod.memory.usage ÷ k8s.container.memory_limit × 100 (both bytes). This is the cause-side signal for CrashLoopBackOff and restart storms: a limit set too low shows up here minutes before the container is killed.",
|
|
1041
|
+
category: "Workload",
|
|
1042
|
+
severity: "Critical",
|
|
1043
|
+
getMonitorStep: (args: KubernetesAlertTemplateArgs): MonitorStep => {
|
|
1044
|
+
const metricAlias: string = "pod_memory_limit_saturation";
|
|
1045
|
+
|
|
1046
|
+
return buildKubernetesMonitorStep({
|
|
1047
|
+
kubernetesMonitor: buildKubernetesRatioMonitorConfig({
|
|
1048
|
+
clusterIdentifier: args.clusterIdentifier,
|
|
1049
|
+
numeratorMetricName: "k8s.pod.memory.usage",
|
|
1050
|
+
denominatorMetricName: "k8s.container.memory_limit",
|
|
1051
|
+
groupByAttributeKey: "resource.k8s.pod.name",
|
|
1052
|
+
numeratorAlias: "used_mem",
|
|
1053
|
+
denominatorAlias: "limit_mem",
|
|
1054
|
+
resultAlias: metricAlias,
|
|
1055
|
+
resultLegend: "Pod Memory vs Limit (%)",
|
|
1056
|
+
resourceScope: KubernetesResourceScope.Pod,
|
|
1057
|
+
rollingTime: RollingTime.Past5Minutes,
|
|
1058
|
+
/*
|
|
1059
|
+
* Avg, deliberately — and the one case in this file where the two
|
|
1060
|
+
* sides have different series shapes, so the trade-off is worth
|
|
1061
|
+
* stating.
|
|
1062
|
+
*
|
|
1063
|
+
* Numerator (k8s.pod.memory.usage, kubeletstats) is ONE series per
|
|
1064
|
+
* pod. Denominator (k8s.container.memory_limit, k8s_cluster) is one
|
|
1065
|
+
* series per CONTAINER, so a multi-container pod contributes
|
|
1066
|
+
* several.
|
|
1067
|
+
*
|
|
1068
|
+
* Sum is definitively wrong here: the two metrics ride different
|
|
1069
|
+
* receivers on independent scrape cycles, so the scrape multiple
|
|
1070
|
+
* would not cancel. Avg is exact for single-container pods (the
|
|
1071
|
+
* overwhelming majority, and the case this template exists for).
|
|
1072
|
+
*
|
|
1073
|
+
* For multi-container pods Avg takes the MEAN container limit
|
|
1074
|
+
* rather than their sum, so the ratio over-reports and the alert
|
|
1075
|
+
* fires early. That is the safe direction for an "OOMKill is
|
|
1076
|
+
* imminent" warning — a false early page beats a missed kill — but
|
|
1077
|
+
* it is a real caveat, not a rounding detail. A per-container
|
|
1078
|
+
* variant needs a container-scoped usage metric to pair against
|
|
1079
|
+
* (`container.memory.usage`), which the shipped catalog does not
|
|
1080
|
+
* carry today.
|
|
1081
|
+
*/
|
|
1082
|
+
aggregationType: MetricsAggregationType.Avg,
|
|
1083
|
+
}),
|
|
1084
|
+
offlineCriteriaInstance: buildOfflineCriteriaInstance({
|
|
1085
|
+
offlineMonitorStatusId: args.offlineMonitorStatusId,
|
|
1086
|
+
incidentSeverityId: args.defaultIncidentSeverityId,
|
|
1087
|
+
alertSeverityId: args.defaultAlertSeverityId,
|
|
1088
|
+
monitorName: args.monitorName,
|
|
1089
|
+
metricAlias,
|
|
1090
|
+
filterType: FilterType.GreaterThan,
|
|
1091
|
+
value: 90,
|
|
1092
|
+
incidentTitle: `[K8s] Pod Memory Saturating Container Limit (>90%) - ${args.monitorName}`,
|
|
1093
|
+
incidentDescription: `A pod's memory usage has exceeded 90% of its configured container memory limit. The kubelet OOMKills a container the moment it crosses its limit, so this is the state immediately preceding a restart — and, if the workload sits behind an autoscaler, the start of a restart/scale-up loop. Either the limit is set too low for the workload's real footprint or the workload has a memory leak. Check the root cause for the specific pod, its limit, and its usage trend.`,
|
|
1094
|
+
criteriaName: "Pod Memory Saturation - Usage/Limit > 90%",
|
|
1095
|
+
criteriaDescription:
|
|
1096
|
+
"Triggers when any pod's memory usage exceeds 90% of its container memory limit.",
|
|
1097
|
+
}),
|
|
1098
|
+
onlineCriteriaInstance: buildOnlineCriteriaInstance({
|
|
1099
|
+
onlineMonitorStatusId: args.onlineMonitorStatusId,
|
|
1100
|
+
metricAlias,
|
|
1101
|
+
filterType: FilterType.LessThanOrEqualTo,
|
|
1102
|
+
value: 90,
|
|
1103
|
+
}),
|
|
1104
|
+
});
|
|
1105
|
+
},
|
|
1106
|
+
};
|
|
1107
|
+
|
|
1108
|
+
const podCpuLimitSaturationTemplate: KubernetesAlertTemplate = {
|
|
1109
|
+
id: "k8s-pod-cpu-limit-saturation",
|
|
1110
|
+
name: "Pod CPU Saturating Container Limit",
|
|
1111
|
+
description:
|
|
1112
|
+
"Alert when a pod's CPU usage exceeds 90% of its configured container CPU limit — the point at which the kernel's CFS quota starts throttling it. Computed per pod as k8s.pod.cpu.utilization ÷ k8s.container.cpu_limit × 100; both are CPU cores, so this is a true percentage (k8s.pod.cpu.utilization is a misnamed cores gauge, not a percent). A throttled pod gets slower, not louder — behind an HPA that reads CPU, throttling drives the replica count up while every pod stays equally starved.",
|
|
1113
|
+
category: "Workload",
|
|
1114
|
+
severity: "Warning",
|
|
1115
|
+
getMonitorStep: (args: KubernetesAlertTemplateArgs): MonitorStep => {
|
|
1116
|
+
const metricAlias: string = "pod_cpu_limit_saturation";
|
|
1117
|
+
|
|
1118
|
+
return buildKubernetesMonitorStep({
|
|
1119
|
+
kubernetesMonitor: buildKubernetesRatioMonitorConfig({
|
|
1120
|
+
clusterIdentifier: args.clusterIdentifier,
|
|
1121
|
+
numeratorMetricName: "k8s.pod.cpu.utilization",
|
|
1122
|
+
denominatorMetricName: "k8s.container.cpu_limit",
|
|
1123
|
+
groupByAttributeKey: "resource.k8s.pod.name",
|
|
1124
|
+
numeratorAlias: "used_cpu",
|
|
1125
|
+
denominatorAlias: "limit_cpu",
|
|
1126
|
+
resultAlias: metricAlias,
|
|
1127
|
+
resultLegend: "Pod CPU vs Limit (%)",
|
|
1128
|
+
resourceScope: KubernetesResourceScope.Pod,
|
|
1129
|
+
rollingTime: RollingTime.Past5Minutes,
|
|
1130
|
+
/*
|
|
1131
|
+
* Avg, for the same reason as the memory template above: ONE
|
|
1132
|
+
* numerator series per pod (kubeletstats) against a per-container
|
|
1133
|
+
* denominator (k8s_cluster) on an independent scrape cycle. Exact
|
|
1134
|
+
* for single-container pods; over-reports (fires early) for
|
|
1135
|
+
* multi-container pods. See that template's note for the full
|
|
1136
|
+
* trade-off.
|
|
1137
|
+
*/
|
|
1138
|
+
aggregationType: MetricsAggregationType.Avg,
|
|
1139
|
+
}),
|
|
1140
|
+
offlineCriteriaInstance: buildOfflineCriteriaInstance({
|
|
1141
|
+
offlineMonitorStatusId: args.offlineMonitorStatusId,
|
|
1142
|
+
incidentSeverityId: args.defaultIncidentSeverityId,
|
|
1143
|
+
alertSeverityId: args.defaultAlertSeverityId,
|
|
1144
|
+
monitorName: args.monitorName,
|
|
1145
|
+
metricAlias,
|
|
1146
|
+
filterType: FilterType.GreaterThan,
|
|
1147
|
+
value: 90,
|
|
1148
|
+
incidentTitle: `[K8s] Pod CPU Saturating Container Limit (>90%) - ${args.monitorName}`,
|
|
1149
|
+
incidentDescription: `A pod's CPU usage has exceeded 90% of its configured container CPU limit and is being throttled by the kernel's CFS quota. Throttling is silent — the pod does not crash, it just gets slower, so this usually surfaces as request latency rather than as an error. If the workload sits behind a CPU-based HorizontalPodAutoscaler, throttling also inflates the metric the HPA scales on, so the autoscaler adds replicas that are each equally starved. Check whether the CPU limit is set too low for the workload rather than adding replicas.`,
|
|
1150
|
+
criteriaName: "Pod CPU Saturation - Usage/Limit > 90%",
|
|
1151
|
+
criteriaDescription:
|
|
1152
|
+
"Triggers when any pod's CPU usage exceeds 90% of its container CPU limit.",
|
|
1153
|
+
}),
|
|
1154
|
+
onlineCriteriaInstance: buildOnlineCriteriaInstance({
|
|
1155
|
+
onlineMonitorStatusId: args.onlineMonitorStatusId,
|
|
1156
|
+
metricAlias,
|
|
1157
|
+
filterType: FilterType.LessThanOrEqualTo,
|
|
1158
|
+
value: 90,
|
|
1159
|
+
}),
|
|
1160
|
+
});
|
|
1161
|
+
},
|
|
1162
|
+
};
|
|
1163
|
+
|
|
962
1164
|
export function getAllKubernetesAlertTemplates(): Array<KubernetesAlertTemplate> {
|
|
963
1165
|
return [
|
|
964
1166
|
crashLoopBackOffTemplate,
|
|
@@ -975,6 +1177,9 @@ export function getAllKubernetesAlertTemplates(): Array<KubernetesAlertTemplate>
|
|
|
975
1177
|
daemonSetUnavailableTemplate,
|
|
976
1178
|
nodeCpuRequestUtilizationTemplate,
|
|
977
1179
|
nodeMemoryRequestUtilizationTemplate,
|
|
1180
|
+
hpaAtMaxReplicasTemplate,
|
|
1181
|
+
podMemoryLimitSaturationTemplate,
|
|
1182
|
+
podCpuLimitSaturationTemplate,
|
|
978
1183
|
];
|
|
979
1184
|
}
|
|
980
1185
|
|