@oneuptime/common 11.0.0 → 11.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (357) hide show
  1. package/Models/DatabaseModels/Alert.ts +110 -0
  2. package/Models/DatabaseModels/CephCluster.ts +964 -0
  3. package/Models/DatabaseModels/CephClusterLabelRule.ts +514 -0
  4. package/Models/DatabaseModels/CephClusterOwnerRule.ts +596 -0
  5. package/Models/DatabaseModels/CephClusterOwnerTeam.ts +487 -0
  6. package/Models/DatabaseModels/CephClusterOwnerUser.ts +486 -0
  7. package/Models/DatabaseModels/CephResource.ts +809 -0
  8. package/Models/DatabaseModels/Host.ts +64 -0
  9. package/Models/DatabaseModels/Incident.ts +110 -0
  10. package/Models/DatabaseModels/Index.ts +24 -0
  11. package/Models/DatabaseModels/ProxmoxCluster.ts +943 -0
  12. package/Models/DatabaseModels/ProxmoxClusterLabelRule.ts +514 -0
  13. package/Models/DatabaseModels/ProxmoxClusterOwnerRule.ts +596 -0
  14. package/Models/DatabaseModels/ProxmoxClusterOwnerTeam.ts +487 -0
  15. package/Models/DatabaseModels/ProxmoxClusterOwnerUser.ts +486 -0
  16. package/Models/DatabaseModels/ProxmoxResource.ts +726 -0
  17. package/Models/DatabaseModels/ScheduledMaintenance.ts +110 -0
  18. package/Server/API/BillingInvoiceAPI.ts +47 -7
  19. package/Server/API/CephResourceAPI.ts +134 -0
  20. package/Server/API/DashboardAPI.ts +46 -0
  21. package/Server/API/ProjectAPI.ts +15 -0
  22. package/Server/API/ProxmoxResourceAPI.ts +132 -0
  23. package/Server/API/ResellerPlanAPI.ts +17 -0
  24. package/Server/Infrastructure/GlobalCache.ts +8 -2
  25. package/Server/Infrastructure/Postgres/SchemaMigrations/1781500000000-AddProxmoxAndCephClusterTables.ts +163 -0
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/1781600000000-AddProxmoxCephV2Columns.ts +211 -0
  27. package/Server/Infrastructure/Postgres/SchemaMigrations/1781600000001-AddProxmoxCephActivityAndRules.ts +590 -0
  28. package/Server/Infrastructure/Postgres/SchemaMigrations/1781700000000-AddProxmoxCephV3Columns.ts +64 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
  30. package/Server/Infrastructure/Redis.ts +40 -12
  31. package/Server/Services/AnalyticsDatabaseService.ts +1 -1
  32. package/Server/Services/BillingService.ts +109 -21
  33. package/Server/Services/CephClusterLabelRuleEngineService.ts +200 -0
  34. package/Server/Services/CephClusterLabelRuleService.ts +14 -0
  35. package/Server/Services/CephClusterOwnerRuleEngineService.ts +218 -0
  36. package/Server/Services/CephClusterOwnerRuleService.ts +14 -0
  37. package/Server/Services/CephClusterOwnerTeamService.ts +10 -0
  38. package/Server/Services/CephClusterOwnerUserService.ts +10 -0
  39. package/Server/Services/CephClusterService.ts +401 -0
  40. package/Server/Services/CephResourceService.ts +383 -0
  41. package/Server/Services/CloudResourceService.ts +11 -3
  42. package/Server/Services/DockerHostService.ts +11 -3
  43. package/Server/Services/ExceptionAggregationService.ts +2 -0
  44. package/Server/Services/HostService.ts +11 -3
  45. package/Server/Services/Index.ts +24 -0
  46. package/Server/Services/KubernetesClusterService.ts +11 -3
  47. package/Server/Services/LogAggregationService.ts +2 -0
  48. package/Server/Services/MetricAggregationService.ts +2 -0
  49. package/Server/Services/OpenTelemetryIngestService.ts +36 -0
  50. package/Server/Services/ProxmoxClusterLabelRuleEngineService.ts +204 -0
  51. package/Server/Services/ProxmoxClusterLabelRuleService.ts +14 -0
  52. package/Server/Services/ProxmoxClusterOwnerRuleEngineService.ts +222 -0
  53. package/Server/Services/ProxmoxClusterOwnerRuleService.ts +14 -0
  54. package/Server/Services/ProxmoxClusterOwnerTeamService.ts +10 -0
  55. package/Server/Services/ProxmoxClusterOwnerUserService.ts +10 -0
  56. package/Server/Services/ProxmoxClusterService.ts +382 -0
  57. package/Server/Services/ProxmoxResourceService.ts +404 -0
  58. package/Server/Services/RumApplicationService.ts +11 -3
  59. package/Server/Services/ServerlessFunctionService.ts +11 -3
  60. package/Server/Services/TelemetryUsageBillingService.ts +41 -3
  61. package/Server/Services/TraceAggregationService.ts +2 -0
  62. package/Server/Types/AnalyticsDatabase/AggregateBy.ts +8 -23
  63. package/Server/Utils/Monitor/MonitorAlert.ts +45 -0
  64. package/Server/Utils/Monitor/MonitorClusterContext.ts +129 -0
  65. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +344 -4
  66. package/Server/Utils/Monitor/MonitorIncident.ts +130 -7
  67. package/Server/Utils/Monitor/MonitorMaintenanceSuppression.ts +39 -6
  68. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +3 -1
  69. package/Server/Utils/Monitor/SeriesResourceLabels.ts +33 -0
  70. package/Server/Utils/Profiling.ts +37 -2
  71. package/Server/Utils/Telemetry/EntityRegistry.ts +4 -0
  72. package/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.ts +1096 -0
  73. package/Server/Utils/Telemetry/TelemetryEntity.ts +85 -0
  74. package/Server/Utils/Telemetry.ts +8 -19
  75. package/Tests/Server/API/BillingInvoiceAPI.test.ts +194 -0
  76. package/Tests/Server/API/ProjectAPI.test.ts +91 -0
  77. package/Tests/Server/API/ResellerPlanAPI.test.ts +207 -0
  78. package/Tests/Server/Infrastructure/GlobalCache.test.ts +100 -0
  79. package/Tests/Server/Services/BillingService.test.ts +323 -0
  80. package/Tests/Server/Services/CephResourceService.test.ts +264 -0
  81. package/Tests/Server/Services/ProxmoxResourceService.test.ts +326 -0
  82. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +322 -0
  83. package/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.ts +13 -0
  84. package/Tests/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.test.ts +879 -0
  85. package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +196 -0
  86. package/Tests/Types/Monitor/CephAlertTemplates.test.ts +1231 -0
  87. package/Tests/Types/Monitor/ProxmoxAlertTemplates.test.ts +732 -0
  88. package/Tests/Utils/ModelImportExport.test.ts +366 -0
  89. package/Tests/Utils/Telemetry/EntityRelationship.test.ts +49 -0
  90. package/Tests/Utils/Telemetry/HeartbeatAvailability.test.ts +423 -0
  91. package/Types/BaseDatabase/AggregationIntervalUtil.ts +74 -0
  92. package/Types/Dashboard/DashboardComponentType.ts +4 -0
  93. package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +2 -0
  94. package/Types/Dashboard/DashboardComponents/DashboardCephOsdListComponent.ts +15 -0
  95. package/Types/Dashboard/DashboardComponents/DashboardCephPoolListComponent.ts +14 -0
  96. package/Types/Dashboard/DashboardComponents/DashboardProxmoxGuestListComponent.ts +17 -0
  97. package/Types/Dashboard/DashboardComponents/DashboardProxmoxNodeListComponent.ts +16 -0
  98. package/Types/Dashboard/DashboardTemplates.ts +446 -0
  99. package/Types/Icon/IconProp.ts +2 -0
  100. package/Types/Monitor/CephAlertTemplates.ts +1647 -0
  101. package/Types/Monitor/CephMetricCatalog.ts +409 -0
  102. package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +44 -0
  103. package/Types/Monitor/MonitorStep.ts +64 -0
  104. package/Types/Monitor/MonitorStepCephMonitor.ts +57 -0
  105. package/Types/Monitor/MonitorStepProxmoxMonitor.ts +81 -0
  106. package/Types/Monitor/MonitorType.ts +29 -1
  107. package/Types/Monitor/ProxmoxAlertTemplates.ts +899 -0
  108. package/Types/Monitor/ProxmoxMetricCatalog.ts +382 -0
  109. package/Types/Permission.ts +464 -0
  110. package/Types/Telemetry/EntityType.ts +11 -0
  111. package/Types/Telemetry/ServiceType.ts +2 -0
  112. package/UI/Components/Icon/Icon.tsx +84 -0
  113. package/UI/Components/ImportExport/ExportModelCard.tsx +90 -0
  114. package/UI/Components/ImportExport/ImportModelsModal.tsx +239 -0
  115. package/UI/Components/ModelTable/ModelTable.tsx +294 -143
  116. package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +9 -5
  117. package/UI/Utils/ModelImportExport.ts +207 -0
  118. package/UI/Utils/Telemetry/Telemetry.ts +16 -21
  119. package/UI/Utils/TelemetryService.ts +7 -3
  120. package/Utils/Dashboard/Components/DashboardCephOsdListComponent.ts +63 -0
  121. package/Utils/Dashboard/Components/DashboardCephPoolListComponent.ts +32 -0
  122. package/Utils/Dashboard/Components/DashboardCephResourceListShared.ts +61 -0
  123. package/Utils/Dashboard/Components/DashboardProxmoxGuestListComponent.ts +69 -0
  124. package/Utils/Dashboard/Components/DashboardProxmoxNodeListComponent.ts +55 -0
  125. package/Utils/Dashboard/Components/DashboardProxmoxResourceListShared.ts +61 -0
  126. package/Utils/Dashboard/Components/Index.ts +28 -0
  127. package/Utils/ModelImportExport.ts +369 -0
  128. package/Utils/Telemetry/EntityKey.ts +35 -0
  129. package/Utils/Telemetry/EntityRelationship.ts +6 -0
  130. package/Utils/Telemetry/HeartbeatAvailability.ts +262 -0
  131. package/build/dist/Models/DatabaseModels/Alert.js +108 -0
  132. package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
  133. package/build/dist/Models/DatabaseModels/CephCluster.js +992 -0
  134. package/build/dist/Models/DatabaseModels/CephCluster.js.map +1 -0
  135. package/build/dist/Models/DatabaseModels/CephClusterLabelRule.js +522 -0
  136. package/build/dist/Models/DatabaseModels/CephClusterLabelRule.js.map +1 -0
  137. package/build/dist/Models/DatabaseModels/CephClusterOwnerRule.js +603 -0
  138. package/build/dist/Models/DatabaseModels/CephClusterOwnerRule.js.map +1 -0
  139. package/build/dist/Models/DatabaseModels/CephClusterOwnerTeam.js +503 -0
  140. package/build/dist/Models/DatabaseModels/CephClusterOwnerTeam.js.map +1 -0
  141. package/build/dist/Models/DatabaseModels/CephClusterOwnerUser.js +502 -0
  142. package/build/dist/Models/DatabaseModels/CephClusterOwnerUser.js.map +1 -0
  143. package/build/dist/Models/DatabaseModels/CephResource.js +846 -0
  144. package/build/dist/Models/DatabaseModels/CephResource.js.map +1 -0
  145. package/build/dist/Models/DatabaseModels/Host.js +63 -0
  146. package/build/dist/Models/DatabaseModels/Host.js.map +1 -1
  147. package/build/dist/Models/DatabaseModels/Incident.js +108 -0
  148. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  149. package/build/dist/Models/DatabaseModels/Index.js +24 -0
  150. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  151. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js +967 -0
  152. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js.map +1 -0
  153. package/build/dist/Models/DatabaseModels/ProxmoxClusterLabelRule.js +522 -0
  154. package/build/dist/Models/DatabaseModels/ProxmoxClusterLabelRule.js.map +1 -0
  155. package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerRule.js +603 -0
  156. package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerRule.js.map +1 -0
  157. package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerTeam.js +503 -0
  158. package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerTeam.js.map +1 -0
  159. package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerUser.js +502 -0
  160. package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerUser.js.map +1 -0
  161. package/build/dist/Models/DatabaseModels/ProxmoxResource.js +761 -0
  162. package/build/dist/Models/DatabaseModels/ProxmoxResource.js.map +1 -0
  163. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +108 -0
  164. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
  165. package/build/dist/Server/API/BillingInvoiceAPI.js +35 -5
  166. package/build/dist/Server/API/BillingInvoiceAPI.js.map +1 -1
  167. package/build/dist/Server/API/CephResourceAPI.js +98 -0
  168. package/build/dist/Server/API/CephResourceAPI.js.map +1 -0
  169. package/build/dist/Server/API/DashboardAPI.js +46 -0
  170. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  171. package/build/dist/Server/API/ProjectAPI.js +11 -0
  172. package/build/dist/Server/API/ProjectAPI.js.map +1 -1
  173. package/build/dist/Server/API/ProxmoxResourceAPI.js +95 -0
  174. package/build/dist/Server/API/ProxmoxResourceAPI.js.map +1 -0
  175. package/build/dist/Server/API/ResellerPlanAPI.js +17 -3
  176. package/build/dist/Server/API/ResellerPlanAPI.js.map +1 -1
  177. package/build/dist/Server/Infrastructure/GlobalCache.js +7 -2
  178. package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
  179. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781500000000-AddProxmoxAndCephClusterTables.js +76 -0
  180. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781500000000-AddProxmoxAndCephClusterTables.js.map +1 -0
  181. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781600000000-AddProxmoxCephV2Columns.js +108 -0
  182. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781600000000-AddProxmoxCephV2Columns.js.map +1 -0
  183. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781600000001-AddProxmoxCephActivityAndRules.js +253 -0
  184. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781600000001-AddProxmoxCephActivityAndRules.js.map +1 -0
  185. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781700000000-AddProxmoxCephV3Columns.js +43 -0
  186. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781700000000-AddProxmoxCephV3Columns.js.map +1 -0
  187. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  188. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  189. package/build/dist/Server/Infrastructure/Redis.js +31 -8
  190. package/build/dist/Server/Infrastructure/Redis.js.map +1 -1
  191. package/build/dist/Server/Services/AnalyticsDatabaseService.js +1 -1
  192. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  193. package/build/dist/Server/Services/BillingService.js +85 -23
  194. package/build/dist/Server/Services/BillingService.js.map +1 -1
  195. package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js +166 -0
  196. package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js.map +1 -0
  197. package/build/dist/Server/Services/CephClusterLabelRuleService.js +13 -0
  198. package/build/dist/Server/Services/CephClusterLabelRuleService.js.map +1 -0
  199. package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js +186 -0
  200. package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js.map +1 -0
  201. package/build/dist/Server/Services/CephClusterOwnerRuleService.js +13 -0
  202. package/build/dist/Server/Services/CephClusterOwnerRuleService.js.map +1 -0
  203. package/build/dist/Server/Services/CephClusterOwnerTeamService.js +9 -0
  204. package/build/dist/Server/Services/CephClusterOwnerTeamService.js.map +1 -0
  205. package/build/dist/Server/Services/CephClusterOwnerUserService.js +9 -0
  206. package/build/dist/Server/Services/CephClusterOwnerUserService.js.map +1 -0
  207. package/build/dist/Server/Services/CephClusterService.js +353 -0
  208. package/build/dist/Server/Services/CephClusterService.js.map +1 -0
  209. package/build/dist/Server/Services/CephResourceService.js +257 -0
  210. package/build/dist/Server/Services/CephResourceService.js.map +1 -0
  211. package/build/dist/Server/Services/CloudResourceService.js +10 -2
  212. package/build/dist/Server/Services/CloudResourceService.js.map +1 -1
  213. package/build/dist/Server/Services/DockerHostService.js +10 -2
  214. package/build/dist/Server/Services/DockerHostService.js.map +1 -1
  215. package/build/dist/Server/Services/ExceptionAggregationService.js +2 -0
  216. package/build/dist/Server/Services/ExceptionAggregationService.js.map +1 -1
  217. package/build/dist/Server/Services/HostService.js +10 -2
  218. package/build/dist/Server/Services/HostService.js.map +1 -1
  219. package/build/dist/Server/Services/Index.js +24 -0
  220. package/build/dist/Server/Services/Index.js.map +1 -1
  221. package/build/dist/Server/Services/KubernetesClusterService.js +10 -2
  222. package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
  223. package/build/dist/Server/Services/LogAggregationService.js +2 -0
  224. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  225. package/build/dist/Server/Services/MetricAggregationService.js +2 -0
  226. package/build/dist/Server/Services/MetricAggregationService.js.map +1 -1
  227. package/build/dist/Server/Services/OpenTelemetryIngestService.js +37 -7
  228. package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
  229. package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js +166 -0
  230. package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js.map +1 -0
  231. package/build/dist/Server/Services/ProxmoxClusterLabelRuleService.js +13 -0
  232. package/build/dist/Server/Services/ProxmoxClusterLabelRuleService.js.map +1 -0
  233. package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js +186 -0
  234. package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js.map +1 -0
  235. package/build/dist/Server/Services/ProxmoxClusterOwnerRuleService.js +13 -0
  236. package/build/dist/Server/Services/ProxmoxClusterOwnerRuleService.js.map +1 -0
  237. package/build/dist/Server/Services/ProxmoxClusterOwnerTeamService.js +9 -0
  238. package/build/dist/Server/Services/ProxmoxClusterOwnerTeamService.js.map +1 -0
  239. package/build/dist/Server/Services/ProxmoxClusterOwnerUserService.js +9 -0
  240. package/build/dist/Server/Services/ProxmoxClusterOwnerUserService.js.map +1 -0
  241. package/build/dist/Server/Services/ProxmoxClusterService.js +337 -0
  242. package/build/dist/Server/Services/ProxmoxClusterService.js.map +1 -0
  243. package/build/dist/Server/Services/ProxmoxResourceService.js +285 -0
  244. package/build/dist/Server/Services/ProxmoxResourceService.js.map +1 -0
  245. package/build/dist/Server/Services/RumApplicationService.js +10 -2
  246. package/build/dist/Server/Services/RumApplicationService.js.map +1 -1
  247. package/build/dist/Server/Services/ServerlessFunctionService.js +10 -2
  248. package/build/dist/Server/Services/ServerlessFunctionService.js.map +1 -1
  249. package/build/dist/Server/Services/TelemetryUsageBillingService.js +30 -3
  250. package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
  251. package/build/dist/Server/Services/TraceAggregationService.js +2 -0
  252. package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
  253. package/build/dist/Server/Types/AnalyticsDatabase/AggregateBy.js +8 -25
  254. package/build/dist/Server/Types/AnalyticsDatabase/AggregateBy.js.map +1 -1
  255. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +36 -0
  256. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  257. package/build/dist/Server/Utils/Monitor/MonitorClusterContext.js +90 -0
  258. package/build/dist/Server/Utils/Monitor/MonitorClusterContext.js.map +1 -0
  259. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +228 -4
  260. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  261. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +103 -8
  262. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  263. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js +23 -6
  264. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -1
  265. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +3 -1
  266. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  267. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +23 -0
  268. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
  269. package/build/dist/Server/Utils/Profiling.js +24 -3
  270. package/build/dist/Server/Utils/Profiling.js.map +1 -1
  271. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +4 -0
  272. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  273. package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js +854 -0
  274. package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js.map +1 -0
  275. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +62 -0
  276. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
  277. package/build/dist/Server/Utils/Telemetry.js +8 -10
  278. package/build/dist/Server/Utils/Telemetry.js.map +1 -1
  279. package/build/dist/Types/BaseDatabase/AggregationIntervalUtil.js +69 -0
  280. package/build/dist/Types/BaseDatabase/AggregationIntervalUtil.js.map +1 -0
  281. package/build/dist/Types/Dashboard/DashboardComponentType.js +4 -0
  282. package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
  283. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +2 -0
  284. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
  285. package/build/dist/Types/Dashboard/DashboardComponents/DashboardCephOsdListComponent.js +2 -0
  286. package/build/dist/Types/Dashboard/DashboardComponents/DashboardCephOsdListComponent.js.map +1 -0
  287. package/build/dist/Types/Dashboard/DashboardComponents/DashboardCephPoolListComponent.js +2 -0
  288. package/build/dist/Types/Dashboard/DashboardComponents/DashboardCephPoolListComponent.js.map +1 -0
  289. package/build/dist/Types/Dashboard/DashboardComponents/DashboardProxmoxGuestListComponent.js +2 -0
  290. package/build/dist/Types/Dashboard/DashboardComponents/DashboardProxmoxGuestListComponent.js.map +1 -0
  291. package/build/dist/Types/Dashboard/DashboardComponents/DashboardProxmoxNodeListComponent.js +2 -0
  292. package/build/dist/Types/Dashboard/DashboardComponents/DashboardProxmoxNodeListComponent.js.map +1 -0
  293. package/build/dist/Types/Dashboard/DashboardTemplates.js +394 -0
  294. package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
  295. package/build/dist/Types/Icon/IconProp.js +2 -0
  296. package/build/dist/Types/Icon/IconProp.js.map +1 -1
  297. package/build/dist/Types/Monitor/CephAlertTemplates.js +1379 -0
  298. package/build/dist/Types/Monitor/CephAlertTemplates.js.map +1 -0
  299. package/build/dist/Types/Monitor/CephMetricCatalog.js +353 -0
  300. package/build/dist/Types/Monitor/CephMetricCatalog.js.map +1 -0
  301. package/build/dist/Types/Monitor/MonitorStep.js +46 -0
  302. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  303. package/build/dist/Types/Monitor/MonitorStepCephMonitor.js +34 -0
  304. package/build/dist/Types/Monitor/MonitorStepCephMonitor.js.map +1 -0
  305. package/build/dist/Types/Monitor/MonitorStepProxmoxMonitor.js +36 -0
  306. package/build/dist/Types/Monitor/MonitorStepProxmoxMonitor.js.map +1 -0
  307. package/build/dist/Types/Monitor/MonitorType.js +27 -1
  308. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  309. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +743 -0
  310. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js.map +1 -0
  311. package/build/dist/Types/Monitor/ProxmoxMetricCatalog.js +320 -0
  312. package/build/dist/Types/Monitor/ProxmoxMetricCatalog.js.map +1 -0
  313. package/build/dist/Types/Permission.js +408 -0
  314. package/build/dist/Types/Permission.js.map +1 -1
  315. package/build/dist/Types/Telemetry/EntityType.js +11 -0
  316. package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
  317. package/build/dist/Types/Telemetry/ServiceType.js +2 -0
  318. package/build/dist/Types/Telemetry/ServiceType.js.map +1 -1
  319. package/build/dist/UI/Components/Icon/Icon.js +33 -0
  320. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  321. package/build/dist/UI/Components/ImportExport/ExportModelCard.js +50 -0
  322. package/build/dist/UI/Components/ImportExport/ExportModelCard.js.map +1 -0
  323. package/build/dist/UI/Components/ImportExport/ImportModelsModal.js +115 -0
  324. package/build/dist/UI/Components/ImportExport/ImportModelsModal.js.map +1 -0
  325. package/build/dist/UI/Components/ModelTable/ModelTable.js +166 -74
  326. package/build/dist/UI/Components/ModelTable/ModelTable.js.map +1 -1
  327. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +5 -1
  328. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  329. package/build/dist/UI/Utils/ModelImportExport.js +142 -0
  330. package/build/dist/UI/Utils/ModelImportExport.js.map +1 -0
  331. package/build/dist/UI/Utils/Telemetry/Telemetry.js +11 -10
  332. package/build/dist/UI/Utils/Telemetry/Telemetry.js.map +1 -1
  333. package/build/dist/UI/Utils/TelemetryService.js +5 -2
  334. package/build/dist/UI/Utils/TelemetryService.js.map +1 -1
  335. package/build/dist/Utils/Dashboard/Components/DashboardCephOsdListComponent.js +50 -0
  336. package/build/dist/Utils/Dashboard/Components/DashboardCephOsdListComponent.js.map +1 -0
  337. package/build/dist/Utils/Dashboard/Components/DashboardCephPoolListComponent.js +27 -0
  338. package/build/dist/Utils/Dashboard/Components/DashboardCephPoolListComponent.js.map +1 -0
  339. package/build/dist/Utils/Dashboard/Components/DashboardCephResourceListShared.js +46 -0
  340. package/build/dist/Utils/Dashboard/Components/DashboardCephResourceListShared.js.map +1 -0
  341. package/build/dist/Utils/Dashboard/Components/DashboardProxmoxGuestListComponent.js +55 -0
  342. package/build/dist/Utils/Dashboard/Components/DashboardProxmoxGuestListComponent.js.map +1 -0
  343. package/build/dist/Utils/Dashboard/Components/DashboardProxmoxNodeListComponent.js +42 -0
  344. package/build/dist/Utils/Dashboard/Components/DashboardProxmoxNodeListComponent.js.map +1 -0
  345. package/build/dist/Utils/Dashboard/Components/DashboardProxmoxResourceListShared.js +46 -0
  346. package/build/dist/Utils/Dashboard/Components/DashboardProxmoxResourceListShared.js.map +1 -0
  347. package/build/dist/Utils/Dashboard/Components/Index.js +16 -0
  348. package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
  349. package/build/dist/Utils/ModelImportExport.js +257 -0
  350. package/build/dist/Utils/ModelImportExport.js.map +1 -0
  351. package/build/dist/Utils/Telemetry/EntityKey.js +27 -0
  352. package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -1
  353. package/build/dist/Utils/Telemetry/EntityRelationship.js +3 -0
  354. package/build/dist/Utils/Telemetry/EntityRelationship.js.map +1 -1
  355. package/build/dist/Utils/Telemetry/HeartbeatAvailability.js +174 -0
  356. package/build/dist/Utils/Telemetry/HeartbeatAvailability.js.map +1 -0
  357. package/package.json +29 -21
