@oneuptime/common 11.0.0 → 11.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (357) hide show
  1. package/Models/DatabaseModels/Alert.ts +110 -0
  2. package/Models/DatabaseModels/CephCluster.ts +964 -0
  3. package/Models/DatabaseModels/CephClusterLabelRule.ts +514 -0
  4. package/Models/DatabaseModels/CephClusterOwnerRule.ts +596 -0
  5. package/Models/DatabaseModels/CephClusterOwnerTeam.ts +487 -0
  6. package/Models/DatabaseModels/CephClusterOwnerUser.ts +486 -0
  7. package/Models/DatabaseModels/CephResource.ts +809 -0
  8. package/Models/DatabaseModels/Host.ts +64 -0
  9. package/Models/DatabaseModels/Incident.ts +110 -0
  10. package/Models/DatabaseModels/Index.ts +24 -0
  11. package/Models/DatabaseModels/ProxmoxCluster.ts +943 -0
  12. package/Models/DatabaseModels/ProxmoxClusterLabelRule.ts +514 -0
  13. package/Models/DatabaseModels/ProxmoxClusterOwnerRule.ts +596 -0
  14. package/Models/DatabaseModels/ProxmoxClusterOwnerTeam.ts +487 -0
  15. package/Models/DatabaseModels/ProxmoxClusterOwnerUser.ts +486 -0
  16. package/Models/DatabaseModels/ProxmoxResource.ts +726 -0
  17. package/Models/DatabaseModels/ScheduledMaintenance.ts +110 -0
  18. package/Server/API/BillingInvoiceAPI.ts +47 -7
  19. package/Server/API/CephResourceAPI.ts +134 -0
  20. package/Server/API/DashboardAPI.ts +46 -0
  21. package/Server/API/ProjectAPI.ts +15 -0
  22. package/Server/API/ProxmoxResourceAPI.ts +132 -0
  23. package/Server/API/ResellerPlanAPI.ts +17 -0
  24. package/Server/Infrastructure/GlobalCache.ts +8 -2
  25. package/Server/Infrastructure/Postgres/SchemaMigrations/1781500000000-AddProxmoxAndCephClusterTables.ts +163 -0
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/1781600000000-AddProxmoxCephV2Columns.ts +211 -0
  27. package/Server/Infrastructure/Postgres/SchemaMigrations/1781600000001-AddProxmoxCephActivityAndRules.ts +590 -0
  28. package/Server/Infrastructure/Postgres/SchemaMigrations/1781700000000-AddProxmoxCephV3Columns.ts +64 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
  30. package/Server/Infrastructure/Redis.ts +40 -12
  31. package/Server/Services/AnalyticsDatabaseService.ts +1 -1
  32. package/Server/Services/BillingService.ts +109 -21
  33. package/Server/Services/CephClusterLabelRuleEngineService.ts +200 -0
  34. package/Server/Services/CephClusterLabelRuleService.ts +14 -0
  35. package/Server/Services/CephClusterOwnerRuleEngineService.ts +218 -0
  36. package/Server/Services/CephClusterOwnerRuleService.ts +14 -0
  37. package/Server/Services/CephClusterOwnerTeamService.ts +10 -0
  38. package/Server/Services/CephClusterOwnerUserService.ts +10 -0
  39. package/Server/Services/CephClusterService.ts +401 -0
  40. package/Server/Services/CephResourceService.ts +383 -0
  41. package/Server/Services/CloudResourceService.ts +11 -3
  42. package/Server/Services/DockerHostService.ts +11 -3
  43. package/Server/Services/ExceptionAggregationService.ts +2 -0
  44. package/Server/Services/HostService.ts +11 -3
  45. package/Server/Services/Index.ts +24 -0
  46. package/Server/Services/KubernetesClusterService.ts +11 -3
  47. package/Server/Services/LogAggregationService.ts +2 -0
  48. package/Server/Services/MetricAggregationService.ts +2 -0
  49. package/Server/Services/OpenTelemetryIngestService.ts +36 -0
  50. package/Server/Services/ProxmoxClusterLabelRuleEngineService.ts +204 -0
  51. package/Server/Services/ProxmoxClusterLabelRuleService.ts +14 -0
  52. package/Server/Services/ProxmoxClusterOwnerRuleEngineService.ts +222 -0
  53. package/Server/Services/ProxmoxClusterOwnerRuleService.ts +14 -0
  54. package/Server/Services/ProxmoxClusterOwnerTeamService.ts +10 -0
  55. package/Server/Services/ProxmoxClusterOwnerUserService.ts +10 -0
  56. package/Server/Services/ProxmoxClusterService.ts +382 -0
  57. package/Server/Services/ProxmoxResourceService.ts +404 -0
  58. package/Server/Services/RumApplicationService.ts +11 -3
  59. package/Server/Services/ServerlessFunctionService.ts +11 -3
  60. package/Server/Services/TelemetryUsageBillingService.ts +41 -3
  61. package/Server/Services/TraceAggregationService.ts +2 -0
  62. package/Server/Types/AnalyticsDatabase/AggregateBy.ts +8 -23
  63. package/Server/Utils/Monitor/MonitorAlert.ts +45 -0
  64. package/Server/Utils/Monitor/MonitorClusterContext.ts +129 -0
  65. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +344 -4
  66. package/Server/Utils/Monitor/MonitorIncident.ts +130 -7
  67. package/Server/Utils/Monitor/MonitorMaintenanceSuppression.ts +39 -6
  68. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +3 -1
  69. package/Server/Utils/Monitor/SeriesResourceLabels.ts +33 -0
  70. package/Server/Utils/Profiling.ts +37 -2
  71. package/Server/Utils/Telemetry/EntityRegistry.ts +4 -0
  72. package/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.ts +1096 -0
  73. package/Server/Utils/Telemetry/TelemetryEntity.ts +85 -0
  74. package/Server/Utils/Telemetry.ts +8 -19
  75. package/Tests/Server/API/BillingInvoiceAPI.test.ts +194 -0
  76. package/Tests/Server/API/ProjectAPI.test.ts +91 -0
  77. package/Tests/Server/API/ResellerPlanAPI.test.ts +207 -0
  78. package/Tests/Server/Infrastructure/GlobalCache.test.ts +100 -0
  79. package/Tests/Server/Services/BillingService.test.ts +323 -0
  80. package/Tests/Server/Services/CephResourceService.test.ts +264 -0
  81. package/Tests/Server/Services/ProxmoxResourceService.test.ts +326 -0
  82. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +322 -0
  83. package/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.ts +13 -0
  84. package/Tests/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.test.ts +879 -0
  85. package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +196 -0
  86. package/Tests/Types/Monitor/CephAlertTemplates.test.ts +1231 -0
  87. package/Tests/Types/Monitor/ProxmoxAlertTemplates.test.ts +732 -0
  88. package/Tests/Utils/ModelImportExport.test.ts +366 -0
  89. package/Tests/Utils/Telemetry/EntityRelationship.test.ts +49 -0
  90. package/Tests/Utils/Telemetry/HeartbeatAvailability.test.ts +423 -0
  91. package/Types/BaseDatabase/AggregationIntervalUtil.ts +74 -0
  92. package/Types/Dashboard/DashboardComponentType.ts +4 -0
  93. package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +2 -0
  94. package/Types/Dashboard/DashboardComponents/DashboardCephOsdListComponent.ts +15 -0
  95. package/Types/Dashboard/DashboardComponents/DashboardCephPoolListComponent.ts +14 -0
  96. package/Types/Dashboard/DashboardComponents/DashboardProxmoxGuestListComponent.ts +17 -0
  97. package/Types/Dashboard/DashboardComponents/DashboardProxmoxNodeListComponent.ts +16 -0
  98. package/Types/Dashboard/DashboardTemplates.ts +446 -0
  99. package/Types/Icon/IconProp.ts +2 -0
  100. package/Types/Monitor/CephAlertTemplates.ts +1647 -0
  101. package/Types/Monitor/CephMetricCatalog.ts +409 -0
  102. package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +44 -0
  103. package/Types/Monitor/MonitorStep.ts +64 -0
  104. package/Types/Monitor/MonitorStepCephMonitor.ts +57 -0
  105. package/Types/Monitor/MonitorStepProxmoxMonitor.ts +81 -0
  106. package/Types/Monitor/MonitorType.ts +29 -1
  107. package/Types/Monitor/ProxmoxAlertTemplates.ts +899 -0
  108. package/Types/Monitor/ProxmoxMetricCatalog.ts +382 -0
  109. package/Types/Permission.ts +464 -0
  110. package/Types/Telemetry/EntityType.ts +11 -0
  111. package/Types/Telemetry/ServiceType.ts +2 -0
  112. package/UI/Components/Icon/Icon.tsx +84 -0
  113. package/UI/Components/ImportExport/ExportModelCard.tsx +90 -0
  114. package/UI/Components/ImportExport/ImportModelsModal.tsx +239 -0
  115. package/UI/Components/ModelTable/ModelTable.tsx +294 -143
  116. package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +9 -5
  117. package/UI/Utils/ModelImportExport.ts +207 -0
  118. package/UI/Utils/Telemetry/Telemetry.ts +16 -21
  119. package/UI/Utils/TelemetryService.ts +7 -3
  120. package/Utils/Dashboard/Components/DashboardCephOsdListComponent.ts +63 -0
  121. package/Utils/Dashboard/Components/DashboardCephPoolListComponent.ts +32 -0
  122. package/Utils/Dashboard/Components/DashboardCephResourceListShared.ts +61 -0
  123. package/Utils/Dashboard/Components/DashboardProxmoxGuestListComponent.ts +69 -0
  124. package/Utils/Dashboard/Components/DashboardProxmoxNodeListComponent.ts +55 -0
  125. package/Utils/Dashboard/Components/DashboardProxmoxResourceListShared.ts +61 -0
  126. package/Utils/Dashboard/Components/Index.ts +28 -0
  127. package/Utils/ModelImportExport.ts +369 -0
  128. package/Utils/Telemetry/EntityKey.ts +35 -0
  129. package/Utils/Telemetry/EntityRelationship.ts +6 -0
  130. package/Utils/Telemetry/HeartbeatAvailability.ts +262 -0
  131. package/build/dist/Models/DatabaseModels/Alert.js +108 -0
  132. package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
  133. package/build/dist/Models/DatabaseModels/CephCluster.js +992 -0
  134. package/build/dist/Models/DatabaseModels/CephCluster.js.map +1 -0
  135. package/build/dist/Models/DatabaseModels/CephClusterLabelRule.js +522 -0
  136. package/build/dist/Models/DatabaseModels/CephClusterLabelRule.js.map +1 -0
  137. package/build/dist/Models/DatabaseModels/CephClusterOwnerRule.js +603 -0
  138. package/build/dist/Models/DatabaseModels/CephClusterOwnerRule.js.map +1 -0
  139. package/build/dist/Models/DatabaseModels/CephClusterOwnerTeam.js +503 -0
  140. package/build/dist/Models/DatabaseModels/CephClusterOwnerTeam.js.map +1 -0
  141. package/build/dist/Models/DatabaseModels/CephClusterOwnerUser.js +502 -0
  142. package/build/dist/Models/DatabaseModels/CephClusterOwnerUser.js.map +1 -0
  143. package/build/dist/Models/DatabaseModels/CephResource.js +846 -0
  144. package/build/dist/Models/DatabaseModels/CephResource.js.map +1 -0
  145. package/build/dist/Models/DatabaseModels/Host.js +63 -0
  146. package/build/dist/Models/DatabaseModels/Host.js.map +1 -1
  147. package/build/dist/Models/DatabaseModels/Incident.js +108 -0
  148. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  149. package/build/dist/Models/DatabaseModels/Index.js +24 -0
  150. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  151. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js +967 -0
  152. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js.map +1 -0
  153. package/build/dist/Models/DatabaseModels/ProxmoxClusterLabelRule.js +522 -0
  154. package/build/dist/Models/DatabaseModels/ProxmoxClusterLabelRule.js.map +1 -0
  155. package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerRule.js +603 -0
  156. package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerRule.js.map +1 -0
  157. package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerTeam.js +503 -0
  158. package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerTeam.js.map +1 -0
  159. package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerUser.js +502 -0
  160. package/build/dist/Models/DatabaseModels/ProxmoxClusterOwnerUser.js.map +1 -0
  161. package/build/dist/Models/DatabaseModels/ProxmoxResource.js +761 -0
  162. package/build/dist/Models/DatabaseModels/ProxmoxResource.js.map +1 -0
  163. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +108 -0
  164. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
  165. package/build/dist/Server/API/BillingInvoiceAPI.js +35 -5
  166. package/build/dist/Server/API/BillingInvoiceAPI.js.map +1 -1
  167. package/build/dist/Server/API/CephResourceAPI.js +98 -0
  168. package/build/dist/Server/API/CephResourceAPI.js.map +1 -0
  169. package/build/dist/Server/API/DashboardAPI.js +46 -0
  170. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  171. package/build/dist/Server/API/ProjectAPI.js +11 -0
  172. package/build/dist/Server/API/ProjectAPI.js.map +1 -1
  173. package/build/dist/Server/API/ProxmoxResourceAPI.js +95 -0
  174. package/build/dist/Server/API/ProxmoxResourceAPI.js.map +1 -0
  175. package/build/dist/Server/API/ResellerPlanAPI.js +17 -3
  176. package/build/dist/Server/API/ResellerPlanAPI.js.map +1 -1
  177. package/build/dist/Server/Infrastructure/GlobalCache.js +7 -2
  178. package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
  179. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781500000000-AddProxmoxAndCephClusterTables.js +76 -0
  180. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781500000000-AddProxmoxAndCephClusterTables.js.map +1 -0
  181. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781600000000-AddProxmoxCephV2Columns.js +108 -0
  182. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781600000000-AddProxmoxCephV2Columns.js.map +1 -0
  183. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781600000001-AddProxmoxCephActivityAndRules.js +253 -0
  184. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781600000001-AddProxmoxCephActivityAndRules.js.map +1 -0
  185. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781700000000-AddProxmoxCephV3Columns.js +43 -0
  186. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1781700000000-AddProxmoxCephV3Columns.js.map +1 -0
  187. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  188. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  189. package/build/dist/Server/Infrastructure/Redis.js +31 -8
  190. package/build/dist/Server/Infrastructure/Redis.js.map +1 -1
  191. package/build/dist/Server/Services/AnalyticsDatabaseService.js +1 -1
  192. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  193. package/build/dist/Server/Services/BillingService.js +85 -23
  194. package/build/dist/Server/Services/BillingService.js.map +1 -1
  195. package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js +166 -0
  196. package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js.map +1 -0
  197. package/build/dist/Server/Services/CephClusterLabelRuleService.js +13 -0
  198. package/build/dist/Server/Services/CephClusterLabelRuleService.js.map +1 -0
  199. package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js +186 -0
  200. package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js.map +1 -0
  201. package/build/dist/Server/Services/CephClusterOwnerRuleService.js +13 -0
  202. package/build/dist/Server/Services/CephClusterOwnerRuleService.js.map +1 -0
  203. package/build/dist/Server/Services/CephClusterOwnerTeamService.js +9 -0
  204. package/build/dist/Server/Services/CephClusterOwnerTeamService.js.map +1 -0
  205. package/build/dist/Server/Services/CephClusterOwnerUserService.js +9 -0
  206. package/build/dist/Server/Services/CephClusterOwnerUserService.js.map +1 -0
  207. package/build/dist/Server/Services/CephClusterService.js +353 -0
  208. package/build/dist/Server/Services/CephClusterService.js.map +1 -0
  209. package/build/dist/Server/Services/CephResourceService.js +257 -0
  210. package/build/dist/Server/Services/CephResourceService.js.map +1 -0
  211. package/build/dist/Server/Services/CloudResourceService.js +10 -2
  212. package/build/dist/Server/Services/CloudResourceService.js.map +1 -1
  213. package/build/dist/Server/Services/DockerHostService.js +10 -2
  214. package/build/dist/Server/Services/DockerHostService.js.map +1 -1
  215. package/build/dist/Server/Services/ExceptionAggregationService.js +2 -0
  216. package/build/dist/Server/Services/ExceptionAggregationService.js.map +1 -1
  217. package/build/dist/Server/Services/HostService.js +10 -2
  218. package/build/dist/Server/Services/HostService.js.map +1 -1
  219. package/build/dist/Server/Services/Index.js +24 -0
  220. package/build/dist/Server/Services/Index.js.map +1 -1
  221. package/build/dist/Server/Services/KubernetesClusterService.js +10 -2
  222. package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
  223. package/build/dist/Server/Services/LogAggregationService.js +2 -0
  224. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  225. package/build/dist/Server/Services/MetricAggregationService.js +2 -0
  226. package/build/dist/Server/Services/MetricAggregationService.js.map +1 -1
  227. package/build/dist/Server/Services/OpenTelemetryIngestService.js +37 -7
  228. package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
  229. package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js +166 -0
  230. package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js.map +1 -0
  231. package/build/dist/Server/Services/ProxmoxClusterLabelRuleService.js +13 -0
  232. package/build/dist/Server/Services/ProxmoxClusterLabelRuleService.js.map +1 -0
  233. package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js +186 -0
  234. package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js.map +1 -0
  235. package/build/dist/Server/Services/ProxmoxClusterOwnerRuleService.js +13 -0
  236. package/build/dist/Server/Services/ProxmoxClusterOwnerRuleService.js.map +1 -0
  237. package/build/dist/Server/Services/ProxmoxClusterOwnerTeamService.js +9 -0
  238. package/build/dist/Server/Services/ProxmoxClusterOwnerTeamService.js.map +1 -0
  239. package/build/dist/Server/Services/ProxmoxClusterOwnerUserService.js +9 -0
  240. package/build/dist/Server/Services/ProxmoxClusterOwnerUserService.js.map +1 -0
  241. package/build/dist/Server/Services/ProxmoxClusterService.js +337 -0
  242. package/build/dist/Server/Services/ProxmoxClusterService.js.map +1 -0
  243. package/build/dist/Server/Services/ProxmoxResourceService.js +285 -0
  244. package/build/dist/Server/Services/ProxmoxResourceService.js.map +1 -0
  245. package/build/dist/Server/Services/RumApplicationService.js +10 -2
  246. package/build/dist/Server/Services/RumApplicationService.js.map +1 -1
  247. package/build/dist/Server/Services/ServerlessFunctionService.js +10 -2
  248. package/build/dist/Server/Services/ServerlessFunctionService.js.map +1 -1
  249. package/build/dist/Server/Services/TelemetryUsageBillingService.js +30 -3
  250. package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
  251. package/build/dist/Server/Services/TraceAggregationService.js +2 -0
  252. package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
  253. package/build/dist/Server/Types/AnalyticsDatabase/AggregateBy.js +8 -25
  254. package/build/dist/Server/Types/AnalyticsDatabase/AggregateBy.js.map +1 -1
  255. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +36 -0
  256. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  257. package/build/dist/Server/Utils/Monitor/MonitorClusterContext.js +90 -0
  258. package/build/dist/Server/Utils/Monitor/MonitorClusterContext.js.map +1 -0
  259. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +228 -4
  260. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  261. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +103 -8
  262. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  263. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js +23 -6
  264. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -1
  265. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +3 -1
  266. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  267. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +23 -0
  268. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
  269. package/build/dist/Server/Utils/Profiling.js +24 -3
  270. package/build/dist/Server/Utils/Profiling.js.map +1 -1
  271. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +4 -0
  272. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  273. package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js +854 -0
  274. package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js.map +1 -0
  275. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +62 -0
  276. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
  277. package/build/dist/Server/Utils/Telemetry.js +8 -10
  278. package/build/dist/Server/Utils/Telemetry.js.map +1 -1
  279. package/build/dist/Types/BaseDatabase/AggregationIntervalUtil.js +69 -0
  280. package/build/dist/Types/BaseDatabase/AggregationIntervalUtil.js.map +1 -0
  281. package/build/dist/Types/Dashboard/DashboardComponentType.js +4 -0
  282. package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
  283. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +2 -0
  284. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
  285. package/build/dist/Types/Dashboard/DashboardComponents/DashboardCephOsdListComponent.js +2 -0
  286. package/build/dist/Types/Dashboard/DashboardComponents/DashboardCephOsdListComponent.js.map +1 -0
  287. package/build/dist/Types/Dashboard/DashboardComponents/DashboardCephPoolListComponent.js +2 -0
  288. package/build/dist/Types/Dashboard/DashboardComponents/DashboardCephPoolListComponent.js.map +1 -0
  289. package/build/dist/Types/Dashboard/DashboardComponents/DashboardProxmoxGuestListComponent.js +2 -0
  290. package/build/dist/Types/Dashboard/DashboardComponents/DashboardProxmoxGuestListComponent.js.map +1 -0
  291. package/build/dist/Types/Dashboard/DashboardComponents/DashboardProxmoxNodeListComponent.js +2 -0
  292. package/build/dist/Types/Dashboard/DashboardComponents/DashboardProxmoxNodeListComponent.js.map +1 -0
  293. package/build/dist/Types/Dashboard/DashboardTemplates.js +394 -0
  294. package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
  295. package/build/dist/Types/Icon/IconProp.js +2 -0
  296. package/build/dist/Types/Icon/IconProp.js.map +1 -1
  297. package/build/dist/Types/Monitor/CephAlertTemplates.js +1379 -0
  298. package/build/dist/Types/Monitor/CephAlertTemplates.js.map +1 -0
  299. package/build/dist/Types/Monitor/CephMetricCatalog.js +353 -0
  300. package/build/dist/Types/Monitor/CephMetricCatalog.js.map +1 -0
  301. package/build/dist/Types/Monitor/MonitorStep.js +46 -0
  302. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  303. package/build/dist/Types/Monitor/MonitorStepCephMonitor.js +34 -0
  304. package/build/dist/Types/Monitor/MonitorStepCephMonitor.js.map +1 -0
  305. package/build/dist/Types/Monitor/MonitorStepProxmoxMonitor.js +36 -0
  306. package/build/dist/Types/Monitor/MonitorStepProxmoxMonitor.js.map +1 -0
  307. package/build/dist/Types/Monitor/MonitorType.js +27 -1
  308. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  309. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +743 -0
  310. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js.map +1 -0
  311. package/build/dist/Types/Monitor/ProxmoxMetricCatalog.js +320 -0
  312. package/build/dist/Types/Monitor/ProxmoxMetricCatalog.js.map +1 -0
  313. package/build/dist/Types/Permission.js +408 -0
  314. package/build/dist/Types/Permission.js.map +1 -1
  315. package/build/dist/Types/Telemetry/EntityType.js +11 -0
  316. package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
  317. package/build/dist/Types/Telemetry/ServiceType.js +2 -0
  318. package/build/dist/Types/Telemetry/ServiceType.js.map +1 -1
  319. package/build/dist/UI/Components/Icon/Icon.js +33 -0
  320. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  321. package/build/dist/UI/Components/ImportExport/ExportModelCard.js +50 -0
  322. package/build/dist/UI/Components/ImportExport/ExportModelCard.js.map +1 -0
  323. package/build/dist/UI/Components/ImportExport/ImportModelsModal.js +115 -0
  324. package/build/dist/UI/Components/ImportExport/ImportModelsModal.js.map +1 -0
  325. package/build/dist/UI/Components/ModelTable/ModelTable.js +166 -74
  326. package/build/dist/UI/Components/ModelTable/ModelTable.js.map +1 -1
  327. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +5 -1
  328. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  329. package/build/dist/UI/Utils/ModelImportExport.js +142 -0
  330. package/build/dist/UI/Utils/ModelImportExport.js.map +1 -0
  331. package/build/dist/UI/Utils/Telemetry/Telemetry.js +11 -10
  332. package/build/dist/UI/Utils/Telemetry/Telemetry.js.map +1 -1
  333. package/build/dist/UI/Utils/TelemetryService.js +5 -2
  334. package/build/dist/UI/Utils/TelemetryService.js.map +1 -1
  335. package/build/dist/Utils/Dashboard/Components/DashboardCephOsdListComponent.js +50 -0
  336. package/build/dist/Utils/Dashboard/Components/DashboardCephOsdListComponent.js.map +1 -0
  337. package/build/dist/Utils/Dashboard/Components/DashboardCephPoolListComponent.js +27 -0
  338. package/build/dist/Utils/Dashboard/Components/DashboardCephPoolListComponent.js.map +1 -0
  339. package/build/dist/Utils/Dashboard/Components/DashboardCephResourceListShared.js +46 -0
  340. package/build/dist/Utils/Dashboard/Components/DashboardCephResourceListShared.js.map +1 -0
  341. package/build/dist/Utils/Dashboard/Components/DashboardProxmoxGuestListComponent.js +55 -0
  342. package/build/dist/Utils/Dashboard/Components/DashboardProxmoxGuestListComponent.js.map +1 -0
  343. package/build/dist/Utils/Dashboard/Components/DashboardProxmoxNodeListComponent.js +42 -0
  344. package/build/dist/Utils/Dashboard/Components/DashboardProxmoxNodeListComponent.js.map +1 -0
  345. package/build/dist/Utils/Dashboard/Components/DashboardProxmoxResourceListShared.js +46 -0
  346. package/build/dist/Utils/Dashboard/Components/DashboardProxmoxResourceListShared.js.map +1 -0
  347. package/build/dist/Utils/Dashboard/Components/Index.js +16 -0
  348. package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
  349. package/build/dist/Utils/ModelImportExport.js +257 -0
  350. package/build/dist/Utils/ModelImportExport.js.map +1 -0
  351. package/build/dist/Utils/Telemetry/EntityKey.js +27 -0
  352. package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -1
  353. package/build/dist/Utils/Telemetry/EntityRelationship.js +3 -0
  354. package/build/dist/Utils/Telemetry/EntityRelationship.js.map +1 -1
  355. package/build/dist/Utils/Telemetry/HeartbeatAvailability.js +174 -0
  356. package/build/dist/Utils/Telemetry/HeartbeatAvailability.js.map +1 -0
  357. package/package.json +29 -21
