@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,732 @@
1
+ import {
2
+ ProxmoxAlertTemplate,
3
+ ProxmoxAlertTemplateArgs,
4
+ getAllProxmoxAlertTemplates,
5
+ getProxmoxAlertTemplateById,
6
+ } from "../../../Types/Monitor/ProxmoxAlertTemplates";
7
+ import { getProxmoxMetricByMetricName } from "../../../Types/Monitor/ProxmoxMetricCatalog";
8
+ import MonitorStep from "../../../Types/Monitor/MonitorStep";
9
+ import MonitorStepProxmoxMonitor from "../../../Types/Monitor/MonitorStepProxmoxMonitor";
10
+ import MonitorCriteriaInstance from "../../../Types/Monitor/MonitorCriteriaInstance";
11
+ import { FilterType } from "../../../Types/Monitor/CriteriaFilter";
12
+ import MetricsAggregationType from "../../../Types/Metrics/MetricsAggregationType";
13
+ import RollingTime from "../../../Types/RollingTime/RollingTime";
14
+ import ObjectID from "../../../Types/ObjectID";
15
+
16
+ /*
17
+ * WI-20: lock in the Proxmox alert-template contracts (v2 WI-9 + the v3
18
+ * WI-24/25 additions). Two layers:
19
+ *
20
+ * 1. ENUMERATED invariants run over getAllProxmoxAlertTemplates(), so a
21
+ * newly added template is automatically covered: it must build a
22
+ * valid MonitorStep, reference only catalog metrics, resolve every
23
+ * criteria alias, group by raw datapoint labels (pve-exporter
24
+ * identity lives in datapoint labels — NEVER `resource.`-prefixed),
25
+ * and use disjoint fire/recover thresholds on the same alias.
26
+ *
27
+ * 2. A per-template expectation table pins the spec'd metric /
28
+ * aggregation / threshold / scope-filter decisions (v3 spec §WI-24:
29
+ * pve-guest-not-backed-up fires >0 / recovers =0 on
30
+ * pve_not_backed_up_total, cluster scope, no groupBy; §WI-25:
31
+ * pve-replication-failing groups by the replication job `id`).
32
+ * The table is exhaustive both ways — adding a template without a
33
+ * row here fails loudly, which is the point.
34
+ */
35
+
36
+ interface QueryExpectation {
37
+ metricName: string;
38
+ aggregation: MetricsAggregationType;
39
+ attributes: Record<string, string>;
40
+ }
41
+
42
+ interface ThresholdExpectation {
43
+ alias: string;
44
+ filterType: FilterType;
45
+ value: number;
46
+ }
47
+
48
+ interface TemplateExpectation {
49
+ id: string;
50
+ category: string;
51
+ severity: string;
52
+ rollingTime: RollingTime;
53
+ queries: Array<QueryExpectation>;
54
+ groupBy: string | null;
55
+ formula: string | null;
56
+ fire: ThresholdExpectation;
57
+ recover: ThresholdExpectation;
58
+ }
59
+
60
+ const EXPECTED_TEMPLATES: Array<TemplateExpectation> = [
61
+ {
62
+ id: "pve-node-offline",
63
+ category: "Availability",
64
+ severity: "Critical",
65
+ rollingTime: RollingTime.Past5Minutes,
66
+ queries: [
67
+ {
68
+ metricName: "pve_up",
69
+ aggregation: MetricsAggregationType.Min,
70
+ attributes: { "pve.scope": "node" },
71
+ },
72
+ ],
73
+ groupBy: "id",
74
+ formula: null,
75
+ fire: { alias: "node_up", filterType: FilterType.LessThan, value: 1 },
76
+ recover: {
77
+ alias: "node_up",
78
+ filterType: FilterType.GreaterThanOrEqualTo,
79
+ value: 1,
80
+ },
81
+ },
82
+ {
83
+ id: "pve-guest-down",
84
+ category: "Availability",
85
+ severity: "Warning",
86
+ rollingTime: RollingTime.Past5Minutes,
87
+ queries: [
88
+ {
89
+ metricName: "pve_up",
90
+ aggregation: MetricsAggregationType.Min,
91
+ attributes: { "pve.scope": "guest" },
92
+ },
93
+ ],
94
+ groupBy: "id",
95
+ formula: null,
96
+ fire: { alias: "guest_up", filterType: FilterType.LessThan, value: 1 },
97
+ recover: {
98
+ alias: "guest_up",
99
+ filterType: FilterType.GreaterThanOrEqualTo,
100
+ value: 1,
101
+ },
102
+ },
103
+ {
104
+ /*
105
+ * Quorum proxy: Σpve_up over node series ÷ Σpve_node_info (constant-1
106
+ * metadata series per node). Same-receiver ratio ⇒ Sum/Sum (the
107
+ * scrape multiple cancels); cluster-wide ⇒ NO groupBy.
108
+ */
109
+ id: "pve-quorum-risk",
110
+ category: "Availability",
111
+ severity: "Critical",
112
+ rollingTime: RollingTime.Past5Minutes,
113
+ queries: [
114
+ {
115
+ metricName: "pve_up",
116
+ aggregation: MetricsAggregationType.Sum,
117
+ attributes: { "pve.scope": "node" },
118
+ },
119
+ {
120
+ metricName: "pve_node_info",
121
+ aggregation: MetricsAggregationType.Sum,
122
+ attributes: { "pve.scope": "node" },
123
+ },
124
+ ],
125
+ groupBy: null,
126
+ formula: "(nodes_online / nodes_total) * 100",
127
+ fire: {
128
+ alias: "node_availability",
129
+ filterType: FilterType.LessThanOrEqualTo,
130
+ value: 50,
131
+ },
132
+ recover: {
133
+ alias: "node_availability",
134
+ filterType: FilterType.GreaterThan,
135
+ value: 50,
136
+ },
137
+ },
138
+ {
139
+ /*
140
+ * pve_cpu_usage_ratio is already a true 0..1 ratio (one series per
141
+ * node) ⇒ Avg, and the threshold stays in ratio units (0.9, not 90).
142
+ */
143
+ id: "pve-node-high-cpu",
144
+ category: "Node",
145
+ severity: "Warning",
146
+ rollingTime: RollingTime.Past5Minutes,
147
+ queries: [
148
+ {
149
+ metricName: "pve_cpu_usage_ratio",
150
+ aggregation: MetricsAggregationType.Avg,
151
+ attributes: { "pve.scope": "node" },
152
+ },
153
+ ],
154
+ groupBy: "id",
155
+ formula: null,
156
+ fire: { alias: "node_cpu", filterType: FilterType.GreaterThan, value: 0.9 },
157
+ recover: {
158
+ alias: "node_cpu",
159
+ filterType: FilterType.LessThanOrEqualTo,
160
+ value: 0.9,
161
+ },
162
+ },
163
+ {
164
+ id: "pve-node-high-memory",
165
+ category: "Node",
166
+ severity: "Warning",
167
+ rollingTime: RollingTime.Past5Minutes,
168
+ queries: [
169
+ {
170
+ metricName: "pve_memory_usage_bytes",
171
+ aggregation: MetricsAggregationType.Sum,
172
+ attributes: { "pve.scope": "node" },
173
+ },
174
+ {
175
+ metricName: "pve_memory_size_bytes",
176
+ aggregation: MetricsAggregationType.Sum,
177
+ attributes: { "pve.scope": "node" },
178
+ },
179
+ ],
180
+ groupBy: "id",
181
+ formula: "(used_mem / total_mem) * 100",
182
+ fire: {
183
+ alias: "node_memory_utilization",
184
+ filterType: FilterType.GreaterThan,
185
+ value: 85,
186
+ },
187
+ recover: {
188
+ alias: "node_memory_utilization",
189
+ filterType: FilterType.LessThanOrEqualTo,
190
+ value: 85,
191
+ },
192
+ },
193
+ {
194
+ id: "pve-guest-high-cpu",
195
+ category: "Guest",
196
+ severity: "Warning",
197
+ rollingTime: RollingTime.Past5Minutes,
198
+ queries: [
199
+ {
200
+ metricName: "pve_cpu_usage_ratio",
201
+ aggregation: MetricsAggregationType.Avg,
202
+ attributes: { "pve.scope": "guest" },
203
+ },
204
+ ],
205
+ groupBy: "id",
206
+ formula: null,
207
+ fire: {
208
+ alias: "guest_cpu",
209
+ filterType: FilterType.GreaterThan,
210
+ value: 0.9,
211
+ },
212
+ recover: {
213
+ alias: "guest_cpu",
214
+ filterType: FilterType.LessThanOrEqualTo,
215
+ value: 0.9,
216
+ },
217
+ },
218
+ {
219
+ id: "pve-storage-near-full",
220
+ category: "Storage",
221
+ severity: "Warning",
222
+ rollingTime: RollingTime.Past5Minutes,
223
+ queries: [
224
+ {
225
+ metricName: "pve_disk_usage_bytes",
226
+ aggregation: MetricsAggregationType.Sum,
227
+ attributes: { "pve.scope": "storage" },
228
+ },
229
+ {
230
+ metricName: "pve_disk_size_bytes",
231
+ aggregation: MetricsAggregationType.Sum,
232
+ attributes: { "pve.scope": "storage" },
233
+ },
234
+ ],
235
+ groupBy: "id",
236
+ formula: "(used_disk / total_disk) * 100",
237
+ fire: {
238
+ alias: "storage_utilization",
239
+ filterType: FilterType.GreaterThan,
240
+ value: 85,
241
+ },
242
+ recover: {
243
+ alias: "storage_utilization",
244
+ filterType: FilterType.LessThanOrEqualTo,
245
+ value: 85,
246
+ },
247
+ },
248
+ {
249
+ /*
250
+ * LXC-only via pve.type (qemu in-guest disk usage reads 0 without the
251
+ * QEMU guest agent — alerting on it would be a lie).
252
+ */
253
+ id: "pve-lxc-disk-near-full",
254
+ category: "Storage",
255
+ severity: "Warning",
256
+ rollingTime: RollingTime.Past5Minutes,
257
+ queries: [
258
+ {
259
+ metricName: "pve_disk_usage_bytes",
260
+ aggregation: MetricsAggregationType.Sum,
261
+ attributes: { "pve.type": "lxc" },
262
+ },
263
+ {
264
+ metricName: "pve_disk_size_bytes",
265
+ aggregation: MetricsAggregationType.Sum,
266
+ attributes: { "pve.type": "lxc" },
267
+ },
268
+ ],
269
+ groupBy: "id",
270
+ formula: "(used_disk / total_disk) * 100",
271
+ fire: {
272
+ alias: "lxc_disk_utilization",
273
+ filterType: FilterType.GreaterThan,
274
+ value: 90,
275
+ },
276
+ recover: {
277
+ alias: "lxc_disk_utilization",
278
+ filterType: FilterType.LessThanOrEqualTo,
279
+ value: 90,
280
+ },
281
+ },
282
+ {
283
+ /*
284
+ * Enum-series filter: pve_ha_state has one series per possible state
285
+ * (value 1 = current). state=error equality filter + Max per resource.
286
+ */
287
+ id: "pve-ha-state-error",
288
+ category: "HA",
289
+ severity: "Critical",
290
+ rollingTime: RollingTime.Past5Minutes,
291
+ queries: [
292
+ {
293
+ metricName: "pve_ha_state",
294
+ aggregation: MetricsAggregationType.Max,
295
+ attributes: { state: "error" },
296
+ },
297
+ ],
298
+ groupBy: "id",
299
+ formula: null,
300
+ fire: {
301
+ alias: "ha_error_state",
302
+ filterType: FilterType.GreaterThan,
303
+ value: 0,
304
+ },
305
+ recover: {
306
+ alias: "ha_error_state",
307
+ filterType: FilterType.EqualTo,
308
+ value: 0,
309
+ },
310
+ },
311
+ {
312
+ /*
313
+ * V3 WI-24: cluster-level backup-info gauge — one series, no `id`
314
+ * label ⇒ NO groupBy (one incident per cluster; per-guest naming
315
+ * belongs to pve_not_backed_up_info in the breakdown, not the alert).
316
+ */
317
+ id: "pve-guest-not-backed-up",
318
+ category: "Backup",
319
+ severity: "Warning",
320
+ rollingTime: RollingTime.Past5Minutes,
321
+ queries: [
322
+ {
323
+ metricName: "pve_not_backed_up_total",
324
+ aggregation: MetricsAggregationType.Max,
325
+ attributes: {},
326
+ },
327
+ ],
328
+ groupBy: null,
329
+ formula: null,
330
+ fire: {
331
+ alias: "guests_without_backup",
332
+ filterType: FilterType.GreaterThan,
333
+ value: 0,
334
+ },
335
+ recover: {
336
+ alias: "guests_without_backup",
337
+ filterType: FilterType.EqualTo,
338
+ value: 0,
339
+ },
340
+ },
341
+ {
342
+ /*
343
+ * V3 WI-25: replication series are labeled `id` with the replication
344
+ * JOB id (e.g. 100-0) — not a node/qemu/lxc resource id, so no
345
+ * pve.scope filter; groupBy `id` fires one incident per job.
346
+ */
347
+ id: "pve-replication-failing",
348
+ category: "Replication",
349
+ severity: "Critical",
350
+ rollingTime: RollingTime.Past5Minutes,
351
+ queries: [
352
+ {
353
+ metricName: "pve_replication_failed_syncs",
354
+ aggregation: MetricsAggregationType.Max,
355
+ attributes: {},
356
+ },
357
+ ],
358
+ groupBy: "id",
359
+ formula: null,
360
+ fire: {
361
+ alias: "replication_failed_syncs",
362
+ filterType: FilterType.GreaterThan,
363
+ value: 0,
364
+ },
365
+ recover: {
366
+ alias: "replication_failed_syncs",
367
+ filterType: FilterType.EqualTo,
368
+ value: 0,
369
+ },
370
+ },
371
+ ];
372
+
373
+ function buildArgs(): ProxmoxAlertTemplateArgs {
374
+ return {
375
+ clusterIdentifier: "pve-prod",
376
+ onlineMonitorStatusId: ObjectID.generate(),
377
+ offlineMonitorStatusId: ObjectID.generate(),
378
+ defaultIncidentSeverityId: ObjectID.generate(),
379
+ defaultAlertSeverityId: ObjectID.generate(),
380
+ monitorName: "Test Monitor",
381
+ };
382
+ }
383
+
384
+ function getProxmoxMonitor(step: MonitorStep): MonitorStepProxmoxMonitor {
385
+ const proxmoxMonitor: MonitorStepProxmoxMonitor | undefined =
386
+ step.data?.proxmoxMonitor;
387
+ if (!proxmoxMonitor) {
388
+ throw new Error("proxmoxMonitor missing from monitor step");
389
+ }
390
+ return proxmoxMonitor;
391
+ }
392
+
393
+ function getCriteriaInstances(
394
+ step: MonitorStep,
395
+ ): Array<MonitorCriteriaInstance> {
396
+ const instances: Array<MonitorCriteriaInstance> | undefined =
397
+ step.data?.monitorCriteria.data?.monitorCriteriaInstanceArray;
398
+ if (!instances || instances.length === 0) {
399
+ throw new Error("monitorCriteria missing from monitor step");
400
+ }
401
+ return instances;
402
+ }
403
+
404
+ // Aliases a criteria filter may legally reference: query + formula variables.
405
+ function getReferencableAliases(
406
+ monitor: MonitorStepProxmoxMonitor,
407
+ ): Set<string> {
408
+ const aliases: Set<string> = new Set<string>();
409
+ for (const queryConfig of monitor.metricViewConfig
410
+ .queryConfigs as Array<any>) {
411
+ aliases.add(queryConfig.metricAliasData.metricVariable);
412
+ }
413
+ for (const formulaConfig of (monitor.metricViewConfig.formulaConfigs ||
414
+ []) as Array<any>) {
415
+ aliases.add(formulaConfig.metricAliasData.metricVariable);
416
+ }
417
+ return aliases;
418
+ }
419
+
420
+ /*
421
+ * Fire and recover must be disjoint complements on the same alias —
422
+ * otherwise the monitor either flaps (overlap) or wedges (gap).
423
+ */
424
+ function isDisjointComplement(
425
+ fire: { filterType: FilterType; value: number },
426
+ recover: { filterType: FilterType; value: number },
427
+ ): boolean {
428
+ if (fire.value !== recover.value) {
429
+ return false;
430
+ }
431
+ switch (fire.filterType) {
432
+ case FilterType.GreaterThan:
433
+ return (
434
+ recover.filterType === FilterType.LessThanOrEqualTo ||
435
+ (fire.value === 0 && recover.filterType === FilterType.EqualTo)
436
+ );
437
+ case FilterType.GreaterThanOrEqualTo:
438
+ return recover.filterType === FilterType.LessThan;
439
+ case FilterType.LessThan:
440
+ return recover.filterType === FilterType.GreaterThanOrEqualTo;
441
+ case FilterType.LessThanOrEqualTo:
442
+ return recover.filterType === FilterType.GreaterThan;
443
+ default:
444
+ return false;
445
+ }
446
+ }
447
+
448
+ const ALL_TEMPLATES: Array<ProxmoxAlertTemplate> =
449
+ getAllProxmoxAlertTemplates();
450
+
451
+ describe("ProxmoxAlertTemplates - registry", () => {
452
+ test("template ids are unique and match the expectation table exactly", () => {
453
+ const ids: Array<string> = ALL_TEMPLATES.map((t: ProxmoxAlertTemplate) => {
454
+ return t.id;
455
+ });
456
+ expect(new Set(ids).size).toBe(ids.length);
457
+ // Exhaustive both ways: a new template must get an expectation row.
458
+ expect([...ids].sort()).toEqual(
459
+ EXPECTED_TEMPLATES.map((t: TemplateExpectation) => {
460
+ return t.id;
461
+ }).sort(),
462
+ );
463
+ });
464
+ });
465
+
466
+ describe("ProxmoxAlertTemplates - enumerated invariants (every template)", () => {
467
+ test.each(
468
+ ALL_TEMPLATES.map((t: ProxmoxAlertTemplate) => {
469
+ return [t.id, t];
470
+ }),
471
+ )("%s builds a valid MonitorStep", (_id: unknown, template: unknown) => {
472
+ const args: ProxmoxAlertTemplateArgs = buildArgs();
473
+ const step: MonitorStep = (template as ProxmoxAlertTemplate).getMonitorStep(
474
+ args,
475
+ );
476
+ const monitor: MonitorStepProxmoxMonitor = getProxmoxMonitor(step);
477
+
478
+ // The cluster attribute is injected from the template args.
479
+ expect(monitor.clusterIdentifier).toBe(args.clusterIdentifier);
480
+ expect(monitor.metricViewConfig.queryConfigs.length).toBeGreaterThan(0);
481
+
482
+ const instances: Array<MonitorCriteriaInstance> =
483
+ getCriteriaInstances(step);
484
+ expect(instances.length).toBeGreaterThanOrEqual(2);
485
+
486
+ /*
487
+ * Criteria are evaluated first-match-wins: every instance before
488
+ * the last is an unhealthy tier (creates incidents + alerts,
489
+ * flips to the offline status); the LAST is the recover instance
490
+ * (no incidents, flips to the online status).
491
+ */
492
+ const offlineInstances: Array<MonitorCriteriaInstance> = instances.slice(
493
+ 0,
494
+ -1,
495
+ );
496
+ const onlineInstance: MonitorCriteriaInstance =
497
+ instances[instances.length - 1]!;
498
+
499
+ for (const offline of offlineInstances) {
500
+ expect(offline.data?.monitorStatusId).toBe(args.offlineMonitorStatusId);
501
+ expect(offline.data?.createIncidents).toBe(true);
502
+ expect(offline.data?.createAlerts).toBe(true);
503
+ expect(offline.data?.incidents).toHaveLength(1);
504
+ expect(offline.data?.alerts).toHaveLength(1);
505
+ expect(offline.data?.incidents?.[0]?.autoResolveIncident).toBe(true);
506
+ expect(offline.data?.alerts?.[0]?.autoResolveAlert).toBe(true);
507
+ }
508
+
509
+ expect(onlineInstance.data?.monitorStatusId).toBe(
510
+ args.onlineMonitorStatusId,
511
+ );
512
+ expect(onlineInstance.data?.createIncidents).toBe(false);
513
+ expect(onlineInstance.data?.createAlerts).toBe(false);
514
+ expect(onlineInstance.data?.name).toBe("Healthy");
515
+ });
516
+
517
+ test.each(
518
+ ALL_TEMPLATES.map((t: ProxmoxAlertTemplate) => {
519
+ return [t.id, t];
520
+ }),
521
+ )(
522
+ "%s references only catalog metrics and resolvable aliases",
523
+ (_id: unknown, template: unknown) => {
524
+ const step: MonitorStep = (
525
+ template as ProxmoxAlertTemplate
526
+ ).getMonitorStep(buildArgs());
527
+ const monitor: MonitorStepProxmoxMonitor = getProxmoxMonitor(step);
528
+
529
+ for (const queryConfig of monitor.metricViewConfig
530
+ .queryConfigs as Array<any>) {
531
+ const metricName: string =
532
+ queryConfig.metricQueryData.filterData.metricName;
533
+ expect(getProxmoxMetricByMetricName(metricName)).toBeDefined();
534
+ }
535
+
536
+ const aliases: Set<string> = getReferencableAliases(monitor);
537
+ for (const instance of getCriteriaInstances(step)) {
538
+ for (const filter of instance.data?.filters || []) {
539
+ expect(aliases).toContain(
540
+ (filter as any).metricMonitorOptions.metricAlias,
541
+ );
542
+ }
543
+ }
544
+ },
545
+ );
546
+
547
+ test.each(
548
+ ALL_TEMPLATES.map((t: ProxmoxAlertTemplate) => {
549
+ return [t.id, t];
550
+ }),
551
+ )(
552
+ "%s groups by raw datapoint labels only (never resource.-prefixed)",
553
+ (_id: unknown, template: unknown) => {
554
+ const step: MonitorStep = (
555
+ template as ProxmoxAlertTemplate
556
+ ).getMonitorStep(buildArgs());
557
+ const monitor: MonitorStepProxmoxMonitor = getProxmoxMonitor(step);
558
+
559
+ for (const queryConfig of monitor.metricViewConfig
560
+ .queryConfigs as Array<any>) {
561
+ const groupBys: Array<string> =
562
+ queryConfig.metricQueryData.groupByAttributeKeys || [];
563
+ for (const key of groupBys) {
564
+ /*
565
+ * pve-exporter identity is the `id` DATAPOINT label. A
566
+ * `resource.`-prefixed key would match nothing in ClickHouse
567
+ * and collapse every resource into one mislabeled series.
568
+ */
569
+ expect(key).toBe("id");
570
+ }
571
+ }
572
+ },
573
+ );
574
+
575
+ test.each(
576
+ ALL_TEMPLATES.map((t: ProxmoxAlertTemplate) => {
577
+ return [t.id, t];
578
+ }),
579
+ )(
580
+ "%s has disjoint fire/recover thresholds on the same alias",
581
+ (_id: unknown, template: unknown) => {
582
+ const step: MonitorStep = (
583
+ template as ProxmoxAlertTemplate
584
+ ).getMonitorStep(buildArgs());
585
+ const instances: Array<MonitorCriteriaInstance> =
586
+ getCriteriaInstances(step);
587
+ const onlineFilters: Array<any> = (instances[instances.length - 1]!.data
588
+ ?.filters || []) as Array<any>;
589
+
590
+ for (const offline of instances.slice(0, -1)) {
591
+ for (const fireFilter of (offline.data?.filters || []) as Array<any>) {
592
+ const recoverFilter: any = onlineFilters.find((f: any) => {
593
+ return (
594
+ f.metricMonitorOptions.metricAlias ===
595
+ fireFilter.metricMonitorOptions.metricAlias
596
+ );
597
+ });
598
+ expect(recoverFilter).toBeDefined();
599
+ expect(
600
+ isDisjointComplement(
601
+ {
602
+ filterType: fireFilter.filterType,
603
+ value: fireFilter.value as number,
604
+ },
605
+ {
606
+ filterType: recoverFilter.filterType,
607
+ value: recoverFilter.value as number,
608
+ },
609
+ ),
610
+ ).toBe(true);
611
+ }
612
+ }
613
+ },
614
+ );
615
+
616
+ test.each(
617
+ ALL_TEMPLATES.map((t: ProxmoxAlertTemplate) => {
618
+ return [t.id, t];
619
+ }),
620
+ )(
621
+ "%s ratio queries use the same aggregation on both sides (same-receiver Sum/Sum contract)",
622
+ (_id: unknown, template: unknown) => {
623
+ const step: MonitorStep = (
624
+ template as ProxmoxAlertTemplate
625
+ ).getMonitorStep(buildArgs());
626
+ const monitor: MonitorStepProxmoxMonitor = getProxmoxMonitor(step);
627
+ const queryConfigs: Array<any> = monitor.metricViewConfig
628
+ .queryConfigs as Array<any>;
629
+ const formulaConfigs: Array<any> = (monitor.metricViewConfig
630
+ .formulaConfigs || []) as Array<any>;
631
+
632
+ if (formulaConfigs.length === 0) {
633
+ return;
634
+ }
635
+
636
+ // Ratio/formula templates: 2 queries, 1 formula, matching groupBys.
637
+ expect(queryConfigs).toHaveLength(2);
638
+ expect(formulaConfigs).toHaveLength(1);
639
+
640
+ const [numerator, denominator] = queryConfigs;
641
+ expect(numerator.metricQueryData.filterData.aggegationType).toBe(
642
+ denominator.metricQueryData.filterData.aggegationType,
643
+ );
644
+ /*
645
+ * Every Proxmox metric rides ONE receiver (the pve-exporter
646
+ * scrape), so ratios are same-receiver and must be Sum/Sum —
647
+ * except pve_cpu_usage_ratio-style single-series gauges, which
648
+ * never appear in formulas here.
649
+ */
650
+ expect(numerator.metricQueryData.filterData.aggegationType).toBe(
651
+ MetricsAggregationType.Sum,
652
+ );
653
+ expect(numerator.metricQueryData.groupByAttributeKeys || []).toEqual(
654
+ denominator.metricQueryData.groupByAttributeKeys || [],
655
+ );
656
+ // Both sides share the same attribute equality filters.
657
+ expect(numerator.metricQueryData.filterData.attributes).toEqual(
658
+ denominator.metricQueryData.filterData.attributes,
659
+ );
660
+ },
661
+ );
662
+ });
663
+
664
+ describe("ProxmoxAlertTemplates - spec table expectations", () => {
665
+ test.each(
666
+ EXPECTED_TEMPLATES.map((t: TemplateExpectation) => {
667
+ return [t.id, t];
668
+ }),
669
+ )(
670
+ "%s matches the spec'd metric/aggregation/threshold contract",
671
+ (_id: unknown, expected: unknown) => {
672
+ const tc: TemplateExpectation = expected as TemplateExpectation;
673
+ const template: ProxmoxAlertTemplate | undefined =
674
+ getProxmoxAlertTemplateById(tc.id);
675
+ expect(template).toBeDefined();
676
+
677
+ expect(template!.category).toBe(tc.category);
678
+ expect(template!.severity).toBe(tc.severity);
679
+
680
+ const step: MonitorStep = template!.getMonitorStep(buildArgs());
681
+ const monitor: MonitorStepProxmoxMonitor = getProxmoxMonitor(step);
682
+
683
+ expect(monitor.rollingTime).toBe(tc.rollingTime);
684
+
685
+ const queryConfigs: Array<any> = monitor.metricViewConfig
686
+ .queryConfigs as Array<any>;
687
+ expect(queryConfigs).toHaveLength(tc.queries.length);
688
+
689
+ for (let i: number = 0; i < tc.queries.length; i++) {
690
+ const expectedQuery: QueryExpectation = tc.queries[i]!;
691
+ const filterData: any = queryConfigs[i].metricQueryData.filterData;
692
+ expect(filterData.metricName).toBe(expectedQuery.metricName);
693
+ expect(filterData.aggegationType).toBe(expectedQuery.aggregation);
694
+ expect(filterData.attributes).toEqual(expectedQuery.attributes);
695
+
696
+ const groupBys: Array<string> =
697
+ queryConfigs[i].metricQueryData.groupByAttributeKeys || [];
698
+ expect(groupBys).toEqual(tc.groupBy ? [tc.groupBy] : []);
699
+ }
700
+
701
+ const formulaConfigs: Array<any> = (monitor.metricViewConfig
702
+ .formulaConfigs || []) as Array<any>;
703
+ if (tc.formula) {
704
+ expect(formulaConfigs).toHaveLength(1);
705
+ expect(formulaConfigs[0].metricFormulaData.metricFormula).toBe(
706
+ tc.formula,
707
+ );
708
+ expect(formulaConfigs[0].metricAliasData.metricVariable).toBe(
709
+ tc.fire.alias,
710
+ );
711
+ } else {
712
+ expect(formulaConfigs).toHaveLength(0);
713
+ }
714
+
715
+ const instances: Array<MonitorCriteriaInstance> =
716
+ getCriteriaInstances(step);
717
+ expect(instances).toHaveLength(2);
718
+
719
+ const fireFilter: any = (instances[0]!.data?.filters as Array<any>)[0];
720
+ expect(fireFilter.metricMonitorOptions.metricAlias).toBe(tc.fire.alias);
721
+ expect(fireFilter.filterType).toBe(tc.fire.filterType);
722
+ expect(fireFilter.value).toBe(tc.fire.value);
723
+
724
+ const recoverFilter: any = (instances[1]!.data?.filters as Array<any>)[0];
725
+ expect(recoverFilter.metricMonitorOptions.metricAlias).toBe(
726
+ tc.recover.alias,
727
+ );
728
+ expect(recoverFilter.filterType).toBe(tc.recover.filterType);
729
+ expect(recoverFilter.value).toBe(tc.recover.value);
730
+ },
731
+ );
732
+ });