@oneuptime/common 11.0.1 → 11.0.2
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/Alert.ts +110 -0
- package/Models/DatabaseModels/CephCluster.ts +964 -0
- package/Models/DatabaseModels/CephClusterLabelRule.ts +514 -0
- package/Models/DatabaseModels/CephClusterOwnerRule.ts +596 -0
- package/Models/DatabaseModels/CephClusterOwnerTeam.ts +487 -0
- package/Models/DatabaseModels/CephClusterOwnerUser.ts +486 -0
- package/Models/DatabaseModels/CephResource.ts +809 -0
- package/Models/DatabaseModels/Host.ts +64 -0
- package/Models/DatabaseModels/Incident.ts +110 -0
- package/Models/DatabaseModels/Index.ts +24 -0
- package/Models/DatabaseModels/ProxmoxCluster.ts +943 -0
- package/Models/DatabaseModels/ProxmoxClusterLabelRule.ts +514 -0
- package/Models/DatabaseModels/ProxmoxClusterOwnerRule.ts +596 -0
- package/Models/DatabaseModels/ProxmoxClusterOwnerTeam.ts +487 -0
- package/Models/DatabaseModels/ProxmoxClusterOwnerUser.ts +486 -0
- package/Models/DatabaseModels/ProxmoxResource.ts +726 -0
- package/Models/DatabaseModels/ScheduledMaintenance.ts +110 -0
- package/Server/API/BillingInvoiceAPI.ts +47 -7
- package/Server/API/CephResourceAPI.ts +134 -0
- package/Server/API/DashboardAPI.ts +46 -0
- package/Server/API/ProjectAPI.ts +15 -0
- package/Server/API/ProxmoxResourceAPI.ts +132 -0
- package/Server/API/ResellerPlanAPI.ts +17 -0
- package/Server/Infrastructure/GlobalCache.ts +8 -2
- package/Server/Infrastructure/Postgres/SchemaMigrations/1781500000000-AddProxmoxAndCephClusterTables.ts +163 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1781600000000-AddProxmoxCephV2Columns.ts +211 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1781600000001-AddProxmoxCephActivityAndRules.ts +590 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1781700000000-AddProxmoxCephV3Columns.ts +64 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
- package/Server/Infrastructure/Redis.ts +40 -12
- package/Server/Services/AnalyticsDatabaseService.ts +1 -1
- package/Server/Services/BillingService.ts +109 -21
- package/Server/Services/CephClusterLabelRuleEngineService.ts +200 -0
- package/Server/Services/CephClusterLabelRuleService.ts +14 -0
- package/Server/Services/CephClusterOwnerRuleEngineService.ts +218 -0
- package/Server/Services/CephClusterOwnerRuleService.ts +14 -0
- package/Server/Services/CephClusterOwnerTeamService.ts +10 -0
- package/Server/Services/CephClusterOwnerUserService.ts +10 -0
- package/Server/Services/CephClusterService.ts +401 -0
- package/Server/Services/CephResourceService.ts +383 -0
- package/Server/Services/CloudResourceService.ts +11 -3
- package/Server/Services/DockerHostService.ts +11 -3
- package/Server/Services/ExceptionAggregationService.ts +2 -0
- package/Server/Services/HostService.ts +11 -3
- package/Server/Services/Index.ts +24 -0
- package/Server/Services/KubernetesClusterService.ts +11 -3
- package/Server/Services/LogAggregationService.ts +2 -0
- package/Server/Services/MetricAggregationService.ts +2 -0
- package/Server/Services/OpenTelemetryIngestService.ts +36 -0
- package/Server/Services/ProxmoxClusterLabelRuleEngineService.ts +204 -0
- package/Server/Services/ProxmoxClusterLabelRuleService.ts +14 -0
- package/Server/Services/ProxmoxClusterOwnerRuleEngineService.ts +222 -0
- package/Server/Services/ProxmoxClusterOwnerRuleService.ts +14 -0
- package/Server/Services/ProxmoxClusterOwnerTeamService.ts +10 -0
- package/Server/Services/ProxmoxClusterOwnerUserService.ts +10 -0
- package/Server/Services/ProxmoxClusterService.ts +382 -0
- package/Server/Services/ProxmoxResourceService.ts +404 -0
- package/Server/Services/RumApplicationService.ts +11 -3
- package/Server/Services/ServerlessFunctionService.ts +11 -3
- package/Server/Services/TelemetryUsageBillingService.ts +41 -3
- package/Server/Services/TraceAggregationService.ts +2 -0
- package/Server/Types/AnalyticsDatabase/AggregateBy.ts +8 -23
- package/Server/Utils/Monitor/MonitorAlert.ts +45 -0
- package/Server/Utils/Monitor/MonitorClusterContext.ts +129 -0
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +344 -4
- package/Server/Utils/Monitor/MonitorIncident.ts +130 -7
- package/Server/Utils/Monitor/MonitorMaintenanceSuppression.ts +39 -6
- package/Server/Utils/Monitor/MonitorTemplateUtil.ts +3 -1
- package/Server/Utils/Monitor/SeriesResourceLabels.ts +33 -0
- package/Server/Utils/Profiling.ts +37 -2
- package/Server/Utils/Telemetry/EntityRegistry.ts +4 -0
- package/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.ts +1096 -0
- package/Server/Utils/Telemetry/TelemetryEntity.ts +85 -0
- package/Server/Utils/Telemetry.ts +8 -19
- package/Tests/Server/API/BillingInvoiceAPI.test.ts +194 -0
- package/Tests/Server/API/ProjectAPI.test.ts +91 -0
- package/Tests/Server/API/ResellerPlanAPI.test.ts +207 -0
- package/Tests/Server/Infrastructure/GlobalCache.test.ts +100 -0
- package/Tests/Server/Services/BillingService.test.ts +323 -0
- package/Tests/Server/Services/CephResourceService.test.ts +264 -0
- package/Tests/Server/Services/ProxmoxResourceService.test.ts +326 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +322 -0
- package/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.ts +13 -0
- package/Tests/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.test.ts +879 -0
- package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +196 -0
- package/Tests/Types/Monitor/CephAlertTemplates.test.ts +1231 -0
- package/Tests/Types/Monitor/ProxmoxAlertTemplates.test.ts +732 -0
- package/Tests/Utils/Telemetry/EntityRelationship.test.ts +49 -0
- package/Tests/Utils/Telemetry/HeartbeatAvailability.test.ts +423 -0
- package/Types/BaseDatabase/AggregationIntervalUtil.ts +74 -0
- package/Types/Dashboard/DashboardComponentType.ts +4 -0
- package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +2 -0
- package/Types/Dashboard/DashboardComponents/DashboardCephOsdListComponent.ts +15 -0
- package/Types/Dashboard/DashboardComponents/DashboardCephPoolListComponent.ts +14 -0
- package/Types/Dashboard/DashboardComponents/DashboardProxmoxGuestListComponent.ts +17 -0
- package/Types/Dashboard/DashboardComponents/DashboardProxmoxNodeListComponent.ts +16 -0
- package/Types/Dashboard/DashboardTemplates.ts +446 -0
- package/Types/Icon/IconProp.ts +2 -0
- package/Types/Monitor/CephAlertTemplates.ts +1647 -0
- package/Types/Monitor/CephMetricCatalog.ts +409 -0
- package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +44 -0
- package/Types/Monitor/MonitorStep.ts +64 -0
- package/Types/Monitor/MonitorStepCephMonitor.ts +57 -0
- package/Types/Monitor/MonitorStepProxmoxMonitor.ts +81 -0
- package/Types/Monitor/MonitorType.ts +29 -1
- package/Types/Monitor/ProxmoxAlertTemplates.ts +899 -0
- package/Types/Monitor/ProxmoxMetricCatalog.ts +382 -0
- package/Types/Permission.ts +464 -0
- package/Types/Telemetry/EntityType.ts +11 -0
- package/Types/Telemetry/ServiceType.ts +2 -0
- package/UI/Components/Icon/Icon.tsx +84 -0
- package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +9 -5
- package/UI/Utils/Telemetry/Telemetry.ts +16 -21
- package/UI/Utils/TelemetryService.ts +7 -3
- package/Utils/Dashboard/Components/DashboardCephOsdListComponent.ts +63 -0
- package/Utils/Dashboard/Components/DashboardCephPoolListComponent.ts +32 -0
- package/Utils/Dashboard/Components/DashboardCephResourceListShared.ts +61 -0
- package/Utils/Dashboard/Components/DashboardProxmoxGuestListComponent.ts +69 -0
- package/Utils/Dashboard/Components/DashboardProxmoxNodeListComponent.ts +55 -0
- package/Utils/Dashboard/Components/DashboardProxmoxResourceListShared.ts +61 -0
- package/Utils/Dashboard/Components/Index.ts +28 -0
- package/Utils/Telemetry/EntityKey.ts +35 -0
- package/Utils/Telemetry/EntityRelationship.ts +6 -0
- package/Utils/Telemetry/HeartbeatAvailability.ts +262 -0
- package/build/dist/Models/DatabaseModels/Alert.js +108 -0
- package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
- package/build/dist/Models/DatabaseModels/CephCluster.js +992 -0
- package/build/dist/Models/DatabaseModels/CephCluster.js.map +1 -0
- package/build/dist/Models/DatabaseModels/CephClusterLabelRule.js +522 -0
- package/build/dist/Models/DatabaseModels/CephClusterLabelRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/CephClusterOwnerRule.js +603 -0
- package/build/dist/Models/DatabaseModels/CephClusterOwnerRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/CephClusterOwnerTeam.js +503 -0
- package/build/dist/Models/DatabaseModels/CephClusterOwnerTeam.js.map +1 -0
- package/build/dist/Models/DatabaseModels/CephClusterOwnerUser.js +502 -0
- package/build/dist/Models/DatabaseModels/CephClusterOwnerUser.js.map +1 -0
- package/build/dist/Models/DatabaseModels/CephResource.js +846 -0
- package/build/dist/Models/DatabaseModels/CephResource.js.map +1 -0
- package/build/dist/Models/DatabaseModels/Host.js +63 -0
- package/build/dist/Models/DatabaseModels/Host.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Incident.js +108 -0
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +24 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ProxmoxCluster.js +967 -0
- package/build/dist/Models/DatabaseModels/ProxmoxCluster.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ProxmoxClusterLabelRule.js +522 -0
- package/build/dist/Models/DatabaseModels/ProxmoxClusterLabelRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerRule.js +603 -0
- package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerTeam.js +503 -0
- package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerTeam.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerUser.js +502 -0
- package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerUser.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ProxmoxResource.js +761 -0
- package/build/dist/Models/DatabaseModels/ProxmoxResource.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +108 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
- package/build/dist/Server/API/BillingInvoiceAPI.js +35 -5
- package/build/dist/Server/API/BillingInvoiceAPI.js.map +1 -1
- package/build/dist/Server/API/CephResourceAPI.js +98 -0
- package/build/dist/Server/API/CephResourceAPI.js.map +1 -0
- package/build/dist/Server/API/DashboardAPI.js +46 -0
- package/build/dist/Server/API/DashboardAPI.js.map +1 -1
- package/build/dist/Server/API/ProjectAPI.js +11 -0
- package/build/dist/Server/API/ProjectAPI.js.map +1 -1
- package/build/dist/Server/API/ProxmoxResourceAPI.js +95 -0
- package/build/dist/Server/API/ProxmoxResourceAPI.js.map +1 -0
- package/build/dist/Server/API/ResellerPlanAPI.js +17 -3
- package/build/dist/Server/API/ResellerPlanAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/GlobalCache.js +7 -2
- package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781500000000-AddProxmoxAndCephClusterTables.js +76 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781500000000-AddProxmoxAndCephClusterTables.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781600000000-AddProxmoxCephV2Columns.js +108 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781600000000-AddProxmoxCephV2Columns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781600000001-AddProxmoxCephActivityAndRules.js +253 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781600000001-AddProxmoxCephActivityAndRules.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781700000000-AddProxmoxCephV3Columns.js +43 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781700000000-AddProxmoxCephV3Columns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/Redis.js +31 -8
- package/build/dist/Server/Infrastructure/Redis.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/BillingService.js +85 -23
- package/build/dist/Server/Services/BillingService.js.map +1 -1
- package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js +166 -0
- package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/CephClusterLabelRuleService.js +13 -0
- package/build/dist/Server/Services/CephClusterLabelRuleService.js.map +1 -0
- package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js +186 -0
- package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/CephClusterOwnerRuleService.js +13 -0
- package/build/dist/Server/Services/CephClusterOwnerRuleService.js.map +1 -0
- package/build/dist/Server/Services/CephClusterOwnerTeamService.js +9 -0
- package/build/dist/Server/Services/CephClusterOwnerTeamService.js.map +1 -0
- package/build/dist/Server/Services/CephClusterOwnerUserService.js +9 -0
- package/build/dist/Server/Services/CephClusterOwnerUserService.js.map +1 -0
- package/build/dist/Server/Services/CephClusterService.js +353 -0
- package/build/dist/Server/Services/CephClusterService.js.map +1 -0
- package/build/dist/Server/Services/CephResourceService.js +257 -0
- package/build/dist/Server/Services/CephResourceService.js.map +1 -0
- package/build/dist/Server/Services/CloudResourceService.js +10 -2
- package/build/dist/Server/Services/CloudResourceService.js.map +1 -1
- package/build/dist/Server/Services/DockerHostService.js +10 -2
- package/build/dist/Server/Services/DockerHostService.js.map +1 -1
- package/build/dist/Server/Services/ExceptionAggregationService.js +2 -0
- package/build/dist/Server/Services/ExceptionAggregationService.js.map +1 -1
- package/build/dist/Server/Services/HostService.js +10 -2
- package/build/dist/Server/Services/HostService.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/KubernetesClusterService.js +10 -2
- package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
- package/build/dist/Server/Services/LogAggregationService.js +2 -0
- package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
- package/build/dist/Server/Services/MetricAggregationService.js +2 -0
- package/build/dist/Server/Services/MetricAggregationService.js.map +1 -1
- package/build/dist/Server/Services/OpenTelemetryIngestService.js +37 -7
- package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
- package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js +166 -0
- package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/ProxmoxClusterLabelRuleService.js +13 -0
- package/build/dist/Server/Services/ProxmoxClusterLabelRuleService.js.map +1 -0
- package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js +186 -0
- package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/ProxmoxClusterOwnerRuleService.js +13 -0
- package/build/dist/Server/Services/ProxmoxClusterOwnerRuleService.js.map +1 -0
- package/build/dist/Server/Services/ProxmoxClusterOwnerTeamService.js +9 -0
- package/build/dist/Server/Services/ProxmoxClusterOwnerTeamService.js.map +1 -0
- package/build/dist/Server/Services/ProxmoxClusterOwnerUserService.js +9 -0
- package/build/dist/Server/Services/ProxmoxClusterOwnerUserService.js.map +1 -0
- package/build/dist/Server/Services/ProxmoxClusterService.js +337 -0
- package/build/dist/Server/Services/ProxmoxClusterService.js.map +1 -0
- package/build/dist/Server/Services/ProxmoxResourceService.js +285 -0
- package/build/dist/Server/Services/ProxmoxResourceService.js.map +1 -0
- package/build/dist/Server/Services/RumApplicationService.js +10 -2
- package/build/dist/Server/Services/RumApplicationService.js.map +1 -1
- package/build/dist/Server/Services/ServerlessFunctionService.js +10 -2
- package/build/dist/Server/Services/ServerlessFunctionService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryUsageBillingService.js +30 -3
- package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
- package/build/dist/Server/Services/TraceAggregationService.js +2 -0
- package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
- package/build/dist/Server/Types/AnalyticsDatabase/AggregateBy.js +8 -25
- package/build/dist/Server/Types/AnalyticsDatabase/AggregateBy.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +36 -0
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorClusterContext.js +90 -0
- package/build/dist/Server/Utils/Monitor/MonitorClusterContext.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +228 -4
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +103 -8
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js +23 -6
- package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +3 -1
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +23 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
- package/build/dist/Server/Utils/Profiling.js +24 -3
- package/build/dist/Server/Utils/Profiling.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +4 -0
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js +854 -0
- package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +62 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry.js +8 -10
- package/build/dist/Server/Utils/Telemetry.js.map +1 -1
- package/build/dist/Types/BaseDatabase/AggregationIntervalUtil.js +69 -0
- package/build/dist/Types/BaseDatabase/AggregationIntervalUtil.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponentType.js +4 -0
- package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardCephOsdListComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardCephOsdListComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardCephPoolListComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardCephPoolListComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardProxmoxGuestListComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardProxmoxGuestListComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardProxmoxNodeListComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardProxmoxNodeListComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js +394 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
- package/build/dist/Types/Icon/IconProp.js +2 -0
- package/build/dist/Types/Icon/IconProp.js.map +1 -1
- package/build/dist/Types/Monitor/CephAlertTemplates.js +1379 -0
- package/build/dist/Types/Monitor/CephAlertTemplates.js.map +1 -0
- package/build/dist/Types/Monitor/CephMetricCatalog.js +353 -0
- package/build/dist/Types/Monitor/CephMetricCatalog.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorStep.js +46 -0
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepCephMonitor.js +34 -0
- package/build/dist/Types/Monitor/MonitorStepCephMonitor.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorStepProxmoxMonitor.js +36 -0
- package/build/dist/Types/Monitor/MonitorStepProxmoxMonitor.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorType.js +27 -1
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +743 -0
- package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js.map +1 -0
- package/build/dist/Types/Monitor/ProxmoxMetricCatalog.js +320 -0
- package/build/dist/Types/Monitor/ProxmoxMetricCatalog.js.map +1 -0
- package/build/dist/Types/Permission.js +408 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Telemetry/EntityType.js +11 -0
- package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
- package/build/dist/Types/Telemetry/ServiceType.js +2 -0
- package/build/dist/Types/Telemetry/ServiceType.js.map +1 -1
- package/build/dist/UI/Components/Icon/Icon.js +33 -0
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +5 -1
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
- package/build/dist/UI/Utils/Telemetry/Telemetry.js +11 -10
- package/build/dist/UI/Utils/Telemetry/Telemetry.js.map +1 -1
- package/build/dist/UI/Utils/TelemetryService.js +5 -2
- package/build/dist/UI/Utils/TelemetryService.js.map +1 -1
- package/build/dist/Utils/Dashboard/Components/DashboardCephOsdListComponent.js +50 -0
- package/build/dist/Utils/Dashboard/Components/DashboardCephOsdListComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardCephPoolListComponent.js +27 -0
- package/build/dist/Utils/Dashboard/Components/DashboardCephPoolListComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardCephResourceListShared.js +46 -0
- package/build/dist/Utils/Dashboard/Components/DashboardCephResourceListShared.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardProxmoxGuestListComponent.js +55 -0
- package/build/dist/Utils/Dashboard/Components/DashboardProxmoxGuestListComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardProxmoxNodeListComponent.js +42 -0
- package/build/dist/Utils/Dashboard/Components/DashboardProxmoxNodeListComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardProxmoxResourceListShared.js +46 -0
- package/build/dist/Utils/Dashboard/Components/DashboardProxmoxResourceListShared.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/Index.js +16 -0
- package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
- package/build/dist/Utils/Telemetry/EntityKey.js +27 -0
- package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -1
- package/build/dist/Utils/Telemetry/EntityRelationship.js +3 -0
- package/build/dist/Utils/Telemetry/EntityRelationship.js.map +1 -1
- package/build/dist/Utils/Telemetry/HeartbeatAvailability.js +174 -0
- package/build/dist/Utils/Telemetry/HeartbeatAvailability.js.map +1 -0
- package/package.json +29 -21
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import Label from "../../Models/DatabaseModels/Label";
|
|
2
|
+
import CephCluster from "../../Models/DatabaseModels/CephCluster";
|
|
3
|
+
import CephClusterOwnerRule from "../../Models/DatabaseModels/CephClusterOwnerRule";
|
|
4
|
+
import CephClusterOwnerUser from "../../Models/DatabaseModels/CephClusterOwnerUser";
|
|
5
|
+
import CephClusterOwnerTeam from "../../Models/DatabaseModels/CephClusterOwnerTeam";
|
|
6
|
+
import CephClusterOwnerRuleService from "./CephClusterOwnerRuleService";
|
|
7
|
+
import CephClusterOwnerUserService from "./CephClusterOwnerUserService";
|
|
8
|
+
import CephClusterOwnerTeamService from "./CephClusterOwnerTeamService";
|
|
9
|
+
import CephClusterService from "./CephClusterService";
|
|
10
|
+
import ObjectID from "../../Types/ObjectID";
|
|
11
|
+
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
12
|
+
import logger, { LogAttributes } from "../Utils/Logger";
|
|
13
|
+
|
|
14
|
+
class CephClusterOwnerRuleEngineServiceClass {
|
|
15
|
+
/**
|
|
16
|
+
* Evaluates CephClusterOwnerRule rows for the given Ceph cluster and adds matched
|
|
17
|
+
* owner users / teams via CephClusterOwnerUserService / CephClusterOwnerTeamService. Rules
|
|
18
|
+
* with notifyOwners set notify the added owners; rules with notifyOwners off
|
|
19
|
+
* add silently.
|
|
20
|
+
*/
|
|
21
|
+
@CaptureSpan()
|
|
22
|
+
public async applyRulesToCephCluster(
|
|
23
|
+
cephCluster: CephCluster,
|
|
24
|
+
): Promise<void> {
|
|
25
|
+
if (!cephCluster.id || !cephCluster.projectId) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const rules: Array<CephClusterOwnerRule> =
|
|
31
|
+
await CephClusterOwnerRuleService.findBy({
|
|
32
|
+
query: {
|
|
33
|
+
projectId: cephCluster.projectId,
|
|
34
|
+
isEnabled: true,
|
|
35
|
+
},
|
|
36
|
+
props: { isRoot: true },
|
|
37
|
+
select: {
|
|
38
|
+
_id: true,
|
|
39
|
+
name: true,
|
|
40
|
+
notifyOwners: true,
|
|
41
|
+
cephClusterLabels: { _id: true },
|
|
42
|
+
cephClusterNamePattern: true,
|
|
43
|
+
cephClusterDescriptionPattern: true,
|
|
44
|
+
ownerUsers: { _id: true },
|
|
45
|
+
ownerTeams: { _id: true },
|
|
46
|
+
},
|
|
47
|
+
limit: 100,
|
|
48
|
+
skip: 0,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
if (rules.length === 0) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const cephClusterWithDetails: CephCluster | null =
|
|
56
|
+
await CephClusterService.findOneById({
|
|
57
|
+
id: cephCluster.id,
|
|
58
|
+
select: {
|
|
59
|
+
name: true,
|
|
60
|
+
description: true,
|
|
61
|
+
labels: { _id: true },
|
|
62
|
+
},
|
|
63
|
+
props: { isRoot: true },
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
if (!cephClusterWithDetails) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const usersByNotify: Map<boolean, Set<string>> = new Map([
|
|
71
|
+
[true, new Set()],
|
|
72
|
+
[false, new Set()],
|
|
73
|
+
]);
|
|
74
|
+
const teamsByNotify: Map<boolean, Set<string>> = new Map([
|
|
75
|
+
[true, new Set()],
|
|
76
|
+
[false, new Set()],
|
|
77
|
+
]);
|
|
78
|
+
|
|
79
|
+
const matchedRules: Array<CephClusterOwnerRule> = [];
|
|
80
|
+
|
|
81
|
+
for (const rule of rules) {
|
|
82
|
+
const matches: boolean = this.doesCephClusterMatchRule(
|
|
83
|
+
cephClusterWithDetails,
|
|
84
|
+
rule,
|
|
85
|
+
);
|
|
86
|
+
if (!matches) {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
let ruleAddedAny: boolean = false;
|
|
90
|
+
const notify: boolean = rule.notifyOwners !== false;
|
|
91
|
+
for (const user of rule.ownerUsers || []) {
|
|
92
|
+
if (user.id) {
|
|
93
|
+
usersByNotify.get(notify)!.add(user.id.toString());
|
|
94
|
+
ruleAddedAny = true;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
for (const team of rule.ownerTeams || []) {
|
|
98
|
+
if (team.id) {
|
|
99
|
+
teamsByNotify.get(notify)!.add(team.id.toString());
|
|
100
|
+
ruleAddedAny = true;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (ruleAddedAny) {
|
|
104
|
+
matchedRules.push(rule);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (matchedRules.length === 0) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
for (const notify of [true, false]) {
|
|
113
|
+
const userIds: Set<string> = usersByNotify.get(notify)!;
|
|
114
|
+
const teamIds: Set<string> = teamsByNotify.get(notify)!;
|
|
115
|
+
|
|
116
|
+
for (const userId of userIds) {
|
|
117
|
+
const owner: CephClusterOwnerUser = new CephClusterOwnerUser();
|
|
118
|
+
owner.cephClusterId = cephCluster.id;
|
|
119
|
+
owner.projectId = cephCluster.projectId;
|
|
120
|
+
owner.userId = new ObjectID(userId);
|
|
121
|
+
owner.isOwnerNotified = !notify;
|
|
122
|
+
await CephClusterOwnerUserService.create({
|
|
123
|
+
data: owner,
|
|
124
|
+
props: { isRoot: true },
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
for (const teamId of teamIds) {
|
|
129
|
+
const owner: CephClusterOwnerTeam = new CephClusterOwnerTeam();
|
|
130
|
+
owner.cephClusterId = cephCluster.id;
|
|
131
|
+
owner.projectId = cephCluster.projectId;
|
|
132
|
+
owner.teamId = new ObjectID(teamId);
|
|
133
|
+
owner.isOwnerNotified = !notify;
|
|
134
|
+
await CephClusterOwnerTeamService.create({
|
|
135
|
+
data: owner,
|
|
136
|
+
props: { isRoot: true },
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
logger.debug(
|
|
142
|
+
`CephClusterOwnerRuleEngine added owners to Ceph cluster ${cephCluster.id}`,
|
|
143
|
+
{ projectId: cephCluster.projectId.toString() } as LogAttributes,
|
|
144
|
+
);
|
|
145
|
+
} catch (error) {
|
|
146
|
+
logger.error(`Error applying Ceph cluster owner rules: ${error}`, {
|
|
147
|
+
projectId: cephCluster.projectId?.toString(),
|
|
148
|
+
cephClusterId: cephCluster.id?.toString(),
|
|
149
|
+
} as LogAttributes);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
private doesCephClusterMatchRule(
|
|
154
|
+
cephCluster: CephCluster,
|
|
155
|
+
rule: CephClusterOwnerRule,
|
|
156
|
+
): boolean {
|
|
157
|
+
if (rule.cephClusterLabels && rule.cephClusterLabels.length > 0) {
|
|
158
|
+
if (!cephCluster.labels || cephCluster.labels.length === 0) {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
const ruleLabelIds: Array<string> = rule.cephClusterLabels.map(
|
|
162
|
+
(l: Label) => {
|
|
163
|
+
return l.id?.toString() || "";
|
|
164
|
+
},
|
|
165
|
+
);
|
|
166
|
+
const labelIds: Array<string> = cephCluster.labels.map((l: Label) => {
|
|
167
|
+
return l.id?.toString() || "";
|
|
168
|
+
});
|
|
169
|
+
if (
|
|
170
|
+
!ruleLabelIds.some((id: string) => {
|
|
171
|
+
return labelIds.includes(id);
|
|
172
|
+
})
|
|
173
|
+
) {
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (
|
|
179
|
+
rule.cephClusterNamePattern &&
|
|
180
|
+
(!cephCluster.name ||
|
|
181
|
+
!this.testRegex(rule.cephClusterNamePattern, cephCluster.name, rule))
|
|
182
|
+
) {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (
|
|
187
|
+
rule.cephClusterDescriptionPattern &&
|
|
188
|
+
(!cephCluster.description ||
|
|
189
|
+
!this.testRegex(
|
|
190
|
+
rule.cephClusterDescriptionPattern,
|
|
191
|
+
cephCluster.description,
|
|
192
|
+
rule,
|
|
193
|
+
))
|
|
194
|
+
) {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
private testRegex(
|
|
202
|
+
pattern: string,
|
|
203
|
+
value: string,
|
|
204
|
+
rule: CephClusterOwnerRule,
|
|
205
|
+
): boolean {
|
|
206
|
+
try {
|
|
207
|
+
const regex: RegExp = new RegExp(pattern, "i");
|
|
208
|
+
return regex.test(value);
|
|
209
|
+
} catch {
|
|
210
|
+
logger.warn(
|
|
211
|
+
`Invalid regex in Ceph cluster owner rule ${rule.id}: ${pattern}`,
|
|
212
|
+
);
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export default new CephClusterOwnerRuleEngineServiceClass();
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import DatabaseService from "./DatabaseService";
|
|
2
|
+
import Model from "../../Models/DatabaseModels/CephClusterOwnerRule";
|
|
3
|
+
import { IsBillingEnabled } from "../EnvironmentConfig";
|
|
4
|
+
|
|
5
|
+
export class Service extends DatabaseService<Model> {
|
|
6
|
+
public constructor() {
|
|
7
|
+
super(Model);
|
|
8
|
+
if (IsBillingEnabled) {
|
|
9
|
+
this.hardDeleteItemsOlderThanInDays("createdAt", 3 * 365);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default new Service();
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import DatabaseService from "./DatabaseService";
|
|
2
|
+
import Model from "../../Models/DatabaseModels/CephClusterOwnerTeam";
|
|
3
|
+
|
|
4
|
+
export class Service extends DatabaseService<Model> {
|
|
5
|
+
public constructor() {
|
|
6
|
+
super(Model);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default new Service();
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import DatabaseService from "./DatabaseService";
|
|
2
|
+
import Model from "../../Models/DatabaseModels/CephClusterOwnerUser";
|
|
3
|
+
|
|
4
|
+
export class Service extends DatabaseService<Model> {
|
|
5
|
+
public constructor() {
|
|
6
|
+
super(Model);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default new Service();
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
import DatabaseService from "./DatabaseService";
|
|
2
|
+
import CephClusterLabelRuleEngineService from "./CephClusterLabelRuleEngineService";
|
|
3
|
+
import CephClusterOwnerRuleEngineService from "./CephClusterOwnerRuleEngineService";
|
|
4
|
+
import Model from "../../Models/DatabaseModels/CephCluster";
|
|
5
|
+
import Label from "../../Models/DatabaseModels/Label";
|
|
6
|
+
import { OnCreate } from "../Types/Database/Hooks";
|
|
7
|
+
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
8
|
+
import ObjectID from "../../Types/ObjectID";
|
|
9
|
+
import QueryHelper from "../Types/Database/QueryHelper";
|
|
10
|
+
import OneUptimeDate from "../../Types/Date";
|
|
11
|
+
import LIMIT_MAX from "../../Types/Database/LimitMax";
|
|
12
|
+
import GlobalCache from "../Infrastructure/GlobalCache";
|
|
13
|
+
import logger, { LogAttributes } from "../Utils/Logger";
|
|
14
|
+
import crypto from "crypto";
|
|
15
|
+
|
|
16
|
+
const LAST_SEEN_CACHE_NAMESPACE: string = "ceph-cluster-last-seen";
|
|
17
|
+
const LAST_SEEN_THROTTLE_SECONDS: number = 60;
|
|
18
|
+
|
|
19
|
+
const LABELS_APPLIED_CACHE_NAMESPACE: string = "ceph-cluster-labels-applied";
|
|
20
|
+
const LABELS_APPLIED_CACHE_TTL_SECONDS: number = 60;
|
|
21
|
+
|
|
22
|
+
export class Service extends DatabaseService<Model> {
|
|
23
|
+
public constructor() {
|
|
24
|
+
super(Model);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@CaptureSpan()
|
|
28
|
+
protected override async onCreateSuccess(
|
|
29
|
+
_onCreate: OnCreate<Model>,
|
|
30
|
+
createdItem: Model,
|
|
31
|
+
): Promise<Model> {
|
|
32
|
+
/*
|
|
33
|
+
* Rules run once, on creation only — exact parity with
|
|
34
|
+
* KubernetesClusterService. Label engine first: it syncs the
|
|
35
|
+
* in-memory labels so the owner engine can match rule-added labels.
|
|
36
|
+
*/
|
|
37
|
+
if (createdItem.projectId && createdItem.id) {
|
|
38
|
+
Promise.resolve()
|
|
39
|
+
.then(async () => {
|
|
40
|
+
await CephClusterLabelRuleEngineService.applyRulesToCephCluster(
|
|
41
|
+
createdItem,
|
|
42
|
+
);
|
|
43
|
+
})
|
|
44
|
+
.then(async () => {
|
|
45
|
+
await CephClusterOwnerRuleEngineService.applyRulesToCephCluster(
|
|
46
|
+
createdItem,
|
|
47
|
+
);
|
|
48
|
+
})
|
|
49
|
+
.catch((error: Error) => {
|
|
50
|
+
logger.error(
|
|
51
|
+
`Error applying ceph cluster rules in CephClusterService.onCreateSuccess: ${error}`,
|
|
52
|
+
{
|
|
53
|
+
projectId: createdItem.projectId?.toString(),
|
|
54
|
+
cephClusterId: createdItem.id?.toString(),
|
|
55
|
+
} as LogAttributes,
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return createdItem;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@CaptureSpan()
|
|
63
|
+
public async findOrCreateByName(data: {
|
|
64
|
+
projectId: ObjectID;
|
|
65
|
+
name: string;
|
|
66
|
+
}): Promise<Model> {
|
|
67
|
+
/*
|
|
68
|
+
* A Ceph cluster is keyed by the `ceph.cluster.name` OTel resource
|
|
69
|
+
* attribute, which the user configures on the agent. Look it up
|
|
70
|
+
* case-insensitively: the unique guard (checkUniqueColumnBy ->
|
|
71
|
+
* findWithSameText) compares case-insensitively, so a case-sensitive
|
|
72
|
+
* lookup would miss an existing row that differs only by case, then
|
|
73
|
+
* fail to create it — wedging ingest for that cluster. Unlike
|
|
74
|
+
* DockerHost.hostIdentifier (host.name casing is unstable on Windows)
|
|
75
|
+
* the configured cluster name's casing is stable, so we preserve the
|
|
76
|
+
* user's casing on create instead of canonicalizing to lowercase.
|
|
77
|
+
*/
|
|
78
|
+
const name: string = data.name.trim();
|
|
79
|
+
|
|
80
|
+
const existingCluster: Model | null = await this.findOneBy({
|
|
81
|
+
query: {
|
|
82
|
+
projectId: data.projectId,
|
|
83
|
+
name: QueryHelper.findWithSameText(name),
|
|
84
|
+
},
|
|
85
|
+
select: {
|
|
86
|
+
_id: true,
|
|
87
|
+
projectId: true,
|
|
88
|
+
name: true,
|
|
89
|
+
},
|
|
90
|
+
props: {
|
|
91
|
+
isRoot: true,
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
if (existingCluster) {
|
|
96
|
+
return existingCluster;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
// Create new cluster
|
|
101
|
+
const newCluster: Model = new Model();
|
|
102
|
+
newCluster.projectId = data.projectId;
|
|
103
|
+
newCluster.name = name;
|
|
104
|
+
newCluster.otelCollectorStatus = "connected";
|
|
105
|
+
newCluster.lastSeenAt = OneUptimeDate.getCurrentDate();
|
|
106
|
+
|
|
107
|
+
const createdCluster: Model = await this.create({
|
|
108
|
+
data: newCluster,
|
|
109
|
+
props: {
|
|
110
|
+
isRoot: true,
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
return createdCluster;
|
|
115
|
+
} catch {
|
|
116
|
+
/*
|
|
117
|
+
* Either two ingest workers raced to create the same cluster, or a
|
|
118
|
+
* cluster with this name in a different case already existed and the
|
|
119
|
+
* unique guard rejected the insert. Re-resolve case-insensitively so
|
|
120
|
+
* the caller still gets the existing row instead of throwing.
|
|
121
|
+
*/
|
|
122
|
+
const reFetchedCluster: Model | null = await this.findOneBy({
|
|
123
|
+
query: {
|
|
124
|
+
projectId: data.projectId,
|
|
125
|
+
name: QueryHelper.findWithSameText(name),
|
|
126
|
+
},
|
|
127
|
+
select: {
|
|
128
|
+
_id: true,
|
|
129
|
+
projectId: true,
|
|
130
|
+
name: true,
|
|
131
|
+
},
|
|
132
|
+
props: {
|
|
133
|
+
isRoot: true,
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
if (reFetchedCluster) {
|
|
138
|
+
return reFetchedCluster;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
throw new Error("Failed to create or find Ceph cluster: " + name);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/*
|
|
146
|
+
* Refresh lastSeenAt / connection status and (optionally) the
|
|
147
|
+
* snapshot columns the list page renders. Count/health columns ride
|
|
148
|
+
* this extras path with COALESCE-per-column semantics: a key that is
|
|
149
|
+
* undefined is simply not written, so a partial batch (one that
|
|
150
|
+
* lacked the matching *_metadata series) never zeroes a count. The
|
|
151
|
+
* 60-second extras fingerprint cache is the write throttle — the
|
|
152
|
+
* steady state (identical snapshot every scrape) costs one Redis
|
|
153
|
+
* read per batch and at most one Postgres UPDATE per minute.
|
|
154
|
+
*
|
|
155
|
+
* Two callers share this throttle with DISJOINT extras shapes: the
|
|
156
|
+
* metrics snapshot flush (version + counts/health, every batch) and
|
|
157
|
+
* the fenced autoDiscoverCephCluster maintenance path (agentVersion
|
|
158
|
+
* + optional fsid only — and usually an all-null fingerprint, since
|
|
159
|
+
* the shipped agent config stamps neither oneuptime.agent.version
|
|
160
|
+
* nor ceph.cluster.fsid by default). The single fingerprint covers
|
|
161
|
+
* the whole extras object, so each alternation between the two
|
|
162
|
+
* shapes busts the throttle: at most one extra Postgres UPDATE per
|
|
163
|
+
* maintenance-fence window (~5 min), which is accepted. Do NOT key
|
|
164
|
+
* the cache per-caller — that would let two callers each refresh
|
|
165
|
+
* lastSeenAt under their own throttle and is not worth the
|
|
166
|
+
* complexity for one UPDATE per 5 minutes.
|
|
167
|
+
*/
|
|
168
|
+
@CaptureSpan()
|
|
169
|
+
public async updateLastSeen(
|
|
170
|
+
clusterId: ObjectID,
|
|
171
|
+
extra?: {
|
|
172
|
+
cephVersion?: string | undefined;
|
|
173
|
+
fsid?: string | undefined;
|
|
174
|
+
agentVersion?: string | undefined;
|
|
175
|
+
monCount?: number | undefined;
|
|
176
|
+
osdCount?: number | undefined;
|
|
177
|
+
osdUpCount?: number | undefined;
|
|
178
|
+
osdInCount?: number | undefined;
|
|
179
|
+
poolCount?: number | undefined;
|
|
180
|
+
healthStatus?: number | undefined;
|
|
181
|
+
capacityUsedPercent?: number | undefined;
|
|
182
|
+
},
|
|
183
|
+
): Promise<void> {
|
|
184
|
+
const cacheKey: string = clusterId.toString();
|
|
185
|
+
const extrasFingerprint: string = crypto
|
|
186
|
+
.createHash("sha1")
|
|
187
|
+
.update(
|
|
188
|
+
JSON.stringify({
|
|
189
|
+
cephVersion: extra?.cephVersion ?? null,
|
|
190
|
+
fsid: extra?.fsid ?? null,
|
|
191
|
+
agentVersion: extra?.agentVersion ?? null,
|
|
192
|
+
monCount: extra?.monCount ?? null,
|
|
193
|
+
osdCount: extra?.osdCount ?? null,
|
|
194
|
+
osdUpCount: extra?.osdUpCount ?? null,
|
|
195
|
+
osdInCount: extra?.osdInCount ?? null,
|
|
196
|
+
poolCount: extra?.poolCount ?? null,
|
|
197
|
+
healthStatus: extra?.healthStatus ?? null,
|
|
198
|
+
capacityUsedPercent: extra?.capacityUsedPercent ?? null,
|
|
199
|
+
}),
|
|
200
|
+
)
|
|
201
|
+
.digest("hex");
|
|
202
|
+
|
|
203
|
+
const cached: string | null = await GlobalCache.getString(
|
|
204
|
+
LAST_SEEN_CACHE_NAMESPACE,
|
|
205
|
+
cacheKey,
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
if (cached === extrasFingerprint) {
|
|
209
|
+
return; // same data was written recently
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
await GlobalCache.setString(
|
|
213
|
+
LAST_SEEN_CACHE_NAMESPACE,
|
|
214
|
+
cacheKey,
|
|
215
|
+
extrasFingerprint,
|
|
216
|
+
{ expiresInSeconds: LAST_SEEN_THROTTLE_SECONDS },
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
220
|
+
const data: any = {
|
|
221
|
+
lastSeenAt: OneUptimeDate.getCurrentDate(),
|
|
222
|
+
otelCollectorStatus: "connected",
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
if (extra?.cephVersion) {
|
|
226
|
+
data.cephVersion = extra.cephVersion;
|
|
227
|
+
}
|
|
228
|
+
if (extra?.fsid) {
|
|
229
|
+
data.fsid = extra.fsid;
|
|
230
|
+
}
|
|
231
|
+
if (extra?.agentVersion) {
|
|
232
|
+
data.agentVersion = extra.agentVersion;
|
|
233
|
+
}
|
|
234
|
+
/*
|
|
235
|
+
* Counts and health: 0 is a legitimate value (healthStatus 0 = OK,
|
|
236
|
+
* osdUpCount 0 = every OSD down) — gate on undefined, not falsiness.
|
|
237
|
+
*/
|
|
238
|
+
if (extra?.monCount !== undefined) {
|
|
239
|
+
data.monCount = extra.monCount;
|
|
240
|
+
}
|
|
241
|
+
if (extra?.osdCount !== undefined) {
|
|
242
|
+
data.osdCount = extra.osdCount;
|
|
243
|
+
}
|
|
244
|
+
if (extra?.osdUpCount !== undefined) {
|
|
245
|
+
data.osdUpCount = extra.osdUpCount;
|
|
246
|
+
}
|
|
247
|
+
if (extra?.osdInCount !== undefined) {
|
|
248
|
+
data.osdInCount = extra.osdInCount;
|
|
249
|
+
}
|
|
250
|
+
if (extra?.poolCount !== undefined) {
|
|
251
|
+
data.poolCount = extra.poolCount;
|
|
252
|
+
}
|
|
253
|
+
if (extra?.healthStatus !== undefined) {
|
|
254
|
+
data.healthStatus = extra.healthStatus;
|
|
255
|
+
}
|
|
256
|
+
if (extra?.capacityUsedPercent !== undefined) {
|
|
257
|
+
data.capacityUsedPercent = extra.capacityUsedPercent;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
await this.updateOneById({
|
|
261
|
+
id: clusterId,
|
|
262
|
+
data: data,
|
|
263
|
+
props: {
|
|
264
|
+
isRoot: true,
|
|
265
|
+
},
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Additively attach labels to a Ceph cluster. Existing labels are
|
|
271
|
+
* never removed — manual labels set via the UI survive ingest. The
|
|
272
|
+
* set of labelIds passed in is fingerprinted and cached for 60s so
|
|
273
|
+
* the common case (steady-state collector pushing the same label
|
|
274
|
+
* set every batch) costs one in-memory lookup, not a join-table
|
|
275
|
+
* scan.
|
|
276
|
+
*/
|
|
277
|
+
@CaptureSpan()
|
|
278
|
+
public async attachLabels(data: {
|
|
279
|
+
cephClusterId: ObjectID;
|
|
280
|
+
labelIds: Array<ObjectID>;
|
|
281
|
+
}): Promise<void> {
|
|
282
|
+
if (!data.labelIds || data.labelIds.length === 0) {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const cacheKey: string = data.cephClusterId.toString();
|
|
287
|
+
const fingerprint: string = fingerprintLabelIds(data.labelIds);
|
|
288
|
+
const cached: string | null = await GlobalCache.getString(
|
|
289
|
+
LABELS_APPLIED_CACHE_NAMESPACE,
|
|
290
|
+
cacheKey,
|
|
291
|
+
);
|
|
292
|
+
if (cached === fingerprint) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
try {
|
|
297
|
+
const cephClusterIdStr: string = data.cephClusterId.toString();
|
|
298
|
+
const existingLabels: Array<Label> = await this.getRepository()
|
|
299
|
+
.createQueryBuilder()
|
|
300
|
+
.relation(Model, "labels")
|
|
301
|
+
.of(cephClusterIdStr)
|
|
302
|
+
.loadMany();
|
|
303
|
+
|
|
304
|
+
const existingIds: Set<string> = new Set();
|
|
305
|
+
for (const lbl of existingLabels) {
|
|
306
|
+
const idStr: string | undefined = lbl._id?.toString();
|
|
307
|
+
if (idStr) {
|
|
308
|
+
existingIds.add(idStr);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
const toAddIds: Array<string> = [];
|
|
313
|
+
const seen: Set<string> = new Set();
|
|
314
|
+
for (const id of data.labelIds) {
|
|
315
|
+
const idStr: string = id.toString();
|
|
316
|
+
if (existingIds.has(idStr) || seen.has(idStr)) {
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
seen.add(idStr);
|
|
320
|
+
toAddIds.push(idStr);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (toAddIds.length > 0) {
|
|
324
|
+
await this.getRepository()
|
|
325
|
+
.createQueryBuilder()
|
|
326
|
+
.relation(Model, "labels")
|
|
327
|
+
.of(cephClusterIdStr)
|
|
328
|
+
.add(toAddIds);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
await GlobalCache.setString(
|
|
332
|
+
LABELS_APPLIED_CACHE_NAMESPACE,
|
|
333
|
+
cacheKey,
|
|
334
|
+
fingerprint,
|
|
335
|
+
{ expiresInSeconds: LABELS_APPLIED_CACHE_TTL_SECONDS },
|
|
336
|
+
);
|
|
337
|
+
} catch (err) {
|
|
338
|
+
logger.warn(
|
|
339
|
+
`CephClusterService.attachLabels failed for ceph cluster ${data.cephClusterId.toString()}: ${
|
|
340
|
+
err instanceof Error ? err.message : String(err)
|
|
341
|
+
}`,
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
@CaptureSpan()
|
|
347
|
+
public async markDisconnectedClusters(): Promise<void> {
|
|
348
|
+
/*
|
|
349
|
+
* Threshold must stay well above the 5-minute OTel ingest
|
|
350
|
+
* maintenance fence (MAINTENANCE_FENCE_TTL_SECONDS in
|
|
351
|
+
* OtelIngestBaseService) — lastSeenAt is legitimately up to
|
|
352
|
+
* ~5 minutes stale during continuous telemetry, so a threshold
|
|
353
|
+
* equal to the fence TTL flaps healthy resources. 15 minutes
|
|
354
|
+
* gives 3x headroom.
|
|
355
|
+
*/
|
|
356
|
+
const fifteenMinutesAgo: Date = OneUptimeDate.addRemoveMinutes(
|
|
357
|
+
OneUptimeDate.getCurrentDate(),
|
|
358
|
+
-15,
|
|
359
|
+
);
|
|
360
|
+
|
|
361
|
+
const connectedClusters: Array<Model> = await this.findBy({
|
|
362
|
+
query: {
|
|
363
|
+
otelCollectorStatus: "connected",
|
|
364
|
+
lastSeenAt: QueryHelper.lessThan(fifteenMinutesAgo),
|
|
365
|
+
},
|
|
366
|
+
select: {
|
|
367
|
+
_id: true,
|
|
368
|
+
},
|
|
369
|
+
limit: LIMIT_MAX,
|
|
370
|
+
skip: 0,
|
|
371
|
+
props: {
|
|
372
|
+
isRoot: true,
|
|
373
|
+
},
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
for (const cluster of connectedClusters) {
|
|
377
|
+
if (cluster._id) {
|
|
378
|
+
await this.updateOneById({
|
|
379
|
+
id: new ObjectID(cluster._id.toString()),
|
|
380
|
+
data: {
|
|
381
|
+
otelCollectorStatus: "disconnected",
|
|
382
|
+
},
|
|
383
|
+
props: {
|
|
384
|
+
isRoot: true,
|
|
385
|
+
},
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function fingerprintLabelIds(labelIds: Array<ObjectID>): string {
|
|
393
|
+
const sorted: Array<string> = labelIds
|
|
394
|
+
.map((id: ObjectID) => {
|
|
395
|
+
return id.toString();
|
|
396
|
+
})
|
|
397
|
+
.sort();
|
|
398
|
+
return crypto.createHash("sha1").update(sorted.join(",")).digest("hex");
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
export default new Service();
|