@oneuptime/common 11.0.2 → 11.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/Alert.ts +166 -0
- package/Models/DatabaseModels/AlertLabelRule.ts +38 -0
- package/Models/DatabaseModels/AlertOwnerRule.ts +38 -0
- package/Models/DatabaseModels/DockerSwarmCluster.ts +989 -0
- package/Models/DatabaseModels/DockerSwarmClusterLabelRule.ts +514 -0
- package/Models/DatabaseModels/DockerSwarmClusterOwnerRule.ts +596 -0
- package/Models/DatabaseModels/DockerSwarmClusterOwnerTeam.ts +487 -0
- package/Models/DatabaseModels/DockerSwarmClusterOwnerUser.ts +486 -0
- package/Models/DatabaseModels/DockerSwarmResource.ts +750 -0
- package/Models/DatabaseModels/Incident.ts +166 -0
- package/Models/DatabaseModels/IncidentLabelRule.ts +38 -0
- package/Models/DatabaseModels/IncidentOwnerRule.ts +38 -0
- package/Models/DatabaseModels/IncidentTemplate.ts +56 -0
- package/Models/DatabaseModels/Index.ts +24 -0
- package/Models/DatabaseModels/PodmanHost.ts +859 -0
- package/Models/DatabaseModels/PodmanHostLabelRule.ts +514 -0
- package/Models/DatabaseModels/PodmanHostOwnerRule.ts +596 -0
- package/Models/DatabaseModels/PodmanHostOwnerTeam.ts +487 -0
- package/Models/DatabaseModels/PodmanHostOwnerUser.ts +486 -0
- package/Models/DatabaseModels/PodmanResource.ts +498 -0
- package/Models/DatabaseModels/ScheduledMaintenance.ts +110 -0
- package/Models/DatabaseModels/ScheduledMaintenanceLabelRule.ts +38 -0
- package/Models/DatabaseModels/ScheduledMaintenanceOwnerRule.ts +38 -0
- package/Models/DatabaseModels/ScheduledMaintenanceTemplate.ts +56 -0
- package/Models/DatabaseModels/TelemetryException.ts +2 -0
- package/Server/API/DashboardAPI.ts +89 -0
- package/Server/API/DockerSwarmResourceAPI.ts +137 -0
- package/Server/API/TelemetryAPI.ts +8 -1
- package/Server/Infrastructure/Postgres/SchemaMigrations/1781587937032-MigrationName.ts +3199 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Services/AlertLabelRuleEngineService.ts +29 -0
- package/Server/Services/AlertOwnerRuleEngineService.ts +67 -0
- package/Server/Services/DockerSwarmClusterLabelRuleEngineService.ts +214 -0
- package/Server/Services/DockerSwarmClusterLabelRuleService.ts +14 -0
- package/Server/Services/DockerSwarmClusterOwnerRuleEngineService.ts +232 -0
- package/Server/Services/DockerSwarmClusterOwnerRuleService.ts +14 -0
- package/Server/Services/DockerSwarmClusterOwnerTeamService.ts +10 -0
- package/Server/Services/DockerSwarmClusterOwnerUserService.ts +10 -0
- package/Server/Services/DockerSwarmClusterService.ts +404 -0
- package/Server/Services/DockerSwarmResourceService.ts +381 -0
- package/Server/Services/ExceptionAggregationService.ts +1 -0
- package/Server/Services/IncidentLabelRuleEngineService.ts +27 -0
- package/Server/Services/IncidentOwnerRuleEngineService.ts +67 -0
- package/Server/Services/IncidentService.ts +11 -0
- package/Server/Services/Index.ts +14 -0
- package/Server/Services/LogAggregationService.ts +1 -0
- package/Server/Services/MetricAggregationService.ts +1 -0
- package/Server/Services/OpenTelemetryIngestService.ts +37 -0
- package/Server/Services/PodmanHostLabelRuleEngineService.ts +198 -0
- package/Server/Services/PodmanHostLabelRuleService.ts +14 -0
- package/Server/Services/PodmanHostOwnerRuleEngineService.ts +216 -0
- package/Server/Services/PodmanHostOwnerRuleService.ts +14 -0
- package/Server/Services/PodmanHostOwnerTeamService.ts +10 -0
- package/Server/Services/PodmanHostOwnerUserService.ts +10 -0
- package/Server/Services/PodmanHostService.ts +368 -0
- package/Server/Services/PodmanResourceService.ts +310 -0
- package/Server/Services/ScheduledMaintenanceLabelRuleEngineService.ts +29 -0
- package/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.ts +67 -0
- package/Server/Services/TelemetryUsageBillingService.ts +18 -0
- package/Server/Services/TraceAggregationService.ts +1 -0
- package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +13 -0
- package/Server/Utils/Monitor/MonitorAlert.ts +10 -0
- package/Server/Utils/Monitor/MonitorClusterContext.ts +35 -6
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +306 -0
- package/Server/Utils/Monitor/MonitorIncident.ts +45 -0
- package/Server/Utils/Monitor/MonitorMaintenanceSuppression.ts +17 -0
- package/Server/Utils/Monitor/MonitorTemplateUtil.ts +3 -0
- package/Server/Utils/Monitor/SeriesResourceLabels.ts +26 -0
- package/Server/Utils/Telemetry/ResourceFacetResolver.ts +49 -0
- package/Server/Utils/Telemetry/Telemetry.ts +10 -0
- package/Server/Utils/Telemetry/TelemetryEntity.ts +22 -0
- package/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.ts +1 -0
- package/Tests/Types/DockerSwarm/DockerSwarmInventoryExtractor.test.ts +667 -0
- package/Tests/Types/Monitor/DockerSwarmAlertTemplates.test.ts +528 -0
- package/Types/Dashboard/DashboardComponentType.ts +7 -0
- package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +2 -0
- package/Types/Dashboard/DashboardComponents/DashboardDockerSwarmNodeListComponent.ts +17 -0
- package/Types/Dashboard/DashboardComponents/DashboardDockerSwarmServiceListComponent.ts +17 -0
- package/Types/Dashboard/DashboardComponents/DashboardPodmanContainerListComponent.ts +16 -0
- package/Types/Dashboard/DashboardComponents/DashboardPodmanHostListComponent.ts +15 -0
- package/Types/Dashboard/DashboardComponents/DashboardPodmanImageListComponent.ts +16 -0
- package/Types/Dashboard/DashboardComponents/DashboardPodmanNetworkListComponent.ts +15 -0
- package/Types/Dashboard/DashboardComponents/DashboardPodmanVolumeListComponent.ts +15 -0
- package/Types/Dashboard/DashboardTemplates.ts +194 -0
- package/Types/DockerSwarm/DockerSwarmInventoryExtractor.ts +452 -0
- package/Types/Icon/IconProp.ts +1 -0
- package/Types/Monitor/DockerSwarmAlertTemplates.ts +461 -0
- package/Types/Monitor/DockerSwarmMetricCatalog.ts +139 -0
- package/Types/Monitor/HostAlertTemplates.ts +455 -0
- package/Types/Monitor/HostMetricCatalog.ts +177 -0
- package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +21 -0
- package/Types/Monitor/MonitorStep.ts +99 -0
- package/Types/Monitor/MonitorStepDockerSwarmMonitor.ts +74 -0
- package/Types/Monitor/MonitorStepHostMonitor.ts +30 -0
- package/Types/Monitor/MonitorStepPodmanMonitor.ts +38 -0
- package/Types/Monitor/MonitorType.ts +42 -0
- package/Types/Monitor/PodmanAlertTemplates.ts +507 -0
- package/Types/Monitor/PodmanMetricCatalog.ts +226 -0
- package/Types/Permission.ts +465 -4
- package/Types/Podman/PodmanInventoryExtractor.ts +343 -0
- package/Types/Telemetry/EntityType.ts +12 -0
- package/Types/Telemetry/ServiceType.ts +2 -0
- package/UI/Components/Icon/Icon.tsx +57 -0
- package/UI/Components/LogsViewer/LogsViewer.tsx +44 -1
- package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +28 -0
- package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +6 -0
- package/UI/Utils/TelemetryService.ts +1 -0
- package/Utils/Dashboard/Components/DashboardDockerSwarmNodeListComponent.ts +70 -0
- package/Utils/Dashboard/Components/DashboardDockerSwarmResourceListShared.ts +61 -0
- package/Utils/Dashboard/Components/DashboardDockerSwarmServiceListComponent.ts +71 -0
- package/Utils/Dashboard/Components/DashboardPodmanContainerListComponent.ts +100 -0
- package/Utils/Dashboard/Components/DashboardPodmanHostListComponent.ts +88 -0
- package/Utils/Dashboard/Components/DashboardPodmanImageListComponent.ts +97 -0
- package/Utils/Dashboard/Components/DashboardPodmanNetworkListComponent.ts +87 -0
- package/Utils/Dashboard/Components/DashboardPodmanVolumeListComponent.ts +87 -0
- package/Utils/Dashboard/Components/Index.ts +51 -0
- package/Utils/Telemetry/EntityKey.ts +18 -0
- package/build/dist/Models/DatabaseModels/Alert.js +162 -0
- package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertLabelRule.js +39 -0
- package/build/dist/Models/DatabaseModels/AlertLabelRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertOwnerRule.js +39 -0
- package/build/dist/Models/DatabaseModels/AlertOwnerRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js +1018 -0
- package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DockerSwarmClusterLabelRule.js +522 -0
- package/build/dist/Models/DatabaseModels/DockerSwarmClusterLabelRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DockerSwarmClusterOwnerRule.js +603 -0
- package/build/dist/Models/DatabaseModels/DockerSwarmClusterOwnerRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DockerSwarmClusterOwnerTeam.js +503 -0
- package/build/dist/Models/DatabaseModels/DockerSwarmClusterOwnerTeam.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DockerSwarmClusterOwnerUser.js +502 -0
- package/build/dist/Models/DatabaseModels/DockerSwarmClusterOwnerUser.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DockerSwarmResource.js +787 -0
- package/build/dist/Models/DatabaseModels/DockerSwarmResource.js.map +1 -0
- package/build/dist/Models/DatabaseModels/Incident.js +162 -0
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentLabelRule.js +39 -0
- package/build/dist/Models/DatabaseModels/IncidentLabelRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentOwnerRule.js +39 -0
- package/build/dist/Models/DatabaseModels/IncidentOwnerRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentTemplate.js +54 -0
- package/build/dist/Models/DatabaseModels/IncidentTemplate.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/PodmanHost.js +885 -0
- package/build/dist/Models/DatabaseModels/PodmanHost.js.map +1 -0
- package/build/dist/Models/DatabaseModels/PodmanHostLabelRule.js +522 -0
- package/build/dist/Models/DatabaseModels/PodmanHostLabelRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/PodmanHostOwnerRule.js +603 -0
- package/build/dist/Models/DatabaseModels/PodmanHostOwnerRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/PodmanHostOwnerTeam.js +503 -0
- package/build/dist/Models/DatabaseModels/PodmanHostOwnerTeam.js.map +1 -0
- package/build/dist/Models/DatabaseModels/PodmanHostOwnerUser.js +502 -0
- package/build/dist/Models/DatabaseModels/PodmanHostOwnerUser.js.map +1 -0
- package/build/dist/Models/DatabaseModels/PodmanResource.js +526 -0
- package/build/dist/Models/DatabaseModels/PodmanResource.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/Models/DatabaseModels/ScheduledMaintenanceLabelRule.js +39 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceLabelRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceOwnerRule.js +39 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceOwnerRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplate.js +54 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplate.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TelemetryException.js +2 -0
- package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
- package/build/dist/Server/API/DashboardAPI.js +89 -0
- package/build/dist/Server/API/DashboardAPI.js.map +1 -1
- package/build/dist/Server/API/DockerSwarmResourceAPI.js +100 -0
- package/build/dist/Server/API/DockerSwarmResourceAPI.js.map +1 -0
- package/build/dist/Server/API/TelemetryAPI.js +8 -1
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781587937032-MigrationName.js +1100 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781587937032-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AlertLabelRuleEngineService.js +30 -4
- package/build/dist/Server/Services/AlertLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertOwnerRuleEngineService.js +62 -5
- package/build/dist/Server/Services/AlertOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js +168 -0
- package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/DockerSwarmClusterLabelRuleService.js +13 -0
- package/build/dist/Server/Services/DockerSwarmClusterLabelRuleService.js.map +1 -0
- package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js +188 -0
- package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleService.js +13 -0
- package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleService.js.map +1 -0
- package/build/dist/Server/Services/DockerSwarmClusterOwnerTeamService.js +9 -0
- package/build/dist/Server/Services/DockerSwarmClusterOwnerTeamService.js.map +1 -0
- package/build/dist/Server/Services/DockerSwarmClusterOwnerUserService.js +9 -0
- package/build/dist/Server/Services/DockerSwarmClusterOwnerUserService.js.map +1 -0
- package/build/dist/Server/Services/DockerSwarmClusterService.js +353 -0
- package/build/dist/Server/Services/DockerSwarmClusterService.js.map +1 -0
- package/build/dist/Server/Services/DockerSwarmResourceService.js +258 -0
- package/build/dist/Server/Services/DockerSwarmResourceService.js.map +1 -0
- package/build/dist/Server/Services/ExceptionAggregationService.js +1 -0
- package/build/dist/Server/Services/ExceptionAggregationService.js.map +1 -1
- package/build/dist/Server/Services/IncidentLabelRuleEngineService.js +28 -4
- package/build/dist/Server/Services/IncidentLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js +62 -5
- package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +8 -0
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +14 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/LogAggregationService.js +1 -0
- package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
- package/build/dist/Server/Services/MetricAggregationService.js +1 -0
- package/build/dist/Server/Services/MetricAggregationService.js.map +1 -1
- package/build/dist/Server/Services/OpenTelemetryIngestService.js +43 -13
- package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
- package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js +166 -0
- package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/PodmanHostLabelRuleService.js +13 -0
- package/build/dist/Server/Services/PodmanHostLabelRuleService.js.map +1 -0
- package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js +186 -0
- package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/PodmanHostOwnerRuleService.js +13 -0
- package/build/dist/Server/Services/PodmanHostOwnerRuleService.js.map +1 -0
- package/build/dist/Server/Services/PodmanHostOwnerTeamService.js +9 -0
- package/build/dist/Server/Services/PodmanHostOwnerTeamService.js.map +1 -0
- package/build/dist/Server/Services/PodmanHostOwnerUserService.js +9 -0
- package/build/dist/Server/Services/PodmanHostOwnerUserService.js.map +1 -0
- package/build/dist/Server/Services/PodmanHostService.js +319 -0
- package/build/dist/Server/Services/PodmanHostService.js.map +1 -0
- package/build/dist/Server/Services/PodmanResourceService.js +196 -0
- package/build/dist/Server/Services/PodmanResourceService.js.map +1 -0
- package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js +30 -4
- package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js +62 -5
- package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryUsageBillingService.js +13 -0
- package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
- package/build/dist/Server/Services/TraceAggregationService.js +1 -0
- package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +13 -0
- package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +8 -0
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorClusterContext.js +35 -7
- package/build/dist/Server/Utils/Monitor/MonitorClusterContext.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +194 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +35 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js +9 -0
- package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +3 -0
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +16 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js +30 -0
- package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/Telemetry.js +6 -0
- package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +18 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponentType.js +7 -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/DashboardDockerSwarmNodeListComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDockerSwarmNodeListComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDockerSwarmServiceListComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDockerSwarmServiceListComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardPodmanContainerListComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardPodmanContainerListComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardPodmanHostListComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardPodmanHostListComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardPodmanImageListComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardPodmanImageListComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardPodmanNetworkListComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardPodmanNetworkListComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardPodmanVolumeListComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardPodmanVolumeListComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js +168 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
- package/build/dist/Types/DockerSwarm/DockerSwarmInventoryExtractor.js +359 -0
- package/build/dist/Types/DockerSwarm/DockerSwarmInventoryExtractor.js.map +1 -0
- package/build/dist/Types/Icon/IconProp.js +1 -0
- package/build/dist/Types/Icon/IconProp.js.map +1 -1
- package/build/dist/Types/Monitor/DockerSwarmAlertTemplates.js +358 -0
- package/build/dist/Types/Monitor/DockerSwarmAlertTemplates.js.map +1 -0
- package/build/dist/Types/Monitor/DockerSwarmMetricCatalog.js +103 -0
- package/build/dist/Types/Monitor/DockerSwarmMetricCatalog.js.map +1 -0
- package/build/dist/Types/Monitor/HostAlertTemplates.js +365 -0
- package/build/dist/Types/Monitor/HostAlertTemplates.js.map +1 -0
- package/build/dist/Types/Monitor/HostMetricCatalog.js +138 -0
- package/build/dist/Types/Monitor/HostMetricCatalog.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorStep.js +69 -0
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepDockerSwarmMonitor.js +21 -0
- package/build/dist/Types/Monitor/MonitorStepDockerSwarmMonitor.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorStepHostMonitor.js +20 -0
- package/build/dist/Types/Monitor/MonitorStepHostMonitor.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorStepPodmanMonitor.js +21 -0
- package/build/dist/Types/Monitor/MonitorStepPodmanMonitor.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorType.js +39 -0
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/Types/Monitor/PodmanAlertTemplates.js +410 -0
- package/build/dist/Types/Monitor/PodmanAlertTemplates.js.map +1 -0
- package/build/dist/Types/Monitor/PodmanMetricCatalog.js +192 -0
- package/build/dist/Types/Monitor/PodmanMetricCatalog.js.map +1 -0
- package/build/dist/Types/Permission.js +420 -4
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Podman/PodmanInventoryExtractor.js +293 -0
- package/build/dist/Types/Podman/PodmanInventoryExtractor.js.map +1 -0
- package/build/dist/Types/Telemetry/EntityType.js +12 -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 +16 -0
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js +30 -2
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +22 -0
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +6 -0
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
- package/build/dist/UI/Utils/TelemetryService.js +1 -0
- package/build/dist/UI/Utils/TelemetryService.js.map +1 -1
- package/build/dist/Utils/Dashboard/Components/DashboardDockerSwarmNodeListComponent.js +55 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDockerSwarmNodeListComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDockerSwarmResourceListShared.js +46 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDockerSwarmResourceListShared.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDockerSwarmServiceListComponent.js +55 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDockerSwarmServiceListComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardPodmanContainerListComponent.js +77 -0
- package/build/dist/Utils/Dashboard/Components/DashboardPodmanContainerListComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardPodmanHostListComponent.js +71 -0
- package/build/dist/Utils/Dashboard/Components/DashboardPodmanHostListComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardPodmanImageListComponent.js +77 -0
- package/build/dist/Utils/Dashboard/Components/DashboardPodmanImageListComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardPodmanNetworkListComponent.js +68 -0
- package/build/dist/Utils/Dashboard/Components/DashboardPodmanNetworkListComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardPodmanVolumeListComponent.js +68 -0
- package/build/dist/Utils/Dashboard/Components/DashboardPodmanVolumeListComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/Index.js +28 -0
- package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
- package/build/dist/Utils/Telemetry/EntityKey.js +14 -0
- package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
import DatabaseService from "./DatabaseService";
|
|
2
|
+
import PodmanHostLabelRuleEngineService from "./PodmanHostLabelRuleEngineService";
|
|
3
|
+
import PodmanHostOwnerRuleEngineService from "./PodmanHostOwnerRuleEngineService";
|
|
4
|
+
import Model from "../../Models/DatabaseModels/PodmanHost";
|
|
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 = "podman-host-last-seen";
|
|
17
|
+
const LAST_SEEN_THROTTLE_SECONDS: number = 60;
|
|
18
|
+
|
|
19
|
+
const LABELS_APPLIED_CACHE_NAMESPACE: string = "podman-host-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
|
+
if (createdItem.projectId && createdItem.id) {
|
|
33
|
+
Promise.resolve()
|
|
34
|
+
.then(async () => {
|
|
35
|
+
await PodmanHostLabelRuleEngineService.applyRulesToPodmanHost(
|
|
36
|
+
createdItem,
|
|
37
|
+
);
|
|
38
|
+
})
|
|
39
|
+
.then(async () => {
|
|
40
|
+
await PodmanHostOwnerRuleEngineService.applyRulesToPodmanHost(
|
|
41
|
+
createdItem,
|
|
42
|
+
);
|
|
43
|
+
})
|
|
44
|
+
.catch((error: Error) => {
|
|
45
|
+
logger.error(
|
|
46
|
+
`Error applying podman host rules in PodmanHostService.onCreateSuccess: ${error}`,
|
|
47
|
+
{
|
|
48
|
+
projectId: createdItem.projectId?.toString(),
|
|
49
|
+
podmanHostId: createdItem.id?.toString(),
|
|
50
|
+
} as LogAttributes,
|
|
51
|
+
);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
return createdItem;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@CaptureSpan()
|
|
58
|
+
public async findOrCreateByHostIdentifier(data: {
|
|
59
|
+
projectId: ObjectID;
|
|
60
|
+
hostIdentifier: string;
|
|
61
|
+
}): Promise<Model> {
|
|
62
|
+
/*
|
|
63
|
+
* Canonicalize + look up case-insensitively. A Podman host is keyed by
|
|
64
|
+
* the OTel `host.name` resource attribute (see autoDiscoverPodmanHost),
|
|
65
|
+
* whose casing is not stable — Windows surfaces PRIMARY01 vs primary01
|
|
66
|
+
* across resource detectors. Ingest already canonicalizes host.name
|
|
67
|
+
* (OtelIngestBaseService.normalizeHostNameAttributesInPlace); we repeat
|
|
68
|
+
* it here so the method is correct for any caller. A case-sensitive
|
|
69
|
+
* lookup would miss an existing row, then fail to create it because the
|
|
70
|
+
* unique guard (checkUniqueColumnBy -> findWithSameText) compares
|
|
71
|
+
* case-insensitively, wedging ingest for that host. Mirrors HostService.
|
|
72
|
+
*/
|
|
73
|
+
const hostIdentifier: string = data.hostIdentifier.trim().toLowerCase();
|
|
74
|
+
|
|
75
|
+
const existingHost: Model | null = await this.findOneBy({
|
|
76
|
+
query: {
|
|
77
|
+
projectId: data.projectId,
|
|
78
|
+
hostIdentifier: QueryHelper.findWithSameText(hostIdentifier),
|
|
79
|
+
},
|
|
80
|
+
select: {
|
|
81
|
+
_id: true,
|
|
82
|
+
projectId: true,
|
|
83
|
+
hostIdentifier: true,
|
|
84
|
+
},
|
|
85
|
+
props: {
|
|
86
|
+
isRoot: true,
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
if (existingHost) {
|
|
91
|
+
/*
|
|
92
|
+
* Converge a legacy mixed-case identifier onto the canonical form so
|
|
93
|
+
* the stored resource.host.name (canonicalized at ingest) keeps
|
|
94
|
+
* matching the Podman-host detail page filter. Best-effort — never
|
|
95
|
+
* block ingest on it. Updates don't re-run the unique guard.
|
|
96
|
+
*/
|
|
97
|
+
if (
|
|
98
|
+
existingHost._id &&
|
|
99
|
+
existingHost.hostIdentifier &&
|
|
100
|
+
existingHost.hostIdentifier !== hostIdentifier
|
|
101
|
+
) {
|
|
102
|
+
try {
|
|
103
|
+
await this.updateOneById({
|
|
104
|
+
id: new ObjectID(existingHost._id.toString()),
|
|
105
|
+
data: {
|
|
106
|
+
hostIdentifier: hostIdentifier,
|
|
107
|
+
},
|
|
108
|
+
props: {
|
|
109
|
+
isRoot: true,
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
existingHost.hostIdentifier = hostIdentifier;
|
|
113
|
+
} catch (err) {
|
|
114
|
+
logger.warn(
|
|
115
|
+
`PodmanHostService: failed to canonicalize hostIdentifier for host ${existingHost._id.toString()}: ${
|
|
116
|
+
err instanceof Error ? err.message : String(err)
|
|
117
|
+
}`,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return existingHost;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
// Create new host
|
|
127
|
+
const newHost: Model = new Model();
|
|
128
|
+
newHost.projectId = data.projectId;
|
|
129
|
+
newHost.name = hostIdentifier;
|
|
130
|
+
newHost.hostIdentifier = hostIdentifier;
|
|
131
|
+
newHost.otelCollectorStatus = "connected";
|
|
132
|
+
newHost.lastSeenAt = OneUptimeDate.getCurrentDate();
|
|
133
|
+
|
|
134
|
+
const createdHost: Model = await this.create({
|
|
135
|
+
data: newHost,
|
|
136
|
+
props: {
|
|
137
|
+
isRoot: true,
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
return createdHost;
|
|
142
|
+
} catch {
|
|
143
|
+
/*
|
|
144
|
+
* Either two ingest workers raced to create the same host, or a host
|
|
145
|
+
* with this identifier in a different case already existed and the
|
|
146
|
+
* unique guard rejected the insert. Re-resolve case-insensitively so
|
|
147
|
+
* the caller still gets the existing row instead of throwing.
|
|
148
|
+
*/
|
|
149
|
+
const reFetchedHost: Model | null = await this.findOneBy({
|
|
150
|
+
query: {
|
|
151
|
+
projectId: data.projectId,
|
|
152
|
+
hostIdentifier: QueryHelper.findWithSameText(hostIdentifier),
|
|
153
|
+
},
|
|
154
|
+
select: {
|
|
155
|
+
_id: true,
|
|
156
|
+
projectId: true,
|
|
157
|
+
hostIdentifier: true,
|
|
158
|
+
},
|
|
159
|
+
props: {
|
|
160
|
+
isRoot: true,
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
if (reFetchedHost) {
|
|
165
|
+
return reFetchedHost;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
throw new Error(
|
|
169
|
+
"Failed to create or find Podman host: " + hostIdentifier,
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
@CaptureSpan()
|
|
175
|
+
public async updateLastSeen(
|
|
176
|
+
hostId: ObjectID,
|
|
177
|
+
extra?: {
|
|
178
|
+
osType?: string | undefined;
|
|
179
|
+
osVersion?: string | undefined;
|
|
180
|
+
agentVersion?: string | undefined;
|
|
181
|
+
},
|
|
182
|
+
): Promise<void> {
|
|
183
|
+
const cacheKey: string = hostId.toString();
|
|
184
|
+
const extrasFingerprint: string = crypto
|
|
185
|
+
.createHash("sha1")
|
|
186
|
+
.update(
|
|
187
|
+
JSON.stringify({
|
|
188
|
+
osType: extra?.osType ?? null,
|
|
189
|
+
osVersion: extra?.osVersion ?? null,
|
|
190
|
+
agentVersion: extra?.agentVersion ?? null,
|
|
191
|
+
}),
|
|
192
|
+
)
|
|
193
|
+
.digest("hex");
|
|
194
|
+
|
|
195
|
+
const cached: string | null = await GlobalCache.getString(
|
|
196
|
+
LAST_SEEN_CACHE_NAMESPACE,
|
|
197
|
+
cacheKey,
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
if (cached === extrasFingerprint) {
|
|
201
|
+
return; // same data was written recently
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
await GlobalCache.setString(
|
|
205
|
+
LAST_SEEN_CACHE_NAMESPACE,
|
|
206
|
+
cacheKey,
|
|
207
|
+
extrasFingerprint,
|
|
208
|
+
{ expiresInSeconds: LAST_SEEN_THROTTLE_SECONDS },
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
212
|
+
const data: any = {
|
|
213
|
+
lastSeenAt: OneUptimeDate.getCurrentDate(),
|
|
214
|
+
otelCollectorStatus: "connected",
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
if (extra?.osType) {
|
|
218
|
+
data.osType = extra.osType;
|
|
219
|
+
}
|
|
220
|
+
if (extra?.osVersion) {
|
|
221
|
+
data.osVersion = extra.osVersion;
|
|
222
|
+
}
|
|
223
|
+
if (extra?.agentVersion) {
|
|
224
|
+
data.agentVersion = extra.agentVersion;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
await this.updateOneById({
|
|
228
|
+
id: hostId,
|
|
229
|
+
data: data,
|
|
230
|
+
props: {
|
|
231
|
+
isRoot: true,
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Additively attach labels to a Podman host. Existing labels are
|
|
238
|
+
* never removed — manual labels set via the UI survive ingest. The
|
|
239
|
+
* set of labelIds passed in is fingerprinted and cached for 60s so
|
|
240
|
+
* the common case (steady-state collector pushing the same label
|
|
241
|
+
* set every batch) costs one in-memory lookup, not a join-table
|
|
242
|
+
* scan.
|
|
243
|
+
*/
|
|
244
|
+
@CaptureSpan()
|
|
245
|
+
public async attachLabels(data: {
|
|
246
|
+
podmanHostId: ObjectID;
|
|
247
|
+
labelIds: Array<ObjectID>;
|
|
248
|
+
}): Promise<void> {
|
|
249
|
+
if (!data.labelIds || data.labelIds.length === 0) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const cacheKey: string = data.podmanHostId.toString();
|
|
254
|
+
const fingerprint: string = fingerprintLabelIds(data.labelIds);
|
|
255
|
+
const cached: string | null = await GlobalCache.getString(
|
|
256
|
+
LABELS_APPLIED_CACHE_NAMESPACE,
|
|
257
|
+
cacheKey,
|
|
258
|
+
);
|
|
259
|
+
if (cached === fingerprint) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
try {
|
|
264
|
+
const podmanHostIdStr: string = data.podmanHostId.toString();
|
|
265
|
+
const existingLabels: Array<Label> = await this.getRepository()
|
|
266
|
+
.createQueryBuilder()
|
|
267
|
+
.relation(Model, "labels")
|
|
268
|
+
.of(podmanHostIdStr)
|
|
269
|
+
.loadMany();
|
|
270
|
+
|
|
271
|
+
const existingIds: Set<string> = new Set();
|
|
272
|
+
for (const lbl of existingLabels) {
|
|
273
|
+
const idStr: string | undefined = lbl._id?.toString();
|
|
274
|
+
if (idStr) {
|
|
275
|
+
existingIds.add(idStr);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const toAddIds: Array<string> = [];
|
|
280
|
+
const seen: Set<string> = new Set();
|
|
281
|
+
for (const id of data.labelIds) {
|
|
282
|
+
const idStr: string = id.toString();
|
|
283
|
+
if (existingIds.has(idStr) || seen.has(idStr)) {
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
seen.add(idStr);
|
|
287
|
+
toAddIds.push(idStr);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (toAddIds.length > 0) {
|
|
291
|
+
await this.getRepository()
|
|
292
|
+
.createQueryBuilder()
|
|
293
|
+
.relation(Model, "labels")
|
|
294
|
+
.of(podmanHostIdStr)
|
|
295
|
+
.add(toAddIds);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
await GlobalCache.setString(
|
|
299
|
+
LABELS_APPLIED_CACHE_NAMESPACE,
|
|
300
|
+
cacheKey,
|
|
301
|
+
fingerprint,
|
|
302
|
+
{ expiresInSeconds: LABELS_APPLIED_CACHE_TTL_SECONDS },
|
|
303
|
+
);
|
|
304
|
+
} catch (err) {
|
|
305
|
+
logger.warn(
|
|
306
|
+
`PodmanHostService.attachLabels failed for podman host ${data.podmanHostId.toString()}: ${
|
|
307
|
+
err instanceof Error ? err.message : String(err)
|
|
308
|
+
}`,
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
@CaptureSpan()
|
|
314
|
+
public async markDisconnectedHosts(): Promise<void> {
|
|
315
|
+
/*
|
|
316
|
+
* Threshold must stay well above the 5-minute OTel ingest
|
|
317
|
+
* maintenance fence (MAINTENANCE_FENCE_TTL_SECONDS in
|
|
318
|
+
* OtelIngestBaseService) — lastSeenAt is legitimately up to
|
|
319
|
+
* ~5 minutes stale during continuous telemetry, so a threshold
|
|
320
|
+
* equal to the fence TTL flaps healthy resources. 15 minutes
|
|
321
|
+
* gives 3x headroom.
|
|
322
|
+
*/
|
|
323
|
+
const fifteenMinutesAgo: Date = OneUptimeDate.addRemoveMinutes(
|
|
324
|
+
OneUptimeDate.getCurrentDate(),
|
|
325
|
+
-15,
|
|
326
|
+
);
|
|
327
|
+
|
|
328
|
+
const connectedHosts: Array<Model> = await this.findBy({
|
|
329
|
+
query: {
|
|
330
|
+
otelCollectorStatus: "connected",
|
|
331
|
+
lastSeenAt: QueryHelper.lessThan(fifteenMinutesAgo),
|
|
332
|
+
},
|
|
333
|
+
select: {
|
|
334
|
+
_id: true,
|
|
335
|
+
},
|
|
336
|
+
limit: LIMIT_MAX,
|
|
337
|
+
skip: 0,
|
|
338
|
+
props: {
|
|
339
|
+
isRoot: true,
|
|
340
|
+
},
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
for (const host of connectedHosts) {
|
|
344
|
+
if (host._id) {
|
|
345
|
+
await this.updateOneById({
|
|
346
|
+
id: new ObjectID(host._id.toString()),
|
|
347
|
+
data: {
|
|
348
|
+
otelCollectorStatus: "disconnected",
|
|
349
|
+
},
|
|
350
|
+
props: {
|
|
351
|
+
isRoot: true,
|
|
352
|
+
},
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function fingerprintLabelIds(labelIds: Array<ObjectID>): string {
|
|
360
|
+
const sorted: Array<string> = labelIds
|
|
361
|
+
.map((id: ObjectID) => {
|
|
362
|
+
return id.toString();
|
|
363
|
+
})
|
|
364
|
+
.sort();
|
|
365
|
+
return crypto.createHash("sha1").update(sorted.join(",")).digest("hex");
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export default new Service();
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import DatabaseService from "./DatabaseService";
|
|
2
|
+
import Model from "../../Models/DatabaseModels/PodmanResource";
|
|
3
|
+
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
4
|
+
import ObjectID from "../../Types/ObjectID";
|
|
5
|
+
import OneUptimeDate from "../../Types/Date";
|
|
6
|
+
import { JSONObject } from "../../Types/JSON";
|
|
7
|
+
import logger from "../Utils/Logger";
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
* ------------------------------------------------------------------
|
|
11
|
+
* PodmanResourceService
|
|
12
|
+
*
|
|
13
|
+
* Writes and reads the Podman inventory table populated by the
|
|
14
|
+
* telemetry ingest path. Container rows are upserted from the
|
|
15
|
+
* docker_stats receiver metric stream — every container.* metric
|
|
16
|
+
* carries container.id / container.name / container.image.name
|
|
17
|
+
* resource attributes, which is enough to maintain a live inventory
|
|
18
|
+
* of running containers per host without any agent-side change.
|
|
19
|
+
*
|
|
20
|
+
* Image / Network / Volume kinds are reserved for a follow-up agent
|
|
21
|
+
* change that adds a snapshot poller; the schema is ready for them.
|
|
22
|
+
*
|
|
23
|
+
* Rows are hard-deleted once lastSeenAt falls behind the staleness
|
|
24
|
+
* threshold (default: 15 min) so containers that stopped emitting
|
|
25
|
+
* metrics fall off the list automatically.
|
|
26
|
+
* ------------------------------------------------------------------
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
export interface ParsedPodmanContainer {
|
|
30
|
+
containerName: string;
|
|
31
|
+
containerId: string | null;
|
|
32
|
+
imageName: string | null;
|
|
33
|
+
state: string;
|
|
34
|
+
cpuPercent: number | null;
|
|
35
|
+
memoryBytes: number | null;
|
|
36
|
+
observedAt: Date;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface ParsedPodmanResource {
|
|
40
|
+
kind: string;
|
|
41
|
+
name: string;
|
|
42
|
+
containerId: string | null;
|
|
43
|
+
imageName: string | null;
|
|
44
|
+
state: string | null;
|
|
45
|
+
labels: JSONObject | null;
|
|
46
|
+
resourceCreationTimestamp: Date | null;
|
|
47
|
+
lastSeenAt: Date;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface PodmanHostInventoryCounts {
|
|
51
|
+
containersRunning: number;
|
|
52
|
+
containersStopped: number;
|
|
53
|
+
containersPaused: number;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const UPSERT_BATCH_SIZE: number = 500;
|
|
57
|
+
const STALE_DELETE_WARN_THRESHOLD: number = 100;
|
|
58
|
+
|
|
59
|
+
export class Service extends DatabaseService<Model> {
|
|
60
|
+
public constructor() {
|
|
61
|
+
super(Model);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Upsert a batch of Container rows for a single (project, host)
|
|
66
|
+
* pair. Uses ON CONFLICT on the UNIQUE (projectId, podmanHostId,
|
|
67
|
+
* kind, name) index with a dominance guard on lastSeenAt so
|
|
68
|
+
* out-of-order ingest never regresses a newer observation.
|
|
69
|
+
*
|
|
70
|
+
* Containers are upserted from metric snapshots (no separate
|
|
71
|
+
* inventory snapshot path), so this also writes
|
|
72
|
+
* latestCpuPercent / latestMemoryBytes / metricsUpdatedAt in the
|
|
73
|
+
* same statement — saves a round trip vs. the K8s pattern of
|
|
74
|
+
* upsert-then-update.
|
|
75
|
+
*/
|
|
76
|
+
@CaptureSpan()
|
|
77
|
+
public async bulkUpsertContainers(data: {
|
|
78
|
+
projectId: ObjectID;
|
|
79
|
+
podmanHostId: ObjectID;
|
|
80
|
+
containers: Array<ParsedPodmanContainer>;
|
|
81
|
+
}): Promise<void> {
|
|
82
|
+
if (data.containers.length === 0) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
for (
|
|
87
|
+
let i: number = 0;
|
|
88
|
+
i < data.containers.length;
|
|
89
|
+
i += UPSERT_BATCH_SIZE
|
|
90
|
+
) {
|
|
91
|
+
const chunk: Array<ParsedPodmanContainer> = data.containers.slice(
|
|
92
|
+
i,
|
|
93
|
+
i + UPSERT_BATCH_SIZE,
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const valueFragments: Array<string> = [];
|
|
97
|
+
const params: Array<unknown> = [];
|
|
98
|
+
let p: number = 1;
|
|
99
|
+
|
|
100
|
+
for (const c of chunk) {
|
|
101
|
+
valueFragments.push(
|
|
102
|
+
`($${p++}, $${p++}, $${p++}, $${p++}, $${p++}, $${p++}, $${p++}, $${p++}::numeric, $${p++}::bigint, $${p++}::timestamptz, $${p++}::timestamptz, $${p++})`,
|
|
103
|
+
);
|
|
104
|
+
params.push(
|
|
105
|
+
data.projectId.toString(),
|
|
106
|
+
data.podmanHostId.toString(),
|
|
107
|
+
"Container",
|
|
108
|
+
c.containerName,
|
|
109
|
+
c.containerId,
|
|
110
|
+
c.imageName,
|
|
111
|
+
c.state,
|
|
112
|
+
c.cpuPercent !== null && c.cpuPercent !== undefined
|
|
113
|
+
? c.cpuPercent
|
|
114
|
+
: null,
|
|
115
|
+
c.memoryBytes !== null && c.memoryBytes !== undefined
|
|
116
|
+
? Math.trunc(c.memoryBytes).toString()
|
|
117
|
+
: null,
|
|
118
|
+
c.observedAt,
|
|
119
|
+
c.observedAt,
|
|
120
|
+
0, // version (BaseModel @VersionColumn)
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const sql: string = `
|
|
125
|
+
INSERT INTO "PodmanResource" (
|
|
126
|
+
"projectId", "podmanHostId", "kind", "name",
|
|
127
|
+
"containerId", "imageName", "state",
|
|
128
|
+
"latestCpuPercent", "latestMemoryBytes",
|
|
129
|
+
"metricsUpdatedAt", "lastSeenAt", "version"
|
|
130
|
+
)
|
|
131
|
+
VALUES ${valueFragments.join(", ")}
|
|
132
|
+
ON CONFLICT ("projectId", "podmanHostId", "kind", "name")
|
|
133
|
+
DO UPDATE SET
|
|
134
|
+
"containerId" = COALESCE(EXCLUDED."containerId", "PodmanResource"."containerId"),
|
|
135
|
+
"imageName" = COALESCE(EXCLUDED."imageName", "PodmanResource"."imageName"),
|
|
136
|
+
"state" = EXCLUDED."state",
|
|
137
|
+
"latestCpuPercent" = COALESCE(EXCLUDED."latestCpuPercent", "PodmanResource"."latestCpuPercent"),
|
|
138
|
+
"latestMemoryBytes" = COALESCE(EXCLUDED."latestMemoryBytes", "PodmanResource"."latestMemoryBytes"),
|
|
139
|
+
"metricsUpdatedAt" = EXCLUDED."metricsUpdatedAt",
|
|
140
|
+
"lastSeenAt" = EXCLUDED."lastSeenAt",
|
|
141
|
+
"updatedAt" = now()
|
|
142
|
+
WHERE EXCLUDED."lastSeenAt" >= "PodmanResource"."lastSeenAt"
|
|
143
|
+
`;
|
|
144
|
+
|
|
145
|
+
await this.getRepository().manager.query(sql, params);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Upsert a batch of resources for any kind. Used by the snapshot
|
|
151
|
+
* ingest path (Container / Image / Network / Volume rows from the
|
|
152
|
+
* Podman agent's inventory poller). Container rows from this path
|
|
153
|
+
* carry full state (running / exited / paused / restarting / dead /
|
|
154
|
+
* created), unlike the metric-derived path which only sees running
|
|
155
|
+
* containers.
|
|
156
|
+
*/
|
|
157
|
+
@CaptureSpan()
|
|
158
|
+
public async bulkUpsert(data: {
|
|
159
|
+
projectId: ObjectID;
|
|
160
|
+
podmanHostId: ObjectID;
|
|
161
|
+
resources: Array<ParsedPodmanResource>;
|
|
162
|
+
}): Promise<void> {
|
|
163
|
+
if (data.resources.length === 0) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
for (let i: number = 0; i < data.resources.length; i += UPSERT_BATCH_SIZE) {
|
|
168
|
+
const chunk: Array<ParsedPodmanResource> = data.resources.slice(
|
|
169
|
+
i,
|
|
170
|
+
i + UPSERT_BATCH_SIZE,
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
const valueFragments: Array<string> = [];
|
|
174
|
+
const params: Array<unknown> = [];
|
|
175
|
+
let p: number = 1;
|
|
176
|
+
|
|
177
|
+
for (const r of chunk) {
|
|
178
|
+
valueFragments.push(
|
|
179
|
+
`($${p++}, $${p++}, $${p++}, $${p++}, $${p++}, $${p++}, $${p++}, $${p++}, $${p++}::timestamptz, $${p++}::timestamptz, $${p++})`,
|
|
180
|
+
);
|
|
181
|
+
params.push(
|
|
182
|
+
data.projectId.toString(),
|
|
183
|
+
data.podmanHostId.toString(),
|
|
184
|
+
r.kind,
|
|
185
|
+
r.name,
|
|
186
|
+
r.containerId,
|
|
187
|
+
r.imageName,
|
|
188
|
+
r.state,
|
|
189
|
+
r.labels ? JSON.stringify(r.labels) : null,
|
|
190
|
+
r.resourceCreationTimestamp,
|
|
191
|
+
r.lastSeenAt,
|
|
192
|
+
0, // version
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const sql: string = `
|
|
197
|
+
INSERT INTO "PodmanResource" (
|
|
198
|
+
"projectId", "podmanHostId", "kind", "name",
|
|
199
|
+
"containerId", "imageName", "state", "labels",
|
|
200
|
+
"resourceCreationTimestamp", "lastSeenAt", "version"
|
|
201
|
+
)
|
|
202
|
+
VALUES ${valueFragments.join(", ")}
|
|
203
|
+
ON CONFLICT ("projectId", "podmanHostId", "kind", "name")
|
|
204
|
+
DO UPDATE SET
|
|
205
|
+
"containerId" = COALESCE(EXCLUDED."containerId", "PodmanResource"."containerId"),
|
|
206
|
+
"imageName" = COALESCE(EXCLUDED."imageName", "PodmanResource"."imageName"),
|
|
207
|
+
"state" = COALESCE(EXCLUDED."state", "PodmanResource"."state"),
|
|
208
|
+
"labels" = COALESCE(EXCLUDED."labels", "PodmanResource"."labels"),
|
|
209
|
+
"resourceCreationTimestamp" = COALESCE(EXCLUDED."resourceCreationTimestamp", "PodmanResource"."resourceCreationTimestamp"),
|
|
210
|
+
"lastSeenAt" = EXCLUDED."lastSeenAt",
|
|
211
|
+
"updatedAt" = now()
|
|
212
|
+
WHERE EXCLUDED."lastSeenAt" >= "PodmanResource"."lastSeenAt"
|
|
213
|
+
`;
|
|
214
|
+
|
|
215
|
+
await this.getRepository().manager.query(sql, params);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Hard-delete all resources on a host whose last observation is
|
|
221
|
+
* older than olderThan. Returns the number of deleted rows.
|
|
222
|
+
*/
|
|
223
|
+
@CaptureSpan()
|
|
224
|
+
public async deleteStaleForHost(data: {
|
|
225
|
+
podmanHostId: ObjectID;
|
|
226
|
+
olderThan: Date;
|
|
227
|
+
}): Promise<number> {
|
|
228
|
+
const result: Array<{ affected?: number }> | { affected?: number } =
|
|
229
|
+
await this.getRepository().manager.query(
|
|
230
|
+
`DELETE FROM "PodmanResource" WHERE "podmanHostId" = $1 AND "lastSeenAt" < $2`,
|
|
231
|
+
[data.podmanHostId.toString(), data.olderThan],
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
let affected: number = 0;
|
|
235
|
+
if (Array.isArray(result) && result.length >= 2) {
|
|
236
|
+
const second: unknown = (result as Array<unknown>)[1];
|
|
237
|
+
if (typeof second === "number") {
|
|
238
|
+
affected = second;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (affected > STALE_DELETE_WARN_THRESHOLD) {
|
|
243
|
+
logger.warn(
|
|
244
|
+
`PodmanResource cleanup deleted ${affected} stale rows for host ${data.podmanHostId.toString()} — larger than expected; investigate agent health.`,
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return affected;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Compute container state breakdowns for a single host from the
|
|
253
|
+
* inventory table. Used by the cleanup worker to refresh the cached
|
|
254
|
+
* counts on PodmanHost so the Hosts page / dashboard widget shows
|
|
255
|
+
* accurate numbers without needing a SQL aggregation per render.
|
|
256
|
+
*/
|
|
257
|
+
@CaptureSpan()
|
|
258
|
+
public async getContainerCountsForHost(data: {
|
|
259
|
+
projectId: ObjectID;
|
|
260
|
+
podmanHostId: ObjectID;
|
|
261
|
+
}): Promise<PodmanHostInventoryCounts> {
|
|
262
|
+
const rows: Array<{
|
|
263
|
+
running: string;
|
|
264
|
+
stopped: string;
|
|
265
|
+
paused: string;
|
|
266
|
+
}> = await this.getRepository().manager.query(
|
|
267
|
+
`SELECT
|
|
268
|
+
COUNT(*) FILTER (WHERE LOWER("state") = 'running')::text AS "running",
|
|
269
|
+
COUNT(*) FILTER (WHERE LOWER("state") IN ('exited', 'dead', 'created'))::text AS "stopped",
|
|
270
|
+
COUNT(*) FILTER (WHERE LOWER("state") = 'paused')::text AS "paused"
|
|
271
|
+
FROM "PodmanResource"
|
|
272
|
+
WHERE "projectId" = $1
|
|
273
|
+
AND "podmanHostId" = $2
|
|
274
|
+
AND "kind" = 'Container'
|
|
275
|
+
AND "deletedAt" IS NULL`,
|
|
276
|
+
[data.projectId.toString(), data.podmanHostId.toString()],
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
const row:
|
|
280
|
+
| { running: string; stopped: string; paused: string }
|
|
281
|
+
| undefined = rows[0];
|
|
282
|
+
return {
|
|
283
|
+
containersRunning: row ? parseInt(row.running, 10) || 0 : 0,
|
|
284
|
+
containersStopped: row ? parseInt(row.stopped, 10) || 0 : 0,
|
|
285
|
+
containersPaused: row ? parseInt(row.paused, 10) || 0 : 0,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
public getStaleThresholdDate(nowOverride?: Date): Date {
|
|
290
|
+
const minutes: number = this.getStaleThresholdMinutes();
|
|
291
|
+
return OneUptimeDate.addRemoveMinutes(
|
|
292
|
+
nowOverride || OneUptimeDate.getCurrentDate(),
|
|
293
|
+
-minutes,
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
public getStaleThresholdMinutes(): number {
|
|
298
|
+
const raw: string | undefined =
|
|
299
|
+
process.env["PODMAN_INVENTORY_STALE_MINUTES"];
|
|
300
|
+
if (raw) {
|
|
301
|
+
const parsed: number = parseInt(raw, 10);
|
|
302
|
+
if (!isNaN(parsed) && parsed >= 5) {
|
|
303
|
+
return parsed;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return 15;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export default new Service();
|