@oneuptime/common 12.0.1 → 12.0.3
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/DatabaseBaseModel/DatabaseBaseModel.ts +14 -0
- package/Models/DatabaseModels/Host.ts +12 -4
- package/Models/DatabaseModels/Index.ts +2 -0
- package/Models/DatabaseModels/KubernetesContainer.ts +5 -4
- package/Models/DatabaseModels/KubernetesResource.ts +8 -7
- package/Models/DatabaseModels/LogDropFilter.ts +9 -20
- package/Models/DatabaseModels/PodmanResource.ts +6 -6
- package/Models/DatabaseModels/ServiceLevelObjective.ts +91 -0
- package/Models/DatabaseModels/StatusPage.ts +95 -0
- package/Models/DatabaseModels/StatusPageMonitorRule.ts +911 -0
- package/Models/DatabaseModels/StatusPageResource.ts +73 -0
- package/Models/DatabaseModels/TraceDropFilter.ts +9 -20
- package/Server/API/BaseAPI.ts +13 -2
- package/Server/API/DashboardAPI.ts +39 -0
- package/Server/API/TeamMemberAPI.ts +85 -0
- package/Server/EnvironmentConfig.ts +31 -1
- package/Server/Infrastructure/GlobalCache.ts +115 -0
- package/Server/Infrastructure/Postgres/DataSourceOptions.ts +16 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785900000000-AddSloMonitorLabelRule.ts +84 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785915638551-IncreaseHostIpAddressesLength.ts +40 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785930000000-WidenInventoryResourceNameColumns.ts +131 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785930709405-AddStatusPageReportPeriod.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.ts +123 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
- package/Server/Middleware/ProjectAuthorization.ts +66 -4
- package/Server/Services/AlertStateTimelineService.ts +20 -0
- package/Server/Services/BillingService.ts +600 -51
- package/Server/Services/CephClusterService.ts +27 -45
- package/Server/Services/CephResourceService.ts +43 -4
- package/Server/Services/CloudResourceService.ts +24 -42
- package/Server/Services/DatabaseService.ts +198 -6
- package/Server/Services/DockerHostService.ts +20 -38
- package/Server/Services/DockerResourceService.ts +62 -8
- package/Server/Services/DockerSwarmClusterService.ts +28 -46
- package/Server/Services/DockerSwarmResourceService.ts +53 -4
- package/Server/Services/HostService.ts +47 -57
- package/Server/Services/IncidentStateTimelineService.ts +20 -0
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/IoTDeviceService.ts +1 -17
- package/Server/Services/IoTFleetService.ts +20 -38
- package/Server/Services/KubernetesClusterService.ts +18 -36
- package/Server/Services/KubernetesContainerService.ts +50 -9
- package/Server/Services/KubernetesResourceService.ts +53 -7
- package/Server/Services/LabelService.ts +153 -1
- package/Server/Services/MetricTypeService.ts +84 -0
- package/Server/Services/MonitorService.ts +146 -14
- package/Server/Services/MonitorStatusTimelineService.ts +29 -0
- package/Server/Services/MonitorTemplateService.ts +65 -0
- package/Server/Services/PodmanHostService.ts +20 -38
- package/Server/Services/PodmanResourceService.ts +62 -8
- package/Server/Services/ProjectService.ts +165 -35
- package/Server/Services/ProxmoxClusterService.ts +24 -42
- package/Server/Services/ProxmoxResourceService.ts +43 -4
- package/Server/Services/RumApplicationService.ts +20 -38
- package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +21 -0
- package/Server/Services/ServerlessFunctionService.ts +25 -43
- package/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.ts +426 -0
- package/Server/Services/ServiceLevelObjectiveService.ts +39 -0
- package/Server/Services/ServiceService.ts +299 -73
- package/Server/Services/StatusPageMonitorRuleEngineService.ts +752 -0
- package/Server/Services/StatusPageMonitorRuleService.ts +471 -0
- package/Server/Services/StatusPageService.ts +95 -36
- package/Server/Services/StatusPageSubscriberNotificationTemplateService.ts +18 -1
- package/Server/Services/StatusPageSubscriberService.ts +3 -0
- package/Server/Services/TelemetryEntityRelationshipService.ts +1 -0
- package/Server/Services/TelemetryEntityService.ts +1 -0
- package/Server/Types/Database/JSONColumnQuery.ts +621 -0
- package/Server/Types/Database/Permissions/PublicPermission.ts +9 -2
- package/Server/Types/Database/QueryHelper.ts +17 -32
- package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +170 -39
- package/Server/Utils/Database/TruncateColumnValue.ts +84 -0
- package/Server/Utils/Monitor/MonitorResource.ts +63 -36
- package/Server/Utils/Monitor/MonitorStatusTimeline.ts +36 -0
- package/Server/Utils/Monitor/MonitorStepsProjectValidator.ts +148 -127
- package/Server/Utils/Monitor/MonitorStepsReferenceExtractor.ts +434 -0
- package/Server/Utils/SingleFlight.ts +83 -0
- package/Server/Utils/StatusPage/MonitorRulePatternValidator.ts +46 -0
- package/Server/Utils/Telemetry/EntityRegistry.ts +107 -26
- package/Server/Utils/Telemetry/ResourceHeartbeat.ts +314 -0
- package/Server/Utils/Telemetry/Telemetry.ts +351 -122
- package/Tests/App/Dashboard/UsersTableGroupsByPerson.test.tsx +448 -0
- package/Tests/App/Dashboard/WidgetCatalog.test.ts +2 -0
- package/Tests/Models/DatabaseModels/ColumnTransformerInvariants.test.ts +306 -0
- package/Tests/Models/DatabaseModels/NumberColumnDeserialization.test.ts +333 -0
- package/Tests/Models/DatabaseModels/StatusPageMonitorRuleModel.test.ts +190 -0
- package/Tests/Server/API/BaseAPIApiKeyAuth.test.ts +704 -0
- package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +26 -0
- package/Tests/Server/API/TeamMemberRemoveUserFromProjectAPI.test.ts +303 -0
- package/Tests/Server/Infrastructure/GlobalCache.test.ts +226 -0
- package/Tests/Server/Infrastructure/PostgresLockTimeoutOptions.test.ts +181 -0
- package/Tests/Server/Middleware/MasterAdminAuthorization.test.ts +350 -0
- package/Tests/Server/Middleware/ProjectAuthorizationApiKeyHeader.test.ts +362 -0
- package/Tests/Server/Middleware/ProjectAuthorizationApiKeyMiddleware.test.ts +687 -0
- package/Tests/Server/Services/BillingService.test.ts +78 -3
- package/Tests/Server/Services/BillingServiceChangePlanCancel.test.ts +645 -0
- package/Tests/Server/Services/BillingServiceTrialPlanChange.test.ts +1005 -0
- package/Tests/Server/Services/DatabaseServiceUpdateColumnsIfUnlocked.test.ts +342 -0
- package/Tests/Server/Services/DropFilterSaveValidation.test.ts +245 -0
- package/Tests/Server/Services/HookFreeWriteLengthClamp.test.ts +503 -0
- package/Tests/Server/Services/HostIpAddressesColumnWidth.test.ts +198 -0
- package/Tests/Server/Services/HostServiceUpdateLastSeen.test.ts +658 -0
- package/Tests/Server/Services/InventoryResourceNameColumnWidth.test.ts +500 -0
- package/Tests/Server/Services/InventoryUpsertSchemaParity.test.ts +586 -0
- package/Tests/Server/Services/InventoryUpsertTruncationGuard.test.ts +1242 -0
- package/Tests/Server/Services/MetricTypeAttachServices.test.ts +222 -0
- package/Tests/Server/Services/MissingReferenceWriteGuard.test.ts +614 -0
- package/Tests/Server/Services/MonitorStatusTimelineFastPath.test.ts +23 -0
- package/Tests/Server/Services/ProjectServiceChangePlan.test.ts +650 -0
- package/Tests/Server/Services/ProjectServiceExtendTrial.test.ts +1 -0
- package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +636 -0
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.test.ts +770 -0
- package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +130 -0
- package/Tests/Server/Services/ServiceUpdateLastSeenSplitGates.test.ts +705 -0
- package/Tests/Server/Services/SloMonitorLabelRuleHooks.test.ts +352 -0
- package/Tests/Server/Services/StatusPageMonitorRuleEngineService.test.ts +1719 -0
- package/Tests/Server/Services/StatusPageMonitorRuleHooks.test.ts +1212 -0
- package/Tests/Server/Services/StatusPageMonitorRuleMonitorCreateHook.test.ts +228 -0
- package/Tests/Server/Services/StatusPageSubscriberReport.test.ts +29 -13
- package/Tests/Server/TestingUtils/Services/BillingServiceHelper.ts +69 -8
- package/Tests/Server/Types/Database/JSONColumnQuery.test.ts +593 -0
- package/Tests/Server/Types/Database/Permissions/PublicPermission.test.ts +495 -0
- package/Tests/Server/Types/Database/QueryUtil.test.ts +113 -0
- package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +267 -0
- package/Tests/Server/Utils/Database/ProjectScopedReferenceValidator.test.ts +260 -13
- package/Tests/Server/Utils/Database/TruncateColumnValue.test.ts +179 -0
- package/Tests/Server/Utils/EntityRegistryRowFence.test.ts +302 -0
- package/Tests/Server/Utils/MetricTypeIndexConvergence.test.ts +598 -0
- package/Tests/Server/Utils/Monitor/MonitorStatusTimelineUnusableStatus.test.ts +154 -0
- package/Tests/Server/Utils/Monitor/MonitorStepsProjectValidator.test.ts +638 -92
- package/Tests/Server/Utils/Monitor/MonitorStepsReferenceExtractor.test.ts +724 -0
- package/Tests/Server/Utils/SingleFlight.test.ts +221 -0
- package/Tests/Types/Dashboard/NetworkDashboardTemplate.test.ts +793 -0
- package/Tests/Types/Database/BigIntColumnTransformer.test.ts +147 -0
- package/Tests/Types/Database/DatabasePropertyTransformer.test.ts +140 -0
- package/Tests/Types/Database/NumericColumnValue.test.ts +127 -0
- package/Tests/Types/Decimal.test.ts +37 -0
- package/Tests/Types/Events/Recurring.test.ts +157 -0
- package/Tests/Types/Monitor/SnmpVersionParsing.test.ts +152 -0
- package/Tests/Types/Port.test.ts +38 -0
- package/Tests/UI/Components/LogsHistogram.test.tsx +276 -0
- package/Tests/UI/Components/ModelTable/ModelTableGroupsProjectUsers.test.tsx +375 -0
- package/Tests/UI/Components/ModelTable/useCustomFieldColumns.test.tsx +196 -0
- package/Tests/UI/Components/UseLiveLogsRefresh.test.tsx +489 -0
- package/Tests/UI/Components/UseLogsHistogram.test.tsx +500 -0
- package/Tests/UI/Utils/ProjectUsersModelAPI.test.ts +739 -0
- package/Tests/UI/Utils/TeamMembersByUser.test.ts +633 -0
- package/Tests/Utils/Dashboard/Components/DashboardComponentsUtil.test.ts +120 -0
- package/Tests/Utils/Dashboard/DashboardNetworkMapComponent.test.ts +327 -0
- package/Tests/Utils/StatusPage/ReportPeriod.test.ts +218 -0
- package/Tests/Utils/Telemetry/HostIpAddresses.test.ts +291 -0
- package/Types/CustomField/CustomFieldDefinition.ts +24 -0
- package/Types/Dashboard/DashboardComponentType.ts +1 -0
- package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.ts +40 -0
- package/Types/Dashboard/DashboardTemplates.ts +397 -0
- package/Types/Database/BigIntColumnTransformer.ts +74 -0
- package/Types/Database/DatabaseProperty.ts +26 -0
- package/Types/Database/NumericColumnValue.ts +128 -0
- package/Types/Date.ts +112 -0
- package/Types/Decimal.ts +16 -4
- package/Types/Events/Recurring.ts +99 -1
- package/Types/Permission.ts +48 -0
- package/Types/Port.ts +16 -4
- package/Types/StatusPage/StatusPageReport.ts +11 -0
- package/Types/StatusPage/StatusPageReportPeriodType.ts +21 -0
- package/UI/Components/LogsViewer/useLiveLogsRefresh.ts +86 -0
- package/UI/Components/LogsViewer/useLogsHistogram.ts +113 -0
- package/UI/Components/ModelTable/CustomFieldColumns.tsx +2 -6
- package/UI/Components/ModelTable/useCustomFieldColumns.ts +21 -2
- package/UI/Utils/ModelAPI/ProjectUsersModelAPI.ts +305 -0
- package/UI/Utils/TeamMembersByUser.ts +302 -0
- package/Utils/Dashboard/Components/DashboardNetworkMapComponent.ts +136 -0
- package/Utils/Dashboard/Components/Index.ts +7 -0
- package/Utils/StatusPage/ReportPeriod.ts +236 -0
- package/Utils/Telemetry/HostIpAddresses.ts +98 -0
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js +12 -0
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Host.js +12 -4
- package/build/dist/Models/DatabaseModels/Host.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/KubernetesContainer.js +4 -4
- package/build/dist/Models/DatabaseModels/KubernetesContainer.js.map +1 -1
- package/build/dist/Models/DatabaseModels/KubernetesResource.js +7 -7
- package/build/dist/Models/DatabaseModels/KubernetesResource.js.map +1 -1
- package/build/dist/Models/DatabaseModels/LogDropFilter.js +9 -20
- package/build/dist/Models/DatabaseModels/LogDropFilter.js.map +1 -1
- package/build/dist/Models/DatabaseModels/PodmanResource.js +6 -6
- package/build/dist/Models/DatabaseModels/PodmanResource.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceLevelObjective.js +87 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjective.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPage.js +98 -0
- package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageMonitorRule.js +925 -0
- package/build/dist/Models/DatabaseModels/StatusPageMonitorRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/StatusPageResource.js +72 -0
- package/build/dist/Models/DatabaseModels/StatusPageResource.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TraceDropFilter.js +9 -20
- package/build/dist/Models/DatabaseModels/TraceDropFilter.js.map +1 -1
- package/build/dist/Server/API/BaseAPI.js +11 -1
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/DashboardAPI.js +39 -0
- package/build/dist/Server/API/DashboardAPI.js.map +1 -1
- package/build/dist/Server/API/TeamMemberAPI.js +57 -2
- package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +27 -1
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/GlobalCache.js +91 -0
- package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js +5 -3
- package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785900000000-AddSloMonitorLabelRule.js +45 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785900000000-AddSloMonitorLabelRule.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785915638551-IncreaseHostIpAddressesLength.js +31 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785915638551-IncreaseHostIpAddressesLength.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785930000000-WidenInventoryResourceNameColumns.js +90 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785930000000-WidenInventoryResourceNameColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785930709405-AddStatusPageReportPeriod.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785930709405-AddStatusPageReportPeriod.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.js +48 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/ProjectAuthorization.js +59 -4
- package/build/dist/Server/Middleware/ProjectAuthorization.js.map +1 -1
- package/build/dist/Server/Services/AlertStateTimelineService.js +19 -0
- package/build/dist/Server/Services/AlertStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/BillingService.js +466 -36
- package/build/dist/Server/Services/BillingService.js.map +1 -1
- package/build/dist/Server/Services/CephClusterService.js +26 -39
- package/build/dist/Server/Services/CephClusterService.js.map +1 -1
- package/build/dist/Server/Services/CephResourceService.js +28 -3
- package/build/dist/Server/Services/CephResourceService.js.map +1 -1
- package/build/dist/Server/Services/CloudResourceService.js +23 -36
- package/build/dist/Server/Services/CloudResourceService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +155 -2
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DockerHostService.js +19 -32
- package/build/dist/Server/Services/DockerHostService.js.map +1 -1
- package/build/dist/Server/Services/DockerResourceService.js +34 -4
- package/build/dist/Server/Services/DockerResourceService.js.map +1 -1
- package/build/dist/Server/Services/DockerSwarmClusterService.js +27 -40
- package/build/dist/Server/Services/DockerSwarmClusterService.js.map +1 -1
- package/build/dist/Server/Services/DockerSwarmResourceService.js +28 -3
- package/build/dist/Server/Services/DockerSwarmResourceService.js.map +1 -1
- package/build/dist/Server/Services/HostService.js +58 -64
- package/build/dist/Server/Services/HostService.js.map +1 -1
- package/build/dist/Server/Services/IncidentStateTimelineService.js +19 -0
- package/build/dist/Server/Services/IncidentStateTimelineService.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/IoTDeviceService.js +1 -8
- package/build/dist/Server/Services/IoTDeviceService.js.map +1 -1
- package/build/dist/Server/Services/IoTFleetService.js +19 -32
- package/build/dist/Server/Services/IoTFleetService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesClusterService.js +17 -30
- package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesContainerService.js +29 -3
- package/build/dist/Server/Services/KubernetesContainerService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesResourceService.js +32 -4
- package/build/dist/Server/Services/KubernetesResourceService.js.map +1 -1
- package/build/dist/Server/Services/LabelService.js +127 -0
- package/build/dist/Server/Services/LabelService.js.map +1 -1
- package/build/dist/Server/Services/MetricTypeService.js +74 -0
- package/build/dist/Server/Services/MetricTypeService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +128 -9
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/MonitorStatusTimelineService.js +28 -0
- package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
- package/build/dist/Server/Services/MonitorTemplateService.js +60 -0
- package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
- package/build/dist/Server/Services/PodmanHostService.js +19 -32
- package/build/dist/Server/Services/PodmanHostService.js.map +1 -1
- package/build/dist/Server/Services/PodmanResourceService.js +34 -4
- package/build/dist/Server/Services/PodmanResourceService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +135 -21
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/ProxmoxClusterService.js +23 -36
- package/build/dist/Server/Services/ProxmoxClusterService.js.map +1 -1
- package/build/dist/Server/Services/ProxmoxResourceService.js +28 -3
- package/build/dist/Server/Services/ProxmoxResourceService.js.map +1 -1
- package/build/dist/Server/Services/RumApplicationService.js +19 -32
- package/build/dist/Server/Services/RumApplicationService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +20 -0
- package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/ServerlessFunctionService.js +24 -37
- package/build/dist/Server/Services/ServerlessFunctionService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js +347 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveService.js +33 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveService.js.map +1 -1
- package/build/dist/Server/Services/ServiceService.js +236 -61
- package/build/dist/Server/Services/ServiceService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js +603 -0
- package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/StatusPageMonitorRuleService.js +401 -0
- package/build/dist/Server/Services/StatusPageMonitorRuleService.js.map +1 -0
- package/build/dist/Server/Services/StatusPageService.js +69 -46
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js +17 -1
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberService.js +3 -0
- package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryEntityRelationshipService.js +1 -0
- package/build/dist/Server/Services/TelemetryEntityRelationshipService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryEntityService.js +1 -0
- package/build/dist/Server/Services/TelemetryEntityService.js.map +1 -1
- package/build/dist/Server/Types/Database/JSONColumnQuery.js +402 -0
- package/build/dist/Server/Types/Database/JSONColumnQuery.js.map +1 -0
- package/build/dist/Server/Types/Database/Permissions/PublicPermission.js +9 -2
- package/build/dist/Server/Types/Database/Permissions/PublicPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryHelper.js +17 -27
- package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +105 -29
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
- package/build/dist/Server/Utils/Database/TruncateColumnValue.js +32 -0
- package/build/dist/Server/Utils/Database/TruncateColumnValue.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +56 -32
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js +30 -3
- package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js +110 -98
- package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js +312 -0
- package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js.map +1 -0
- package/build/dist/Server/Utils/SingleFlight.js +76 -0
- package/build/dist/Server/Utils/SingleFlight.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js +29 -0
- package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +78 -19
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js +160 -0
- package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/Telemetry.js +279 -104
- package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
- package/build/dist/Types/CustomField/CustomFieldDefinition.js +2 -0
- package/build/dist/Types/CustomField/CustomFieldDefinition.js.map +1 -0
- 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/DashboardNetworkMapComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js +368 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
- package/build/dist/Types/Database/BigIntColumnTransformer.js +66 -0
- package/build/dist/Types/Database/BigIntColumnTransformer.js.map +1 -0
- package/build/dist/Types/Database/DatabaseProperty.js +25 -0
- package/build/dist/Types/Database/DatabaseProperty.js.map +1 -1
- package/build/dist/Types/Database/NumericColumnValue.js +97 -0
- package/build/dist/Types/Database/NumericColumnValue.js.map +1 -0
- package/build/dist/Types/Date.js +68 -0
- package/build/dist/Types/Date.js.map +1 -1
- package/build/dist/Types/Decimal.js +14 -3
- package/build/dist/Types/Decimal.js.map +1 -1
- package/build/dist/Types/Events/Recurring.js +63 -0
- package/build/dist/Types/Events/Recurring.js.map +1 -1
- package/build/dist/Types/Permission.js +42 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Port.js +15 -5
- package/build/dist/Types/Port.js.map +1 -1
- package/build/dist/Types/StatusPage/StatusPageReportPeriodType.js +22 -0
- package/build/dist/Types/StatusPage/StatusPageReportPeriodType.js.map +1 -0
- package/build/dist/UI/Components/LogsViewer/useLiveLogsRefresh.js +44 -0
- package/build/dist/UI/Components/LogsViewer/useLiveLogsRefresh.js.map +1 -0
- package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js +75 -0
- package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js.map +1 -0
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js +18 -2
- package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js.map +1 -1
- package/build/dist/UI/Utils/ModelAPI/ProjectUsersModelAPI.js +213 -0
- package/build/dist/UI/Utils/ModelAPI/ProjectUsersModelAPI.js.map +1 -0
- package/build/dist/UI/Utils/TeamMembersByUser.js +195 -0
- package/build/dist/UI/Utils/TeamMembersByUser.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardNetworkMapComponent.js +114 -0
- package/build/dist/Utils/Dashboard/Components/DashboardNetworkMapComponent.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/StatusPage/ReportPeriod.js +131 -0
- package/build/dist/Utils/StatusPage/ReportPeriod.js.map +1 -0
- package/build/dist/Utils/Telemetry/HostIpAddresses.js +82 -0
- package/build/dist/Utils/Telemetry/HostIpAddresses.js.map +1 -0
- package/jest.config.json +2 -0
- package/package.json +1 -1
- package/tsconfig.json +12 -1
|
@@ -5,6 +5,7 @@ import Model from "../../Models/DatabaseModels/KubernetesCluster";
|
|
|
5
5
|
import Label from "../../Models/DatabaseModels/Label";
|
|
6
6
|
import { OnCreate } from "../Types/Database/Hooks";
|
|
7
7
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
8
|
+
import ResourceHeartbeat from "../Utils/Telemetry/ResourceHeartbeat";
|
|
8
9
|
import ObjectID from "../../Types/ObjectID";
|
|
9
10
|
import QueryHelper from "../Types/Database/QueryHelper";
|
|
10
11
|
import OneUptimeDate from "../../Types/Date";
|
|
@@ -145,7 +146,6 @@ export class Service extends DatabaseService<Model> {
|
|
|
145
146
|
agentVersion?: string | undefined;
|
|
146
147
|
},
|
|
147
148
|
): Promise<void> {
|
|
148
|
-
const cacheKey: string = clusterId.toString();
|
|
149
149
|
const extrasFingerprint: string = crypto
|
|
150
150
|
.createHash("sha1")
|
|
151
151
|
.update(
|
|
@@ -155,52 +155,34 @@ export class Service extends DatabaseService<Model> {
|
|
|
155
155
|
)
|
|
156
156
|
.digest("hex");
|
|
157
157
|
|
|
158
|
-
let cached: string | null = null;
|
|
159
|
-
try {
|
|
160
|
-
cached = await GlobalCache.getString(LAST_SEEN_CACHE_NAMESPACE, cacheKey);
|
|
161
|
-
} catch {
|
|
162
|
-
/*
|
|
163
|
-
* Cache unavailable — fail open and refresh lastSeenAt anyway. A
|
|
164
|
-
* cache error must never skip the DB write below, otherwise the
|
|
165
|
-
* resource is wrongly marked "disconnected" while telemetry is
|
|
166
|
-
* still flowing. Mirrors shouldRunMaintenance's fail-open stance.
|
|
167
|
-
*/
|
|
168
|
-
cached = null;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
if (cached === extrasFingerprint) {
|
|
172
|
-
return; // same data was written recently
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
try {
|
|
176
|
-
await GlobalCache.setString(
|
|
177
|
-
LAST_SEEN_CACHE_NAMESPACE,
|
|
178
|
-
cacheKey,
|
|
179
|
-
extrasFingerprint,
|
|
180
|
-
{ expiresInSeconds: LAST_SEEN_THROTTLE_SECONDS },
|
|
181
|
-
);
|
|
182
|
-
} catch {
|
|
183
|
-
// Best-effort throttle write; proceed with the DB update regardless.
|
|
184
|
-
}
|
|
185
|
-
|
|
186
158
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
187
|
-
const
|
|
159
|
+
const liveness: any = {
|
|
188
160
|
lastSeenAt: OneUptimeDate.getCurrentDate(),
|
|
189
161
|
otelCollectorStatus: "connected",
|
|
190
162
|
};
|
|
191
163
|
|
|
164
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
165
|
+
const metadata: any = {};
|
|
166
|
+
|
|
192
167
|
if (extra?.agentVersion) {
|
|
193
|
-
|
|
168
|
+
metadata.agentVersion = extra.agentVersion;
|
|
194
169
|
}
|
|
195
170
|
|
|
196
171
|
/*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
172
|
+
* One gated, non-blocking heartbeat write. The gates, the fail-open /
|
|
173
|
+
* fail-closed split and the liveness-only fallback all live in
|
|
174
|
+
* ResourceHeartbeat — see there for why this row's throttle used to
|
|
175
|
+
* provide no throttling at all.
|
|
200
176
|
*/
|
|
201
|
-
await
|
|
177
|
+
await ResourceHeartbeat.write({
|
|
178
|
+
service: this,
|
|
202
179
|
id: clusterId,
|
|
203
|
-
|
|
180
|
+
cacheNamespace: LAST_SEEN_CACHE_NAMESPACE,
|
|
181
|
+
throttleInSeconds: LAST_SEEN_THROTTLE_SECONDS,
|
|
182
|
+
liveness: liveness,
|
|
183
|
+
metadata: metadata,
|
|
184
|
+
fingerprint: extrasFingerprint,
|
|
185
|
+
describe: `kubernetes cluster ${clusterId.toString()}`,
|
|
204
186
|
});
|
|
205
187
|
}
|
|
206
188
|
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import DatabaseService from "./DatabaseService";
|
|
2
2
|
import Model from "../../Models/DatabaseModels/KubernetesContainer";
|
|
3
3
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
4
|
+
import ColumnLength from "../../Types/Database/ColumnLength";
|
|
4
5
|
import ObjectID from "../../Types/ObjectID";
|
|
6
|
+
import {
|
|
7
|
+
truncateLongText,
|
|
8
|
+
truncateShortText,
|
|
9
|
+
} from "../Utils/Database/TruncateColumnValue";
|
|
5
10
|
import logger from "../Utils/Logger";
|
|
6
11
|
|
|
7
12
|
/*
|
|
@@ -61,6 +66,29 @@ const UPSERT_COLUMNS: Array<string> = [
|
|
|
61
66
|
"version",
|
|
62
67
|
];
|
|
63
68
|
|
|
69
|
+
/*
|
|
70
|
+
* KubernetesContainer's text columns are bounded varchars — podName and
|
|
71
|
+
* image at 500 chars, podNamespaceKey / name / state / reason at 100.
|
|
72
|
+
* The bulk paths below go through manager.query(), which skips the
|
|
73
|
+
* length validation DatabaseService applies to ordinary writes, so a
|
|
74
|
+
* single oversized value aborts the whole 500-row INSERT chunk it rides
|
|
75
|
+
* in. Clamp per value instead, so one pathological pod can never drop
|
|
76
|
+
* the rest of the snapshot.
|
|
77
|
+
*/
|
|
78
|
+
function sanitizeContainer(
|
|
79
|
+
c: ParsedKubernetesContainer,
|
|
80
|
+
): ParsedKubernetesContainer {
|
|
81
|
+
return {
|
|
82
|
+
...c,
|
|
83
|
+
podNamespaceKey: truncateShortText(c.podNamespaceKey),
|
|
84
|
+
podName: truncateLongText(c.podName),
|
|
85
|
+
name: truncateShortText(c.name),
|
|
86
|
+
image: truncateLongText(c.image),
|
|
87
|
+
state: truncateShortText(c.state),
|
|
88
|
+
reason: truncateShortText(c.reason),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
64
92
|
export class Service extends DatabaseService<Model> {
|
|
65
93
|
public constructor() {
|
|
66
94
|
super(Model);
|
|
@@ -86,12 +114,20 @@ export class Service extends DatabaseService<Model> {
|
|
|
86
114
|
return;
|
|
87
115
|
}
|
|
88
116
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
117
|
+
const containers: Array<ParsedKubernetesContainer> = data.containers.map(
|
|
118
|
+
(c: ParsedKubernetesContainer) => {
|
|
119
|
+
const sanitized: ParsedKubernetesContainer = sanitizeContainer(c);
|
|
120
|
+
if (sanitized.podName !== c.podName) {
|
|
121
|
+
logger.warn(
|
|
122
|
+
`KubernetesContainer podName exceeds ${ColumnLength.LongText} chars; truncated to "${sanitized.podName}" (cluster ${data.kubernetesClusterId.toString()}).`,
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
return sanitized;
|
|
126
|
+
},
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
for (let i: number = 0; i < containers.length; i += UPSERT_BATCH_SIZE) {
|
|
130
|
+
const chunk: Array<ParsedKubernetesContainer> = containers.slice(
|
|
95
131
|
i,
|
|
96
132
|
i + UPSERT_BATCH_SIZE,
|
|
97
133
|
);
|
|
@@ -224,10 +260,15 @@ export class Service extends DatabaseService<Model> {
|
|
|
224
260
|
valueFragments.push(
|
|
225
261
|
`($${paramIndex++}, $${paramIndex++}, $${paramIndex++}, $${paramIndex++}::numeric, $${paramIndex++}::bigint, $${paramIndex++}::timestamptz)`,
|
|
226
262
|
);
|
|
263
|
+
/*
|
|
264
|
+
* The identity clamps MUST match bulkUpsert's, or this mirror
|
|
265
|
+
* UPDATE would silently miss the row the upsert just wrote
|
|
266
|
+
* under the truncated podName.
|
|
267
|
+
*/
|
|
227
268
|
params.push(
|
|
228
|
-
m.podNamespaceKey,
|
|
229
|
-
m.podName,
|
|
230
|
-
m.name,
|
|
269
|
+
truncateShortText(m.podNamespaceKey),
|
|
270
|
+
truncateLongText(m.podName),
|
|
271
|
+
truncateShortText(m.name),
|
|
231
272
|
m.cpuPercent !== null && m.cpuPercent !== undefined
|
|
232
273
|
? m.cpuPercent
|
|
233
274
|
: null,
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import DatabaseService from "./DatabaseService";
|
|
2
2
|
import Model from "../../Models/DatabaseModels/KubernetesResource";
|
|
3
3
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
4
|
+
import ColumnLength from "../../Types/Database/ColumnLength";
|
|
4
5
|
import ObjectID from "../../Types/ObjectID";
|
|
5
6
|
import OneUptimeDate from "../../Types/Date";
|
|
6
7
|
import { ParsedKubernetesResource } from "../../Types/Kubernetes/KubernetesInventoryExtractor";
|
|
8
|
+
import {
|
|
9
|
+
truncateLongText,
|
|
10
|
+
truncateShortText,
|
|
11
|
+
} from "../Utils/Database/TruncateColumnValue";
|
|
7
12
|
import logger from "../Utils/Logger";
|
|
8
13
|
|
|
9
14
|
/*
|
|
@@ -317,6 +322,28 @@ const UPSERT_COLUMNS: Array<keyof ParsedKubernetesResource | string> = [
|
|
|
317
322
|
"version",
|
|
318
323
|
];
|
|
319
324
|
|
|
325
|
+
/*
|
|
326
|
+
* KubernetesResource's text columns are bounded varchars — name and
|
|
327
|
+
* controllerDeploymentName at 500 chars, kind / namespaceKey / uid /
|
|
328
|
+
* phase at 100. The bulk paths below go through manager.query(), which
|
|
329
|
+
* skips the length validation DatabaseService applies to ordinary
|
|
330
|
+
* writes, so a single oversized value aborts the whole 500-row INSERT
|
|
331
|
+
* chunk it rides in. Clamp per value instead, so one pathological
|
|
332
|
+
* object can never drop the rest of the snapshot.
|
|
333
|
+
*/
|
|
334
|
+
function sanitizeResource(
|
|
335
|
+
r: ParsedKubernetesResource,
|
|
336
|
+
): ParsedKubernetesResource {
|
|
337
|
+
return {
|
|
338
|
+
...r,
|
|
339
|
+
kind: truncateShortText(r.kind),
|
|
340
|
+
namespaceKey: truncateShortText(r.namespaceKey),
|
|
341
|
+
name: truncateLongText(r.name),
|
|
342
|
+
uid: truncateShortText(r.uid),
|
|
343
|
+
phase: truncateShortText(r.phase),
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
|
|
320
347
|
export class Service extends DatabaseService<Model> {
|
|
321
348
|
public constructor() {
|
|
322
349
|
super(Model);
|
|
@@ -338,9 +365,21 @@ export class Service extends DatabaseService<Model> {
|
|
|
338
365
|
return;
|
|
339
366
|
}
|
|
340
367
|
|
|
368
|
+
const resources: Array<ParsedKubernetesResource> = data.resources.map(
|
|
369
|
+
(r: ParsedKubernetesResource) => {
|
|
370
|
+
const sanitized: ParsedKubernetesResource = sanitizeResource(r);
|
|
371
|
+
if (sanitized.name !== r.name) {
|
|
372
|
+
logger.warn(
|
|
373
|
+
`KubernetesResource name exceeds ${ColumnLength.LongText} chars; truncated to "${sanitized.name}" (cluster ${data.kubernetesClusterId.toString()}).`,
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
return sanitized;
|
|
377
|
+
},
|
|
378
|
+
);
|
|
379
|
+
|
|
341
380
|
// Chunk to keep individual statement parameter counts reasonable.
|
|
342
|
-
for (let i: number = 0; i <
|
|
343
|
-
const chunk: Array<ParsedKubernetesResource> =
|
|
381
|
+
for (let i: number = 0; i < resources.length; i += UPSERT_BATCH_SIZE) {
|
|
382
|
+
const chunk: Array<ParsedKubernetesResource> = resources.slice(
|
|
344
383
|
i,
|
|
345
384
|
i + UPSERT_BATCH_SIZE,
|
|
346
385
|
);
|
|
@@ -450,10 +489,17 @@ export class Service extends DatabaseService<Model> {
|
|
|
450
489
|
valueFragments.push(
|
|
451
490
|
`($${paramIndex++}, $${paramIndex++}, $${paramIndex++}, $${paramIndex++}::numeric, $${paramIndex++}::bigint, $${paramIndex++}::numeric, $${paramIndex++}::timestamptz, $${paramIndex++}, $${paramIndex++})`,
|
|
452
491
|
);
|
|
492
|
+
/*
|
|
493
|
+
* The identity clamps MUST match bulkUpsert's, or this mirror
|
|
494
|
+
* UPDATE would silently miss the row the upsert just wrote
|
|
495
|
+
* under the truncated name. controllerDeploymentName /
|
|
496
|
+
* controllerCronJobName are assigned columns, so an oversized
|
|
497
|
+
* value there aborts the chunk exactly like the INSERT path.
|
|
498
|
+
*/
|
|
453
499
|
params.push(
|
|
454
|
-
m.kind,
|
|
455
|
-
m.namespaceKey,
|
|
456
|
-
m.name,
|
|
500
|
+
truncateShortText(m.kind),
|
|
501
|
+
truncateShortText(m.namespaceKey),
|
|
502
|
+
truncateLongText(m.name),
|
|
457
503
|
m.cpuPercent !== null && m.cpuPercent !== undefined
|
|
458
504
|
? m.cpuPercent
|
|
459
505
|
: null,
|
|
@@ -464,8 +510,8 @@ export class Service extends DatabaseService<Model> {
|
|
|
464
510
|
? m.memoryPercent
|
|
465
511
|
: null,
|
|
466
512
|
m.observedAt,
|
|
467
|
-
m.controllerDeploymentName ?? null,
|
|
468
|
-
m.controllerCronJobName ?? null,
|
|
513
|
+
truncateLongText(m.controllerDeploymentName ?? null),
|
|
514
|
+
truncateShortText(m.controllerCronJobName ?? null),
|
|
469
515
|
);
|
|
470
516
|
}
|
|
471
517
|
|
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
import CreateBy from "../Types/Database/CreateBy";
|
|
2
|
-
import
|
|
2
|
+
import DeleteBy from "../Types/Database/DeleteBy";
|
|
3
|
+
import { OnCreate, OnDelete } from "../Types/Database/Hooks";
|
|
3
4
|
import QueryHelper from "../Types/Database/QueryHelper";
|
|
4
5
|
import DatabaseService from "./DatabaseService";
|
|
6
|
+
import ServiceLevelObjectiveMonitorRuleEngineService from "./ServiceLevelObjectiveMonitorRuleEngineService";
|
|
7
|
+
import ServiceLevelObjectiveService from "./ServiceLevelObjectiveService";
|
|
8
|
+
import StatusPageMonitorRuleEngineService from "./StatusPageMonitorRuleEngineService";
|
|
9
|
+
import StatusPageMonitorRuleService from "./StatusPageMonitorRuleService";
|
|
10
|
+
import ServiceLevelObjective from "../../Models/DatabaseModels/ServiceLevelObjective";
|
|
11
|
+
import StatusPageMonitorRule from "../../Models/DatabaseModels/StatusPageMonitorRule";
|
|
5
12
|
import BadDataException from "../../Types/Exception/BadDataException";
|
|
13
|
+
import LIMIT_MAX from "../../Types/Database/LimitMax";
|
|
6
14
|
import ObjectID from "../../Types/ObjectID";
|
|
7
15
|
import Color from "../../Types/Color";
|
|
8
16
|
import { BrightColors } from "../../Types/BrandColors";
|
|
9
17
|
import GlobalCache from "../Infrastructure/GlobalCache";
|
|
10
18
|
import Model from "../../Models/DatabaseModels/Label";
|
|
11
19
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
20
|
+
import logger from "../Utils/Logger";
|
|
12
21
|
|
|
13
22
|
const AUTO_LABEL_ID_CACHE_NAMESPACE: string = "auto-label-id";
|
|
14
23
|
const AUTO_LABEL_ID_CACHE_TTL_SECONDS: number = 24 * 60 * 60;
|
|
@@ -57,6 +66,149 @@ export class Service extends DatabaseService<Model> {
|
|
|
57
66
|
return Promise.resolve({ createBy, carryForward: null });
|
|
58
67
|
}
|
|
59
68
|
|
|
69
|
+
/*
|
|
70
|
+
* Deleting a label cascades its join rows away at the database level, so no
|
|
71
|
+
* service hook ever fires for the SLO label rules or status page monitor
|
|
72
|
+
* rules that referenced it. Those would keep the monitors the rule attached,
|
|
73
|
+
* with nothing left to explain why. Note the ids down while the label still
|
|
74
|
+
* exists, and re-run the (now smaller) rules once it is gone.
|
|
75
|
+
*/
|
|
76
|
+
@CaptureSpan()
|
|
77
|
+
protected override async onBeforeDelete(
|
|
78
|
+
deleteBy: DeleteBy<Model>,
|
|
79
|
+
): Promise<OnDelete<Model>> {
|
|
80
|
+
let serviceLevelObjectiveIds: Array<ObjectID> = [];
|
|
81
|
+
let statusPageMonitorRuleIds: Array<ObjectID> = [];
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
const labels: Array<Model> = await this.findBy({
|
|
85
|
+
query: deleteBy.query,
|
|
86
|
+
select: {
|
|
87
|
+
_id: true,
|
|
88
|
+
},
|
|
89
|
+
limit: LIMIT_MAX,
|
|
90
|
+
skip: 0,
|
|
91
|
+
props: {
|
|
92
|
+
isRoot: true,
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const labelIds: Array<ObjectID> = labels
|
|
97
|
+
.map((label: Model) => {
|
|
98
|
+
return label.id;
|
|
99
|
+
})
|
|
100
|
+
.filter((id: ObjectID | null): id is ObjectID => {
|
|
101
|
+
return Boolean(id);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
if (labelIds.length > 0) {
|
|
105
|
+
const slos: Array<ServiceLevelObjective> =
|
|
106
|
+
await ServiceLevelObjectiveService.findBy({
|
|
107
|
+
query: {
|
|
108
|
+
monitorLabels: labelIds,
|
|
109
|
+
},
|
|
110
|
+
select: {
|
|
111
|
+
_id: true,
|
|
112
|
+
},
|
|
113
|
+
limit: LIMIT_MAX,
|
|
114
|
+
skip: 0,
|
|
115
|
+
props: {
|
|
116
|
+
isRoot: true,
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
serviceLevelObjectiveIds = slos
|
|
121
|
+
.map((slo: ServiceLevelObjective) => {
|
|
122
|
+
return slo.id;
|
|
123
|
+
})
|
|
124
|
+
.filter((id: ObjectID | null): id is ObjectID => {
|
|
125
|
+
return Boolean(id);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
const statusPageMonitorRules: Array<StatusPageMonitorRule> =
|
|
129
|
+
await StatusPageMonitorRuleService.findBy({
|
|
130
|
+
query: {
|
|
131
|
+
monitorLabels: labelIds,
|
|
132
|
+
},
|
|
133
|
+
select: {
|
|
134
|
+
_id: true,
|
|
135
|
+
},
|
|
136
|
+
limit: LIMIT_MAX,
|
|
137
|
+
skip: 0,
|
|
138
|
+
props: {
|
|
139
|
+
isRoot: true,
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
statusPageMonitorRuleIds = statusPageMonitorRules
|
|
144
|
+
.map((rule: StatusPageMonitorRule) => {
|
|
145
|
+
return rule.id;
|
|
146
|
+
})
|
|
147
|
+
.filter((id: ObjectID | null): id is ObjectID => {
|
|
148
|
+
return Boolean(id);
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
} catch (err) {
|
|
152
|
+
logger.error(
|
|
153
|
+
`Error collecting label rules affected by a label delete: ${err}`,
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return {
|
|
158
|
+
deleteBy,
|
|
159
|
+
carryForward: {
|
|
160
|
+
serviceLevelObjectiveIds: serviceLevelObjectiveIds,
|
|
161
|
+
statusPageMonitorRuleIds: statusPageMonitorRuleIds,
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
@CaptureSpan()
|
|
167
|
+
protected override async onDeleteSuccess(
|
|
168
|
+
onDelete: OnDelete<Model>,
|
|
169
|
+
_itemIdsBeforeDelete: Array<ObjectID>,
|
|
170
|
+
): Promise<OnDelete<Model>> {
|
|
171
|
+
const carryForward: {
|
|
172
|
+
serviceLevelObjectiveIds?: Array<ObjectID>;
|
|
173
|
+
statusPageMonitorRuleIds?: Array<ObjectID>;
|
|
174
|
+
} | null = onDelete.carryForward as {
|
|
175
|
+
serviceLevelObjectiveIds?: Array<ObjectID>;
|
|
176
|
+
statusPageMonitorRuleIds?: Array<ObjectID>;
|
|
177
|
+
} | null;
|
|
178
|
+
|
|
179
|
+
const serviceLevelObjectiveIds: Array<ObjectID> =
|
|
180
|
+
carryForward?.serviceLevelObjectiveIds || [];
|
|
181
|
+
|
|
182
|
+
for (const serviceLevelObjectiveId of serviceLevelObjectiveIds) {
|
|
183
|
+
try {
|
|
184
|
+
await ServiceLevelObjectiveMonitorRuleEngineService.syncMonitorsForSlo({
|
|
185
|
+
serviceLevelObjectiveId: serviceLevelObjectiveId,
|
|
186
|
+
});
|
|
187
|
+
} catch (err) {
|
|
188
|
+
logger.error(
|
|
189
|
+
`Error re-applying the monitor label rule for SLO ${serviceLevelObjectiveId.toString()} after a label delete: ${err}`,
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const statusPageMonitorRuleIds: Array<ObjectID> =
|
|
195
|
+
carryForward?.statusPageMonitorRuleIds || [];
|
|
196
|
+
|
|
197
|
+
for (const statusPageMonitorRuleId of statusPageMonitorRuleIds) {
|
|
198
|
+
try {
|
|
199
|
+
await StatusPageMonitorRuleEngineService.syncResourcesForRule({
|
|
200
|
+
statusPageMonitorRuleId: statusPageMonitorRuleId,
|
|
201
|
+
});
|
|
202
|
+
} catch (err) {
|
|
203
|
+
logger.error(
|
|
204
|
+
`Error re-applying status page monitor rule ${statusPageMonitorRuleId.toString()} after a label delete: ${err}`,
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return onDelete;
|
|
210
|
+
}
|
|
211
|
+
|
|
60
212
|
/**
|
|
61
213
|
* Find existing labels by name (case-insensitive) or auto-create
|
|
62
214
|
* them, returning the ObjectIDs in the same order as the input.
|
|
@@ -1,10 +1,94 @@
|
|
|
1
1
|
import DatabaseService from "./DatabaseService";
|
|
2
2
|
import Model from "../../Models/DatabaseModels/MetricType";
|
|
3
|
+
import ObjectID from "../../Types/ObjectID";
|
|
4
|
+
import BadDataException from "../../Types/Exception/BadDataException";
|
|
5
|
+
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
6
|
+
import { RelationMetadata } from "typeorm/metadata/RelationMetadata";
|
|
3
7
|
|
|
4
8
|
export class Service extends DatabaseService<Model> {
|
|
5
9
|
public constructor() {
|
|
6
10
|
super(Model);
|
|
7
11
|
}
|
|
12
|
+
|
|
13
|
+
/*
|
|
14
|
+
* Additively associate services with a metric type, in ONE statement.
|
|
15
|
+
*
|
|
16
|
+
* This replaces routing the association through `updateOneById` with the
|
|
17
|
+
* whole `services` array in the payload. That looked innocuous and was not:
|
|
18
|
+
* `services` is a `TableColumnType.EntityArray`, and its mere PRESENCE as a
|
|
19
|
+
* key flips `hasRelationUpdates` in DatabaseService, which routes the write
|
|
20
|
+
* to `getRepository().save()` — a real BEGIN/COMMIT that reloads the entity,
|
|
21
|
+
* loads the relation ids, bumps `version`, and DELETEs then re-INSERTs
|
|
22
|
+
* junction rows, holding the MetricType row's write lock across every one of
|
|
23
|
+
* those round trips. On the ingest path, where this runs per metric name per
|
|
24
|
+
* batch with no backpressure, it was the only multi-round-trip lock hold in
|
|
25
|
+
* the pipeline.
|
|
26
|
+
*
|
|
27
|
+
* The whole-array write was also silently LOSING data. `save()` diffs the
|
|
28
|
+
* array it is given against what is currently in the database and deletes
|
|
29
|
+
* anything missing — but each ingest worker only knows the services in ITS
|
|
30
|
+
* batch. Two workers with different batches therefore deleted each other's
|
|
31
|
+
* associations and re-inserted them on the next batch: permanent junction
|
|
32
|
+
* churn, and real service-to-metric links disappearing from the UI in
|
|
33
|
+
* between. Additive insert makes that impossible to express.
|
|
34
|
+
*
|
|
35
|
+
* ON CONFLICT DO NOTHING is well-defined here: the junction's primary key is
|
|
36
|
+
* exactly (metricTypeId, serviceId), so a concurrent writer adding the same
|
|
37
|
+
* association is a no-op rather than a unique violation.
|
|
38
|
+
*/
|
|
39
|
+
@CaptureSpan()
|
|
40
|
+
public async attachServices(data: {
|
|
41
|
+
metricTypeId: ObjectID;
|
|
42
|
+
serviceIds: Array<ObjectID>;
|
|
43
|
+
}): Promise<void> {
|
|
44
|
+
if (!data.metricTypeId) {
|
|
45
|
+
throw new BadDataException("metricTypeId is required");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!data.serviceIds || data.serviceIds.length === 0) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/*
|
|
53
|
+
* Identifiers come from entity metadata, never from the caller, and every
|
|
54
|
+
* value is bound as a parameter — the same rule the other raw-SQL paths in
|
|
55
|
+
* DatabaseService follow.
|
|
56
|
+
*/
|
|
57
|
+
const relation: RelationMetadata | undefined =
|
|
58
|
+
this.getRepository().metadata.findRelationWithPropertyPath("services");
|
|
59
|
+
|
|
60
|
+
const junction: string | undefined =
|
|
61
|
+
relation?.junctionEntityMetadata?.tableName;
|
|
62
|
+
const metricTypeColumn: string | undefined =
|
|
63
|
+
relation?.junctionEntityMetadata?.columns[0]?.databaseName;
|
|
64
|
+
const serviceColumn: string | undefined =
|
|
65
|
+
relation?.junctionEntityMetadata?.columns[1]?.databaseName;
|
|
66
|
+
|
|
67
|
+
if (!junction || !metricTypeColumn || !serviceColumn) {
|
|
68
|
+
throw new BadDataException(
|
|
69
|
+
"MetricTypeService.attachServices: the services relation has no junction metadata",
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/*
|
|
74
|
+
* Deduplicate and SORT. Concurrent statements that insert overlapping sets
|
|
75
|
+
* acquire their row locks in the same order this way, which is what keeps
|
|
76
|
+
* two workers associating the same services from deadlocking each other.
|
|
77
|
+
*/
|
|
78
|
+
const serviceIds: Array<string> = Array.from(
|
|
79
|
+
new Set(
|
|
80
|
+
data.serviceIds.map((id: ObjectID) => {
|
|
81
|
+
return id.toString();
|
|
82
|
+
}),
|
|
83
|
+
),
|
|
84
|
+
).sort();
|
|
85
|
+
|
|
86
|
+
await this.getRepository().manager.query(
|
|
87
|
+
`INSERT INTO "${junction}" ("${metricTypeColumn}", "${serviceColumn}") ` +
|
|
88
|
+
`SELECT $1, unnest($2::uuid[]) ON CONFLICT DO NOTHING`,
|
|
89
|
+
[data.metricTypeId.toString(), serviceIds],
|
|
90
|
+
);
|
|
91
|
+
}
|
|
8
92
|
}
|
|
9
93
|
|
|
10
94
|
export default new Service();
|