@oneuptime/common 14.0.2 → 14.0.5

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 (765) hide show
  1. package/Models/DatabaseModels/Alert.ts +55 -0
  2. package/Models/DatabaseModels/AlertFeed.ts +2 -0
  3. package/Models/DatabaseModels/DatabaseServer.ts +1650 -0
  4. package/Models/DatabaseModels/DatabaseServerEndpoint.ts +540 -0
  5. package/Models/DatabaseModels/DatabaseServerFeed.ts +625 -0
  6. package/Models/DatabaseModels/DatabaseServerLabelRule.ts +514 -0
  7. package/Models/DatabaseModels/DatabaseServerOwnerRule.ts +596 -0
  8. package/Models/DatabaseModels/DatabaseServerOwnerTeam.ts +491 -0
  9. package/Models/DatabaseModels/DatabaseServerOwnerUser.ts +490 -0
  10. package/Models/DatabaseModels/Incident.ts +55 -0
  11. package/Models/DatabaseModels/IncidentAlert.ts +540 -0
  12. package/Models/DatabaseModels/IncidentFeed.ts +2 -0
  13. package/Models/DatabaseModels/Index.ts +18 -0
  14. package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +26 -0
  15. package/Models/DatabaseModels/Project.ts +60 -0
  16. package/Models/DatabaseModels/RumApplication.ts +52 -1
  17. package/Models/DatabaseModels/ScheduledMaintenance.ts +55 -0
  18. package/Models/DatabaseModels/TelemetryException.ts +2 -0
  19. package/Models/DatabaseModels/UserProjectSsoConsent.ts +146 -0
  20. package/Server/Infrastructure/Postgres/SchemaMigrations/1794800000000-AddSessionReplaySameOriginTracePropagation.ts +28 -0
  21. package/Server/Infrastructure/Postgres/SchemaMigrations/1794900000000-AddIncidentAlert.ts +89 -0
  22. package/Server/Infrastructure/Postgres/SchemaMigrations/1795000000000-AddDatabaseServerTables.ts +673 -0
  23. package/Server/Infrastructure/Postgres/SchemaMigrations/1795100000000-AddUserProjectSsoConsent.ts +51 -0
  24. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
  25. package/Server/Middleware/MultipartFormData.ts +1 -1
  26. package/Server/Middleware/TelemetryIngest.ts +15 -8
  27. package/Server/Services/AlertReminderRuleService.ts +100 -24
  28. package/Server/Services/DatabaseServerEndpointService.ts +895 -0
  29. package/Server/Services/DatabaseServerFeedService.ts +128 -0
  30. package/Server/Services/DatabaseServerLabelRuleEngineService.ts +340 -0
  31. package/Server/Services/DatabaseServerLabelRuleService.ts +14 -0
  32. package/Server/Services/DatabaseServerOwnerRuleEngineService.ts +425 -0
  33. package/Server/Services/DatabaseServerOwnerRuleService.ts +14 -0
  34. package/Server/Services/DatabaseServerOwnerTeamService.ts +180 -0
  35. package/Server/Services/DatabaseServerOwnerUserService.ts +173 -0
  36. package/Server/Services/DatabaseServerService.ts +4546 -0
  37. package/Server/Services/DatabaseService.ts +14 -8
  38. package/Server/Services/DockerResourceService.ts +43 -2
  39. package/Server/Services/IncidentAlertService.ts +1811 -0
  40. package/Server/Services/IncidentReminderRuleService.ts +103 -23
  41. package/Server/Services/IncidentService.ts +210 -10
  42. package/Server/Services/IncidentStateTimelineService.ts +24 -0
  43. package/Server/Services/Index.ts +18 -0
  44. package/Server/Services/InventoryItemService.ts +113 -5
  45. package/Server/Services/IoTDeviceService.ts +145 -37
  46. package/Server/Services/OpenTelemetryIngestService.ts +19 -0
  47. package/Server/Services/PodmanResourceService.ts +43 -2
  48. package/Server/Services/ScheduledMaintenanceReminderRuleService.ts +107 -23
  49. package/Server/Services/ServiceService.ts +1 -1
  50. package/Server/Services/TelemetryUsageBillingService.ts +29 -2
  51. package/Server/Services/UserProjectSsoConsentService.ts +74 -0
  52. package/Server/Services/UserService.ts +14 -1
  53. package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +18 -0
  54. package/Server/Types/Database/QueryHelper.ts +30 -1
  55. package/Server/Utils/AI/Toolbox/ResourceTools.ts +69 -1
  56. package/Server/Utils/Database/AffectedResourceRelations.ts +6 -0
  57. package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +188 -6
  58. package/Server/Utils/Monitor/MonitorAlert.ts +28 -1
  59. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +2262 -755
  60. package/Server/Utils/Monitor/MonitorIncident.ts +28 -1
  61. package/Server/Utils/Monitor/MonitorMaintenanceSuppression.ts +268 -6
  62. package/Server/Utils/Monitor/MonitorResource.ts +47 -11
  63. package/Server/Utils/Monitor/MonitorResourceContext.ts +1 -0
  64. package/Server/Utils/Monitor/MonitorStepResourceIdentity.ts +239 -21
  65. package/Server/Utils/Monitor/PerSeriesResolutionRootCause.ts +43 -0
  66. package/Server/Utils/Monitor/SeriesResourceLabels.ts +291 -0
  67. package/Server/Utils/Monitor/SeriesResourceLinker.ts +111 -12
  68. package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +25 -0
  69. package/Server/Utils/SessionReplay/SessionReplayGateCache.ts +24 -2
  70. package/Server/Utils/StartServer.ts +26 -6
  71. package/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.ts +2 -0
  72. package/Server/Utils/Telemetry/DatabaseEndpointDiscovery.ts +688 -0
  73. package/Server/Utils/Telemetry/EntityRegistry.ts +5 -1
  74. package/Server/Utils/Telemetry/LogExceptionExtractor.ts +18 -1
  75. package/Server/Utils/Telemetry/ResourceEntityFilter.ts +175 -12
  76. package/Server/Utils/Telemetry/ResourceFacetResolver.ts +12 -0
  77. package/Server/Utils/Telemetry/ServiceDependencyDiscovery.ts +606 -36
  78. package/Server/Utils/Telemetry/Telemetry.ts +16 -0
  79. package/Server/Utils/Telemetry/TelemetryEntity.ts +22 -22
  80. package/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.ts +16 -10
  81. package/Tests/App/Accounts/SignedInRedirect.test.tsx +241 -0
  82. package/Tests/App/AdminDashboard/AdminHeaderSmallScreens.test.tsx +221 -4
  83. package/Tests/App/Dashboard/AIInsightsResourcePageContext.test.ts +42 -0
  84. package/Tests/App/Dashboard/AffectedResourcesDisplay.test.tsx +100 -0
  85. package/Tests/App/Dashboard/AffectedResourcesPicker.test.tsx +86 -0
  86. package/Tests/App/Dashboard/AffectedResourcesPickerHiddenTypes.test.tsx +2 -0
  87. package/Tests/App/Dashboard/AffectedResourcesSummaryStep.test.tsx +19 -0
  88. package/Tests/App/Dashboard/BreadcrumbCoverage.test.tsx +14 -0
  89. package/Tests/App/Dashboard/BulkIncidentLinkActions.test.tsx +869 -0
  90. package/Tests/App/Dashboard/CephMetricTooltips.test.tsx +1777 -0
  91. package/Tests/App/Dashboard/CloudFleetSummary.test.ts +8 -0
  92. package/Tests/App/Dashboard/CloudMetricTooltips.test.tsx +887 -0
  93. package/Tests/App/Dashboard/ContainerHostMetricTooltips.test.tsx +1309 -0
  94. package/Tests/App/Dashboard/CorrelateFilterBuilder.test.tsx +26 -1
  95. package/Tests/App/Dashboard/DashboardAppSsoError.test.tsx +501 -0
  96. package/Tests/App/Dashboard/DashboardHeaderRequests.test.tsx +64 -1
  97. package/Tests/App/Dashboard/DashboardHeaderSmallScreens.test.tsx +178 -18
  98. package/Tests/App/Dashboard/DashboardMasterPageSsoRedirect.test.tsx +444 -0
  99. package/Tests/App/Dashboard/DashboardNavBarForeignHiddenRule.test.tsx +573 -0
  100. package/Tests/App/Dashboard/DatabaseChartAxes.test.tsx +431 -0
  101. package/Tests/App/Dashboard/DatabaseContainerDetailBadge.test.tsx +249 -0
  102. package/Tests/App/Dashboard/DatabaseDashboardE2EFixes.test.ts +681 -0
  103. package/Tests/App/Dashboard/DatabaseDocumentationMarkdown.test.ts +1801 -0
  104. package/Tests/App/Dashboard/DatabaseFleetSummaryRefresh.test.tsx +280 -0
  105. package/Tests/App/Dashboard/DatabaseFormHelpers.test.tsx +321 -0
  106. package/Tests/App/Dashboard/DatabaseMetricMonitorLink.test.tsx +795 -0
  107. package/Tests/App/Dashboard/DatabaseOverviewHeader.test.tsx +580 -0
  108. package/Tests/App/Dashboard/DatabaseRecommendationsEngineMetrics.test.ts +270 -0
  109. package/Tests/App/Dashboard/DatabaseServerComponents.test.tsx +1486 -0
  110. package/Tests/App/Dashboard/DatabaseServerEngineMetricsFilter.test.ts +223 -0
  111. package/Tests/App/Dashboard/DatabaseServerPresentation.test.ts +435 -0
  112. package/Tests/App/Dashboard/DatabaseServerSummary.test.ts +186 -0
  113. package/Tests/App/Dashboard/DatabaseServerTelemetryQueries.test.ts +1553 -0
  114. package/Tests/App/Dashboard/DatabaseTableTruncation.test.tsx +326 -0
  115. package/Tests/App/Dashboard/DatabaseTelemetryScope.test.ts +512 -0
  116. package/Tests/App/Dashboard/DatabaseTelemetryTabs.test.tsx +774 -0
  117. package/Tests/App/Dashboard/DatabaseViewLayout.test.tsx +233 -0
  118. package/Tests/App/Dashboard/DatabaseWorkloadBadge.test.tsx +972 -0
  119. package/Tests/App/Dashboard/DiscoveryReviewInventoryRefresh.test.tsx +5 -0
  120. package/Tests/App/Dashboard/DiscoveryReviewUnnamedHostHint.test.tsx +1061 -0
  121. package/Tests/App/Dashboard/DiscoveryScanLivePage.test.tsx +39 -0
  122. package/Tests/App/Dashboard/DockerSwarmClustersListTooltips.test.tsx +414 -0
  123. package/Tests/App/Dashboard/DockerSwarmMetricTooltips.test.ts +796 -0
  124. package/Tests/App/Dashboard/DockerSwarmOverviewTooltips.test.tsx +747 -0
  125. package/Tests/App/Dashboard/EventOverlayScope.test.ts +147 -0
  126. package/Tests/App/Dashboard/EventOverlayScopeHook.test.tsx +1 -0
  127. package/Tests/App/Dashboard/ExceptionMonitorEnvironmentFilter.test.tsx +38 -18
  128. package/Tests/App/Dashboard/HostDetailViewTooltips.test.tsx +725 -0
  129. package/Tests/App/Dashboard/HostListColumnTooltips.test.tsx +472 -0
  130. package/Tests/App/Dashboard/HostMetricTooltips.test.ts +709 -0
  131. package/Tests/App/Dashboard/HostOverviewTooltips.test.tsx +698 -0
  132. package/Tests/App/Dashboard/HostTooltipHarness.ts +124 -0
  133. package/Tests/App/Dashboard/HostsListTooltips.test.tsx +395 -0
  134. package/Tests/App/Dashboard/IncidentAlertLinkDialog.test.tsx +691 -0
  135. package/Tests/App/Dashboard/IncidentAlertLinkHelpers.test.ts +458 -0
  136. package/Tests/App/Dashboard/IncidentAlertLinkPages.test.tsx +828 -0
  137. package/Tests/App/Dashboard/IncidentAlertLinkSideMenus.test.tsx +231 -0
  138. package/Tests/App/Dashboard/IncidentCreateFromAlerts.test.tsx +689 -0
  139. package/Tests/App/Dashboard/IoTMetricTooltips.test.tsx +1123 -0
  140. package/Tests/App/Dashboard/KubernetesClusterMetricTooltips.test.ts +837 -0
  141. package/Tests/App/Dashboard/KubernetesClusterOverviewTooltips.test.tsx +699 -0
  142. package/Tests/App/Dashboard/KubernetesContainersTabTooltips.test.tsx +320 -0
  143. package/Tests/App/Dashboard/KubernetesCostTooltips.test.tsx +502 -0
  144. package/Tests/App/Dashboard/KubernetesInsightsTooltips.test.tsx +222 -0
  145. package/Tests/App/Dashboard/KubernetesResourceMetricTooltips.test.ts +561 -0
  146. package/Tests/App/Dashboard/KubernetesResourcePagesTooltips.test.tsx +1168 -0
  147. package/Tests/App/Dashboard/LinkIncidentAlertModal.test.tsx +154 -0
  148. package/Tests/App/Dashboard/LogsResourceFacetChips.test.tsx +1 -0
  149. package/Tests/App/Dashboard/MetricDescriptionRules.ts +170 -0
  150. package/Tests/App/Dashboard/MetricDescriptionsCatalog.test.ts +206 -0
  151. package/Tests/App/Dashboard/MetricDescriptionsConsistency.test.ts +275 -0
  152. package/Tests/App/Dashboard/MetricsViewerDrillDown.test.tsx +310 -0
  153. package/Tests/App/Dashboard/MetricsViewerEntityScopedRows.test.tsx +495 -0
  154. package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +132 -1
  155. package/Tests/App/Dashboard/NavigationSearchKeywords.test.tsx +5 -0
  156. package/Tests/App/Dashboard/NetworkDeviceTooltips.test.tsx +852 -0
  157. package/Tests/App/Dashboard/NetworkDiagnosticsTooltips.test.tsx +556 -0
  158. package/Tests/App/Dashboard/NetworkMetricTooltips.test.ts +1348 -0
  159. package/Tests/App/Dashboard/NetworkSiteTooltips.test.tsx +679 -0
  160. package/Tests/App/Dashboard/ProductOrientation.test.tsx +4 -3
  161. package/Tests/App/Dashboard/ProxmoxMetricTooltips.test.ts +592 -0
  162. package/Tests/App/Dashboard/ProxmoxOverviewTooltips.test.tsx +1002 -0
  163. package/Tests/App/Dashboard/ProxmoxResourcePageTooltips.test.tsx +923 -0
  164. package/Tests/App/Dashboard/RecommendationsLoadedContext.test.tsx +349 -0
  165. package/Tests/App/Dashboard/ResourceArchiveSettings.test.tsx +62 -0
  166. package/Tests/App/Dashboard/ResourceFeedPageWiring.test.ts +8 -1
  167. package/Tests/App/Dashboard/ResourceFeedPagesFilterSort.test.tsx +14 -0
  168. package/Tests/App/Dashboard/ResourceOverviewTileTooltips.test.tsx +1066 -0
  169. package/Tests/App/Dashboard/RumOverviewPage.test.tsx +1195 -0
  170. package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +2 -0
  171. package/Tests/App/Dashboard/ServerlessMetricTooltips.test.tsx +474 -0
  172. package/Tests/App/Dashboard/ServiceMapDatabaseLink.test.tsx +1085 -0
  173. package/Tests/App/Dashboard/ServiceMetricTooltips.test.tsx +772 -0
  174. package/Tests/App/Dashboard/SessionReplayAuditTable.test.tsx +56 -1
  175. package/Tests/App/Dashboard/TelemetryMetricsSignals.test.ts +1207 -0
  176. package/Tests/App/Dashboard/TelemetryResourceRetentionSettings.test.tsx +10 -0
  177. package/Tests/App/Dashboard/TelemetryResourceTabTooltips.test.tsx +437 -0
  178. package/Tests/App/Dashboard/TracesResourceFacets.test.tsx +2 -1
  179. package/Tests/App/Dashboard/VMwareMetricTooltips.test.ts +801 -0
  180. package/Tests/App/Dashboard/VMwareOverviewTooltips.test.tsx +601 -0
  181. package/Tests/App/Dashboard/VMwareResourcePagesTooltips.test.tsx +646 -0
  182. package/Tests/App/Dashboard/VMwareTooltipHarness.ts +145 -0
  183. package/Tests/App/StatusPage/StatusPageHeaderForeignHiddenRule.test.tsx +284 -0
  184. package/Tests/ClassStrings.ts +178 -0
  185. package/Tests/Fixtures/MobilePasskeyUser.json +1 -2
  186. package/Tests/ForeignHiddenRuleGuard.ts +2152 -0
  187. package/Tests/Models/DatabaseModels/DatabaseServerModels.test.ts +2250 -0
  188. package/Tests/Models/DatabaseModels/IncidentAlertModel.test.ts +554 -0
  189. package/Tests/Models/DatabaseModels/ResourceFeedModels.test.ts +24 -5
  190. package/Tests/Models/DatabaseModels/SessionReplayModels.test.ts +117 -0
  191. package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
  192. package/Tests/RenderedMarkup.ts +518 -0
  193. package/Tests/ResponsiveVisibility.test.ts +490 -4
  194. package/Tests/ResponsiveVisibility.ts +505 -52
  195. package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
  196. package/Tests/Server/Infrastructure/Postgres/AddDatabaseServerTablesMigration.test.ts +541 -0
  197. package/Tests/Server/Infrastructure/Postgres/AddIncidentAlertMigration.test.ts +341 -0
  198. package/Tests/Server/Infrastructure/Postgres/AddSessionReplaySameOriginTracePropagationMigration.test.ts +247 -0
  199. package/Tests/Server/Infrastructure/Postgres/AddUserProjectSsoConsentMigration.test.ts +234 -0
  200. package/Tests/Server/Services/ContainerSnapshotUpsertPostgres.test.ts +319 -0
  201. package/Tests/Server/Services/CrossProjectRelationWriteGuard.test.ts +13 -0
  202. package/Tests/Server/Services/DatabaseServerEndpointService.test.ts +2033 -0
  203. package/Tests/Server/Services/DatabaseServerFeedAndOwnerServices.test.ts +529 -0
  204. package/Tests/Server/Services/DatabaseServerLifecycle.test.ts +3302 -0
  205. package/Tests/Server/Services/DatabaseServerRegistries.test.ts +603 -0
  206. package/Tests/Server/Services/DatabaseServerRuleEngines.test.ts +754 -0
  207. package/Tests/Server/Services/DatabaseServerService.test.ts +3558 -0
  208. package/Tests/Server/Services/DatabaseServerSqlPostgres.test.ts +2045 -0
  209. package/Tests/Server/Services/DatabaseServiceUpdateColumnsIfUnlockedPostgres.test.ts +362 -0
  210. package/Tests/Server/Services/DatabaseServiceUpdateColumnsIfUnlockedReply.test.ts +210 -0
  211. package/Tests/Server/Services/HookFreeWriteLengthClamp.test.ts +18 -0
  212. package/Tests/Server/Services/IncidentAlertPostgres.test.ts +903 -0
  213. package/Tests/Server/Services/IncidentAlertRegistration.test.ts +96 -0
  214. package/Tests/Server/Services/IncidentAlertService.test.ts +2225 -0
  215. package/Tests/Server/Services/IncidentAlertSloLinkSurvivesEdit.test.ts +2 -0
  216. package/Tests/Server/Services/IncidentAlertStateCascade.test.ts +970 -0
  217. package/Tests/Server/Services/IncidentCreateFromAlerts.test.ts +1284 -0
  218. package/Tests/Server/Services/IncomingCallPolicyEscalationRuleTarget.test.ts +225 -0
  219. package/Tests/Server/Services/InventoryItemDisplayName.test.ts +280 -2
  220. package/Tests/Server/Services/InventoryUpsertSchemaParity.test.ts +8 -2
  221. package/Tests/Server/Services/IoTDeviceLatestMetricsPostgres.test.ts +689 -0
  222. package/Tests/Server/Services/IoTDeviceService.test.ts +379 -0
  223. package/Tests/Server/Services/LatestMetricsValuesShape.test.ts +360 -0
  224. package/Tests/Server/Services/LlmModelPriceService.test.ts +402 -0
  225. package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +7 -1
  226. package/Tests/Server/Services/OwnerRowUniqueness.test.ts +61 -9
  227. package/Tests/Server/Services/ReminderRuleLookupPostgres.test.ts +2250 -0
  228. package/Tests/Server/Services/ReminderRuleRefreshOpenSubjectsPaging.test.ts +653 -0
  229. package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +68 -20
  230. package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +3 -3
  231. package/Tests/Server/Services/TelemetryResourceFacetCounting.test.ts +9 -0
  232. package/Tests/Server/Services/UserProjectSsoConsentPostgres.test.ts +153 -0
  233. package/Tests/Server/Services/UserProjectSsoConsentService.test.ts +192 -0
  234. package/Tests/Server/Services/UserServiceFirstMasterAdminElection.test.ts +71 -0
  235. package/Tests/Server/Services/UserSignupIdTakeoverPostgres.test.ts +238 -0
  236. package/Tests/Server/Services/WorkspaceNotificationSummaryHelpers.test.ts +592 -0
  237. package/Tests/Server/Types/Billing/PayAsYouGoMeteredAuthorization.test.ts +3 -0
  238. package/Tests/Server/Types/Database/EventOverlayScopePostgres.test.ts +1 -0
  239. package/Tests/Server/Types/Database/FeedEventTypeFilterQuery.test.ts +11 -0
  240. package/Tests/Server/Types/Database/Permissions/InfrastructureOwnershipScope.test.ts +8 -0
  241. package/Tests/Server/Types/Database/QueryHelperBooleanForCriteriaBackedRule.test.ts +1094 -0
  242. package/Tests/Server/Utils/AI/ResourceTools.test.ts +134 -0
  243. package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.test.ts +41 -0
  244. package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaAnomalyUnits.test.ts +279 -9
  245. package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaDisplayContext.test.ts +933 -0
  246. package/Tests/Server/Utils/Monitor/DatabaseMaintenanceSuppression.test.ts +582 -0
  247. package/Tests/Server/Utils/Monitor/DatabaseServerMonitorLinking.test.ts +753 -0
  248. package/Tests/Server/Utils/Monitor/MonitorActionTimestamps.test.ts +1 -0
  249. package/Tests/Server/Utils/Monitor/MonitorAlertCriteriaReferences.test.ts +1 -0
  250. package/Tests/Server/Utils/Monitor/MonitorAlertResourceLinking.test.ts +119 -0
  251. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +60 -25
  252. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorAffectedResourceEdgeCases.test.ts +1719 -0
  253. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorKubernetesAffectedResources.test.ts +1447 -0
  254. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorKubernetesRatioEmail.test.ts +352 -0
  255. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorPlatformMetricUnits.test.ts +717 -0
  256. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorPlatformRawScan.test.ts +2125 -0
  257. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorPlatformSeriesAffectedResources.test.ts +1288 -0
  258. package/Tests/Server/Utils/Monitor/MonitorDependencySuppressionCreatorSkip.test.ts +1 -0
  259. package/Tests/Server/Utils/Monitor/MonitorIncidentCriteriaReferences.test.ts +1 -0
  260. package/Tests/Server/Utils/Monitor/MonitorIncidentMemberRoleMembership.test.ts +1 -0
  261. package/Tests/Server/Utils/Monitor/MonitorIncidentResourceLinking.test.ts +88 -0
  262. package/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.ts +205 -0
  263. package/Tests/Server/Utils/Monitor/MonitorResourceContext.test.ts +62 -0
  264. package/Tests/Server/Utils/Monitor/MonitorResourceDatabaseMaintenance.test.ts +803 -0
  265. package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +133 -3
  266. package/Tests/Server/Utils/Monitor/MonitorSummaryPersistence.test.ts +1 -0
  267. package/Tests/Server/Utils/Monitor/PerSeriesRecoveryResolution.test.ts +472 -1
  268. package/Tests/Server/Utils/Monitor/PerSeriesSecondEntityAlerting.test.ts +1 -0
  269. package/Tests/Server/Utils/Monitor/SeriesResourceLinker.test.ts +236 -2
  270. package/Tests/Server/Utils/SeriesResourceLabels.test.ts +70 -0
  271. package/Tests/Server/Utils/SessionReplay/SessionReplayGateCachePolicy.test.ts +103 -0
  272. package/Tests/Server/Utils/StartServerProtobufContentType.test.ts +54 -0
  273. package/Tests/Server/Utils/Telemetry/DatabaseEndpointDiscovery.test.ts +1895 -0
  274. package/Tests/Server/Utils/Telemetry/EntityRegistry.test.ts +7 -0
  275. package/Tests/Server/Utils/Telemetry/LogExceptionExtractorSeverityGate.test.ts +90 -0
  276. package/Tests/Server/Utils/Telemetry/ResourceEntityFilter.test.ts +570 -0
  277. package/Tests/Server/Utils/Telemetry/ResourceFacetResolver.test.ts +97 -2
  278. package/Tests/Server/Utils/Telemetry/ServiceDependencyDiscovery.test.ts +1337 -0
  279. package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +295 -0
  280. package/Tests/Types/AI/AIResourceContext.test.ts +30 -0
  281. package/Tests/Types/DatabaseServer/DatabaseContainerClassifier.test.ts +3644 -0
  282. package/Tests/Types/DatabaseServer/DatabaseContainerCommand.test.ts +340 -0
  283. package/Tests/Types/DatabaseServer/DatabaseContainerCommandCorpus.ts +826 -0
  284. package/Tests/Types/DatabaseServer/DatabaseContainerCommandPostgres.test.ts +150 -0
  285. package/Tests/Types/DatabaseServer/DatabaseEndpoint.test.ts +2657 -0
  286. package/Tests/Types/DatabaseServer/DatabaseServerDiscoverySource.test.ts +64 -0
  287. package/Tests/Types/DatabaseServer/DatabaseServerEntityKeys.test.ts +952 -0
  288. package/Tests/Types/DatabaseServer/DatabaseServerMetricCatalog.test.ts +1161 -0
  289. package/Tests/Types/DatabaseServer/DatabaseSystem.test.ts +1514 -0
  290. package/Tests/Types/DatabaseServer/DatabaseTelemetryResolver.test.ts +1558 -0
  291. package/Tests/Types/Monitor/CephAlertTemplates.test.ts +255 -6
  292. package/Tests/Types/Monitor/DatabaseAlertTemplates.test.ts +2254 -0
  293. package/Tests/Types/Monitor/KubernetesAlertTemplates.test.ts +298 -0
  294. package/Tests/Types/Monitor/KubernetesMetricCatalog.test.ts +271 -0
  295. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +253 -9
  296. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +13 -5
  297. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +4 -2
  298. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +111 -2
  299. package/Tests/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.test.ts +61 -0
  300. package/Tests/Types/Monitor/SeriesContext/SeriesLabelDisplay.test.ts +114 -0
  301. package/Tests/Types/Monitor/Utils/KubernetesAgentEmittedMetrics.ts +181 -0
  302. package/Tests/Types/NetworkDevice/DiscoveredHostNamingStatus.test.ts +401 -0
  303. package/Tests/Types/Rum/WebVitals.test.ts +173 -0
  304. package/Tests/Types/Telemetry/ResourceEntityFacet.test.ts +4 -1
  305. package/Tests/Types/Telemetry/ResourceFacetCatalog.test.ts +24 -2
  306. package/Tests/UI/Components/Card.test.tsx +93 -2
  307. package/Tests/UI/Components/FeedOptions.test.ts +6 -0
  308. package/Tests/UI/Components/FeedOptionsButton.test.tsx +8 -1
  309. package/Tests/UI/Components/FieldLabelInfoCardTooltip.test.tsx +413 -0
  310. package/Tests/UI/Components/ForeignHiddenRuleResilience.test.tsx +1147 -0
  311. package/Tests/UI/Components/HeaderRightRail.test.tsx +41 -1
  312. package/Tests/UI/Components/InfoTooltip.test.tsx +242 -0
  313. package/Tests/UI/Components/LogsEntityNames.test.ts +16 -1
  314. package/Tests/UI/Components/LogsFacetSidebarHiddenFacets.test.tsx +7 -3
  315. package/Tests/UI/Components/ModelTable/BaseModelTableBulkDelete.test.tsx +207 -3
  316. package/Tests/UI/Components/ModelTable/BaseModelTableBulkDeleteVerb.test.tsx +367 -0
  317. package/Tests/UI/Components/ModelTable/BaseModelTableCreateButtonTitle.test.tsx +275 -0
  318. package/Tests/UI/Components/ResourceFacetConfigs.test.ts +2 -1
  319. package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
  320. package/Tests/UI/Components/SrOnlyForeignRule.test.tsx +994 -0
  321. package/Tests/UI/Components/StatusPage/ResourceListSelection.test.tsx +34 -1
  322. package/Tests/UI/Components/TableHeaderTooltip.test.tsx +662 -0
  323. package/Tests/UI/Components/TelemetryFacetSidebarHiddenFacets.test.tsx +4 -1
  324. package/Tests/UI/ForeignHiddenRuleGuard.test.ts +1951 -0
  325. package/Tests/UI/Rum/PrivacySummaryCard.test.tsx +166 -9
  326. package/Tests/UI/Rum/RecordingHealthTooltips.test.tsx +447 -0
  327. package/Tests/UI/Rum/ReplayCorrelationPanel.test.tsx +164 -0
  328. package/Tests/UI/Rum/ReplayFrameCapture.test.ts +6750 -0
  329. package/Tests/UI/Rum/ReplayPlayerChrome.test.tsx +19 -1
  330. package/Tests/UI/Rum/ReplayRail.test.tsx +723 -12
  331. package/Tests/UI/Rum/ReplayRailDetail.test.tsx +86 -0
  332. package/Tests/UI/Rum/ReplayScreenshot.test.ts +2124 -0
  333. package/Tests/UI/Rum/ReplayScreenshotActions.test.tsx +3288 -0
  334. package/Tests/UI/Rum/ReplayStage.test.tsx +62 -0
  335. package/Tests/UI/Rum/ReplayStageOverlays.test.tsx +983 -2
  336. package/Tests/UI/Rum/ReplayTabSwitcher.test.tsx +19 -1
  337. package/Tests/UI/Rum/SessionReplaySettingsPolicyLoading.test.tsx +149 -0
  338. package/Tests/UI/Rum/SessionReplaySetupGuide.test.tsx +107 -6
  339. package/Tests/UI/Rum/SessionReplayUsersTableTooltips.test.tsx +330 -0
  340. package/Tests/UI/Rum/UserFlowTooltips.test.tsx +886 -0
  341. package/Tests/UI/TailwindPlayCdnForeignHiddenRule.test.ts +1005 -0
  342. package/Tests/UI/ThemeGroupHoverReveal.test.ts +847 -0
  343. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +80 -0
  344. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +23 -0
  345. package/Tests/UI/Utils/ModelAPISsoRedirect.test.ts +127 -0
  346. package/Tests/UI/Utils/Navigation.test.ts +102 -0
  347. package/Tests/UI/Utils/PermissionGate.test.ts +76 -0
  348. package/Tests/UI/Utils/Telemetry/TelemetryEntityNames.test.ts +23 -0
  349. package/Tests/Utils/Incident/IncidentFromAlerts.test.ts +696 -0
  350. package/Tests/Utils/LabelRuleImportExport.test.ts +5 -0
  351. package/Tests/Utils/MetricUnitUtil.test.ts +227 -2
  352. package/Tests/Utils/Monitor/MetricValueFormatter.test.ts +288 -2
  353. package/Tests/Utils/Monitor/PlatformResourceIdentityAndUnits.test.ts +1559 -0
  354. package/Tests/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.test.ts +2546 -0
  355. package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +315 -0
  356. package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +336 -1
  357. package/Tests/Utils/NetworkDiscovery/NetbiosNameUtil.test.ts +244 -0
  358. package/Tests/Utils/Rum/SessionTraceState.test.ts +239 -0
  359. package/Tests/Utils/ValueFormatter.test.ts +50 -0
  360. package/Tests/tsconfig.json +16 -0
  361. package/Types/AI/AIResourceContext.ts +7 -0
  362. package/Types/Dashboard/DashboardTemplates.ts +2 -1
  363. package/Types/DatabaseServer/DatabaseConnectionSpan.ts +77 -0
  364. package/Types/DatabaseServer/DatabaseContainerClassifier.ts +2068 -0
  365. package/Types/DatabaseServer/DatabaseContainerCommand.ts +801 -0
  366. package/Types/DatabaseServer/DatabaseEndpoint.ts +1943 -0
  367. package/Types/DatabaseServer/DatabaseServerDiscoverySource.ts +68 -0
  368. package/Types/DatabaseServer/DatabaseServerMetricCatalog.ts +966 -0
  369. package/Types/DatabaseServer/DatabaseSystem.ts +2124 -0
  370. package/Types/DatabaseServer/DatabaseTelemetryResolver.ts +555 -0
  371. package/Types/Email/EmailTemplateType.ts +1 -0
  372. package/Types/Incident/IncidentAlertLink.ts +38 -0
  373. package/Types/Monitor/CephAlertTemplates.ts +18 -0
  374. package/Types/Monitor/DatabaseAlertTemplates.ts +2020 -0
  375. package/Types/Monitor/KubernetesAlertTemplates.ts +64 -24
  376. package/Types/Monitor/KubernetesMetricCatalog.ts +118 -19
  377. package/Types/Monitor/MetricMonitor/MetricCriteriaContext.ts +14 -0
  378. package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +93 -10
  379. package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +109 -8
  380. package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +36 -7
  381. package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +43 -2
  382. package/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.ts +41 -6
  383. package/Types/Monitor/SeriesContext/SeriesLabelDisplay.ts +26 -0
  384. package/Types/NetworkDevice/DiscoveredHostNamingStatus.ts +147 -0
  385. package/Types/Permission.ts +315 -0
  386. package/Types/Probe/ProbeApiIngestResponse.ts +8 -0
  387. package/Types/Rules/RuleCriteriaFieldRegistry.ts +10 -0
  388. package/Types/Rules/RuleRun.ts +12 -0
  389. package/Types/Rum/SessionReplay.ts +25 -6
  390. package/Types/Rum/WebVitals.ts +52 -0
  391. package/Types/Telemetry/EntityType.ts +23 -0
  392. package/Types/Telemetry/ResourceFacetCatalog.ts +14 -0
  393. package/Types/Telemetry/ServiceType.ts +8 -0
  394. package/UI/Components/Banner/Banner.tsx +1 -1
  395. package/UI/Components/Card/Card.tsx +1 -1
  396. package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +2 -2
  397. package/UI/Components/Charts/Line/LineChart.tsx +7 -0
  398. package/UI/Components/CommandPalette/CommandPalette.tsx +1 -1
  399. package/UI/Components/Date/StartAndEndDate.tsx +5 -5
  400. package/UI/Components/Detail/FieldLabel.tsx +8 -0
  401. package/UI/Components/Diagram/HorizontalStepChain.tsx +1 -1
  402. package/UI/Components/Feed/FeedOptionsButton.tsx +1 -1
  403. package/UI/Components/Forms/BasicForm.tsx +1 -1
  404. package/UI/Components/Header/Header.tsx +1 -1
  405. package/UI/Components/Header/HeaderIconDropdownButton.tsx +1 -1
  406. package/UI/Components/HeaderAlert/HeaderAlert.tsx +1 -1
  407. package/UI/Components/InfoCard/InfoCard.tsx +47 -1
  408. package/UI/Components/LogsViewer/components/FacetValueRow.tsx +1 -1
  409. package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +1 -1
  410. package/UI/Components/Modal/ModalFooter.tsx +1 -1
  411. package/UI/Components/ModelDetail/CardModelDetail.tsx +2 -2
  412. package/UI/Components/ModelTable/BaseModelTable.tsx +99 -21
  413. package/UI/Components/ModelTable/Column.ts +5 -0
  414. package/UI/Components/Navbar/NavBar.tsx +9 -2
  415. package/UI/Components/Navbar/NavBarMenuModal.tsx +2 -2
  416. package/UI/Components/Page/Page.tsx +1 -1
  417. package/UI/Components/Pagination/Pagination.tsx +3 -3
  418. package/UI/Components/ProgressButtons/ProgressButtonItem.tsx +1 -1
  419. package/UI/Components/SideMenu/SideMenu.tsx +4 -1
  420. package/UI/Components/StatusPage/ResourceGroupNavigator.tsx +4 -2
  421. package/UI/Components/StatusPage/ResourceList.tsx +6 -6
  422. package/UI/Components/Table/TableHeader.tsx +47 -2
  423. package/UI/Components/Table/Types/Column.ts +7 -0
  424. package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +1 -1
  425. package/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.tsx +1 -1
  426. package/UI/Components/Tooltip/InfoTooltip.tsx +78 -0
  427. package/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.tsx +1 -1
  428. package/UI/Components/Workflow/ComponentsModal.tsx +2 -2
  429. package/UI/Components/Workflow/StepTraceViewer.tsx +1 -1
  430. package/UI/Styles/Theme.css +8 -1
  431. package/UI/Utils/Navigation.ts +89 -42
  432. package/UI/Utils/PermissionGate.ts +11 -2
  433. package/UI/Utils/Telemetry/TelemetryEntityNames.ts +7 -0
  434. package/UI/Utils/TelemetryService.ts +4 -3
  435. package/Utils/Incident/IncidentFromAlerts.ts +516 -0
  436. package/Utils/LabelRuleImportExport.ts +2 -0
  437. package/Utils/MetricUnitUtil.ts +103 -11
  438. package/Utils/Monitor/MetricValueFormatter.ts +66 -13
  439. package/Utils/Monitor/PlatformMetricUnitUtil.ts +215 -0
  440. package/Utils/Monitor/PlatformResourceIdentity.ts +514 -0
  441. package/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.ts +425 -0
  442. package/Utils/NetworkDiscovery/DiscoveredHostUtil.ts +32 -0
  443. package/Utils/NetworkDiscovery/NetbiosNameUtil.ts +73 -0
  444. package/Utils/Rum/SessionTraceState.ts +212 -0
  445. package/Utils/Telemetry/DatabaseServerEntityKeys.ts +275 -0
  446. package/Utils/Telemetry/EntityKey.ts +176 -0
  447. package/Utils/ValueFormatter.ts +16 -0
  448. package/build/dist/Models/DatabaseModels/Alert.js +54 -0
  449. package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
  450. package/build/dist/Models/DatabaseModels/AlertFeed.js +2 -0
  451. package/build/dist/Models/DatabaseModels/AlertFeed.js.map +1 -1
  452. package/build/dist/Models/DatabaseModels/DatabaseServer.js +1683 -0
  453. package/build/dist/Models/DatabaseModels/DatabaseServer.js.map +1 -0
  454. package/build/dist/Models/DatabaseModels/DatabaseServerEndpoint.js +559 -0
  455. package/build/dist/Models/DatabaseModels/DatabaseServerEndpoint.js.map +1 -0
  456. package/build/dist/Models/DatabaseModels/DatabaseServerFeed.js +648 -0
  457. package/build/dist/Models/DatabaseModels/DatabaseServerFeed.js.map +1 -0
  458. package/build/dist/Models/DatabaseModels/DatabaseServerLabelRule.js +522 -0
  459. package/build/dist/Models/DatabaseModels/DatabaseServerLabelRule.js.map +1 -0
  460. package/build/dist/Models/DatabaseModels/DatabaseServerOwnerRule.js +603 -0
  461. package/build/dist/Models/DatabaseModels/DatabaseServerOwnerRule.js.map +1 -0
  462. package/build/dist/Models/DatabaseModels/DatabaseServerOwnerTeam.js +506 -0
  463. package/build/dist/Models/DatabaseModels/DatabaseServerOwnerTeam.js.map +1 -0
  464. package/build/dist/Models/DatabaseModels/DatabaseServerOwnerUser.js +505 -0
  465. package/build/dist/Models/DatabaseModels/DatabaseServerOwnerUser.js.map +1 -0
  466. package/build/dist/Models/DatabaseModels/Incident.js +54 -0
  467. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  468. package/build/dist/Models/DatabaseModels/IncidentAlert.js +553 -0
  469. package/build/dist/Models/DatabaseModels/IncidentAlert.js.map +1 -0
  470. package/build/dist/Models/DatabaseModels/IncidentFeed.js +2 -0
  471. package/build/dist/Models/DatabaseModels/IncidentFeed.js.map +1 -1
  472. package/build/dist/Models/DatabaseModels/Index.js +18 -0
  473. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  474. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
  475. package/build/dist/Models/DatabaseModels/Project.js +62 -0
  476. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  477. package/build/dist/Models/DatabaseModels/RumApplication.js +53 -1
  478. package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
  479. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +54 -0
  480. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
  481. package/build/dist/Models/DatabaseModels/TelemetryException.js +2 -0
  482. package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
  483. package/build/dist/Models/DatabaseModels/UserProjectSsoConsent.js +162 -0
  484. package/build/dist/Models/DatabaseModels/UserProjectSsoConsent.js.map +1 -0
  485. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794800000000-AddSessionReplaySameOriginTracePropagation.js +20 -0
  486. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794800000000-AddSessionReplaySameOriginTracePropagation.js.map +1 -0
  487. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794900000000-AddIncidentAlert.js +42 -0
  488. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794900000000-AddIncidentAlert.js.map +1 -0
  489. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795000000000-AddDatabaseServerTables.js +240 -0
  490. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795000000000-AddDatabaseServerTables.js.map +1 -0
  491. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795100000000-AddUserProjectSsoConsent.js +26 -0
  492. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795100000000-AddUserProjectSsoConsent.js.map +1 -0
  493. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  494. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  495. package/build/dist/Server/Middleware/MultipartFormData.js +1 -1
  496. package/build/dist/Server/Middleware/TelemetryIngest.js +15 -8
  497. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  498. package/build/dist/Server/Services/AlertReminderRuleService.js +72 -23
  499. package/build/dist/Server/Services/AlertReminderRuleService.js.map +1 -1
  500. package/build/dist/Server/Services/DatabaseServerEndpointService.js +694 -0
  501. package/build/dist/Server/Services/DatabaseServerEndpointService.js.map +1 -0
  502. package/build/dist/Server/Services/DatabaseServerFeedService.js +110 -0
  503. package/build/dist/Server/Services/DatabaseServerFeedService.js.map +1 -0
  504. package/build/dist/Server/Services/DatabaseServerLabelRuleEngineService.js +272 -0
  505. package/build/dist/Server/Services/DatabaseServerLabelRuleEngineService.js.map +1 -0
  506. package/build/dist/Server/Services/DatabaseServerLabelRuleService.js +13 -0
  507. package/build/dist/Server/Services/DatabaseServerLabelRuleService.js.map +1 -0
  508. package/build/dist/Server/Services/DatabaseServerOwnerRuleEngineService.js +340 -0
  509. package/build/dist/Server/Services/DatabaseServerOwnerRuleEngineService.js.map +1 -0
  510. package/build/dist/Server/Services/DatabaseServerOwnerRuleService.js +13 -0
  511. package/build/dist/Server/Services/DatabaseServerOwnerRuleService.js.map +1 -0
  512. package/build/dist/Server/Services/DatabaseServerOwnerTeamService.js +160 -0
  513. package/build/dist/Server/Services/DatabaseServerOwnerTeamService.js.map +1 -0
  514. package/build/dist/Server/Services/DatabaseServerOwnerUserService.js +153 -0
  515. package/build/dist/Server/Services/DatabaseServerOwnerUserService.js.map +1 -0
  516. package/build/dist/Server/Services/DatabaseServerService.js +3272 -0
  517. package/build/dist/Server/Services/DatabaseServerService.js.map +1 -0
  518. package/build/dist/Server/Services/DatabaseService.js +8 -4
  519. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  520. package/build/dist/Server/Services/DockerResourceService.js +30 -3
  521. package/build/dist/Server/Services/DockerResourceService.js.map +1 -1
  522. package/build/dist/Server/Services/IncidentAlertService.js +1370 -0
  523. package/build/dist/Server/Services/IncidentAlertService.js.map +1 -0
  524. package/build/dist/Server/Services/IncidentReminderRuleService.js +73 -23
  525. package/build/dist/Server/Services/IncidentReminderRuleService.js.map +1 -1
  526. package/build/dist/Server/Services/IncidentService.js +164 -12
  527. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  528. package/build/dist/Server/Services/IncidentStateTimelineService.js +21 -0
  529. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  530. package/build/dist/Server/Services/Index.js +18 -0
  531. package/build/dist/Server/Services/Index.js.map +1 -1
  532. package/build/dist/Server/Services/InventoryItemService.js +88 -5
  533. package/build/dist/Server/Services/InventoryItemService.js.map +1 -1
  534. package/build/dist/Server/Services/IoTDeviceService.js +111 -24
  535. package/build/dist/Server/Services/IoTDeviceService.js.map +1 -1
  536. package/build/dist/Server/Services/OpenTelemetryIngestService.js +24 -9
  537. package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
  538. package/build/dist/Server/Services/PodmanResourceService.js +30 -3
  539. package/build/dist/Server/Services/PodmanResourceService.js.map +1 -1
  540. package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js +75 -23
  541. package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js.map +1 -1
  542. package/build/dist/Server/Services/ServiceService.js +1 -1
  543. package/build/dist/Server/Services/ServiceService.js.map +1 -1
  544. package/build/dist/Server/Services/TelemetryUsageBillingService.js +23 -2
  545. package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
  546. package/build/dist/Server/Services/UserProjectSsoConsentService.js +79 -0
  547. package/build/dist/Server/Services/UserProjectSsoConsentService.js.map +1 -0
  548. package/build/dist/Server/Services/UserService.js +13 -1
  549. package/build/dist/Server/Services/UserService.js.map +1 -1
  550. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +18 -0
  551. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
  552. package/build/dist/Server/Types/Database/QueryHelper.js +26 -1
  553. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  554. package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js +46 -0
  555. package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js.map +1 -1
  556. package/build/dist/Server/Utils/Database/AffectedResourceRelations.js +6 -0
  557. package/build/dist/Server/Utils/Database/AffectedResourceRelations.js.map +1 -1
  558. package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +134 -13
  559. package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js.map +1 -1
  560. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +22 -6
  561. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  562. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +1489 -524
  563. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  564. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +22 -6
  565. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  566. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js +196 -6
  567. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -1
  568. package/build/dist/Server/Utils/Monitor/MonitorResource.js +36 -9
  569. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  570. package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js +1 -0
  571. package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js.map +1 -1
  572. package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js +175 -17
  573. package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js.map +1 -1
  574. package/build/dist/Server/Utils/Monitor/PerSeriesResolutionRootCause.js +29 -0
  575. package/build/dist/Server/Utils/Monitor/PerSeriesResolutionRootCause.js.map +1 -0
  576. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +211 -0
  577. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
  578. package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js +82 -10
  579. package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js.map +1 -1
  580. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +25 -0
  581. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
  582. package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js +8 -0
  583. package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js.map +1 -1
  584. package/build/dist/Server/Utils/StartServer.js +20 -4
  585. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  586. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js +2 -0
  587. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js.map +1 -1
  588. package/build/dist/Server/Utils/Telemetry/DatabaseEndpointDiscovery.js +442 -0
  589. package/build/dist/Server/Utils/Telemetry/DatabaseEndpointDiscovery.js.map +1 -0
  590. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +5 -1
  591. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  592. package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js +15 -1
  593. package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js.map +1 -1
  594. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +121 -5
  595. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -1
  596. package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js +12 -0
  597. package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js.map +1 -1
  598. package/build/dist/Server/Utils/Telemetry/ServiceDependencyDiscovery.js +438 -36
  599. package/build/dist/Server/Utils/Telemetry/ServiceDependencyDiscovery.js.map +1 -1
  600. package/build/dist/Server/Utils/Telemetry/Telemetry.js +12 -0
  601. package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
  602. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +17 -18
  603. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
  604. package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js +16 -10
  605. package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js.map +1 -1
  606. package/build/dist/Types/AI/AIResourceContext.js +7 -0
  607. package/build/dist/Types/AI/AIResourceContext.js.map +1 -1
  608. package/build/dist/Types/Dashboard/DashboardTemplates.js +2 -1
  609. package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
  610. package/build/dist/Types/DatabaseServer/DatabaseConnectionSpan.js +71 -0
  611. package/build/dist/Types/DatabaseServer/DatabaseConnectionSpan.js.map +1 -0
  612. package/build/dist/Types/DatabaseServer/DatabaseContainerClassifier.js +1462 -0
  613. package/build/dist/Types/DatabaseServer/DatabaseContainerClassifier.js.map +1 -0
  614. package/build/dist/Types/DatabaseServer/DatabaseContainerCommand.js +691 -0
  615. package/build/dist/Types/DatabaseServer/DatabaseContainerCommand.js.map +1 -0
  616. package/build/dist/Types/DatabaseServer/DatabaseEndpoint.js +1407 -0
  617. package/build/dist/Types/DatabaseServer/DatabaseEndpoint.js.map +1 -0
  618. package/build/dist/Types/DatabaseServer/DatabaseServerDiscoverySource.js +60 -0
  619. package/build/dist/Types/DatabaseServer/DatabaseServerDiscoverySource.js.map +1 -0
  620. package/build/dist/Types/DatabaseServer/DatabaseServerMetricCatalog.js +804 -0
  621. package/build/dist/Types/DatabaseServer/DatabaseServerMetricCatalog.js.map +1 -0
  622. package/build/dist/Types/DatabaseServer/DatabaseSystem.js +1860 -0
  623. package/build/dist/Types/DatabaseServer/DatabaseSystem.js.map +1 -0
  624. package/build/dist/Types/DatabaseServer/DatabaseTelemetryResolver.js +406 -0
  625. package/build/dist/Types/DatabaseServer/DatabaseTelemetryResolver.js.map +1 -0
  626. package/build/dist/Types/Email/EmailTemplateType.js +1 -0
  627. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  628. package/build/dist/Types/Incident/IncidentAlertLink.js +34 -0
  629. package/build/dist/Types/Incident/IncidentAlertLink.js.map +1 -0
  630. package/build/dist/Types/Monitor/CephAlertTemplates.js +18 -0
  631. package/build/dist/Types/Monitor/CephAlertTemplates.js.map +1 -1
  632. package/build/dist/Types/Monitor/DatabaseAlertTemplates.js +1518 -0
  633. package/build/dist/Types/Monitor/DatabaseAlertTemplates.js.map +1 -0
  634. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +57 -24
  635. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
  636. package/build/dist/Types/Monitor/KubernetesMetricCatalog.js +104 -18
  637. package/build/dist/Types/Monitor/KubernetesMetricCatalog.js.map +1 -1
  638. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +80 -3
  639. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -1
  640. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +10 -3
  641. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -1
  642. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +29 -0
  643. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -1
  644. package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js +21 -6
  645. package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js.map +1 -1
  646. package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js +25 -0
  647. package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js.map +1 -1
  648. package/build/dist/Types/NetworkDevice/DiscoveredHostNamingStatus.js +136 -0
  649. package/build/dist/Types/NetworkDevice/DiscoveredHostNamingStatus.js.map +1 -0
  650. package/build/dist/Types/Permission.js +276 -0
  651. package/build/dist/Types/Permission.js.map +1 -1
  652. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +10 -0
  653. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
  654. package/build/dist/Types/Rules/RuleRun.js +4 -0
  655. package/build/dist/Types/Rules/RuleRun.js.map +1 -1
  656. package/build/dist/Types/Rum/WebVitals.js +25 -0
  657. package/build/dist/Types/Rum/WebVitals.js.map +1 -1
  658. package/build/dist/Types/Telemetry/EntityType.js +23 -0
  659. package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
  660. package/build/dist/Types/Telemetry/ResourceFacetCatalog.js +14 -0
  661. package/build/dist/Types/Telemetry/ResourceFacetCatalog.js.map +1 -1
  662. package/build/dist/Types/Telemetry/ServiceType.js +8 -0
  663. package/build/dist/Types/Telemetry/ServiceType.js.map +1 -1
  664. package/build/dist/UI/Components/Banner/Banner.js +1 -1
  665. package/build/dist/UI/Components/Banner/Banner.js.map +1 -1
  666. package/build/dist/UI/Components/Card/Card.js +1 -1
  667. package/build/dist/UI/Components/Card/Card.js.map +1 -1
  668. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +2 -2
  669. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
  670. package/build/dist/UI/Components/Charts/Line/LineChart.js +1 -1
  671. package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
  672. package/build/dist/UI/Components/CommandPalette/CommandPalette.js +1 -1
  673. package/build/dist/UI/Components/CommandPalette/CommandPalette.js.map +1 -1
  674. package/build/dist/UI/Components/Date/StartAndEndDate.js +5 -5
  675. package/build/dist/UI/Components/Date/StartAndEndDate.js.map +1 -1
  676. package/build/dist/UI/Components/Detail/FieldLabel.js +2 -0
  677. package/build/dist/UI/Components/Detail/FieldLabel.js.map +1 -1
  678. package/build/dist/UI/Components/Diagram/HorizontalStepChain.js +1 -1
  679. package/build/dist/UI/Components/Diagram/HorizontalStepChain.js.map +1 -1
  680. package/build/dist/UI/Components/Feed/FeedOptionsButton.js +1 -1
  681. package/build/dist/UI/Components/Feed/FeedOptionsButton.js.map +1 -1
  682. package/build/dist/UI/Components/Forms/BasicForm.js +1 -1
  683. package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
  684. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +1 -1
  685. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
  686. package/build/dist/UI/Components/HeaderAlert/HeaderAlert.js +1 -1
  687. package/build/dist/UI/Components/HeaderAlert/HeaderAlert.js.map +1 -1
  688. package/build/dist/UI/Components/InfoCard/InfoCard.js +22 -1
  689. package/build/dist/UI/Components/InfoCard/InfoCard.js.map +1 -1
  690. package/build/dist/UI/Components/LogsViewer/components/FacetValueRow.js +1 -1
  691. package/build/dist/UI/Components/LogsViewer/components/FacetValueRow.js.map +1 -1
  692. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +1 -1
  693. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
  694. package/build/dist/UI/Components/Modal/ModalFooter.js +1 -1
  695. package/build/dist/UI/Components/Modal/ModalFooter.js.map +1 -1
  696. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +2 -2
  697. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
  698. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +70 -18
  699. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  700. package/build/dist/UI/Components/Navbar/NavBar.js +9 -2
  701. package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
  702. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +2 -2
  703. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
  704. package/build/dist/UI/Components/Page/Page.js +1 -1
  705. package/build/dist/UI/Components/Page/Page.js.map +1 -1
  706. package/build/dist/UI/Components/Pagination/Pagination.js +3 -3
  707. package/build/dist/UI/Components/Pagination/Pagination.js.map +1 -1
  708. package/build/dist/UI/Components/ProgressButtons/ProgressButtonItem.js +1 -1
  709. package/build/dist/UI/Components/ProgressButtons/ProgressButtonItem.js.map +1 -1
  710. package/build/dist/UI/Components/SideMenu/SideMenu.js +4 -1
  711. package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
  712. package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js +3 -1
  713. package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js.map +1 -1
  714. package/build/dist/UI/Components/StatusPage/ResourceList.js +6 -6
  715. package/build/dist/UI/Components/StatusPage/ResourceList.js.map +1 -1
  716. package/build/dist/UI/Components/Table/TableHeader.js +18 -2
  717. package/build/dist/UI/Components/Table/TableHeader.js.map +1 -1
  718. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +1 -1
  719. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
  720. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js +1 -1
  721. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js.map +1 -1
  722. package/build/dist/UI/Components/Tooltip/InfoTooltip.js +28 -0
  723. package/build/dist/UI/Components/Tooltip/InfoTooltip.js.map +1 -0
  724. package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js +1 -1
  725. package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js.map +1 -1
  726. package/build/dist/UI/Components/Workflow/ComponentsModal.js +2 -2
  727. package/build/dist/UI/Components/Workflow/ComponentsModal.js.map +1 -1
  728. package/build/dist/UI/Components/Workflow/StepTraceViewer.js +1 -1
  729. package/build/dist/UI/Components/Workflow/StepTraceViewer.js.map +1 -1
  730. package/build/dist/UI/Utils/Navigation.js +66 -33
  731. package/build/dist/UI/Utils/Navigation.js.map +1 -1
  732. package/build/dist/UI/Utils/PermissionGate.js +4 -2
  733. package/build/dist/UI/Utils/PermissionGate.js.map +1 -1
  734. package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js +7 -0
  735. package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js.map +1 -1
  736. package/build/dist/UI/Utils/TelemetryService.js +3 -2
  737. package/build/dist/UI/Utils/TelemetryService.js.map +1 -1
  738. package/build/dist/Utils/Incident/IncidentFromAlerts.js +306 -0
  739. package/build/dist/Utils/Incident/IncidentFromAlerts.js.map +1 -0
  740. package/build/dist/Utils/LabelRuleImportExport.js +2 -0
  741. package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
  742. package/build/dist/Utils/MetricUnitUtil.js +77 -13
  743. package/build/dist/Utils/MetricUnitUtil.js.map +1 -1
  744. package/build/dist/Utils/Monitor/MetricValueFormatter.js +58 -13
  745. package/build/dist/Utils/Monitor/MetricValueFormatter.js.map +1 -1
  746. package/build/dist/Utils/Monitor/PlatformMetricUnitUtil.js +161 -0
  747. package/build/dist/Utils/Monitor/PlatformMetricUnitUtil.js.map +1 -0
  748. package/build/dist/Utils/Monitor/PlatformResourceIdentity.js +323 -0
  749. package/build/dist/Utils/Monitor/PlatformResourceIdentity.js.map +1 -0
  750. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.js +270 -0
  751. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.js.map +1 -0
  752. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js +23 -0
  753. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js.map +1 -1
  754. package/build/dist/Utils/NetworkDiscovery/NetbiosNameUtil.js +61 -0
  755. package/build/dist/Utils/NetworkDiscovery/NetbiosNameUtil.js.map +1 -1
  756. package/build/dist/Utils/Rum/SessionTraceState.js +154 -0
  757. package/build/dist/Utils/Rum/SessionTraceState.js.map +1 -0
  758. package/build/dist/Utils/Telemetry/DatabaseServerEntityKeys.js +178 -0
  759. package/build/dist/Utils/Telemetry/DatabaseServerEntityKeys.js.map +1 -0
  760. package/build/dist/Utils/Telemetry/EntityKey.js +133 -0
  761. package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -1
  762. package/build/dist/Utils/ValueFormatter.js +15 -0
  763. package/build/dist/Utils/ValueFormatter.js.map +1 -1
  764. package/package.json +1 -1
  765. package/tsconfig.tests.json +7 -5
