@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.
Files changed (344) hide show
  1. package/Models/DatabaseModels/Alert.ts +166 -0
  2. package/Models/DatabaseModels/AlertLabelRule.ts +38 -0
  3. package/Models/DatabaseModels/AlertOwnerRule.ts +38 -0
  4. package/Models/DatabaseModels/DockerSwarmCluster.ts +989 -0
  5. package/Models/DatabaseModels/DockerSwarmClusterLabelRule.ts +514 -0
  6. package/Models/DatabaseModels/DockerSwarmClusterOwnerRule.ts +596 -0
  7. package/Models/DatabaseModels/DockerSwarmClusterOwnerTeam.ts +487 -0
  8. package/Models/DatabaseModels/DockerSwarmClusterOwnerUser.ts +486 -0
  9. package/Models/DatabaseModels/DockerSwarmResource.ts +750 -0
  10. package/Models/DatabaseModels/Incident.ts +166 -0
  11. package/Models/DatabaseModels/IncidentLabelRule.ts +38 -0
  12. package/Models/DatabaseModels/IncidentOwnerRule.ts +38 -0
  13. package/Models/DatabaseModels/IncidentTemplate.ts +56 -0
  14. package/Models/DatabaseModels/Index.ts +24 -0
  15. package/Models/DatabaseModels/PodmanHost.ts +859 -0
  16. package/Models/DatabaseModels/PodmanHostLabelRule.ts +514 -0
  17. package/Models/DatabaseModels/PodmanHostOwnerRule.ts +596 -0
  18. package/Models/DatabaseModels/PodmanHostOwnerTeam.ts +487 -0
  19. package/Models/DatabaseModels/PodmanHostOwnerUser.ts +486 -0
  20. package/Models/DatabaseModels/PodmanResource.ts +498 -0
  21. package/Models/DatabaseModels/ScheduledMaintenance.ts +110 -0
  22. package/Models/DatabaseModels/ScheduledMaintenanceLabelRule.ts +38 -0
  23. package/Models/DatabaseModels/ScheduledMaintenanceOwnerRule.ts +38 -0
  24. package/Models/DatabaseModels/ScheduledMaintenanceTemplate.ts +56 -0
  25. package/Models/DatabaseModels/TelemetryException.ts +2 -0
  26. package/Server/API/DashboardAPI.ts +89 -0
  27. package/Server/API/DockerSwarmResourceAPI.ts +137 -0
  28. package/Server/API/TelemetryAPI.ts +8 -1
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1781587937032-MigrationName.ts +3199 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  31. package/Server/Services/AlertLabelRuleEngineService.ts +29 -0
  32. package/Server/Services/AlertOwnerRuleEngineService.ts +67 -0
  33. package/Server/Services/DockerSwarmClusterLabelRuleEngineService.ts +214 -0
  34. package/Server/Services/DockerSwarmClusterLabelRuleService.ts +14 -0
  35. package/Server/Services/DockerSwarmClusterOwnerRuleEngineService.ts +232 -0
  36. package/Server/Services/DockerSwarmClusterOwnerRuleService.ts +14 -0
  37. package/Server/Services/DockerSwarmClusterOwnerTeamService.ts +10 -0
  38. package/Server/Services/DockerSwarmClusterOwnerUserService.ts +10 -0
  39. package/Server/Services/DockerSwarmClusterService.ts +404 -0
  40. package/Server/Services/DockerSwarmResourceService.ts +381 -0
  41. package/Server/Services/ExceptionAggregationService.ts +1 -0
  42. package/Server/Services/IncidentLabelRuleEngineService.ts +27 -0
  43. package/Server/Services/IncidentOwnerRuleEngineService.ts +67 -0
  44. package/Server/Services/IncidentService.ts +11 -0
  45. package/Server/Services/Index.ts +14 -0
  46. package/Server/Services/LogAggregationService.ts +1 -0
  47. package/Server/Services/MetricAggregationService.ts +1 -0
  48. package/Server/Services/OpenTelemetryIngestService.ts +37 -0
  49. package/Server/Services/PodmanHostLabelRuleEngineService.ts +198 -0
  50. package/Server/Services/PodmanHostLabelRuleService.ts +14 -0
  51. package/Server/Services/PodmanHostOwnerRuleEngineService.ts +216 -0
  52. package/Server/Services/PodmanHostOwnerRuleService.ts +14 -0
  53. package/Server/Services/PodmanHostOwnerTeamService.ts +10 -0
  54. package/Server/Services/PodmanHostOwnerUserService.ts +10 -0
  55. package/Server/Services/PodmanHostService.ts +368 -0
  56. package/Server/Services/PodmanResourceService.ts +310 -0
  57. package/Server/Services/ScheduledMaintenanceLabelRuleEngineService.ts +29 -0
  58. package/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.ts +67 -0
  59. package/Server/Services/TelemetryUsageBillingService.ts +18 -0
  60. package/Server/Services/TraceAggregationService.ts +1 -0
  61. package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +13 -0
  62. package/Server/Utils/Monitor/MonitorAlert.ts +10 -0
  63. package/Server/Utils/Monitor/MonitorClusterContext.ts +35 -6
  64. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +306 -0
  65. package/Server/Utils/Monitor/MonitorIncident.ts +45 -0
  66. package/Server/Utils/Monitor/MonitorMaintenanceSuppression.ts +17 -0
  67. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +3 -0
  68. package/Server/Utils/Monitor/SeriesResourceLabels.ts +26 -0
  69. package/Server/Utils/Telemetry/ResourceFacetResolver.ts +49 -0
  70. package/Server/Utils/Telemetry/Telemetry.ts +10 -0
  71. package/Server/Utils/Telemetry/TelemetryEntity.ts +22 -0
  72. package/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.ts +1 -0
  73. package/Tests/Types/DockerSwarm/DockerSwarmInventoryExtractor.test.ts +667 -0
  74. package/Tests/Types/Monitor/DockerSwarmAlertTemplates.test.ts +528 -0
  75. package/Types/Dashboard/DashboardComponentType.ts +7 -0
  76. package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +2 -0
  77. package/Types/Dashboard/DashboardComponents/DashboardDockerSwarmNodeListComponent.ts +17 -0
  78. package/Types/Dashboard/DashboardComponents/DashboardDockerSwarmServiceListComponent.ts +17 -0
  79. package/Types/Dashboard/DashboardComponents/DashboardPodmanContainerListComponent.ts +16 -0
  80. package/Types/Dashboard/DashboardComponents/DashboardPodmanHostListComponent.ts +15 -0
  81. package/Types/Dashboard/DashboardComponents/DashboardPodmanImageListComponent.ts +16 -0
  82. package/Types/Dashboard/DashboardComponents/DashboardPodmanNetworkListComponent.ts +15 -0
  83. package/Types/Dashboard/DashboardComponents/DashboardPodmanVolumeListComponent.ts +15 -0
  84. package/Types/Dashboard/DashboardTemplates.ts +194 -0
  85. package/Types/DockerSwarm/DockerSwarmInventoryExtractor.ts +452 -0
  86. package/Types/Icon/IconProp.ts +1 -0
  87. package/Types/Monitor/DockerSwarmAlertTemplates.ts +461 -0
  88. package/Types/Monitor/DockerSwarmMetricCatalog.ts +139 -0
  89. package/Types/Monitor/HostAlertTemplates.ts +455 -0
  90. package/Types/Monitor/HostMetricCatalog.ts +177 -0
  91. package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +21 -0
  92. package/Types/Monitor/MonitorStep.ts +99 -0
  93. package/Types/Monitor/MonitorStepDockerSwarmMonitor.ts +74 -0
  94. package/Types/Monitor/MonitorStepHostMonitor.ts +30 -0
  95. package/Types/Monitor/MonitorStepPodmanMonitor.ts +38 -0
  96. package/Types/Monitor/MonitorType.ts +42 -0
  97. package/Types/Monitor/PodmanAlertTemplates.ts +507 -0
  98. package/Types/Monitor/PodmanMetricCatalog.ts +226 -0
  99. package/Types/Permission.ts +465 -4
  100. package/Types/Podman/PodmanInventoryExtractor.ts +343 -0
  101. package/Types/Telemetry/EntityType.ts +12 -0
  102. package/Types/Telemetry/ServiceType.ts +2 -0
  103. package/UI/Components/Icon/Icon.tsx +57 -0
  104. package/UI/Components/LogsViewer/LogsViewer.tsx +44 -1
  105. package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +28 -0
  106. package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +6 -0
  107. package/UI/Utils/TelemetryService.ts +1 -0
  108. package/Utils/Dashboard/Components/DashboardDockerSwarmNodeListComponent.ts +70 -0
  109. package/Utils/Dashboard/Components/DashboardDockerSwarmResourceListShared.ts +61 -0
  110. package/Utils/Dashboard/Components/DashboardDockerSwarmServiceListComponent.ts +71 -0
  111. package/Utils/Dashboard/Components/DashboardPodmanContainerListComponent.ts +100 -0
  112. package/Utils/Dashboard/Components/DashboardPodmanHostListComponent.ts +88 -0
  113. package/Utils/Dashboard/Components/DashboardPodmanImageListComponent.ts +97 -0
  114. package/Utils/Dashboard/Components/DashboardPodmanNetworkListComponent.ts +87 -0
  115. package/Utils/Dashboard/Components/DashboardPodmanVolumeListComponent.ts +87 -0
  116. package/Utils/Dashboard/Components/Index.ts +51 -0
  117. package/Utils/Telemetry/EntityKey.ts +18 -0
  118. package/build/dist/Models/DatabaseModels/Alert.js +162 -0
  119. package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
  120. package/build/dist/Models/DatabaseModels/AlertLabelRule.js +39 -0
  121. package/build/dist/Models/DatabaseModels/AlertLabelRule.js.map +1 -1
  122. package/build/dist/Models/DatabaseModels/AlertOwnerRule.js +39 -0
  123. package/build/dist/Models/DatabaseModels/AlertOwnerRule.js.map +1 -1
  124. package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js +1018 -0
  125. package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js.map +1 -0
  126. package/build/dist/Models/DatabaseModels/DockerSwarmClusterLabelRule.js +522 -0
  127. package/build/dist/Models/DatabaseModels/DockerSwarmClusterLabelRule.js.map +1 -0
  128. package/build/dist/Models/DatabaseModels/DockerSwarmClusterOwnerRule.js +603 -0
  129. package/build/dist/Models/DatabaseModels/DockerSwarmClusterOwnerRule.js.map +1 -0
  130. package/build/dist/Models/DatabaseModels/DockerSwarmClusterOwnerTeam.js +503 -0
  131. package/build/dist/Models/DatabaseModels/DockerSwarmClusterOwnerTeam.js.map +1 -0
  132. package/build/dist/Models/DatabaseModels/DockerSwarmClusterOwnerUser.js +502 -0
  133. package/build/dist/Models/DatabaseModels/DockerSwarmClusterOwnerUser.js.map +1 -0
  134. package/build/dist/Models/DatabaseModels/DockerSwarmResource.js +787 -0
  135. package/build/dist/Models/DatabaseModels/DockerSwarmResource.js.map +1 -0
  136. package/build/dist/Models/DatabaseModels/Incident.js +162 -0
  137. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  138. package/build/dist/Models/DatabaseModels/IncidentLabelRule.js +39 -0
  139. package/build/dist/Models/DatabaseModels/IncidentLabelRule.js.map +1 -1
  140. package/build/dist/Models/DatabaseModels/IncidentOwnerRule.js +39 -0
  141. package/build/dist/Models/DatabaseModels/IncidentOwnerRule.js.map +1 -1
  142. package/build/dist/Models/DatabaseModels/IncidentTemplate.js +54 -0
  143. package/build/dist/Models/DatabaseModels/IncidentTemplate.js.map +1 -1
  144. package/build/dist/Models/DatabaseModels/Index.js +24 -0
  145. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  146. package/build/dist/Models/DatabaseModels/PodmanHost.js +885 -0
  147. package/build/dist/Models/DatabaseModels/PodmanHost.js.map +1 -0
  148. package/build/dist/Models/DatabaseModels/PodmanHostLabelRule.js +522 -0
  149. package/build/dist/Models/DatabaseModels/PodmanHostLabelRule.js.map +1 -0
  150. package/build/dist/Models/DatabaseModels/PodmanHostOwnerRule.js +603 -0
  151. package/build/dist/Models/DatabaseModels/PodmanHostOwnerRule.js.map +1 -0
  152. package/build/dist/Models/DatabaseModels/PodmanHostOwnerTeam.js +503 -0
  153. package/build/dist/Models/DatabaseModels/PodmanHostOwnerTeam.js.map +1 -0
  154. package/build/dist/Models/DatabaseModels/PodmanHostOwnerUser.js +502 -0
  155. package/build/dist/Models/DatabaseModels/PodmanHostOwnerUser.js.map +1 -0
  156. package/build/dist/Models/DatabaseModels/PodmanResource.js +526 -0
  157. package/build/dist/Models/DatabaseModels/PodmanResource.js.map +1 -0
  158. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +108 -0
  159. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
  160. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceLabelRule.js +39 -0
  161. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceLabelRule.js.map +1 -1
  162. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceOwnerRule.js +39 -0
  163. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceOwnerRule.js.map +1 -1
  164. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplate.js +54 -0
  165. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplate.js.map +1 -1
  166. package/build/dist/Models/DatabaseModels/TelemetryException.js +2 -0
  167. package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
  168. package/build/dist/Server/API/DashboardAPI.js +89 -0
  169. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  170. package/build/dist/Server/API/DockerSwarmResourceAPI.js +100 -0
  171. package/build/dist/Server/API/DockerSwarmResourceAPI.js.map +1 -0
  172. package/build/dist/Server/API/TelemetryAPI.js +8 -1
  173. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  174. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781587937032-MigrationName.js +1100 -0
  175. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781587937032-MigrationName.js.map +1 -0
  176. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  177. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  178. package/build/dist/Server/Services/AlertLabelRuleEngineService.js +30 -4
  179. package/build/dist/Server/Services/AlertLabelRuleEngineService.js.map +1 -1
  180. package/build/dist/Server/Services/AlertOwnerRuleEngineService.js +62 -5
  181. package/build/dist/Server/Services/AlertOwnerRuleEngineService.js.map +1 -1
  182. package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js +168 -0
  183. package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js.map +1 -0
  184. package/build/dist/Server/Services/DockerSwarmClusterLabelRuleService.js +13 -0
  185. package/build/dist/Server/Services/DockerSwarmClusterLabelRuleService.js.map +1 -0
  186. package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js +188 -0
  187. package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js.map +1 -0
  188. package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleService.js +13 -0
  189. package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleService.js.map +1 -0
  190. package/build/dist/Server/Services/DockerSwarmClusterOwnerTeamService.js +9 -0
  191. package/build/dist/Server/Services/DockerSwarmClusterOwnerTeamService.js.map +1 -0
  192. package/build/dist/Server/Services/DockerSwarmClusterOwnerUserService.js +9 -0
  193. package/build/dist/Server/Services/DockerSwarmClusterOwnerUserService.js.map +1 -0
  194. package/build/dist/Server/Services/DockerSwarmClusterService.js +353 -0
  195. package/build/dist/Server/Services/DockerSwarmClusterService.js.map +1 -0
  196. package/build/dist/Server/Services/DockerSwarmResourceService.js +258 -0
  197. package/build/dist/Server/Services/DockerSwarmResourceService.js.map +1 -0
  198. package/build/dist/Server/Services/ExceptionAggregationService.js +1 -0
  199. package/build/dist/Server/Services/ExceptionAggregationService.js.map +1 -1
  200. package/build/dist/Server/Services/IncidentLabelRuleEngineService.js +28 -4
  201. package/build/dist/Server/Services/IncidentLabelRuleEngineService.js.map +1 -1
  202. package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js +62 -5
  203. package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js.map +1 -1
  204. package/build/dist/Server/Services/IncidentService.js +8 -0
  205. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  206. package/build/dist/Server/Services/Index.js +14 -0
  207. package/build/dist/Server/Services/Index.js.map +1 -1
  208. package/build/dist/Server/Services/LogAggregationService.js +1 -0
  209. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  210. package/build/dist/Server/Services/MetricAggregationService.js +1 -0
  211. package/build/dist/Server/Services/MetricAggregationService.js.map +1 -1
  212. package/build/dist/Server/Services/OpenTelemetryIngestService.js +43 -13
  213. package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
  214. package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js +166 -0
  215. package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js.map +1 -0
  216. package/build/dist/Server/Services/PodmanHostLabelRuleService.js +13 -0
  217. package/build/dist/Server/Services/PodmanHostLabelRuleService.js.map +1 -0
  218. package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js +186 -0
  219. package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js.map +1 -0
  220. package/build/dist/Server/Services/PodmanHostOwnerRuleService.js +13 -0
  221. package/build/dist/Server/Services/PodmanHostOwnerRuleService.js.map +1 -0
  222. package/build/dist/Server/Services/PodmanHostOwnerTeamService.js +9 -0
  223. package/build/dist/Server/Services/PodmanHostOwnerTeamService.js.map +1 -0
  224. package/build/dist/Server/Services/PodmanHostOwnerUserService.js +9 -0
  225. package/build/dist/Server/Services/PodmanHostOwnerUserService.js.map +1 -0
  226. package/build/dist/Server/Services/PodmanHostService.js +319 -0
  227. package/build/dist/Server/Services/PodmanHostService.js.map +1 -0
  228. package/build/dist/Server/Services/PodmanResourceService.js +196 -0
  229. package/build/dist/Server/Services/PodmanResourceService.js.map +1 -0
  230. package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js +30 -4
  231. package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js.map +1 -1
  232. package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js +62 -5
  233. package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js.map +1 -1
  234. package/build/dist/Server/Services/TelemetryUsageBillingService.js +13 -0
  235. package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
  236. package/build/dist/Server/Services/TraceAggregationService.js +1 -0
  237. package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
  238. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +13 -0
  239. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
  240. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +8 -0
  241. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  242. package/build/dist/Server/Utils/Monitor/MonitorClusterContext.js +35 -7
  243. package/build/dist/Server/Utils/Monitor/MonitorClusterContext.js.map +1 -1
  244. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +194 -0
  245. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  246. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +35 -1
  247. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  248. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js +9 -0
  249. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -1
  250. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +3 -0
  251. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  252. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +16 -0
  253. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
  254. package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js +30 -0
  255. package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js.map +1 -1
  256. package/build/dist/Server/Utils/Telemetry/Telemetry.js +6 -0
  257. package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
  258. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +18 -0
  259. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
  260. package/build/dist/Types/Dashboard/DashboardComponentType.js +7 -0
  261. package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
  262. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +2 -0
  263. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
  264. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDockerSwarmNodeListComponent.js +2 -0
  265. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDockerSwarmNodeListComponent.js.map +1 -0
  266. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDockerSwarmServiceListComponent.js +2 -0
  267. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDockerSwarmServiceListComponent.js.map +1 -0
  268. package/build/dist/Types/Dashboard/DashboardComponents/DashboardPodmanContainerListComponent.js +2 -0
  269. package/build/dist/Types/Dashboard/DashboardComponents/DashboardPodmanContainerListComponent.js.map +1 -0
  270. package/build/dist/Types/Dashboard/DashboardComponents/DashboardPodmanHostListComponent.js +2 -0
  271. package/build/dist/Types/Dashboard/DashboardComponents/DashboardPodmanHostListComponent.js.map +1 -0
  272. package/build/dist/Types/Dashboard/DashboardComponents/DashboardPodmanImageListComponent.js +2 -0
  273. package/build/dist/Types/Dashboard/DashboardComponents/DashboardPodmanImageListComponent.js.map +1 -0
  274. package/build/dist/Types/Dashboard/DashboardComponents/DashboardPodmanNetworkListComponent.js +2 -0
  275. package/build/dist/Types/Dashboard/DashboardComponents/DashboardPodmanNetworkListComponent.js.map +1 -0
  276. package/build/dist/Types/Dashboard/DashboardComponents/DashboardPodmanVolumeListComponent.js +2 -0
  277. package/build/dist/Types/Dashboard/DashboardComponents/DashboardPodmanVolumeListComponent.js.map +1 -0
  278. package/build/dist/Types/Dashboard/DashboardTemplates.js +168 -0
  279. package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
  280. package/build/dist/Types/DockerSwarm/DockerSwarmInventoryExtractor.js +359 -0
  281. package/build/dist/Types/DockerSwarm/DockerSwarmInventoryExtractor.js.map +1 -0
  282. package/build/dist/Types/Icon/IconProp.js +1 -0
  283. package/build/dist/Types/Icon/IconProp.js.map +1 -1
  284. package/build/dist/Types/Monitor/DockerSwarmAlertTemplates.js +358 -0
  285. package/build/dist/Types/Monitor/DockerSwarmAlertTemplates.js.map +1 -0
  286. package/build/dist/Types/Monitor/DockerSwarmMetricCatalog.js +103 -0
  287. package/build/dist/Types/Monitor/DockerSwarmMetricCatalog.js.map +1 -0
  288. package/build/dist/Types/Monitor/HostAlertTemplates.js +365 -0
  289. package/build/dist/Types/Monitor/HostAlertTemplates.js.map +1 -0
  290. package/build/dist/Types/Monitor/HostMetricCatalog.js +138 -0
  291. package/build/dist/Types/Monitor/HostMetricCatalog.js.map +1 -0
  292. package/build/dist/Types/Monitor/MonitorStep.js +69 -0
  293. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  294. package/build/dist/Types/Monitor/MonitorStepDockerSwarmMonitor.js +21 -0
  295. package/build/dist/Types/Monitor/MonitorStepDockerSwarmMonitor.js.map +1 -0
  296. package/build/dist/Types/Monitor/MonitorStepHostMonitor.js +20 -0
  297. package/build/dist/Types/Monitor/MonitorStepHostMonitor.js.map +1 -0
  298. package/build/dist/Types/Monitor/MonitorStepPodmanMonitor.js +21 -0
  299. package/build/dist/Types/Monitor/MonitorStepPodmanMonitor.js.map +1 -0
  300. package/build/dist/Types/Monitor/MonitorType.js +39 -0
  301. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  302. package/build/dist/Types/Monitor/PodmanAlertTemplates.js +410 -0
  303. package/build/dist/Types/Monitor/PodmanAlertTemplates.js.map +1 -0
  304. package/build/dist/Types/Monitor/PodmanMetricCatalog.js +192 -0
  305. package/build/dist/Types/Monitor/PodmanMetricCatalog.js.map +1 -0
  306. package/build/dist/Types/Permission.js +420 -4
  307. package/build/dist/Types/Permission.js.map +1 -1
  308. package/build/dist/Types/Podman/PodmanInventoryExtractor.js +293 -0
  309. package/build/dist/Types/Podman/PodmanInventoryExtractor.js.map +1 -0
  310. package/build/dist/Types/Telemetry/EntityType.js +12 -0
  311. package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
  312. package/build/dist/Types/Telemetry/ServiceType.js +2 -0
  313. package/build/dist/Types/Telemetry/ServiceType.js.map +1 -1
  314. package/build/dist/UI/Components/Icon/Icon.js +16 -0
  315. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  316. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +30 -2
  317. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  318. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +22 -0
  319. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
  320. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +6 -0
  321. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  322. package/build/dist/UI/Utils/TelemetryService.js +1 -0
  323. package/build/dist/UI/Utils/TelemetryService.js.map +1 -1
  324. package/build/dist/Utils/Dashboard/Components/DashboardDockerSwarmNodeListComponent.js +55 -0
  325. package/build/dist/Utils/Dashboard/Components/DashboardDockerSwarmNodeListComponent.js.map +1 -0
  326. package/build/dist/Utils/Dashboard/Components/DashboardDockerSwarmResourceListShared.js +46 -0
  327. package/build/dist/Utils/Dashboard/Components/DashboardDockerSwarmResourceListShared.js.map +1 -0
  328. package/build/dist/Utils/Dashboard/Components/DashboardDockerSwarmServiceListComponent.js +55 -0
  329. package/build/dist/Utils/Dashboard/Components/DashboardDockerSwarmServiceListComponent.js.map +1 -0
  330. package/build/dist/Utils/Dashboard/Components/DashboardPodmanContainerListComponent.js +77 -0
  331. package/build/dist/Utils/Dashboard/Components/DashboardPodmanContainerListComponent.js.map +1 -0
  332. package/build/dist/Utils/Dashboard/Components/DashboardPodmanHostListComponent.js +71 -0
  333. package/build/dist/Utils/Dashboard/Components/DashboardPodmanHostListComponent.js.map +1 -0
  334. package/build/dist/Utils/Dashboard/Components/DashboardPodmanImageListComponent.js +77 -0
  335. package/build/dist/Utils/Dashboard/Components/DashboardPodmanImageListComponent.js.map +1 -0
  336. package/build/dist/Utils/Dashboard/Components/DashboardPodmanNetworkListComponent.js +68 -0
  337. package/build/dist/Utils/Dashboard/Components/DashboardPodmanNetworkListComponent.js.map +1 -0
  338. package/build/dist/Utils/Dashboard/Components/DashboardPodmanVolumeListComponent.js +68 -0
  339. package/build/dist/Utils/Dashboard/Components/DashboardPodmanVolumeListComponent.js.map +1 -0
  340. package/build/dist/Utils/Dashboard/Components/Index.js +28 -0
  341. package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
  342. package/build/dist/Utils/Telemetry/EntityKey.js +14 -0
  343. package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -1
  344. 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();