@oneuptime/common 11.0.1 → 11.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (341) 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/Telemetry/EntityRelationship.test.ts +49 -0
  89. package/Tests/Utils/Telemetry/HeartbeatAvailability.test.ts +423 -0
  90. package/Types/BaseDatabase/AggregationIntervalUtil.ts +74 -0
  91. package/Types/Dashboard/DashboardComponentType.ts +4 -0
  92. package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +2 -0
  93. package/Types/Dashboard/DashboardComponents/DashboardCephOsdListComponent.ts +15 -0
  94. package/Types/Dashboard/DashboardComponents/DashboardCephPoolListComponent.ts +14 -0
  95. package/Types/Dashboard/DashboardComponents/DashboardProxmoxGuestListComponent.ts +17 -0
  96. package/Types/Dashboard/DashboardComponents/DashboardProxmoxNodeListComponent.ts +16 -0
  97. package/Types/Dashboard/DashboardTemplates.ts +446 -0
  98. package/Types/Icon/IconProp.ts +2 -0
  99. package/Types/Monitor/CephAlertTemplates.ts +1647 -0
  100. package/Types/Monitor/CephMetricCatalog.ts +409 -0
  101. package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +44 -0
  102. package/Types/Monitor/MonitorStep.ts +64 -0
  103. package/Types/Monitor/MonitorStepCephMonitor.ts +57 -0
  104. package/Types/Monitor/MonitorStepProxmoxMonitor.ts +81 -0
  105. package/Types/Monitor/MonitorType.ts +29 -1
  106. package/Types/Monitor/ProxmoxAlertTemplates.ts +899 -0
  107. package/Types/Monitor/ProxmoxMetricCatalog.ts +382 -0
  108. package/Types/Permission.ts +464 -0
  109. package/Types/Telemetry/EntityType.ts +11 -0
  110. package/Types/Telemetry/ServiceType.ts +2 -0
  111. package/UI/Components/Icon/Icon.tsx +84 -0
  112. package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +9 -5
  113. package/UI/Utils/Telemetry/Telemetry.ts +16 -21
  114. package/UI/Utils/TelemetryService.ts +7 -3
  115. package/Utils/Dashboard/Components/DashboardCephOsdListComponent.ts +63 -0
  116. package/Utils/Dashboard/Components/DashboardCephPoolListComponent.ts +32 -0
  117. package/Utils/Dashboard/Components/DashboardCephResourceListShared.ts +61 -0
  118. package/Utils/Dashboard/Components/DashboardProxmoxGuestListComponent.ts +69 -0
  119. package/Utils/Dashboard/Components/DashboardProxmoxNodeListComponent.ts +55 -0
  120. package/Utils/Dashboard/Components/DashboardProxmoxResourceListShared.ts +61 -0
  121. package/Utils/Dashboard/Components/Index.ts +28 -0
  122. package/Utils/Telemetry/EntityKey.ts +35 -0
  123. package/Utils/Telemetry/EntityRelationship.ts +6 -0
  124. package/Utils/Telemetry/HeartbeatAvailability.ts +262 -0
  125. package/build/dist/Models/DatabaseModels/Alert.js +108 -0
  126. package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
  127. package/build/dist/Models/DatabaseModels/CephCluster.js +992 -0
  128. package/build/dist/Models/DatabaseModels/CephCluster.js.map +1 -0
  129. package/build/dist/Models/DatabaseModels/CephClusterLabelRule.js +522 -0
  130. package/build/dist/Models/DatabaseModels/CephClusterLabelRule.js.map +1 -0
  131. package/build/dist/Models/DatabaseModels/CephClusterOwnerRule.js +603 -0
  132. package/build/dist/Models/DatabaseModels/CephClusterOwnerRule.js.map +1 -0
  133. package/build/dist/Models/DatabaseModels/CephClusterOwnerTeam.js +503 -0
  134. package/build/dist/Models/DatabaseModels/CephClusterOwnerTeam.js.map +1 -0
  135. package/build/dist/Models/DatabaseModels/CephClusterOwnerUser.js +502 -0
  136. package/build/dist/Models/DatabaseModels/CephClusterOwnerUser.js.map +1 -0
  137. package/build/dist/Models/DatabaseModels/CephResource.js +846 -0
  138. package/build/dist/Models/DatabaseModels/CephResource.js.map +1 -0
  139. package/build/dist/Models/DatabaseModels/Host.js +63 -0
  140. package/build/dist/Models/DatabaseModels/Host.js.map +1 -1
  141. package/build/dist/Models/DatabaseModels/Incident.js +108 -0
  142. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  143. package/build/dist/Models/DatabaseModels/Index.js +24 -0
  144. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  145. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js +967 -0
  146. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js.map +1 -0
  147. package/build/dist/Models/DatabaseModels/ProxmoxClusterLabelRule.js +522 -0
  148. package/build/dist/Models/DatabaseModels/ProxmoxClusterLabelRule.js.map +1 -0
  149. package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerRule.js +603 -0
  150. package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerRule.js.map +1 -0
  151. package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerTeam.js +503 -0
  152. package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerTeam.js.map +1 -0
  153. package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerUser.js +502 -0
  154. package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerUser.js.map +1 -0
  155. package/build/dist/Models/DatabaseModels/ProxmoxResource.js +761 -0
  156. package/build/dist/Models/DatabaseModels/ProxmoxResource.js.map +1 -0
  157. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +108 -0
  158. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
  159. package/build/dist/Server/API/BillingInvoiceAPI.js +35 -5
  160. package/build/dist/Server/API/BillingInvoiceAPI.js.map +1 -1
  161. package/build/dist/Server/API/CephResourceAPI.js +98 -0
  162. package/build/dist/Server/API/CephResourceAPI.js.map +1 -0
  163. package/build/dist/Server/API/DashboardAPI.js +46 -0
  164. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  165. package/build/dist/Server/API/ProjectAPI.js +11 -0
  166. package/build/dist/Server/API/ProjectAPI.js.map +1 -1
  167. package/build/dist/Server/API/ProxmoxResourceAPI.js +95 -0
  168. package/build/dist/Server/API/ProxmoxResourceAPI.js.map +1 -0
  169. package/build/dist/Server/API/ResellerPlanAPI.js +17 -3
  170. package/build/dist/Server/API/ResellerPlanAPI.js.map +1 -1
  171. package/build/dist/Server/Infrastructure/GlobalCache.js +7 -2
  172. package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
  173. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781500000000-AddProxmoxAndCephClusterTables.js +76 -0
  174. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781500000000-AddProxmoxAndCephClusterTables.js.map +1 -0
  175. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781600000000-AddProxmoxCephV2Columns.js +108 -0
  176. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781600000000-AddProxmoxCephV2Columns.js.map +1 -0
  177. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781600000001-AddProxmoxCephActivityAndRules.js +253 -0
  178. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781600000001-AddProxmoxCephActivityAndRules.js.map +1 -0
  179. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781700000000-AddProxmoxCephV3Columns.js +43 -0
  180. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781700000000-AddProxmoxCephV3Columns.js.map +1 -0
  181. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  182. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  183. package/build/dist/Server/Infrastructure/Redis.js +31 -8
  184. package/build/dist/Server/Infrastructure/Redis.js.map +1 -1
  185. package/build/dist/Server/Services/AnalyticsDatabaseService.js +1 -1
  186. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  187. package/build/dist/Server/Services/BillingService.js +85 -23
  188. package/build/dist/Server/Services/BillingService.js.map +1 -1
  189. package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js +166 -0
  190. package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js.map +1 -0
  191. package/build/dist/Server/Services/CephClusterLabelRuleService.js +13 -0
  192. package/build/dist/Server/Services/CephClusterLabelRuleService.js.map +1 -0
  193. package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js +186 -0
  194. package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js.map +1 -0
  195. package/build/dist/Server/Services/CephClusterOwnerRuleService.js +13 -0
  196. package/build/dist/Server/Services/CephClusterOwnerRuleService.js.map +1 -0
  197. package/build/dist/Server/Services/CephClusterOwnerTeamService.js +9 -0
  198. package/build/dist/Server/Services/CephClusterOwnerTeamService.js.map +1 -0
  199. package/build/dist/Server/Services/CephClusterOwnerUserService.js +9 -0
  200. package/build/dist/Server/Services/CephClusterOwnerUserService.js.map +1 -0
  201. package/build/dist/Server/Services/CephClusterService.js +353 -0
  202. package/build/dist/Server/Services/CephClusterService.js.map +1 -0
  203. package/build/dist/Server/Services/CephResourceService.js +257 -0
  204. package/build/dist/Server/Services/CephResourceService.js.map +1 -0
  205. package/build/dist/Server/Services/CloudResourceService.js +10 -2
  206. package/build/dist/Server/Services/CloudResourceService.js.map +1 -1
  207. package/build/dist/Server/Services/DockerHostService.js +10 -2
  208. package/build/dist/Server/Services/DockerHostService.js.map +1 -1
  209. package/build/dist/Server/Services/ExceptionAggregationService.js +2 -0
  210. package/build/dist/Server/Services/ExceptionAggregationService.js.map +1 -1
  211. package/build/dist/Server/Services/HostService.js +10 -2
  212. package/build/dist/Server/Services/HostService.js.map +1 -1
  213. package/build/dist/Server/Services/Index.js +24 -0
  214. package/build/dist/Server/Services/Index.js.map +1 -1
  215. package/build/dist/Server/Services/KubernetesClusterService.js +10 -2
  216. package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
  217. package/build/dist/Server/Services/LogAggregationService.js +2 -0
  218. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  219. package/build/dist/Server/Services/MetricAggregationService.js +2 -0
  220. package/build/dist/Server/Services/MetricAggregationService.js.map +1 -1
  221. package/build/dist/Server/Services/OpenTelemetryIngestService.js +37 -7
  222. package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
  223. package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js +166 -0
  224. package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js.map +1 -0
  225. package/build/dist/Server/Services/ProxmoxClusterLabelRuleService.js +13 -0
  226. package/build/dist/Server/Services/ProxmoxClusterLabelRuleService.js.map +1 -0
  227. package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js +186 -0
  228. package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js.map +1 -0
  229. package/build/dist/Server/Services/ProxmoxClusterOwnerRuleService.js +13 -0
  230. package/build/dist/Server/Services/ProxmoxClusterOwnerRuleService.js.map +1 -0
  231. package/build/dist/Server/Services/ProxmoxClusterOwnerTeamService.js +9 -0
  232. package/build/dist/Server/Services/ProxmoxClusterOwnerTeamService.js.map +1 -0
  233. package/build/dist/Server/Services/ProxmoxClusterOwnerUserService.js +9 -0
  234. package/build/dist/Server/Services/ProxmoxClusterOwnerUserService.js.map +1 -0
  235. package/build/dist/Server/Services/ProxmoxClusterService.js +337 -0
  236. package/build/dist/Server/Services/ProxmoxClusterService.js.map +1 -0
  237. package/build/dist/Server/Services/ProxmoxResourceService.js +285 -0
  238. package/build/dist/Server/Services/ProxmoxResourceService.js.map +1 -0
  239. package/build/dist/Server/Services/RumApplicationService.js +10 -2
  240. package/build/dist/Server/Services/RumApplicationService.js.map +1 -1
  241. package/build/dist/Server/Services/ServerlessFunctionService.js +10 -2
  242. package/build/dist/Server/Services/ServerlessFunctionService.js.map +1 -1
  243. package/build/dist/Server/Services/TelemetryUsageBillingService.js +30 -3
  244. package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
  245. package/build/dist/Server/Services/TraceAggregationService.js +2 -0
  246. package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
  247. package/build/dist/Server/Types/AnalyticsDatabase/AggregateBy.js +8 -25
  248. package/build/dist/Server/Types/AnalyticsDatabase/AggregateBy.js.map +1 -1
  249. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +36 -0
  250. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  251. package/build/dist/Server/Utils/Monitor/MonitorClusterContext.js +90 -0
  252. package/build/dist/Server/Utils/Monitor/MonitorClusterContext.js.map +1 -0
  253. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +228 -4
  254. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  255. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +103 -8
  256. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  257. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js +23 -6
  258. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -1
  259. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +3 -1
  260. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  261. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +23 -0
  262. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
  263. package/build/dist/Server/Utils/Profiling.js +24 -3
  264. package/build/dist/Server/Utils/Profiling.js.map +1 -1
  265. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +4 -0
  266. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  267. package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js +854 -0
  268. package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js.map +1 -0
  269. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +62 -0
  270. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
  271. package/build/dist/Server/Utils/Telemetry.js +8 -10
  272. package/build/dist/Server/Utils/Telemetry.js.map +1 -1
  273. package/build/dist/Types/BaseDatabase/AggregationIntervalUtil.js +69 -0
  274. package/build/dist/Types/BaseDatabase/AggregationIntervalUtil.js.map +1 -0
  275. package/build/dist/Types/Dashboard/DashboardComponentType.js +4 -0
  276. package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
  277. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +2 -0
  278. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
  279. package/build/dist/Types/Dashboard/DashboardComponents/DashboardCephOsdListComponent.js +2 -0
  280. package/build/dist/Types/Dashboard/DashboardComponents/DashboardCephOsdListComponent.js.map +1 -0
  281. package/build/dist/Types/Dashboard/DashboardComponents/DashboardCephPoolListComponent.js +2 -0
  282. package/build/dist/Types/Dashboard/DashboardComponents/DashboardCephPoolListComponent.js.map +1 -0
  283. package/build/dist/Types/Dashboard/DashboardComponents/DashboardProxmoxGuestListComponent.js +2 -0
  284. package/build/dist/Types/Dashboard/DashboardComponents/DashboardProxmoxGuestListComponent.js.map +1 -0
  285. package/build/dist/Types/Dashboard/DashboardComponents/DashboardProxmoxNodeListComponent.js +2 -0
  286. package/build/dist/Types/Dashboard/DashboardComponents/DashboardProxmoxNodeListComponent.js.map +1 -0
  287. package/build/dist/Types/Dashboard/DashboardTemplates.js +394 -0
  288. package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
  289. package/build/dist/Types/Icon/IconProp.js +2 -0
  290. package/build/dist/Types/Icon/IconProp.js.map +1 -1
  291. package/build/dist/Types/Monitor/CephAlertTemplates.js +1379 -0
  292. package/build/dist/Types/Monitor/CephAlertTemplates.js.map +1 -0
  293. package/build/dist/Types/Monitor/CephMetricCatalog.js +353 -0
  294. package/build/dist/Types/Monitor/CephMetricCatalog.js.map +1 -0
  295. package/build/dist/Types/Monitor/MonitorStep.js +46 -0
  296. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  297. package/build/dist/Types/Monitor/MonitorStepCephMonitor.js +34 -0
  298. package/build/dist/Types/Monitor/MonitorStepCephMonitor.js.map +1 -0
  299. package/build/dist/Types/Monitor/MonitorStepProxmoxMonitor.js +36 -0
  300. package/build/dist/Types/Monitor/MonitorStepProxmoxMonitor.js.map +1 -0
  301. package/build/dist/Types/Monitor/MonitorType.js +27 -1
  302. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  303. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +743 -0
  304. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js.map +1 -0
  305. package/build/dist/Types/Monitor/ProxmoxMetricCatalog.js +320 -0
  306. package/build/dist/Types/Monitor/ProxmoxMetricCatalog.js.map +1 -0
  307. package/build/dist/Types/Permission.js +408 -0
  308. package/build/dist/Types/Permission.js.map +1 -1
  309. package/build/dist/Types/Telemetry/EntityType.js +11 -0
  310. package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
  311. package/build/dist/Types/Telemetry/ServiceType.js +2 -0
  312. package/build/dist/Types/Telemetry/ServiceType.js.map +1 -1
  313. package/build/dist/UI/Components/Icon/Icon.js +33 -0
  314. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  315. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +5 -1
  316. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  317. package/build/dist/UI/Utils/Telemetry/Telemetry.js +11 -10
  318. package/build/dist/UI/Utils/Telemetry/Telemetry.js.map +1 -1
  319. package/build/dist/UI/Utils/TelemetryService.js +5 -2
  320. package/build/dist/UI/Utils/TelemetryService.js.map +1 -1
  321. package/build/dist/Utils/Dashboard/Components/DashboardCephOsdListComponent.js +50 -0
  322. package/build/dist/Utils/Dashboard/Components/DashboardCephOsdListComponent.js.map +1 -0
  323. package/build/dist/Utils/Dashboard/Components/DashboardCephPoolListComponent.js +27 -0
  324. package/build/dist/Utils/Dashboard/Components/DashboardCephPoolListComponent.js.map +1 -0
  325. package/build/dist/Utils/Dashboard/Components/DashboardCephResourceListShared.js +46 -0
  326. package/build/dist/Utils/Dashboard/Components/DashboardCephResourceListShared.js.map +1 -0
  327. package/build/dist/Utils/Dashboard/Components/DashboardProxmoxGuestListComponent.js +55 -0
  328. package/build/dist/Utils/Dashboard/Components/DashboardProxmoxGuestListComponent.js.map +1 -0
  329. package/build/dist/Utils/Dashboard/Components/DashboardProxmoxNodeListComponent.js +42 -0
  330. package/build/dist/Utils/Dashboard/Components/DashboardProxmoxNodeListComponent.js.map +1 -0
  331. package/build/dist/Utils/Dashboard/Components/DashboardProxmoxResourceListShared.js +46 -0
  332. package/build/dist/Utils/Dashboard/Components/DashboardProxmoxResourceListShared.js.map +1 -0
  333. package/build/dist/Utils/Dashboard/Components/Index.js +16 -0
  334. package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
  335. package/build/dist/Utils/Telemetry/EntityKey.js +27 -0
  336. package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -1
  337. package/build/dist/Utils/Telemetry/EntityRelationship.js +3 -0
  338. package/build/dist/Utils/Telemetry/EntityRelationship.js.map +1 -1
  339. package/build/dist/Utils/Telemetry/HeartbeatAvailability.js +174 -0
  340. package/build/dist/Utils/Telemetry/HeartbeatAvailability.js.map +1 -0
  341. package/package.json +29 -21