@@ -0,0 +1,64 @@
1
+ import { MigrationInterface, QueryRunner } from "typeorm";
2
+
3
+ /*
4
+ * Proxmox + Ceph V3 (Internal/Roadmap/ProxmoxCephProductsV3.md):
5
+ *
6
+ * 1. WI-24 backup coverage — ProxmoxCluster.guestsWithoutBackupCount
7
+ * (written from pve_not_backed_up_total on the WI-3 extras path) and
8
+ * ProxmoxResource.isBackedUp (per-guest flag derived from
9
+ * pve_not_backed_up_info presence: an info series carrying the
10
+ * guest's id means NOT covered by any backup job). Both nullable —
11
+ * NULL means the exporter's cluster-level backup-info collector has
12
+ * not reported, which is distinct from "0 uncovered guests".
13
+ *
14
+ * 2. WI-28 hyperconverged cross-link — nullable
15
+ * ProxmoxCluster.cephClusterId FK (SET NULL on delete), manually
16
+ * linked via the cluster's Settings page. No auto-link heuristic:
17
+ * pve-exporter exposes no fsid, so there is no honest join signal
18
+ * (contrast WI-17's Host link, which had name equality). Mirrors
19
+ * Host.proxmoxClusterId: SET NULL, no index.
20
+ *
21
+ * Columns/FKs are derived from the model decorators in
22
+ * Common/Models/DatabaseModels/{ProxmoxCluster,ProxmoxResource}.ts.
23
+ */
24
+ export class AddProxmoxCephV3Columns1781700000000
25
+ implements MigrationInterface
26
+ {
27
+ public name = "AddProxmoxCephV3Columns1781700000000";
28
+
29
+ public async up(queryRunner: QueryRunner): Promise<void> {
30
+ // WI-24: backup coverage snapshot columns.
31
+ await queryRunner.query(
32
+ `ALTER TABLE "ProxmoxCluster" ADD "guestsWithoutBackupCount" integer`,
33
+ );
34
+ await queryRunner.query(
35
+ `ALTER TABLE "ProxmoxResource" ADD "isBackedUp" boolean`,
36
+ );
37
+
38
+ // WI-28: ProxmoxCluster -> CephCluster cross-link (manual only).
39
+ await queryRunner.query(
40
+ `ALTER TABLE "ProxmoxCluster" ADD "cephClusterId" uuid`,
41
+ );
42
+ await queryRunner.query(
43
+ `ALTER TABLE "ProxmoxCluster" ADD CONSTRAINT "FK_proxmox_cluster_cephClusterId" FOREIGN KEY ("cephClusterId") REFERENCES "CephCluster"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
44
+ );
45
+ }
46
+
47
+ public async down(queryRunner: QueryRunner): Promise<void> {
48
+ // WI-28: Ceph cross-link.
49
+ await queryRunner.query(
50
+ `ALTER TABLE "ProxmoxCluster" DROP CONSTRAINT "FK_proxmox_cluster_cephClusterId"`,
51
+ );
52
+ await queryRunner.query(
53
+ `ALTER TABLE "ProxmoxCluster" DROP COLUMN "cephClusterId"`,
54
+ );
55
+
56
+ // WI-24: backup coverage snapshot columns.
57
+ await queryRunner.query(
58
+ `ALTER TABLE "ProxmoxResource" DROP COLUMN "isBackedUp"`,
59
+ );
60
+ await queryRunner.query(
61
+ `ALTER TABLE "ProxmoxCluster" DROP COLUMN "guestsWithoutBackupCount"`,
62
+ );
63
+ }
64
+ }
@@ -385,6 +385,10 @@ import { AddTelemetryEntityRelationshipTable1781200000001 } from "./178120000000
385
385
  import { MigrationName1781250074195 } from "./1781250074195-MigrationName";
386
386
  import { AddTelemetryEntityLabels1781300000000 } from "./1781300000000-AddTelemetryEntityLabels";
387
387
  import { AddServiceTelemetrySdkLanguage1781400000000 } from "./1781400000000-AddServiceTelemetrySdkLanguage";
388
+ import { AddProxmoxAndCephClusterTables1781500000000 } from "./1781500000000-AddProxmoxAndCephClusterTables";
389
+ import { AddProxmoxCephV2Columns1781600000000 } from "./1781600000000-AddProxmoxCephV2Columns";
390
+ import { AddProxmoxCephActivityAndRules1781600000001 } from "./1781600000001-AddProxmoxCephActivityAndRules";
391
+ import { AddProxmoxCephV3Columns1781700000000 } from "./1781700000000-AddProxmoxCephV3Columns";
388
392
 
389
393
  export default [
390
394
  InitialMigration,
@@ -774,4 +778,8 @@ export default [
774
778
  AddTelemetryEntityLabels1781300000000,
775
779
  AddServiceTelemetrySdkLanguage1781400000000,
776
780
  MigrationName1781250074195,
781
+ AddProxmoxAndCephClusterTables1781500000000,
782
+ AddProxmoxCephV2Columns1781600000000,
783
+ AddProxmoxCephActivityAndRules1781600000001,
784
+ AddProxmoxCephV3Columns1781700000000,
777
785
  ];
@@ -100,22 +100,50 @@ export default abstract class Redis {
100
100
  const connectToDatabase: ConnectToDatabaseFunction = async (
101
101
  client: RedisClient,
102
102
  ): Promise<void> => {
103
- try {
104
- await client.connect();
105
- } catch (err) {
106
- if (retry < 3) {
107
- logger.debug(
108
- "Cannot connect to Redis. Retrying again in 5 seconds",
109
- );
110
- // sleep for 5 seconds.
103
+ // A previous attempt (or ioredis' background reconnect) already succeeded.
104
+ if (client.status === "ready") {
105
+ return;
106
+ }
111
107
 
112
- await Sleep.sleep(5000);
108
+ /*
109
+ * The client is created with lazyConnect, so it starts in the "wait" state
110
+ * and only opens when we call connect(). If the first attempt fails, ioredis
111
+ * begins auto-reconnecting in the background (status "connecting" /
112
+ * "reconnecting"), and calling connect() again in that state throws
113
+ * "Redis is already connecting/connected" — which previously propagated out
114
+ * of init() and crashlooped the process. So only issue connect() when the
115
+ * client is idle; when a (re)connect is already in flight, skip the call and
116
+ * wait for it to settle on the next iteration.
117
+ */
118
+ const isIdle: boolean =
119
+ client.status === "wait" ||
120
+ client.status === "end" ||
121
+ client.status === "close";
113
122
 
114
- retry++;
115
- return await connectToDatabase(client);
123
+ try {
124
+ if (isIdle) {
125
+ await client.connect();
126
+ return;
127
+ }
128
+ } catch (err) {
129
+ if (retry >= 3) {
130
+ throw err;
116
131
  }
117
- throw err;
118
132
  }
133
+
134
+ if (retry >= 3) {
135
+ throw new Error(
136
+ `Unable to connect to Redis at ${RedisHostname}:${RedisPort.toNumber()} (status: ${client.status})`,
137
+ );
138
+ }
139
+
140
+ logger.debug("Cannot connect to Redis. Retrying again in 5 seconds");
141
+ // sleep for 5 seconds.
142
+
143
+ await Sleep.sleep(5000);
144
+
145
+ retry++;
146
+ return await connectToDatabase(client);
119
147
  };
120
148
 
121
149
  await connectToDatabase(this.client);
@@ -285,7 +285,7 @@ export default class AnalyticsDatabaseService<
285
285
 
286
286
  const columnName: string = column.key;
287
287
 
288
- if (!this.doesColumnExistInDatabase(columnName)) {
288
+ if (!(await this.doesColumnExistInDatabase(columnName))) {
289
289
  return null;
290
290
  }
291
291
 
@@ -793,14 +793,35 @@ export class BillingService extends BaseService {
793
793
  const customer: Stripe.Response<Stripe.Customer | Stripe.DeletedCustomer> =
794
794
  await this.stripe.customers.retrieve(customerId);
795
795
 
796
- if (
796
+ const defaultPaymentMethod:
797
+ | string
798
+ | Stripe.PaymentMethod
799
+ | null
800
+ | undefined = (customer as Stripe.Customer).invoice_settings
801
+ ?.default_payment_method;
802
+
803
+ const defaultPaymentMethodId: string | undefined =
804
+ typeof defaultPaymentMethod === "string"
805
+ ? defaultPaymentMethod
806
+ : defaultPaymentMethod?.id;
807
+
808
+ if (defaultPaymentMethodId) {
809
+ for (const paymentMethod of paymentMethods) {
810
+ paymentMethod.isDefault = paymentMethod.id === defaultPaymentMethodId;
811
+ }
812
+
813
+ // default payment method first — it's charged first when paying invoices.
814
+ paymentMethods.sort((a: PaymentMethod, b: PaymentMethod) => {
815
+ return Number(b.isDefault) - Number(a.isDefault);
816
+ });
817
+ } else if (
797
818
  (customer as Stripe.Customer).invoice_settings &&
798
- !(customer as Stripe.Customer).invoice_settings?.default_payment_method
819
+ paymentMethods.length > 0 &&
820
+ paymentMethods[0]?.id
799
821
  ) {
800
822
  // set the first payment method as default.
801
- if (paymentMethods.length > 0 && paymentMethods[0]?.id) {
802
- await this.setDefaultPaymentMethod(customerId, paymentMethods[0]?.id);
803
- }
823
+ await this.setDefaultPaymentMethod(customerId, paymentMethods[0].id);
824
+ paymentMethods[0].isDefault = true;
804
825
  }
805
826
 
806
827
  return paymentMethods;
@@ -1237,6 +1258,41 @@ export class BillingService extends BaseService {
1237
1258
  return invoice;
1238
1259
  }
1239
1260
 
1261
+ /*
1262
+ * Returns true if the error is attributable to the payment method itself
1263
+ * (declined, expired, unusable), meaning paying with a different payment
1264
+ * method may succeed.
1265
+ *
1266
+ * Not retryable:
1267
+ * - invoice_payment_intent_requires_action (3DS/SCA): the payment method
1268
+ * works but needs customer authentication — throw so the interactive
1269
+ * flow (BillingInvoiceAPI) surfaces the authentication prompt for the
1270
+ * default method instead of silently charging a backup method.
1271
+ * - Invoice-state or connectivity errors: another payment method would
1272
+ * not help, and if the outcome of the attempt is unknown a retry could
1273
+ * double-charge the customer.
1274
+ *
1275
+ * Note: most bank debit (ACH/SEPA/BACS) failures are asynchronous — the
1276
+ * pay call succeeds and the failure arrives days later via webhook — so
1277
+ * failover only catches the synchronous ones (unverified/unusable
1278
+ * accounts).
1279
+ */
1280
+ private canRetryWithDifferentPaymentMethod(err: unknown): boolean {
1281
+ const stripeError: { type?: string; code?: string } = err as {
1282
+ type?: string;
1283
+ code?: string;
1284
+ };
1285
+
1286
+ if (stripeError?.type === "StripeCardError") {
1287
+ return true;
1288
+ }
1289
+
1290
+ return Boolean(
1291
+ stripeError?.code?.startsWith("payment_method_") ||
1292
+ stripeError?.code?.startsWith("bank_account_"),
1293
+ );
1294
+ }
1295
+
1240
1296
  @CaptureSpan()
1241
1297
  public async payInvoice(
1242
1298
  customerId: string,
@@ -1250,23 +1306,55 @@ export class BillingService extends BaseService {
1250
1306
  throw new BadDataException(Errors.BillingService.NO_PAYMENTS_METHODS);
1251
1307
  }
1252
1308
 
1253
- const invoice: Stripe.Invoice = await this.stripe.invoices.pay(invoiceId, {
1254
- payment_method: paymentMethods[0]?.id || "",
1255
- });
1309
+ /*
1310
+ * getPaymentMethods returns the default payment method first. If it is
1311
+ * declined, fall back to the customer's other payment methods before
1312
+ * giving up. Attempts are capped to bound decline traffic on unattended
1313
+ * retry paths (e.g. recharge-on-low-balance), which create a fresh
1314
+ * invoice and retry on every cycle.
1315
+ */
1316
+ const maxPaymentMethodsToTry: number = 3;
1317
+ let lastError: unknown = null;
1256
1318
 
1257
- return {
1258
- id: invoice.id!,
1259
- amount: invoice.amount_due,
1260
- currencyCode: invoice.currency,
1261
- subscriptionId: invoice.subscription?.toString() || undefined,
1262
- status: invoice.status?.toString() || "Unknown",
1263
- downloadableLink: invoice.invoice_pdf?.toString() || "",
1264
- customerId: invoice.customer?.toString() || "",
1265
- invoiceDate: invoice.created
1266
- ? new Date(invoice.created * 1000)
1267
- : OneUptimeDate.getCurrentDate(),
1268
- invoiceNumber: invoice.number || undefined,
1269
- };
1319
+ for (const paymentMethod of paymentMethods.slice(
1320
+ 0,
1321
+ maxPaymentMethodsToTry,
1322
+ )) {
1323
+ try {
1324
+ const invoice: Stripe.Invoice = await this.stripe.invoices.pay(
1325
+ invoiceId,
1326
+ {
1327
+ payment_method: paymentMethod.id,
1328
+ },
1329
+ );
1330
+
1331
+ return {
1332
+ id: invoice.id!,
1333
+ amount: invoice.amount_due,
1334
+ currencyCode: invoice.currency,
1335
+ subscriptionId: invoice.subscription?.toString() || undefined,
1336
+ status: invoice.status?.toString() || "Unknown",
1337
+ downloadableLink: invoice.invoice_pdf?.toString() || "",
1338
+ customerId: invoice.customer?.toString() || "",
1339
+ invoiceDate: invoice.created
1340
+ ? new Date(invoice.created * 1000)
1341
+ : OneUptimeDate.getCurrentDate(),
1342
+ invoiceNumber: invoice.number || undefined,
1343
+ };
1344
+ } catch (err) {
1345
+ logger.error(
1346
+ `Failed to pay invoice ${invoiceId} with payment method ${paymentMethod.type} ending in ${paymentMethod.last4Digits}: ${err}`,
1347
+ );
1348
+
1349
+ if (!this.canRetryWithDifferentPaymentMethod(err)) {
1350
+ throw err;
1351
+ }
1352
+
1353
+ lastError = err;
1354
+ }
1355
+ }
1356
+
1357
+ throw lastError;
1270
1358
  }
1271
1359
 
1272
1360
  public getMeteredPlanPriceId(productType: ProductType): string {
@@ -0,0 +1,200 @@
1
+ import Label from "../../Models/DatabaseModels/Label";
2
+ import CephCluster from "../../Models/DatabaseModels/CephCluster";
3
+ import CephClusterLabelRule from "../../Models/DatabaseModels/CephClusterLabelRule";
4
+ import CephClusterLabelRuleService from "./CephClusterLabelRuleService";
5
+ import CephClusterService from "./CephClusterService";
6
+ import ObjectID from "../../Types/ObjectID";
7
+ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
8
+ import logger, { LogAttributes } from "../Utils/Logger";
9
+
10
+ class CephClusterLabelRuleEngineServiceClass {
11
+ /**
12
+ * Evaluates CephClusterLabelRule rows for the given Ceph cluster and attaches matched
13
+ * labels to it. The union is deduped against labels already on the Ceph cluster
14
+ * before insert to avoid PK conflicts on the join table.
15
+ */
16
+ @CaptureSpan()
17
+ public async applyRulesToCephCluster(
18
+ cephCluster: CephCluster,
19
+ ): Promise<void> {
20
+ if (!cephCluster.id || !cephCluster.projectId) {
21
+ return;
22
+ }
23
+
24
+ try {
25
+ const rules: Array<CephClusterLabelRule> =
26
+ await CephClusterLabelRuleService.findBy({
27
+ query: {
28
+ projectId: cephCluster.projectId,
29
+ isEnabled: true,
30
+ },
31
+ props: { isRoot: true },
32
+ select: {
33
+ _id: true,
34
+ name: true,
35
+ cephClusterLabels: { _id: true },
36
+ cephClusterNamePattern: true,
37
+ cephClusterDescriptionPattern: true,
38
+ labelsToAdd: { _id: true },
39
+ },
40
+ limit: 100,
41
+ skip: 0,
42
+ });
43
+
44
+ if (rules.length === 0) {
45
+ return;
46
+ }
47
+
48
+ const cephClusterWithDetails: CephCluster | null =
49
+ await CephClusterService.findOneById({
50
+ id: cephCluster.id,
51
+ select: {
52
+ name: true,
53
+ description: true,
54
+ labels: { _id: true },
55
+ },
56
+ props: { isRoot: true },
57
+ });
58
+
59
+ if (!cephClusterWithDetails) {
60
+ return;
61
+ }
62
+
63
+ const labelIdsToAdd: Set<string> = new Set();
64
+
65
+ for (const rule of rules) {
66
+ const matches: boolean = this.doesCephClusterMatchRule(
67
+ cephClusterWithDetails,
68
+ rule,
69
+ );
70
+ if (!matches) {
71
+ continue;
72
+ }
73
+ for (const label of rule.labelsToAdd || []) {
74
+ if (label.id) {
75
+ labelIdsToAdd.add(label.id.toString());
76
+ }
77
+ }
78
+ }
79
+
80
+ if (labelIdsToAdd.size === 0) {
81
+ return;
82
+ }
83
+
84
+ const existingLabelIds: Set<string> = new Set(
85
+ (cephClusterWithDetails.labels || [])
86
+ .map((l: Label) => {
87
+ return l.id?.toString() || "";
88
+ })
89
+ .filter((id: string) => {
90
+ return id !== "";
91
+ }),
92
+ );
93
+
94
+ const newLabelIds: Array<string> = Array.from(labelIdsToAdd).filter(
95
+ (id: string) => {
96
+ return !existingLabelIds.has(id);
97
+ },
98
+ );
99
+ if (newLabelIds.length === 0) {
100
+ return;
101
+ }
102
+
103
+ await CephClusterService.getRepository()
104
+ .createQueryBuilder()
105
+ .relation(CephCluster, "labels")
106
+ .of(cephCluster.id.toString())
107
+ .add(newLabelIds);
108
+
109
+ /*
110
+ * Sync in-memory cephCluster.labels so a downstream owner-rule engine in
111
+ * the same onCreateSuccess chain can match on rule-added labels.
112
+ */
113
+ const mergedLabelIds: Set<string> = new Set([
114
+ ...existingLabelIds,
115
+ ...newLabelIds,
116
+ ]);
117
+ cephCluster.labels = Array.from(mergedLabelIds).map((id: string) => {
118
+ const label: Label = new Label();
119
+ label.id = new ObjectID(id);
120
+ return label;
121
+ });
122
+
123
+ logger.debug(
124
+ `CephClusterLabelRuleEngine attached ${newLabelIds.length} labels to Ceph cluster ${cephCluster.id}`,
125
+ { projectId: cephCluster.projectId.toString() } as LogAttributes,
126
+ );
127
+ } catch (error) {
128
+ logger.error(`Error applying Ceph cluster label rules: ${error}`, {
129
+ projectId: cephCluster.projectId?.toString(),
130
+ cephClusterId: cephCluster.id?.toString(),
131
+ } as LogAttributes);
132
+ }
133
+ }
134
+
135
+ private doesCephClusterMatchRule(
136
+ cephCluster: CephCluster,
137
+ rule: CephClusterLabelRule,
138
+ ): boolean {
139
+ if (rule.cephClusterLabels && rule.cephClusterLabels.length > 0) {
140
+ if (!cephCluster.labels || cephCluster.labels.length === 0) {
141
+ return false;
142
+ }
143
+ const ruleLabelIds: Array<string> = rule.cephClusterLabels.map(
144
+ (l: Label) => {
145
+ return l.id?.toString() || "";
146
+ },
147
+ );
148
+ const labelIds: Array<string> = cephCluster.labels.map((l: Label) => {
149
+ return l.id?.toString() || "";
150
+ });
151
+ if (
152
+ !ruleLabelIds.some((id: string) => {
153
+ return labelIds.includes(id);
154
+ })
155
+ ) {
156
+ return false;
157
+ }
158
+ }
159
+
160
+ if (
161
+ rule.cephClusterNamePattern &&
162
+ (!cephCluster.name ||
163
+ !this.testRegex(rule.cephClusterNamePattern, cephCluster.name, rule))
164
+ ) {
165
+ return false;
166
+ }
167
+
168
+ if (
169
+ rule.cephClusterDescriptionPattern &&
170
+ (!cephCluster.description ||
171
+ !this.testRegex(
172
+ rule.cephClusterDescriptionPattern,
173
+ cephCluster.description,
174
+ rule,
175
+ ))
176
+ ) {
177
+ return false;
178
+ }
179
+
180
+ return true;
181
+ }
182
+
183
+ private testRegex(
184
+ pattern: string,
185
+ value: string,
186
+ rule: CephClusterLabelRule,
187
+ ): boolean {
188
+ try {
189
+ const regex: RegExp = new RegExp(pattern, "i");
190
+ return regex.test(value);
191
+ } catch {
192
+ logger.warn(
193
+ `Invalid regex in Ceph cluster label rule ${rule.id}: ${pattern}`,
194
+ );
195
+ return false;
196
+ }
197
+ }
198
+ }
199
+
200
+ export default new CephClusterLabelRuleEngineServiceClass();
@@ -0,0 +1,14 @@
1
+ import DatabaseService from "./DatabaseService";
2
+ import Model from "../../Models/DatabaseModels/CephClusterLabelRule";
3
+ import { IsBillingEnabled } from "../EnvironmentConfig";
4
+
5
+ export class Service extends DatabaseService<Model> {
6
+ public constructor() {
7
+ super(Model);
8
+ if (IsBillingEnabled) {
9
+ this.hardDeleteItemsOlderThanInDays("createdAt", 3 * 365);
10
+ }
11
+ }
12
+ }
13
+
14
+ export default new Service();