@@ -0,0 +1,404 @@
1
+ import DatabaseService from "./DatabaseService";
2
+ import Model from "../../Models/DatabaseModels/ProxmoxResource";
3
+ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
4
+ import ObjectID from "../../Types/ObjectID";
5
+ import OneUptimeDate from "../../Types/Date";
6
+ import QueryHelper from "../Types/Database/QueryHelper";
7
+ import logger from "../Utils/Logger";
8
+
9
+ /*
10
+ * ------------------------------------------------------------------
11
+ * ProxmoxResourceService
12
+ *
13
+ * Writes and reads the Proxmox inventory table populated by the
14
+ * telemetry ingest path. Callers are either:
15
+ * - OtelMetricsIngestService (bulkUpsert + bulkUpdateLatestMetrics,
16
+ * from the pve_* snapshot scan in processMetricsAsync)
17
+ * - CleanupStaleResources worker (deleteStaleForCluster)
18
+ * - ProxmoxResourceAPI / the dashboard pages (reads via the
19
+ * inherited DatabaseService CRUD)
20
+ *
21
+ * Identity + status and the latest-metric mirror both arrive on the
22
+ * same metric scrape (unlike K8s, which needs a separate k8sobjects
23
+ * log stream for identity), so both writes happen in the same flush.
24
+ *
25
+ * ------------------------------------------------------------------
26
+ */
27
+
28
+ export interface ParsedProxmoxResource {
29
+ kind: string; // Node | Guest | Storage
30
+ externalId: string; // raw pve `id` label, e.g. node/pve1, qemu/100
31
+ name: string | null;
32
+ vmid: number | null;
33
+ guestType: string | null; // qemu | lxc
34
+ parentNodeName: string | null;
35
+ isUp: boolean | null;
36
+ haState: string | null;
37
+ onboot: boolean | null;
38
+ /*
39
+ * WI-24 backup coverage: true = covered by at least one backup job,
40
+ * false = a pve_not_backed_up_info series carried this guest's id,
41
+ * null = batch lacked the backup-info collector output (keeps the
42
+ * last-known value via COALESCE) or non-Guest kind.
43
+ */
44
+ isBackedUp: boolean | null;
45
+ uptimeSeconds: number | null;
46
+ lastSeenAt: Date;
47
+ }
48
+
49
+ export interface ProxmoxResourceLatestMetric {
50
+ kind: string;
51
+ externalId: string;
52
+ cpuPercent: number | null;
53
+ memoryBytes: number | null;
54
+ maxMemoryBytes: number | null;
55
+ memoryPercent: number | null;
56
+ diskBytes: number | null;
57
+ maxDiskBytes: number | null;
58
+ observedAt: Date;
59
+ }
60
+
61
+ export interface ProxmoxInventorySummary {
62
+ countsByKind: Record<string, number>;
63
+ nodeOnlineCount: number;
64
+ guestRunningCount: number;
65
+ }
66
+
67
+ const UPSERT_BATCH_SIZE: number = 500;
68
+ const STALE_DELETE_WARN_THRESHOLD: number = 100;
69
+
70
+ /*
71
+ * Column order used by bulkUpsert() and its generated parameter tuples.
72
+ * Keep this and the INSERT column list in perfect sync.
73
+ */
74
+ const UPSERT_COLUMNS: Array<string> = [
75
+ "projectId",
76
+ "proxmoxClusterId",
77
+ "kind",
78
+ "externalId",
79
+ "name",
80
+ "vmid",
81
+ "guestType",
82
+ "parentNodeName",
83
+ "isUp",
84
+ "haState",
85
+ "onboot",
86
+ "isBackedUp",
87
+ "uptimeSeconds",
88
+ "lastSeenAt",
89
+ "version",
90
+ ];
91
+
92
+ export class Service extends DatabaseService<Model> {
93
+ public constructor() {
94
+ super(Model);
95
+ }
96
+
97
+ /**
98
+ * Upsert a batch of parsed resources for a single (project, cluster)
99
+ * pair. Uses ON CONFLICT on the UNIQUE (projectId, proxmoxClusterId,
100
+ * kind, externalId) index with a dominance guard on lastSeenAt so
101
+ * out-of-order ingest never regresses a newer snapshot.
102
+ *
103
+ * Identity/status columns COALESCE against the existing row (unlike
104
+ * the K8s upsert, which overwrites): a pve-exporter batch is usually
105
+ * a complete scrape, but a batch that happens to lack an info series
106
+ * (e.g. only pve_up made it through a pipeline filter) must not blank
107
+ * name/vmid/haState that an earlier batch already filled.
108
+ */
109
+ @CaptureSpan()
110
+ public async bulkUpsert(data: {
111
+ projectId: ObjectID;
112
+ proxmoxClusterId: ObjectID;
113
+ resources: Array<ParsedProxmoxResource>;
114
+ }): Promise<void> {
115
+ if (data.resources.length === 0) {
116
+ return;
117
+ }
118
+
119
+ // Chunk to keep individual statement parameter counts reasonable.
120
+ for (let i: number = 0; i < data.resources.length; i += UPSERT_BATCH_SIZE) {
121
+ const chunk: Array<ParsedProxmoxResource> = data.resources.slice(
122
+ i,
123
+ i + UPSERT_BATCH_SIZE,
124
+ );
125
+
126
+ const valueFragments: Array<string> = [];
127
+ const params: Array<unknown> = [];
128
+ let paramIndex: number = 1;
129
+
130
+ for (const r of chunk) {
131
+ const placeholders: Array<string> = [];
132
+ for (let c: number = 0; c < UPSERT_COLUMNS.length; c++) {
133
+ placeholders.push(`$${paramIndex++}`);
134
+ }
135
+ valueFragments.push(`(${placeholders.join(", ")})`);
136
+
137
+ params.push(
138
+ data.projectId.toString(),
139
+ data.proxmoxClusterId.toString(),
140
+ r.kind,
141
+ r.externalId,
142
+ r.name,
143
+ r.vmid,
144
+ r.guestType,
145
+ r.parentNodeName,
146
+ r.isUp,
147
+ r.haState,
148
+ r.onboot,
149
+ r.isBackedUp,
150
+ r.uptimeSeconds !== null ? Math.trunc(r.uptimeSeconds) : null,
151
+ r.lastSeenAt,
152
+ 0, // version (BaseModel @VersionColumn)
153
+ );
154
+ }
155
+
156
+ const sql: string = `
157
+ INSERT INTO "ProxmoxResource" (
158
+ "projectId", "proxmoxClusterId", "kind", "externalId",
159
+ "name", "vmid", "guestType", "parentNodeName",
160
+ "isUp", "haState", "onboot", "isBackedUp", "uptimeSeconds",
161
+ "lastSeenAt", "version"
162
+ )
163
+ VALUES ${valueFragments.join(", ")}
164
+ ON CONFLICT ("projectId", "proxmoxClusterId", "kind", "externalId")
165
+ DO UPDATE SET
166
+ "name" = COALESCE(EXCLUDED."name", "ProxmoxResource"."name"),
167
+ "vmid" = COALESCE(EXCLUDED."vmid", "ProxmoxResource"."vmid"),
168
+ "guestType" = COALESCE(EXCLUDED."guestType", "ProxmoxResource"."guestType"),
169
+ "parentNodeName" = COALESCE(EXCLUDED."parentNodeName", "ProxmoxResource"."parentNodeName"),
170
+ "isUp" = COALESCE(EXCLUDED."isUp", "ProxmoxResource"."isUp"),
171
+ "haState" = COALESCE(EXCLUDED."haState", "ProxmoxResource"."haState"),
172
+ "onboot" = COALESCE(EXCLUDED."onboot", "ProxmoxResource"."onboot"),
173
+ "isBackedUp" = COALESCE(EXCLUDED."isBackedUp", "ProxmoxResource"."isBackedUp"),
174
+ "uptimeSeconds" = COALESCE(EXCLUDED."uptimeSeconds", "ProxmoxResource"."uptimeSeconds"),
175
+ "lastSeenAt" = EXCLUDED."lastSeenAt",
176
+ "updatedAt" = now()
177
+ WHERE EXCLUDED."lastSeenAt" >= "ProxmoxResource"."lastSeenAt"
178
+ `;
179
+
180
+ await this.getRepository().manager.query(sql, params);
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Update the latest-metric mirror columns for a batch of resources.
186
+ * Plain UPDATE: in practice the row always exists because bulkUpsert
187
+ * runs in the same flush; if it somehow doesn't, the write is
188
+ * silently skipped and the next flush catches up.
189
+ *
190
+ * Guarded by metricsUpdatedAt so out-of-order points don't regress a
191
+ * newer observation. COALESCE keeps the existing value when a batch
192
+ * lacks a series — notably latestDiskBytes stays NULL (never 0) for
193
+ * qemu guests without the QEMU guest agent.
194
+ */
195
+ @CaptureSpan()
196
+ public async bulkUpdateLatestMetrics(data: {
197
+ projectId: ObjectID;
198
+ proxmoxClusterId: ObjectID;
199
+ metrics: Array<ProxmoxResourceLatestMetric>;
200
+ }): Promise<void> {
201
+ if (data.metrics.length === 0) {
202
+ return;
203
+ }
204
+
205
+ for (let i: number = 0; i < data.metrics.length; i += UPSERT_BATCH_SIZE) {
206
+ const chunk: Array<ProxmoxResourceLatestMetric> = data.metrics.slice(
207
+ i,
208
+ i + UPSERT_BATCH_SIZE,
209
+ );
210
+
211
+ const valueFragments: Array<string> = [];
212
+ const params: Array<unknown> = [
213
+ data.projectId.toString(),
214
+ data.proxmoxClusterId.toString(),
215
+ ];
216
+ let paramIndex: number = 3;
217
+
218
+ for (const m of chunk) {
219
+ valueFragments.push(
220
+ `($${paramIndex++}, $${paramIndex++}, $${paramIndex++}::numeric, $${paramIndex++}::bigint, $${paramIndex++}::bigint, $${paramIndex++}::numeric, $${paramIndex++}::bigint, $${paramIndex++}::bigint, $${paramIndex++}::timestamptz)`,
221
+ );
222
+ params.push(
223
+ m.kind,
224
+ m.externalId,
225
+ m.cpuPercent !== null && m.cpuPercent !== undefined
226
+ ? m.cpuPercent
227
+ : null,
228
+ m.memoryBytes !== null && m.memoryBytes !== undefined
229
+ ? Math.trunc(m.memoryBytes).toString()
230
+ : null,
231
+ m.maxMemoryBytes !== null && m.maxMemoryBytes !== undefined
232
+ ? Math.trunc(m.maxMemoryBytes).toString()
233
+ : null,
234
+ m.memoryPercent !== null && m.memoryPercent !== undefined
235
+ ? m.memoryPercent
236
+ : null,
237
+ m.diskBytes !== null && m.diskBytes !== undefined
238
+ ? Math.trunc(m.diskBytes).toString()
239
+ : null,
240
+ m.maxDiskBytes !== null && m.maxDiskBytes !== undefined
241
+ ? Math.trunc(m.maxDiskBytes).toString()
242
+ : null,
243
+ m.observedAt,
244
+ );
245
+ }
246
+
247
+ const sql: string = `
248
+ UPDATE "ProxmoxResource" AS p
249
+ SET
250
+ "latestCpuPercent" = COALESCE(v."cpu", p."latestCpuPercent"),
251
+ "latestMemoryBytes" = COALESCE(v."mem", p."latestMemoryBytes"),
252
+ "maxMemoryBytes" = COALESCE(v."maxMem", p."maxMemoryBytes"),
253
+ "latestMemoryPercent" = COALESCE(v."memPct", p."latestMemoryPercent"),
254
+ "latestDiskBytes" = COALESCE(v."disk", p."latestDiskBytes"),
255
+ "maxDiskBytes" = COALESCE(v."maxDisk", p."maxDiskBytes"),
256
+ "metricsUpdatedAt" = v."observedAt",
257
+ "updatedAt" = now()
258
+ FROM (VALUES ${valueFragments.join(", ")})
259
+ AS v("kind", "externalId", "cpu", "mem", "maxMem", "memPct", "disk", "maxDisk", "observedAt")
260
+ WHERE
261
+ p."projectId" = $1
262
+ AND p."proxmoxClusterId" = $2
263
+ AND p."kind" = v."kind"
264
+ AND p."externalId" = v."externalId"
265
+ AND (p."metricsUpdatedAt" IS NULL OR v."observedAt" >= p."metricsUpdatedAt")
266
+ `;
267
+
268
+ await this.getRepository().manager.query(sql, params);
269
+ }
270
+ }
271
+
272
+ /**
273
+ * Hard-delete all resources in a cluster whose last scrape is older
274
+ * than olderThan. Returns the number of deleted rows. Only called by
275
+ * the cleanup worker for clusters that are still connected — a
276
+ * disconnected cluster keeps its last-known inventory.
277
+ */
278
+ @CaptureSpan()
279
+ public async deleteStaleForCluster(data: {
280
+ proxmoxClusterId: ObjectID;
281
+ olderThan: Date;
282
+ }): Promise<number> {
283
+ const result: Array<{ affected?: number }> | { affected?: number } =
284
+ await this.getRepository().manager.query(
285
+ `DELETE FROM "ProxmoxResource" WHERE "proxmoxClusterId" = $1 AND "lastSeenAt" < $2`,
286
+ [data.proxmoxClusterId.toString(), data.olderThan],
287
+ );
288
+
289
+ // Postgres driver returns [rows, affected] for DELETE — normalize.
290
+ let affected: number = 0;
291
+ if (Array.isArray(result) && result.length >= 2) {
292
+ const second: unknown = (result as Array<unknown>)[1];
293
+ if (typeof second === "number") {
294
+ affected = second;
295
+ }
296
+ }
297
+
298
+ if (affected > STALE_DELETE_WARN_THRESHOLD) {
299
+ logger.warn(
300
+ `ProxmoxResource cleanup deleted ${affected} stale rows for cluster ${data.proxmoxClusterId.toString()} — larger than expected; investigate agent health.`,
301
+ );
302
+ }
303
+
304
+ return affected;
305
+ }
306
+
307
+ /**
308
+ * Compute the sidebar/overview summary in Postgres: counts per kind
309
+ * plus the online/running breakdowns, in a single round-trip.
310
+ */
311
+ @CaptureSpan()
312
+ public async getInventorySummary(data: {
313
+ projectId: ObjectID;
314
+ proxmoxClusterId: ObjectID;
315
+ }): Promise<ProxmoxInventorySummary> {
316
+ const rows: Array<{
317
+ kind: string;
318
+ count: string;
319
+ upCount: string;
320
+ }> = await this.getRepository().manager.query(
321
+ `SELECT "kind",
322
+ COUNT(*)::text AS count,
323
+ COUNT(*) FILTER (WHERE "isUp" IS TRUE)::text AS "upCount"
324
+ FROM "ProxmoxResource"
325
+ WHERE "projectId" = $1 AND "proxmoxClusterId" = $2 AND "deletedAt" IS NULL
326
+ GROUP BY "kind"`,
327
+ [data.projectId.toString(), data.proxmoxClusterId.toString()],
328
+ );
329
+
330
+ const countsByKind: Record<string, number> = {};
331
+ let nodeOnlineCount: number = 0;
332
+ let guestRunningCount: number = 0;
333
+ for (const row of rows) {
334
+ countsByKind[row.kind] = parseInt(row.count, 10) || 0;
335
+ if (row.kind === "Node") {
336
+ nodeOnlineCount = parseInt(row.upCount, 10) || 0;
337
+ }
338
+ if (row.kind === "Guest") {
339
+ guestRunningCount = parseInt(row.upCount, 10) || 0;
340
+ }
341
+ }
342
+
343
+ return {
344
+ countsByKind,
345
+ nodeOnlineCount,
346
+ guestRunningCount,
347
+ };
348
+ }
349
+
350
+ /**
351
+ * Host cross-link heuristic (WI-17): resolve the cluster a guest
352
+ * with this name belongs to. Case-insensitive — host.name casing
353
+ * (canonicalized at ingest) rarely matches the PVE guest name's
354
+ * casing exactly. Returns null when no guest matches.
355
+ */
356
+ @CaptureSpan()
357
+ public async findGuestClusterIdByName(data: {
358
+ projectId: ObjectID;
359
+ name: string;
360
+ }): Promise<ObjectID | null> {
361
+ const guest: Model | null = await this.findOneBy({
362
+ query: {
363
+ projectId: data.projectId,
364
+ kind: "Guest",
365
+ name: QueryHelper.findWithSameText(data.name),
366
+ },
367
+ select: {
368
+ _id: true,
369
+ proxmoxClusterId: true,
370
+ },
371
+ props: {
372
+ isRoot: true,
373
+ },
374
+ });
375
+
376
+ return guest?.proxmoxClusterId || null;
377
+ }
378
+
379
+ /**
380
+ * Helper for the cleanup worker: snapshot-interval aware cutoff.
381
+ * 3× the 5-minute scrape interval by default. Tune via
382
+ * PVE_INVENTORY_STALE_MINUTES (min 5).
383
+ */
384
+ public getStaleThresholdDate(nowOverride?: Date): Date {
385
+ const minutes: number = this.getStaleThresholdMinutes();
386
+ return OneUptimeDate.addRemoveMinutes(
387
+ nowOverride || OneUptimeDate.getCurrentDate(),
388
+ -minutes,
389
+ );
390
+ }
391
+
392
+ public getStaleThresholdMinutes(): number {
393
+ const raw: string | undefined = process.env["PVE_INVENTORY_STALE_MINUTES"];
394
+ if (raw) {
395
+ const parsed: number = parseInt(raw, 10);
396
+ if (!isNaN(parsed) && parsed >= 5) {
397
+ return parsed;
398
+ }
399
+ }
400
+ return 15;
401
+ }
402
+ }
403
+
404
+ export default new Service();
@@ -253,15 +253,23 @@ export class Service extends DatabaseService<Model> {
253
253
 
254
254
  @CaptureSpan()
255
255
  public async markDisconnectedApplications(): Promise<void> {
256
- const fiveMinutesAgo: Date = OneUptimeDate.addRemoveMinutes(
256
+ /*
257
+ * Threshold must stay well above the 5-minute OTel ingest
258
+ * maintenance fence (MAINTENANCE_FENCE_TTL_SECONDS in
259
+ * OtelIngestBaseService) — lastSeenAt is legitimately up to
260
+ * ~5 minutes stale during continuous telemetry, so a threshold
261
+ * equal to the fence TTL flaps healthy resources. 15 minutes
262
+ * gives 3x headroom.
263
+ */
264
+ const fifteenMinutesAgo: Date = OneUptimeDate.addRemoveMinutes(
257
265
  OneUptimeDate.getCurrentDate(),
258
- -5,
266
+ -15,
259
267
  );
260
268
 
261
269
  const connectedApps: Array<Model> = await this.findBy({
262
270
  query: {
263
271
  otelCollectorStatus: "connected",
264
- lastSeenAt: QueryHelper.lessThan(fiveMinutesAgo),
272
+ lastSeenAt: QueryHelper.lessThan(fifteenMinutesAgo),
265
273
  },
266
274
  select: {
267
275
  _id: true,
@@ -303,15 +303,23 @@ export class Service extends DatabaseService<Model> {
303
303
 
304
304
  @CaptureSpan()
305
305
  public async markDisconnectedFunctions(): Promise<void> {
306
- const fiveMinutesAgo: Date = OneUptimeDate.addRemoveMinutes(
306
+ /*
307
+ * Threshold must stay well above the 5-minute OTel ingest
308
+ * maintenance fence (MAINTENANCE_FENCE_TTL_SECONDS in
309
+ * OtelIngestBaseService) — lastSeenAt is legitimately up to
310
+ * ~5 minutes stale during continuous telemetry, so a threshold
311
+ * equal to the fence TTL flaps healthy resources. 15 minutes
312
+ * gives 3x headroom.
313
+ */
314
+ const fifteenMinutesAgo: Date = OneUptimeDate.addRemoveMinutes(
307
315
  OneUptimeDate.getCurrentDate(),
308
- -5,
316
+ -15,
309
317
  );
310
318
 
311
319
  const connectedFunctions: Array<Model> = await this.findBy({
312
320
  query: {
313
321
  otelCollectorStatus: "connected",
314
- lastSeenAt: QueryHelper.lessThan(fiveMinutesAgo),
322
+ lastSeenAt: QueryHelper.lessThan(fifteenMinutesAgo),
315
323
  },
316
324
  select: {
317
325
  _id: true,
@@ -26,9 +26,13 @@ import ServiceModel from "../../Models/DatabaseModels/Service";
26
26
  import HostService from "./HostService";
27
27
  import DockerHostService from "./DockerHostService";
28
28
  import KubernetesClusterService from "./KubernetesClusterService";
29
+ import ProxmoxClusterService from "./ProxmoxClusterService";
30
+ import CephClusterService from "./CephClusterService";
29
31
  import Host from "../../Models/DatabaseModels/Host";
30
32
  import DockerHost from "../../Models/DatabaseModels/DockerHost";
31
33
  import KubernetesCluster from "../../Models/DatabaseModels/KubernetesCluster";
34
+ import ProxmoxCluster from "../../Models/DatabaseModels/ProxmoxCluster";
35
+ import CephCluster from "../../Models/DatabaseModels/CephCluster";
32
36
  import ServiceType from "../../Types/Telemetry/ServiceType";
33
37
  import {
34
38
  AverageSpanRowSizeInBytes,
@@ -347,9 +351,10 @@ export class Service extends DatabaseService<Model> {
347
351
  /*
348
352
  * Map of resourceId -> retainTelemetryDataForDays for every resource in
349
353
  * the project that can own telemetry (Service, Host, DockerHost,
350
- * KubernetesCluster). Used to scale billed cost by the actual retention
351
- * applied to each resource's telemetry. Resources without an override
352
- * (and the unattributed bucket) fall back to the project default.
354
+ * KubernetesCluster, ProxmoxCluster, CephCluster). Used to scale billed
355
+ * cost by the actual retention applied to each resource's telemetry.
356
+ * Resources without an override (and the unattributed bucket) fall back
357
+ * to the project default.
353
358
  */
354
359
  @CaptureSpan()
355
360
  private async buildTelemetryRetentionMap(
@@ -422,6 +427,39 @@ export class Service extends DatabaseService<Model> {
422
427
  }
423
428
  }
424
429
 
430
+ const proxmoxClusters: Array<ProxmoxCluster> =
431
+ await ProxmoxClusterService.findBy({
432
+ query: { projectId: projectId },
433
+ select: { _id: true, retainTelemetryDataForDays: true },
434
+ skip: 0,
435
+ limit: LIMIT_MAX,
436
+ props: { isRoot: true },
437
+ });
438
+ for (const proxmoxCluster of proxmoxClusters) {
439
+ if (proxmoxCluster.id && proxmoxCluster.retainTelemetryDataForDays) {
440
+ retentionByServiceId.set(
441
+ proxmoxCluster.id.toString(),
442
+ proxmoxCluster.retainTelemetryDataForDays,
443
+ );
444
+ }
445
+ }
446
+
447
+ const cephClusters: Array<CephCluster> = await CephClusterService.findBy({
448
+ query: { projectId: projectId },
449
+ select: { _id: true, retainTelemetryDataForDays: true },
450
+ skip: 0,
451
+ limit: LIMIT_MAX,
452
+ props: { isRoot: true },
453
+ });
454
+ for (const cephCluster of cephClusters) {
455
+ if (cephCluster.id && cephCluster.retainTelemetryDataForDays) {
456
+ retentionByServiceId.set(
457
+ cephCluster.id.toString(),
458
+ cephCluster.retainTelemetryDataForDays,
459
+ );
460
+ }
461
+ }
462
+
425
463
  return retentionByServiceId;
426
464
  }
427
465
 
@@ -159,6 +159,8 @@ export class TraceAggregationService {
159
159
  ["hostId", ServiceType.Host],
160
160
  ["dockerHostId", ServiceType.DockerHost],
161
161
  ["kubernetesClusterId", ServiceType.KubernetesCluster],
162
+ ["proxmoxClusterId", ServiceType.ProxmoxCluster],
163
+ ["cephClusterId", ServiceType.CephCluster],
162
164
  ["serverlessFunctionId", ServiceType.ServerlessFunction],
163
165
  ["cloudResourceId", ServiceType.CloudResource],
164
166
  ["rumApplicationId", ServiceType.RealUserMonitor],
@@ -1,8 +1,8 @@
1
1
  import AggregationInterval from "../../../Types/BaseDatabase/AggregationInterval";
2
+ import AggregationIntervalUtil from "../../../Types/BaseDatabase/AggregationIntervalUtil";
2
3
  import CommonAggregateBy from "../../../Types/BaseDatabase/AggregateBy";
3
4
  import AnalyticsBaseModel from "../../../Models/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel";
4
5
  import DatabaseCommonInteractionProps from "../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
5
- import OneUptimeDate from "../../../Types/Date";
6
6
  import CaptureSpan from "../../Utils/Telemetry/CaptureSpan";
7
7
 
8
8
  export default interface AggregateBy<TBaseModel extends AnalyticsBaseModel>
@@ -11,32 +11,17 @@ export default interface AggregateBy<TBaseModel extends AnalyticsBaseModel>
11
11
  }
12
12
 
13
13
  export class AggregateUtil {
14
+ /*
15
+ * Delegates to the isomorphic AggregationIntervalUtil so browser
16
+ * code reconstructing the server's bucket grid (heartbeat
17
+ * availability charts) always agrees with the interval the
18
+ * statement generator compiles into `toStartOfInterval(...)`.
19
+ */
14
20
  @CaptureSpan()
15
21
  public static getAggregationInterval(data: {
16
22
  startDate: Date;
17
23
  endDate: Date;
18
24
  }): AggregationInterval {
19
- data.startDate = OneUptimeDate.fromString(data.startDate);
20
- data.endDate = OneUptimeDate.fromString(data.endDate);
21
-
22
- const diff: number = data.endDate.getTime() - data.startDate.getTime();
23
-
24
- if (diff <= 1000 * 60 * 60 * 3) {
25
- // if less than 3 hours, then get minute precision
26
- return AggregationInterval.Minute;
27
- } else if (diff <= 1000 * 60 * 60 * 24 * 7) {
28
- // 3 days
29
- return AggregationInterval.Hour;
30
- } else if (diff <= 1000 * 60 * 60 * 24 * 7 * 6) {
31
- // 3 weeks
32
- return AggregationInterval.Day;
33
- } else if (diff <= 1000 * 60 * 60 * 24 * 30 * 6) {
34
- // 3 months
35
- return AggregationInterval.Week;
36
- } else if (diff <= 1000 * 60 * 60 * 24 * 365 * 6) {
37
- // 3 years
38
- return AggregationInterval.Month;
39
- }
40
- return AggregationInterval.Year;
25
+ return AggregationIntervalUtil.getAggregationIntervalForWindow(data);
41
26
  }
42
27
  }
@@ -1,10 +1,12 @@
1
1
  import Alert from "../../../Models/DatabaseModels/Alert";
2
2
  import AlertSeverity from "../../../Models/DatabaseModels/AlertSeverity";
3
3
  import AlertStateTimeline from "../../../Models/DatabaseModels/AlertStateTimeline";
4
+ import CephCluster from "../../../Models/DatabaseModels/CephCluster";
4
5
  import Host from "../../../Models/DatabaseModels/Host";
5
6
  import Label from "../../../Models/DatabaseModels/Label";
6
7
  import Monitor from "../../../Models/DatabaseModels/Monitor";
7
8
  import OnCallDutyPolicy from "../../../Models/DatabaseModels/OnCallDutyPolicy";
9
+ import ProxmoxCluster from "../../../Models/DatabaseModels/ProxmoxCluster";
8
10
  import Service from "../../../Models/DatabaseModels/Service";
9
11
  import SortOrder from "../../../Types/BaseDatabase/SortOrder";
10
12
  import { LIMIT_PER_PROJECT } from "../../../Types/Database/LimitMax";
@@ -24,6 +26,9 @@ import ServiceService from "../../Services/ServiceService";
24
26
  import logger, { LogAttributes } from "../Logger";
25
27
  import CaptureSpan from "../Telemetry/CaptureSpan";
26
28
  import DataToProcess from "./DataToProcess";
29
+ import MonitorClusterContextUtil, {
30
+ MonitorClusterContext,
31
+ } from "./MonitorClusterContext";
27
32
  import MonitorTemplateUtil from "./MonitorTemplateUtil";
28
33
  import { JSONObject } from "../../../Types/JSON";
29
34
  import OneUptimeDate from "../../../Types/Date";
@@ -159,6 +164,19 @@ export default class MonitorAlert {
159
164
  return;
160
165
  }
161
166
 
167
+ /*
168
+ * Proxmox/Ceph monitors: resolve the monitored cluster once per
169
+ * evaluation (lookup-only, from the step config's clusterIdentifier)
170
+ * so every alert created below is attached to it. Series labels
171
+ * cannot supply this — they carry datapoint labels (`id`,
172
+ * `ceph_daemon`, `pool_id`), not cluster identity, and ungrouped
173
+ * templates have no series at all. No-op for other monitor types.
174
+ */
175
+ const clusterContext: MonitorClusterContext =
176
+ await MonitorClusterContextUtil.resolveClusterContextForMonitor({
177
+ monitor: input.monitor,
178
+ });
179
+
162
180
  const seriesToProcess: Array<PerSeriesCriteriaMatch | undefined> =
163
181
  input.matchesPerSeries && input.matchesPerSeries.length > 0
164
182
  ? input.matchesPerSeries
@@ -376,6 +394,33 @@ export default class MonitorAlert {
376
394
  }
377
395
  }
378
396
 
397
+ /*
398
+ * Deterministic Proxmox/Ceph cluster link from the monitor's
399
+ * step config (resolved once above). Series labels never carry
400
+ * cluster identity for these monitor types, so this — not the
401
+ * label path above — is what makes the per-cluster Activity
402
+ * tabs and badge counts see monitor-created alerts. Runs for
403
+ * both grouped and ungrouped alerts.
404
+ */
405
+ if (clusterContext.proxmoxClusterIds.length > 0) {
406
+ alert.proxmoxClusters = clusterContext.proxmoxClusterIds.map(
407
+ (id: string): ProxmoxCluster => {
408
+ const cluster: ProxmoxCluster = new ProxmoxCluster();
409
+ cluster._id = id;
410
+ return cluster;
411
+ },
412
+ );
413
+ }
414
+ if (clusterContext.cephClusterIds.length > 0) {
415
+ alert.cephClusters = clusterContext.cephClusterIds.map(
416
+ (id: string): CephCluster => {
417
+ const cluster: CephCluster = new CephCluster();
418
+ cluster._id = id;
419
+ return cluster;
420
+ },
421
+ );
422
+ }
423
+
379
424
  alert.onCallDutyPolicies =
380
425
  criteriaAlert.onCallPolicyIds?.map((id: ObjectID) => {
381
426
  const onCallPolicy: OnCallDutyPolicy = new OnCallDutyPolicy();