@@ -0,0 +1,1462 @@
1
+ import { DATABASE_SYSTEMS, getDatabaseSystemDescriptor, getDatabaseSystemFamily, getDefaultDatabasePort, getMoreSpecificDatabaseSystem, isSameDatabaseFamily, } from "./DatabaseSystem";
2
+ import { isNonServerCommand } from "./DatabaseContainerCommand";
3
+ /*
4
+ * What a Docker / Podman database's workload is: the Swarm service or the
5
+ * Compose service its replicas were grouped by, else a container of its own.
6
+ * Stored as the database's workloadKind and read back as written ("detected
7
+ * from Compose service shop-db", "Swarm service/mystack_db").
8
+ */
9
+ export var ContainerWorkloadKind;
10
+ (function (ContainerWorkloadKind) {
11
+ ContainerWorkloadKind["Container"] = "Container";
12
+ ContainerWorkloadKind["ComposeService"] = "Compose service";
13
+ ContainerWorkloadKind["SwarmService"] = "Swarm service";
14
+ })(ContainerWorkloadKind || (ContainerWorkloadKind = {}));
15
+ /*
16
+ * Same matching rule as DatabaseSystemDescriptor.imageRepositories: an entry
17
+ * without "/" is an exact basename, an entry with one is an exact path (or
18
+ * a path suffix at a "/" boundary, for registry mirrors).
19
+ */
20
+ const EXCLUDED_IMAGE_GROUPS = [
21
+ {
22
+ reason: "exporter",
23
+ repositories: [
24
+ "postgres-exporter",
25
+ "postgres_exporter",
26
+ "redis_exporter",
27
+ "mysqld-exporter",
28
+ "mongodb_exporter",
29
+ "elasticsearch-exporter",
30
+ "memcached-exporter",
31
+ ],
32
+ },
33
+ {
34
+ reason: "operator",
35
+ repositories: [
36
+ "cloudnative-pg/cloudnative-pg",
37
+ "zalando/postgres-operator",
38
+ "acid/postgres-operator",
39
+ "crunchydata/postgres-operator",
40
+ "mongodb/mongodb-kubernetes",
41
+ "eck/eck-operator",
42
+ ],
43
+ },
44
+ {
45
+ reason: "admin-ui",
46
+ repositories: [
47
+ "dpage/pgadmin4",
48
+ "pgadmin4",
49
+ "phpmyadmin",
50
+ "adminer",
51
+ "mongo-express",
52
+ "redisinsight",
53
+ "redis-commander",
54
+ "kibana",
55
+ "opensearch-dashboards",
56
+ "cerebro",
57
+ ],
58
+ },
59
+ {
60
+ reason: "pooler",
61
+ repositories: [
62
+ "pgbouncer",
63
+ "crunchydata/crunchy-pgbouncer",
64
+ "pgpool",
65
+ "pgpool2",
66
+ "pgcat",
67
+ "odyssey",
68
+ "supavisor",
69
+ "proxysql",
70
+ "proxysql2",
71
+ "haproxy",
72
+ "mysql-router",
73
+ "twemproxy",
74
+ "gce-proxy",
75
+ "cloud-sql-proxy",
76
+ ],
77
+ },
78
+ {
79
+ reason: "backup",
80
+ repositories: [
81
+ "pgbackrest",
82
+ "crunchydata/crunchy-pgbackrest",
83
+ "barman",
84
+ "wal-g",
85
+ "kubectl",
86
+ "percona-xtrabackup",
87
+ "percona-backup-mongodb",
88
+ "mydumper",
89
+ "postgres-backup-local",
90
+ "postgres-backup-s3",
91
+ "mysql-backup",
92
+ "db-backup",
93
+ ],
94
+ },
95
+ {
96
+ // Part of a database deployment, but not the database process itself.
97
+ reason: "companion",
98
+ repositories: [
99
+ "redis-sentinel",
100
+ "mongodb-agent",
101
+ "mongodb-agent-ubi",
102
+ "k8ssandra/system-logger",
103
+ ],
104
+ },
105
+ ];
106
+ // Basename suffixes that are never a database, whatever comes before them.
107
+ const EXCLUDED_BASENAME_SUFFIXES = [
108
+ { reason: "exporter", suffix: "-exporter" },
109
+ { reason: "exporter", suffix: "_exporter" },
110
+ { reason: "operator", suffix: "-operator" },
111
+ ];
112
+ // Mesh proxies, log shippers, VPN / tunnel and monitoring agents that sit next to anything.
113
+ const INFRASTRUCTURE_SIDECAR_REPOSITORIES = [
114
+ "proxyv2",
115
+ "linkerd/proxy",
116
+ "linkerd2-proxy",
117
+ "envoy",
118
+ "envoyproxy/envoy",
119
+ "aws-appmesh-envoy",
120
+ "hashicorp/vault",
121
+ "hashicorp/consul-dataplane",
122
+ "fluent-bit",
123
+ "fluentd",
124
+ "filebeat",
125
+ "promtail",
126
+ "opentelemetry-collector",
127
+ "opentelemetry-collector-contrib",
128
+ "opentelemetry-collector-k8s",
129
+ "splunk-otel-collector",
130
+ "busybox",
131
+ "cadvisor",
132
+ "datadog/agent",
133
+ "datadoghq/agent",
134
+ "grafana/agent",
135
+ "grafana/alloy",
136
+ "timberio/vector",
137
+ "vectordotdev/vector",
138
+ "jaeger-agent",
139
+ "pmm-client",
140
+ "aws-xray-daemon",
141
+ "daprd",
142
+ "kuma-dp",
143
+ "tailscale/tailscale",
144
+ "cloudflare/cloudflared",
145
+ "bitnami/os-shell",
146
+ "pause",
147
+ ];
148
+ /*
149
+ * Anchored basename patterns for images whose name carries a version, so no
150
+ * finite exact list covers them (Zalando Spilo: `spilo-15`, `spilo-16`).
151
+ * Still whole-basename matches, never substrings.
152
+ */
153
+ const DATABASE_BASENAME_PATTERNS = [{ system: "postgresql", pattern: /^spilo(?:-\d+)?$/ }];
154
+ const IMAGE_REPOSITORY_REGEX = /^[a-z0-9._/-]+$/;
155
+ // A bare image id (untagged docker_stats image) names no repository.
156
+ const BARE_IMAGE_ID_REGEX = /^(?:sha256:)?[0-9a-f]{12,64}$/;
157
+ /*
158
+ * Organisations that republish another organisation's images unchanged:
159
+ * Bitnami's catalogue moved to `bitnamilegacy/` (frozen tags) and
160
+ * `bitnamisecure/` (hardened builds), under every registry that mirrors it
161
+ * (`docker.io/`, `public.ecr.aws/`, a Harbor proxy …).
162
+ */
163
+ const IMAGE_ORGANIZATION_ALIASES = new Map([
164
+ ["bitnamilegacy", "bitnami"],
165
+ ["bitnamisecure", "bitnami"],
166
+ ]);
167
+ /*
168
+ * Red Hat Software Collections put the engine AND its version in the image
169
+ * name and the image build in the tag: `registry.redhat.io/rhel9/postgresql-16:1-54`,
170
+ * `quay.io/sclorg/mysql-80-c9s`, `centos/postgresql-96-centos7`. Recognised
171
+ * only under these namespaces, so `bitnami/postgresql-repmgr` or an
172
+ * application called `api-2` keeps its name.
173
+ */
174
+ const SOFTWARE_COLLECTION_NAMESPACE_REGEX = /^(?:rhel\d*|rhscl|sclorg|centos\d*|fedora)$/;
175
+ const SOFTWARE_COLLECTION_PLATFORM_REGEX = /^(?:rhel\d+|el\d+|centos\d+|c\d+s|ubi\d+|fedora)$/;
176
+ const SOFTWARE_COLLECTION_VERSION_REGEX = /^\d{1,4}$/;
177
+ const SOFTWARE_COLLECTION_ENGINE_REGEX = /^[a-z][a-z0-9]*$/;
178
+ // Red Hat UBI rebuilds carry a `-ubi` / `-ubi8` basename suffix.
179
+ const UBI_BASENAME_SUFFIX_REGEX = /-ubi\d*$/;
180
+ /*
181
+ * Version sources in an image reference: a Spilo image name carries the
182
+ * PostgreSQL major, a Percona tag carries "ppg<version>", any other tag
183
+ * starts with it.
184
+ */
185
+ const SPILO_IMAGE_REGEX = /^spilo-(\d+)$/;
186
+ const PERCONA_POSTGRESQL_TAG_REGEX = /(?:^|-)ppg(\d+(?:\.\d+)?)(?:-|$)/;
187
+ const IMAGE_TAG_VERSION_REGEX = /^v?(\d+(?:\.\d+){0,2})/;
188
+ /*
189
+ * `rhel9/postgresql-16` → { engine "postgresql", digits "16" }; null for any
190
+ * basename that is not `<engine>-<1-4 digits>[-<platform>]`.
191
+ */
192
+ function parseSoftwareCollectionBasename(basename) {
193
+ const parts = basename.split("-");
194
+ if (parts.length > 2 &&
195
+ SOFTWARE_COLLECTION_PLATFORM_REGEX.test(parts[parts.length - 1])) {
196
+ parts.pop();
197
+ }
198
+ if (parts.length !== 2) {
199
+ return null;
200
+ }
201
+ const engine = parts[0];
202
+ const digits = parts[1];
203
+ if (!SOFTWARE_COLLECTION_ENGINE_REGEX.test(engine) ||
204
+ !SOFTWARE_COLLECTION_VERSION_REGEX.test(digits)) {
205
+ return null;
206
+ }
207
+ return { engine, digits };
208
+ }
209
+ /*
210
+ * Software Collections spell versions without the dot: `postgresql-96` is
211
+ * 9.6 but `postgresql-16` is 16, `mysql-80` is 8.0, `mariadb-105` 10.5 and
212
+ * `mariadb-1011` 10.11.
213
+ */
214
+ function formatSoftwareCollectionVersion(engine, digits) {
215
+ if (engine === "postgresql") {
216
+ return digits.length === 2 && digits.startsWith("9")
217
+ ? `9.${digits.substring(1)}`
218
+ : digits;
219
+ }
220
+ if (digits.length === 2) {
221
+ return `${digits.substring(0, 1)}.${digits.substring(1)}`;
222
+ }
223
+ if (digits.length === 3) {
224
+ return `${digits.substring(0, 2)}.${digits.substring(2)}`;
225
+ }
226
+ if (digits.length === 4) {
227
+ return `${digits.substring(0, 2)}.${digits.substring(2)}`;
228
+ }
229
+ return digits;
230
+ }
231
+ function splitImageReference(image) {
232
+ if (typeof image !== "string") {
233
+ return null;
234
+ }
235
+ let value = image.trim().toLowerCase();
236
+ if (!value || BARE_IMAGE_ID_REGEX.test(value)) {
237
+ return null;
238
+ }
239
+ const digestIndex = value.indexOf("@");
240
+ if (digestIndex >= 0) {
241
+ value = value.substring(0, digestIndex);
242
+ }
243
+ let tag = null;
244
+ const tagIndex = value.lastIndexOf(":");
245
+ if (tagIndex > value.lastIndexOf("/")) {
246
+ tag = value.substring(tagIndex + 1) || null;
247
+ value = value.substring(0, tagIndex);
248
+ }
249
+ const segments = value
250
+ .split("/")
251
+ .filter((segment) => {
252
+ return segment.length > 0;
253
+ });
254
+ // Registry host: the first segment when it has a "." or ":" or is localhost.
255
+ if (segments.length > 1 &&
256
+ (segments[0].includes(".") ||
257
+ segments[0].includes(":") ||
258
+ segments[0] === "localhost")) {
259
+ segments.shift();
260
+ }
261
+ if (segments.length > 1 && segments[0] === "library") {
262
+ segments.shift();
263
+ }
264
+ // Republishing organisations → the original (never the basename itself).
265
+ for (let index = 0; index < segments.length - 1; index++) {
266
+ const alias = IMAGE_ORGANIZATION_ALIASES.get(segments[index]);
267
+ if (alias) {
268
+ segments[index] = alias;
269
+ }
270
+ }
271
+ let nameVersion = null;
272
+ const lastIndex = segments.length - 1;
273
+ if (lastIndex >= 0) {
274
+ let basename = segments[lastIndex];
275
+ const withoutUbi = basename.replace(UBI_BASENAME_SUFFIX_REGEX, "");
276
+ if (withoutUbi && withoutUbi !== basename) {
277
+ basename = withoutUbi;
278
+ }
279
+ if (lastIndex >= 1 &&
280
+ SOFTWARE_COLLECTION_NAMESPACE_REGEX.test(segments[lastIndex - 1])) {
281
+ const collection = parseSoftwareCollectionBasename(basename);
282
+ if (collection) {
283
+ basename = collection.engine;
284
+ nameVersion = formatSoftwareCollectionVersion(collection.engine, collection.digits);
285
+ }
286
+ }
287
+ segments[lastIndex] = basename;
288
+ }
289
+ const repository = segments.join("/");
290
+ if (!repository || !IMAGE_REPOSITORY_REGEX.test(repository)) {
291
+ return null;
292
+ }
293
+ return { repository, tag, nameVersion };
294
+ }
295
+ function basenameOf(repository) {
296
+ return repository.substring(repository.lastIndexOf("/") + 1);
297
+ }
298
+ function repositoryMatches(repository, entry) {
299
+ if (entry.includes("/")) {
300
+ return repository === entry || repository.endsWith(`/${entry}`);
301
+ }
302
+ return basenameOf(repository) === entry;
303
+ }
304
+ function matchesAny(repository, entries) {
305
+ for (const entry of entries) {
306
+ if (repositoryMatches(repository, entry)) {
307
+ return true;
308
+ }
309
+ }
310
+ return false;
311
+ }
312
+ /**
313
+ * The image's repository path without registry host, `library/`, tag or
314
+ * digest, lowercased: `docker.io/library/postgres:16` → `postgres`,
315
+ * `ghcr.io/cloudnative-pg/postgresql:16.2@sha256:…` →
316
+ * `cloudnative-pg/postgresql`. Republished images read as the original
317
+ * (`bitnamilegacy/redis-cluster` → `bitnami/redis-cluster`), a Red Hat
318
+ * Software Collections name loses its version and platform
319
+ * (`registry.redhat.io/rhel9/postgresql-16` → `rhel9/postgresql`) and a UBI
320
+ * rebuild its `-ubi` suffix. Null for an empty value or a bare image id.
321
+ */
322
+ export function normalizeImageRepository(image) {
323
+ const split = splitImageReference(image);
324
+ return split ? split.repository : null;
325
+ }
326
+ /**
327
+ * Best-effort engine version from the image: the leading
328
+ * `major[.minor[.patch]]` of the tag (`16.2-alpine` → `16.2`,
329
+ * `16.2.0-debian-12-r5` → `16.2.0`), the Postgres major of a Spilo image
330
+ * (`spilo-16` → `16`) or of a Percona `…-ppg16-postgres` tag, and the
331
+ * version in a Software Collections name (`rhel9/mysql-80` → `8.0`; its tag
332
+ * is the image build, never read). Null for `latest`, a digest-only
333
+ * reference or a tag that does not start with a number.
334
+ */
335
+ export function parseImageVersion(image) {
336
+ const split = splitImageReference(image);
337
+ if (!split) {
338
+ return null;
339
+ }
340
+ if (split.nameVersion) {
341
+ return split.nameVersion;
342
+ }
343
+ const spilo = SPILO_IMAGE_REGEX.exec(basenameOf(split.repository));
344
+ if (spilo) {
345
+ return spilo[1];
346
+ }
347
+ if (!split.tag) {
348
+ return null;
349
+ }
350
+ const percona = PERCONA_POSTGRESQL_TAG_REGEX.exec(split.tag);
351
+ if (percona) {
352
+ return percona[1];
353
+ }
354
+ const version = IMAGE_TAG_VERSION_REGEX.exec(split.tag);
355
+ return version ? version[1] : null;
356
+ }
357
+ /**
358
+ * What a container image is: a known database engine, something that must
359
+ * not count as one (with the reason), an infrastructure sidecar, or unknown.
360
+ */
361
+ export function classifyImage(image) {
362
+ const repository = normalizeImageRepository(image);
363
+ if (!repository) {
364
+ return { kind: "unknown" };
365
+ }
366
+ for (const group of EXCLUDED_IMAGE_GROUPS) {
367
+ if (matchesAny(repository, group.repositories)) {
368
+ return { kind: "excluded", reason: group.reason };
369
+ }
370
+ }
371
+ const basename = basenameOf(repository);
372
+ for (const excluded of EXCLUDED_BASENAME_SUFFIXES) {
373
+ if (basename.endsWith(excluded.suffix)) {
374
+ return { kind: "excluded", reason: excluded.reason };
375
+ }
376
+ }
377
+ if (matchesAny(repository, INFRASTRUCTURE_SIDECAR_REPOSITORIES)) {
378
+ return { kind: "infrastructure-sidecar" };
379
+ }
380
+ for (const descriptor of DATABASE_SYSTEMS) {
381
+ if (matchesAny(repository, descriptor.imageRepositories)) {
382
+ return { kind: "database", system: descriptor.system };
383
+ }
384
+ }
385
+ for (const entry of DATABASE_BASENAME_PATTERNS) {
386
+ if (entry.pattern.test(basename)) {
387
+ return { kind: "database", system: entry.system };
388
+ }
389
+ }
390
+ return { kind: "unknown" };
391
+ }
392
+ const SKIPPED_POD_PHASES = new Set([
393
+ "succeeded",
394
+ "failed",
395
+ ]);
396
+ const BATCH_OWNER_KINDS = new Set([
397
+ "job",
398
+ "cronjob",
399
+ ]);
400
+ // Owner kinds whose name conventionally is also a Service's name.
401
+ const SERVICE_NAMED_OWNER_KINDS = new Set([
402
+ "StatefulSet",
403
+ "Deployment",
404
+ "DaemonSet",
405
+ ]);
406
+ /*
407
+ * `app.kubernetes.io/component` values of pods that carry a database's
408
+ * cluster/chart labels but are not a database member: poolers, proxies,
409
+ * routers, exporters, orchestrators, backup and monitoring pods.
410
+ */
411
+ const NON_MEMBER_COMPONENTS = new Set([
412
+ "pgpool",
413
+ "pgbouncer",
414
+ "proxysql",
415
+ "haproxy",
416
+ "mongos",
417
+ "metrics",
418
+ "exporter",
419
+ "router",
420
+ "mysqlrouter",
421
+ "orc",
422
+ "orchestrator",
423
+ "backup",
424
+ "pmm",
425
+ ]);
426
+ /*
427
+ * Exclusion reasons that make a pod a non-member on their own. "operator"
428
+ * and "companion" are deliberately absent: Percona's PostgreSQL operator
429
+ * ships its postgres operand in the operator's image repository, and a
430
+ * Sentinel / agent container never runs alone in a member pod anyway.
431
+ */
432
+ const NON_MEMBER_IMAGE_REASONS = new Set([
433
+ "pooler",
434
+ "exporter",
435
+ "admin-ui",
436
+ "backup",
437
+ ]);
438
+ /*
439
+ * False for a container whose image is never the database process itself:
440
+ * a mesh proxy / log shipper, or an image excluded as a pooler, exporter,
441
+ * admin UI, backup tool or companion (Sentinel, agent). An "operator" image
442
+ * still could be — Percona ships its postgres operand in one.
443
+ */
444
+ function couldBeDatabaseProcess(container) {
445
+ const classification = container.classification;
446
+ if (classification.kind === "infrastructure-sidecar") {
447
+ return false;
448
+ }
449
+ return !(classification.kind === "excluded" &&
450
+ (NON_MEMBER_IMAGE_REASONS.has(classification.reason) ||
451
+ classification.reason === "companion"));
452
+ }
453
+ const PRIMARY_ROLE_VALUES = new Set([
454
+ "primary",
455
+ "master",
456
+ ]);
457
+ const REPLICA_ROLE_VALUES = new Set([
458
+ "replica",
459
+ "replicas",
460
+ "read",
461
+ "secondary",
462
+ "slave",
463
+ "standby",
464
+ ]);
465
+ function labelValue(labels, key) {
466
+ if (!Object.prototype.hasOwnProperty.call(labels, key)) {
467
+ return null;
468
+ }
469
+ const value = labels[key];
470
+ if (typeof value === "string") {
471
+ const trimmed = value.trim();
472
+ return trimmed.length > 0 ? trimmed : null;
473
+ }
474
+ if (typeof value === "number" || typeof value === "boolean") {
475
+ return String(value);
476
+ }
477
+ return null;
478
+ }
479
+ function hasLabel(labels, key) {
480
+ return Object.prototype.hasOwnProperty.call(labels, key);
481
+ }
482
+ function roleFrom(value) {
483
+ if (!value) {
484
+ return null;
485
+ }
486
+ const normalized = value.trim().toLowerCase();
487
+ if (PRIMARY_ROLE_VALUES.has(normalized)) {
488
+ return "primary";
489
+ }
490
+ if (REPLICA_ROLE_VALUES.has(normalized)) {
491
+ return "replica";
492
+ }
493
+ return null;
494
+ }
495
+ const CHART_SYSTEM_BY_NAME = (() => {
496
+ const map = new Map();
497
+ for (const descriptor of DATABASE_SYSTEMS) {
498
+ for (const chartName of descriptor.kubernetesChartNames) {
499
+ // Labels are compared lowercased.
500
+ map.set(chartName.toLowerCase(), descriptor.system);
501
+ }
502
+ }
503
+ return map;
504
+ })();
505
+ const PERCONA_SYSTEM_BY_NAME = new Map([
506
+ ["percona-xtradb-cluster", "mysql"],
507
+ ["percona-server", "mysql"],
508
+ ["percona-server-mongodb", "mongodb"],
509
+ ]);
510
+ /**
511
+ * Label keys whose presence makes an operator rule look at a pod. With
512
+ * DATABASE_WORKLOAD_NAME_LABEL_VALUES this is the whole trigger surface of
513
+ * the label rules, so a store can pre-select the pods worth classifying
514
+ * (`labels ?| keys OR lower(labels->>'app.kubernetes.io/name') = ANY(values)`)
515
+ * — see hasDatabaseWorkloadLabels, which is the same test in TypeScript.
516
+ */
517
+ export const DATABASE_OPERATOR_LABEL_KEYS = [
518
+ "cnpg.io/cluster",
519
+ "cluster-name",
520
+ "postgres-operator.crunchydata.com/cluster",
521
+ "mysql.oracle.com/cluster",
522
+ "elasticsearch.k8s.elastic.co/cluster-name",
523
+ "clickhouse.altinity.com/chi",
524
+ "cassandra.datastax.com/cluster",
525
+ "planetscale.com/cluster",
526
+ ];
527
+ // Lowercase `app.kubernetes.io/name` values a chart / Percona rule matches.
528
+ export const DATABASE_WORKLOAD_NAME_LABEL_VALUES = Array.from(new Set([
529
+ ...Array.from(CHART_SYSTEM_BY_NAME.keys()),
530
+ ...Array.from(PERCONA_SYSTEM_BY_NAME.keys()),
531
+ ])).sort();
532
+ /**
533
+ * True when a pod's labels could make an operator / chart rule match — the
534
+ * TypeScript twin of the store-side pre-filter over
535
+ * DATABASE_OPERATOR_LABEL_KEYS and DATABASE_WORKLOAD_NAME_LABEL_VALUES.
536
+ */
537
+ export function hasDatabaseWorkloadLabels(labels) {
538
+ if (!labels || typeof labels !== "object" || Array.isArray(labels)) {
539
+ return false;
540
+ }
541
+ const record = labels;
542
+ for (const key of DATABASE_OPERATOR_LABEL_KEYS) {
543
+ if (hasLabel(record, key)) {
544
+ return true;
545
+ }
546
+ }
547
+ const name = labelValue(record, "app.kubernetes.io/name");
548
+ return (name !== null &&
549
+ DATABASE_WORKLOAD_NAME_LABEL_VALUES.includes(name.toLowerCase()));
550
+ }
551
+ /*
552
+ * Operator / chart label rules, most specific first. Each returns a match,
553
+ * "skip" (the pod belongs to a database cluster but is not a member — a
554
+ * pooler, a backup repo host), or null (not this operator). Label keys and
555
+ * Service naming follow each operator's documented conventions, including
556
+ * the proxy / pooler Services clients usually connect through.
557
+ */
558
+ const OPERATOR_RULES = [
559
+ // CloudNativePG.
560
+ (labels) => {
561
+ const cluster = labelValue(labels, "cnpg.io/cluster");
562
+ if (!cluster) {
563
+ return null;
564
+ }
565
+ const podRole = labelValue(labels, "cnpg.io/podRole");
566
+ if ((podRole && podRole.toLowerCase() !== "instance") ||
567
+ labelValue(labels, "cnpg.io/poolerName")) {
568
+ return "skip";
569
+ }
570
+ return {
571
+ operator: "cloudnative-pg",
572
+ system: "postgresql",
573
+ clusterName: cluster,
574
+ role: roleFrom(labelValue(labels, "cnpg.io/instanceRole") ||
575
+ labelValue(labels, "role")),
576
+ serviceNames: [`${cluster}-rw`, `${cluster}-ro`, `${cluster}-r`],
577
+ evidence: `label:cnpg.io/cluster=${cluster}`,
578
+ };
579
+ },
580
+ // Zalando postgres-operator (Spilo).
581
+ (labels) => {
582
+ const application = labelValue(labels, "application");
583
+ const cluster = labelValue(labels, "cluster-name");
584
+ if (!application || application.toLowerCase() !== "spilo" || !cluster) {
585
+ return null;
586
+ }
587
+ return {
588
+ operator: "zalando",
589
+ system: "postgresql",
590
+ clusterName: cluster,
591
+ role: roleFrom(labelValue(labels, "spilo-role")),
592
+ serviceNames: [
593
+ cluster,
594
+ `${cluster}-repl`,
595
+ `${cluster}-pooler`,
596
+ `${cluster}-pooler-repl`,
597
+ ],
598
+ evidence: `label:cluster-name=${cluster}`,
599
+ };
600
+ },
601
+ // Crunchy Data PGO v5 (also Percona's PostgreSQL operator v2, a fork).
602
+ (labels) => {
603
+ const cluster = labelValue(labels, "postgres-operator.crunchydata.com/cluster");
604
+ if (!cluster) {
605
+ return null;
606
+ }
607
+ const role = labelValue(labels, "postgres-operator.crunchydata.com/role");
608
+ if ((role && ["pgbouncer", "pgadmin"].includes(role.toLowerCase())) ||
609
+ hasLabel(labels, "postgres-operator.crunchydata.com/pgbackrest-dedicated") ||
610
+ hasLabel(labels, "postgres-operator.crunchydata.com/pgadmin")) {
611
+ return "skip";
612
+ }
613
+ return {
614
+ operator: "crunchy",
615
+ system: "postgresql",
616
+ clusterName: cluster,
617
+ role: roleFrom(role),
618
+ serviceNames: [
619
+ `${cluster}-primary`,
620
+ `${cluster}-replicas`,
621
+ `${cluster}-ha`,
622
+ `${cluster}-pgbouncer`,
623
+ ],
624
+ evidence: `label:postgres-operator.crunchydata.com/cluster=${cluster}`,
625
+ };
626
+ },
627
+ // Percona XtraDB Cluster / Server for MySQL / Server for MongoDB operators.
628
+ (labels) => {
629
+ const managedBy = labelValue(labels, "app.kubernetes.io/managed-by");
630
+ const name = labelValue(labels, "app.kubernetes.io/name");
631
+ const instance = labelValue(labels, "app.kubernetes.io/instance");
632
+ if (!managedBy ||
633
+ !managedBy.toLowerCase().startsWith("percona-") ||
634
+ !name ||
635
+ !instance) {
636
+ return null;
637
+ }
638
+ const system = PERCONA_SYSTEM_BY_NAME.get(name.toLowerCase());
639
+ if (!system) {
640
+ return null;
641
+ }
642
+ const serviceNames = [];
643
+ const normalizedName = name.toLowerCase();
644
+ if (normalizedName === "percona-xtradb-cluster") {
645
+ serviceNames.push(`${instance}-pxc`, `${instance}-haproxy`, `${instance}-haproxy-replicas`, `${instance}-proxysql`);
646
+ }
647
+ else if (normalizedName === "percona-server") {
648
+ serviceNames.push(`${instance}-mysql`, `${instance}-mysql-primary`, `${instance}-haproxy`, `${instance}-router`);
649
+ }
650
+ else {
651
+ const replicaSet = labelValue(labels, "app.kubernetes.io/replset");
652
+ if (replicaSet) {
653
+ serviceNames.push(`${instance}-${replicaSet}`);
654
+ }
655
+ serviceNames.push(`${instance}-mongos`);
656
+ }
657
+ return {
658
+ operator: "percona",
659
+ system,
660
+ clusterName: instance,
661
+ role: null,
662
+ serviceNames,
663
+ evidence: `label:app.kubernetes.io/name=${name}`,
664
+ };
665
+ },
666
+ // Oracle MySQL Operator (InnoDB Cluster).
667
+ (labels) => {
668
+ const cluster = labelValue(labels, "mysql.oracle.com/cluster");
669
+ if (!cluster) {
670
+ return null;
671
+ }
672
+ const component = labelValue(labels, "component");
673
+ if (component && NON_MEMBER_COMPONENTS.has(component.toLowerCase())) {
674
+ return "skip";
675
+ }
676
+ const clusterRole = labelValue(labels, "mysql.oracle.com/cluster-role");
677
+ return {
678
+ operator: "mysql-operator",
679
+ system: "mysql",
680
+ clusterName: cluster,
681
+ role: roleFrom(clusterRole),
682
+ serviceNames: [`${cluster}-instances`],
683
+ evidence: `label:mysql.oracle.com/cluster=${cluster}`,
684
+ };
685
+ },
686
+ // Elastic Cloud on Kubernetes.
687
+ (labels) => {
688
+ const type = labelValue(labels, "common.k8s.elastic.co/type");
689
+ const cluster = labelValue(labels, "elasticsearch.k8s.elastic.co/cluster-name");
690
+ if (!type || type.toLowerCase() !== "elasticsearch" || !cluster) {
691
+ return null;
692
+ }
693
+ return {
694
+ operator: "eck",
695
+ system: "elasticsearch",
696
+ clusterName: cluster,
697
+ role: null,
698
+ serviceNames: [`${cluster}-es-http`],
699
+ evidence: `label:elasticsearch.k8s.elastic.co/cluster-name=${cluster}`,
700
+ };
701
+ },
702
+ // Altinity ClickHouse operator.
703
+ (labels) => {
704
+ const installation = labelValue(labels, "clickhouse.altinity.com/chi");
705
+ if (!installation) {
706
+ return null;
707
+ }
708
+ return {
709
+ operator: "altinity",
710
+ system: "clickhouse",
711
+ clusterName: installation,
712
+ role: null,
713
+ serviceNames: [`clickhouse-${installation}`],
714
+ evidence: `label:clickhouse.altinity.com/chi=${installation}`,
715
+ };
716
+ },
717
+ // K8ssandra cass-operator.
718
+ (labels) => {
719
+ const cluster = labelValue(labels, "cassandra.datastax.com/cluster");
720
+ if (!cluster) {
721
+ return null;
722
+ }
723
+ const datacenter = labelValue(labels, "cassandra.datastax.com/datacenter");
724
+ return {
725
+ operator: "cass-operator",
726
+ system: "cassandra",
727
+ clusterName: cluster,
728
+ role: null,
729
+ serviceNames: datacenter
730
+ ? [
731
+ `${cluster}-${datacenter}-service`,
732
+ `${cluster}-${datacenter}-all-pods-service`,
733
+ ]
734
+ : [],
735
+ evidence: `label:cassandra.datastax.com/cluster=${cluster}`,
736
+ };
737
+ },
738
+ /*
739
+ * The Vitess operator (PlanetScale). It runs every component on the same
740
+ * `vitess/lite` image, so only `planetscale.com/component` tells them
741
+ * apart. The database clients connect to is vtgate, speaking MySQL; the
742
+ * vttablets (each with its own mysqld), vtctld, vtorc, vtbackup, vtadmin,
743
+ * the etcd lockserver and the backup-storage subcontroller are parts of
744
+ * the VitessCluster, not members. vtgate Services carry a hash suffix
745
+ * (`<cluster>-vtgate-<hash>`), so none are guessed: the owner
746
+ * Deployment's name is added, as for any Deployment.
747
+ */
748
+ (labels) => {
749
+ const cluster = labelValue(labels, "planetscale.com/cluster");
750
+ if (!cluster) {
751
+ return null;
752
+ }
753
+ const component = labelValue(labels, "planetscale.com/component");
754
+ if (!component || component.toLowerCase() !== "vtgate") {
755
+ return "skip";
756
+ }
757
+ return {
758
+ operator: "vitess-operator",
759
+ system: "vitess",
760
+ clusterName: cluster,
761
+ role: null,
762
+ serviceNames: [],
763
+ evidence: `label:planetscale.com/cluster=${cluster}`,
764
+ };
765
+ },
766
+ // Bitnami and most other Helm charts (`app.kubernetes.io/name`).
767
+ (labels) => {
768
+ const chartName = labelValue(labels, "app.kubernetes.io/name");
769
+ if (!chartName) {
770
+ return null;
771
+ }
772
+ const chart = chartName.toLowerCase();
773
+ const system = CHART_SYSTEM_BY_NAME.get(chart);
774
+ if (!system) {
775
+ return null;
776
+ }
777
+ const instance = labelValue(labels, "app.kubernetes.io/instance");
778
+ const component = labelValue(labels, "app.kubernetes.io/component");
779
+ /*
780
+ * Helm's conventional fullname: the release name when it already
781
+ * contains the chart name, else `${release}-${chart}`. A
782
+ * `fullnameOverride` breaks the guess; the owner StatefulSet's name and
783
+ * its headless Service (added for every pod) still name the real ones.
784
+ */
785
+ const fullName = instance
786
+ ? instance.toLowerCase().includes(chart)
787
+ ? instance
788
+ : `${instance}-${chart}`
789
+ : null;
790
+ const serviceNames = [];
791
+ if (fullName) {
792
+ serviceNames.push(`${fullName}-headless`, `${fullName}-hl`);
793
+ if (component) {
794
+ serviceNames.push(`${fullName}-${component.toLowerCase()}`);
795
+ if (component.toLowerCase() === "replica") {
796
+ serviceNames.push(`${fullName}-replicas`);
797
+ }
798
+ }
799
+ }
800
+ const managedBy = labelValue(labels, "app.kubernetes.io/managed-by");
801
+ return {
802
+ operator: managedBy && managedBy.toLowerCase() === "helm" ? "helm" : null,
803
+ system,
804
+ clusterName: fullName,
805
+ role: roleFrom(component),
806
+ serviceNames,
807
+ evidence: `label:app.kubernetes.io/name=${chartName}`,
808
+ };
809
+ },
810
+ ];
811
+ function readPorts(declaredPorts) {
812
+ const ports = [];
813
+ if (!Array.isArray(declaredPorts)) {
814
+ return ports;
815
+ }
816
+ for (const declared of declaredPorts) {
817
+ const port = declared && typeof declared === "object"
818
+ ? declared.containerPort
819
+ : undefined;
820
+ if (typeof port === "number" &&
821
+ Number.isInteger(port) &&
822
+ port >= 1 &&
823
+ port <= 65535 &&
824
+ !ports.includes(port)) {
825
+ ports.push(port);
826
+ }
827
+ }
828
+ return ports;
829
+ }
830
+ /*
831
+ * Reads ONLY name, image, declared ports and what command/args run —
832
+ * never `env` (see the file header), never by spreading the container
833
+ * object.
834
+ */
835
+ function readContainers(pod) {
836
+ var _a;
837
+ const containers = (_a = pod.spec) === null || _a === void 0 ? void 0 : _a.containers;
838
+ if (!Array.isArray(containers)) {
839
+ return [];
840
+ }
841
+ const views = [];
842
+ for (const container of containers) {
843
+ if (!container || typeof container !== "object") {
844
+ continue;
845
+ }
846
+ const name = container.name;
847
+ const image = container.image;
848
+ const imageText = typeof image === "string" && image.trim() ? image.trim() : null;
849
+ views.push({
850
+ name: typeof name === "string" ? name.trim() : "",
851
+ image: imageText,
852
+ ports: readPorts(container.ports),
853
+ nonServer: isNonServerCommand({
854
+ command: container.command,
855
+ args: container.args,
856
+ }),
857
+ classification: classifyImage(imageText),
858
+ });
859
+ }
860
+ return views;
861
+ }
862
+ function readOwners(pod) {
863
+ var _a;
864
+ const items = (_a = pod.ownerReferences) === null || _a === void 0 ? void 0 : _a.items;
865
+ if (!Array.isArray(items)) {
866
+ return [];
867
+ }
868
+ const owners = [];
869
+ for (const item of items) {
870
+ const kind = item === null || item === void 0 ? void 0 : item.kind;
871
+ const name = item === null || item === void 0 ? void 0 : item.name;
872
+ if (typeof kind === "string" &&
873
+ kind.trim() &&
874
+ typeof name === "string" &&
875
+ name.trim()) {
876
+ owners.push({ kind: kind.trim(), name: name.trim() });
877
+ }
878
+ }
879
+ return owners;
880
+ }
881
+ function resolveOwnerWorkload(podName, owner, labels) {
882
+ if (!owner) {
883
+ return { workloadKind: "Pod", workloadName: podName };
884
+ }
885
+ const kind = owner.kind.toLowerCase();
886
+ if (kind === "statefulset") {
887
+ return { workloadKind: "StatefulSet", workloadName: owner.name };
888
+ }
889
+ if (kind === "daemonset") {
890
+ return { workloadKind: "DaemonSet", workloadName: owner.name };
891
+ }
892
+ if (kind === "replicaset") {
893
+ /*
894
+ * A Deployment's ReplicaSet is `${deployment}-${pod-template-hash}`, and
895
+ * the pod carries that hash as a label — so stripping it is exact, with
896
+ * no guessing at what a hash looks like.
897
+ */
898
+ const hash = labelValue(labels, "pod-template-hash");
899
+ const suffix = hash ? `-${hash}` : "";
900
+ if (hash &&
901
+ owner.name.endsWith(suffix) &&
902
+ owner.name.length > suffix.length) {
903
+ return {
904
+ workloadKind: "Deployment",
905
+ workloadName: owner.name.substring(0, owner.name.length - suffix.length),
906
+ };
907
+ }
908
+ return { workloadKind: "ReplicaSet", workloadName: owner.name };
909
+ }
910
+ return { workloadKind: owner.kind, workloadName: owner.name };
911
+ }
912
+ function uniqueNonEmpty(values) {
913
+ const result = [];
914
+ for (const value of values) {
915
+ const trimmed = typeof value === "string" ? value.trim() : "";
916
+ if (trimmed && !result.includes(trimmed)) {
917
+ result.push(trimmed);
918
+ }
919
+ }
920
+ return result;
921
+ }
922
+ /*
923
+ * A database container with one unrecognised neighbour is still a database
924
+ * pod when the evidence says so on its own: a StatefulSet (the shape
925
+ * databases are deployed in, not apps with a cache sidecar) whose database
926
+ * container declares its engine's default port. A log shipper or backup
927
+ * agent nobody has catalogued yet must not hide a Postgres StatefulSet.
928
+ */
929
+ function toleratesUnknownNeighbour(data) {
930
+ if (data.unknownNeighbours !== 1 || data.ownerKind !== "StatefulSet") {
931
+ return false;
932
+ }
933
+ const defaultPort = getDefaultDatabasePort(data.system);
934
+ return (defaultPort !== null && data.databaseContainer.ports.includes(defaultPort));
935
+ }
936
+ /**
937
+ * The database a Kubernetes pod runs, or null. Operator / chart labels are
938
+ * consulted first (they name the cluster: workloadKind "Cluster"); otherwise
939
+ * the first container whose image is a database, provided no other
940
+ * container is an unrecognised application (a DB sidecar in an app pod is
941
+ * not a database — one unknown neighbour is tolerated in a StatefulSet whose
942
+ * database container declares the engine's default port). Batch pods,
943
+ * finished pods, client / debug runs, owner-less pods declaring no port and
944
+ * non-member pods of a database cluster (poolers, routers, exporters,
945
+ * backup repos) are null.
946
+ */
947
+ export function classifyKubernetesPod(pod, extra) {
948
+ if (!pod || typeof pod !== "object") {
949
+ return null;
950
+ }
951
+ const podName = typeof pod.name === "string" ? pod.name.trim() : "";
952
+ const namespace = typeof pod.namespaceKey === "string" ? pod.namespaceKey.trim() : "";
953
+ if (!podName) {
954
+ return null;
955
+ }
956
+ if (typeof pod.phase === "string" &&
957
+ SKIPPED_POD_PHASES.has(pod.phase.trim().toLowerCase())) {
958
+ return null;
959
+ }
960
+ const owners = readOwners(pod);
961
+ for (const owner of owners) {
962
+ if (BATCH_OWNER_KINDS.has(owner.kind.toLowerCase())) {
963
+ return null;
964
+ }
965
+ }
966
+ const owner = owners[0] || null;
967
+ const labels = pod.labels && typeof pod.labels === "object" ? pod.labels : {};
968
+ const containers = readContainers(pod);
969
+ const statefulSetServiceNames = (extra === null || extra === void 0 ? void 0 : extra.statefulSetServiceNames) &&
970
+ typeof extra.statefulSetServiceNames === "object"
971
+ ? extra.statefulSetServiceNames
972
+ : {};
973
+ const headlessServiceName = owner &&
974
+ owner.kind.toLowerCase() === "statefulset" &&
975
+ Object.prototype.hasOwnProperty.call(statefulSetServiceNames, owner.name) &&
976
+ typeof statefulSetServiceNames[owner.name] === "string" &&
977
+ statefulSetServiceNames[owner.name].trim()
978
+ ? statefulSetServiceNames[owner.name].trim()
979
+ : null;
980
+ const ownerWorkload = resolveOwnerWorkload(podName, owner, labels);
981
+ const ownerKind = owner ? ownerWorkload.workloadKind : null;
982
+ const ownerName = owner ? ownerWorkload.workloadName : null;
983
+ // 1. Operator / chart labels.
984
+ for (const rule of OPERATOR_RULES) {
985
+ const match = rule(labels);
986
+ if (match === null) {
987
+ continue;
988
+ }
989
+ if (match === "skip") {
990
+ return null;
991
+ }
992
+ const component = labelValue(labels, "app.kubernetes.io/component");
993
+ if (component && NON_MEMBER_COMPONENTS.has(component.toLowerCase())) {
994
+ return null;
995
+ }
996
+ /*
997
+ * A pod that only runs poolers / exporters / admin UIs / backup tools is
998
+ * not a member even when it carries the cluster's labels (a router or
999
+ * pooler Deployment the operator labels as part of the cluster).
1000
+ */
1001
+ const onlyNonMemberContainers = containers.length > 0 &&
1002
+ containers.every((container) => {
1003
+ return (container.classification.kind === "excluded" &&
1004
+ NON_MEMBER_IMAGE_REASONS.has(container.classification.reason));
1005
+ });
1006
+ if (onlyNonMemberContainers) {
1007
+ return null;
1008
+ }
1009
+ /*
1010
+ * A chart's test hook or a debug pod is labelled like the cluster but
1011
+ * only runs a client, and a member whose database container is held
1012
+ * asleep (diagnostic mode) may still run its exporter, pooler or mesh
1013
+ * proxy: with no running container left that could be the server, it
1014
+ * is not a member — a sidecar's image, version and ports never stand in
1015
+ * for the database's.
1016
+ */
1017
+ const serverContainers = containers.filter((container) => {
1018
+ return !container.nonServer && couldBeDatabaseProcess(container);
1019
+ });
1020
+ if (containers.length > 0 && serverContainers.length === 0) {
1021
+ return null;
1022
+ }
1023
+ const databaseContainer = serverContainers.find((container) => {
1024
+ return (container.classification.kind === "database" &&
1025
+ container.classification.system === match.system);
1026
+ }) ||
1027
+ serverContainers.find((container) => {
1028
+ return container.classification.kind === "database";
1029
+ }) ||
1030
+ serverContainers.find((container) => {
1031
+ return container.classification.kind === "unknown";
1032
+ }) ||
1033
+ serverContainers[0] ||
1034
+ null;
1035
+ const workloadKind = match.clusterName
1036
+ ? "Cluster"
1037
+ : ownerWorkload.workloadKind;
1038
+ const workloadName = match.clusterName || ownerWorkload.workloadName;
1039
+ const evidence = [match.evidence];
1040
+ if (databaseContainer === null || databaseContainer === void 0 ? void 0 : databaseContainer.image) {
1041
+ evidence.push(`image:${databaseContainer.image}`);
1042
+ }
1043
+ return {
1044
+ system: match.system,
1045
+ namespace,
1046
+ workloadKind,
1047
+ workloadName,
1048
+ ownerKind,
1049
+ ownerName,
1050
+ podName,
1051
+ containerName: (databaseContainer === null || databaseContainer === void 0 ? void 0 : databaseContainer.name) || "",
1052
+ image: (databaseContainer === null || databaseContainer === void 0 ? void 0 : databaseContainer.image) || null,
1053
+ version: parseImageVersion(databaseContainer === null || databaseContainer === void 0 ? void 0 : databaseContainer.image),
1054
+ ports: databaseContainer ? [...databaseContainer.ports] : [],
1055
+ operator: match.operator,
1056
+ role: match.role,
1057
+ serviceNames: uniqueNonEmpty([
1058
+ workloadName,
1059
+ ...match.serviceNames,
1060
+ ownerKind && SERVICE_NAMED_OWNER_KINDS.has(ownerKind) && ownerName
1061
+ ? ownerName
1062
+ : "",
1063
+ headlessServiceName || "",
1064
+ ]),
1065
+ headlessServiceName,
1066
+ evidence,
1067
+ };
1068
+ }
1069
+ // 2. Container images: the first database container that runs a server.
1070
+ const databaseContainer = containers.find((container) => {
1071
+ return (container.classification.kind === "database" && !container.nonServer);
1072
+ });
1073
+ if (!databaseContainer ||
1074
+ databaseContainer.classification.kind !== "database") {
1075
+ return null;
1076
+ }
1077
+ const system = databaseContainer.classification.system;
1078
+ const unknownNeighbours = containers.filter((container) => {
1079
+ return (container !== databaseContainer &&
1080
+ container.classification.kind === "unknown");
1081
+ }).length;
1082
+ if (unknownNeighbours > 0 &&
1083
+ !toleratesUnknownNeighbour({
1084
+ ownerKind,
1085
+ databaseContainer,
1086
+ system,
1087
+ unknownNeighbours,
1088
+ })) {
1089
+ return null;
1090
+ }
1091
+ /*
1092
+ * An owner-less pod is what `kubectl run` makes — usually a one-off client
1093
+ * session in a database image. A server run that way declares its port.
1094
+ */
1095
+ if (!owner && databaseContainer.ports.length === 0) {
1096
+ return null;
1097
+ }
1098
+ return {
1099
+ system,
1100
+ namespace,
1101
+ workloadKind: ownerWorkload.workloadKind,
1102
+ workloadName: ownerWorkload.workloadName,
1103
+ ownerKind,
1104
+ ownerName,
1105
+ podName,
1106
+ containerName: databaseContainer.name,
1107
+ image: databaseContainer.image,
1108
+ version: parseImageVersion(databaseContainer.image),
1109
+ ports: [...databaseContainer.ports],
1110
+ operator: null,
1111
+ role: null,
1112
+ serviceNames: uniqueNonEmpty([
1113
+ ownerWorkload.workloadName,
1114
+ headlessServiceName || "",
1115
+ ]),
1116
+ headlessServiceName,
1117
+ evidence: [`image:${databaseContainer.image}`],
1118
+ };
1119
+ }
1120
+ /**
1121
+ * The Service a CloudNativePG pooler pod backs (the Pooler's name), for
1122
+ * attachPoolerServices; null for any other pod. Pooler pods are never
1123
+ * members (classifyKubernetesPod is null for them), but applications
1124
+ * connect through their Service.
1125
+ */
1126
+ export function classifyKubernetesPoolerPod(pod) {
1127
+ if (!pod || typeof pod !== "object") {
1128
+ return null;
1129
+ }
1130
+ if (typeof pod.phase === "string" &&
1131
+ SKIPPED_POD_PHASES.has(pod.phase.trim().toLowerCase())) {
1132
+ return null;
1133
+ }
1134
+ const labels = pod.labels && typeof pod.labels === "object" ? pod.labels : {};
1135
+ const cluster = labelValue(labels, "cnpg.io/cluster");
1136
+ const pooler = labelValue(labels, "cnpg.io/poolerName");
1137
+ if (!cluster || !pooler) {
1138
+ return null;
1139
+ }
1140
+ return {
1141
+ system: "postgresql",
1142
+ namespace: typeof pod.namespaceKey === "string" ? pod.namespaceKey.trim() : "",
1143
+ clusterName: cluster,
1144
+ serviceName: pooler,
1145
+ };
1146
+ }
1147
+ function compareStrings(a, b) {
1148
+ if (a < b) {
1149
+ return -1;
1150
+ }
1151
+ return a > b ? 1 : 0;
1152
+ }
1153
+ /**
1154
+ * The engine of a database whose members report several engines of one
1155
+ * family: the most specific of them (getMoreSpecificDatabaseSystem). A
1156
+ * StatefulSet mid-rollout from a redis image to a valkey image is ONE
1157
+ * Valkey database, as its family-keyed identifier
1158
+ * (buildWorkloadDatabaseServerIdentifier) already says. The engines are
1159
+ * folded most-reported first, then by name, so member order never changes
1160
+ * the answer; of two forks that do not refine each other (valkey and keydb)
1161
+ * the more reported one stays, the first by name on a tie. Null when no
1162
+ * engine is given.
1163
+ */
1164
+ export function pickMostSpecificDatabaseSystem(systems) {
1165
+ const counts = new Map();
1166
+ for (const system of Array.isArray(systems) ? systems : []) {
1167
+ if (typeof system === "string" && system) {
1168
+ counts.set(system, (counts.get(system) || 0) + 1);
1169
+ }
1170
+ }
1171
+ const ordered = Array.from(counts.keys()).sort((a, b) => {
1172
+ return ((counts.get(b) || 0) - (counts.get(a) || 0) || compareStrings(a, b));
1173
+ });
1174
+ let result = null;
1175
+ for (const system of ordered) {
1176
+ result = getMoreSpecificDatabaseSystem(result, system);
1177
+ }
1178
+ return result;
1179
+ }
1180
+ /**
1181
+ * Fold per-pod candidates into one entry per database workload
1182
+ * (engine FAMILY + namespace + workloadKind + workloadName - the parts of
1183
+ * its family-keyed identifier). The group's engine is the most specific its
1184
+ * members report (pickMostSpecificDatabaseSystem). Member pods, ports,
1185
+ * Service names and owner workloads are unioned; image and version come
1186
+ * from the primary member running that engine when one is known, else from
1187
+ * the first such pod by name. Deterministic: groups and pod names are
1188
+ * sorted.
1189
+ */
1190
+ export function groupKubernetesDatabaseCandidates(candidates) {
1191
+ var _a, _b;
1192
+ if (!Array.isArray(candidates)) {
1193
+ return [];
1194
+ }
1195
+ const byKey = new Map();
1196
+ for (const candidate of candidates) {
1197
+ if (!candidate || !candidate.system || !candidate.workloadName) {
1198
+ continue;
1199
+ }
1200
+ const key = [
1201
+ getDatabaseSystemFamily(candidate.system) || candidate.system,
1202
+ candidate.namespace,
1203
+ candidate.workloadKind,
1204
+ candidate.workloadName,
1205
+ ].join("\u0000");
1206
+ const members = byKey.get(key) || [];
1207
+ members.push(candidate);
1208
+ byKey.set(key, members);
1209
+ }
1210
+ const groups = [];
1211
+ for (const members of byKey.values()) {
1212
+ const sorted = [...members].sort((a, b) => {
1213
+ return compareStrings(a.podName, b.podName);
1214
+ });
1215
+ const first = sorted[0];
1216
+ const system = pickMostSpecificDatabaseSystem(sorted.map((member) => {
1217
+ return member.system;
1218
+ })) || first.system;
1219
+ // Image and version describe the engine the group is shown as.
1220
+ const runningSystem = sorted.filter((member) => {
1221
+ return member.system === system;
1222
+ });
1223
+ const pool = runningSystem.length > 0 ? runningSystem : sorted;
1224
+ const representative = pool.find((member) => {
1225
+ return member.role === "primary";
1226
+ }) || pool[0];
1227
+ const podNames = uniqueNonEmpty(sorted.map((member) => {
1228
+ return member.podName;
1229
+ }));
1230
+ const ports = [];
1231
+ for (const member of sorted) {
1232
+ for (const port of member.ports || []) {
1233
+ if (!ports.includes(port)) {
1234
+ ports.push(port);
1235
+ }
1236
+ }
1237
+ }
1238
+ ports.sort((a, b) => {
1239
+ return a - b;
1240
+ });
1241
+ const serviceNames = uniqueNonEmpty(sorted.flatMap((member) => {
1242
+ return member.serviceNames || [];
1243
+ }));
1244
+ const podServiceNames = [];
1245
+ for (const member of sorted) {
1246
+ if (member.headlessServiceName &&
1247
+ !podServiceNames.some((entry) => {
1248
+ return entry.podName === member.podName;
1249
+ })) {
1250
+ podServiceNames.push({
1251
+ podName: member.podName,
1252
+ serviceName: member.headlessServiceName,
1253
+ });
1254
+ }
1255
+ }
1256
+ const ownerWorkloads = [];
1257
+ for (const member of sorted) {
1258
+ if (member.ownerKind &&
1259
+ member.ownerName &&
1260
+ !ownerWorkloads.some((entry) => {
1261
+ return (entry.kind === member.ownerKind && entry.name === member.ownerName);
1262
+ })) {
1263
+ ownerWorkloads.push({ kind: member.ownerKind, name: member.ownerName });
1264
+ }
1265
+ }
1266
+ ownerWorkloads.sort((a, b) => {
1267
+ return compareStrings(a.kind, b.kind) || compareStrings(a.name, b.name);
1268
+ });
1269
+ groups.push({
1270
+ system,
1271
+ namespace: first.namespace,
1272
+ workloadKind: first.workloadKind,
1273
+ workloadName: first.workloadName,
1274
+ podNames,
1275
+ image: representative.image,
1276
+ version: representative.version,
1277
+ ports,
1278
+ operator: ((_a = sorted.find((member) => {
1279
+ return Boolean(member.operator);
1280
+ })) === null || _a === void 0 ? void 0 : _a.operator) || null,
1281
+ serviceNames,
1282
+ headlessServiceName: ((_b = sorted.find((member) => {
1283
+ return Boolean(member.headlessServiceName);
1284
+ })) === null || _b === void 0 ? void 0 : _b.headlessServiceName) || null,
1285
+ podServiceNames,
1286
+ ownerWorkloads,
1287
+ });
1288
+ }
1289
+ return groups.sort((a, b) => {
1290
+ return (compareStrings(a.namespace, b.namespace) ||
1291
+ compareStrings(a.workloadKind, b.workloadKind) ||
1292
+ compareStrings(a.workloadName, b.workloadName) ||
1293
+ compareStrings(a.system, b.system));
1294
+ });
1295
+ }
1296
+ /**
1297
+ * Add each pooler's Service to the operator cluster it pools (same engine
1298
+ * family, namespace and cluster name). Returns new group objects; a pooler
1299
+ * whose cluster has no group this run is dropped.
1300
+ */
1301
+ export function attachPoolerServices(groups, poolers) {
1302
+ if (!Array.isArray(groups)) {
1303
+ return [];
1304
+ }
1305
+ const list = Array.isArray(poolers)
1306
+ ? poolers
1307
+ : [];
1308
+ return groups.map((group) => {
1309
+ if (group.workloadKind !== "Cluster") {
1310
+ return group;
1311
+ }
1312
+ const extra = list
1313
+ .filter((pooler) => {
1314
+ return (Boolean(pooler) &&
1315
+ isSameDatabaseFamily(pooler.system, group.system) &&
1316
+ pooler.namespace === group.namespace &&
1317
+ pooler.clusterName === group.workloadName);
1318
+ })
1319
+ .map((pooler) => {
1320
+ return pooler.serviceName;
1321
+ })
1322
+ .sort(compareStrings);
1323
+ if (extra.length === 0) {
1324
+ return group;
1325
+ }
1326
+ return Object.assign(Object.assign({}, group), { serviceNames: uniqueNonEmpty([...group.serviceNames, ...extra]) });
1327
+ });
1328
+ }
1329
+ // ---- Docker / Podman containers -------------------------------------------
1330
+ /*
1331
+ * Every container label classifyContainer reads: the Swarm / Compose
1332
+ * service that groups replicas, and the marks of Testcontainers runs,
1333
+ * `docker compose run` one-offs and kubelet-managed containers. The Docker
1334
+ * and Podman agents copy exactly these onto their docker_stats metrics as
1335
+ * resource attributes (`container_labels_to_metric_labels`, same names),
1336
+ * and the metrics ingest stores them as the container row's labels — the
1337
+ * one inventory path every agent version runs.
1338
+ */
1339
+ export const CONTAINER_CLASSIFIER_LABEL_KEYS = [
1340
+ "com.docker.compose.oneoff",
1341
+ "com.docker.compose.project",
1342
+ "com.docker.compose.service",
1343
+ "com.docker.swarm.service.name",
1344
+ "io.kubernetes.pod.name",
1345
+ "io.podman.compose.project",
1346
+ "io.podman.compose.service",
1347
+ "org.testcontainers",
1348
+ "org.testcontainers.sessionId",
1349
+ ];
1350
+ // A Swarm task id: 25 lowercase alphanumerics (`stack_db.1.<task id>`).
1351
+ const SWARM_TASK_ID_REGEX = /^[a-z0-9]{25}$/;
1352
+ const SWARM_SLOT_REGEX = /^(?:\d+|[a-z0-9]{25})$/;
1353
+ /*
1354
+ * Containers that are never a long-lived database server of their own:
1355
+ * Testcontainers runs (CI), `docker compose run` one-offs, and containers
1356
+ * the kubelet manages on a Docker node (the Kubernetes path discovers those
1357
+ * as pods).
1358
+ */
1359
+ function isEphemeralOrManagedContainer(labels) {
1360
+ for (const key of Object.keys(labels)) {
1361
+ if (key === "org.testcontainers" || key.startsWith("org.testcontainers.")) {
1362
+ return true;
1363
+ }
1364
+ }
1365
+ const oneOff = labelValue(labels, "com.docker.compose.oneoff");
1366
+ if (oneOff && oneOff.toLowerCase() === "true") {
1367
+ return true;
1368
+ }
1369
+ return (hasLabel(labels, "io.kubernetes.pod.name") ||
1370
+ hasLabel(labels, "io.kubernetes.container.name"));
1371
+ }
1372
+ /*
1373
+ * The Swarm service a task container belongs to, from its name alone
1374
+ * (`stack_db.1.<25-char task id>`, `stack_db.<node id>.<task id>`) — for
1375
+ * rows whose labels have not been inventoried.
1376
+ */
1377
+ function swarmServiceFromTaskName(containerName) {
1378
+ const parts = containerName.split(".");
1379
+ if (parts.length < 3) {
1380
+ return null;
1381
+ }
1382
+ const taskId = parts[parts.length - 1];
1383
+ const slot = parts[parts.length - 2];
1384
+ if (!SWARM_TASK_ID_REGEX.test(taskId) || !SWARM_SLOT_REGEX.test(slot)) {
1385
+ return null;
1386
+ }
1387
+ const service = parts.slice(0, -2).join(".");
1388
+ return service || null;
1389
+ }
1390
+ /*
1391
+ * What groups a container's replicas: its Swarm service, its Compose
1392
+ * project + service (Docker Compose and podman-compose both stamp
1393
+ * `com.docker.compose.*`; podman-compose also `io.podman.compose.*`), else
1394
+ * the container name exactly as it is — never a guessed-away suffix, since
1395
+ * `redis-6379` and `redis-6380` or `pg-14` and `pg-16` are different
1396
+ * servers. The kind says which of the three it is.
1397
+ */
1398
+ function containerWorkload(containerName, labels) {
1399
+ const swarmService = labelValue(labels, "com.docker.swarm.service.name") ||
1400
+ swarmServiceFromTaskName(containerName);
1401
+ if (swarmService) {
1402
+ return {
1403
+ workloadKind: ContainerWorkloadKind.SwarmService,
1404
+ workloadName: swarmService,
1405
+ };
1406
+ }
1407
+ const project = labelValue(labels, "com.docker.compose.project") ||
1408
+ labelValue(labels, "io.podman.compose.project");
1409
+ const service = labelValue(labels, "com.docker.compose.service") ||
1410
+ labelValue(labels, "io.podman.compose.service");
1411
+ if (project && service) {
1412
+ return {
1413
+ workloadKind: ContainerWorkloadKind.ComposeService,
1414
+ workloadName: `${project}-${service}`,
1415
+ };
1416
+ }
1417
+ return {
1418
+ workloadKind: ContainerWorkloadKind.Container,
1419
+ workloadName: containerName,
1420
+ };
1421
+ }
1422
+ /**
1423
+ * The database a Docker / Podman container runs, or null. The workload is
1424
+ * the Swarm service or Compose service the container belongs to (so its
1425
+ * replicas group together), else the container's own name, and its kind
1426
+ * says which. Testcontainers runs, `docker compose run` one-offs and
1427
+ * kubelet-managed containers are null.
1428
+ */
1429
+ export function classifyContainer(container) {
1430
+ if (!container || typeof container.name !== "string") {
1431
+ return null;
1432
+ }
1433
+ // Docker reports names as "/name" (and occasionally "/a,/b").
1434
+ const containerName = (container.name.split(",")[0] || "")
1435
+ .trim()
1436
+ .replace(/^\/+/, "");
1437
+ if (!containerName) {
1438
+ return null;
1439
+ }
1440
+ const labels = container.labels &&
1441
+ typeof container.labels === "object" &&
1442
+ !Array.isArray(container.labels)
1443
+ ? container.labels
1444
+ : {};
1445
+ if (isEphemeralOrManagedContainer(labels)) {
1446
+ return null;
1447
+ }
1448
+ const classification = classifyImage(container.imageName);
1449
+ if (classification.kind !== "database") {
1450
+ return null;
1451
+ }
1452
+ const descriptor = getDatabaseSystemDescriptor(classification.system);
1453
+ const workload = containerWorkload(containerName, labels);
1454
+ return {
1455
+ system: descriptor ? descriptor.system : classification.system,
1456
+ workloadKind: workload.workloadKind,
1457
+ workloadName: workload.workloadName,
1458
+ containerName,
1459
+ version: parseImageVersion(container.imageName),
1460
+ };
1461
+ }
1462
+ //# sourceMappingURL=DatabaseContainerClassifier.js.map