@oneuptime/common 11.6.1 → 11.7.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/AnalyticsModels/Index.ts +4 -0
- package/Models/AnalyticsModels/KubernetesCostAllocation.ts +842 -0
- package/Models/AnalyticsModels/NetworkFlow.ts +54 -0
- package/Models/AnalyticsModels/SloHistory.ts +243 -0
- package/Models/DatabaseModels/Index.ts +20 -0
- package/Models/DatabaseModels/NetworkDevice.ts +453 -6
- package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +7 -6
- package/Models/DatabaseModels/NetworkEndpoint.ts +753 -0
- package/Models/DatabaseModels/NetworkSite.ts +1155 -0
- package/Models/DatabaseModels/NetworkSiteAssignmentRule.ts +517 -0
- package/Models/DatabaseModels/NetworkSiteLink.ts +611 -0
- package/Models/DatabaseModels/NetworkSiteStatusTimeline.ts +520 -0
- package/Models/DatabaseModels/NetworkSiteType.ts +499 -0
- package/Models/DatabaseModels/ServiceLevelObjective.ts +1115 -0
- package/Models/DatabaseModels/ServiceLevelObjectiveBurnRateRule.ts +762 -0
- package/Models/DatabaseModels/ServiceLevelObjectiveOwnerTeam.ts +444 -0
- package/Models/DatabaseModels/ServiceLevelObjectiveOwnerUser.ts +443 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784757142154-AddNetworkSiteHierarchyAndEndpoints.ts +359 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784897317860-AddNetworkSiteAlerting.ts +48 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784970388777-AddNetworkDevicePollingColumns.ts +65 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784986826214-AddNetworkSiteTypeTable.ts +88 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784987015619-AddServiceLevelObjective.ts +391 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785066759532-MigrationName.ts +30 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
- package/Server/Services/AnalyticsDatabaseService.ts +25 -9
- package/Server/Services/Index.ts +24 -0
- package/Server/Services/KubernetesCostAllocationService.ts +14 -0
- package/Server/Services/MetricService.ts +21 -2
- package/Server/Services/MonitorService.ts +22 -0
- package/Server/Services/NetworkDeviceService.ts +438 -2
- package/Server/Services/NetworkEndpointService.ts +414 -0
- package/Server/Services/NetworkSiteAssignmentRuleService.ts +98 -0
- package/Server/Services/NetworkSiteLinkService.ts +10 -0
- package/Server/Services/NetworkSiteService.ts +1254 -0
- package/Server/Services/NetworkSiteStatusTimelineService.ts +10 -0
- package/Server/Services/NetworkSiteTypeService.ts +10 -0
- package/Server/Services/ProjectService.ts +122 -2
- package/Server/Services/ServiceLevelObjectiveBurnRateRuleService.ts +457 -0
- package/Server/Services/ServiceLevelObjectiveOwnerTeamService.ts +10 -0
- package/Server/Services/ServiceLevelObjectiveOwnerUserService.ts +10 -0
- package/Server/Services/ServiceLevelObjectiveService.ts +685 -0
- package/Server/Services/SloHistoryService.ts +101 -0
- package/Server/Services/UserNotificationSettingService.ts +37 -0
- package/Server/Types/AnalyticsDatabase/AggregateBy.ts +9 -0
- package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +15 -0
- package/Server/Utils/AnalyticsDatabase/Statement.ts +39 -3
- package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +87 -48
- package/Server/Utils/Memory.ts +9 -1
- package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +190 -12
- package/Server/Utils/Monitor/Data/OuiVendors.json +6920 -0
- package/Server/Utils/Monitor/DnsResolutionCache.ts +129 -0
- package/Server/Utils/Monitor/MonitorResource.ts +4 -30
- package/Server/Utils/Monitor/NetworkDeviceHydrationUtil.ts +214 -39
- package/Server/Utils/Monitor/NetworkDeviceMetricUtil.ts +343 -0
- package/Server/Utils/Monitor/NetworkDeviceWalkUtil.ts +251 -0
- package/Server/Utils/Monitor/NetworkInventoryUtil.ts +176 -142
- package/Server/Utils/Monitor/OuiLookupUtil.ts +49 -0
- package/Server/Utils/Monitor/SnmpInterfaceRateUtil.ts +17 -13
- package/Server/Utils/WhatsAppTemplateUtil.ts +7 -3
- package/Tests/Models/AnalyticsModels/KubernetesCostAllocation.test.ts +135 -0
- package/Tests/Models/NetworkSiteHierarchy.test.ts +134 -0
- package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +239 -0
- package/Tests/Server/Services/KubernetesCostAllocationAggregate.test.ts +338 -0
- package/Tests/Server/Services/MetricServiceAggregate.test.ts +142 -0
- package/Tests/Server/Services/NetworkDeviceSiteAssignment.test.ts +484 -0
- package/Tests/Server/Services/NetworkEndpointServiceUpsert.test.ts +686 -0
- package/Tests/Server/Services/NetworkSiteAssignmentRuleService.test.ts +185 -0
- package/Tests/Server/Services/NetworkSiteService.test.ts +1354 -0
- package/Tests/Server/Services/ServiceLevelObjectiveBurnRateRuleService.test.ts +1313 -0
- package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +1988 -0
- package/Tests/Server/Utils/AnalyticsDatabase/Statement.test.ts +22 -0
- package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +404 -0
- package/Tests/Server/Utils/Encryption.test.ts +70 -0
- package/Tests/Server/Utils/FileAttachmentMarkdownUtil.test.ts +225 -0
- package/Tests/Server/Utils/JsonWebToken.test.ts +175 -0
- package/Tests/Server/Utils/LocalFile.test.ts +258 -0
- package/Tests/Server/Utils/Memory.test.ts +213 -0
- package/Tests/Server/Utils/Monitor/Criteria/LogMonitorCriteria.test.ts +30 -0
- package/Tests/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.test.ts +385 -0
- package/Tests/Server/Utils/Monitor/DnsResolutionCache.test.ts +194 -0
- package/Tests/Server/Utils/Monitor/NetworkDeviceHydrationUtil.test.ts +155 -0
- package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +600 -0
- package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +151 -124
- package/Tests/Server/Utils/Monitor/SnmpInterfaceRateUtil.test.ts +496 -0
- package/Tests/Server/Utils/MonitorCriteriaDataExtractor.test.ts +175 -0
- package/Tests/Server/Utils/MonitorCriteriaMessageFormatter.test.ts +282 -0
- package/Tests/Server/Utils/OuiLookupUtil.test.ts +59 -0
- package/Tests/Server/Utils/SeriesResourceLabels.test.ts +117 -0
- package/Tests/Server/Utils/StackTraceParser.test.ts +370 -0
- package/Tests/Server/Utils/Stream.test.ts +87 -0
- package/Tests/Server/Utils/ValidateGlobalProviderProjectTeams.test.ts +221 -0
- package/Tests/Server/Utils/WhatsAppTemplateUtil.test.ts +199 -0
- package/Tests/Types/Database/CompareOperatorWireSerialization.test.ts +33 -0
- package/Tests/Types/Email.test.ts +198 -0
- package/Tests/Types/Kubernetes/KubernetesObjectParser.test.ts +177 -0
- package/Tests/Types/Log/LogQueryToFilter.test.ts +111 -0
- package/Tests/Types/Monitor/MonitorCriteria.test.ts +155 -0
- package/Tests/Types/Monitor/MonitorCriteriaInstance.test.ts +465 -0
- package/Tests/Types/Monitor/MonitorStep.test.ts +183 -0
- package/Tests/Types/Monitor/MonitorStepNetworkDeviceMonitor.test.ts +141 -1
- package/Tests/Types/Monitor/MonitorSteps.test.ts +183 -0
- package/Tests/Types/Monitor/MonitorType.test.ts +59 -1
- package/Tests/Types/Monitor/NetworkDeviceAlertPack.test.ts +97 -0
- package/Tests/Types/Monitor/SnmpEndpointDiscovery.test.ts +151 -0
- package/Tests/Types/Monitor/SnmpVendorTemplate.test.ts +110 -6
- package/Tests/Types/NetworkSite/DefaultNetworkSiteType.test.ts +129 -0
- package/Tests/Types/SerializableObjectDictionary.test.ts +166 -0
- package/Tests/Types/Time/RangeStartAndEndDateTime.test.ts +98 -0
- package/Tests/Types/WebsiteRequest.test.ts +230 -0
- package/Tests/UI/Components/EntityFilterRoundTrip.test.tsx +103 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableUrlState.test.tsx +612 -0
- package/Tests/UI/Components/ModelTable/FilterDataToQuery.test.ts +275 -0
- package/Tests/UI/Utils/LogExport.test.ts +159 -0
- package/Tests/UI/Utils/Navigation.test.ts +183 -0
- package/Tests/UI/Utils/TableFilterUrlState.test.ts +539 -0
- package/Tests/UI/Utils/TableViewUrlState.test.ts +272 -0
- package/Tests/Utils/Base64.test.ts +51 -0
- package/Tests/Utils/Boolean.test.ts +76 -0
- package/Tests/Utils/Crypto.test.ts +48 -0
- package/Tests/Utils/Dashboard/DashboardSloComponent.test.ts +259 -0
- package/Tests/Utils/Dashboard/ModelQueryVariableInterpolation.test.ts +162 -0
- package/Tests/Utils/Enum.test.ts +54 -0
- package/Tests/Utils/IpCanonicalUtil.test.ts +85 -0
- package/Tests/Utils/Memory.test.ts +44 -0
- package/Tests/Utils/Metrics/MetricSeriesFingerprint.test.ts +160 -0
- package/Tests/Utils/Monitor/EndpointAttachmentUtil.test.ts +836 -0
- package/Tests/Utils/Monitor/MonitorMetricType.test.ts +218 -0
- package/Tests/Utils/Monitor/NetworkTopologyUtil.test.ts +447 -0
- package/Tests/Utils/NetworkSite/CidrMatchUtil.test.ts +440 -0
- package/Tests/Utils/NetworkSite/MaterializedPathUtil.test.ts +205 -0
- package/Tests/Utils/NetworkSite/SiteStatusRollupUtil.test.ts +221 -0
- package/Tests/Utils/NetworkSite/SiteUptimeUtil.test.ts +283 -0
- package/Tests/Utils/ObjectUtil.test.ts +30 -0
- package/Tests/Utils/Slo/SloBurnRateRuleState.test.ts +124 -0
- package/Tests/Utils/Slo/SloDuration.test.ts +148 -0
- package/Tests/Utils/Slo/SloHealth.test.ts +334 -0
- package/Tests/Utils/Slo/SloStatusColor.test.ts +89 -0
- package/Tests/Utils/Slo/SloUtil.test.ts +1980 -0
- package/Tests/Utils/Slo/SloWidgetFormat.test.ts +605 -0
- package/Tests/Utils/TechStack.test.ts +50 -0
- package/Tests/Utils/Traces/CriticalPath.test.ts +178 -0
- package/Types/AnalyticsDatabase/AnalyticsTableName.ts +10 -0
- package/Types/BaseDatabase/EqualTo.ts +9 -1
- package/Types/BaseDatabase/EqualToOrNull.ts +9 -1
- package/Types/BaseDatabase/NotEqual.ts +9 -1
- package/Types/Dashboard/DashboardComponentType.ts +1 -0
- package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardSloComponent.ts +42 -0
- package/Types/Dashboard/DashboardTemplates.ts +214 -0
- package/Types/Email/EmailTemplateType.ts +2 -0
- package/Types/Kubernetes/KubernetesCostIngest.ts +79 -0
- package/Types/Monitor/CriteriaFilter.ts +9 -0
- package/Types/Monitor/MonitorStep.ts +5 -8
- package/Types/Monitor/MonitorStepNetworkDeviceMonitor.ts +27 -5
- package/Types/Monitor/MonitorType.ts +15 -5
- package/Types/Monitor/SnmpMonitor/ArpEntry.ts +14 -0
- package/Types/Monitor/SnmpMonitor/FdbEntry.ts +18 -0
- package/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.ts +10 -3
- package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +31 -5
- package/Types/Monitor/SnmpMonitor/SnmpMonitorResponse.ts +12 -0
- package/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.ts +231 -3
- package/Types/NetworkSite/DefaultNetworkSiteType.ts +20 -0
- package/Types/NotificationSetting/NotificationSettingEventType.ts +4 -0
- package/Types/Permission.ts +449 -0
- package/Types/ServiceLevelObjective/SliType.ts +6 -0
- package/Types/ServiceLevelObjective/SloMultiMonitorMode.ts +6 -0
- package/Types/ServiceLevelObjective/SloStatus.ts +9 -0
- package/Types/ServiceLevelObjective/SloWindowType.ts +6 -0
- package/Types/Telemetry/ServiceType.ts +1 -0
- package/UI/Components/Filters/EntityFilter.tsx +16 -0
- package/UI/Components/Filters/FilterViewer.tsx +22 -5
- package/UI/Components/List/List.tsx +8 -0
- package/UI/Components/ModelTable/BaseModelTable.tsx +309 -106
- package/UI/Components/ModelTable/FilterDataToQuery.ts +172 -0
- package/UI/Components/Navbar/NavBar.tsx +16 -2
- package/UI/Components/Navbar/NavBarMenuModal.tsx +3 -3
- package/UI/Utils/Navigation.ts +10 -0
- package/UI/Utils/TableFilterUrlState.ts +204 -17
- package/UI/Utils/TableViewUrlState.ts +165 -0
- package/Utils/Dashboard/Components/DashboardSloComponent.ts +114 -0
- package/Utils/Dashboard/Components/Index.ts +7 -0
- package/Utils/IpCanonicalUtil.ts +134 -0
- package/Utils/Monitor/EndpointAttachmentUtil.ts +508 -0
- package/Utils/Monitor/NetworkTopologyUtil.ts +157 -5
- package/Utils/NetworkSite/CidrMatchUtil.ts +296 -0
- package/Utils/NetworkSite/MaterializedPathUtil.ts +115 -0
- package/Utils/NetworkSite/SiteStatusRollupUtil.ts +97 -0
- package/Utils/NetworkSite/SiteUptimeUtil.ts +111 -0
- package/Utils/Slo/SloBurnRateRuleState.ts +91 -0
- package/Utils/Slo/SloDuration.ts +165 -0
- package/Utils/Slo/SloEvaluation.ts +22 -0
- package/Utils/Slo/SloHealth.ts +302 -0
- package/Utils/Slo/SloStatusColor.ts +54 -0
- package/Utils/Slo/SloUtil.ts +637 -0
- package/Utils/Slo/SloWidgetFormat.ts +383 -0
- package/build/dist/Models/AnalyticsModels/Index.js +4 -0
- package/build/dist/Models/AnalyticsModels/Index.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/KubernetesCostAllocation.js +713 -0
- package/build/dist/Models/AnalyticsModels/KubernetesCostAllocation.js.map +1 -0
- package/build/dist/Models/AnalyticsModels/NetworkFlow.js +44 -0
- package/build/dist/Models/AnalyticsModels/NetworkFlow.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/SloHistory.js +218 -0
- package/build/dist/Models/AnalyticsModels/SloHistory.js.map +1 -0
- package/build/dist/Models/DatabaseModels/Index.js +20 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +458 -6
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +0 -6
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkEndpoint.js +779 -0
- package/build/dist/Models/DatabaseModels/NetworkEndpoint.js.map +1 -0
- package/build/dist/Models/DatabaseModels/NetworkSite.js +1180 -0
- package/build/dist/Models/DatabaseModels/NetworkSite.js.map +1 -0
- package/build/dist/Models/DatabaseModels/NetworkSiteAssignmentRule.js +534 -0
- package/build/dist/Models/DatabaseModels/NetworkSiteAssignmentRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/NetworkSiteLink.js +629 -0
- package/build/dist/Models/DatabaseModels/NetworkSiteLink.js.map +1 -0
- package/build/dist/Models/DatabaseModels/NetworkSiteStatusTimeline.js +538 -0
- package/build/dist/Models/DatabaseModels/NetworkSiteStatusTimeline.js.map +1 -0
- package/build/dist/Models/DatabaseModels/NetworkSiteType.js +522 -0
- package/build/dist/Models/DatabaseModels/NetworkSiteType.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjective.js +1134 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjective.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveBurnRateRule.js +769 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveBurnRateRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerTeam.js +460 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerTeam.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerUser.js +459 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerUser.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784757142154-AddNetworkSiteHierarchyAndEndpoints.js +130 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784757142154-AddNetworkSiteHierarchyAndEndpoints.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784897317860-AddNetworkSiteAlerting.js +31 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784897317860-AddNetworkSiteAlerting.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784970388777-AddNetworkDevicePollingColumns.js +36 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784970388777-AddNetworkDevicePollingColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784986826214-AddNetworkSiteTypeTable.js +49 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784986826214-AddNetworkSiteTypeTable.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784987015619-AddServiceLevelObjective.js +140 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784987015619-AddServiceLevelObjective.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785066759532-MigrationName.js +21 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785066759532-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +23 -6
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +24 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/KubernetesCostAllocationService.js +12 -0
- package/build/dist/Server/Services/KubernetesCostAllocationService.js.map +1 -0
- package/build/dist/Server/Services/MetricService.js +21 -3
- package/build/dist/Server/Services/MetricService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +19 -0
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +351 -1
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/NetworkEndpointService.js +319 -0
- package/build/dist/Server/Services/NetworkEndpointService.js.map +1 -0
- package/build/dist/Server/Services/NetworkSiteAssignmentRuleService.js +90 -0
- package/build/dist/Server/Services/NetworkSiteAssignmentRuleService.js.map +1 -0
- package/build/dist/Server/Services/NetworkSiteLinkService.js +9 -0
- package/build/dist/Server/Services/NetworkSiteLinkService.js.map +1 -0
- package/build/dist/Server/Services/NetworkSiteService.js +1038 -0
- package/build/dist/Server/Services/NetworkSiteService.js.map +1 -0
- package/build/dist/Server/Services/NetworkSiteStatusTimelineService.js +9 -0
- package/build/dist/Server/Services/NetworkSiteStatusTimelineService.js.map +1 -0
- package/build/dist/Server/Services/NetworkSiteTypeService.js +9 -0
- package/build/dist/Server/Services/NetworkSiteTypeService.js.map +1 -0
- package/build/dist/Server/Services/ProjectService.js +98 -2
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveBurnRateRuleService.js +358 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveBurnRateRuleService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerTeamService.js +9 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerTeamService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerUserService.js +9 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerUserService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveService.js +588 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveService.js.map +1 -0
- package/build/dist/Server/Services/SloHistoryService.js +77 -0
- package/build/dist/Server/Services/SloHistoryService.js.map +1 -0
- package/build/dist/Server/Services/UserNotificationSettingService.js +20 -0
- package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
- package/build/dist/Server/Types/AnalyticsDatabase/AggregateBy.js +9 -0
- package/build/dist/Server/Types/AnalyticsDatabase/AggregateBy.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +15 -0
- package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js +31 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +76 -48
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
- package/build/dist/Server/Utils/Memory.js +9 -1
- package/build/dist/Server/Utils/Memory.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +132 -10
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Data/OuiVendors.json +6920 -0
- package/build/dist/Server/Utils/Monitor/DnsResolutionCache.js +77 -0
- package/build/dist/Server/Utils/Monitor/DnsResolutionCache.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +21 -41
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js +152 -40
- package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js +262 -0
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js +201 -0
- package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +152 -120
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/OuiLookupUtil.js +44 -0
- package/build/dist/Server/Utils/Monitor/OuiLookupUtil.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/SnmpInterfaceRateUtil.js +10 -10
- package/build/dist/Server/Utils/Monitor/SnmpInterfaceRateUtil.js.map +1 -1
- package/build/dist/Server/Utils/WhatsAppTemplateUtil.js +5 -0
- package/build/dist/Server/Utils/WhatsAppTemplateUtil.js.map +1 -1
- package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js +10 -0
- package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js.map +1 -1
- package/build/dist/Types/BaseDatabase/EqualTo.js +9 -1
- package/build/dist/Types/BaseDatabase/EqualTo.js.map +1 -1
- package/build/dist/Types/BaseDatabase/EqualToOrNull.js +9 -1
- package/build/dist/Types/BaseDatabase/EqualToOrNull.js.map +1 -1
- package/build/dist/Types/BaseDatabase/NotEqual.js +9 -1
- package/build/dist/Types/BaseDatabase/NotEqual.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/ComponentArgument.js +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardSloComponent.js +23 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardSloComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js +205 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
- package/build/dist/Types/Email/EmailTemplateType.js +1 -0
- package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
- package/build/dist/Types/Kubernetes/KubernetesCostIngest.js +21 -0
- package/build/dist/Types/Kubernetes/KubernetesCostIngest.js.map +1 -0
- package/build/dist/Types/Monitor/CriteriaFilter.js +1 -0
- package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +5 -5
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepNetworkDeviceMonitor.js +8 -0
- package/build/dist/Types/Monitor/MonitorStepNetworkDeviceMonitor.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorType.js +15 -5
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/Types/Monitor/SnmpMonitor/ArpEntry.js +2 -0
- package/build/dist/Types/Monitor/SnmpMonitor/ArpEntry.js.map +1 -0
- package/build/dist/Types/Monitor/SnmpMonitor/FdbEntry.js +2 -0
- package/build/dist/Types/Monitor/SnmpMonitor/FdbEntry.js.map +1 -0
- package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js +9 -3
- package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js.map +1 -1
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.js +217 -3
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.js.map +1 -1
- package/build/dist/Types/NetworkSite/DefaultNetworkSiteType.js +21 -0
- package/build/dist/Types/NetworkSite/DefaultNetworkSiteType.js.map +1 -0
- package/build/dist/Types/NotificationSetting/NotificationSettingEventType.js +3 -0
- package/build/dist/Types/NotificationSetting/NotificationSettingEventType.js.map +1 -1
- package/build/dist/Types/Permission.js +409 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/ServiceLevelObjective/SliType.js +7 -0
- package/build/dist/Types/ServiceLevelObjective/SliType.js.map +1 -0
- package/build/dist/Types/ServiceLevelObjective/SloMultiMonitorMode.js +7 -0
- package/build/dist/Types/ServiceLevelObjective/SloMultiMonitorMode.js.map +1 -0
- package/build/dist/Types/ServiceLevelObjective/SloStatus.js +10 -0
- package/build/dist/Types/ServiceLevelObjective/SloStatus.js.map +1 -0
- package/build/dist/Types/ServiceLevelObjective/SloWindowType.js +7 -0
- package/build/dist/Types/ServiceLevelObjective/SloWindowType.js.map +1 -0
- package/build/dist/Types/Telemetry/ServiceType.js +1 -0
- package/build/dist/Types/Telemetry/ServiceType.js.map +1 -1
- package/build/dist/UI/Components/Filters/EntityFilter.js +15 -0
- package/build/dist/UI/Components/Filters/EntityFilter.js.map +1 -1
- package/build/dist/UI/Components/Filters/FilterViewer.js +19 -4
- package/build/dist/UI/Components/Filters/FilterViewer.js.map +1 -1
- package/build/dist/UI/Components/List/List.js +1 -1
- package/build/dist/UI/Components/List/List.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +235 -89
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/FilterDataToQuery.js +96 -0
- package/build/dist/UI/Components/ModelTable/FilterDataToQuery.js.map +1 -0
- package/build/dist/UI/Components/Navbar/NavBar.js +14 -2
- package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +3 -2
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
- package/build/dist/UI/Utils/Navigation.js +9 -0
- package/build/dist/UI/Utils/Navigation.js.map +1 -1
- package/build/dist/UI/Utils/TableFilterUrlState.js +159 -15
- package/build/dist/UI/Utils/TableFilterUrlState.js.map +1 -1
- package/build/dist/UI/Utils/TableViewUrlState.js +103 -0
- package/build/dist/UI/Utils/TableViewUrlState.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardSloComponent.js +93 -0
- package/build/dist/Utils/Dashboard/Components/DashboardSloComponent.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/IpCanonicalUtil.js +110 -0
- package/build/dist/Utils/IpCanonicalUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/EndpointAttachmentUtil.js +311 -0
- package/build/dist/Utils/Monitor/EndpointAttachmentUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +98 -5
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
- package/build/dist/Utils/NetworkSite/CidrMatchUtil.js +222 -0
- package/build/dist/Utils/NetworkSite/CidrMatchUtil.js.map +1 -0
- package/build/dist/Utils/NetworkSite/MaterializedPathUtil.js +89 -0
- package/build/dist/Utils/NetworkSite/MaterializedPathUtil.js.map +1 -0
- package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js +60 -0
- package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js.map +1 -0
- package/build/dist/Utils/NetworkSite/SiteUptimeUtil.js +76 -0
- package/build/dist/Utils/NetworkSite/SiteUptimeUtil.js.map +1 -0
- package/build/dist/Utils/Slo/SloBurnRateRuleState.js +35 -0
- package/build/dist/Utils/Slo/SloBurnRateRuleState.js.map +1 -0
- package/build/dist/Utils/Slo/SloDuration.js +87 -0
- package/build/dist/Utils/Slo/SloDuration.js.map +1 -0
- package/build/dist/Utils/Slo/SloEvaluation.js +21 -0
- package/build/dist/Utils/Slo/SloEvaluation.js.map +1 -0
- package/build/dist/Utils/Slo/SloHealth.js +179 -0
- package/build/dist/Utils/Slo/SloHealth.js.map +1 -0
- package/build/dist/Utils/Slo/SloStatusColor.js +18 -0
- package/build/dist/Utils/Slo/SloStatusColor.js.map +1 -0
- package/build/dist/Utils/Slo/SloUtil.js +393 -0
- package/build/dist/Utils/Slo/SloUtil.js.map +1 -0
- package/build/dist/Utils/Slo/SloWidgetFormat.js +174 -0
- package/build/dist/Utils/Slo/SloWidgetFormat.js.map +1 -0
- package/package.json +2 -2
- package/Types/Dashboard/DashboardComponents/Index.ts +0 -7
- package/build/dist/Types/Dashboard/DashboardComponents/Index.js +0 -8
- package/build/dist/Types/Dashboard/DashboardComponents/Index.js.map +0 -1
|
@@ -0,0 +1,1038 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import AlertService from "./AlertService";
|
|
11
|
+
import AlertSeverityService from "./AlertSeverityService";
|
|
12
|
+
import AlertStateTimelineService from "./AlertStateTimelineService";
|
|
13
|
+
import DatabaseService from "./DatabaseService";
|
|
14
|
+
import MonitorService from "./MonitorService";
|
|
15
|
+
import MonitorStatusService from "./MonitorStatusService";
|
|
16
|
+
import NetworkDeviceService from "./NetworkDeviceService";
|
|
17
|
+
import NetworkSiteStatusTimelineService from "./NetworkSiteStatusTimelineService";
|
|
18
|
+
import Model from "../../Models/DatabaseModels/NetworkSite";
|
|
19
|
+
import Alert from "../../Models/DatabaseModels/Alert";
|
|
20
|
+
import AlertStateTimeline from "../../Models/DatabaseModels/AlertStateTimeline";
|
|
21
|
+
import NetworkSiteStatusTimeline from "../../Models/DatabaseModels/NetworkSiteStatusTimeline";
|
|
22
|
+
import { DisableAutomaticAlertCreation } from "../EnvironmentConfig";
|
|
23
|
+
import SortOrder from "../../Types/BaseDatabase/SortOrder";
|
|
24
|
+
import QueryHelper from "../Types/Database/QueryHelper";
|
|
25
|
+
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
26
|
+
import NetworkDeviceHydrationUtil from "../Utils/Monitor/NetworkDeviceHydrationUtil";
|
|
27
|
+
import logger from "../Utils/Logger";
|
|
28
|
+
import LIMIT_MAX, { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
|
|
29
|
+
import BadDataException from "../../Types/Exception/BadDataException";
|
|
30
|
+
import MonitorType from "../../Types/Monitor/MonitorType";
|
|
31
|
+
import ObjectID from "../../Types/ObjectID";
|
|
32
|
+
import OneUptimeDate from "../../Types/Date";
|
|
33
|
+
import Text from "../../Types/Text";
|
|
34
|
+
import { Raw } from "typeorm";
|
|
35
|
+
import MaterializedPathUtil from "../../Utils/NetworkSite/MaterializedPathUtil";
|
|
36
|
+
import SiteStatusRollupUtil from "../../Utils/NetworkSite/SiteStatusRollupUtil";
|
|
37
|
+
export class Service extends DatabaseService {
|
|
38
|
+
constructor() {
|
|
39
|
+
super(Model);
|
|
40
|
+
}
|
|
41
|
+
/*
|
|
42
|
+
* ------------------------------------------------------------------
|
|
43
|
+
* Hierarchy maintenance (materializedPath + depth)
|
|
44
|
+
* ------------------------------------------------------------------
|
|
45
|
+
*/
|
|
46
|
+
/*
|
|
47
|
+
* The hierarchy hooks run BEFORE DatabaseService applies tenant scoping to
|
|
48
|
+
* the caller's query (ModelPermission.check*QueryPermissions runs after
|
|
49
|
+
* onBeforeUpdate / onBeforeDelete), so reading the raw client query with
|
|
50
|
+
* props.isRoot would hand the hook rows from other projects - which the
|
|
51
|
+
* success hooks then write. Re-apply the caller's tenant here so a hook can
|
|
52
|
+
* never see, let alone rewrite, a row outside the caller's project.
|
|
53
|
+
*/
|
|
54
|
+
scopeQueryToCallerTenant(query, props) {
|
|
55
|
+
if (props.isRoot || !props.tenantId) {
|
|
56
|
+
return query;
|
|
57
|
+
}
|
|
58
|
+
return Object.assign(Object.assign({}, query), { projectId: props.tenantId });
|
|
59
|
+
}
|
|
60
|
+
/*
|
|
61
|
+
* Case-sensitive, un-CAST prefix predicate on materializedPath.
|
|
62
|
+
* QueryHelper.startsWith emits `CAST(alias AS TEXT) ILIKE :x`, and both the
|
|
63
|
+
* cast and the case-insensitive match make the btree index on the column
|
|
64
|
+
* unusable, so every rollup would sequentially scan the table. Paths are
|
|
65
|
+
* built from UUIDs only, so there are no LIKE wildcards to escape.
|
|
66
|
+
*/
|
|
67
|
+
pathStartsWith(path) {
|
|
68
|
+
const rid = Text.generateRandomText(10);
|
|
69
|
+
return Raw((alias) => {
|
|
70
|
+
return `(${alias} LIKE :${rid})`;
|
|
71
|
+
}, {
|
|
72
|
+
[rid]: `${path}%`,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/*
|
|
76
|
+
* A stored path is trustworthy only when it agrees with parentSiteId: it
|
|
77
|
+
* must end with the site's own id, and the segment before it must be the
|
|
78
|
+
* parent (nothing before it for a root). A delete that nulls parentSiteId,
|
|
79
|
+
* or a half-applied move, leaves the two disagreeing - and a stale path
|
|
80
|
+
* silently corrupts every prefix query built from it, so treat it as
|
|
81
|
+
* missing and let the caller rebuild.
|
|
82
|
+
*/
|
|
83
|
+
isPathConsistent(site) {
|
|
84
|
+
if (!site.id) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
const segments = MaterializedPathUtil.segmentsOf(site.materializedPath);
|
|
88
|
+
if (segments.length === 0) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
if (segments[segments.length - 1] !== site.id.toString()) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
const parentSegment = segments.length > 1 ? segments[segments.length - 2] : null;
|
|
95
|
+
const parentId = site.parentSiteId
|
|
96
|
+
? site.parentSiteId.toString()
|
|
97
|
+
: null;
|
|
98
|
+
return parentSegment === parentId;
|
|
99
|
+
}
|
|
100
|
+
async onBeforeCreate(createBy) {
|
|
101
|
+
let parentPath = null;
|
|
102
|
+
if (createBy.data.parentSiteId) {
|
|
103
|
+
const parent = await this.findOneById({
|
|
104
|
+
id: createBy.data.parentSiteId,
|
|
105
|
+
select: {
|
|
106
|
+
_id: true,
|
|
107
|
+
projectId: true,
|
|
108
|
+
},
|
|
109
|
+
props: {
|
|
110
|
+
isRoot: true,
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
if (!parent) {
|
|
114
|
+
throw new BadDataException("Parent site not found.");
|
|
115
|
+
}
|
|
116
|
+
if (createBy.data.projectId &&
|
|
117
|
+
parent.projectId &&
|
|
118
|
+
parent.projectId.toString() !== createBy.data.projectId.toString()) {
|
|
119
|
+
throw new BadDataException("Parent site must belong to the same project.");
|
|
120
|
+
}
|
|
121
|
+
parentPath = await this.getMaterializedPathForSite(createBy.data.parentSiteId);
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
createBy: createBy,
|
|
125
|
+
carryForward: {
|
|
126
|
+
parentPath: parentPath,
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
async onCreateSuccess(onCreate, createdItem) {
|
|
131
|
+
var _a;
|
|
132
|
+
if (!createdItem.id) {
|
|
133
|
+
return createdItem;
|
|
134
|
+
}
|
|
135
|
+
const parentPath = ((_a = onCreate.carryForward) === null || _a === void 0 ? void 0 : _a.parentPath) || null;
|
|
136
|
+
const path = MaterializedPathUtil.buildPath(parentPath, createdItem.id.toString());
|
|
137
|
+
await this.updateColumnsByIdWithoutHooks({
|
|
138
|
+
id: createdItem.id,
|
|
139
|
+
data: {
|
|
140
|
+
materializedPath: path,
|
|
141
|
+
depth: MaterializedPathUtil.depthOf(path),
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
createdItem.materializedPath = path;
|
|
145
|
+
createdItem.depth = MaterializedPathUtil.depthOf(path);
|
|
146
|
+
return createdItem;
|
|
147
|
+
}
|
|
148
|
+
async onBeforeUpdate(updateBy) {
|
|
149
|
+
const dataKeys = Object.keys(updateBy.data || {});
|
|
150
|
+
if (!dataKeys.includes("parentSiteId")) {
|
|
151
|
+
return { updateBy, carryForward: null };
|
|
152
|
+
}
|
|
153
|
+
const newParentIdValue = updateBy.data["parentSiteId"];
|
|
154
|
+
const newParentId = newParentIdValue
|
|
155
|
+
? new ObjectID(newParentIdValue.toString())
|
|
156
|
+
: null;
|
|
157
|
+
const previousItems = await this.findBy({
|
|
158
|
+
query: this.scopeQueryToCallerTenant(updateBy.query, updateBy.props),
|
|
159
|
+
select: {
|
|
160
|
+
_id: true,
|
|
161
|
+
projectId: true,
|
|
162
|
+
parentSiteId: true,
|
|
163
|
+
materializedPath: true,
|
|
164
|
+
},
|
|
165
|
+
limit: LIMIT_MAX,
|
|
166
|
+
skip: 0,
|
|
167
|
+
props: {
|
|
168
|
+
isRoot: true,
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
/*
|
|
172
|
+
* Same-project assertion for EVERY parentSiteId write, including the
|
|
173
|
+
* detach case (parentSiteId: null) which has no parent to compare
|
|
174
|
+
* against: onUpdateSuccess rewrites each matched site's whole subtree, so
|
|
175
|
+
* a site outside the caller's project must never reach it.
|
|
176
|
+
*/
|
|
177
|
+
if (updateBy.props.tenantId) {
|
|
178
|
+
for (const item of previousItems) {
|
|
179
|
+
if (item.projectId &&
|
|
180
|
+
item.projectId.toString() !== updateBy.props.tenantId.toString()) {
|
|
181
|
+
throw new BadDataException("Network site must belong to the same project.");
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
let newParentPath = null;
|
|
186
|
+
if (newParentId) {
|
|
187
|
+
const parent = await this.findOneById({
|
|
188
|
+
id: newParentId,
|
|
189
|
+
select: {
|
|
190
|
+
_id: true,
|
|
191
|
+
projectId: true,
|
|
192
|
+
},
|
|
193
|
+
props: {
|
|
194
|
+
isRoot: true,
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
if (!parent) {
|
|
198
|
+
throw new BadDataException("Parent site not found.");
|
|
199
|
+
}
|
|
200
|
+
for (const item of previousItems) {
|
|
201
|
+
if (item.id && item.id.toString() === newParentId.toString()) {
|
|
202
|
+
throw new BadDataException("A site cannot be its own parent.");
|
|
203
|
+
}
|
|
204
|
+
if (item.projectId &&
|
|
205
|
+
parent.projectId &&
|
|
206
|
+
item.projectId.toString() !== parent.projectId.toString()) {
|
|
207
|
+
throw new BadDataException("Parent site must belong to the same project.");
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
newParentPath = await this.getMaterializedPathForSite(newParentId);
|
|
211
|
+
for (const item of previousItems) {
|
|
212
|
+
if (item.id &&
|
|
213
|
+
MaterializedPathUtil.wouldCreateCycle(item.id.toString(), newParentPath)) {
|
|
214
|
+
throw new BadDataException("Cannot move a site under itself or one of its own descendants.");
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
const carryForward = {
|
|
219
|
+
previousItems: previousItems,
|
|
220
|
+
newParentId: newParentId,
|
|
221
|
+
newParentPath: newParentPath,
|
|
222
|
+
};
|
|
223
|
+
return { updateBy, carryForward };
|
|
224
|
+
}
|
|
225
|
+
async onUpdateSuccess(onUpdate, updatedItemIds) {
|
|
226
|
+
var _a;
|
|
227
|
+
const parentChange = onUpdate.carryForward || null;
|
|
228
|
+
if (!parentChange) {
|
|
229
|
+
return onUpdate;
|
|
230
|
+
}
|
|
231
|
+
/*
|
|
232
|
+
* DatabaseService calls onUpdateSuccess even when the tenant-scoped
|
|
233
|
+
* UPDATE matched zero rows, so the carried previousItems are not proof
|
|
234
|
+
* that anything was written. Only rows the UPDATE actually matched may be
|
|
235
|
+
* rebased here.
|
|
236
|
+
*/
|
|
237
|
+
const updatedIds = new Set(updatedItemIds.map((id) => {
|
|
238
|
+
return id.toString();
|
|
239
|
+
}));
|
|
240
|
+
for (const previousItem of parentChange.previousItems) {
|
|
241
|
+
if (!previousItem.id || !updatedIds.has(previousItem.id.toString())) {
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
const oldPath = previousItem.materializedPath || null;
|
|
245
|
+
const newPath = MaterializedPathUtil.buildPath(parentChange.newParentPath, previousItem.id.toString());
|
|
246
|
+
if (oldPath === newPath) {
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
// Rebase the moved site itself...
|
|
250
|
+
await this.updateColumnsByIdWithoutHooks({
|
|
251
|
+
id: previousItem.id,
|
|
252
|
+
data: {
|
|
253
|
+
materializedPath: newPath,
|
|
254
|
+
depth: MaterializedPathUtil.depthOf(newPath),
|
|
255
|
+
},
|
|
256
|
+
});
|
|
257
|
+
// ...then its entire subtree in one prefix query.
|
|
258
|
+
if (oldPath) {
|
|
259
|
+
const descendants = await this.findBy({
|
|
260
|
+
query: {
|
|
261
|
+
projectId: previousItem.projectId,
|
|
262
|
+
materializedPath: this.pathStartsWith(oldPath),
|
|
263
|
+
},
|
|
264
|
+
select: {
|
|
265
|
+
_id: true,
|
|
266
|
+
materializedPath: true,
|
|
267
|
+
},
|
|
268
|
+
limit: LIMIT_MAX,
|
|
269
|
+
skip: 0,
|
|
270
|
+
props: {
|
|
271
|
+
isRoot: true,
|
|
272
|
+
},
|
|
273
|
+
});
|
|
274
|
+
for (const descendant of descendants) {
|
|
275
|
+
if (!descendant.id ||
|
|
276
|
+
!descendant.materializedPath ||
|
|
277
|
+
descendant.id.toString() === previousItem.id.toString()) {
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
const rebasedPath = MaterializedPathUtil.rebasePaths(oldPath, newPath, [descendant.materializedPath])[0];
|
|
281
|
+
await this.updateColumnsByIdWithoutHooks({
|
|
282
|
+
id: descendant.id,
|
|
283
|
+
data: {
|
|
284
|
+
materializedPath: rebasedPath,
|
|
285
|
+
depth: MaterializedPathUtil.depthOf(rebasedPath),
|
|
286
|
+
},
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/*
|
|
291
|
+
* Moving a subtree changes the rollup of both the new ancestor chain
|
|
292
|
+
* (via the moved site) and the old one (via the old parent). Rollup
|
|
293
|
+
* failures must never fail the move itself - the cron backstop
|
|
294
|
+
* reconciles.
|
|
295
|
+
*/
|
|
296
|
+
try {
|
|
297
|
+
await this.recomputeRollupForSiteAndAncestors(previousItem.id);
|
|
298
|
+
if (previousItem.parentSiteId) {
|
|
299
|
+
await this.recomputeRollupForSiteAndAncestors(previousItem.parentSiteId);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
catch (error) {
|
|
303
|
+
logger.error(`NetworkSiteService.onUpdateSuccess: rollup after site move failed for site ${previousItem.id.toString()}: ${error}`, {
|
|
304
|
+
projectId: (_a = previousItem.projectId) === null || _a === void 0 ? void 0 : _a.toString(),
|
|
305
|
+
siteId: previousItem.id.toString(),
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return onUpdate;
|
|
310
|
+
}
|
|
311
|
+
/*
|
|
312
|
+
* Deletes are hard deletes, so the rows' hierarchy state has to be captured
|
|
313
|
+
* before they disappear. Scoped to the caller's tenant for the same reason
|
|
314
|
+
* onBeforeUpdate is: this hook runs before the delete query is permission
|
|
315
|
+
* checked.
|
|
316
|
+
*/
|
|
317
|
+
async onBeforeDelete(deleteBy) {
|
|
318
|
+
const sitesToDelete = await this.findBy({
|
|
319
|
+
query: this.scopeQueryToCallerTenant(deleteBy.query, deleteBy.props),
|
|
320
|
+
select: {
|
|
321
|
+
_id: true,
|
|
322
|
+
projectId: true,
|
|
323
|
+
parentSiteId: true,
|
|
324
|
+
materializedPath: true,
|
|
325
|
+
},
|
|
326
|
+
limit: LIMIT_MAX,
|
|
327
|
+
skip: 0,
|
|
328
|
+
props: {
|
|
329
|
+
isRoot: true,
|
|
330
|
+
},
|
|
331
|
+
});
|
|
332
|
+
const carryForward = {
|
|
333
|
+
sitesToDelete: sitesToDelete,
|
|
334
|
+
};
|
|
335
|
+
return { deleteBy, carryForward };
|
|
336
|
+
}
|
|
337
|
+
/*
|
|
338
|
+
* parentSiteId is declared onDelete: "SET NULL", so Postgres detaches the
|
|
339
|
+
* deleted site's direct children but leaves their materializedPath - and
|
|
340
|
+
* their whole subtree's - routed through a row that no longer exists. That
|
|
341
|
+
* strands the subtree: the children endpoint (which reads parentSiteId)
|
|
342
|
+
* shows them at the root while the rollup engine (which reads
|
|
343
|
+
* materializedPath) still folds them into the dead ancestor's chain, double
|
|
344
|
+
* counting every outage. Re-attach the orphans to the deleted site's own
|
|
345
|
+
* parent - NULL when it was a root, which is exactly what the FK did - and
|
|
346
|
+
* rebase the subtree paths so both readers agree again.
|
|
347
|
+
*/
|
|
348
|
+
async onDeleteSuccess(onDelete, itemIdsBeforeDelete) {
|
|
349
|
+
const carryForward = onDelete.carryForward || null;
|
|
350
|
+
if (!carryForward) {
|
|
351
|
+
return onDelete;
|
|
352
|
+
}
|
|
353
|
+
// Only rows the permission-checked delete actually removed.
|
|
354
|
+
const deletedIds = new Set(itemIdsBeforeDelete.map((id) => {
|
|
355
|
+
return id.toString();
|
|
356
|
+
}));
|
|
357
|
+
for (const deletedSite of carryForward.sitesToDelete) {
|
|
358
|
+
if (!deletedSite.id ||
|
|
359
|
+
!deletedSite.projectId ||
|
|
360
|
+
!deletedIds.has(deletedSite.id.toString())) {
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
/*
|
|
364
|
+
* Repair failures must never fail the delete itself - the row is
|
|
365
|
+
* already gone, and getMaterializedPathForSite self-heals a stranded
|
|
366
|
+
* path on next use.
|
|
367
|
+
*/
|
|
368
|
+
try {
|
|
369
|
+
await this.reattachOrphanedSubtree(deletedSite);
|
|
370
|
+
}
|
|
371
|
+
catch (error) {
|
|
372
|
+
logger.error(`NetworkSiteService.onDeleteSuccess: subtree repair after deleting site ${deletedSite.id.toString()} failed: ${error}`, {
|
|
373
|
+
projectId: deletedSite.projectId.toString(),
|
|
374
|
+
siteId: deletedSite.id.toString(),
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return onDelete;
|
|
379
|
+
}
|
|
380
|
+
/*
|
|
381
|
+
* Rewrites the deleted site's former subtree so the '/deletedId/' segment
|
|
382
|
+
* is dropped from every path, and re-points its direct children at the
|
|
383
|
+
* deleted site's parent.
|
|
384
|
+
*/
|
|
385
|
+
async reattachOrphanedSubtree(deletedSite) {
|
|
386
|
+
const oldPath = deletedSite.materializedPath || null;
|
|
387
|
+
if (!oldPath || !deletedSite.id) {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
const parentPath = deletedSite.parentSiteId
|
|
391
|
+
? await this.getMaterializedPathForSite(deletedSite.parentSiteId)
|
|
392
|
+
: null;
|
|
393
|
+
const deletedDepth = MaterializedPathUtil.segmentsOf(oldPath).length;
|
|
394
|
+
const descendants = await this.findBy({
|
|
395
|
+
query: {
|
|
396
|
+
projectId: deletedSite.projectId,
|
|
397
|
+
materializedPath: this.pathStartsWith(oldPath),
|
|
398
|
+
},
|
|
399
|
+
select: {
|
|
400
|
+
_id: true,
|
|
401
|
+
materializedPath: true,
|
|
402
|
+
},
|
|
403
|
+
limit: LIMIT_MAX,
|
|
404
|
+
skip: 0,
|
|
405
|
+
props: {
|
|
406
|
+
isRoot: true,
|
|
407
|
+
},
|
|
408
|
+
});
|
|
409
|
+
for (const descendant of descendants) {
|
|
410
|
+
if (!descendant.id ||
|
|
411
|
+
!descendant.materializedPath ||
|
|
412
|
+
descendant.id.toString() === deletedSite.id.toString()) {
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
const tailSegments = MaterializedPathUtil.segmentsOf(descendant.materializedPath).slice(deletedDepth);
|
|
416
|
+
if (tailSegments.length === 0) {
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
let rebasedPath = parentPath;
|
|
420
|
+
for (const segment of tailSegments) {
|
|
421
|
+
rebasedPath = MaterializedPathUtil.buildPath(rebasedPath, segment);
|
|
422
|
+
}
|
|
423
|
+
const data = {
|
|
424
|
+
materializedPath: rebasedPath,
|
|
425
|
+
depth: MaterializedPathUtil.depthOf(rebasedPath),
|
|
426
|
+
};
|
|
427
|
+
// A direct child is the one the FK just detached - give it a parent back.
|
|
428
|
+
if (tailSegments.length === 1) {
|
|
429
|
+
data["parentSiteId"] = deletedSite.parentSiteId || null;
|
|
430
|
+
}
|
|
431
|
+
await this.updateColumnsByIdWithoutHooks({
|
|
432
|
+
id: descendant.id,
|
|
433
|
+
data: data,
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
/*
|
|
437
|
+
* The deleted site's own devices were detached by their FK too, so the
|
|
438
|
+
* surviving ancestor chain's rollup is now stale.
|
|
439
|
+
*/
|
|
440
|
+
if (deletedSite.parentSiteId) {
|
|
441
|
+
await this.recomputeRollupForSiteAndAncestors(deletedSite.parentSiteId);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
/*
|
|
445
|
+
* Returns the site's materialized path, rebuilding (and persisting) it by
|
|
446
|
+
* walking up the parent chain when the stored value is missing OR no longer
|
|
447
|
+
* agrees with parentSiteId - a row created before path maintenance existed,
|
|
448
|
+
* one whose maintenance write failed, or one stranded by a deleted
|
|
449
|
+
* ancestor, self-heals on first use.
|
|
450
|
+
*/
|
|
451
|
+
async getMaterializedPathForSite(siteId) {
|
|
452
|
+
var _a;
|
|
453
|
+
const site = await this.findOneById({
|
|
454
|
+
id: siteId,
|
|
455
|
+
select: {
|
|
456
|
+
_id: true,
|
|
457
|
+
parentSiteId: true,
|
|
458
|
+
materializedPath: true,
|
|
459
|
+
},
|
|
460
|
+
props: {
|
|
461
|
+
isRoot: true,
|
|
462
|
+
},
|
|
463
|
+
});
|
|
464
|
+
if (!site || !site.id) {
|
|
465
|
+
return null;
|
|
466
|
+
}
|
|
467
|
+
if (site.materializedPath && this.isPathConsistent(site)) {
|
|
468
|
+
return site.materializedPath;
|
|
469
|
+
}
|
|
470
|
+
/*
|
|
471
|
+
* Walk up until a parent with a stored path (or a root) is found. The
|
|
472
|
+
* visited set guards against pre-existing cycles in the data - without
|
|
473
|
+
* it a corrupted parent chain would loop forever.
|
|
474
|
+
*/
|
|
475
|
+
const chain = [site];
|
|
476
|
+
const visited = new Set([site.id.toString()]);
|
|
477
|
+
let prefixPath = null;
|
|
478
|
+
let cursor = site;
|
|
479
|
+
while (cursor.parentSiteId) {
|
|
480
|
+
if (visited.has(cursor.parentSiteId.toString())) {
|
|
481
|
+
logger.error(`NetworkSiteService.getMaterializedPathForSite: cycle detected in parent chain of site ${siteId.toString()}; treating ${(_a = cursor.id) === null || _a === void 0 ? void 0 : _a.toString()} as a root.`);
|
|
482
|
+
break;
|
|
483
|
+
}
|
|
484
|
+
const parent = await this.findOneById({
|
|
485
|
+
id: cursor.parentSiteId,
|
|
486
|
+
select: {
|
|
487
|
+
_id: true,
|
|
488
|
+
parentSiteId: true,
|
|
489
|
+
materializedPath: true,
|
|
490
|
+
},
|
|
491
|
+
props: {
|
|
492
|
+
isRoot: true,
|
|
493
|
+
},
|
|
494
|
+
});
|
|
495
|
+
if (!parent || !parent.id) {
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
// A stale ancestor path would poison every path rebuilt from it.
|
|
499
|
+
if (parent.materializedPath && this.isPathConsistent(parent)) {
|
|
500
|
+
prefixPath = parent.materializedPath;
|
|
501
|
+
break;
|
|
502
|
+
}
|
|
503
|
+
visited.add(parent.id.toString());
|
|
504
|
+
chain.push(parent);
|
|
505
|
+
cursor = parent;
|
|
506
|
+
}
|
|
507
|
+
// Fold back down, persisting the healed paths as we go.
|
|
508
|
+
let path = prefixPath;
|
|
509
|
+
for (let i = chain.length - 1; i >= 0; i--) {
|
|
510
|
+
const chainSite = chain[i];
|
|
511
|
+
path = MaterializedPathUtil.buildPath(path, chainSite.id.toString());
|
|
512
|
+
await this.updateColumnsByIdWithoutHooks({
|
|
513
|
+
id: chainSite.id,
|
|
514
|
+
data: {
|
|
515
|
+
materializedPath: path,
|
|
516
|
+
depth: MaterializedPathUtil.depthOf(path),
|
|
517
|
+
},
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
return path;
|
|
521
|
+
}
|
|
522
|
+
// Ancestor IDs from root to direct parent (excludes the site itself).
|
|
523
|
+
async getAncestorIds(siteId) {
|
|
524
|
+
const path = await this.getMaterializedPathForSite(siteId);
|
|
525
|
+
if (!path) {
|
|
526
|
+
return [];
|
|
527
|
+
}
|
|
528
|
+
return MaterializedPathUtil.segmentsOf(path)
|
|
529
|
+
.filter((segment) => {
|
|
530
|
+
return segment !== siteId.toString();
|
|
531
|
+
})
|
|
532
|
+
.map((segment) => {
|
|
533
|
+
return new ObjectID(segment);
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
/*
|
|
537
|
+
* Strict descendant IDs (excludes the site itself), via path prefix query.
|
|
538
|
+
* projectId is required by every production caller: without it the prefix
|
|
539
|
+
* scan has no indexable predicate and reads every tenant's rows.
|
|
540
|
+
*/
|
|
541
|
+
async getDescendantSiteIds(siteId, projectId) {
|
|
542
|
+
const path = await this.getMaterializedPathForSite(siteId);
|
|
543
|
+
if (!path) {
|
|
544
|
+
return [];
|
|
545
|
+
}
|
|
546
|
+
const query = {
|
|
547
|
+
materializedPath: this.pathStartsWith(path),
|
|
548
|
+
};
|
|
549
|
+
if (projectId) {
|
|
550
|
+
query.projectId = projectId;
|
|
551
|
+
}
|
|
552
|
+
const descendants = await this.findBy({
|
|
553
|
+
query: query,
|
|
554
|
+
select: {
|
|
555
|
+
_id: true,
|
|
556
|
+
},
|
|
557
|
+
limit: LIMIT_MAX,
|
|
558
|
+
skip: 0,
|
|
559
|
+
props: {
|
|
560
|
+
isRoot: true,
|
|
561
|
+
},
|
|
562
|
+
});
|
|
563
|
+
return descendants
|
|
564
|
+
.filter((descendant) => {
|
|
565
|
+
return descendant.id && descendant.id.toString() !== siteId.toString();
|
|
566
|
+
})
|
|
567
|
+
.map((descendant) => {
|
|
568
|
+
return descendant.id;
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
/*
|
|
572
|
+
* ------------------------------------------------------------------
|
|
573
|
+
* Persisted rollup engine
|
|
574
|
+
* ------------------------------------------------------------------
|
|
575
|
+
*/
|
|
576
|
+
/*
|
|
577
|
+
* Recomputes the worst-of rollup for one site from the devices in its
|
|
578
|
+
* subtree, persisting currentMonitorStatusId + lastRollupAt and keeping
|
|
579
|
+
* the NetworkSiteStatusTimeline in sync (close the open row, open a new
|
|
580
|
+
* one) whenever the status actually changes.
|
|
581
|
+
*/
|
|
582
|
+
async recomputeRollupForSite(siteId) {
|
|
583
|
+
var _a;
|
|
584
|
+
const site = await this.findOneById({
|
|
585
|
+
id: siteId,
|
|
586
|
+
select: {
|
|
587
|
+
_id: true,
|
|
588
|
+
projectId: true,
|
|
589
|
+
currentMonitorStatusId: true,
|
|
590
|
+
name: true,
|
|
591
|
+
shouldAlertWhenUnhealthy: true,
|
|
592
|
+
alertSeverityId: true,
|
|
593
|
+
currentActiveAlertId: true,
|
|
594
|
+
},
|
|
595
|
+
props: {
|
|
596
|
+
isRoot: true,
|
|
597
|
+
},
|
|
598
|
+
});
|
|
599
|
+
if (!site || !site.id || !site.projectId) {
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
const subtreeSiteIds = [
|
|
603
|
+
site.id,
|
|
604
|
+
...(await this.getDescendantSiteIds(site.id, site.projectId)),
|
|
605
|
+
];
|
|
606
|
+
/*
|
|
607
|
+
* Archived devices are decommissioned: they keep their siteId but must
|
|
608
|
+
* not vote in the rollup. An archived, never-monitored device otherwise
|
|
609
|
+
* falls through to the freshness fallback (stale lastSeenAt -> Offline)
|
|
610
|
+
* and pins its whole ancestor chain red forever, with the drill-down
|
|
611
|
+
* showing zero devices because that query excludes archived rows.
|
|
612
|
+
*/
|
|
613
|
+
const devices = await NetworkDeviceService.findBy({
|
|
614
|
+
query: {
|
|
615
|
+
projectId: site.projectId,
|
|
616
|
+
siteId: QueryHelper.any(subtreeSiteIds),
|
|
617
|
+
isArchived: false,
|
|
618
|
+
},
|
|
619
|
+
select: {
|
|
620
|
+
_id: true,
|
|
621
|
+
currentMonitorStatusId: true,
|
|
622
|
+
lastSeenAt: true,
|
|
623
|
+
},
|
|
624
|
+
limit: LIMIT_MAX,
|
|
625
|
+
skip: 0,
|
|
626
|
+
props: {
|
|
627
|
+
isRoot: true,
|
|
628
|
+
},
|
|
629
|
+
});
|
|
630
|
+
const statuses = await MonitorStatusService.findBy({
|
|
631
|
+
query: {
|
|
632
|
+
projectId: site.projectId,
|
|
633
|
+
},
|
|
634
|
+
select: {
|
|
635
|
+
_id: true,
|
|
636
|
+
name: true,
|
|
637
|
+
priority: true,
|
|
638
|
+
isOperationalState: true,
|
|
639
|
+
isOfflineState: true,
|
|
640
|
+
},
|
|
641
|
+
limit: LIMIT_PER_PROJECT,
|
|
642
|
+
skip: 0,
|
|
643
|
+
props: {
|
|
644
|
+
isRoot: true,
|
|
645
|
+
},
|
|
646
|
+
});
|
|
647
|
+
const priorityByStatusId = new Map();
|
|
648
|
+
let operationalStatus = null;
|
|
649
|
+
let offlineStatus = null;
|
|
650
|
+
for (const status of statuses) {
|
|
651
|
+
if (!status.id || typeof status.priority !== "number") {
|
|
652
|
+
continue;
|
|
653
|
+
}
|
|
654
|
+
priorityByStatusId.set(status.id.toString(), status.priority);
|
|
655
|
+
if (status.isOperationalState && !operationalStatus) {
|
|
656
|
+
operationalStatus = {
|
|
657
|
+
monitorStatusId: status.id.toString(),
|
|
658
|
+
priority: status.priority,
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
if (status.isOfflineState && !offlineStatus) {
|
|
662
|
+
offlineStatus = {
|
|
663
|
+
monitorStatusId: status.id.toString(),
|
|
664
|
+
priority: status.priority,
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
const deviceStates = devices.map((device) => {
|
|
669
|
+
var _a;
|
|
670
|
+
const statusId = (_a = device.currentMonitorStatusId) === null || _a === void 0 ? void 0 : _a.toString();
|
|
671
|
+
return {
|
|
672
|
+
currentMonitorStatusId: statusId,
|
|
673
|
+
monitorStatusPriority: statusId
|
|
674
|
+
? priorityByStatusId.get(statusId)
|
|
675
|
+
: undefined,
|
|
676
|
+
lastSeenAt: device.lastSeenAt,
|
|
677
|
+
};
|
|
678
|
+
});
|
|
679
|
+
const worstStatusId = SiteStatusRollupUtil.worstStatus({
|
|
680
|
+
deviceStates: deviceStates,
|
|
681
|
+
operationalStatus: operationalStatus,
|
|
682
|
+
offlineStatus: offlineStatus,
|
|
683
|
+
});
|
|
684
|
+
const now = OneUptimeDate.getCurrentDate();
|
|
685
|
+
const currentStatusId = ((_a = site.currentMonitorStatusId) === null || _a === void 0 ? void 0 : _a.toString()) || null;
|
|
686
|
+
// No devices contribute -> leave the status alone, just stamp the run.
|
|
687
|
+
if (!worstStatusId || worstStatusId === currentStatusId) {
|
|
688
|
+
await this.updateColumnsByIdWithoutHooks({
|
|
689
|
+
id: site.id,
|
|
690
|
+
data: {
|
|
691
|
+
lastRollupAt: now,
|
|
692
|
+
},
|
|
693
|
+
});
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
await this.updateColumnsByIdWithoutHooks({
|
|
697
|
+
id: site.id,
|
|
698
|
+
data: {
|
|
699
|
+
currentMonitorStatusId: new ObjectID(worstStatusId),
|
|
700
|
+
lastRollupAt: now,
|
|
701
|
+
},
|
|
702
|
+
});
|
|
703
|
+
// Close every open timeline row, then open one for the new status.
|
|
704
|
+
await NetworkSiteStatusTimelineService.updateBy({
|
|
705
|
+
query: {
|
|
706
|
+
siteId: site.id,
|
|
707
|
+
endsAt: QueryHelper.isNull(),
|
|
708
|
+
},
|
|
709
|
+
data: {
|
|
710
|
+
endsAt: now,
|
|
711
|
+
},
|
|
712
|
+
limit: LIMIT_MAX,
|
|
713
|
+
skip: 0,
|
|
714
|
+
props: {
|
|
715
|
+
isRoot: true,
|
|
716
|
+
},
|
|
717
|
+
});
|
|
718
|
+
const timeline = new NetworkSiteStatusTimeline();
|
|
719
|
+
timeline.projectId = site.projectId;
|
|
720
|
+
timeline.siteId = site.id;
|
|
721
|
+
timeline.monitorStatusId = new ObjectID(worstStatusId);
|
|
722
|
+
timeline.startsAt = now;
|
|
723
|
+
await NetworkSiteStatusTimelineService.create({
|
|
724
|
+
data: timeline,
|
|
725
|
+
props: {
|
|
726
|
+
isRoot: true,
|
|
727
|
+
},
|
|
728
|
+
});
|
|
729
|
+
/*
|
|
730
|
+
* Site alerting rides the same transition the timeline records. Alert
|
|
731
|
+
* bookkeeping must never break the rollup itself.
|
|
732
|
+
*/
|
|
733
|
+
try {
|
|
734
|
+
await this.syncSiteAlertForStatusTransition({
|
|
735
|
+
site: site,
|
|
736
|
+
newStatus: statuses.find((status) => {
|
|
737
|
+
var _a;
|
|
738
|
+
return ((_a = status.id) === null || _a === void 0 ? void 0 : _a.toString()) === worstStatusId;
|
|
739
|
+
}) || null,
|
|
740
|
+
});
|
|
741
|
+
}
|
|
742
|
+
catch (err) {
|
|
743
|
+
logger.error(`Network site rollup: error syncing alert for site ${site.id.toString()}:`);
|
|
744
|
+
logger.error(err);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
/*
|
|
748
|
+
* Opens an alert when a site's rollup TRANSITIONS to a non-operational
|
|
749
|
+
* status (and alerting is enabled on the site), and auto-resolves that
|
|
750
|
+
* alert when the site transitions back to operational. Transition-only
|
|
751
|
+
* by design: enabling alerting on an already-unhealthy site arms the
|
|
752
|
+
* next transition instead of retro-alerting, and a manually resolved
|
|
753
|
+
* alert is not reopened until the site recovers and degrades again
|
|
754
|
+
* (a transition clears the tracked id).
|
|
755
|
+
*/
|
|
756
|
+
async syncSiteAlertForStatusTransition(data) {
|
|
757
|
+
const site = data.site;
|
|
758
|
+
if (!site.id || !site.projectId || !data.newStatus) {
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
const isNowOperational = Boolean(data.newStatus.isOperationalState);
|
|
762
|
+
// Recovery: resolve the open site alert, if one is tracked.
|
|
763
|
+
if (isNowOperational) {
|
|
764
|
+
if (!site.currentActiveAlertId) {
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
await this.resolveSiteAlert({
|
|
768
|
+
projectId: site.projectId,
|
|
769
|
+
alertId: site.currentActiveAlertId,
|
|
770
|
+
rootCause: `**Recovered:** Network site **${site.name || "site"}** rolled back up to ${data.newStatus.name || "an operational status"}.`,
|
|
771
|
+
});
|
|
772
|
+
await this.updateColumnsByIdWithoutHooks({
|
|
773
|
+
id: site.id,
|
|
774
|
+
data: {
|
|
775
|
+
currentActiveAlertId: null,
|
|
776
|
+
},
|
|
777
|
+
});
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
// Degradation between two unhealthy statuses keeps the existing alert.
|
|
781
|
+
if (!site.shouldAlertWhenUnhealthy ||
|
|
782
|
+
site.currentActiveAlertId ||
|
|
783
|
+
DisableAutomaticAlertCreation) {
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
786
|
+
let alertSeverityId = site.alertSeverityId;
|
|
787
|
+
if (!alertSeverityId) {
|
|
788
|
+
// Same default the monitor alert path uses: the most severe first.
|
|
789
|
+
const severity = await AlertSeverityService.findOneBy({
|
|
790
|
+
query: {
|
|
791
|
+
projectId: site.projectId,
|
|
792
|
+
},
|
|
793
|
+
sort: {
|
|
794
|
+
order: SortOrder.Ascending,
|
|
795
|
+
},
|
|
796
|
+
select: {
|
|
797
|
+
_id: true,
|
|
798
|
+
},
|
|
799
|
+
props: {
|
|
800
|
+
isRoot: true,
|
|
801
|
+
},
|
|
802
|
+
});
|
|
803
|
+
if (!severity || !severity.id) {
|
|
804
|
+
logger.warn(`Network site alerting: project ${site.projectId.toString()} has no alert severity; skipping site alert.`);
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
807
|
+
alertSeverityId = severity.id;
|
|
808
|
+
}
|
|
809
|
+
const statusName = data.newStatus.name || "Unhealthy";
|
|
810
|
+
const alert = new Alert();
|
|
811
|
+
alert.projectId = site.projectId;
|
|
812
|
+
alert.title = `Network site ${site.name || site.id.toString()} is ${statusName}`;
|
|
813
|
+
alert.description = `The health rollup of network site **${site.name || site.id.toString()}** changed to **${statusName}** — the worst status of the devices at this site and every site below it. This alert auto-resolves when the site rolls back up to an operational status.`;
|
|
814
|
+
alert.alertSeverityId = alertSeverityId;
|
|
815
|
+
alert.rootCause = `Network site **${site.name || site.id.toString()}** rolled up to **${statusName}**.`;
|
|
816
|
+
const createdAlert = await AlertService.create({
|
|
817
|
+
data: alert,
|
|
818
|
+
props: {
|
|
819
|
+
isRoot: true,
|
|
820
|
+
},
|
|
821
|
+
});
|
|
822
|
+
if (createdAlert.id) {
|
|
823
|
+
await this.updateColumnsByIdWithoutHooks({
|
|
824
|
+
id: site.id,
|
|
825
|
+
data: {
|
|
826
|
+
currentActiveAlertId: createdAlert.id,
|
|
827
|
+
},
|
|
828
|
+
});
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
// Moves a site alert to the project's resolved state, if not already there.
|
|
832
|
+
async resolveSiteAlert(data) {
|
|
833
|
+
var _a;
|
|
834
|
+
const alert = await AlertService.findOneById({
|
|
835
|
+
id: data.alertId,
|
|
836
|
+
select: {
|
|
837
|
+
_id: true,
|
|
838
|
+
currentAlertStateId: true,
|
|
839
|
+
},
|
|
840
|
+
props: {
|
|
841
|
+
isRoot: true,
|
|
842
|
+
},
|
|
843
|
+
});
|
|
844
|
+
if (!alert || !alert.id) {
|
|
845
|
+
// Deleted by hand — nothing to resolve.
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
const resolvedStateId = await AlertStateTimelineService.getResolvedStateIdForProject(data.projectId);
|
|
849
|
+
if (((_a = alert.currentAlertStateId) === null || _a === void 0 ? void 0 : _a.toString()) === resolvedStateId.toString()) {
|
|
850
|
+
// Already resolved manually.
|
|
851
|
+
return;
|
|
852
|
+
}
|
|
853
|
+
const alertStateTimeline = new AlertStateTimeline();
|
|
854
|
+
alertStateTimeline.alertId = alert.id;
|
|
855
|
+
alertStateTimeline.alertStateId = resolvedStateId;
|
|
856
|
+
alertStateTimeline.projectId = data.projectId;
|
|
857
|
+
alertStateTimeline.rootCause = data.rootCause;
|
|
858
|
+
await AlertStateTimelineService.create({
|
|
859
|
+
data: alertStateTimeline,
|
|
860
|
+
props: {
|
|
861
|
+
isRoot: true,
|
|
862
|
+
},
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
// Recomputes the site itself, then each ancestor (nearest first).
|
|
866
|
+
async recomputeRollupForSiteAndAncestors(siteId) {
|
|
867
|
+
await this.recomputeRollupForSite(siteId);
|
|
868
|
+
const ancestorIds = await this.getAncestorIds(siteId);
|
|
869
|
+
// getAncestorIds returns root-first; recompute nearest ancestor first.
|
|
870
|
+
for (let i = ancestorIds.length - 1; i >= 0; i--) {
|
|
871
|
+
await this.recomputeRollupForSite(ancestorIds[i]);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
/*
|
|
875
|
+
* ------------------------------------------------------------------
|
|
876
|
+
* Monitor status bridge
|
|
877
|
+
* ------------------------------------------------------------------
|
|
878
|
+
*/
|
|
879
|
+
/*
|
|
880
|
+
* Called by MonitorService.changeMonitorStatus after a status persists.
|
|
881
|
+
* Resolves which NetworkDevices the monitors reference in their steps,
|
|
882
|
+
* stamps those devices' currentMonitorStatusId, then recomputes the
|
|
883
|
+
* rollup for every affected site chain. Never throws - a rollup failure
|
|
884
|
+
* must never break a monitor status change.
|
|
885
|
+
*/
|
|
886
|
+
async onMonitorStatusChanged(data) {
|
|
887
|
+
try {
|
|
888
|
+
if (data.monitorIds.length === 0) {
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
const monitors = await MonitorService.findBy({
|
|
892
|
+
query: {
|
|
893
|
+
_id: QueryHelper.any(data.monitorIds),
|
|
894
|
+
projectId: data.projectId,
|
|
895
|
+
monitorType: MonitorType.NetworkDevice,
|
|
896
|
+
},
|
|
897
|
+
select: {
|
|
898
|
+
_id: true,
|
|
899
|
+
monitorType: true,
|
|
900
|
+
monitorSteps: true,
|
|
901
|
+
},
|
|
902
|
+
limit: LIMIT_MAX,
|
|
903
|
+
skip: 0,
|
|
904
|
+
props: {
|
|
905
|
+
isRoot: true,
|
|
906
|
+
},
|
|
907
|
+
});
|
|
908
|
+
if (monitors.length === 0) {
|
|
909
|
+
return;
|
|
910
|
+
}
|
|
911
|
+
const deviceIds = NetworkDeviceHydrationUtil.getReferencedNetworkDeviceIds(monitors);
|
|
912
|
+
if (deviceIds.length === 0) {
|
|
913
|
+
return;
|
|
914
|
+
}
|
|
915
|
+
const devices = await NetworkDeviceService.findBy({
|
|
916
|
+
query: {
|
|
917
|
+
_id: QueryHelper.any(deviceIds),
|
|
918
|
+
projectId: data.projectId,
|
|
919
|
+
},
|
|
920
|
+
select: {
|
|
921
|
+
_id: true,
|
|
922
|
+
siteId: true,
|
|
923
|
+
},
|
|
924
|
+
limit: LIMIT_MAX,
|
|
925
|
+
skip: 0,
|
|
926
|
+
props: {
|
|
927
|
+
isRoot: true,
|
|
928
|
+
},
|
|
929
|
+
});
|
|
930
|
+
for (const device of devices) {
|
|
931
|
+
if (!device.id) {
|
|
932
|
+
continue;
|
|
933
|
+
}
|
|
934
|
+
await NetworkDeviceService.updateColumnsByIdWithoutHooks({
|
|
935
|
+
id: device.id,
|
|
936
|
+
data: {
|
|
937
|
+
currentMonitorStatusId: data.monitorStatusId,
|
|
938
|
+
},
|
|
939
|
+
});
|
|
940
|
+
}
|
|
941
|
+
const distinctSiteIds = new Map();
|
|
942
|
+
for (const device of devices) {
|
|
943
|
+
if (device.siteId) {
|
|
944
|
+
distinctSiteIds.set(device.siteId.toString(), device.siteId);
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
for (const siteId of distinctSiteIds.values()) {
|
|
948
|
+
await this.recomputeRollupForSiteAndAncestors(siteId);
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
catch (error) {
|
|
952
|
+
logger.error(`NetworkSiteService.onMonitorStatusChanged: failed to update network site rollups: ${error}`, {
|
|
953
|
+
projectId: data.projectId.toString(),
|
|
954
|
+
monitorStatusId: data.monitorStatusId.toString(),
|
|
955
|
+
});
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
__decorate([
|
|
960
|
+
CaptureSpan(),
|
|
961
|
+
__metadata("design:type", Function),
|
|
962
|
+
__metadata("design:paramtypes", [Object]),
|
|
963
|
+
__metadata("design:returntype", Promise)
|
|
964
|
+
], Service.prototype, "onBeforeCreate", null);
|
|
965
|
+
__decorate([
|
|
966
|
+
CaptureSpan(),
|
|
967
|
+
__metadata("design:type", Function),
|
|
968
|
+
__metadata("design:paramtypes", [Object, Model]),
|
|
969
|
+
__metadata("design:returntype", Promise)
|
|
970
|
+
], Service.prototype, "onCreateSuccess", null);
|
|
971
|
+
__decorate([
|
|
972
|
+
CaptureSpan(),
|
|
973
|
+
__metadata("design:type", Function),
|
|
974
|
+
__metadata("design:paramtypes", [Object]),
|
|
975
|
+
__metadata("design:returntype", Promise)
|
|
976
|
+
], Service.prototype, "onBeforeUpdate", null);
|
|
977
|
+
__decorate([
|
|
978
|
+
CaptureSpan(),
|
|
979
|
+
__metadata("design:type", Function),
|
|
980
|
+
__metadata("design:paramtypes", [Object, Array]),
|
|
981
|
+
__metadata("design:returntype", Promise)
|
|
982
|
+
], Service.prototype, "onUpdateSuccess", null);
|
|
983
|
+
__decorate([
|
|
984
|
+
CaptureSpan(),
|
|
985
|
+
__metadata("design:type", Function),
|
|
986
|
+
__metadata("design:paramtypes", [Object]),
|
|
987
|
+
__metadata("design:returntype", Promise)
|
|
988
|
+
], Service.prototype, "onBeforeDelete", null);
|
|
989
|
+
__decorate([
|
|
990
|
+
CaptureSpan(),
|
|
991
|
+
__metadata("design:type", Function),
|
|
992
|
+
__metadata("design:paramtypes", [Object, Array]),
|
|
993
|
+
__metadata("design:returntype", Promise)
|
|
994
|
+
], Service.prototype, "onDeleteSuccess", null);
|
|
995
|
+
__decorate([
|
|
996
|
+
CaptureSpan(),
|
|
997
|
+
__metadata("design:type", Function),
|
|
998
|
+
__metadata("design:paramtypes", [ObjectID]),
|
|
999
|
+
__metadata("design:returntype", Promise)
|
|
1000
|
+
], Service.prototype, "getMaterializedPathForSite", null);
|
|
1001
|
+
__decorate([
|
|
1002
|
+
CaptureSpan(),
|
|
1003
|
+
__metadata("design:type", Function),
|
|
1004
|
+
__metadata("design:paramtypes", [ObjectID]),
|
|
1005
|
+
__metadata("design:returntype", Promise)
|
|
1006
|
+
], Service.prototype, "getAncestorIds", null);
|
|
1007
|
+
__decorate([
|
|
1008
|
+
CaptureSpan(),
|
|
1009
|
+
__metadata("design:type", Function),
|
|
1010
|
+
__metadata("design:paramtypes", [ObjectID, Object]),
|
|
1011
|
+
__metadata("design:returntype", Promise)
|
|
1012
|
+
], Service.prototype, "getDescendantSiteIds", null);
|
|
1013
|
+
__decorate([
|
|
1014
|
+
CaptureSpan(),
|
|
1015
|
+
__metadata("design:type", Function),
|
|
1016
|
+
__metadata("design:paramtypes", [ObjectID]),
|
|
1017
|
+
__metadata("design:returntype", Promise)
|
|
1018
|
+
], Service.prototype, "recomputeRollupForSite", null);
|
|
1019
|
+
__decorate([
|
|
1020
|
+
CaptureSpan(),
|
|
1021
|
+
__metadata("design:type", Function),
|
|
1022
|
+
__metadata("design:paramtypes", [Object]),
|
|
1023
|
+
__metadata("design:returntype", Promise)
|
|
1024
|
+
], Service.prototype, "syncSiteAlertForStatusTransition", null);
|
|
1025
|
+
__decorate([
|
|
1026
|
+
CaptureSpan(),
|
|
1027
|
+
__metadata("design:type", Function),
|
|
1028
|
+
__metadata("design:paramtypes", [ObjectID]),
|
|
1029
|
+
__metadata("design:returntype", Promise)
|
|
1030
|
+
], Service.prototype, "recomputeRollupForSiteAndAncestors", null);
|
|
1031
|
+
__decorate([
|
|
1032
|
+
CaptureSpan(),
|
|
1033
|
+
__metadata("design:type", Function),
|
|
1034
|
+
__metadata("design:paramtypes", [Object]),
|
|
1035
|
+
__metadata("design:returntype", Promise)
|
|
1036
|
+
], Service.prototype, "onMonitorStatusChanged", null);
|
|
1037
|
+
export default new Service();
|
|
1038
|
+
//# sourceMappingURL=NetworkSiteService.js.map
|