@oneuptime/common 14.0.3 → 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 (617) hide show
  1. package/Models/DatabaseModels/Alert.ts +55 -0
  2. package/Models/DatabaseModels/DatabaseServer.ts +1650 -0
  3. package/Models/DatabaseModels/DatabaseServerEndpoint.ts +540 -0
  4. package/Models/DatabaseModels/DatabaseServerFeed.ts +625 -0
  5. package/Models/DatabaseModels/DatabaseServerLabelRule.ts +514 -0
  6. package/Models/DatabaseModels/DatabaseServerOwnerRule.ts +596 -0
  7. package/Models/DatabaseModels/DatabaseServerOwnerTeam.ts +491 -0
  8. package/Models/DatabaseModels/DatabaseServerOwnerUser.ts +490 -0
  9. package/Models/DatabaseModels/Incident.ts +55 -0
  10. package/Models/DatabaseModels/Index.ts +16 -0
  11. package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +26 -0
  12. package/Models/DatabaseModels/ScheduledMaintenance.ts +55 -0
  13. package/Models/DatabaseModels/TelemetryException.ts +2 -0
  14. package/Models/DatabaseModels/UserProjectSsoConsent.ts +146 -0
  15. package/Server/Infrastructure/Postgres/SchemaMigrations/1795000000000-AddDatabaseServerTables.ts +673 -0
  16. package/Server/Infrastructure/Postgres/SchemaMigrations/1795100000000-AddUserProjectSsoConsent.ts +51 -0
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
  18. package/Server/Middleware/MultipartFormData.ts +1 -1
  19. package/Server/Middleware/TelemetryIngest.ts +15 -8
  20. package/Server/Services/AlertReminderRuleService.ts +100 -24
  21. package/Server/Services/DatabaseServerEndpointService.ts +895 -0
  22. package/Server/Services/DatabaseServerFeedService.ts +128 -0
  23. package/Server/Services/DatabaseServerLabelRuleEngineService.ts +340 -0
  24. package/Server/Services/DatabaseServerLabelRuleService.ts +14 -0
  25. package/Server/Services/DatabaseServerOwnerRuleEngineService.ts +425 -0
  26. package/Server/Services/DatabaseServerOwnerRuleService.ts +14 -0
  27. package/Server/Services/DatabaseServerOwnerTeamService.ts +180 -0
  28. package/Server/Services/DatabaseServerOwnerUserService.ts +173 -0
  29. package/Server/Services/DatabaseServerService.ts +4546 -0
  30. package/Server/Services/DatabaseService.ts +14 -8
  31. package/Server/Services/DockerResourceService.ts +43 -2
  32. package/Server/Services/IncidentReminderRuleService.ts +103 -23
  33. package/Server/Services/Index.ts +16 -0
  34. package/Server/Services/InventoryItemService.ts +113 -5
  35. package/Server/Services/IoTDeviceService.ts +145 -37
  36. package/Server/Services/OpenTelemetryIngestService.ts +19 -0
  37. package/Server/Services/PodmanResourceService.ts +43 -2
  38. package/Server/Services/ScheduledMaintenanceReminderRuleService.ts +107 -23
  39. package/Server/Services/ServiceService.ts +1 -1
  40. package/Server/Services/TelemetryUsageBillingService.ts +29 -2
  41. package/Server/Services/UserProjectSsoConsentService.ts +74 -0
  42. package/Server/Services/UserService.ts +14 -1
  43. package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +18 -0
  44. package/Server/Types/Database/QueryHelper.ts +30 -1
  45. package/Server/Utils/AI/Toolbox/ResourceTools.ts +69 -1
  46. package/Server/Utils/Database/AffectedResourceRelations.ts +6 -0
  47. package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +188 -6
  48. package/Server/Utils/Monitor/MonitorAlert.ts +28 -1
  49. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +2262 -755
  50. package/Server/Utils/Monitor/MonitorIncident.ts +28 -1
  51. package/Server/Utils/Monitor/MonitorMaintenanceSuppression.ts +268 -6
  52. package/Server/Utils/Monitor/MonitorResource.ts +47 -11
  53. package/Server/Utils/Monitor/MonitorResourceContext.ts +1 -0
  54. package/Server/Utils/Monitor/MonitorStepResourceIdentity.ts +239 -21
  55. package/Server/Utils/Monitor/PerSeriesResolutionRootCause.ts +43 -0
  56. package/Server/Utils/Monitor/SeriesResourceLabels.ts +291 -0
  57. package/Server/Utils/Monitor/SeriesResourceLinker.ts +111 -12
  58. package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +25 -0
  59. package/Server/Utils/StartServer.ts +26 -6
  60. package/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.ts +2 -0
  61. package/Server/Utils/Telemetry/DatabaseEndpointDiscovery.ts +688 -0
  62. package/Server/Utils/Telemetry/EntityRegistry.ts +5 -1
  63. package/Server/Utils/Telemetry/LogExceptionExtractor.ts +18 -1
  64. package/Server/Utils/Telemetry/ResourceEntityFilter.ts +175 -12
  65. package/Server/Utils/Telemetry/ResourceFacetResolver.ts +12 -0
  66. package/Server/Utils/Telemetry/ServiceDependencyDiscovery.ts +606 -36
  67. package/Server/Utils/Telemetry/Telemetry.ts +16 -0
  68. package/Server/Utils/Telemetry/TelemetryEntity.ts +22 -22
  69. package/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.ts +16 -10
  70. package/Tests/App/Accounts/SignedInRedirect.test.tsx +241 -0
  71. package/Tests/App/AdminDashboard/AdminHeaderSmallScreens.test.tsx +221 -4
  72. package/Tests/App/Dashboard/AIInsightsResourcePageContext.test.ts +42 -0
  73. package/Tests/App/Dashboard/AffectedResourcesDisplay.test.tsx +100 -0
  74. package/Tests/App/Dashboard/AffectedResourcesPicker.test.tsx +86 -0
  75. package/Tests/App/Dashboard/AffectedResourcesPickerHiddenTypes.test.tsx +2 -0
  76. package/Tests/App/Dashboard/AffectedResourcesSummaryStep.test.tsx +19 -0
  77. package/Tests/App/Dashboard/BreadcrumbCoverage.test.tsx +14 -0
  78. package/Tests/App/Dashboard/CorrelateFilterBuilder.test.tsx +26 -1
  79. package/Tests/App/Dashboard/DashboardAppSsoError.test.tsx +501 -0
  80. package/Tests/App/Dashboard/DashboardHeaderRequests.test.tsx +64 -1
  81. package/Tests/App/Dashboard/DashboardHeaderSmallScreens.test.tsx +178 -18
  82. package/Tests/App/Dashboard/DashboardMasterPageSsoRedirect.test.tsx +444 -0
  83. package/Tests/App/Dashboard/DashboardNavBarForeignHiddenRule.test.tsx +573 -0
  84. package/Tests/App/Dashboard/DatabaseChartAxes.test.tsx +431 -0
  85. package/Tests/App/Dashboard/DatabaseContainerDetailBadge.test.tsx +249 -0
  86. package/Tests/App/Dashboard/DatabaseDashboardE2EFixes.test.ts +681 -0
  87. package/Tests/App/Dashboard/DatabaseDocumentationMarkdown.test.ts +1801 -0
  88. package/Tests/App/Dashboard/DatabaseFleetSummaryRefresh.test.tsx +280 -0
  89. package/Tests/App/Dashboard/DatabaseFormHelpers.test.tsx +321 -0
  90. package/Tests/App/Dashboard/DatabaseMetricMonitorLink.test.tsx +795 -0
  91. package/Tests/App/Dashboard/DatabaseOverviewHeader.test.tsx +580 -0
  92. package/Tests/App/Dashboard/DatabaseRecommendationsEngineMetrics.test.ts +270 -0
  93. package/Tests/App/Dashboard/DatabaseServerComponents.test.tsx +1486 -0
  94. package/Tests/App/Dashboard/DatabaseServerEngineMetricsFilter.test.ts +223 -0
  95. package/Tests/App/Dashboard/DatabaseServerPresentation.test.ts +435 -0
  96. package/Tests/App/Dashboard/DatabaseServerSummary.test.ts +186 -0
  97. package/Tests/App/Dashboard/DatabaseServerTelemetryQueries.test.ts +1553 -0
  98. package/Tests/App/Dashboard/DatabaseTableTruncation.test.tsx +326 -0
  99. package/Tests/App/Dashboard/DatabaseTelemetryScope.test.ts +512 -0
  100. package/Tests/App/Dashboard/DatabaseTelemetryTabs.test.tsx +774 -0
  101. package/Tests/App/Dashboard/DatabaseViewLayout.test.tsx +233 -0
  102. package/Tests/App/Dashboard/DatabaseWorkloadBadge.test.tsx +972 -0
  103. package/Tests/App/Dashboard/DiscoveryReviewInventoryRefresh.test.tsx +5 -0
  104. package/Tests/App/Dashboard/DiscoveryReviewUnnamedHostHint.test.tsx +1061 -0
  105. package/Tests/App/Dashboard/EventOverlayScope.test.ts +147 -0
  106. package/Tests/App/Dashboard/EventOverlayScopeHook.test.tsx +1 -0
  107. package/Tests/App/Dashboard/LogsResourceFacetChips.test.tsx +1 -0
  108. package/Tests/App/Dashboard/MetricsViewerDrillDown.test.tsx +310 -0
  109. package/Tests/App/Dashboard/MetricsViewerEntityScopedRows.test.tsx +495 -0
  110. package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +132 -1
  111. package/Tests/App/Dashboard/NavigationSearchKeywords.test.tsx +5 -0
  112. package/Tests/App/Dashboard/ProductOrientation.test.tsx +4 -3
  113. package/Tests/App/Dashboard/RecommendationsLoadedContext.test.tsx +349 -0
  114. package/Tests/App/Dashboard/ResourceArchiveSettings.test.tsx +62 -0
  115. package/Tests/App/Dashboard/ResourceFeedPageWiring.test.ts +8 -1
  116. package/Tests/App/Dashboard/ResourceFeedPagesFilterSort.test.tsx +14 -0
  117. package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +2 -0
  118. package/Tests/App/Dashboard/ServiceMapDatabaseLink.test.tsx +1085 -0
  119. package/Tests/App/Dashboard/TelemetryResourceRetentionSettings.test.tsx +10 -0
  120. package/Tests/App/Dashboard/TracesResourceFacets.test.tsx +2 -1
  121. package/Tests/App/StatusPage/StatusPageHeaderForeignHiddenRule.test.tsx +284 -0
  122. package/Tests/ClassStrings.ts +178 -0
  123. package/Tests/Fixtures/MobilePasskeyUser.json +1 -2
  124. package/Tests/ForeignHiddenRuleGuard.ts +2152 -0
  125. package/Tests/Models/DatabaseModels/DatabaseServerModels.test.ts +2250 -0
  126. package/Tests/Models/DatabaseModels/ResourceFeedModels.test.ts +24 -5
  127. package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
  128. package/Tests/RenderedMarkup.ts +518 -0
  129. package/Tests/ResponsiveVisibility.test.ts +490 -4
  130. package/Tests/ResponsiveVisibility.ts +505 -52
  131. package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
  132. package/Tests/Server/Infrastructure/Postgres/AddDatabaseServerTablesMigration.test.ts +541 -0
  133. package/Tests/Server/Infrastructure/Postgres/AddUserProjectSsoConsentMigration.test.ts +234 -0
  134. package/Tests/Server/Services/ContainerSnapshotUpsertPostgres.test.ts +319 -0
  135. package/Tests/Server/Services/CrossProjectRelationWriteGuard.test.ts +13 -0
  136. package/Tests/Server/Services/DatabaseServerEndpointService.test.ts +2033 -0
  137. package/Tests/Server/Services/DatabaseServerFeedAndOwnerServices.test.ts +529 -0
  138. package/Tests/Server/Services/DatabaseServerLifecycle.test.ts +3302 -0
  139. package/Tests/Server/Services/DatabaseServerRegistries.test.ts +603 -0
  140. package/Tests/Server/Services/DatabaseServerRuleEngines.test.ts +754 -0
  141. package/Tests/Server/Services/DatabaseServerService.test.ts +3558 -0
  142. package/Tests/Server/Services/DatabaseServerSqlPostgres.test.ts +2045 -0
  143. package/Tests/Server/Services/DatabaseServiceUpdateColumnsIfUnlockedPostgres.test.ts +362 -0
  144. package/Tests/Server/Services/DatabaseServiceUpdateColumnsIfUnlockedReply.test.ts +210 -0
  145. package/Tests/Server/Services/HookFreeWriteLengthClamp.test.ts +18 -0
  146. package/Tests/Server/Services/IncidentAlertSloLinkSurvivesEdit.test.ts +2 -0
  147. package/Tests/Server/Services/IncomingCallPolicyEscalationRuleTarget.test.ts +225 -0
  148. package/Tests/Server/Services/InventoryItemDisplayName.test.ts +280 -2
  149. package/Tests/Server/Services/InventoryUpsertSchemaParity.test.ts +8 -2
  150. package/Tests/Server/Services/IoTDeviceLatestMetricsPostgres.test.ts +689 -0
  151. package/Tests/Server/Services/IoTDeviceService.test.ts +379 -0
  152. package/Tests/Server/Services/LatestMetricsValuesShape.test.ts +360 -0
  153. package/Tests/Server/Services/LlmModelPriceService.test.ts +402 -0
  154. package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +7 -1
  155. package/Tests/Server/Services/OwnerRowUniqueness.test.ts +61 -9
  156. package/Tests/Server/Services/ReminderRuleLookupPostgres.test.ts +2250 -0
  157. package/Tests/Server/Services/ReminderRuleRefreshOpenSubjectsPaging.test.ts +653 -0
  158. package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +68 -20
  159. package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +3 -3
  160. package/Tests/Server/Services/TelemetryResourceFacetCounting.test.ts +9 -0
  161. package/Tests/Server/Services/UserProjectSsoConsentPostgres.test.ts +153 -0
  162. package/Tests/Server/Services/UserProjectSsoConsentService.test.ts +192 -0
  163. package/Tests/Server/Services/UserServiceFirstMasterAdminElection.test.ts +71 -0
  164. package/Tests/Server/Services/UserSignupIdTakeoverPostgres.test.ts +238 -0
  165. package/Tests/Server/Services/WorkspaceNotificationSummaryHelpers.test.ts +592 -0
  166. package/Tests/Server/Types/Billing/PayAsYouGoMeteredAuthorization.test.ts +3 -0
  167. package/Tests/Server/Types/Database/EventOverlayScopePostgres.test.ts +1 -0
  168. package/Tests/Server/Types/Database/FeedEventTypeFilterQuery.test.ts +11 -0
  169. package/Tests/Server/Types/Database/Permissions/InfrastructureOwnershipScope.test.ts +8 -0
  170. package/Tests/Server/Types/Database/QueryHelperBooleanForCriteriaBackedRule.test.ts +1094 -0
  171. package/Tests/Server/Utils/AI/ResourceTools.test.ts +134 -0
  172. package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.test.ts +41 -0
  173. package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaAnomalyUnits.test.ts +279 -9
  174. package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaDisplayContext.test.ts +933 -0
  175. package/Tests/Server/Utils/Monitor/DatabaseMaintenanceSuppression.test.ts +582 -0
  176. package/Tests/Server/Utils/Monitor/DatabaseServerMonitorLinking.test.ts +753 -0
  177. package/Tests/Server/Utils/Monitor/MonitorActionTimestamps.test.ts +1 -0
  178. package/Tests/Server/Utils/Monitor/MonitorAlertCriteriaReferences.test.ts +1 -0
  179. package/Tests/Server/Utils/Monitor/MonitorAlertResourceLinking.test.ts +119 -0
  180. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +60 -25
  181. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorAffectedResourceEdgeCases.test.ts +1719 -0
  182. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorKubernetesAffectedResources.test.ts +1447 -0
  183. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorKubernetesRatioEmail.test.ts +352 -0
  184. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorPlatformMetricUnits.test.ts +717 -0
  185. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorPlatformRawScan.test.ts +2125 -0
  186. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorPlatformSeriesAffectedResources.test.ts +1288 -0
  187. package/Tests/Server/Utils/Monitor/MonitorDependencySuppressionCreatorSkip.test.ts +1 -0
  188. package/Tests/Server/Utils/Monitor/MonitorIncidentCriteriaReferences.test.ts +1 -0
  189. package/Tests/Server/Utils/Monitor/MonitorIncidentMemberRoleMembership.test.ts +1 -0
  190. package/Tests/Server/Utils/Monitor/MonitorIncidentResourceLinking.test.ts +88 -0
  191. package/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.ts +205 -0
  192. package/Tests/Server/Utils/Monitor/MonitorResourceContext.test.ts +62 -0
  193. package/Tests/Server/Utils/Monitor/MonitorResourceDatabaseMaintenance.test.ts +803 -0
  194. package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +133 -3
  195. package/Tests/Server/Utils/Monitor/MonitorSummaryPersistence.test.ts +1 -0
  196. package/Tests/Server/Utils/Monitor/PerSeriesRecoveryResolution.test.ts +472 -1
  197. package/Tests/Server/Utils/Monitor/PerSeriesSecondEntityAlerting.test.ts +1 -0
  198. package/Tests/Server/Utils/Monitor/SeriesResourceLinker.test.ts +236 -2
  199. package/Tests/Server/Utils/SeriesResourceLabels.test.ts +70 -0
  200. package/Tests/Server/Utils/StartServerProtobufContentType.test.ts +54 -0
  201. package/Tests/Server/Utils/Telemetry/DatabaseEndpointDiscovery.test.ts +1895 -0
  202. package/Tests/Server/Utils/Telemetry/EntityRegistry.test.ts +7 -0
  203. package/Tests/Server/Utils/Telemetry/LogExceptionExtractorSeverityGate.test.ts +90 -0
  204. package/Tests/Server/Utils/Telemetry/ResourceEntityFilter.test.ts +570 -0
  205. package/Tests/Server/Utils/Telemetry/ResourceFacetResolver.test.ts +97 -2
  206. package/Tests/Server/Utils/Telemetry/ServiceDependencyDiscovery.test.ts +1337 -0
  207. package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +295 -0
  208. package/Tests/Types/AI/AIResourceContext.test.ts +30 -0
  209. package/Tests/Types/DatabaseServer/DatabaseContainerClassifier.test.ts +3644 -0
  210. package/Tests/Types/DatabaseServer/DatabaseContainerCommand.test.ts +340 -0
  211. package/Tests/Types/DatabaseServer/DatabaseContainerCommandCorpus.ts +826 -0
  212. package/Tests/Types/DatabaseServer/DatabaseContainerCommandPostgres.test.ts +150 -0
  213. package/Tests/Types/DatabaseServer/DatabaseEndpoint.test.ts +2657 -0
  214. package/Tests/Types/DatabaseServer/DatabaseServerDiscoverySource.test.ts +64 -0
  215. package/Tests/Types/DatabaseServer/DatabaseServerEntityKeys.test.ts +952 -0
  216. package/Tests/Types/DatabaseServer/DatabaseServerMetricCatalog.test.ts +1161 -0
  217. package/Tests/Types/DatabaseServer/DatabaseSystem.test.ts +1514 -0
  218. package/Tests/Types/DatabaseServer/DatabaseTelemetryResolver.test.ts +1558 -0
  219. package/Tests/Types/Monitor/CephAlertTemplates.test.ts +255 -6
  220. package/Tests/Types/Monitor/DatabaseAlertTemplates.test.ts +2254 -0
  221. package/Tests/Types/Monitor/KubernetesAlertTemplates.test.ts +298 -0
  222. package/Tests/Types/Monitor/KubernetesMetricCatalog.test.ts +271 -0
  223. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +253 -9
  224. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +13 -5
  225. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +4 -2
  226. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +111 -2
  227. package/Tests/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.test.ts +61 -0
  228. package/Tests/Types/Monitor/SeriesContext/SeriesLabelDisplay.test.ts +114 -0
  229. package/Tests/Types/Monitor/Utils/KubernetesAgentEmittedMetrics.ts +181 -0
  230. package/Tests/Types/NetworkDevice/DiscoveredHostNamingStatus.test.ts +401 -0
  231. package/Tests/Types/Telemetry/ResourceEntityFacet.test.ts +4 -1
  232. package/Tests/Types/Telemetry/ResourceFacetCatalog.test.ts +24 -2
  233. package/Tests/UI/Components/Card.test.tsx +93 -2
  234. package/Tests/UI/Components/FeedOptions.test.ts +6 -0
  235. package/Tests/UI/Components/FeedOptionsButton.test.tsx +8 -1
  236. package/Tests/UI/Components/ForeignHiddenRuleResilience.test.tsx +1147 -0
  237. package/Tests/UI/Components/HeaderRightRail.test.tsx +41 -1
  238. package/Tests/UI/Components/LogsEntityNames.test.ts +16 -1
  239. package/Tests/UI/Components/LogsFacetSidebarHiddenFacets.test.tsx +7 -3
  240. package/Tests/UI/Components/ResourceFacetConfigs.test.ts +2 -1
  241. package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
  242. package/Tests/UI/Components/SrOnlyForeignRule.test.tsx +994 -0
  243. package/Tests/UI/Components/StatusPage/ResourceListSelection.test.tsx +34 -1
  244. package/Tests/UI/Components/TelemetryFacetSidebarHiddenFacets.test.tsx +4 -1
  245. package/Tests/UI/ForeignHiddenRuleGuard.test.ts +1951 -0
  246. package/Tests/UI/Rum/ReplayPlayerChrome.test.tsx +19 -1
  247. package/Tests/UI/Rum/ReplayTabSwitcher.test.tsx +19 -1
  248. package/Tests/UI/TailwindPlayCdnForeignHiddenRule.test.ts +1005 -0
  249. package/Tests/UI/ThemeGroupHoverReveal.test.ts +847 -0
  250. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +70 -0
  251. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +21 -0
  252. package/Tests/UI/Utils/ModelAPISsoRedirect.test.ts +127 -0
  253. package/Tests/UI/Utils/Navigation.test.ts +102 -0
  254. package/Tests/UI/Utils/Telemetry/TelemetryEntityNames.test.ts +23 -0
  255. package/Tests/Utils/LabelRuleImportExport.test.ts +5 -0
  256. package/Tests/Utils/MetricUnitUtil.test.ts +227 -2
  257. package/Tests/Utils/Monitor/MetricValueFormatter.test.ts +288 -2
  258. package/Tests/Utils/Monitor/PlatformResourceIdentityAndUnits.test.ts +1559 -0
  259. package/Tests/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.test.ts +2546 -0
  260. package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +315 -0
  261. package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +336 -1
  262. package/Tests/Utils/NetworkDiscovery/NetbiosNameUtil.test.ts +244 -0
  263. package/Tests/Utils/ValueFormatter.test.ts +50 -0
  264. package/Tests/tsconfig.json +16 -0
  265. package/Types/AI/AIResourceContext.ts +7 -0
  266. package/Types/Dashboard/DashboardTemplates.ts +2 -1
  267. package/Types/DatabaseServer/DatabaseConnectionSpan.ts +77 -0
  268. package/Types/DatabaseServer/DatabaseContainerClassifier.ts +2068 -0
  269. package/Types/DatabaseServer/DatabaseContainerCommand.ts +801 -0
  270. package/Types/DatabaseServer/DatabaseEndpoint.ts +1943 -0
  271. package/Types/DatabaseServer/DatabaseServerDiscoverySource.ts +68 -0
  272. package/Types/DatabaseServer/DatabaseServerMetricCatalog.ts +966 -0
  273. package/Types/DatabaseServer/DatabaseSystem.ts +2124 -0
  274. package/Types/DatabaseServer/DatabaseTelemetryResolver.ts +555 -0
  275. package/Types/Email/EmailTemplateType.ts +1 -0
  276. package/Types/Monitor/CephAlertTemplates.ts +18 -0
  277. package/Types/Monitor/DatabaseAlertTemplates.ts +2020 -0
  278. package/Types/Monitor/KubernetesAlertTemplates.ts +64 -24
  279. package/Types/Monitor/KubernetesMetricCatalog.ts +118 -19
  280. package/Types/Monitor/MetricMonitor/MetricCriteriaContext.ts +14 -0
  281. package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +93 -10
  282. package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +109 -8
  283. package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +36 -7
  284. package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +43 -2
  285. package/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.ts +41 -6
  286. package/Types/Monitor/SeriesContext/SeriesLabelDisplay.ts +26 -0
  287. package/Types/NetworkDevice/DiscoveredHostNamingStatus.ts +147 -0
  288. package/Types/Permission.ts +267 -0
  289. package/Types/Probe/ProbeApiIngestResponse.ts +8 -0
  290. package/Types/Rules/RuleCriteriaFieldRegistry.ts +10 -0
  291. package/Types/Rules/RuleRun.ts +12 -0
  292. package/Types/Telemetry/EntityType.ts +23 -0
  293. package/Types/Telemetry/ResourceFacetCatalog.ts +14 -0
  294. package/Types/Telemetry/ServiceType.ts +8 -0
  295. package/UI/Components/Banner/Banner.tsx +1 -1
  296. package/UI/Components/Card/Card.tsx +1 -1
  297. package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +2 -2
  298. package/UI/Components/Charts/Line/LineChart.tsx +7 -0
  299. package/UI/Components/CommandPalette/CommandPalette.tsx +1 -1
  300. package/UI/Components/Date/StartAndEndDate.tsx +5 -5
  301. package/UI/Components/Diagram/HorizontalStepChain.tsx +1 -1
  302. package/UI/Components/Feed/FeedOptionsButton.tsx +1 -1
  303. package/UI/Components/Forms/BasicForm.tsx +1 -1
  304. package/UI/Components/Header/Header.tsx +1 -1
  305. package/UI/Components/Header/HeaderIconDropdownButton.tsx +1 -1
  306. package/UI/Components/HeaderAlert/HeaderAlert.tsx +1 -1
  307. package/UI/Components/LogsViewer/components/FacetValueRow.tsx +1 -1
  308. package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +1 -1
  309. package/UI/Components/Modal/ModalFooter.tsx +1 -1
  310. package/UI/Components/ModelDetail/CardModelDetail.tsx +2 -2
  311. package/UI/Components/ModelTable/BaseModelTable.tsx +4 -4
  312. package/UI/Components/Navbar/NavBar.tsx +9 -2
  313. package/UI/Components/Navbar/NavBarMenuModal.tsx +2 -2
  314. package/UI/Components/Page/Page.tsx +1 -1
  315. package/UI/Components/Pagination/Pagination.tsx +3 -3
  316. package/UI/Components/ProgressButtons/ProgressButtonItem.tsx +1 -1
  317. package/UI/Components/SideMenu/SideMenu.tsx +4 -1
  318. package/UI/Components/StatusPage/ResourceGroupNavigator.tsx +4 -2
  319. package/UI/Components/StatusPage/ResourceList.tsx +6 -6
  320. package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +1 -1
  321. package/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.tsx +1 -1
  322. package/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.tsx +1 -1
  323. package/UI/Components/Workflow/ComponentsModal.tsx +2 -2
  324. package/UI/Components/Workflow/StepTraceViewer.tsx +1 -1
  325. package/UI/Styles/Theme.css +8 -1
  326. package/UI/Utils/Navigation.ts +89 -42
  327. package/UI/Utils/Telemetry/TelemetryEntityNames.ts +7 -0
  328. package/UI/Utils/TelemetryService.ts +4 -3
  329. package/Utils/LabelRuleImportExport.ts +2 -0
  330. package/Utils/MetricUnitUtil.ts +103 -11
  331. package/Utils/Monitor/MetricValueFormatter.ts +66 -13
  332. package/Utils/Monitor/PlatformMetricUnitUtil.ts +215 -0
  333. package/Utils/Monitor/PlatformResourceIdentity.ts +514 -0
  334. package/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.ts +425 -0
  335. package/Utils/NetworkDiscovery/DiscoveredHostUtil.ts +32 -0
  336. package/Utils/NetworkDiscovery/NetbiosNameUtil.ts +73 -0
  337. package/Utils/Telemetry/DatabaseServerEntityKeys.ts +275 -0
  338. package/Utils/Telemetry/EntityKey.ts +176 -0
  339. package/Utils/ValueFormatter.ts +16 -0
  340. package/build/dist/Models/DatabaseModels/Alert.js +54 -0
  341. package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
  342. package/build/dist/Models/DatabaseModels/DatabaseServer.js +1683 -0
  343. package/build/dist/Models/DatabaseModels/DatabaseServer.js.map +1 -0
  344. package/build/dist/Models/DatabaseModels/DatabaseServerEndpoint.js +559 -0
  345. package/build/dist/Models/DatabaseModels/DatabaseServerEndpoint.js.map +1 -0
  346. package/build/dist/Models/DatabaseModels/DatabaseServerFeed.js +648 -0
  347. package/build/dist/Models/DatabaseModels/DatabaseServerFeed.js.map +1 -0
  348. package/build/dist/Models/DatabaseModels/DatabaseServerLabelRule.js +522 -0
  349. package/build/dist/Models/DatabaseModels/DatabaseServerLabelRule.js.map +1 -0
  350. package/build/dist/Models/DatabaseModels/DatabaseServerOwnerRule.js +603 -0
  351. package/build/dist/Models/DatabaseModels/DatabaseServerOwnerRule.js.map +1 -0
  352. package/build/dist/Models/DatabaseModels/DatabaseServerOwnerTeam.js +506 -0
  353. package/build/dist/Models/DatabaseModels/DatabaseServerOwnerTeam.js.map +1 -0
  354. package/build/dist/Models/DatabaseModels/DatabaseServerOwnerUser.js +505 -0
  355. package/build/dist/Models/DatabaseModels/DatabaseServerOwnerUser.js.map +1 -0
  356. package/build/dist/Models/DatabaseModels/Incident.js +54 -0
  357. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  358. package/build/dist/Models/DatabaseModels/Index.js +16 -0
  359. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  360. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
  361. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +54 -0
  362. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
  363. package/build/dist/Models/DatabaseModels/TelemetryException.js +2 -0
  364. package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
  365. package/build/dist/Models/DatabaseModels/UserProjectSsoConsent.js +162 -0
  366. package/build/dist/Models/DatabaseModels/UserProjectSsoConsent.js.map +1 -0
  367. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795000000000-AddDatabaseServerTables.js +240 -0
  368. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795000000000-AddDatabaseServerTables.js.map +1 -0
  369. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795100000000-AddUserProjectSsoConsent.js +26 -0
  370. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795100000000-AddUserProjectSsoConsent.js.map +1 -0
  371. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
  372. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  373. package/build/dist/Server/Middleware/MultipartFormData.js +1 -1
  374. package/build/dist/Server/Middleware/TelemetryIngest.js +15 -8
  375. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  376. package/build/dist/Server/Services/AlertReminderRuleService.js +72 -23
  377. package/build/dist/Server/Services/AlertReminderRuleService.js.map +1 -1
  378. package/build/dist/Server/Services/DatabaseServerEndpointService.js +694 -0
  379. package/build/dist/Server/Services/DatabaseServerEndpointService.js.map +1 -0
  380. package/build/dist/Server/Services/DatabaseServerFeedService.js +110 -0
  381. package/build/dist/Server/Services/DatabaseServerFeedService.js.map +1 -0
  382. package/build/dist/Server/Services/DatabaseServerLabelRuleEngineService.js +272 -0
  383. package/build/dist/Server/Services/DatabaseServerLabelRuleEngineService.js.map +1 -0
  384. package/build/dist/Server/Services/DatabaseServerLabelRuleService.js +13 -0
  385. package/build/dist/Server/Services/DatabaseServerLabelRuleService.js.map +1 -0
  386. package/build/dist/Server/Services/DatabaseServerOwnerRuleEngineService.js +340 -0
  387. package/build/dist/Server/Services/DatabaseServerOwnerRuleEngineService.js.map +1 -0
  388. package/build/dist/Server/Services/DatabaseServerOwnerRuleService.js +13 -0
  389. package/build/dist/Server/Services/DatabaseServerOwnerRuleService.js.map +1 -0
  390. package/build/dist/Server/Services/DatabaseServerOwnerTeamService.js +160 -0
  391. package/build/dist/Server/Services/DatabaseServerOwnerTeamService.js.map +1 -0
  392. package/build/dist/Server/Services/DatabaseServerOwnerUserService.js +153 -0
  393. package/build/dist/Server/Services/DatabaseServerOwnerUserService.js.map +1 -0
  394. package/build/dist/Server/Services/DatabaseServerService.js +3272 -0
  395. package/build/dist/Server/Services/DatabaseServerService.js.map +1 -0
  396. package/build/dist/Server/Services/DatabaseService.js +8 -4
  397. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  398. package/build/dist/Server/Services/DockerResourceService.js +30 -3
  399. package/build/dist/Server/Services/DockerResourceService.js.map +1 -1
  400. package/build/dist/Server/Services/IncidentReminderRuleService.js +73 -23
  401. package/build/dist/Server/Services/IncidentReminderRuleService.js.map +1 -1
  402. package/build/dist/Server/Services/Index.js +16 -0
  403. package/build/dist/Server/Services/Index.js.map +1 -1
  404. package/build/dist/Server/Services/InventoryItemService.js +88 -5
  405. package/build/dist/Server/Services/InventoryItemService.js.map +1 -1
  406. package/build/dist/Server/Services/IoTDeviceService.js +111 -24
  407. package/build/dist/Server/Services/IoTDeviceService.js.map +1 -1
  408. package/build/dist/Server/Services/OpenTelemetryIngestService.js +24 -9
  409. package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
  410. package/build/dist/Server/Services/PodmanResourceService.js +30 -3
  411. package/build/dist/Server/Services/PodmanResourceService.js.map +1 -1
  412. package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js +75 -23
  413. package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js.map +1 -1
  414. package/build/dist/Server/Services/ServiceService.js +1 -1
  415. package/build/dist/Server/Services/ServiceService.js.map +1 -1
  416. package/build/dist/Server/Services/TelemetryUsageBillingService.js +23 -2
  417. package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
  418. package/build/dist/Server/Services/UserProjectSsoConsentService.js +79 -0
  419. package/build/dist/Server/Services/UserProjectSsoConsentService.js.map +1 -0
  420. package/build/dist/Server/Services/UserService.js +13 -1
  421. package/build/dist/Server/Services/UserService.js.map +1 -1
  422. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +18 -0
  423. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
  424. package/build/dist/Server/Types/Database/QueryHelper.js +26 -1
  425. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  426. package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js +46 -0
  427. package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js.map +1 -1
  428. package/build/dist/Server/Utils/Database/AffectedResourceRelations.js +6 -0
  429. package/build/dist/Server/Utils/Database/AffectedResourceRelations.js.map +1 -1
  430. package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +134 -13
  431. package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js.map +1 -1
  432. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +22 -6
  433. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  434. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +1489 -524
  435. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  436. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +22 -6
  437. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  438. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js +196 -6
  439. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -1
  440. package/build/dist/Server/Utils/Monitor/MonitorResource.js +36 -9
  441. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  442. package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js +1 -0
  443. package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js.map +1 -1
  444. package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js +175 -17
  445. package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js.map +1 -1
  446. package/build/dist/Server/Utils/Monitor/PerSeriesResolutionRootCause.js +29 -0
  447. package/build/dist/Server/Utils/Monitor/PerSeriesResolutionRootCause.js.map +1 -0
  448. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +211 -0
  449. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
  450. package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js +82 -10
  451. package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js.map +1 -1
  452. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +25 -0
  453. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
  454. package/build/dist/Server/Utils/StartServer.js +20 -4
  455. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  456. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js +2 -0
  457. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js.map +1 -1
  458. package/build/dist/Server/Utils/Telemetry/DatabaseEndpointDiscovery.js +442 -0
  459. package/build/dist/Server/Utils/Telemetry/DatabaseEndpointDiscovery.js.map +1 -0
  460. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +5 -1
  461. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  462. package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js +15 -1
  463. package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js.map +1 -1
  464. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +121 -5
  465. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -1
  466. package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js +12 -0
  467. package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js.map +1 -1
  468. package/build/dist/Server/Utils/Telemetry/ServiceDependencyDiscovery.js +438 -36
  469. package/build/dist/Server/Utils/Telemetry/ServiceDependencyDiscovery.js.map +1 -1
  470. package/build/dist/Server/Utils/Telemetry/Telemetry.js +12 -0
  471. package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
  472. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +17 -18
  473. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
  474. package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js +16 -10
  475. package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js.map +1 -1
  476. package/build/dist/Types/AI/AIResourceContext.js +7 -0
  477. package/build/dist/Types/AI/AIResourceContext.js.map +1 -1
  478. package/build/dist/Types/Dashboard/DashboardTemplates.js +2 -1
  479. package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
  480. package/build/dist/Types/DatabaseServer/DatabaseConnectionSpan.js +71 -0
  481. package/build/dist/Types/DatabaseServer/DatabaseConnectionSpan.js.map +1 -0
  482. package/build/dist/Types/DatabaseServer/DatabaseContainerClassifier.js +1462 -0
  483. package/build/dist/Types/DatabaseServer/DatabaseContainerClassifier.js.map +1 -0
  484. package/build/dist/Types/DatabaseServer/DatabaseContainerCommand.js +691 -0
  485. package/build/dist/Types/DatabaseServer/DatabaseContainerCommand.js.map +1 -0
  486. package/build/dist/Types/DatabaseServer/DatabaseEndpoint.js +1407 -0
  487. package/build/dist/Types/DatabaseServer/DatabaseEndpoint.js.map +1 -0
  488. package/build/dist/Types/DatabaseServer/DatabaseServerDiscoverySource.js +60 -0
  489. package/build/dist/Types/DatabaseServer/DatabaseServerDiscoverySource.js.map +1 -0
  490. package/build/dist/Types/DatabaseServer/DatabaseServerMetricCatalog.js +804 -0
  491. package/build/dist/Types/DatabaseServer/DatabaseServerMetricCatalog.js.map +1 -0
  492. package/build/dist/Types/DatabaseServer/DatabaseSystem.js +1860 -0
  493. package/build/dist/Types/DatabaseServer/DatabaseSystem.js.map +1 -0
  494. package/build/dist/Types/DatabaseServer/DatabaseTelemetryResolver.js +406 -0
  495. package/build/dist/Types/DatabaseServer/DatabaseTelemetryResolver.js.map +1 -0
  496. package/build/dist/Types/Email/EmailTemplateType.js +1 -0
  497. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  498. package/build/dist/Types/Monitor/CephAlertTemplates.js +18 -0
  499. package/build/dist/Types/Monitor/CephAlertTemplates.js.map +1 -1
  500. package/build/dist/Types/Monitor/DatabaseAlertTemplates.js +1518 -0
  501. package/build/dist/Types/Monitor/DatabaseAlertTemplates.js.map +1 -0
  502. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +57 -24
  503. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
  504. package/build/dist/Types/Monitor/KubernetesMetricCatalog.js +104 -18
  505. package/build/dist/Types/Monitor/KubernetesMetricCatalog.js.map +1 -1
  506. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +80 -3
  507. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -1
  508. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +10 -3
  509. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -1
  510. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +29 -0
  511. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -1
  512. package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js +21 -6
  513. package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js.map +1 -1
  514. package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js +25 -0
  515. package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js.map +1 -1
  516. package/build/dist/Types/NetworkDevice/DiscoveredHostNamingStatus.js +136 -0
  517. package/build/dist/Types/NetworkDevice/DiscoveredHostNamingStatus.js.map +1 -0
  518. package/build/dist/Types/Permission.js +234 -0
  519. package/build/dist/Types/Permission.js.map +1 -1
  520. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +10 -0
  521. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
  522. package/build/dist/Types/Rules/RuleRun.js +4 -0
  523. package/build/dist/Types/Rules/RuleRun.js.map +1 -1
  524. package/build/dist/Types/Telemetry/EntityType.js +23 -0
  525. package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
  526. package/build/dist/Types/Telemetry/ResourceFacetCatalog.js +14 -0
  527. package/build/dist/Types/Telemetry/ResourceFacetCatalog.js.map +1 -1
  528. package/build/dist/Types/Telemetry/ServiceType.js +8 -0
  529. package/build/dist/Types/Telemetry/ServiceType.js.map +1 -1
  530. package/build/dist/UI/Components/Banner/Banner.js +1 -1
  531. package/build/dist/UI/Components/Banner/Banner.js.map +1 -1
  532. package/build/dist/UI/Components/Card/Card.js +1 -1
  533. package/build/dist/UI/Components/Card/Card.js.map +1 -1
  534. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +2 -2
  535. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
  536. package/build/dist/UI/Components/Charts/Line/LineChart.js +1 -1
  537. package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
  538. package/build/dist/UI/Components/CommandPalette/CommandPalette.js +1 -1
  539. package/build/dist/UI/Components/CommandPalette/CommandPalette.js.map +1 -1
  540. package/build/dist/UI/Components/Date/StartAndEndDate.js +5 -5
  541. package/build/dist/UI/Components/Date/StartAndEndDate.js.map +1 -1
  542. package/build/dist/UI/Components/Diagram/HorizontalStepChain.js +1 -1
  543. package/build/dist/UI/Components/Diagram/HorizontalStepChain.js.map +1 -1
  544. package/build/dist/UI/Components/Feed/FeedOptionsButton.js +1 -1
  545. package/build/dist/UI/Components/Feed/FeedOptionsButton.js.map +1 -1
  546. package/build/dist/UI/Components/Forms/BasicForm.js +1 -1
  547. package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
  548. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +1 -1
  549. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
  550. package/build/dist/UI/Components/HeaderAlert/HeaderAlert.js +1 -1
  551. package/build/dist/UI/Components/HeaderAlert/HeaderAlert.js.map +1 -1
  552. package/build/dist/UI/Components/LogsViewer/components/FacetValueRow.js +1 -1
  553. package/build/dist/UI/Components/LogsViewer/components/FacetValueRow.js.map +1 -1
  554. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +1 -1
  555. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
  556. package/build/dist/UI/Components/Modal/ModalFooter.js +1 -1
  557. package/build/dist/UI/Components/Modal/ModalFooter.js.map +1 -1
  558. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +2 -2
  559. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
  560. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +4 -4
  561. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  562. package/build/dist/UI/Components/Navbar/NavBar.js +9 -2
  563. package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
  564. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +2 -2
  565. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
  566. package/build/dist/UI/Components/Page/Page.js +1 -1
  567. package/build/dist/UI/Components/Page/Page.js.map +1 -1
  568. package/build/dist/UI/Components/Pagination/Pagination.js +3 -3
  569. package/build/dist/UI/Components/Pagination/Pagination.js.map +1 -1
  570. package/build/dist/UI/Components/ProgressButtons/ProgressButtonItem.js +1 -1
  571. package/build/dist/UI/Components/ProgressButtons/ProgressButtonItem.js.map +1 -1
  572. package/build/dist/UI/Components/SideMenu/SideMenu.js +4 -1
  573. package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
  574. package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js +3 -1
  575. package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js.map +1 -1
  576. package/build/dist/UI/Components/StatusPage/ResourceList.js +6 -6
  577. package/build/dist/UI/Components/StatusPage/ResourceList.js.map +1 -1
  578. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +1 -1
  579. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
  580. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js +1 -1
  581. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js.map +1 -1
  582. package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js +1 -1
  583. package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js.map +1 -1
  584. package/build/dist/UI/Components/Workflow/ComponentsModal.js +2 -2
  585. package/build/dist/UI/Components/Workflow/ComponentsModal.js.map +1 -1
  586. package/build/dist/UI/Components/Workflow/StepTraceViewer.js +1 -1
  587. package/build/dist/UI/Components/Workflow/StepTraceViewer.js.map +1 -1
  588. package/build/dist/UI/Utils/Navigation.js +66 -33
  589. package/build/dist/UI/Utils/Navigation.js.map +1 -1
  590. package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js +7 -0
  591. package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js.map +1 -1
  592. package/build/dist/UI/Utils/TelemetryService.js +3 -2
  593. package/build/dist/UI/Utils/TelemetryService.js.map +1 -1
  594. package/build/dist/Utils/LabelRuleImportExport.js +2 -0
  595. package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
  596. package/build/dist/Utils/MetricUnitUtil.js +77 -13
  597. package/build/dist/Utils/MetricUnitUtil.js.map +1 -1
  598. package/build/dist/Utils/Monitor/MetricValueFormatter.js +58 -13
  599. package/build/dist/Utils/Monitor/MetricValueFormatter.js.map +1 -1
  600. package/build/dist/Utils/Monitor/PlatformMetricUnitUtil.js +161 -0
  601. package/build/dist/Utils/Monitor/PlatformMetricUnitUtil.js.map +1 -0
  602. package/build/dist/Utils/Monitor/PlatformResourceIdentity.js +323 -0
  603. package/build/dist/Utils/Monitor/PlatformResourceIdentity.js.map +1 -0
  604. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.js +270 -0
  605. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.js.map +1 -0
  606. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js +23 -0
  607. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js.map +1 -1
  608. package/build/dist/Utils/NetworkDiscovery/NetbiosNameUtil.js +61 -0
  609. package/build/dist/Utils/NetworkDiscovery/NetbiosNameUtil.js.map +1 -1
  610. package/build/dist/Utils/Telemetry/DatabaseServerEntityKeys.js +178 -0
  611. package/build/dist/Utils/Telemetry/DatabaseServerEntityKeys.js.map +1 -0
  612. package/build/dist/Utils/Telemetry/EntityKey.js +133 -0
  613. package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -1
  614. package/build/dist/Utils/ValueFormatter.js +15 -0
  615. package/build/dist/Utils/ValueFormatter.js.map +1 -1
  616. package/package.json +1 -1
  617. package/tsconfig.tests.json +7 -5