@@ -0,0 +1,854 @@
1
+ import OneUptimeDate from "../../../Types/Date";
2
+ import logger from "../Logger";
3
+ /*
4
+ * ------------------------------------------------------------------
5
+ * Proxmox / Ceph snapshot scan — pure fold & derive helpers
6
+ * ------------------------------------------------------------------
7
+ *
8
+ * Extracted from App/FeatureSet/Telemetry/Services/
9
+ * OtelMetricsIngestService.ts (WI-21 refactor-for-testability, no
10
+ * behavior change). The ingest service owns the I/O: it walks the
11
+ * OTLP payload, calls bufferProxmoxSnapshotMetric /
12
+ * bufferCephSnapshotMetric per datapoint, and at flush time maps the
13
+ * folded buffers through computeProxmoxGuestBackedUp /
14
+ * deriveProxmoxClusterSnapshotExtras / deriveCephClusterSnapshotExtras
15
+ * before handing the results to ProxmoxResourceService /
16
+ * CephResourceService / *ClusterService. Everything in this module is
17
+ * pure (Map/object mutation only — no DB, no network), which is what
18
+ * makes the snapshot-scan semantics unit-testable:
19
+ *
20
+ * - identity labels fold first-non-null-wins; status/metric fields
21
+ * fold newest-observedAt-wins,
22
+ * - count columns are only derived when the batch carried the
23
+ * matching identity series (never zero a count on a partial
24
+ * batch — the COALESCE-per-column contract),
25
+ * - non-allow-listed metric names are skipped via the exported
26
+ * PVE_/CEPH_SNAPSHOT_METRIC_NAMES sets.
27
+ */
28
+ /*
29
+ * Proxmox snapshot metrics — emitted by pve-exporter (prometheus
30
+ * receiver), identity in the `id` datapoint label (node/pve1,
31
+ * qemu/100, lxc/101, storage/local) plus the pve.scope / pve.type /
32
+ * pve.id attributes the agent's transform processor derives from it.
33
+ * Unlike K8s there is no separate object stream: identity, status AND
34
+ * the latest-metric mirror all arrive on every scrape, so the same
35
+ * scan feeds the ProxmoxResource inventory upsert and the
36
+ * ProxmoxCluster count/version snapshot columns (single source — the
37
+ * list-page counts and the sidebar badges can never drift).
38
+ *
39
+ * pve_cpu_usage_ratio is already a true 0..1 ratio — no allocatable-
40
+ * denominator cache is needed, unlike K8s cpuCoresToPercent.
41
+ */
42
+ export const PVE_SNAPSHOT_METRIC_NAMES = new Set([
43
+ // Identity / status (WI-3 cluster counts derive from these)
44
+ "pve_up",
45
+ "pve_node_info",
46
+ "pve_guest_info",
47
+ "pve_storage_info",
48
+ "pve_version_info",
49
+ "pve_ha_state",
50
+ "pve_onboot_status",
51
+ // Latest-metric mirror (WI-6 inventory columns)
52
+ "pve_uptime_seconds",
53
+ "pve_cpu_usage_ratio",
54
+ "pve_memory_usage_bytes",
55
+ "pve_memory_size_bytes",
56
+ "pve_disk_usage_bytes",
57
+ "pve_disk_size_bytes",
58
+ /*
59
+ * Backup coverage (WI-24) — cluster-level backup-info collector.
60
+ * pve_not_backed_up_total = count of guests not covered by ANY
61
+ * backup job; pve_not_backed_up_info = one series per uncovered
62
+ * guest, labeled only `id`. "Covered by a job" ≠ "backed up
63
+ * recently/successfully" — freshness needs the PVE task log or PBS
64
+ * API (v4 API-agent track).
65
+ */
66
+ "pve_not_backed_up_total",
67
+ "pve_not_backed_up_info",
68
+ ]);
69
+ /*
70
+ * Ceph snapshot metrics — emitted by the ceph-mgr prometheus module
71
+ * (honor_labels), identity in the `ceph_daemon` (osd.3, mon.a, …) or
72
+ * `pool_id` datapoint labels. Same single-source rule as Proxmox: one
73
+ * scan feeds the CephResource inventory and the CephCluster
74
+ * count/health/capacity snapshot columns.
75
+ */
76
+ export const CEPH_SNAPSHOT_METRIC_NAMES = new Set([
77
+ // Cluster-level health / capacity (WI-3 columns)
78
+ "ceph_health_status",
79
+ "ceph_cluster_total_bytes",
80
+ "ceph_cluster_total_used_bytes",
81
+ // Daemon identity / status
82
+ "ceph_mon_quorum_status",
83
+ "ceph_mon_metadata",
84
+ "ceph_osd_up",
85
+ "ceph_osd_in",
86
+ "ceph_osd_metadata",
87
+ "ceph_mgr_metadata",
88
+ "ceph_mds_metadata",
89
+ "ceph_rgw_metadata",
90
+ // OSD latest-metric mirror (WI-6 inventory columns)
91
+ "ceph_osd_stat_bytes",
92
+ "ceph_osd_stat_bytes_used",
93
+ "ceph_osd_apply_latency_ms",
94
+ "ceph_osd_commit_latency_ms",
95
+ "ceph_osd_numpg",
96
+ // Pool identity + latest-metric mirror
97
+ "ceph_pool_metadata",
98
+ "ceph_pool_stored",
99
+ "ceph_pool_max_avail",
100
+ "ceph_pool_objects",
101
+ "ceph_pool_rd",
102
+ "ceph_pool_wr",
103
+ ]);
104
+ /*
105
+ * Same finite-or-null coercion contract as the ingest service's
106
+ * toNumberOrNull (NaN / ±Infinity fold to null so a malformed
107
+ * datapoint is skipped rather than poisoning a snapshot column).
108
+ */
109
+ function toNumberOrNull(value) {
110
+ if (typeof value === "number") {
111
+ return Number.isFinite(value) ? value : null;
112
+ }
113
+ if (typeof value === "string") {
114
+ const parsed = Number.parseFloat(value);
115
+ return Number.isFinite(parsed) ? parsed : null;
116
+ }
117
+ return null;
118
+ }
119
+ /*
120
+ * Same fall-back-to-now parse contract as the ingest service's
121
+ * safeParseUnixNano — only the Date is needed on the snapshot path.
122
+ */
123
+ function parseUnixNanoToDate(value, context) {
124
+ let numericValue = OneUptimeDate.getCurrentDateAsUnixNano();
125
+ if (value !== undefined && value !== null) {
126
+ try {
127
+ if (typeof value === "string") {
128
+ const parsed = Number.parseFloat(value);
129
+ if (isNaN(parsed)) {
130
+ throw new Error(`Invalid timestamp string: ${value}`);
131
+ }
132
+ numericValue = parsed;
133
+ }
134
+ else if (typeof value === "number") {
135
+ if (!Number.isFinite(value)) {
136
+ throw new Error(`Invalid timestamp number: ${value}`);
137
+ }
138
+ numericValue = value;
139
+ }
140
+ }
141
+ catch (error) {
142
+ logger.warn(`Error processing ${context}: ${error instanceof Error ? error.message : String(error)}, using current time`);
143
+ numericValue = OneUptimeDate.getCurrentDateAsUnixNano();
144
+ }
145
+ }
146
+ return OneUptimeDate.fromUnixNano(numericValue);
147
+ }
148
+ // Same trim-or-null read contract as OtelIngestBaseService.getStringAttribute.
149
+ function getStringAttribute(attributes, key) {
150
+ for (const attribute of attributes) {
151
+ if (attribute["key"] === key &&
152
+ attribute["value"] &&
153
+ attribute["value"]["stringValue"]) {
154
+ const value = attribute["value"]["stringValue"];
155
+ if (typeof value === "string" && value.trim()) {
156
+ return value.trim();
157
+ }
158
+ }
159
+ }
160
+ return null;
161
+ }
162
+ export function getOrCreateProxmoxClusterSnapshot(buffer, clusterIdStr) {
163
+ let entry = buffer.get(clusterIdStr);
164
+ if (!entry) {
165
+ entry = {
166
+ sawNodeIdentity: false,
167
+ sawNodeUp: false,
168
+ sawGuestIdentity: false,
169
+ sawStorageIdentity: false,
170
+ pveVersion: null,
171
+ sawBackupInfo: false,
172
+ guestsWithoutBackupCount: null,
173
+ notBackedUpIds: new Set(),
174
+ };
175
+ buffer.set(clusterIdStr, entry);
176
+ }
177
+ return entry;
178
+ }
179
+ /*
180
+ * Fold one pve_* datapoint into the per-cluster buffers. Identity
181
+ * lives in the `id` DATAPOINT label (prometheus receiver), so this
182
+ * reads the raw datapoint attribute array — not the merged
183
+ * resource-prefixed map the K8s scan uses.
184
+ */
185
+ export function bufferProxmoxSnapshotMetric(data) {
186
+ const valueFromInt = toNumberOrNull(data.datapoint["asInt"]);
187
+ const valueFromDouble = toNumberOrNull(data.datapoint["asDouble"]);
188
+ const rawValue = valueFromDouble !== null && valueFromDouble !== void 0 ? valueFromDouble : valueFromInt;
189
+ if (rawValue === null) {
190
+ return;
191
+ }
192
+ const observedAt = parseUnixNanoToDate(data.datapoint["timeUnixNano"], "pve snapshot timeUnixNano");
193
+ const dpAttributes = data.datapoint["attributes"] || [];
194
+ const cluster = getOrCreateProxmoxClusterSnapshot(data.clusterBuffer, data.clusterIdStr);
195
+ /*
196
+ * pve_version_info carries no `id` label — it is the cluster-level
197
+ * PVE version (this is what populates ProxmoxCluster.pveVersion).
198
+ */
199
+ if (data.metricName === "pve_version_info") {
200
+ const version = getStringAttribute(dpAttributes, "version");
201
+ if (version) {
202
+ cluster.pveVersion = version;
203
+ }
204
+ return;
205
+ }
206
+ /*
207
+ * WI-24 backup coverage — cluster-level backup-info collector
208
+ * series, handled before the generic scope parse:
209
+ * pve_not_backed_up_total carries no `id` label, and the
210
+ * pve_not_backed_up_info `id` label format is unverified upstream
211
+ * (`qemu/100` vs bare vmid — §3.9 spike), so neither goes through
212
+ * the inventory-row path. The ids are folded into the cluster
213
+ * buffer and joined to the buffered Guest rows at flush time.
214
+ */
215
+ if (data.metricName === "pve_not_backed_up_total") {
216
+ cluster.sawBackupInfo = true;
217
+ cluster.guestsWithoutBackupCount = Math.max(0, Math.trunc(rawValue));
218
+ return;
219
+ }
220
+ if (data.metricName === "pve_not_backed_up_info") {
221
+ cluster.sawBackupInfo = true;
222
+ const uncoveredId = getStringAttribute(dpAttributes, "id");
223
+ if (uncoveredId) {
224
+ cluster.notBackedUpIds.add(uncoveredId);
225
+ }
226
+ return;
227
+ }
228
+ const id = getStringAttribute(dpAttributes, "id");
229
+ if (!id) {
230
+ return;
231
+ }
232
+ /*
233
+ * Scope/type: prefer the pve.scope / pve.type attributes stamped
234
+ * by the agent's transform/pve-identity processor; fall back to
235
+ * parsing the id prefix so inventory still populates on a
236
+ * hand-rolled collector config without the transform.
237
+ */
238
+ const slashIndex = id.indexOf("/");
239
+ const idPrefix = slashIndex > 0 ? id.substring(0, slashIndex) : "";
240
+ const pveType = getStringAttribute(dpAttributes, "pve.type") || idPrefix;
241
+ let scope = getStringAttribute(dpAttributes, "pve.scope");
242
+ if (!scope) {
243
+ scope = idPrefix === "qemu" || idPrefix === "lxc" ? "guest" : idPrefix;
244
+ }
245
+ let kind;
246
+ if (scope === "node") {
247
+ kind = "Node";
248
+ }
249
+ else if (scope === "guest") {
250
+ kind = "Guest";
251
+ }
252
+ else if (scope === "storage") {
253
+ kind = "Storage";
254
+ }
255
+ else {
256
+ // cluster/* series and unknown scopes aren't inventory rows.
257
+ return;
258
+ }
259
+ const patch = {
260
+ kind,
261
+ externalId: id,
262
+ name: null,
263
+ vmid: null,
264
+ guestType: null,
265
+ parentNodeName: null,
266
+ isUp: null,
267
+ haState: null,
268
+ onboot: null,
269
+ uptimeSeconds: null,
270
+ latestCpuPercent: null,
271
+ latestMemoryBytes: null,
272
+ maxMemoryBytes: null,
273
+ latestDiskBytes: null,
274
+ maxDiskBytes: null,
275
+ observedAt,
276
+ };
277
+ if (kind === "Guest") {
278
+ patch.guestType = pveType === "qemu" || pveType === "lxc" ? pveType : null;
279
+ if (slashIndex > 0) {
280
+ const vmidParsed = parseInt(id.substring(slashIndex + 1), 10);
281
+ patch.vmid = isNaN(vmidParsed) ? null : vmidParsed;
282
+ }
283
+ }
284
+ // `node` label: present on the info series and pve_onboot_status.
285
+ const nodeLabel = getStringAttribute(dpAttributes, "node");
286
+ if (nodeLabel && kind !== "Node") {
287
+ patch.parentNodeName = nodeLabel;
288
+ }
289
+ switch (data.metricName) {
290
+ case "pve_up": {
291
+ patch.isUp = rawValue >= 1;
292
+ if (kind === "Node") {
293
+ // pve_up doubles as the node-identity fallback per the spec.
294
+ cluster.sawNodeIdentity = true;
295
+ cluster.sawNodeUp = true;
296
+ }
297
+ break;
298
+ }
299
+ case "pve_node_info": {
300
+ patch.name = getStringAttribute(dpAttributes, "name");
301
+ cluster.sawNodeIdentity = true;
302
+ break;
303
+ }
304
+ case "pve_guest_info": {
305
+ patch.name = getStringAttribute(dpAttributes, "name");
306
+ cluster.sawGuestIdentity = true;
307
+ break;
308
+ }
309
+ case "pve_storage_info": {
310
+ patch.name = getStringAttribute(dpAttributes, "storage");
311
+ cluster.sawStorageIdentity = true;
312
+ break;
313
+ }
314
+ case "pve_ha_state": {
315
+ /*
316
+ * Enum-series: one row per possible state, value 1 marks the
317
+ * current one. Only the active row carries signal — skip the
318
+ * zero-valued rows entirely so they don't create empty patches.
319
+ */
320
+ if (rawValue < 1) {
321
+ return;
322
+ }
323
+ patch.haState = getStringAttribute(dpAttributes, "state");
324
+ break;
325
+ }
326
+ case "pve_onboot_status": {
327
+ patch.onboot = rawValue >= 1;
328
+ break;
329
+ }
330
+ case "pve_uptime_seconds": {
331
+ patch.uptimeSeconds = Math.max(0, Math.trunc(rawValue));
332
+ break;
333
+ }
334
+ case "pve_cpu_usage_ratio": {
335
+ /*
336
+ * Already a true 0..1 ratio — no allocatable-denominator cache
337
+ * needed, unlike K8s cpuCoresToPercent.
338
+ */
339
+ patch.latestCpuPercent = rawValue * 100;
340
+ break;
341
+ }
342
+ case "pve_memory_usage_bytes": {
343
+ patch.latestMemoryBytes = Math.max(0, Math.trunc(rawValue));
344
+ break;
345
+ }
346
+ case "pve_memory_size_bytes": {
347
+ patch.maxMemoryBytes = Math.max(0, Math.trunc(rawValue));
348
+ break;
349
+ }
350
+ case "pve_disk_usage_bytes": {
351
+ patch.latestDiskBytes = Math.max(0, Math.trunc(rawValue));
352
+ break;
353
+ }
354
+ case "pve_disk_size_bytes": {
355
+ patch.maxDiskBytes = Math.max(0, Math.trunc(rawValue));
356
+ break;
357
+ }
358
+ default: {
359
+ return;
360
+ }
361
+ }
362
+ foldProxmoxResourceSnapshot({
363
+ buffer: data.resourceBuffer,
364
+ clusterIdStr: data.clusterIdStr,
365
+ patch,
366
+ });
367
+ }
368
+ /*
369
+ * Merge a patch into the per-cluster Proxmox buffer: identity labels
370
+ * are first-non-null-wins (stable, and a batch missing an info
371
+ * series must not blank them), status/metric fields are
372
+ * newest-observedAt-wins (K8s buffer semantics).
373
+ */
374
+ export function foldProxmoxResourceSnapshot(data) {
375
+ let perCluster = data.buffer.get(data.clusterIdStr);
376
+ if (!perCluster) {
377
+ perCluster = new Map();
378
+ data.buffer.set(data.clusterIdStr, perCluster);
379
+ }
380
+ const key = `${data.patch.kind}|${data.patch.externalId}`;
381
+ const existing = perCluster.get(key);
382
+ if (!existing) {
383
+ perCluster.set(key, data.patch);
384
+ return;
385
+ }
386
+ const patch = data.patch;
387
+ const newer = patch.observedAt >= existing.observedAt;
388
+ // Identity: first-non-null wins.
389
+ if (existing.name === null && patch.name !== null) {
390
+ existing.name = patch.name;
391
+ }
392
+ if (existing.vmid === null && patch.vmid !== null) {
393
+ existing.vmid = patch.vmid;
394
+ }
395
+ if (existing.guestType === null && patch.guestType !== null) {
396
+ existing.guestType = patch.guestType;
397
+ }
398
+ if (existing.parentNodeName === null && patch.parentNodeName !== null) {
399
+ existing.parentNodeName = patch.parentNodeName;
400
+ }
401
+ // Status / metrics: newest observation wins.
402
+ if (patch.isUp !== null && newer) {
403
+ existing.isUp = patch.isUp;
404
+ }
405
+ if (patch.haState !== null && newer) {
406
+ existing.haState = patch.haState;
407
+ }
408
+ if (patch.onboot !== null && newer) {
409
+ existing.onboot = patch.onboot;
410
+ }
411
+ if (patch.uptimeSeconds !== null && newer) {
412
+ existing.uptimeSeconds = patch.uptimeSeconds;
413
+ }
414
+ if (patch.latestCpuPercent !== null && newer) {
415
+ existing.latestCpuPercent = patch.latestCpuPercent;
416
+ }
417
+ if (patch.latestMemoryBytes !== null && newer) {
418
+ existing.latestMemoryBytes = patch.latestMemoryBytes;
419
+ }
420
+ if (patch.maxMemoryBytes !== null && newer) {
421
+ existing.maxMemoryBytes = patch.maxMemoryBytes;
422
+ }
423
+ if (patch.latestDiskBytes !== null && newer) {
424
+ existing.latestDiskBytes = patch.latestDiskBytes;
425
+ }
426
+ if (patch.maxDiskBytes !== null && newer) {
427
+ existing.maxDiskBytes = patch.maxDiskBytes;
428
+ }
429
+ if (patch.observedAt > existing.observedAt) {
430
+ existing.observedAt = patch.observedAt;
431
+ }
432
+ }
433
+ /*
434
+ * WI-24: a guest is "covered by a backup job" exactly when the batch
435
+ * carried the backup-info collector output at all AND no
436
+ * pve_not_backed_up_info series carries its id (series present =
437
+ * NOT covered — the exporter emits one info row per uncovered
438
+ * guest). A batch without the collector output yields null, so the
439
+ * upsert COALESCE keeps the last-known value (the same
440
+ * never-zero-on-partial-batch guard the count columns use).
441
+ *
442
+ * The info `id` label's value format is unverified upstream
443
+ * (`qemu/100` vs bare vmid — §3.9 spike), so match both the full
444
+ * externalId and the bare vmid.
445
+ */
446
+ export function computeProxmoxGuestBackedUp(entry, snap) {
447
+ if (entry.kind !== "Guest" || !(snap === null || snap === void 0 ? void 0 : snap.sawBackupInfo)) {
448
+ return null;
449
+ }
450
+ if (snap.notBackedUpIds.has(entry.externalId)) {
451
+ return false;
452
+ }
453
+ if (entry.vmid !== null && snap.notBackedUpIds.has(String(entry.vmid))) {
454
+ return false;
455
+ }
456
+ return true;
457
+ }
458
+ /*
459
+ * Derive the ProxmoxCluster snapshot columns from one folded batch.
460
+ * Counts are only set when the batch carried the matching identity
461
+ * series — never zero a count on a partial batch. Returns an object
462
+ * whose keys are exactly the columns to write (empty object = nothing
463
+ * to write).
464
+ */
465
+ export function deriveProxmoxClusterSnapshotExtras(entries, snap) {
466
+ const extras = {};
467
+ if (snap === null || snap === void 0 ? void 0 : snap.pveVersion) {
468
+ extras.pveVersion = snap.pveVersion;
469
+ }
470
+ if (snap === null || snap === void 0 ? void 0 : snap.sawNodeIdentity) {
471
+ extras.nodeCount = entries.filter((e) => {
472
+ return e.kind === "Node";
473
+ }).length;
474
+ }
475
+ if (snap === null || snap === void 0 ? void 0 : snap.sawNodeUp) {
476
+ extras.onlineNodeCount = entries.filter((e) => {
477
+ return e.kind === "Node" && e.isUp === true;
478
+ }).length;
479
+ }
480
+ if (snap === null || snap === void 0 ? void 0 : snap.sawGuestIdentity) {
481
+ extras.guestCount = entries.filter((e) => {
482
+ return e.kind === "Guest";
483
+ }).length;
484
+ }
485
+ if (snap === null || snap === void 0 ? void 0 : snap.sawStorageIdentity) {
486
+ extras.storageCount = entries.filter((e) => {
487
+ return e.kind === "Storage";
488
+ }).length;
489
+ }
490
+ /*
491
+ * WI-24: written only when the batch carried pve_not_backed_up_total
492
+ * itself — NULL in Postgres stays "collector not reporting",
493
+ * distinct from 0 uncovered guests.
494
+ */
495
+ if (snap &&
496
+ snap.guestsWithoutBackupCount !== null &&
497
+ snap.guestsWithoutBackupCount !== undefined) {
498
+ extras.guestsWithoutBackupCount = snap.guestsWithoutBackupCount;
499
+ }
500
+ return extras;
501
+ }
502
+ export function getOrCreateCephClusterSnapshot(buffer, clusterIdStr) {
503
+ let entry = buffer.get(clusterIdStr);
504
+ if (!entry) {
505
+ entry = {
506
+ sawMonMetadata: false,
507
+ sawOsdMetadata: false,
508
+ sawOsdUp: false,
509
+ sawOsdIn: false,
510
+ sawPoolMetadata: false,
511
+ healthStatus: null,
512
+ totalBytes: null,
513
+ totalUsedBytes: null,
514
+ cephVersionCounts: new Map(),
515
+ };
516
+ buffer.set(clusterIdStr, entry);
517
+ }
518
+ return entry;
519
+ }
520
+ export function emptyCephResourceEntry(kind, externalId, observedAt) {
521
+ return {
522
+ kind,
523
+ externalId,
524
+ name: null,
525
+ hostname: null,
526
+ daemonVersion: null,
527
+ deviceClass: null,
528
+ isUp: null,
529
+ isIn: null,
530
+ inQuorum: null,
531
+ statBytes: null,
532
+ statBytesUsed: null,
533
+ applyLatencyMs: null,
534
+ commitLatencyMs: null,
535
+ pgCount: null,
536
+ storedBytes: null,
537
+ maxAvailBytes: null,
538
+ objects: null,
539
+ readOpsCounter: null,
540
+ writeOpsCounter: null,
541
+ observedAt,
542
+ };
543
+ }
544
+ /*
545
+ * Fold one ceph_* datapoint into the per-cluster buffers. Pool
546
+ * series are keyed by the `pool_id` datapoint label, daemon series
547
+ * by `ceph_daemon` (osd.3, mon.a, mgr.x, …).
548
+ */
549
+ export function bufferCephSnapshotMetric(data) {
550
+ const valueFromInt = toNumberOrNull(data.datapoint["asInt"]);
551
+ const valueFromDouble = toNumberOrNull(data.datapoint["asDouble"]);
552
+ const rawValue = valueFromDouble !== null && valueFromDouble !== void 0 ? valueFromDouble : valueFromInt;
553
+ if (rawValue === null) {
554
+ return;
555
+ }
556
+ const observedAt = parseUnixNanoToDate(data.datapoint["timeUnixNano"], "ceph snapshot timeUnixNano");
557
+ const dpAttributes = data.datapoint["attributes"] || [];
558
+ const cluster = getOrCreateCephClusterSnapshot(data.clusterBuffer, data.clusterIdStr);
559
+ // Cluster-level series — no per-resource row.
560
+ if (data.metricName === "ceph_health_status") {
561
+ // 0 = HEALTH_OK, 1 = HEALTH_WARN, 2 = HEALTH_ERR.
562
+ cluster.healthStatus = Math.max(0, Math.trunc(rawValue));
563
+ return;
564
+ }
565
+ if (data.metricName === "ceph_cluster_total_bytes") {
566
+ cluster.totalBytes = Math.max(0, rawValue);
567
+ return;
568
+ }
569
+ if (data.metricName === "ceph_cluster_total_used_bytes") {
570
+ cluster.totalUsedBytes = Math.max(0, rawValue);
571
+ return;
572
+ }
573
+ if (data.metricName.startsWith("ceph_pool_")) {
574
+ const poolId = getStringAttribute(dpAttributes, "pool_id");
575
+ if (!poolId) {
576
+ return;
577
+ }
578
+ const patch = emptyCephResourceEntry("Pool", poolId, observedAt);
579
+ switch (data.metricName) {
580
+ case "ceph_pool_metadata": {
581
+ // The only pool series that carries the human-readable name.
582
+ patch.name = getStringAttribute(dpAttributes, "name");
583
+ cluster.sawPoolMetadata = true;
584
+ break;
585
+ }
586
+ case "ceph_pool_stored": {
587
+ patch.storedBytes = Math.max(0, Math.trunc(rawValue));
588
+ break;
589
+ }
590
+ case "ceph_pool_max_avail": {
591
+ patch.maxAvailBytes = Math.max(0, Math.trunc(rawValue));
592
+ break;
593
+ }
594
+ case "ceph_pool_objects": {
595
+ patch.objects = Math.max(0, Math.trunc(rawValue));
596
+ break;
597
+ }
598
+ /*
599
+ * Latest RAW cumulative counters — the Pools list computes
600
+ * IOPS rates on read from ClickHouse, never from these.
601
+ */
602
+ case "ceph_pool_rd": {
603
+ patch.readOpsCounter = Math.max(0, Math.trunc(rawValue));
604
+ break;
605
+ }
606
+ case "ceph_pool_wr": {
607
+ patch.writeOpsCounter = Math.max(0, Math.trunc(rawValue));
608
+ break;
609
+ }
610
+ default: {
611
+ return;
612
+ }
613
+ }
614
+ foldCephResourceSnapshot({
615
+ buffer: data.resourceBuffer,
616
+ clusterIdStr: data.clusterIdStr,
617
+ patch,
618
+ });
619
+ return;
620
+ }
621
+ const cephDaemon = getStringAttribute(dpAttributes, "ceph_daemon");
622
+ if (!cephDaemon) {
623
+ return;
624
+ }
625
+ const dotIndex = cephDaemon.indexOf(".");
626
+ const daemonPrefix = dotIndex > 0 ? cephDaemon.substring(0, dotIndex) : "";
627
+ let kind;
628
+ if (daemonPrefix === "osd") {
629
+ kind = "Osd";
630
+ }
631
+ else if (daemonPrefix === "mon") {
632
+ kind = "Mon";
633
+ }
634
+ else if (daemonPrefix === "mgr") {
635
+ kind = "Mgr";
636
+ }
637
+ else if (daemonPrefix === "mds") {
638
+ kind = "Mds";
639
+ }
640
+ else if (daemonPrefix === "rgw") {
641
+ kind = "Rgw";
642
+ }
643
+ else {
644
+ return;
645
+ }
646
+ const patch = emptyCephResourceEntry(kind, cephDaemon, observedAt);
647
+ switch (data.metricName) {
648
+ case "ceph_mon_quorum_status": {
649
+ patch.inQuorum = rawValue >= 1;
650
+ break;
651
+ }
652
+ case "ceph_mon_metadata": {
653
+ patch.hostname = getStringAttribute(dpAttributes, "hostname");
654
+ patch.daemonVersion = getStringAttribute(dpAttributes, "ceph_version");
655
+ cluster.sawMonMetadata = true;
656
+ // CephCluster.cephVersion = modal mon version across the batch.
657
+ if (patch.daemonVersion) {
658
+ cluster.cephVersionCounts.set(patch.daemonVersion, (cluster.cephVersionCounts.get(patch.daemonVersion) || 0) + 1);
659
+ }
660
+ break;
661
+ }
662
+ case "ceph_osd_up": {
663
+ patch.isUp = rawValue >= 1;
664
+ cluster.sawOsdUp = true;
665
+ break;
666
+ }
667
+ case "ceph_osd_in": {
668
+ patch.isIn = rawValue >= 1;
669
+ cluster.sawOsdIn = true;
670
+ break;
671
+ }
672
+ case "ceph_osd_metadata": {
673
+ patch.hostname = getStringAttribute(dpAttributes, "hostname");
674
+ patch.deviceClass = getStringAttribute(dpAttributes, "device_class");
675
+ patch.daemonVersion = getStringAttribute(dpAttributes, "ceph_version");
676
+ cluster.sawOsdMetadata = true;
677
+ break;
678
+ }
679
+ case "ceph_mgr_metadata":
680
+ case "ceph_mds_metadata":
681
+ case "ceph_rgw_metadata": {
682
+ patch.hostname = getStringAttribute(dpAttributes, "hostname");
683
+ patch.daemonVersion = getStringAttribute(dpAttributes, "ceph_version");
684
+ break;
685
+ }
686
+ case "ceph_osd_stat_bytes": {
687
+ patch.statBytes = Math.max(0, Math.trunc(rawValue));
688
+ break;
689
+ }
690
+ case "ceph_osd_stat_bytes_used": {
691
+ patch.statBytesUsed = Math.max(0, Math.trunc(rawValue));
692
+ break;
693
+ }
694
+ case "ceph_osd_apply_latency_ms": {
695
+ patch.applyLatencyMs = Math.max(0, rawValue);
696
+ break;
697
+ }
698
+ case "ceph_osd_commit_latency_ms": {
699
+ patch.commitLatencyMs = Math.max(0, rawValue);
700
+ break;
701
+ }
702
+ case "ceph_osd_numpg": {
703
+ patch.pgCount = Math.max(0, Math.trunc(rawValue));
704
+ break;
705
+ }
706
+ default: {
707
+ return;
708
+ }
709
+ }
710
+ foldCephResourceSnapshot({
711
+ buffer: data.resourceBuffer,
712
+ clusterIdStr: data.clusterIdStr,
713
+ patch,
714
+ });
715
+ }
716
+ /*
717
+ * Merge a patch into the per-cluster Ceph buffer — same semantics
718
+ * as foldProxmoxResourceSnapshot (identity first-non-null-wins,
719
+ * status/metrics newest-observedAt-wins).
720
+ */
721
+ export function foldCephResourceSnapshot(data) {
722
+ let perCluster = data.buffer.get(data.clusterIdStr);
723
+ if (!perCluster) {
724
+ perCluster = new Map();
725
+ data.buffer.set(data.clusterIdStr, perCluster);
726
+ }
727
+ const key = `${data.patch.kind}|${data.patch.externalId}`;
728
+ const existing = perCluster.get(key);
729
+ if (!existing) {
730
+ perCluster.set(key, data.patch);
731
+ return;
732
+ }
733
+ const patch = data.patch;
734
+ const newer = patch.observedAt >= existing.observedAt;
735
+ // Identity: first-non-null wins.
736
+ if (existing.name === null && patch.name !== null) {
737
+ existing.name = patch.name;
738
+ }
739
+ if (existing.hostname === null && patch.hostname !== null) {
740
+ existing.hostname = patch.hostname;
741
+ }
742
+ if (existing.daemonVersion === null && patch.daemonVersion !== null) {
743
+ existing.daemonVersion = patch.daemonVersion;
744
+ }
745
+ if (existing.deviceClass === null && patch.deviceClass !== null) {
746
+ existing.deviceClass = patch.deviceClass;
747
+ }
748
+ // Status / metrics: newest observation wins.
749
+ if (patch.isUp !== null && newer) {
750
+ existing.isUp = patch.isUp;
751
+ }
752
+ if (patch.isIn !== null && newer) {
753
+ existing.isIn = patch.isIn;
754
+ }
755
+ if (patch.inQuorum !== null && newer) {
756
+ existing.inQuorum = patch.inQuorum;
757
+ }
758
+ if (patch.statBytes !== null && newer) {
759
+ existing.statBytes = patch.statBytes;
760
+ }
761
+ if (patch.statBytesUsed !== null && newer) {
762
+ existing.statBytesUsed = patch.statBytesUsed;
763
+ }
764
+ if (patch.applyLatencyMs !== null && newer) {
765
+ existing.applyLatencyMs = patch.applyLatencyMs;
766
+ }
767
+ if (patch.commitLatencyMs !== null && newer) {
768
+ existing.commitLatencyMs = patch.commitLatencyMs;
769
+ }
770
+ if (patch.pgCount !== null && newer) {
771
+ existing.pgCount = patch.pgCount;
772
+ }
773
+ if (patch.storedBytes !== null && newer) {
774
+ existing.storedBytes = patch.storedBytes;
775
+ }
776
+ if (patch.maxAvailBytes !== null && newer) {
777
+ existing.maxAvailBytes = patch.maxAvailBytes;
778
+ }
779
+ if (patch.objects !== null && newer) {
780
+ existing.objects = patch.objects;
781
+ }
782
+ if (patch.readOpsCounter !== null && newer) {
783
+ existing.readOpsCounter = patch.readOpsCounter;
784
+ }
785
+ if (patch.writeOpsCounter !== null && newer) {
786
+ existing.writeOpsCounter = patch.writeOpsCounter;
787
+ }
788
+ if (patch.observedAt > existing.observedAt) {
789
+ existing.observedAt = patch.observedAt;
790
+ }
791
+ }
792
+ /*
793
+ * Derive the CephCluster snapshot columns from one folded batch —
794
+ * same never-zero-a-count-on-a-partial-batch contract as the Proxmox
795
+ * derive above.
796
+ */
797
+ export function deriveCephClusterSnapshotExtras(entries, snap) {
798
+ const extras = {};
799
+ if (snap === null || snap === void 0 ? void 0 : snap.sawMonMetadata) {
800
+ extras.monCount = entries.filter((e) => {
801
+ return e.kind === "Mon";
802
+ }).length;
803
+ }
804
+ if (snap === null || snap === void 0 ? void 0 : snap.sawOsdMetadata) {
805
+ extras.osdCount = entries.filter((e) => {
806
+ return e.kind === "Osd";
807
+ }).length;
808
+ }
809
+ if (snap === null || snap === void 0 ? void 0 : snap.sawOsdUp) {
810
+ extras.osdUpCount = entries.filter((e) => {
811
+ return e.kind === "Osd" && e.isUp === true;
812
+ }).length;
813
+ }
814
+ if (snap === null || snap === void 0 ? void 0 : snap.sawOsdIn) {
815
+ extras.osdInCount = entries.filter((e) => {
816
+ return e.kind === "Osd" && e.isIn === true;
817
+ }).length;
818
+ }
819
+ if (snap === null || snap === void 0 ? void 0 : snap.sawPoolMetadata) {
820
+ extras.poolCount = entries.filter((e) => {
821
+ return e.kind === "Pool";
822
+ }).length;
823
+ }
824
+ if (snap && snap.healthStatus !== null) {
825
+ extras.healthStatus = snap.healthStatus;
826
+ }
827
+ if (snap &&
828
+ snap.totalBytes !== null &&
829
+ snap.totalBytes > 0 &&
830
+ snap.totalUsedBytes !== null) {
831
+ /*
832
+ * Round to 2 decimals: full float precision would change the
833
+ * extras fingerprint on every scrape and defeat the 60-s
834
+ * write throttle for an invisible difference.
835
+ */
836
+ extras.capacityUsedPercent =
837
+ Math.round((snap.totalUsedBytes / snap.totalBytes) * 10000) / 100;
838
+ }
839
+ if (snap && snap.cephVersionCounts.size > 0) {
840
+ let modalVersion = null;
841
+ let modalCount = 0;
842
+ for (const [version, count] of snap.cephVersionCounts.entries()) {
843
+ if (count > modalCount) {
844
+ modalVersion = version;
845
+ modalCount = count;
846
+ }
847
+ }
848
+ if (modalVersion) {
849
+ extras.cephVersion = modalVersion;
850
+ }
851
+ }
852
+ return extras;
853
+ }
854
+ //# sourceMappingURL=ProxmoxCephSnapshotScan.js.map