@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.
- package/Models/DatabaseModels/Alert.ts +55 -0
- package/Models/DatabaseModels/DatabaseServer.ts +1650 -0
- package/Models/DatabaseModels/DatabaseServerEndpoint.ts +540 -0
- package/Models/DatabaseModels/DatabaseServerFeed.ts +625 -0
- package/Models/DatabaseModels/DatabaseServerLabelRule.ts +514 -0
- package/Models/DatabaseModels/DatabaseServerOwnerRule.ts +596 -0
- package/Models/DatabaseModels/DatabaseServerOwnerTeam.ts +491 -0
- package/Models/DatabaseModels/DatabaseServerOwnerUser.ts +490 -0
- package/Models/DatabaseModels/Incident.ts +55 -0
- package/Models/DatabaseModels/Index.ts +16 -0
- package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +26 -0
- package/Models/DatabaseModels/ScheduledMaintenance.ts +55 -0
- package/Models/DatabaseModels/TelemetryException.ts +2 -0
- package/Models/DatabaseModels/UserProjectSsoConsent.ts +146 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795000000000-AddDatabaseServerTables.ts +673 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795100000000-AddUserProjectSsoConsent.ts +51 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
- package/Server/Middleware/MultipartFormData.ts +1 -1
- package/Server/Middleware/TelemetryIngest.ts +15 -8
- package/Server/Services/AlertReminderRuleService.ts +100 -24
- package/Server/Services/DatabaseServerEndpointService.ts +895 -0
- package/Server/Services/DatabaseServerFeedService.ts +128 -0
- package/Server/Services/DatabaseServerLabelRuleEngineService.ts +340 -0
- package/Server/Services/DatabaseServerLabelRuleService.ts +14 -0
- package/Server/Services/DatabaseServerOwnerRuleEngineService.ts +425 -0
- package/Server/Services/DatabaseServerOwnerRuleService.ts +14 -0
- package/Server/Services/DatabaseServerOwnerTeamService.ts +180 -0
- package/Server/Services/DatabaseServerOwnerUserService.ts +173 -0
- package/Server/Services/DatabaseServerService.ts +4546 -0
- package/Server/Services/DatabaseService.ts +14 -8
- package/Server/Services/DockerResourceService.ts +43 -2
- package/Server/Services/IncidentReminderRuleService.ts +103 -23
- package/Server/Services/Index.ts +16 -0
- package/Server/Services/InventoryItemService.ts +113 -5
- package/Server/Services/IoTDeviceService.ts +145 -37
- package/Server/Services/OpenTelemetryIngestService.ts +19 -0
- package/Server/Services/PodmanResourceService.ts +43 -2
- package/Server/Services/ScheduledMaintenanceReminderRuleService.ts +107 -23
- package/Server/Services/ServiceService.ts +1 -1
- package/Server/Services/TelemetryUsageBillingService.ts +29 -2
- package/Server/Services/UserProjectSsoConsentService.ts +74 -0
- package/Server/Services/UserService.ts +14 -1
- package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +18 -0
- package/Server/Types/Database/QueryHelper.ts +30 -1
- package/Server/Utils/AI/Toolbox/ResourceTools.ts +69 -1
- package/Server/Utils/Database/AffectedResourceRelations.ts +6 -0
- package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +188 -6
- package/Server/Utils/Monitor/MonitorAlert.ts +28 -1
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +2262 -755
- package/Server/Utils/Monitor/MonitorIncident.ts +28 -1
- package/Server/Utils/Monitor/MonitorMaintenanceSuppression.ts +268 -6
- package/Server/Utils/Monitor/MonitorResource.ts +47 -11
- package/Server/Utils/Monitor/MonitorResourceContext.ts +1 -0
- package/Server/Utils/Monitor/MonitorStepResourceIdentity.ts +239 -21
- package/Server/Utils/Monitor/PerSeriesResolutionRootCause.ts +43 -0
- package/Server/Utils/Monitor/SeriesResourceLabels.ts +291 -0
- package/Server/Utils/Monitor/SeriesResourceLinker.ts +111 -12
- package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +25 -0
- package/Server/Utils/StartServer.ts +26 -6
- package/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.ts +2 -0
- package/Server/Utils/Telemetry/DatabaseEndpointDiscovery.ts +688 -0
- package/Server/Utils/Telemetry/EntityRegistry.ts +5 -1
- package/Server/Utils/Telemetry/LogExceptionExtractor.ts +18 -1
- package/Server/Utils/Telemetry/ResourceEntityFilter.ts +175 -12
- package/Server/Utils/Telemetry/ResourceFacetResolver.ts +12 -0
- package/Server/Utils/Telemetry/ServiceDependencyDiscovery.ts +606 -36
- package/Server/Utils/Telemetry/Telemetry.ts +16 -0
- package/Server/Utils/Telemetry/TelemetryEntity.ts +22 -22
- package/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.ts +16 -10
- package/Tests/App/Accounts/SignedInRedirect.test.tsx +241 -0
- package/Tests/App/AdminDashboard/AdminHeaderSmallScreens.test.tsx +221 -4
- package/Tests/App/Dashboard/AIInsightsResourcePageContext.test.ts +42 -0
- package/Tests/App/Dashboard/AffectedResourcesDisplay.test.tsx +100 -0
- package/Tests/App/Dashboard/AffectedResourcesPicker.test.tsx +86 -0
- package/Tests/App/Dashboard/AffectedResourcesPickerHiddenTypes.test.tsx +2 -0
- package/Tests/App/Dashboard/AffectedResourcesSummaryStep.test.tsx +19 -0
- package/Tests/App/Dashboard/BreadcrumbCoverage.test.tsx +14 -0
- package/Tests/App/Dashboard/CorrelateFilterBuilder.test.tsx +26 -1
- package/Tests/App/Dashboard/DashboardAppSsoError.test.tsx +501 -0
- package/Tests/App/Dashboard/DashboardHeaderRequests.test.tsx +64 -1
- package/Tests/App/Dashboard/DashboardHeaderSmallScreens.test.tsx +178 -18
- package/Tests/App/Dashboard/DashboardMasterPageSsoRedirect.test.tsx +444 -0
- package/Tests/App/Dashboard/DashboardNavBarForeignHiddenRule.test.tsx +573 -0
- package/Tests/App/Dashboard/DatabaseChartAxes.test.tsx +431 -0
- package/Tests/App/Dashboard/DatabaseContainerDetailBadge.test.tsx +249 -0
- package/Tests/App/Dashboard/DatabaseDashboardE2EFixes.test.ts +681 -0
- package/Tests/App/Dashboard/DatabaseDocumentationMarkdown.test.ts +1801 -0
- package/Tests/App/Dashboard/DatabaseFleetSummaryRefresh.test.tsx +280 -0
- package/Tests/App/Dashboard/DatabaseFormHelpers.test.tsx +321 -0
- package/Tests/App/Dashboard/DatabaseMetricMonitorLink.test.tsx +795 -0
- package/Tests/App/Dashboard/DatabaseOverviewHeader.test.tsx +580 -0
- package/Tests/App/Dashboard/DatabaseRecommendationsEngineMetrics.test.ts +270 -0
- package/Tests/App/Dashboard/DatabaseServerComponents.test.tsx +1486 -0
- package/Tests/App/Dashboard/DatabaseServerEngineMetricsFilter.test.ts +223 -0
- package/Tests/App/Dashboard/DatabaseServerPresentation.test.ts +435 -0
- package/Tests/App/Dashboard/DatabaseServerSummary.test.ts +186 -0
- package/Tests/App/Dashboard/DatabaseServerTelemetryQueries.test.ts +1553 -0
- package/Tests/App/Dashboard/DatabaseTableTruncation.test.tsx +326 -0
- package/Tests/App/Dashboard/DatabaseTelemetryScope.test.ts +512 -0
- package/Tests/App/Dashboard/DatabaseTelemetryTabs.test.tsx +774 -0
- package/Tests/App/Dashboard/DatabaseViewLayout.test.tsx +233 -0
- package/Tests/App/Dashboard/DatabaseWorkloadBadge.test.tsx +972 -0
- package/Tests/App/Dashboard/DiscoveryReviewInventoryRefresh.test.tsx +5 -0
- package/Tests/App/Dashboard/DiscoveryReviewUnnamedHostHint.test.tsx +1061 -0
- package/Tests/App/Dashboard/EventOverlayScope.test.ts +147 -0
- package/Tests/App/Dashboard/EventOverlayScopeHook.test.tsx +1 -0
- package/Tests/App/Dashboard/LogsResourceFacetChips.test.tsx +1 -0
- package/Tests/App/Dashboard/MetricsViewerDrillDown.test.tsx +310 -0
- package/Tests/App/Dashboard/MetricsViewerEntityScopedRows.test.tsx +495 -0
- package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +132 -1
- package/Tests/App/Dashboard/NavigationSearchKeywords.test.tsx +5 -0
- package/Tests/App/Dashboard/ProductOrientation.test.tsx +4 -3
- package/Tests/App/Dashboard/RecommendationsLoadedContext.test.tsx +349 -0
- package/Tests/App/Dashboard/ResourceArchiveSettings.test.tsx +62 -0
- package/Tests/App/Dashboard/ResourceFeedPageWiring.test.ts +8 -1
- package/Tests/App/Dashboard/ResourceFeedPagesFilterSort.test.tsx +14 -0
- package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +2 -0
- package/Tests/App/Dashboard/ServiceMapDatabaseLink.test.tsx +1085 -0
- package/Tests/App/Dashboard/TelemetryResourceRetentionSettings.test.tsx +10 -0
- package/Tests/App/Dashboard/TracesResourceFacets.test.tsx +2 -1
- package/Tests/App/StatusPage/StatusPageHeaderForeignHiddenRule.test.tsx +284 -0
- package/Tests/ClassStrings.ts +178 -0
- package/Tests/Fixtures/MobilePasskeyUser.json +1 -2
- package/Tests/ForeignHiddenRuleGuard.ts +2152 -0
- package/Tests/Models/DatabaseModels/DatabaseServerModels.test.ts +2250 -0
- package/Tests/Models/DatabaseModels/ResourceFeedModels.test.ts +24 -5
- package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
- package/Tests/RenderedMarkup.ts +518 -0
- package/Tests/ResponsiveVisibility.test.ts +490 -4
- package/Tests/ResponsiveVisibility.ts +505 -52
- package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
- package/Tests/Server/Infrastructure/Postgres/AddDatabaseServerTablesMigration.test.ts +541 -0
- package/Tests/Server/Infrastructure/Postgres/AddUserProjectSsoConsentMigration.test.ts +234 -0
- package/Tests/Server/Services/ContainerSnapshotUpsertPostgres.test.ts +319 -0
- package/Tests/Server/Services/CrossProjectRelationWriteGuard.test.ts +13 -0
- package/Tests/Server/Services/DatabaseServerEndpointService.test.ts +2033 -0
- package/Tests/Server/Services/DatabaseServerFeedAndOwnerServices.test.ts +529 -0
- package/Tests/Server/Services/DatabaseServerLifecycle.test.ts +3302 -0
- package/Tests/Server/Services/DatabaseServerRegistries.test.ts +603 -0
- package/Tests/Server/Services/DatabaseServerRuleEngines.test.ts +754 -0
- package/Tests/Server/Services/DatabaseServerService.test.ts +3558 -0
- package/Tests/Server/Services/DatabaseServerSqlPostgres.test.ts +2045 -0
- package/Tests/Server/Services/DatabaseServiceUpdateColumnsIfUnlockedPostgres.test.ts +362 -0
- package/Tests/Server/Services/DatabaseServiceUpdateColumnsIfUnlockedReply.test.ts +210 -0
- package/Tests/Server/Services/HookFreeWriteLengthClamp.test.ts +18 -0
- package/Tests/Server/Services/IncidentAlertSloLinkSurvivesEdit.test.ts +2 -0
- package/Tests/Server/Services/IncomingCallPolicyEscalationRuleTarget.test.ts +225 -0
- package/Tests/Server/Services/InventoryItemDisplayName.test.ts +280 -2
- package/Tests/Server/Services/InventoryUpsertSchemaParity.test.ts +8 -2
- package/Tests/Server/Services/IoTDeviceLatestMetricsPostgres.test.ts +689 -0
- package/Tests/Server/Services/IoTDeviceService.test.ts +379 -0
- package/Tests/Server/Services/LatestMetricsValuesShape.test.ts +360 -0
- package/Tests/Server/Services/LlmModelPriceService.test.ts +402 -0
- package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +7 -1
- package/Tests/Server/Services/OwnerRowUniqueness.test.ts +61 -9
- package/Tests/Server/Services/ReminderRuleLookupPostgres.test.ts +2250 -0
- package/Tests/Server/Services/ReminderRuleRefreshOpenSubjectsPaging.test.ts +653 -0
- package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +68 -20
- package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +3 -3
- package/Tests/Server/Services/TelemetryResourceFacetCounting.test.ts +9 -0
- package/Tests/Server/Services/UserProjectSsoConsentPostgres.test.ts +153 -0
- package/Tests/Server/Services/UserProjectSsoConsentService.test.ts +192 -0
- package/Tests/Server/Services/UserServiceFirstMasterAdminElection.test.ts +71 -0
- package/Tests/Server/Services/UserSignupIdTakeoverPostgres.test.ts +238 -0
- package/Tests/Server/Services/WorkspaceNotificationSummaryHelpers.test.ts +592 -0
- package/Tests/Server/Types/Billing/PayAsYouGoMeteredAuthorization.test.ts +3 -0
- package/Tests/Server/Types/Database/EventOverlayScopePostgres.test.ts +1 -0
- package/Tests/Server/Types/Database/FeedEventTypeFilterQuery.test.ts +11 -0
- package/Tests/Server/Types/Database/Permissions/InfrastructureOwnershipScope.test.ts +8 -0
- package/Tests/Server/Types/Database/QueryHelperBooleanForCriteriaBackedRule.test.ts +1094 -0
- package/Tests/Server/Utils/AI/ResourceTools.test.ts +134 -0
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.test.ts +41 -0
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaAnomalyUnits.test.ts +279 -9
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaDisplayContext.test.ts +933 -0
- package/Tests/Server/Utils/Monitor/DatabaseMaintenanceSuppression.test.ts +582 -0
- package/Tests/Server/Utils/Monitor/DatabaseServerMonitorLinking.test.ts +753 -0
- package/Tests/Server/Utils/Monitor/MonitorActionTimestamps.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/MonitorAlertCriteriaReferences.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/MonitorAlertResourceLinking.test.ts +119 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +60 -25
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorAffectedResourceEdgeCases.test.ts +1719 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorKubernetesAffectedResources.test.ts +1447 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorKubernetesRatioEmail.test.ts +352 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorPlatformMetricUnits.test.ts +717 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorPlatformRawScan.test.ts +2125 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorPlatformSeriesAffectedResources.test.ts +1288 -0
- package/Tests/Server/Utils/Monitor/MonitorDependencySuppressionCreatorSkip.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/MonitorIncidentCriteriaReferences.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/MonitorIncidentMemberRoleMembership.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/MonitorIncidentResourceLinking.test.ts +88 -0
- package/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.ts +205 -0
- package/Tests/Server/Utils/Monitor/MonitorResourceContext.test.ts +62 -0
- package/Tests/Server/Utils/Monitor/MonitorResourceDatabaseMaintenance.test.ts +803 -0
- package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +133 -3
- package/Tests/Server/Utils/Monitor/MonitorSummaryPersistence.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/PerSeriesRecoveryResolution.test.ts +472 -1
- package/Tests/Server/Utils/Monitor/PerSeriesSecondEntityAlerting.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/SeriesResourceLinker.test.ts +236 -2
- package/Tests/Server/Utils/SeriesResourceLabels.test.ts +70 -0
- package/Tests/Server/Utils/StartServerProtobufContentType.test.ts +54 -0
- package/Tests/Server/Utils/Telemetry/DatabaseEndpointDiscovery.test.ts +1895 -0
- package/Tests/Server/Utils/Telemetry/EntityRegistry.test.ts +7 -0
- package/Tests/Server/Utils/Telemetry/LogExceptionExtractorSeverityGate.test.ts +90 -0
- package/Tests/Server/Utils/Telemetry/ResourceEntityFilter.test.ts +570 -0
- package/Tests/Server/Utils/Telemetry/ResourceFacetResolver.test.ts +97 -2
- package/Tests/Server/Utils/Telemetry/ServiceDependencyDiscovery.test.ts +1337 -0
- package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +295 -0
- package/Tests/Types/AI/AIResourceContext.test.ts +30 -0
- package/Tests/Types/DatabaseServer/DatabaseContainerClassifier.test.ts +3644 -0
- package/Tests/Types/DatabaseServer/DatabaseContainerCommand.test.ts +340 -0
- package/Tests/Types/DatabaseServer/DatabaseContainerCommandCorpus.ts +826 -0
- package/Tests/Types/DatabaseServer/DatabaseContainerCommandPostgres.test.ts +150 -0
- package/Tests/Types/DatabaseServer/DatabaseEndpoint.test.ts +2657 -0
- package/Tests/Types/DatabaseServer/DatabaseServerDiscoverySource.test.ts +64 -0
- package/Tests/Types/DatabaseServer/DatabaseServerEntityKeys.test.ts +952 -0
- package/Tests/Types/DatabaseServer/DatabaseServerMetricCatalog.test.ts +1161 -0
- package/Tests/Types/DatabaseServer/DatabaseSystem.test.ts +1514 -0
- package/Tests/Types/DatabaseServer/DatabaseTelemetryResolver.test.ts +1558 -0
- package/Tests/Types/Monitor/CephAlertTemplates.test.ts +255 -6
- package/Tests/Types/Monitor/DatabaseAlertTemplates.test.ts +2254 -0
- package/Tests/Types/Monitor/KubernetesAlertTemplates.test.ts +298 -0
- package/Tests/Types/Monitor/KubernetesMetricCatalog.test.ts +271 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +253 -9
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +13 -5
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +4 -2
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +111 -2
- package/Tests/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.test.ts +61 -0
- package/Tests/Types/Monitor/SeriesContext/SeriesLabelDisplay.test.ts +114 -0
- package/Tests/Types/Monitor/Utils/KubernetesAgentEmittedMetrics.ts +181 -0
- package/Tests/Types/NetworkDevice/DiscoveredHostNamingStatus.test.ts +401 -0
- package/Tests/Types/Telemetry/ResourceEntityFacet.test.ts +4 -1
- package/Tests/Types/Telemetry/ResourceFacetCatalog.test.ts +24 -2
- package/Tests/UI/Components/Card.test.tsx +93 -2
- package/Tests/UI/Components/FeedOptions.test.ts +6 -0
- package/Tests/UI/Components/FeedOptionsButton.test.tsx +8 -1
- package/Tests/UI/Components/ForeignHiddenRuleResilience.test.tsx +1147 -0
- package/Tests/UI/Components/HeaderRightRail.test.tsx +41 -1
- package/Tests/UI/Components/LogsEntityNames.test.ts +16 -1
- package/Tests/UI/Components/LogsFacetSidebarHiddenFacets.test.tsx +7 -3
- package/Tests/UI/Components/ResourceFacetConfigs.test.ts +2 -1
- package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
- package/Tests/UI/Components/SrOnlyForeignRule.test.tsx +994 -0
- package/Tests/UI/Components/StatusPage/ResourceListSelection.test.tsx +34 -1
- package/Tests/UI/Components/TelemetryFacetSidebarHiddenFacets.test.tsx +4 -1
- package/Tests/UI/ForeignHiddenRuleGuard.test.ts +1951 -0
- package/Tests/UI/Rum/ReplayPlayerChrome.test.tsx +19 -1
- package/Tests/UI/Rum/ReplayTabSwitcher.test.tsx +19 -1
- package/Tests/UI/TailwindPlayCdnForeignHiddenRule.test.ts +1005 -0
- package/Tests/UI/ThemeGroupHoverReveal.test.ts +847 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +70 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +21 -0
- package/Tests/UI/Utils/ModelAPISsoRedirect.test.ts +127 -0
- package/Tests/UI/Utils/Navigation.test.ts +102 -0
- package/Tests/UI/Utils/Telemetry/TelemetryEntityNames.test.ts +23 -0
- package/Tests/Utils/LabelRuleImportExport.test.ts +5 -0
- package/Tests/Utils/MetricUnitUtil.test.ts +227 -2
- package/Tests/Utils/Monitor/MetricValueFormatter.test.ts +288 -2
- package/Tests/Utils/Monitor/PlatformResourceIdentityAndUnits.test.ts +1559 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.test.ts +2546 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +315 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +336 -1
- package/Tests/Utils/NetworkDiscovery/NetbiosNameUtil.test.ts +244 -0
- package/Tests/Utils/ValueFormatter.test.ts +50 -0
- package/Tests/tsconfig.json +16 -0
- package/Types/AI/AIResourceContext.ts +7 -0
- package/Types/Dashboard/DashboardTemplates.ts +2 -1
- package/Types/DatabaseServer/DatabaseConnectionSpan.ts +77 -0
- package/Types/DatabaseServer/DatabaseContainerClassifier.ts +2068 -0
- package/Types/DatabaseServer/DatabaseContainerCommand.ts +801 -0
- package/Types/DatabaseServer/DatabaseEndpoint.ts +1943 -0
- package/Types/DatabaseServer/DatabaseServerDiscoverySource.ts +68 -0
- package/Types/DatabaseServer/DatabaseServerMetricCatalog.ts +966 -0
- package/Types/DatabaseServer/DatabaseSystem.ts +2124 -0
- package/Types/DatabaseServer/DatabaseTelemetryResolver.ts +555 -0
- package/Types/Email/EmailTemplateType.ts +1 -0
- package/Types/Monitor/CephAlertTemplates.ts +18 -0
- package/Types/Monitor/DatabaseAlertTemplates.ts +2020 -0
- package/Types/Monitor/KubernetesAlertTemplates.ts +64 -24
- package/Types/Monitor/KubernetesMetricCatalog.ts +118 -19
- package/Types/Monitor/MetricMonitor/MetricCriteriaContext.ts +14 -0
- package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +93 -10
- package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +109 -8
- package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +36 -7
- package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +43 -2
- package/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.ts +41 -6
- package/Types/Monitor/SeriesContext/SeriesLabelDisplay.ts +26 -0
- package/Types/NetworkDevice/DiscoveredHostNamingStatus.ts +147 -0
- package/Types/Permission.ts +267 -0
- package/Types/Probe/ProbeApiIngestResponse.ts +8 -0
- package/Types/Rules/RuleCriteriaFieldRegistry.ts +10 -0
- package/Types/Rules/RuleRun.ts +12 -0
- package/Types/Telemetry/EntityType.ts +23 -0
- package/Types/Telemetry/ResourceFacetCatalog.ts +14 -0
- package/Types/Telemetry/ServiceType.ts +8 -0
- package/UI/Components/Banner/Banner.tsx +1 -1
- package/UI/Components/Card/Card.tsx +1 -1
- package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +2 -2
- package/UI/Components/Charts/Line/LineChart.tsx +7 -0
- package/UI/Components/CommandPalette/CommandPalette.tsx +1 -1
- package/UI/Components/Date/StartAndEndDate.tsx +5 -5
- package/UI/Components/Diagram/HorizontalStepChain.tsx +1 -1
- package/UI/Components/Feed/FeedOptionsButton.tsx +1 -1
- package/UI/Components/Forms/BasicForm.tsx +1 -1
- package/UI/Components/Header/Header.tsx +1 -1
- package/UI/Components/Header/HeaderIconDropdownButton.tsx +1 -1
- package/UI/Components/HeaderAlert/HeaderAlert.tsx +1 -1
- package/UI/Components/LogsViewer/components/FacetValueRow.tsx +1 -1
- package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +1 -1
- package/UI/Components/Modal/ModalFooter.tsx +1 -1
- package/UI/Components/ModelDetail/CardModelDetail.tsx +2 -2
- package/UI/Components/ModelTable/BaseModelTable.tsx +4 -4
- package/UI/Components/Navbar/NavBar.tsx +9 -2
- package/UI/Components/Navbar/NavBarMenuModal.tsx +2 -2
- package/UI/Components/Page/Page.tsx +1 -1
- package/UI/Components/Pagination/Pagination.tsx +3 -3
- package/UI/Components/ProgressButtons/ProgressButtonItem.tsx +1 -1
- package/UI/Components/SideMenu/SideMenu.tsx +4 -1
- package/UI/Components/StatusPage/ResourceGroupNavigator.tsx +4 -2
- package/UI/Components/StatusPage/ResourceList.tsx +6 -6
- package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +1 -1
- package/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.tsx +1 -1
- package/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.tsx +1 -1
- package/UI/Components/Workflow/ComponentsModal.tsx +2 -2
- package/UI/Components/Workflow/StepTraceViewer.tsx +1 -1
- package/UI/Styles/Theme.css +8 -1
- package/UI/Utils/Navigation.ts +89 -42
- package/UI/Utils/Telemetry/TelemetryEntityNames.ts +7 -0
- package/UI/Utils/TelemetryService.ts +4 -3
- package/Utils/LabelRuleImportExport.ts +2 -0
- package/Utils/MetricUnitUtil.ts +103 -11
- package/Utils/Monitor/MetricValueFormatter.ts +66 -13
- package/Utils/Monitor/PlatformMetricUnitUtil.ts +215 -0
- package/Utils/Monitor/PlatformResourceIdentity.ts +514 -0
- package/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.ts +425 -0
- package/Utils/NetworkDiscovery/DiscoveredHostUtil.ts +32 -0
- package/Utils/NetworkDiscovery/NetbiosNameUtil.ts +73 -0
- package/Utils/Telemetry/DatabaseServerEntityKeys.ts +275 -0
- package/Utils/Telemetry/EntityKey.ts +176 -0
- package/Utils/ValueFormatter.ts +16 -0
- package/build/dist/Models/DatabaseModels/Alert.js +54 -0
- package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DatabaseServer.js +1683 -0
- package/build/dist/Models/DatabaseModels/DatabaseServer.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerEndpoint.js +559 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerEndpoint.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerFeed.js +648 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerFeed.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerLabelRule.js +522 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerLabelRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerOwnerRule.js +603 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerOwnerRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerOwnerTeam.js +506 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerOwnerTeam.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerOwnerUser.js +505 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerOwnerUser.js.map +1 -0
- package/build/dist/Models/DatabaseModels/Incident.js +54 -0
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +16 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +54 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TelemetryException.js +2 -0
- package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserProjectSsoConsent.js +162 -0
- package/build/dist/Models/DatabaseModels/UserProjectSsoConsent.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795000000000-AddDatabaseServerTables.js +240 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795000000000-AddDatabaseServerTables.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795100000000-AddUserProjectSsoConsent.js +26 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795100000000-AddUserProjectSsoConsent.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/MultipartFormData.js +1 -1
- package/build/dist/Server/Middleware/TelemetryIngest.js +15 -8
- package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
- package/build/dist/Server/Services/AlertReminderRuleService.js +72 -23
- package/build/dist/Server/Services/AlertReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseServerEndpointService.js +694 -0
- package/build/dist/Server/Services/DatabaseServerEndpointService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerFeedService.js +110 -0
- package/build/dist/Server/Services/DatabaseServerFeedService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerLabelRuleEngineService.js +272 -0
- package/build/dist/Server/Services/DatabaseServerLabelRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerLabelRuleService.js +13 -0
- package/build/dist/Server/Services/DatabaseServerLabelRuleService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerOwnerRuleEngineService.js +340 -0
- package/build/dist/Server/Services/DatabaseServerOwnerRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerOwnerRuleService.js +13 -0
- package/build/dist/Server/Services/DatabaseServerOwnerRuleService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerOwnerTeamService.js +160 -0
- package/build/dist/Server/Services/DatabaseServerOwnerTeamService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerOwnerUserService.js +153 -0
- package/build/dist/Server/Services/DatabaseServerOwnerUserService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerService.js +3272 -0
- package/build/dist/Server/Services/DatabaseServerService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseService.js +8 -4
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DockerResourceService.js +30 -3
- package/build/dist/Server/Services/DockerResourceService.js.map +1 -1
- package/build/dist/Server/Services/IncidentReminderRuleService.js +73 -23
- package/build/dist/Server/Services/IncidentReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +16 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/InventoryItemService.js +88 -5
- package/build/dist/Server/Services/InventoryItemService.js.map +1 -1
- package/build/dist/Server/Services/IoTDeviceService.js +111 -24
- package/build/dist/Server/Services/IoTDeviceService.js.map +1 -1
- package/build/dist/Server/Services/OpenTelemetryIngestService.js +24 -9
- package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
- package/build/dist/Server/Services/PodmanResourceService.js +30 -3
- package/build/dist/Server/Services/PodmanResourceService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js +75 -23
- package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/ServiceService.js +1 -1
- package/build/dist/Server/Services/ServiceService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryUsageBillingService.js +23 -2
- package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
- package/build/dist/Server/Services/UserProjectSsoConsentService.js +79 -0
- package/build/dist/Server/Services/UserProjectSsoConsentService.js.map +1 -0
- package/build/dist/Server/Services/UserService.js +13 -1
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +18 -0
- package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryHelper.js +26 -1
- package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js +46 -0
- package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js.map +1 -1
- package/build/dist/Server/Utils/Database/AffectedResourceRelations.js +6 -0
- package/build/dist/Server/Utils/Database/AffectedResourceRelations.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +134 -13
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +22 -6
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +1489 -524
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +22 -6
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js +196 -6
- package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +36 -9
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js +175 -17
- package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/PerSeriesResolutionRootCause.js +29 -0
- package/build/dist/Server/Utils/Monitor/PerSeriesResolutionRootCause.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +211 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js +82 -10
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js.map +1 -1
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +25 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +20 -4
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js +2 -0
- package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/DatabaseEndpointDiscovery.js +442 -0
- package/build/dist/Server/Utils/Telemetry/DatabaseEndpointDiscovery.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +5 -1
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js +15 -1
- package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +121 -5
- package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js +12 -0
- package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ServiceDependencyDiscovery.js +438 -36
- package/build/dist/Server/Utils/Telemetry/ServiceDependencyDiscovery.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/Telemetry.js +12 -0
- package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +17 -18
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js +16 -10
- package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js.map +1 -1
- package/build/dist/Types/AI/AIResourceContext.js +7 -0
- package/build/dist/Types/AI/AIResourceContext.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardTemplates.js +2 -1
- package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
- package/build/dist/Types/DatabaseServer/DatabaseConnectionSpan.js +71 -0
- package/build/dist/Types/DatabaseServer/DatabaseConnectionSpan.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseContainerClassifier.js +1462 -0
- package/build/dist/Types/DatabaseServer/DatabaseContainerClassifier.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseContainerCommand.js +691 -0
- package/build/dist/Types/DatabaseServer/DatabaseContainerCommand.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseEndpoint.js +1407 -0
- package/build/dist/Types/DatabaseServer/DatabaseEndpoint.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseServerDiscoverySource.js +60 -0
- package/build/dist/Types/DatabaseServer/DatabaseServerDiscoverySource.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseServerMetricCatalog.js +804 -0
- package/build/dist/Types/DatabaseServer/DatabaseServerMetricCatalog.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseSystem.js +1860 -0
- package/build/dist/Types/DatabaseServer/DatabaseSystem.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseTelemetryResolver.js +406 -0
- package/build/dist/Types/DatabaseServer/DatabaseTelemetryResolver.js.map +1 -0
- package/build/dist/Types/Email/EmailTemplateType.js +1 -0
- package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
- package/build/dist/Types/Monitor/CephAlertTemplates.js +18 -0
- package/build/dist/Types/Monitor/CephAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/DatabaseAlertTemplates.js +1518 -0
- package/build/dist/Types/Monitor/DatabaseAlertTemplates.js.map +1 -0
- package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +57 -24
- package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/KubernetesMetricCatalog.js +104 -18
- package/build/dist/Types/Monitor/KubernetesMetricCatalog.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +80 -3
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +10 -3
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +29 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js +21 -6
- package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js.map +1 -1
- package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js +25 -0
- package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js.map +1 -1
- package/build/dist/Types/NetworkDevice/DiscoveredHostNamingStatus.js +136 -0
- package/build/dist/Types/NetworkDevice/DiscoveredHostNamingStatus.js.map +1 -0
- package/build/dist/Types/Permission.js +234 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +10 -0
- package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
- package/build/dist/Types/Rules/RuleRun.js +4 -0
- package/build/dist/Types/Rules/RuleRun.js.map +1 -1
- package/build/dist/Types/Telemetry/EntityType.js +23 -0
- package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
- package/build/dist/Types/Telemetry/ResourceFacetCatalog.js +14 -0
- package/build/dist/Types/Telemetry/ResourceFacetCatalog.js.map +1 -1
- package/build/dist/Types/Telemetry/ServiceType.js +8 -0
- package/build/dist/Types/Telemetry/ServiceType.js.map +1 -1
- package/build/dist/UI/Components/Banner/Banner.js +1 -1
- package/build/dist/UI/Components/Banner/Banner.js.map +1 -1
- package/build/dist/UI/Components/Card/Card.js +1 -1
- package/build/dist/UI/Components/Card/Card.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +2 -2
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js +1 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
- package/build/dist/UI/Components/CommandPalette/CommandPalette.js +1 -1
- package/build/dist/UI/Components/CommandPalette/CommandPalette.js.map +1 -1
- package/build/dist/UI/Components/Date/StartAndEndDate.js +5 -5
- package/build/dist/UI/Components/Date/StartAndEndDate.js.map +1 -1
- package/build/dist/UI/Components/Diagram/HorizontalStepChain.js +1 -1
- package/build/dist/UI/Components/Diagram/HorizontalStepChain.js.map +1 -1
- package/build/dist/UI/Components/Feed/FeedOptionsButton.js +1 -1
- package/build/dist/UI/Components/Feed/FeedOptionsButton.js.map +1 -1
- package/build/dist/UI/Components/Forms/BasicForm.js +1 -1
- package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
- package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +1 -1
- package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
- package/build/dist/UI/Components/HeaderAlert/HeaderAlert.js +1 -1
- package/build/dist/UI/Components/HeaderAlert/HeaderAlert.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/FacetValueRow.js +1 -1
- package/build/dist/UI/Components/LogsViewer/components/FacetValueRow.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/Modal/ModalFooter.js +1 -1
- package/build/dist/UI/Components/Modal/ModalFooter.js.map +1 -1
- package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +2 -2
- package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +4 -4
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBar.js +9 -2
- package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +2 -2
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
- package/build/dist/UI/Components/Page/Page.js +1 -1
- package/build/dist/UI/Components/Page/Page.js.map +1 -1
- package/build/dist/UI/Components/Pagination/Pagination.js +3 -3
- package/build/dist/UI/Components/Pagination/Pagination.js.map +1 -1
- package/build/dist/UI/Components/ProgressButtons/ProgressButtonItem.js +1 -1
- package/build/dist/UI/Components/ProgressButtons/ProgressButtonItem.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/SideMenu.js +4 -1
- package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
- package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js +3 -1
- package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js.map +1 -1
- package/build/dist/UI/Components/StatusPage/ResourceList.js +6 -6
- package/build/dist/UI/Components/StatusPage/ResourceList.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js +1 -1
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ComponentsModal.js +2 -2
- package/build/dist/UI/Components/Workflow/ComponentsModal.js.map +1 -1
- package/build/dist/UI/Components/Workflow/StepTraceViewer.js +1 -1
- package/build/dist/UI/Components/Workflow/StepTraceViewer.js.map +1 -1
- package/build/dist/UI/Utils/Navigation.js +66 -33
- package/build/dist/UI/Utils/Navigation.js.map +1 -1
- package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js +7 -0
- package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js.map +1 -1
- package/build/dist/UI/Utils/TelemetryService.js +3 -2
- package/build/dist/UI/Utils/TelemetryService.js.map +1 -1
- package/build/dist/Utils/LabelRuleImportExport.js +2 -0
- package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
- package/build/dist/Utils/MetricUnitUtil.js +77 -13
- package/build/dist/Utils/MetricUnitUtil.js.map +1 -1
- package/build/dist/Utils/Monitor/MetricValueFormatter.js +58 -13
- package/build/dist/Utils/Monitor/MetricValueFormatter.js.map +1 -1
- package/build/dist/Utils/Monitor/PlatformMetricUnitUtil.js +161 -0
- package/build/dist/Utils/Monitor/PlatformMetricUnitUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/PlatformResourceIdentity.js +323 -0
- package/build/dist/Utils/Monitor/PlatformResourceIdentity.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.js +270 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js +23 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/NetbiosNameUtil.js +61 -0
- package/build/dist/Utils/NetworkDiscovery/NetbiosNameUtil.js.map +1 -1
- package/build/dist/Utils/Telemetry/DatabaseServerEntityKeys.js +178 -0
- package/build/dist/Utils/Telemetry/DatabaseServerEntityKeys.js.map +1 -0
- package/build/dist/Utils/Telemetry/EntityKey.js +133 -0
- package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -1
- package/build/dist/Utils/ValueFormatter.js +15 -0
- package/build/dist/Utils/ValueFormatter.js.map +1 -1
- package/package.json +1 -1
- package/tsconfig.tests.json +7 -5
|
@@ -0,0 +1,895 @@
|
|
|
1
|
+
import DatabaseService from "./DatabaseService";
|
|
2
|
+
import DatabaseServerFeedService from "./DatabaseServerFeedService";
|
|
3
|
+
import DatabaseServerService from "./DatabaseServerService";
|
|
4
|
+
import Model from "../../Models/DatabaseModels/DatabaseServerEndpoint";
|
|
5
|
+
import DatabaseServer from "../../Models/DatabaseModels/DatabaseServer";
|
|
6
|
+
import { DatabaseServerFeedEventType } from "../../Models/DatabaseModels/DatabaseServerFeed";
|
|
7
|
+
import CreateBy from "../Types/Database/CreateBy";
|
|
8
|
+
import DeleteBy from "../Types/Database/DeleteBy";
|
|
9
|
+
import { OnCreate, OnDelete } from "../Types/Database/Hooks";
|
|
10
|
+
import ModelPermission from "../Types/Database/Permissions/Index";
|
|
11
|
+
import Query from "../Types/Database/Query";
|
|
12
|
+
import RelationIdUtil from "../Utils/Database/RelationIdUtil";
|
|
13
|
+
import logger from "../Utils/Logger";
|
|
14
|
+
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
15
|
+
import DatabaseCommonInteractionProps from "../../Types/BaseDatabase/DatabaseCommonInteractionProps";
|
|
16
|
+
import SortOrder from "../../Types/BaseDatabase/SortOrder";
|
|
17
|
+
import { Gray500, Red500 } from "../../Types/BrandColors";
|
|
18
|
+
import ColumnLength from "../../Types/Database/ColumnLength";
|
|
19
|
+
import LIMIT_MAX from "../../Types/Database/LimitMax";
|
|
20
|
+
import OneUptimeDate from "../../Types/Date";
|
|
21
|
+
import BadDataException from "../../Types/Exception/BadDataException";
|
|
22
|
+
import NotAuthorizedException from "../../Types/Exception/NotAuthorizedException";
|
|
23
|
+
import ObjectID from "../../Types/ObjectID";
|
|
24
|
+
import {
|
|
25
|
+
DatabaseEndpoint,
|
|
26
|
+
ManualDatabaseEndpoint,
|
|
27
|
+
formatDatabaseEndpoint,
|
|
28
|
+
parseManualDatabaseEndpoint,
|
|
29
|
+
} from "../../Types/DatabaseServer/DatabaseEndpoint";
|
|
30
|
+
|
|
31
|
+
/*
|
|
32
|
+
* Who added an endpoint:
|
|
33
|
+
* - "auto": a telemetry path claimed it (the endpoint an application trace
|
|
34
|
+
* or a collector reported);
|
|
35
|
+
* - "workload": container discovery claimed it as a Service name of the
|
|
36
|
+
* Kubernetes workload the database runs as - released again once the
|
|
37
|
+
* workload stops producing it;
|
|
38
|
+
* - "user": a person added it (an alias from the database's Endpoints tab,
|
|
39
|
+
* or the address typed into the create form of a manually added
|
|
40
|
+
* database). Discovery never releases or moves a "user" endpoint.
|
|
41
|
+
*/
|
|
42
|
+
export type DatabaseServerEndpointSource = "auto" | "workload" | "user";
|
|
43
|
+
|
|
44
|
+
/*
|
|
45
|
+
* The outcome of claimEndpoint. Discovery only ever needs to know whether the
|
|
46
|
+
* endpoint is now this row's, and - when it is not - that some other row
|
|
47
|
+
* already owns it, which is never tie-broken or taken over.
|
|
48
|
+
*/
|
|
49
|
+
export type DatabaseServerEndpointClaimResult =
|
|
50
|
+
| "claimed"
|
|
51
|
+
| "already-owned-by-this"
|
|
52
|
+
| "owned-by-other";
|
|
53
|
+
|
|
54
|
+
export interface DatabaseServerEndpointOwner {
|
|
55
|
+
databaseServerId: ObjectID;
|
|
56
|
+
isPrimary: boolean;
|
|
57
|
+
// The endpoint row itself, when it was read (findOwnerByEndpoint reads it).
|
|
58
|
+
endpointId?: ObjectID | undefined;
|
|
59
|
+
source?: string | undefined;
|
|
60
|
+
lastMatchedAt?: Date | undefined;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/*
|
|
64
|
+
* "Last matched" is refreshed at most this often per endpoint: often enough
|
|
65
|
+
* that a stale alias stands out on the Endpoints tab, rarely enough that a
|
|
66
|
+
* busy endpoint costs one write an hour, not one per lookup.
|
|
67
|
+
*/
|
|
68
|
+
export const ENDPOINT_MATCH_REFRESH_SECONDS: number = 60 * 60;
|
|
69
|
+
|
|
70
|
+
// What onBeforeDelete hands onDeleteSuccess: the endpoints the delete matched.
|
|
71
|
+
interface EndpointDeleteCarryForward {
|
|
72
|
+
endpointsToDelete: Array<Model>;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// What an alias looks like, for the refusal of an empty one.
|
|
76
|
+
const ENDPOINT_EXAMPLE: string =
|
|
77
|
+
"Enter the host name or IP address applications use to reach this database, with an optional port, for example orders-db.example.com:5432.";
|
|
78
|
+
|
|
79
|
+
/*
|
|
80
|
+
* The endpoints a database is reached at. Every endpoint belongs to at most
|
|
81
|
+
* one database per project: the (projectId, endpoint) unique index enforces
|
|
82
|
+
* it, and this service turns a collision into a message naming the database
|
|
83
|
+
* that already owns the endpoint instead of a raw constraint error.
|
|
84
|
+
*
|
|
85
|
+
* Endpoints are stored canonical (formatDatabaseEndpoint), because the
|
|
86
|
+
* telemetry entity key of a database is derived from the endpoint string -
|
|
87
|
+
* a person typing "Orders-DB.example.com" must land on the same key ingest
|
|
88
|
+
* computes for `server.address=orders-db.example.com`.
|
|
89
|
+
*/
|
|
90
|
+
export class Service extends DatabaseService<Model> {
|
|
91
|
+
public constructor() {
|
|
92
|
+
super(Model);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/*
|
|
96
|
+
* A person adding an alias. Root writes (the discovery paths, through
|
|
97
|
+
* claimEndpoint) pass through untouched: they already hold a canonical
|
|
98
|
+
* endpoint and handle ownership themselves.
|
|
99
|
+
*
|
|
100
|
+
* Adding an endpoint is an EDIT of the database it is added to: it decides
|
|
101
|
+
* which traffic that database's pages show and - one owner per endpoint -
|
|
102
|
+
* that no other database can claim it. So the caller must be allowed to
|
|
103
|
+
* edit that very row, label and Owned scopes included. DatabaseService
|
|
104
|
+
* checks the create permission only after this hook, and never scopes a
|
|
105
|
+
* create to the parent row, so both happen here - the create permission
|
|
106
|
+
* FIRST, so a caller without it learns nothing about which databases exist
|
|
107
|
+
* or who owns an endpoint.
|
|
108
|
+
*/
|
|
109
|
+
@CaptureSpan()
|
|
110
|
+
protected override async onBeforeCreate(
|
|
111
|
+
createBy: CreateBy<Model>,
|
|
112
|
+
): Promise<OnCreate<Model>> {
|
|
113
|
+
if (createBy.props.isRoot) {
|
|
114
|
+
return { createBy: createBy, carryForward: null };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const data: Model = createBy.data;
|
|
118
|
+
|
|
119
|
+
ModelPermission.checkCreatePermissions(Model, data, createBy.props);
|
|
120
|
+
|
|
121
|
+
/*
|
|
122
|
+
* The tenant column is stamped from props.tenantId only after this hook,
|
|
123
|
+
* so read the request tenant first - it is the only project the caller
|
|
124
|
+
* was checked in.
|
|
125
|
+
*/
|
|
126
|
+
const projectId: ObjectID | undefined =
|
|
127
|
+
createBy.props.tenantId || data.projectId || undefined;
|
|
128
|
+
|
|
129
|
+
if (!projectId) {
|
|
130
|
+
throw new BadDataException(
|
|
131
|
+
"Project ID is required to add a database endpoint.",
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/*
|
|
136
|
+
* The reference arrives as the FK column or as a relation object, and
|
|
137
|
+
* TypeORM persists the relation object's id over the column's. Read both
|
|
138
|
+
* spellings, refuse a payload whose two spellings disagree, and leave the
|
|
139
|
+
* validated column as the only one that can reach the insert.
|
|
140
|
+
*/
|
|
141
|
+
const databaseServerId: ObjectID | null = RelationIdUtil.readConsistent(
|
|
142
|
+
data as unknown as Record<string, unknown>,
|
|
143
|
+
["databaseServerId", "databaseServer"],
|
|
144
|
+
"database",
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
data.setColumnValue("databaseServer", undefined);
|
|
148
|
+
|
|
149
|
+
if (!databaseServerId) {
|
|
150
|
+
throw new BadDataException(
|
|
151
|
+
"Select the database this endpoint belongs to.",
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const databaseServer: DatabaseServer | null =
|
|
156
|
+
await this.findEditableDatabaseServer({
|
|
157
|
+
projectId: projectId,
|
|
158
|
+
databaseServerId: databaseServerId,
|
|
159
|
+
props: createBy.props,
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
/*
|
|
163
|
+
* One answer for "no such database in this project" and "a database you
|
|
164
|
+
* may not edit", so the refusal is not a way to probe for ids.
|
|
165
|
+
*/
|
|
166
|
+
if (!databaseServer) {
|
|
167
|
+
throw new NotAuthorizedException(
|
|
168
|
+
"Database not found, or you do not have permission to edit it. Adding an endpoint to a database needs permission to edit that database.",
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/*
|
|
173
|
+
* Canonicalize with the database's own context: its engine supplies the
|
|
174
|
+
* default port, and for a database discovered on Kubernetes its
|
|
175
|
+
* namespace expands a bare service name (and `<service>.<namespace>` to
|
|
176
|
+
* the Service's full name) and its cluster qualifies a cluster-local
|
|
177
|
+
* name - exactly what ingest does for the pods calling it. A value that
|
|
178
|
+
* cannot be used - `user@host`, a cluster qualifier on a public host, a
|
|
179
|
+
* loopback name, a port outside 1-65535 - is refused with a message
|
|
180
|
+
* saying what to change, never read as something else or quietly given
|
|
181
|
+
* the engine's default port.
|
|
182
|
+
*/
|
|
183
|
+
const manual: ManualDatabaseEndpoint = parseManualDatabaseEndpoint(
|
|
184
|
+
data.endpoint,
|
|
185
|
+
{
|
|
186
|
+
system: databaseServer.dbSystem || "",
|
|
187
|
+
kubernetesClusterName:
|
|
188
|
+
databaseServer.kubernetesCluster?.clusterIdentifier,
|
|
189
|
+
kubernetesNamespace: databaseServer.kubernetesNamespace,
|
|
190
|
+
},
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
const endpoint: DatabaseEndpoint | null = manual.endpoint;
|
|
194
|
+
|
|
195
|
+
if (!endpoint) {
|
|
196
|
+
throw new BadDataException(
|
|
197
|
+
typeof data.endpoint !== "string" || !data.endpoint.trim()
|
|
198
|
+
? `Endpoint is required. ${ENDPOINT_EXAMPLE}`
|
|
199
|
+
: manual.error || `This is not a valid endpoint. ${ENDPOINT_EXAMPLE}`,
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const formatted: string = formatDatabaseEndpoint(endpoint);
|
|
204
|
+
|
|
205
|
+
if (formatted.length > ColumnLength.LongText) {
|
|
206
|
+
throw new BadDataException(
|
|
207
|
+
`This endpoint is too long. Endpoints can be at most ${ColumnLength.LongText} characters.`,
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const owner: DatabaseServerEndpointOwner | null =
|
|
212
|
+
await this.findOwnerByEndpoint(projectId, formatted);
|
|
213
|
+
|
|
214
|
+
if (owner) {
|
|
215
|
+
if (owner.databaseServerId.toString() === databaseServerId.toString()) {
|
|
216
|
+
throw new BadDataException(
|
|
217
|
+
`${formatted} is already an endpoint of this database.`,
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
throw new BadDataException(
|
|
222
|
+
await getOwnedByOtherDatabaseMessage(formatted, owner, createBy.props),
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
data.databaseServerId = databaseServerId;
|
|
227
|
+
data.endpoint = formatted;
|
|
228
|
+
/*
|
|
229
|
+
* Forced, whatever the caller sent: a person only ever adds a removable
|
|
230
|
+
* alias. The primary endpoint is written by whichever path created the
|
|
231
|
+
* database, as root.
|
|
232
|
+
*/
|
|
233
|
+
data.source = "user";
|
|
234
|
+
data.isPrimary = false;
|
|
235
|
+
|
|
236
|
+
return { createBy: createBy, carryForward: null };
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/*
|
|
240
|
+
* A person removing endpoints. Removing one is an EDIT of the database it
|
|
241
|
+
* belongs to, exactly like adding one (onBeforeCreate): it decides which
|
|
242
|
+
* traffic that database's pages show, and frees the endpoint for another
|
|
243
|
+
* database to claim. DatabaseService scopes a delete to the project only -
|
|
244
|
+
* the endpoint has no labels of its own, and the parent's label and Owned
|
|
245
|
+
* scopes never reach a delete - so the caller must be allowed to edit
|
|
246
|
+
* every database the delete would touch, checked here: the delete
|
|
247
|
+
* permission FIRST (so a caller without it learns nothing), then the
|
|
248
|
+
* parents, and only then the primary guard, whose refusal names the
|
|
249
|
+
* endpoint.
|
|
250
|
+
*
|
|
251
|
+
* The primary endpoint is what the database was created from; discovery
|
|
252
|
+
* would claim it straight back, and a manually added database would lose
|
|
253
|
+
* the only endpoint its telemetry is keyed by. Aliases can be removed.
|
|
254
|
+
*/
|
|
255
|
+
@CaptureSpan()
|
|
256
|
+
protected override async onBeforeDelete(
|
|
257
|
+
deleteBy: DeleteBy<Model>,
|
|
258
|
+
): Promise<OnDelete<Model>> {
|
|
259
|
+
if (deleteBy.props.isRoot) {
|
|
260
|
+
return { deleteBy: deleteBy, carryForward: null };
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// The project the caller was checked in, whatever project the query named.
|
|
264
|
+
const query: Query<Model> =
|
|
265
|
+
await ModelPermission.checkDeleteQueryPermission(
|
|
266
|
+
Model,
|
|
267
|
+
deleteBy.query,
|
|
268
|
+
deleteBy.props,
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
const matched: Array<Model> = await this.findBy({
|
|
272
|
+
query: query,
|
|
273
|
+
select: {
|
|
274
|
+
_id: true,
|
|
275
|
+
projectId: true,
|
|
276
|
+
databaseServerId: true,
|
|
277
|
+
endpoint: true,
|
|
278
|
+
isPrimary: true,
|
|
279
|
+
},
|
|
280
|
+
limit: LIMIT_MAX,
|
|
281
|
+
skip: 0,
|
|
282
|
+
props: {
|
|
283
|
+
isRoot: true,
|
|
284
|
+
},
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
const checked: Set<string> = new Set<string>();
|
|
288
|
+
|
|
289
|
+
for (const endpoint of matched) {
|
|
290
|
+
const databaseServerId: string | undefined =
|
|
291
|
+
endpoint.databaseServerId?.toString();
|
|
292
|
+
const projectId: ObjectID | undefined =
|
|
293
|
+
deleteBy.props.tenantId || endpoint.projectId || undefined;
|
|
294
|
+
|
|
295
|
+
if (!databaseServerId || !projectId || checked.has(databaseServerId)) {
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const databaseServer: DatabaseServer | null =
|
|
300
|
+
await this.findEditableDatabaseServer({
|
|
301
|
+
projectId: projectId,
|
|
302
|
+
databaseServerId: new ObjectID(databaseServerId),
|
|
303
|
+
props: deleteBy.props,
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
// The same answer onBeforeCreate gives: no probing for ids.
|
|
307
|
+
if (!databaseServer) {
|
|
308
|
+
throw new NotAuthorizedException(
|
|
309
|
+
"Database not found, or you do not have permission to edit it. Removing an endpoint from a database needs permission to edit that database.",
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
checked.add(databaseServerId);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const primary: Model | undefined = matched.find((endpoint: Model) => {
|
|
317
|
+
return Boolean(endpoint.isPrimary);
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
if (primary) {
|
|
321
|
+
const endpoint: string = primary.endpoint || "The primary endpoint";
|
|
322
|
+
|
|
323
|
+
throw new BadDataException(
|
|
324
|
+
`${endpoint} is the primary endpoint of this database and cannot be removed. Add another endpoint as an alias instead, or delete the database.`,
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// The rows are gone by onDeleteSuccess: its feed items are built from these.
|
|
329
|
+
const carryForward: EndpointDeleteCarryForward = {
|
|
330
|
+
endpointsToDelete: matched,
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
return { deleteBy: deleteBy, carryForward: carryForward };
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/*
|
|
337
|
+
* A person added an alias: that is an edit of the database (it decides
|
|
338
|
+
* which traffic the database's pages show), so it goes on the database's
|
|
339
|
+
* Feed like any other edit, naming the endpoint and who added it. A
|
|
340
|
+
* discovery claim is root and never gets here.
|
|
341
|
+
*/
|
|
342
|
+
@CaptureSpan()
|
|
343
|
+
protected override async onCreateSuccess(
|
|
344
|
+
onCreate: OnCreate<Model>,
|
|
345
|
+
createdItem: Model,
|
|
346
|
+
): Promise<Model> {
|
|
347
|
+
if (onCreate.createBy.props.isRoot) {
|
|
348
|
+
return createdItem;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
await this.writeEndpointFeedItem({
|
|
352
|
+
change: "added",
|
|
353
|
+
endpoint: createdItem,
|
|
354
|
+
projectId:
|
|
355
|
+
createdItem.projectId || onCreate.createBy.props.tenantId || undefined,
|
|
356
|
+
userId:
|
|
357
|
+
createdItem.createdByUserId ||
|
|
358
|
+
onCreate.createBy.props.userId ||
|
|
359
|
+
undefined,
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
return createdItem;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/*
|
|
366
|
+
* A person removed aliases: one feed item per endpoint actually removed,
|
|
367
|
+
* on its own database. Discovery's releases and moves are root writes and
|
|
368
|
+
* never get here.
|
|
369
|
+
*/
|
|
370
|
+
@CaptureSpan()
|
|
371
|
+
protected override async onDeleteSuccess(
|
|
372
|
+
onDelete: OnDelete<Model>,
|
|
373
|
+
itemIdsBeforeDelete: Array<ObjectID>,
|
|
374
|
+
): Promise<OnDelete<Model>> {
|
|
375
|
+
const carried: EndpointDeleteCarryForward | null =
|
|
376
|
+
(onDelete.carryForward as EndpointDeleteCarryForward | null) || null;
|
|
377
|
+
|
|
378
|
+
if (onDelete.deleteBy.props.isRoot || !carried) {
|
|
379
|
+
return onDelete;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const deletedIds: Set<string> = new Set<string>(
|
|
383
|
+
(itemIdsBeforeDelete || []).map((id: ObjectID): string => {
|
|
384
|
+
return id.toString();
|
|
385
|
+
}),
|
|
386
|
+
);
|
|
387
|
+
|
|
388
|
+
const userId: ObjectID | undefined =
|
|
389
|
+
onDelete.deleteBy.deletedByUser?.id ||
|
|
390
|
+
onDelete.deleteBy.props.userId ||
|
|
391
|
+
undefined;
|
|
392
|
+
|
|
393
|
+
for (const endpoint of carried.endpointsToDelete || []) {
|
|
394
|
+
if (!endpoint._id || !deletedIds.has(endpoint._id.toString())) {
|
|
395
|
+
continue;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
await this.writeEndpointFeedItem({
|
|
399
|
+
change: "removed",
|
|
400
|
+
endpoint: endpoint,
|
|
401
|
+
projectId:
|
|
402
|
+
endpoint.projectId || onDelete.deleteBy.props.tenantId || undefined,
|
|
403
|
+
userId: userId,
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
return onDelete;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// One "endpoint added / removed" item on the database's Feed. Never throws.
|
|
411
|
+
private async writeEndpointFeedItem(data: {
|
|
412
|
+
change: "added" | "removed";
|
|
413
|
+
endpoint: Model;
|
|
414
|
+
projectId: ObjectID | undefined;
|
|
415
|
+
userId: ObjectID | undefined;
|
|
416
|
+
}): Promise<void> {
|
|
417
|
+
const databaseServerId: ObjectID | undefined =
|
|
418
|
+
data.endpoint.databaseServerId || undefined;
|
|
419
|
+
const endpoint: string = (data.endpoint.endpoint || "").trim();
|
|
420
|
+
|
|
421
|
+
if (!databaseServerId || !data.projectId || !endpoint) {
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
try {
|
|
426
|
+
const link: string =
|
|
427
|
+
await DatabaseServerService.getDatabaseServerMarkdownLink(
|
|
428
|
+
data.projectId,
|
|
429
|
+
databaseServerId,
|
|
430
|
+
);
|
|
431
|
+
const added: boolean = data.change === "added";
|
|
432
|
+
|
|
433
|
+
await DatabaseServerFeedService.createDatabaseServerFeedItem({
|
|
434
|
+
databaseServerId: databaseServerId,
|
|
435
|
+
projectId: data.projectId,
|
|
436
|
+
databaseServerFeedEventType:
|
|
437
|
+
DatabaseServerFeedEventType.DatabaseServerUpdated,
|
|
438
|
+
displayColor: added ? Gray500 : Red500,
|
|
439
|
+
feedInfoInMarkdown: added
|
|
440
|
+
? `🔗 Added the endpoint \`${endpoint}\` to ${link}.`
|
|
441
|
+
: `🔗 Removed the endpoint \`${endpoint}\` from ${link}.`,
|
|
442
|
+
moreInformationInMarkdown: added
|
|
443
|
+
? `**Endpoint**: \`${endpoint}\`\n\nCalls applications make to this endpoint now count as this database's traffic, and no other database can claim it.`
|
|
444
|
+
: `**Endpoint**: \`${endpoint}\`\n\nCalls to this endpoint no longer count as this database's traffic, and another database may claim it.`,
|
|
445
|
+
userId: data.userId,
|
|
446
|
+
});
|
|
447
|
+
} catch (error) {
|
|
448
|
+
logger.warn(
|
|
449
|
+
`DatabaseServerEndpointService: could not write the feed item for endpoint ${endpoint} ${data.change}: ${
|
|
450
|
+
error instanceof Error ? error.message : String(error)
|
|
451
|
+
}`,
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* The database that owns this canonical (formatDatabaseEndpoint) endpoint
|
|
458
|
+
* in the project, or null when no database lists it.
|
|
459
|
+
*/
|
|
460
|
+
@CaptureSpan()
|
|
461
|
+
public async findOwnerByEndpoint(
|
|
462
|
+
projectId: ObjectID,
|
|
463
|
+
formattedEndpoint: string,
|
|
464
|
+
): Promise<DatabaseServerEndpointOwner | null> {
|
|
465
|
+
const endpoint: string = (formattedEndpoint || "").trim();
|
|
466
|
+
|
|
467
|
+
if (!endpoint) {
|
|
468
|
+
return null;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
const row: Model | null = await this.findOneBy({
|
|
472
|
+
query: {
|
|
473
|
+
projectId: projectId,
|
|
474
|
+
endpoint: endpoint,
|
|
475
|
+
},
|
|
476
|
+
select: {
|
|
477
|
+
_id: true,
|
|
478
|
+
databaseServerId: true,
|
|
479
|
+
isPrimary: true,
|
|
480
|
+
source: true,
|
|
481
|
+
lastMatchedAt: true,
|
|
482
|
+
},
|
|
483
|
+
props: {
|
|
484
|
+
isRoot: true,
|
|
485
|
+
},
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
if (!row || !row.databaseServerId) {
|
|
489
|
+
return null;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
return {
|
|
493
|
+
databaseServerId: new ObjectID(row.databaseServerId.toString()),
|
|
494
|
+
isPrimary: Boolean(row.isPrimary),
|
|
495
|
+
endpointId: row._id ? new ObjectID(row._id.toString()) : undefined,
|
|
496
|
+
source: row.source || undefined,
|
|
497
|
+
lastMatchedAt: row.lastMatchedAt || undefined,
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Record that telemetry just matched this endpoint to its database: moves
|
|
503
|
+
* lastMatchedAt to now, at most once per ENDPOINT_MATCH_REFRESH_SECONDS
|
|
504
|
+
* (decided from the lastMatchedAt the owner lookup already read, so a
|
|
505
|
+
* fresh endpoint costs nothing). A "workload" endpoint is left alone: its
|
|
506
|
+
* lastMatchedAt says when the workload last produced it, which is what
|
|
507
|
+
* decides whether discovery may release it. Never throws.
|
|
508
|
+
*/
|
|
509
|
+
@CaptureSpan()
|
|
510
|
+
public async markEndpointMatched(
|
|
511
|
+
owner: DatabaseServerEndpointOwner | null,
|
|
512
|
+
): Promise<void> {
|
|
513
|
+
if (!owner || !owner.endpointId || owner.source === "workload") {
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
const now: Date = OneUptimeDate.getCurrentDate();
|
|
518
|
+
|
|
519
|
+
if (
|
|
520
|
+
owner.lastMatchedAt &&
|
|
521
|
+
OneUptimeDate.isAfter(
|
|
522
|
+
owner.lastMatchedAt,
|
|
523
|
+
OneUptimeDate.addRemoveSeconds(now, -ENDPOINT_MATCH_REFRESH_SECONDS),
|
|
524
|
+
)
|
|
525
|
+
) {
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
try {
|
|
530
|
+
await this.updateColumnsByIdWithoutHooks({
|
|
531
|
+
id: owner.endpointId,
|
|
532
|
+
data: {
|
|
533
|
+
lastMatchedAt: now,
|
|
534
|
+
},
|
|
535
|
+
skipUpdateDateColumn: true,
|
|
536
|
+
});
|
|
537
|
+
owner.lastMatchedAt = now;
|
|
538
|
+
} catch (error) {
|
|
539
|
+
logger.warn(
|
|
540
|
+
`DatabaseServerEndpointService: could not record a match of endpoint ${owner.endpointId.toString()}: ${
|
|
541
|
+
error instanceof Error ? error.message : String(error)
|
|
542
|
+
}`,
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Move lastMatchedAt to `now` on those of `endpoints` this database owns
|
|
549
|
+
* whose lastMatchedAt is empty or older than `staleBefore` - one
|
|
550
|
+
* statement, however many endpoints. The workload path calls it for the
|
|
551
|
+
* aliases a discovery run produced again.
|
|
552
|
+
*/
|
|
553
|
+
@CaptureSpan()
|
|
554
|
+
public async refreshMatchedEndpoints(data: {
|
|
555
|
+
projectId: ObjectID;
|
|
556
|
+
databaseServerId: ObjectID;
|
|
557
|
+
endpoints: Array<string>;
|
|
558
|
+
now: Date;
|
|
559
|
+
staleBefore: Date;
|
|
560
|
+
}): Promise<void> {
|
|
561
|
+
if (data.endpoints.length === 0) {
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
await this.getRepository().manager.query(
|
|
566
|
+
`UPDATE "DatabaseServerEndpoint"
|
|
567
|
+
SET "lastMatchedAt" = $1
|
|
568
|
+
WHERE "projectId" = $2
|
|
569
|
+
AND "databaseServerId" = $3
|
|
570
|
+
AND "endpoint" = ANY($4::text[])
|
|
571
|
+
AND ("lastMatchedAt" IS NULL OR "lastMatchedAt" < $5)
|
|
572
|
+
AND "deletedAt" IS NULL`,
|
|
573
|
+
[
|
|
574
|
+
data.now,
|
|
575
|
+
data.projectId.toString(),
|
|
576
|
+
data.databaseServerId.toString(),
|
|
577
|
+
data.endpoints,
|
|
578
|
+
data.staleBefore,
|
|
579
|
+
],
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* Hand a discovered endpoint to another database: the workload that now
|
|
585
|
+
* serves it. A compare-and-set on the current owner, and never a "user"
|
|
586
|
+
* endpoint - those only a person moves. The endpoint becomes a "workload"
|
|
587
|
+
* endpoint of its new owner, matched now. True when it moved.
|
|
588
|
+
*/
|
|
589
|
+
@CaptureSpan()
|
|
590
|
+
public async transferEndpoint(data: {
|
|
591
|
+
projectId: ObjectID;
|
|
592
|
+
endpointId: ObjectID;
|
|
593
|
+
fromDatabaseServerId: ObjectID;
|
|
594
|
+
toDatabaseServerId: ObjectID;
|
|
595
|
+
isPrimary: boolean;
|
|
596
|
+
now: Date;
|
|
597
|
+
}): Promise<boolean> {
|
|
598
|
+
/*
|
|
599
|
+
* Wrapped in a CTE so the statement is a SELECT: TypeORM answers a bare
|
|
600
|
+
* UPDATE with [rows, rowCount], which would read as "moved" every time.
|
|
601
|
+
*/
|
|
602
|
+
const moved: unknown = await this.getRepository().manager.query(
|
|
603
|
+
`WITH "moved" AS (
|
|
604
|
+
UPDATE "DatabaseServerEndpoint"
|
|
605
|
+
SET "databaseServerId" = $1,
|
|
606
|
+
"source" = 'workload',
|
|
607
|
+
"isPrimary" = $2,
|
|
608
|
+
"lastMatchedAt" = $3,
|
|
609
|
+
"updatedAt" = CURRENT_TIMESTAMP
|
|
610
|
+
WHERE "_id" = $4
|
|
611
|
+
AND "projectId" = $5
|
|
612
|
+
AND "databaseServerId" = $6
|
|
613
|
+
AND COALESCE("source", '') <> 'user'
|
|
614
|
+
AND "deletedAt" IS NULL
|
|
615
|
+
RETURNING "_id"
|
|
616
|
+
)
|
|
617
|
+
SELECT "_id" FROM "moved"`,
|
|
618
|
+
[
|
|
619
|
+
data.toDatabaseServerId.toString(),
|
|
620
|
+
data.isPrimary,
|
|
621
|
+
data.now,
|
|
622
|
+
data.endpointId.toString(),
|
|
623
|
+
data.projectId.toString(),
|
|
624
|
+
data.fromDatabaseServerId.toString(),
|
|
625
|
+
],
|
|
626
|
+
);
|
|
627
|
+
|
|
628
|
+
return Array.isArray(moved) && moved.length > 0;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Release the "workload" endpoints of one database that its workload no
|
|
633
|
+
* longer produces: not in `keepEndpoints` and not matched since
|
|
634
|
+
* `staleBefore` (so one partial discovery run releases nothing). Never the
|
|
635
|
+
* primary endpoint, never an "auto" or "user" one. Returns the endpoints
|
|
636
|
+
* released.
|
|
637
|
+
*/
|
|
638
|
+
@CaptureSpan()
|
|
639
|
+
public async releaseUnproducedWorkloadEndpoints(data: {
|
|
640
|
+
projectId: ObjectID;
|
|
641
|
+
databaseServerId: ObjectID;
|
|
642
|
+
keepEndpoints: Array<string>;
|
|
643
|
+
staleBefore: Date;
|
|
644
|
+
}): Promise<Array<string>> {
|
|
645
|
+
// A CTE for the same reason as transferEndpoint: a SELECT's rows come back.
|
|
646
|
+
const released: unknown = await this.getRepository().manager.query(
|
|
647
|
+
`WITH "released" AS (
|
|
648
|
+
DELETE FROM "DatabaseServerEndpoint"
|
|
649
|
+
WHERE "projectId" = $1
|
|
650
|
+
AND "databaseServerId" = $2
|
|
651
|
+
AND "source" = 'workload'
|
|
652
|
+
AND "isPrimary" = false
|
|
653
|
+
AND NOT ("endpoint" = ANY($3::text[]))
|
|
654
|
+
AND ("lastMatchedAt" IS NULL OR "lastMatchedAt" < $4)
|
|
655
|
+
RETURNING "endpoint"
|
|
656
|
+
)
|
|
657
|
+
SELECT "endpoint" FROM "released"`,
|
|
658
|
+
[
|
|
659
|
+
data.projectId.toString(),
|
|
660
|
+
data.databaseServerId.toString(),
|
|
661
|
+
data.keepEndpoints,
|
|
662
|
+
data.staleBefore,
|
|
663
|
+
],
|
|
664
|
+
);
|
|
665
|
+
|
|
666
|
+
if (!Array.isArray(released)) {
|
|
667
|
+
return [];
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
return released
|
|
671
|
+
.map((row: unknown): string => {
|
|
672
|
+
const endpoint: unknown = (row as { endpoint?: unknown })?.endpoint;
|
|
673
|
+
return typeof endpoint === "string" ? endpoint : "";
|
|
674
|
+
})
|
|
675
|
+
.filter((endpoint: string): boolean => {
|
|
676
|
+
return endpoint.length > 0;
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
// True when the database has a primary endpoint.
|
|
681
|
+
@CaptureSpan()
|
|
682
|
+
public async hasPrimaryEndpoint(data: {
|
|
683
|
+
projectId: ObjectID;
|
|
684
|
+
databaseServerId: ObjectID;
|
|
685
|
+
}): Promise<boolean> {
|
|
686
|
+
const primary: Model | null = await this.findOneBy({
|
|
687
|
+
query: {
|
|
688
|
+
projectId: data.projectId,
|
|
689
|
+
databaseServerId: data.databaseServerId,
|
|
690
|
+
isPrimary: true,
|
|
691
|
+
},
|
|
692
|
+
select: {
|
|
693
|
+
_id: true,
|
|
694
|
+
},
|
|
695
|
+
props: {
|
|
696
|
+
isRoot: true,
|
|
697
|
+
},
|
|
698
|
+
});
|
|
699
|
+
|
|
700
|
+
return Boolean(primary);
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* Make a canonical endpoint this database's, as root. Never takes an
|
|
705
|
+
* endpoint away from another database: that answers "owned-by-other" and
|
|
706
|
+
* the caller decides what to do (discovery logs and skips it).
|
|
707
|
+
*
|
|
708
|
+
* Two discovery writers can race to claim the same endpoint. The unique
|
|
709
|
+
* index lets exactly one insert through; the loser re-reads the owner and
|
|
710
|
+
* reports the winner rather than throwing.
|
|
711
|
+
*/
|
|
712
|
+
@CaptureSpan()
|
|
713
|
+
public async claimEndpoint(data: {
|
|
714
|
+
projectId: ObjectID;
|
|
715
|
+
databaseServerId: ObjectID;
|
|
716
|
+
endpoint: string;
|
|
717
|
+
isPrimary: boolean;
|
|
718
|
+
source: DatabaseServerEndpointSource;
|
|
719
|
+
}): Promise<DatabaseServerEndpointClaimResult> {
|
|
720
|
+
const endpoint: string = (data.endpoint || "").trim();
|
|
721
|
+
|
|
722
|
+
if (!endpoint) {
|
|
723
|
+
throw new BadDataException("Endpoint is required to claim it.");
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
const existingOwner: DatabaseServerEndpointOwner | null =
|
|
727
|
+
await this.findOwnerByEndpoint(data.projectId, endpoint);
|
|
728
|
+
|
|
729
|
+
if (existingOwner) {
|
|
730
|
+
const result: DatabaseServerEndpointClaimResult = classifyOwner(
|
|
731
|
+
existingOwner,
|
|
732
|
+
data.databaseServerId,
|
|
733
|
+
);
|
|
734
|
+
|
|
735
|
+
// Re-reported by the database that owns it: that is a match.
|
|
736
|
+
if (result === "already-owned-by-this") {
|
|
737
|
+
await this.markEndpointMatched(existingOwner);
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
return result;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
try {
|
|
744
|
+
const row: Model = new Model();
|
|
745
|
+
row.projectId = data.projectId;
|
|
746
|
+
row.databaseServerId = data.databaseServerId;
|
|
747
|
+
row.endpoint = endpoint;
|
|
748
|
+
row.isPrimary = data.isPrimary;
|
|
749
|
+
row.source = data.source;
|
|
750
|
+
row.lastMatchedAt = OneUptimeDate.getCurrentDate();
|
|
751
|
+
|
|
752
|
+
await this.create({
|
|
753
|
+
data: row,
|
|
754
|
+
props: {
|
|
755
|
+
isRoot: true,
|
|
756
|
+
},
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
return "claimed";
|
|
760
|
+
} catch (error) {
|
|
761
|
+
const racedOwner: DatabaseServerEndpointOwner | null =
|
|
762
|
+
await this.findOwnerByEndpoint(data.projectId, endpoint);
|
|
763
|
+
|
|
764
|
+
if (racedOwner) {
|
|
765
|
+
return classifyOwner(racedOwner, data.databaseServerId);
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
// Not a lost race (a foreign key, a dead connection): surface it.
|
|
769
|
+
throw error;
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
/**
|
|
774
|
+
* Every endpoint of one database, primary first then alphabetical - the
|
|
775
|
+
* input getDatabaseServerSignalEntityKeys turns into the database's
|
|
776
|
+
* telemetry key set.
|
|
777
|
+
*/
|
|
778
|
+
@CaptureSpan()
|
|
779
|
+
public async listEndpoints(
|
|
780
|
+
databaseServerId: ObjectID,
|
|
781
|
+
): Promise<Array<string>> {
|
|
782
|
+
const rows: Array<Model> = await this.findBy({
|
|
783
|
+
query: {
|
|
784
|
+
databaseServerId: databaseServerId,
|
|
785
|
+
},
|
|
786
|
+
select: {
|
|
787
|
+
_id: true,
|
|
788
|
+
endpoint: true,
|
|
789
|
+
isPrimary: true,
|
|
790
|
+
},
|
|
791
|
+
sort: {
|
|
792
|
+
isPrimary: SortOrder.Descending,
|
|
793
|
+
endpoint: SortOrder.Ascending,
|
|
794
|
+
},
|
|
795
|
+
limit: LIMIT_MAX,
|
|
796
|
+
skip: 0,
|
|
797
|
+
props: {
|
|
798
|
+
isRoot: true,
|
|
799
|
+
},
|
|
800
|
+
});
|
|
801
|
+
|
|
802
|
+
const endpoints: Array<string> = [];
|
|
803
|
+
|
|
804
|
+
for (const row of rows) {
|
|
805
|
+
if (row.endpoint && !endpoints.includes(row.endpoint)) {
|
|
806
|
+
endpoints.push(row.endpoint);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
return endpoints;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
/**
|
|
814
|
+
* The database a caller adds an endpoint to, read only if the caller may
|
|
815
|
+
* EDIT it: the update permission check scopes the lookup exactly the way
|
|
816
|
+
* an update of that row would be scoped (project, label-scoped and
|
|
817
|
+
* Owned-scoped grants, block permissions). Null when the row does not
|
|
818
|
+
* exist in the project or the caller may not edit it - deliberately the
|
|
819
|
+
* same answer.
|
|
820
|
+
*/
|
|
821
|
+
@CaptureSpan()
|
|
822
|
+
public async findEditableDatabaseServer(data: {
|
|
823
|
+
projectId: ObjectID;
|
|
824
|
+
databaseServerId: ObjectID;
|
|
825
|
+
props: DatabaseCommonInteractionProps;
|
|
826
|
+
}): Promise<DatabaseServer | null> {
|
|
827
|
+
const editableQuery: Query<DatabaseServer> =
|
|
828
|
+
await ModelPermission.checkUpdateQueryPermissions(
|
|
829
|
+
DatabaseServer,
|
|
830
|
+
{
|
|
831
|
+
_id: data.databaseServerId.toString(),
|
|
832
|
+
projectId: data.projectId,
|
|
833
|
+
},
|
|
834
|
+
{},
|
|
835
|
+
data.props,
|
|
836
|
+
);
|
|
837
|
+
|
|
838
|
+
return await DatabaseServerService.findOneBy({
|
|
839
|
+
query: editableQuery,
|
|
840
|
+
select: {
|
|
841
|
+
_id: true,
|
|
842
|
+
dbSystem: true,
|
|
843
|
+
kubernetesNamespace: true,
|
|
844
|
+
kubernetesCluster: {
|
|
845
|
+
clusterIdentifier: true,
|
|
846
|
+
},
|
|
847
|
+
},
|
|
848
|
+
props: {
|
|
849
|
+
isRoot: true,
|
|
850
|
+
},
|
|
851
|
+
});
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
function classifyOwner(
|
|
856
|
+
owner: DatabaseServerEndpointOwner,
|
|
857
|
+
databaseServerId: ObjectID,
|
|
858
|
+
): DatabaseServerEndpointClaimResult {
|
|
859
|
+
return owner.databaseServerId.toString() === databaseServerId.toString()
|
|
860
|
+
? "already-owned-by-this"
|
|
861
|
+
: "owned-by-other";
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
/*
|
|
865
|
+
* "orders-db.example.com:5432 already belongs to the database "PostgreSQL
|
|
866
|
+
* orders-db.example.com:5432"" - naming the owner is the only way a person can
|
|
867
|
+
* find and fix the conflict. But only a database the caller can READ is
|
|
868
|
+
* named: with label- or Owned-scoped permissions the owner may be a row they
|
|
869
|
+
* are not allowed to see, and then it is just "another database". Without
|
|
870
|
+
* props (a root path) the name is read as root.
|
|
871
|
+
*/
|
|
872
|
+
export async function getOwnedByOtherDatabaseMessage(
|
|
873
|
+
formattedEndpoint: string,
|
|
874
|
+
owner: DatabaseServerEndpointOwner,
|
|
875
|
+
props?: DatabaseCommonInteractionProps | undefined,
|
|
876
|
+
): Promise<string> {
|
|
877
|
+
let ownerName: string = "";
|
|
878
|
+
|
|
879
|
+
try {
|
|
880
|
+
ownerName = await DatabaseServerService.getDatabaseServerNameIfReadable({
|
|
881
|
+
databaseServerId: owner.databaseServerId,
|
|
882
|
+
props: props,
|
|
883
|
+
});
|
|
884
|
+
} catch {
|
|
885
|
+
// The name only decorates the message; the refusal stands without it.
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
const ownerLabel: string = ownerName
|
|
889
|
+
? `the database "${ownerName}"`
|
|
890
|
+
: "another database";
|
|
891
|
+
|
|
892
|
+
return `${formattedEndpoint} already belongs to ${ownerLabel}. An endpoint can belong to only one database in a project - remove it from that database first.`;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
export default new Service();
|