@@ -0,0 +1,1558 @@
1
+ import {
2
+ DATABASE_ADDRESS_ATTRIBUTES,
3
+ DATABASE_PORT_ATTRIBUTES,
4
+ DATABASE_SYSTEM_ATTRIBUTES,
5
+ isStableCollectorEndpoint,
6
+ resolveDatabaseCallTarget,
7
+ resolveDatabaseFromResourceAttributes,
8
+ } from "../../../Types/DatabaseServer/DatabaseTelemetryResolver";
9
+ import {
10
+ buildDatabaseCallerContext,
11
+ canonicalizeDatabaseEndpoint,
12
+ DatabaseCallerContext,
13
+ DatabaseEndpoint,
14
+ DatabaseEndpointScope,
15
+ } from "../../../Types/DatabaseServer/DatabaseEndpoint";
16
+ import {
17
+ getDatabaseReceiverSystemHint,
18
+ normalizeDatabaseSystem,
19
+ } from "../../../Types/DatabaseServer/DatabaseSystem";
20
+ import { describe, expect, test } from "@jest/globals";
21
+
22
+ type CallTarget = {
23
+ system: string;
24
+ endpoint: DatabaseEndpoint;
25
+ scope: DatabaseEndpointScope;
26
+ } | null;
27
+
28
+ type ResourceResolution = {
29
+ system: string;
30
+ endpoint: DatabaseEndpoint | null;
31
+ linkedDatabaseServerId: string | null;
32
+ displayName: string | null;
33
+ version: string | null;
34
+ endpointIsStable: boolean;
35
+ allowCreate: boolean;
36
+ } | null;
37
+
38
+ const VM_CALLER: DatabaseCallerContext = {
39
+ hostName: "app-7",
40
+ isEphemeral: false,
41
+ };
42
+
43
+ const K8S_CALLER: DatabaseCallerContext = {
44
+ kubernetesNamespace: "shop",
45
+ kubernetesClusterName: "prod-eu",
46
+ hostName: "checkout-7d9f",
47
+ isEphemeral: true,
48
+ };
49
+
50
+ const LINKED_ID: string = "5f2b7c1e-8d3a-4b6f-9c0d-1e2f3a4b5c6d";
51
+
52
+ const CONTRIB: string =
53
+ "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/";
54
+
55
+ function callTarget(
56
+ attributes: Record<string, unknown>,
57
+ caller: DatabaseCallerContext = VM_CALLER,
58
+ ): CallTarget {
59
+ return resolveDatabaseCallTarget({
60
+ getAttribute: (key: string): unknown => {
61
+ return attributes[key];
62
+ },
63
+ caller,
64
+ });
65
+ }
66
+
67
+ function fromResource(
68
+ attributes: Record<string, unknown>,
69
+ receiverSystemHint?: string | null,
70
+ ): ResourceResolution {
71
+ return resolveDatabaseFromResourceAttributes({
72
+ attributes,
73
+ receiverSystemHint,
74
+ });
75
+ }
76
+
77
+ describe("attribute precedence lists", () => {
78
+ test("stable semconv names come first, legacy names after", () => {
79
+ expect(DATABASE_SYSTEM_ATTRIBUTES).toEqual(["db.system.name", "db.system"]);
80
+ expect(DATABASE_ADDRESS_ATTRIBUTES).toEqual([
81
+ "server.address",
82
+ "net.peer.name",
83
+ "network.peer.address",
84
+ "net.sock.peer.addr",
85
+ ]);
86
+ expect(DATABASE_PORT_ATTRIBUTES).toEqual([
87
+ "server.port",
88
+ "net.peer.port",
89
+ "network.peer.port",
90
+ "net.sock.peer.port",
91
+ ]);
92
+ });
93
+ });
94
+
95
+ describe("resolveDatabaseCallTarget", () => {
96
+ test("a stable-semconv span resolves to its endpoint", () => {
97
+ expect(
98
+ callTarget({
99
+ "db.system.name": "postgresql",
100
+ "server.address": "db.prod.example.com",
101
+ }),
102
+ ).toEqual({
103
+ system: "postgresql",
104
+ endpoint: { host: "db.prod.example.com", port: 5432 },
105
+ scope: "global",
106
+ });
107
+ });
108
+
109
+ test("legacy attributes resolve the same endpoint", () => {
110
+ expect(
111
+ callTarget({
112
+ "db.system": "postgres",
113
+ "net.peer.name": "db.prod.example.com",
114
+ "net.peer.port": 5432,
115
+ }),
116
+ ).toEqual(
117
+ callTarget({
118
+ "db.system.name": "postgresql",
119
+ "server.address": "db.prod.example.com",
120
+ }),
121
+ );
122
+ });
123
+
124
+ test("returns before reading anything else when no system is present", () => {
125
+ const readKeys: Array<string> = [];
126
+ const getAttribute: (key: string) => unknown = (key: string): unknown => {
127
+ readKeys.push(key);
128
+ return key === "server.address" ? "db.prod" : undefined;
129
+ };
130
+ expect(
131
+ resolveDatabaseCallTarget({ getAttribute, caller: VM_CALLER }),
132
+ ).toBeNull();
133
+ expect(readKeys).toEqual(DATABASE_SYSTEM_ATTRIBUTES);
134
+ });
135
+
136
+ test("an empty-string system counts as absent; the legacy one is used", () => {
137
+ expect(
138
+ callTarget({
139
+ "db.system.name": "",
140
+ "db.system": "mysql",
141
+ "server.address": "db.prod",
142
+ })?.system,
143
+ ).toBe("mysql");
144
+ });
145
+
146
+ test("the engine is normalized", () => {
147
+ expect(
148
+ callTarget({ "db.system.name": "MSSQL", "server.address": "sql.prod" }),
149
+ ).toEqual({
150
+ system: "microsoft.sql_server",
151
+ endpoint: { host: "sql.prod", port: 1433 },
152
+ scope: "global",
153
+ });
154
+ });
155
+
156
+ test("address precedence: server.address > net.peer.name > network.peer.address > net.sock.peer.addr", () => {
157
+ const all: Record<string, unknown> = {
158
+ "db.system.name": "redis",
159
+ "server.address": "a.prod",
160
+ "net.peer.name": "b.prod",
161
+ "network.peer.address": "c.prod",
162
+ "net.sock.peer.addr": "d.prod",
163
+ };
164
+ expect(callTarget(all)?.endpoint.host).toBe("a.prod");
165
+ expect(callTarget({ ...all, "server.address": "" })?.endpoint.host).toBe(
166
+ "b.prod",
167
+ );
168
+ expect(
169
+ callTarget({ ...all, "server.address": "", "net.peer.name": null })
170
+ ?.endpoint.host,
171
+ ).toBe("c.prod");
172
+ expect(
173
+ callTarget({
174
+ ...all,
175
+ "server.address": undefined,
176
+ "net.peer.name": undefined,
177
+ "network.peer.address": undefined,
178
+ })?.endpoint.host,
179
+ ).toBe("d.prod");
180
+ });
181
+
182
+ test("a scrubbed address does NOT fall back to the next attribute", () => {
183
+ /*
184
+ * Mirrors the discovery SQL's multiIf(x != '', …): the first non-empty
185
+ * attribute is THE address, so the ingest key and the cron endpoint
186
+ * agree even when that value is unusable.
187
+ */
188
+ expect(
189
+ callTarget({
190
+ "db.system.name": "postgresql",
191
+ "server.address": "[REDACTED]",
192
+ "network.peer.address": "10.0.0.5",
193
+ }),
194
+ ).toBeNull();
195
+ });
196
+
197
+ test("port precedence and the engine default", () => {
198
+ expect(
199
+ callTarget({
200
+ "db.system.name": "postgresql",
201
+ "server.address": "db.prod",
202
+ "server.port": 6543,
203
+ "network.peer.port": 5432,
204
+ })?.endpoint.port,
205
+ ).toBe(6543);
206
+ expect(
207
+ callTarget({
208
+ "db.system.name": "postgresql",
209
+ "server.address": "db.prod",
210
+ "network.peer.port": "6432",
211
+ })?.endpoint.port,
212
+ ).toBe(6432);
213
+ expect(
214
+ callTarget({
215
+ "db.system.name": "postgresql",
216
+ "server.address": "db.prod",
217
+ })?.endpoint.port,
218
+ ).toBe(5432);
219
+ });
220
+
221
+ test("an address:port value is honoured when no port attribute exists", () => {
222
+ expect(
223
+ callTarget({
224
+ "db.system.name": "postgresql",
225
+ "server.address": "db.prod:6543",
226
+ })?.endpoint.port,
227
+ ).toBe(6543);
228
+ });
229
+
230
+ test("no address → null (an engine alone is not a server)", () => {
231
+ expect(callTarget({ "db.system.name": "postgresql" })).toBeNull();
232
+ expect(
233
+ callTarget({ "db.system.name": "postgresql", "server.address": "" }),
234
+ ).toBeNull();
235
+ });
236
+
237
+ test.each([
238
+ "localhost",
239
+ "127.0.0.1",
240
+ "::1",
241
+ "host.docker.internal",
242
+ "(local)",
243
+ ])("loopback / host-relative %s is never an identity", (address: string) => {
244
+ expect(
245
+ callTarget({ "db.system.name": "postgresql", "server.address": address }),
246
+ ).toBeNull();
247
+ expect(
248
+ callTarget(
249
+ { "db.system.name": "postgresql", "server.address": address },
250
+ K8S_CALLER,
251
+ ),
252
+ ).toBeNull();
253
+ });
254
+
255
+ test.each(["[REDACTED]", "[HASHED:ab12cd34]", "***.***.***.***"])(
256
+ "scrubbed address %s → null",
257
+ (address: string) => {
258
+ expect(
259
+ callTarget({ "db.system.name": "redis", "server.address": address }),
260
+ ).toBeNull();
261
+ },
262
+ );
263
+
264
+ test("a Kubernetes caller's short name expands and is cluster-qualified", () => {
265
+ expect(
266
+ callTarget(
267
+ { "db.system.name": "postgresql", "server.address": "pg" },
268
+ K8S_CALLER,
269
+ ),
270
+ ).toEqual({
271
+ system: "postgresql",
272
+ endpoint: {
273
+ host: "pg.shop.svc.cluster.local",
274
+ port: 5432,
275
+ kubernetesClusterName: "prod-eu",
276
+ },
277
+ scope: "global",
278
+ });
279
+ });
280
+
281
+ test("scope: bare names, unqualified cluster DNS and private IPs are local", () => {
282
+ expect(
283
+ callTarget({ "db.system.name": "postgresql", "server.address": "db" })
284
+ ?.scope,
285
+ ).toBe("local");
286
+ expect(
287
+ callTarget({
288
+ "db.system.name": "postgresql",
289
+ "server.address": "pg.shop.svc.cluster.local",
290
+ })?.scope,
291
+ ).toBe("local");
292
+ expect(
293
+ callTarget({
294
+ "db.system.name": "postgresql",
295
+ "server.address": "10.0.0.5",
296
+ })?.scope,
297
+ ).toBe("local");
298
+ expect(
299
+ callTarget(
300
+ { "db.system.name": "postgresql", "server.address": "10.0.0.5" },
301
+ K8S_CALLER,
302
+ )?.scope,
303
+ ).toBe("global");
304
+ });
305
+
306
+ test("unknown engines still resolve (the key is engine-agnostic)", () => {
307
+ expect(
308
+ callTarget({
309
+ "db.system.name": "acme-db",
310
+ "server.address": "acme.prod",
311
+ }),
312
+ ).toEqual({
313
+ system: "acme-db",
314
+ endpoint: { host: "acme.prod", port: null },
315
+ scope: "global",
316
+ });
317
+ });
318
+
319
+ test("a SQL Server named instance beside the address is read like the canonicalizer defines it", () => {
320
+ const base: Record<string, unknown> = {
321
+ "db.system.name": "microsoft.sql_server",
322
+ "server.address": "sql1.corp.example.com",
323
+ };
324
+
325
+ for (const [attributes, instance] of [
326
+ [{ ...base, "db.mssql.instance_name": "INST01" }, "INST01"],
327
+ [{ ...base, "db.namespace": "INST02|orders" }, "INST02"],
328
+ ] as Array<[Record<string, unknown>, string]>) {
329
+ expect(callTarget(attributes)?.endpoint).toEqual(
330
+ canonicalizeDatabaseEndpoint({
331
+ system: "microsoft.sql_server",
332
+ address: "sql1.corp.example.com",
333
+ instance,
334
+ caller: VM_CALLER,
335
+ purpose: "client-call",
336
+ }),
337
+ );
338
+ }
339
+
340
+ // Two instances on one host are two servers…
341
+ expect(
342
+ callTarget({ ...base, "db.mssql.instance_name": "INST01" })?.endpoint,
343
+ ).not.toEqual(
344
+ callTarget({ ...base, "db.mssql.instance_name": "INST02" })?.endpoint,
345
+ );
346
+ });
347
+
348
+ test("an instance-shaped db.namespace means nothing for another engine", () => {
349
+ expect(
350
+ callTarget({
351
+ "db.system.name": "postgresql",
352
+ "server.address": "db.prod.example.com",
353
+ "db.namespace": "INST01|orders",
354
+ "db.mssql.instance_name": "INST01",
355
+ })?.endpoint,
356
+ ).toEqual(
357
+ callTarget({
358
+ "db.system.name": "postgresql",
359
+ "server.address": "db.prod.example.com",
360
+ })?.endpoint,
361
+ );
362
+ });
363
+
364
+ test("a missing caller is treated as ephemeral, never throws", () => {
365
+ expect(
366
+ resolveDatabaseCallTarget({
367
+ getAttribute: (key: string): unknown => {
368
+ return (
369
+ {
370
+ "db.system.name": "postgresql",
371
+ "server.address": "db.prod",
372
+ } as Record<string, unknown>
373
+ )[key];
374
+ },
375
+ caller: undefined as unknown as DatabaseCallerContext,
376
+ })?.endpoint,
377
+ ).toEqual({ host: "db.prod", port: 5432 });
378
+ expect(
379
+ resolveDatabaseCallTarget(
380
+ undefined as unknown as {
381
+ getAttribute: (key: string) => unknown;
382
+ caller: DatabaseCallerContext;
383
+ },
384
+ ),
385
+ ).toBeNull();
386
+ });
387
+
388
+ test("object-valued attributes are ignored", () => {
389
+ expect(
390
+ callTarget({
391
+ "db.system.name": { value: "postgresql" },
392
+ "server.address": "db.prod",
393
+ }),
394
+ ).toBeNull();
395
+ });
396
+ });
397
+
398
+ describe("resolveDatabaseFromResourceAttributes — which batches are databases", () => {
399
+ test("a receiver hint alone decides the engine", () => {
400
+ expect(
401
+ fromResource(
402
+ { "server.address": "db.prod", "server.port": "5432" },
403
+ "postgresql",
404
+ ),
405
+ ).toEqual({
406
+ system: "postgresql",
407
+ endpoint: { host: "db.prod", port: 5432 },
408
+ linkedDatabaseServerId: null,
409
+ displayName: "PostgreSQL db.prod:5432",
410
+ version: null,
411
+ endpointIsStable: true,
412
+ allowCreate: true,
413
+ });
414
+ });
415
+
416
+ test("the hint is refined by db.system.name (MariaDB via the mysql receiver)", () => {
417
+ // The stamp wins, normalized the way the engine catalog normalizes it.
418
+ expect(
419
+ fromResource(
420
+ { "db.system.name": "mariadb", "server.address": "db.prod" },
421
+ "mysql",
422
+ )?.system,
423
+ ).toBe(normalizeDatabaseSystem("mariadb"));
424
+ expect(
425
+ fromResource(
426
+ { "db.system.name": "cockroachdb", "server.address": "crdb.prod" },
427
+ "postgresql",
428
+ )?.system,
429
+ ).toBe("cockroachdb");
430
+ });
431
+
432
+ test("an explicit stamp (db.system.name + server.address) is enough", () => {
433
+ expect(
434
+ fromResource({
435
+ "db.system.name": "redis",
436
+ "server.address": "cache.prod",
437
+ "oneuptime.database.agent": "true",
438
+ }),
439
+ ).toMatchObject({
440
+ system: "redis",
441
+ endpoint: { host: "cache.prod", port: 6379 },
442
+ });
443
+ });
444
+
445
+ test("an application resource is never a database", () => {
446
+ // No hint, no stamp: an app that merely has server.address…
447
+ expect(
448
+ fromResource({
449
+ "service.name": "checkout",
450
+ "server.address": "db.prod",
451
+ "host.name": "app-7",
452
+ }),
453
+ ).toBeNull();
454
+ // …or a db.system.name without an address or a linked id.
455
+ expect(
456
+ fromResource({ "service.name": "checkout", "db.system.name": "redis" }),
457
+ ).toBeNull();
458
+ expect(fromResource({})).toBeNull();
459
+ });
460
+
461
+ test("a linked row id makes the batch a database even without an endpoint", () => {
462
+ expect(fromResource({ "oneuptime.database.server.id": LINKED_ID })).toEqual(
463
+ {
464
+ system: "",
465
+ endpoint: null,
466
+ linkedDatabaseServerId: LINKED_ID,
467
+ displayName: null,
468
+ version: null,
469
+ // No endpoint: nothing to create a row for or claim as an alias.
470
+ endpointIsStable: false,
471
+ allowCreate: false,
472
+ },
473
+ );
474
+ expect(
475
+ fromResource({
476
+ "oneuptime.database.server.id": ` ${LINKED_ID.toUpperCase()} `,
477
+ "db.system.name": "postgres",
478
+ }),
479
+ ).toMatchObject({
480
+ system: "postgresql",
481
+ linkedDatabaseServerId: LINKED_ID,
482
+ });
483
+ });
484
+
485
+ test("the legacy db.system stamp counts like db.system.name (receivers that predate the rename)", () => {
486
+ expect(
487
+ fromResource({
488
+ "db.system": "redis",
489
+ "server.address": "cache.prod",
490
+ "oneuptime.database.agent": "true",
491
+ }),
492
+ ).toMatchObject({
493
+ system: "redis",
494
+ endpoint: { host: "cache.prod", port: 6379 },
495
+ displayName: "Redis cache.prod:6379",
496
+ });
497
+ // …with a linked id and no address, too.
498
+ expect(
499
+ fromResource({
500
+ "oneuptime.database.server.id": LINKED_ID,
501
+ "db.system": "postgres",
502
+ }),
503
+ ).toMatchObject({
504
+ system: "postgresql",
505
+ linkedDatabaseServerId: LINKED_ID,
506
+ });
507
+ // …and it refines a receiver hint exactly as db.system.name does.
508
+ expect(
509
+ fromResource(
510
+ { "db.system": "mariadb", "server.address": "db.prod" },
511
+ "mysql",
512
+ )?.system,
513
+ ).toBe("mariadb");
514
+ });
515
+
516
+ test("db.system.name wins over db.system; an empty or blank one falls back to it", () => {
517
+ expect(
518
+ fromResource({
519
+ "db.system.name": "mariadb",
520
+ "db.system": "mysql",
521
+ "server.address": "db.prod",
522
+ })?.system,
523
+ ).toBe("mariadb");
524
+ for (const blank of ["", " "]) {
525
+ expect(
526
+ fromResource({
527
+ "db.system.name": blank,
528
+ "db.system": "postgresql",
529
+ "server.address": "db.prod",
530
+ })?.system,
531
+ ).toBe("postgresql");
532
+ }
533
+ // The stored resource.-prefixed spelling of the legacy key is read too.
534
+ expect(
535
+ fromResource({
536
+ "resource.db.system": "redis",
537
+ "resource.server.address": "cache.prod",
538
+ })?.system,
539
+ ).toBe("redis");
540
+ });
541
+
542
+ test("a db.system stamp alone (no address, no link) is still not a database", () => {
543
+ expect(
544
+ fromResource({ "service.name": "checkout", "db.system": "redis" }),
545
+ ).toBeNull();
546
+ // A non-string, object-valued stamp is no engine at all.
547
+ expect(
548
+ fromResource({
549
+ "db.system": { name: "redis" },
550
+ "server.address": "cache.prod",
551
+ }),
552
+ ).toBeNull();
553
+ });
554
+
555
+ test("a non-UUID linked id is ignored", () => {
556
+ expect(
557
+ fromResource({ "oneuptime.database.server.id": "not-a-uuid" }),
558
+ ).toBeNull();
559
+ expect(
560
+ fromResource(
561
+ { "oneuptime.database.server.id": "123", "server.address": "db.prod" },
562
+ "postgresql",
563
+ )?.linkedDatabaseServerId,
564
+ ).toBeNull();
565
+ });
566
+ });
567
+
568
+ describe("resolveDatabaseFromResourceAttributes — endpoint precedence", () => {
569
+ test("server.address (+ server.port) first", () => {
570
+ expect(
571
+ fromResource(
572
+ {
573
+ "server.address": "db.prod",
574
+ "server.port": 6543,
575
+ "service.instance.id": "other.prod:5432",
576
+ },
577
+ "postgresql",
578
+ )?.endpoint,
579
+ ).toEqual({ host: "db.prod", port: 6543 });
580
+ });
581
+
582
+ test("then service.instance.id parsed as host[:port] (PG legacy)", () => {
583
+ expect(
584
+ fromResource({ "service.instance.id": "db.prod:5433" }, "postgresql")
585
+ ?.endpoint,
586
+ ).toEqual({ host: "db.prod", port: 5433 });
587
+ });
588
+
589
+ test("service.instance.id host:port/service is read as host:port (Oracle)", () => {
590
+ expect(
591
+ fromResource(
592
+ { "service.instance.id": "ora.prod:1521/ORCLPDB1" },
593
+ "oracle.db",
594
+ )?.endpoint,
595
+ ).toEqual({ host: "ora.prod", port: 1521 });
596
+ });
597
+
598
+ test("service.instance.id host\\instance is read through the endpoint canonicalizer (SQL Server)", () => {
599
+ const endpoint: DatabaseEndpoint | null | undefined = fromResource(
600
+ { "service.instance.id": "sql.prod\\REPORTING" },
601
+ "microsoft.sql_server",
602
+ )?.endpoint;
603
+
604
+ // The server is the address part; a named instance never replaces it.
605
+ expect(endpoint?.host.split("\\")[0]).toBe("sql.prod");
606
+ expect(endpoint).toEqual(
607
+ canonicalizeDatabaseEndpoint({
608
+ system: "microsoft.sql_server",
609
+ address: "sql.prod\\REPORTING",
610
+ caller: buildDatabaseCallerContext({}),
611
+ purpose: "collector",
612
+ }),
613
+ );
614
+ });
615
+
616
+ test("a UUID-shaped service.instance.id is ignored (MySQL / MongoDB)", () => {
617
+ expect(
618
+ fromResource(
619
+ {
620
+ "service.instance.id": "8e9b4f43-5c1f-5a88-9a57-6d3c0a9f1b2e",
621
+ "mysql.instance.endpoint": "mysql.prod:3306",
622
+ },
623
+ "mysql",
624
+ )?.endpoint,
625
+ ).toEqual({ host: "mysql.prod", port: 3306 });
626
+ expect(
627
+ fromResource(
628
+ { "service.instance.id": "8e9b4f43-5c1f-5a88-9a57-6d3c0a9f1b2e" },
629
+ "mongodb",
630
+ ),
631
+ ).toBeNull();
632
+ });
633
+
634
+ test("mongodb_atlas.host.name + mongodb_atlas.process.port (Atlas)", () => {
635
+ expect(
636
+ fromResource(
637
+ {
638
+ "mongodb_atlas.host.name": "atlas-abc-shard-00-00.xyz.mongodb.net",
639
+ "mongodb_atlas.process.port": 27017,
640
+ "mongodb_atlas.project.name": "prod",
641
+ },
642
+ "mongodb",
643
+ )?.endpoint,
644
+ ).toEqual({
645
+ host: "atlas-abc-shard-00-00.xyz.mongodb.net",
646
+ port: 27017,
647
+ });
648
+ });
649
+
650
+ describe("SAP HANA (the saphana receiver: db.system + saphana.host)", () => {
651
+ // What the receiver stamps: the legacy engine key and the host alone.
652
+ const SAPHANA: Record<string, unknown> = {
653
+ "db.system": "saphana",
654
+ "saphana.host": "hana.prod.example.com",
655
+ };
656
+ const SAPHANA_HINT: string | null = getDatabaseReceiverSystemHint([
657
+ `${CONTRIB}saphanareceiver`,
658
+ ]);
659
+
660
+ test("the receiver's scope is the hint", () => {
661
+ expect(SAPHANA_HINT).toBe("sap.hana");
662
+ });
663
+
664
+ test("saphana.host is the endpoint, on the engine's default port", () => {
665
+ expect(fromResource(SAPHANA, SAPHANA_HINT)).toEqual({
666
+ system: "sap.hana",
667
+ endpoint: { host: "hana.prod.example.com", port: 30015 },
668
+ linkedDatabaseServerId: null,
669
+ displayName: "SAP HANA hana.prod.example.com:30015",
670
+ version: null,
671
+ endpointIsStable: true,
672
+ allowCreate: true,
673
+ });
674
+ });
675
+
676
+ test("a port inside saphana.host is honoured", () => {
677
+ expect(
678
+ fromResource(
679
+ { ...SAPHANA, "saphana.host": "hana.prod.example.com:39017" },
680
+ SAPHANA_HINT,
681
+ )?.endpoint,
682
+ ).toEqual({ host: "hana.prod.example.com", port: 39017 });
683
+ });
684
+
685
+ test("the legacy engine stamp alone names the engine (no scope hint)", () => {
686
+ // Linked: the id identifies the row, the host keys the rows.
687
+ expect(
688
+ fromResource({
689
+ ...SAPHANA,
690
+ "oneuptime.database.server.id": LINKED_ID,
691
+ }),
692
+ ).toMatchObject({
693
+ system: "sap.hana",
694
+ linkedDatabaseServerId: LINKED_ID,
695
+ endpoint: { host: "hana.prod.example.com", port: 30015 },
696
+ });
697
+ /*
698
+ * Unlinked, with no server.address and no hint, it is not an explicit
699
+ * stamp: nothing says this resource is the database itself.
700
+ */
701
+ expect(fromResource(SAPHANA)).toBeNull();
702
+ });
703
+
704
+ test("saphana.host is the last resort: server.address wins", () => {
705
+ expect(
706
+ fromResource(
707
+ {
708
+ ...SAPHANA,
709
+ "server.address": "hana-vip.prod.example.com",
710
+ "server.port": 30041,
711
+ },
712
+ SAPHANA_HINT,
713
+ )?.endpoint,
714
+ ).toEqual({ host: "hana-vip.prod.example.com", port: 30041 });
715
+ });
716
+
717
+ test("a HANA-internal single-label host keys the rows but never creates one", () => {
718
+ // HANA reports its own hostname ("hxehost"), not the address dialled.
719
+ expect(
720
+ fromResource(
721
+ { ...SAPHANA, "saphana.host": "hxehost", "os.type": "linux" },
722
+ SAPHANA_HINT,
723
+ ),
724
+ ).toMatchObject({
725
+ endpoint: { host: "hxehost", port: 30015 },
726
+ endpointIsStable: false,
727
+ allowCreate: false,
728
+ });
729
+ });
730
+
731
+ test("a placeholder saphana.host is no endpoint", () => {
732
+ expect(
733
+ fromResource({ ...SAPHANA, "saphana.host": "unknown" }, SAPHANA_HINT),
734
+ ).toBeNull();
735
+ });
736
+ });
737
+
738
+ test("an unusable candidate falls through to the next one", () => {
739
+ expect(
740
+ fromResource(
741
+ {
742
+ "server.address": "[REDACTED]",
743
+ "service.instance.id": "unknown:5432",
744
+ "mysql.instance.endpoint": "mysql.prod:3307",
745
+ },
746
+ "mysql",
747
+ )?.endpoint,
748
+ ).toEqual({ host: "mysql.prod", port: 3307 });
749
+ });
750
+
751
+ test("NO host.name fallback: a collector scraping N Redis never merges them", () => {
752
+ const redisA: ResourceResolution = fromResource(
753
+ {
754
+ "host.name": "collector-1",
755
+ "os.type": "linux",
756
+ "redis.version": "7.2",
757
+ },
758
+ "redis",
759
+ );
760
+ const redisB: ResourceResolution = fromResource(
761
+ {
762
+ "host.name": "collector-1",
763
+ "os.type": "linux",
764
+ "redis.version": "7.0",
765
+ },
766
+ "redis",
767
+ );
768
+ expect(redisA).toBeNull();
769
+ expect(redisB).toBeNull();
770
+ });
771
+
772
+ test("memcached (no resource attributes at all) is not a database row", () => {
773
+ expect(fromResource({}, "memcached")).toBeNull();
774
+ });
775
+
776
+ test("Elasticsearch cluster / node names are never used as a host", () => {
777
+ expect(
778
+ fromResource(
779
+ {
780
+ "elasticsearch.cluster.name": "docker-cluster",
781
+ "elasticsearch.node.name": "es-0",
782
+ },
783
+ "elasticsearch",
784
+ ),
785
+ ).toBeNull();
786
+ });
787
+ });
788
+
789
+ describe("resolveDatabaseFromResourceAttributes — non-identity hosts", () => {
790
+ test.each([
791
+ ["unknown:5432"],
792
+ ["unknown"],
793
+ ["unknown_service"],
794
+ ["nohost"],
795
+ ["localhost.localdomain"],
796
+ ])("%s counts as absent", (value: string) => {
797
+ expect(
798
+ fromResource({ "service.instance.id": value }, "postgresql"),
799
+ ).toBeNull();
800
+ expect(fromResource({ "server.address": value }, "postgresql")).toBeNull();
801
+ });
802
+
803
+ test("CouchDB's default nonode@nohost does not become a host", () => {
804
+ expect(fromResource({ "server.address": "nohost" }, "couchdb")).toBeNull();
805
+ });
806
+
807
+ test("the resource's own pod name is not a server (sidecar collector)", () => {
808
+ expect(
809
+ fromResource(
810
+ {
811
+ "server.address": "pg-exporter-6c9f-x2x",
812
+ "k8s.pod.name": "PG-Exporter-6c9f-x2x",
813
+ },
814
+ "postgresql",
815
+ ),
816
+ ).toBeNull();
817
+ });
818
+
819
+ test("a 12- or 64-hex container id is not a server", () => {
820
+ expect(
821
+ fromResource({ "server.address": "0123456789ab" }, "postgresql"),
822
+ ).toBeNull();
823
+ expect(
824
+ fromResource({ "server.address": "a".repeat(64) }, "postgresql"),
825
+ ).toBeNull();
826
+ // Other hex lengths are ordinary names.
827
+ expect(
828
+ fromResource({ "server.address": "0123456789abcd" }, "postgresql")
829
+ ?.endpoint,
830
+ ).toEqual({ host: "0123456789abcd", port: 5432 });
831
+ });
832
+
833
+ test("…unless OUR agent stamped the address explicitly", () => {
834
+ expect(
835
+ fromResource(
836
+ {
837
+ "server.address": "0123456789ab",
838
+ "oneuptime.database.agent": "true",
839
+ },
840
+ "postgresql",
841
+ )?.endpoint,
842
+ ).toEqual({ host: "0123456789ab", port: 5432 });
843
+ expect(
844
+ fromResource(
845
+ {
846
+ "server.address": "pg-0",
847
+ "k8s.pod.name": "pg-0",
848
+ "k8s.namespace.name": "data",
849
+ "k8s.cluster.name": "prod",
850
+ "oneuptime.database.agent": "true",
851
+ },
852
+ "postgresql",
853
+ )?.endpoint,
854
+ ).toEqual({
855
+ host: "pg-0.data.svc.cluster.local",
856
+ port: 5432,
857
+ kubernetesClusterName: "prod",
858
+ });
859
+ });
860
+
861
+ test("the agent stamp does not rescue 'unknown'", () => {
862
+ expect(
863
+ fromResource(
864
+ { "server.address": "unknown", "oneuptime.database.agent": "true" },
865
+ "postgresql",
866
+ ),
867
+ ).toBeNull();
868
+ });
869
+
870
+ test("a non-identity host with a linked id still resolves the row, endpoint-less", () => {
871
+ expect(
872
+ fromResource(
873
+ {
874
+ "server.address": "unknown",
875
+ "oneuptime.database.server.id": LINKED_ID,
876
+ },
877
+ "postgresql",
878
+ ),
879
+ ).toMatchObject({ endpoint: null, linkedDatabaseServerId: LINKED_ID });
880
+ });
881
+ });
882
+
883
+ describe("resolveDatabaseFromResourceAttributes — loopback (collector purpose)", () => {
884
+ test("a stable collector's loopback address is its own host", () => {
885
+ expect(
886
+ fromResource(
887
+ {
888
+ "server.address": "localhost",
889
+ "host.name": "db-1.corp",
890
+ "os.type": "linux",
891
+ },
892
+ "postgresql",
893
+ )?.endpoint,
894
+ ).toEqual({ host: "db-1.corp", port: 5432 });
895
+ });
896
+
897
+ test("an ephemeral collector's loopback address is refused", () => {
898
+ // Kubernetes sidecar / Docker container collectors.
899
+ expect(
900
+ fromResource(
901
+ {
902
+ "server.address": "localhost",
903
+ "host.name": "pg-0",
904
+ "os.type": "linux",
905
+ "k8s.pod.name": "pg-0",
906
+ },
907
+ "postgresql",
908
+ ),
909
+ ).toBeNull();
910
+ expect(
911
+ fromResource(
912
+ {
913
+ "server.address": "127.0.0.1",
914
+ "host.name": "3f9a1b2c4d5e",
915
+ "os.type": "linux",
916
+ "container.id": "3f9a1b2c4d5e",
917
+ },
918
+ "redis",
919
+ ),
920
+ ).toBeNull();
921
+ });
922
+
923
+ test("the rewrite never lands on a container-id host.name", () => {
924
+ expect(
925
+ fromResource(
926
+ {
927
+ "server.address": "localhost",
928
+ "host.name": "3f9a1b2c4d5e",
929
+ "os.type": "linux",
930
+ },
931
+ "postgresql",
932
+ ),
933
+ ).toBeNull();
934
+ });
935
+ });
936
+
937
+ describe("resolveDatabaseFromResourceAttributes — descriptive fields", () => {
938
+ test.each([
939
+ ["db.system.version", "16.2"],
940
+ ["redis.version", "7.2.4"],
941
+ ["oracle.db.version", "23.4"],
942
+ ["elasticsearch.node.version", "8.13.0"],
943
+ ["mongodb.version", "7.0.5"],
944
+ ])("version from %s", (key: string, version: string) => {
945
+ expect(
946
+ fromResource({ "server.address": "db.prod", [key]: version }, "redis")
947
+ ?.version,
948
+ ).toBe(version);
949
+ });
950
+
951
+ test("db.system.version wins when several are present", () => {
952
+ expect(
953
+ fromResource(
954
+ {
955
+ "server.address": "db.prod",
956
+ "redis.version": "7.0",
957
+ "db.system.version": "7.2",
958
+ },
959
+ "redis",
960
+ )?.version,
961
+ ).toBe("7.2");
962
+ });
963
+
964
+ describe("the server's own version string refines a family engine", () => {
965
+ const MARIADB_VERSION: string = "10.11.7-MariaDB-1:10.11.7+maria~ubu2204";
966
+ const TIDB_VERSION: string = "8.0.11-TiDB-v7.5.1";
967
+
968
+ test("the mysql receiver's hint + a MariaDB version is MariaDB", () => {
969
+ expect(
970
+ fromResource(
971
+ { "server.address": "db.prod", "db.system.version": MARIADB_VERSION },
972
+ "mysql",
973
+ ),
974
+ ).toMatchObject({
975
+ system: "mariadb",
976
+ displayName: "MariaDB db.prod:3306",
977
+ version: MARIADB_VERSION,
978
+ allowCreate: true,
979
+ });
980
+ });
981
+
982
+ test("an explicit mysql stamp + a TiDB version is TiDB", () => {
983
+ expect(
984
+ fromResource({
985
+ "db.system.name": "mysql",
986
+ "server.address": "db.prod",
987
+ "server.port": 4000,
988
+ "db.system.version": TIDB_VERSION,
989
+ })?.system,
990
+ ).toBe("tidb");
991
+ });
992
+
993
+ test("the linked-id path is refined too", () => {
994
+ expect(
995
+ fromResource({
996
+ "oneuptime.database.server.id": LINKED_ID,
997
+ "db.system.name": "mysql",
998
+ "db.system.version": MARIADB_VERSION,
999
+ })?.system,
1000
+ ).toBe("mariadb");
1001
+ });
1002
+
1003
+ test("the endpoint does not move with the version: identity is the engine as reported", () => {
1004
+ const withVersion: ResourceResolution = fromResource(
1005
+ { "server.address": "db.prod", "db.system.version": TIDB_VERSION },
1006
+ "mysql",
1007
+ );
1008
+ const withoutVersion: ResourceResolution = fromResource(
1009
+ { "server.address": "db.prod" },
1010
+ "mysql",
1011
+ );
1012
+ expect(withVersion?.system).toBe("tidb");
1013
+ expect(withoutVersion?.system).toBe("mysql");
1014
+ /*
1015
+ * MySQL's default port, not TiDB's: the same server keys the same way
1016
+ * whether or not its receiver managed to read the version.
1017
+ */
1018
+ expect(withVersion?.endpoint).toEqual({ host: "db.prod", port: 3306 });
1019
+ expect(withVersion?.endpoint).toEqual(withoutVersion?.endpoint);
1020
+ });
1021
+
1022
+ test.each<[string, string, string]>([
1023
+ ["a bare version", "mysql", "8.0.36"],
1024
+ ["a fork already named (never re-forked)", "mariadb", TIDB_VERSION],
1025
+ ["a fork's version under another family", "postgresql", MARIADB_VERSION],
1026
+ ["an unknown engine", "acme-db", MARIADB_VERSION],
1027
+ ])(
1028
+ "%s keeps the engine",
1029
+ (_label: string, system: string, version: string) => {
1030
+ expect(
1031
+ fromResource({
1032
+ "db.system.name": system,
1033
+ "server.address": "db.prod",
1034
+ "db.system.version": version,
1035
+ })?.system,
1036
+ ).toBe(system);
1037
+ },
1038
+ );
1039
+
1040
+ test("a batch that names no engine is not given one by its version", () => {
1041
+ expect(
1042
+ fromResource({
1043
+ "oneuptime.database.server.id": LINKED_ID,
1044
+ "db.system.version": MARIADB_VERSION,
1045
+ })?.system,
1046
+ ).toBe("");
1047
+ });
1048
+
1049
+ /*
1050
+ * Regression (e2e): the Database Agent installed with
1051
+ * DATABASE_SYSTEM=mysql against MariaDB 11.4.13. This is its batch's
1052
+ * resource exactly as ClickHouse stored it: the receiver reports the
1053
+ * bare "11.4.13" (SELECT VERSION() says "11.4.13-MariaDB-ubu2404"), so
1054
+ * the database read "MySQL mariamysql…" for good.
1055
+ */
1056
+ const MARIADB_AGENT_LABELLED_MYSQL: Record<string, unknown> = {
1057
+ "mysql.instance.endpoint": "e2e-receivers-mariadb:3306",
1058
+ "service.instance.id": "74f6b653-070b-549a-9e22-6a56a802a4ab",
1059
+ "db.system.version": "11.4.13",
1060
+ "db.system.name": "mysql",
1061
+ "server.address": "mariamysql.rcv-e2e.example.net",
1062
+ "server.port": "3306",
1063
+ "oneuptime.database.agent": "true",
1064
+ "oneuptime.agent.version": "0.161.0",
1065
+ };
1066
+
1067
+ test("a MySQL-labelled agent against MariaDB reports MariaDB: MySQL has no 11.x", () => {
1068
+ expect(
1069
+ fromResource(
1070
+ MARIADB_AGENT_LABELLED_MYSQL,
1071
+ getDatabaseReceiverSystemHint([`${CONTRIB}mysqlreceiver`]),
1072
+ ),
1073
+ ).toMatchObject({
1074
+ system: "mariadb",
1075
+ displayName: "MariaDB mariamysql.rcv-e2e.example.net:3306",
1076
+ version: "11.4.13",
1077
+ endpoint: { host: "mariamysql.rcv-e2e.example.net", port: 3306 },
1078
+ allowCreate: true,
1079
+ });
1080
+ });
1081
+
1082
+ test("the same agent against MySQL 8.4 stays MySQL", () => {
1083
+ expect(
1084
+ fromResource(
1085
+ {
1086
+ ...MARIADB_AGENT_LABELLED_MYSQL,
1087
+ "mysql.instance.endpoint": "e2e-receivers-mysql:3306",
1088
+ "db.system.version": "8.4.11",
1089
+ "server.address": "mysql84.rcv-e2e.example.net",
1090
+ },
1091
+ "mysql",
1092
+ ),
1093
+ ).toMatchObject({ system: "mysql", version: "8.4.11" });
1094
+ });
1095
+ });
1096
+
1097
+ /*
1098
+ * Regression (e2e): Valkey 8.1.10 was stored as version 7.2.4. The redis
1099
+ * receiver fills redis.version from INFO's redis_version, which Valkey
1100
+ * keeps at 7.2.4 for compatibility (valkey_version:8.1.10 is its own).
1101
+ * This is the agent's batch resource exactly as ClickHouse stored it.
1102
+ */
1103
+ describe("a version that is the family's, not the engine's own", () => {
1104
+ const VALKEY_AGENT_BATCH: Record<string, unknown> = {
1105
+ "redis.version": "7.2.4",
1106
+ "server.address": "valkey8.rcv-e2e.example.net",
1107
+ "server.port": "6379",
1108
+ "db.system.name": "valkey",
1109
+ "oneuptime.database.agent": "true",
1110
+ "oneuptime.agent.version": "0.161.0",
1111
+ };
1112
+
1113
+ test("Valkey's redis.version is never its version", () => {
1114
+ expect(
1115
+ fromResource(
1116
+ VALKEY_AGENT_BATCH,
1117
+ getDatabaseReceiverSystemHint([`${CONTRIB}redisreceiver`]),
1118
+ ),
1119
+ ).toMatchObject({
1120
+ system: "valkey",
1121
+ version: null,
1122
+ displayName: "Valkey valkey8.rcv-e2e.example.net:6379",
1123
+ allowCreate: true,
1124
+ });
1125
+ });
1126
+
1127
+ test("nor on a batch linked by id, or stored with the resource. prefix", () => {
1128
+ expect(
1129
+ fromResource({
1130
+ "resource.redis.version": "7.2.4",
1131
+ "resource.db.system.name": "valkey",
1132
+ "resource.oneuptime.database.server.id": LINKED_ID,
1133
+ }),
1134
+ ).toMatchObject({ system: "valkey", version: null });
1135
+ });
1136
+
1137
+ test("a version Valkey does report as its own is kept", () => {
1138
+ expect(
1139
+ fromResource({ ...VALKEY_AGENT_BATCH, "db.system.version": "8.1.10" })
1140
+ ?.version,
1141
+ ).toBe("8.1.10");
1142
+ });
1143
+
1144
+ test("Redis and KeyDB keep redis.version: it is their own release", () => {
1145
+ for (const system of ["redis", "keydb"]) {
1146
+ expect(
1147
+ fromResource({ ...VALKEY_AGENT_BATCH, "db.system.name": system })
1148
+ ?.version,
1149
+ ).toBe("7.2.4");
1150
+ }
1151
+ });
1152
+ });
1153
+
1154
+ test("the display name uses the endpoint, without the cluster qualifier", () => {
1155
+ expect(
1156
+ fromResource(
1157
+ {
1158
+ "server.address": "10.0.0.5",
1159
+ "k8s.cluster.name": "prod",
1160
+ "oneuptime.database.agent": "true",
1161
+ },
1162
+ "postgresql",
1163
+ ),
1164
+ ).toMatchObject({
1165
+ endpoint: {
1166
+ host: "10.0.0.5",
1167
+ port: 5432,
1168
+ kubernetesClusterName: "prod",
1169
+ },
1170
+ displayName: "PostgreSQL 10.0.0.5:5432",
1171
+ });
1172
+ });
1173
+
1174
+ test("the stored resource.-prefixed spelling is accepted", () => {
1175
+ expect(
1176
+ fromResource(
1177
+ { "resource.server.address": "db.prod", "resource.server.port": 6543 },
1178
+ "postgresql",
1179
+ )?.endpoint,
1180
+ ).toEqual({ host: "db.prod", port: 6543 });
1181
+ });
1182
+
1183
+ test("garbage input never throws", () => {
1184
+ expect(
1185
+ resolveDatabaseFromResourceAttributes(
1186
+ undefined as unknown as { attributes: Record<string, unknown> },
1187
+ ),
1188
+ ).toBeNull();
1189
+ expect(
1190
+ resolveDatabaseFromResourceAttributes({
1191
+ attributes: null as unknown as Record<string, unknown>,
1192
+ receiverSystemHint: "postgresql",
1193
+ }),
1194
+ ).toBeNull();
1195
+ });
1196
+
1197
+ test("a hint that is not a known engine is not a hint", () => {
1198
+ expect(
1199
+ fromResource({ "server.address": "db.prod" }, `${CONTRIB}kafkareceiver`),
1200
+ ).toBeNull();
1201
+ expect(fromResource({ "server.address": "db.prod" }, "acme-db")).toBeNull();
1202
+ // An alias of a known engine is fine.
1203
+ expect(
1204
+ fromResource({ "server.address": "db.prod" }, "postgres")?.system,
1205
+ ).toBe("postgresql");
1206
+ });
1207
+ });
1208
+
1209
+ /*
1210
+ * Which collector endpoints may become a server's identity. A pod IP or a
1211
+ * name a collector made up from its own namespace keys the rows (so a row
1212
+ * that owns it finds them) but never creates a row or becomes an alias:
1213
+ * every pod restart would otherwise add another database.
1214
+ */
1215
+ describe("resolveDatabaseFromResourceAttributes — stable identities (endpointIsStable / allowCreate)", () => {
1216
+ // A receiver_creator + k8s_observer batch: the scraped pod's IP and identity.
1217
+ const RECEIVER_CREATOR: Record<string, unknown> = {
1218
+ "server.address": "10.42.1.17",
1219
+ "server.port": "5432",
1220
+ "k8s.pod.name": "postgres-0",
1221
+ "k8s.namespace.name": "prod",
1222
+ "k8s.cluster.name": "prod-eu",
1223
+ };
1224
+
1225
+ test("a pod IP qualified with its cluster keys the rows but is not stable", () => {
1226
+ const resolved: ResourceResolution = fromResource(
1227
+ RECEIVER_CREATOR,
1228
+ "postgresql",
1229
+ );
1230
+
1231
+ expect(resolved?.endpoint).toEqual({
1232
+ host: "10.42.1.17",
1233
+ port: 5432,
1234
+ kubernetesClusterName: "prod-eu",
1235
+ });
1236
+ expect(resolved?.endpointIsStable).toBe(false);
1237
+ expect(resolved?.allowCreate).toBe(false);
1238
+ });
1239
+
1240
+ test("a rolling restart's new pod IPs never become new databases", () => {
1241
+ for (const address of ["10.42.3.88", "10.42.7.4", "10.42.9.201"]) {
1242
+ const resolved: ResourceResolution = fromResource(
1243
+ { ...RECEIVER_CREATOR, "server.address": address },
1244
+ "postgresql",
1245
+ );
1246
+ expect(resolved?.endpoint?.host).toBe(address);
1247
+ expect(resolved?.allowCreate).toBe(false);
1248
+ }
1249
+ });
1250
+
1251
+ test("the same pod IP without a cluster is LOCAL, and not stable either", () => {
1252
+ const resolved: ResourceResolution = fromResource(
1253
+ { ...RECEIVER_CREATOR, "k8s.cluster.name": undefined },
1254
+ "postgresql",
1255
+ );
1256
+
1257
+ expect(resolved?.endpoint).toEqual({ host: "10.42.1.17", port: 5432 });
1258
+ expect(resolved?.endpointIsStable).toBe(false);
1259
+ expect(resolved?.allowCreate).toBe(false);
1260
+ });
1261
+
1262
+ test.each([["k8s.pod.name"], ["k8s.pod.uid"]])(
1263
+ "an IP reported for a pod (%s) is not stable even when it is public",
1264
+ (key: string) => {
1265
+ const resolved: ResourceResolution = fromResource(
1266
+ {
1267
+ "server.address": "34.120.7.9",
1268
+ [key]: key === "k8s.pod.uid" ? LINKED_ID : "redis-master-0",
1269
+ },
1270
+ "redis",
1271
+ );
1272
+
1273
+ expect(resolved?.endpoint).toEqual({ host: "34.120.7.9", port: 6379 });
1274
+ expect(resolved?.endpointIsStable).toBe(false);
1275
+ expect(resolved?.allowCreate).toBe(false);
1276
+ },
1277
+ );
1278
+
1279
+ test("a public IP a VM collector was pointed at is a stable identity", () => {
1280
+ const resolved: ResourceResolution = fromResource(
1281
+ {
1282
+ "server.address": "34.120.7.9",
1283
+ "host.name": "collector-vm-1",
1284
+ "os.type": "linux",
1285
+ },
1286
+ "mysql",
1287
+ );
1288
+
1289
+ expect(resolved?.endpoint).toEqual({ host: "34.120.7.9", port: 3306 });
1290
+ expect(resolved?.endpointIsStable).toBe(true);
1291
+ expect(resolved?.allowCreate).toBe(true);
1292
+ });
1293
+
1294
+ test("the Database Agent's cluster-qualified private IP is keyed but not stable", () => {
1295
+ expect(
1296
+ fromResource(
1297
+ {
1298
+ "server.address": "10.0.0.5",
1299
+ "k8s.cluster.name": "prod",
1300
+ "oneuptime.database.agent": "true",
1301
+ },
1302
+ "postgresql",
1303
+ ),
1304
+ ).toMatchObject({
1305
+ endpoint: {
1306
+ host: "10.0.0.5",
1307
+ port: 5432,
1308
+ kubernetesClusterName: "prod",
1309
+ },
1310
+ endpointIsStable: false,
1311
+ allowCreate: false,
1312
+ });
1313
+ });
1314
+
1315
+ test("a sidecar's pod hostname expanded with the collector's own namespace is not a Service", () => {
1316
+ // The receiver substituted os.Hostname() (the pod name) for localhost.
1317
+ const resolved: ResourceResolution = fromResource(
1318
+ {
1319
+ "server.address": "orders-api-7c9d8f6b5-x2k4q",
1320
+ "k8s.namespace.name": "prod",
1321
+ "k8s.cluster.name": "c1",
1322
+ },
1323
+ "postgresql",
1324
+ );
1325
+
1326
+ expect(resolved?.endpoint).toEqual({
1327
+ host: "orders-api-7c9d8f6b5-x2k4q.prod.svc.cluster.local",
1328
+ port: 5432,
1329
+ kubernetesClusterName: "c1",
1330
+ });
1331
+ expect(resolved?.endpointIsStable).toBe(false);
1332
+ expect(resolved?.allowCreate).toBe(false);
1333
+ });
1334
+
1335
+ test("a single-label Service name keys exactly like the detected workload's alias, and joins it instead of creating", () => {
1336
+ const resolved: ResourceResolution = fromResource(
1337
+ {
1338
+ "server.address": "postgres",
1339
+ "k8s.namespace.name": "prod",
1340
+ "k8s.cluster.name": "c1",
1341
+ },
1342
+ "postgresql",
1343
+ );
1344
+
1345
+ // The alias DiscoverContainerDatabases stores: postgres.prod.svc.cluster.local:5432@c1.
1346
+ expect(resolved?.endpoint).toEqual({
1347
+ host: "postgres.prod.svc.cluster.local",
1348
+ port: 5432,
1349
+ kubernetesClusterName: "c1",
1350
+ });
1351
+ expect(resolved?.allowCreate).toBe(false);
1352
+ });
1353
+
1354
+ test.each([
1355
+ ["a Service FQDN", "postgres.prod.svc.cluster.local"],
1356
+ [
1357
+ "a StatefulSet member behind a headless Service",
1358
+ "postgres-0.postgres.prod.svc.cluster.local",
1359
+ ],
1360
+ ["the short .svc form", "postgres.prod.svc"],
1361
+ ])(
1362
+ "%s written out with the cluster stamped is a stable identity",
1363
+ (_label: string, address: string) => {
1364
+ const resolved: ResourceResolution = fromResource(
1365
+ {
1366
+ "server.address": address,
1367
+ "k8s.namespace.name": "monitoring",
1368
+ "k8s.cluster.name": "c1",
1369
+ },
1370
+ "postgresql",
1371
+ );
1372
+
1373
+ expect(resolved?.endpoint?.kubernetesClusterName).toBe("c1");
1374
+ expect(resolved?.endpointIsStable).toBe(true);
1375
+ expect(resolved?.allowCreate).toBe(true);
1376
+ },
1377
+ );
1378
+
1379
+ test("a stable collector's loopback rewritten to its FQDN host.name is stable", () => {
1380
+ const resolved: ResourceResolution = fromResource(
1381
+ {
1382
+ "server.address": "localhost",
1383
+ "host.name": "db-1.corp.example.com",
1384
+ "os.type": "linux",
1385
+ },
1386
+ "postgresql",
1387
+ );
1388
+
1389
+ expect(resolved?.endpoint).toEqual({
1390
+ host: "db-1.corp.example.com",
1391
+ port: 5432,
1392
+ });
1393
+ expect(resolved?.endpointIsStable).toBe(true);
1394
+ expect(resolved?.allowCreate).toBe(true);
1395
+ });
1396
+
1397
+ test("a loopback rewritten to a single-label host.name stays LOCAL", () => {
1398
+ const resolved: ResourceResolution = fromResource(
1399
+ {
1400
+ "server.address": "localhost",
1401
+ "host.name": "db01",
1402
+ "os.type": "linux",
1403
+ },
1404
+ "postgresql",
1405
+ );
1406
+
1407
+ expect(resolved?.endpoint).toEqual({ host: "db01", port: 5432 });
1408
+ expect(resolved?.endpointIsStable).toBe(false);
1409
+ expect(resolved?.allowCreate).toBe(false);
1410
+ });
1411
+
1412
+ test("an unknown engine keys and may be joined, but never creates a row", () => {
1413
+ const resolved: ResourceResolution = fromResource({
1414
+ "db.system.name": "acme-db",
1415
+ "server.address": "acme.prod.example.com",
1416
+ "server.port": "7000",
1417
+ });
1418
+
1419
+ expect(resolved?.system).toBe("acme-db");
1420
+ expect(resolved?.endpointIsStable).toBe(true);
1421
+ expect(resolved?.allowCreate).toBe(false);
1422
+ });
1423
+
1424
+ test("a cloud-API engine (a shared regional host) never creates a row", () => {
1425
+ const resolved: ResourceResolution = fromResource({
1426
+ "db.system.name": "aws.dynamodb",
1427
+ "server.address": "dynamodb.us-east-1.amazonaws.com",
1428
+ "server.port": "443",
1429
+ });
1430
+
1431
+ expect(resolved?.endpointIsStable).toBe(true);
1432
+ expect(resolved?.allowCreate).toBe(false);
1433
+ });
1434
+
1435
+ test("a linked id with a pod IP still resolves the link, endpoint not stable", () => {
1436
+ expect(
1437
+ fromResource(
1438
+ { ...RECEIVER_CREATOR, "oneuptime.database.server.id": LINKED_ID },
1439
+ "postgresql",
1440
+ ),
1441
+ ).toMatchObject({
1442
+ linkedDatabaseServerId: LINKED_ID,
1443
+ endpointIsStable: false,
1444
+ allowCreate: false,
1445
+ });
1446
+ });
1447
+ });
1448
+
1449
+ describe("isStableCollectorEndpoint", () => {
1450
+ test("LOCAL endpoints are never stable", () => {
1451
+ const endpoints: Array<DatabaseEndpoint> = [
1452
+ { host: "pg-primary", port: 5432 },
1453
+ { host: "10.0.3.7", port: 5432 },
1454
+ { host: "postgres.prod.svc.cluster.local", port: 5432 },
1455
+ ];
1456
+ for (const endpoint of endpoints) {
1457
+ expect(
1458
+ isStableCollectorEndpoint({
1459
+ rawHost: endpoint.host,
1460
+ endpoint,
1461
+ attributes: {},
1462
+ }),
1463
+ ).toBe(false);
1464
+ }
1465
+ });
1466
+
1467
+ test("an FQDN is stable whatever resource reported it", () => {
1468
+ expect(
1469
+ isStableCollectorEndpoint({
1470
+ rawHost: "db.prod.example.com",
1471
+ endpoint: { host: "db.prod.example.com", port: 5432 },
1472
+ attributes: { "k8s.pod.name": "collector-0" },
1473
+ }),
1474
+ ).toBe(true);
1475
+ });
1476
+
1477
+ test("the pod rule reads the stored resource.-prefixed spelling too", () => {
1478
+ expect(
1479
+ isStableCollectorEndpoint({
1480
+ rawHost: "34.120.7.9",
1481
+ endpoint: { host: "34.120.7.9", port: 5432 },
1482
+ attributes: { "resource.k8s.pod.name": "pg-0" },
1483
+ }),
1484
+ ).toBe(false);
1485
+ });
1486
+
1487
+ test("an IPv6 global address from a VM is stable; qualified with a cluster it is not", () => {
1488
+ expect(
1489
+ isStableCollectorEndpoint({
1490
+ rawHost: "2001:db8::10",
1491
+ endpoint: { host: "2001:db8::10", port: 5432 },
1492
+ attributes: {},
1493
+ }),
1494
+ ).toBe(true);
1495
+ expect(
1496
+ isStableCollectorEndpoint({
1497
+ rawHost: "fd00::10",
1498
+ endpoint: {
1499
+ host: "fd00::10",
1500
+ port: 5432,
1501
+ kubernetesClusterName: "c1",
1502
+ },
1503
+ attributes: {},
1504
+ }),
1505
+ ).toBe(false);
1506
+ });
1507
+
1508
+ test("a SQL Server named instance is judged by its network host", () => {
1509
+ expect(
1510
+ isStableCollectorEndpoint({
1511
+ rawHost: "sql.prod.example.com",
1512
+ endpoint: { host: "sql.prod.example.com\\reporting", port: null },
1513
+ attributes: {},
1514
+ }),
1515
+ ).toBe(true);
1516
+ expect(
1517
+ isStableCollectorEndpoint({
1518
+ rawHost: "34.120.7.9",
1519
+ endpoint: { host: "34.120.7.9\\reporting", port: null },
1520
+ attributes: { "k8s.pod.name": "mssql-0" },
1521
+ }),
1522
+ ).toBe(false);
1523
+ // The raw host is compared case- and whitespace-insensitively, instance dropped.
1524
+ expect(
1525
+ isStableCollectorEndpoint({
1526
+ rawHost: " SQL.Prod.Example.COM\\Reporting ",
1527
+ endpoint: { host: "sql.prod.example.com\\reporting", port: null },
1528
+ attributes: {},
1529
+ }),
1530
+ ).toBe(true);
1531
+ });
1532
+
1533
+ test("garbage input is not stable and never throws", () => {
1534
+ expect(
1535
+ isStableCollectorEndpoint(
1536
+ undefined as unknown as {
1537
+ rawHost: string;
1538
+ endpoint: DatabaseEndpoint;
1539
+ attributes: Record<string, unknown>;
1540
+ },
1541
+ ),
1542
+ ).toBe(false);
1543
+ expect(
1544
+ isStableCollectorEndpoint({
1545
+ rawHost: "",
1546
+ endpoint: null as unknown as DatabaseEndpoint,
1547
+ attributes: {},
1548
+ }),
1549
+ ).toBe(false);
1550
+ expect(
1551
+ isStableCollectorEndpoint({
1552
+ rawHost: undefined as unknown as string,
1553
+ endpoint: { host: "db.prod.example.com", port: 5432 },
1554
+ attributes: undefined as unknown as Record<string, unknown>,
1555
+ }),
1556
+ ).toBe(true);
1557
+ });
1558
+ });