@oneuptime/common 10.5.9 → 10.5.18
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/AnalyticsModels/ExceptionInstance.ts +1 -1
- package/Models/AnalyticsModels/Log.ts +1 -1
- package/Models/AnalyticsModels/Metric.ts +1 -1
- package/Models/AnalyticsModels/Profile.ts +1 -1
- package/Models/AnalyticsModels/ProfileSample.ts +1 -1
- package/Models/AnalyticsModels/Span.ts +1 -1
- package/Models/DatabaseModels/TelemetryException.ts +46 -34
- package/Models/DatabaseModels/TelemetryUsageBilling.ts +35 -2
- package/Server/API/AIAgentDataAPI.ts +25 -7
- package/Server/API/TelemetryAPI.ts +6 -0
- package/Server/API/TelemetryExceptionAPI.ts +6 -2
- package/Server/EnvironmentConfig.ts +27 -0
- package/Server/Infrastructure/ClickhouseDatabase.ts +21 -1
- package/Server/Infrastructure/Postgres/DataSourceOptions.ts +19 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1780381124553-MigrationName.ts +28 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1780382837019-MigrationName.ts +24 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1780387560604-MigrationName.ts +47 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1780388219225-MigrationName.ts +34 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
- package/Server/Infrastructure/PostgresDatabase.ts +27 -1
- package/Server/Infrastructure/QueueWorker.ts +54 -4
- package/Server/Infrastructure/Redis.ts +11 -0
- package/Server/Services/AnalyticsDatabaseService.ts +87 -0
- package/Server/Services/DatabaseService.ts +73 -0
- package/Server/Services/TelemetryAttributeService.ts +38 -2
- package/Server/Services/TelemetryExceptionService.ts +24 -49
- package/Server/Services/TelemetryUsageBillingService.ts +289 -166
- package/Server/Types/AnalyticsDatabase/ModelPermission.ts +102 -72
- package/Server/Types/Database/Permissions/OwnedScopePermission.ts +81 -60
- package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +67 -0
- package/Server/Utils/Express.ts +32 -0
- package/Server/Utils/GracefulShutdown.ts +194 -0
- package/Server/Utils/Logger.ts +12 -1
- package/Server/Utils/Monitor/MonitorLogUtil.ts +22 -17
- package/Server/Utils/Profiling.ts +14 -6
- package/Server/Utils/StartServer.ts +13 -5
- package/Server/Utils/Telemetry/ContextSpanProcessor.ts +48 -0
- package/Server/Utils/Telemetry/LogExceptionExtractor.ts +289 -0
- package/Server/Utils/Telemetry/SpanUtil.ts +16 -35
- package/Server/Utils/Telemetry/StackTraceParser.ts +423 -0
- package/Server/Utils/Telemetry/TelemetryContext.ts +190 -0
- package/Server/Utils/Telemetry.ts +33 -7
- package/Tests/Server/Services/TelemetryAttributeService.test.ts +83 -0
- package/Tests/Server/Utils/Telemetry/LogExceptionExtractor.test.ts +0 -0
- package/Types/Database/AccessControl/OwnedThrough.ts +31 -3
- package/Types/Telemetry/ServiceType.ts +10 -0
- package/UI/Components/AutocompleteTextInput/AutocompleteTextInput.tsx +7 -1
- package/UI/Components/Dictionary/Dictionary.tsx +19 -0
- package/UI/Components/Filters/FiltersForm.tsx +1 -0
- package/UI/Components/Filters/JSONFilter.tsx +2 -0
- package/UI/Components/Filters/Types/Filter.ts +1 -0
- package/UI/Components/LogsViewer/LogsViewer.tsx +16 -0
- package/UI/Utils/Project.ts +6 -0
- package/UI/Utils/Telemetry/Telemetry.ts +65 -0
- package/UI/Utils/TelemetryService.ts +150 -0
- package/build/dist/Models/AnalyticsModels/ExceptionInstance.js +1 -1
- package/build/dist/Models/AnalyticsModels/ExceptionInstance.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Log.js +1 -1
- package/build/dist/Models/AnalyticsModels/Log.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Metric.js +1 -1
- package/build/dist/Models/AnalyticsModels/Metric.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Profile.js +1 -1
- package/build/dist/Models/AnalyticsModels/Profile.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/ProfileSample.js +1 -1
- package/build/dist/Models/AnalyticsModels/ProfileSample.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Span.js +1 -1
- package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TelemetryException.js +47 -33
- package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TelemetryUsageBilling.js +36 -2
- package/build/dist/Models/DatabaseModels/TelemetryUsageBilling.js.map +1 -1
- package/build/dist/Server/API/AIAgentDataAPI.js +24 -8
- package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -1
- package/build/dist/Server/API/TelemetryAPI.js +4 -0
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/API/TelemetryExceptionAPI.js +6 -2
- package/build/dist/Server/API/TelemetryExceptionAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +19 -0
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/ClickhouseDatabase.js +16 -2
- package/build/dist/Server/Infrastructure/ClickhouseDatabase.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js +10 -9
- package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780381124553-MigrationName.js +23 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780381124553-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780382837019-MigrationName.js +19 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780382837019-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780387560604-MigrationName.js +22 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780387560604-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780388219225-MigrationName.js +25 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780388219225-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/PostgresDatabase.js +20 -1
- package/build/dist/Server/Infrastructure/PostgresDatabase.js.map +1 -1
- package/build/dist/Server/Infrastructure/QueueWorker.js +40 -3
- package/build/dist/Server/Infrastructure/QueueWorker.js.map +1 -1
- package/build/dist/Server/Infrastructure/Redis.js +5 -0
- package/build/dist/Server/Infrastructure/Redis.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +59 -0
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +62 -0
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryAttributeService.js +23 -1
- package/build/dist/Server/Services/TelemetryAttributeService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryExceptionService.js +16 -41
- package/build/dist/Server/Services/TelemetryExceptionService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryUsageBillingService.js +211 -147
- package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
- package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js +84 -63
- package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/OwnedScopePermission.js +67 -49
- package/build/dist/Server/Types/Database/Permissions/OwnedScopePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +51 -0
- package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Express.js +23 -0
- package/build/dist/Server/Utils/Express.js.map +1 -1
- package/build/dist/Server/Utils/GracefulShutdown.js +145 -0
- package/build/dist/Server/Utils/GracefulShutdown.js.map +1 -0
- package/build/dist/Server/Utils/Logger.js +8 -1
- package/build/dist/Server/Utils/Logger.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorLogUtil.js +12 -10
- package/build/dist/Server/Utils/Monitor/MonitorLogUtil.js.map +1 -1
- package/build/dist/Server/Utils/Profiling.js +8 -3
- package/build/dist/Server/Utils/Profiling.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +12 -4
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ContextSpanProcessor.js +37 -0
- package/build/dist/Server/Utils/Telemetry/ContextSpanProcessor.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js +214 -0
- package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/SpanUtil.js +15 -24
- package/build/dist/Server/Utils/Telemetry/SpanUtil.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/StackTraceParser.js +365 -0
- package/build/dist/Server/Utils/Telemetry/StackTraceParser.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryContext.js +124 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryContext.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry.js +22 -5
- package/build/dist/Server/Utils/Telemetry.js.map +1 -1
- package/build/dist/Tests/Server/Services/TelemetryAttributeService.test.js +50 -0
- package/build/dist/Tests/Server/Services/TelemetryAttributeService.test.js.map +1 -0
- package/build/dist/Tests/Server/Utils/Telemetry/LogExceptionExtractor.test.js +0 -0
- package/build/dist/Tests/Server/Utils/Telemetry/LogExceptionExtractor.test.js.map +1 -0
- package/build/dist/Types/Database/AccessControl/OwnedThrough.js +7 -2
- package/build/dist/Types/Database/AccessControl/OwnedThrough.js.map +1 -1
- package/build/dist/Types/Telemetry/ServiceType.js +10 -0
- package/build/dist/Types/Telemetry/ServiceType.js.map +1 -1
- package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js +7 -1
- package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js.map +1 -1
- package/build/dist/UI/Components/Dictionary/Dictionary.js +10 -0
- package/build/dist/UI/Components/Dictionary/Dictionary.js.map +1 -1
- package/build/dist/UI/Components/Filters/FiltersForm.js +1 -1
- package/build/dist/UI/Components/Filters/FiltersForm.js.map +1 -1
- package/build/dist/UI/Components/Filters/JSONFilter.js +1 -1
- package/build/dist/UI/Components/Filters/JSONFilter.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js +15 -0
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
- package/build/dist/UI/Utils/Project.js +5 -0
- package/build/dist/UI/Utils/Project.js.map +1 -1
- package/build/dist/UI/Utils/Telemetry/Telemetry.js +44 -0
- package/build/dist/UI/Utils/Telemetry/Telemetry.js.map +1 -1
- package/build/dist/UI/Utils/TelemetryService.js +113 -0
- package/build/dist/UI/Utils/TelemetryService.js.map +1 -0
- package/package.json +1 -1
|
@@ -807,6 +807,23 @@ export default class ModelPermission {
|
|
|
807
807
|
}
|
|
808
808
|
}
|
|
809
809
|
|
|
810
|
+
/*
|
|
811
|
+
* Telemetry with no owning resource (the unattributed "Unknown"
|
|
812
|
+
* bucket) is tagged with the projectId in place of a resource id. It
|
|
813
|
+
* belongs to the project, not any owner, so an Owned-scoped user
|
|
814
|
+
* (project-level catch-all access) sees it. Gated on hasOwnedGrant:
|
|
815
|
+
* a purely Labels-scoped user asked for label-matching telemetry, and
|
|
816
|
+
* the unattributed bucket carries no labels, so it stays excluded for
|
|
817
|
+
* them.
|
|
818
|
+
*/
|
|
819
|
+
if (
|
|
820
|
+
hasOwnedGrant &&
|
|
821
|
+
model.ownedThrough.includeProjectScope &&
|
|
822
|
+
props.tenantId
|
|
823
|
+
) {
|
|
824
|
+
allowedResourceIds.add(props.tenantId.toString());
|
|
825
|
+
}
|
|
826
|
+
|
|
810
827
|
const fkColumn: string = model.ownedThrough.fkColumn;
|
|
811
828
|
const idList: Array<string> =
|
|
812
829
|
allowedResourceIds.size > 0
|
|
@@ -841,64 +858,73 @@ export default class ModelPermission {
|
|
|
841
858
|
|
|
842
859
|
const ownerTableRegistry: Map<
|
|
843
860
|
string,
|
|
844
|
-
|
|
845
|
-
|
|
861
|
+
{
|
|
862
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
863
|
+
ownerUserService: any;
|
|
864
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
865
|
+
ownerTeamService: any;
|
|
866
|
+
fkColumn: string;
|
|
867
|
+
canOwnTelemetry?: boolean;
|
|
868
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
869
|
+
modelService?: any;
|
|
870
|
+
}
|
|
846
871
|
> =
|
|
847
872
|
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
|
|
848
873
|
require("../Database/Permissions/OwnerTableRegistry").default;
|
|
849
874
|
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
875
|
+
/*
|
|
876
|
+
* Telemetry serviceId is polymorphic — it can reference any resource
|
|
877
|
+
* type flagged `canOwnTelemetry` in the registry (Service, Monitor,
|
|
878
|
+
* Host, DockerHost, KubernetesCluster). Resolve ownership across all of
|
|
879
|
+
* them so a user who owns any such resource sees its telemetry, not
|
|
880
|
+
* just owned Services. The polymorphic set lives only in the registry
|
|
881
|
+
* (single source of truth); the resolved union is the same for every
|
|
882
|
+
* telemetry analytics model, so the single per-request `ownedIds`
|
|
883
|
+
* cache slot still holds it.
|
|
884
|
+
*/
|
|
885
|
+
for (const entry of ownerTableRegistry.values()) {
|
|
886
|
+
if (!entry.canOwnTelemetry) {
|
|
887
|
+
continue;
|
|
888
|
+
}
|
|
889
|
+
const fkColumn: string = entry.fkColumn;
|
|
863
890
|
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
await serviceEntry.ownerUserService.findBy({
|
|
891
|
+
if (props.userId) {
|
|
892
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
893
|
+
const userOwnedRows: Array<any> = await entry.ownerUserService.findBy({
|
|
868
894
|
query: {
|
|
869
895
|
userId: props.userId,
|
|
870
896
|
...(props.tenantId ? { projectId: props.tenantId } : {}),
|
|
871
897
|
},
|
|
872
|
-
select: {
|
|
898
|
+
select: { [fkColumn]: true },
|
|
873
899
|
props: { isRoot: true },
|
|
874
900
|
skip: 0,
|
|
875
901
|
limit: LIMIT_MAX,
|
|
876
902
|
});
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
903
|
+
for (const row of userOwnedRows) {
|
|
904
|
+
const id: ObjectID | undefined = row[fkColumn];
|
|
905
|
+
if (id) {
|
|
906
|
+
result.add(id.toString());
|
|
907
|
+
}
|
|
881
908
|
}
|
|
882
909
|
}
|
|
883
|
-
}
|
|
884
910
|
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
await serviceEntry.ownerTeamService.findBy({
|
|
911
|
+
if (props.userTeamIds && props.userTeamIds.length > 0) {
|
|
912
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
913
|
+
const teamOwnedRows: Array<any> = await entry.ownerTeamService.findBy({
|
|
889
914
|
query: {
|
|
890
915
|
teamId: QueryHelper.any(props.userTeamIds),
|
|
891
916
|
...(props.tenantId ? { projectId: props.tenantId } : {}),
|
|
892
917
|
},
|
|
893
|
-
select: {
|
|
918
|
+
select: { [fkColumn]: true },
|
|
894
919
|
props: { isRoot: true },
|
|
895
920
|
skip: 0,
|
|
896
921
|
limit: LIMIT_MAX,
|
|
897
922
|
});
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
923
|
+
for (const row of teamOwnedRows) {
|
|
924
|
+
const id: ObjectID | undefined = row[fkColumn];
|
|
925
|
+
if (id) {
|
|
926
|
+
result.add(id.toString());
|
|
927
|
+
}
|
|
902
928
|
}
|
|
903
929
|
}
|
|
904
930
|
}
|
|
@@ -942,50 +968,54 @@ export default class ModelPermission {
|
|
|
942
968
|
return cached;
|
|
943
969
|
}
|
|
944
970
|
|
|
945
|
-
const ServiceService: any =
|
|
946
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
|
|
947
|
-
require("../../Services/ServiceService").default;
|
|
948
|
-
const MonitorService: any =
|
|
949
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
|
|
950
|
-
require("../../Services/MonitorService").default;
|
|
951
|
-
|
|
952
971
|
const tenantFilter: Record<string, ObjectID> = props.tenantId
|
|
953
972
|
? { projectId: props.tenantId }
|
|
954
973
|
: {};
|
|
955
974
|
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
for (const row of serviceRows) {
|
|
968
|
-
const id: ObjectID | string | undefined = row._id;
|
|
969
|
-
if (id) {
|
|
970
|
-
result.add(id.toString());
|
|
975
|
+
const ownerTableRegistry: Map<
|
|
976
|
+
string,
|
|
977
|
+
{
|
|
978
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
979
|
+
ownerUserService: any;
|
|
980
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
981
|
+
ownerTeamService: any;
|
|
982
|
+
fkColumn: string;
|
|
983
|
+
canOwnTelemetry?: boolean;
|
|
984
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
985
|
+
modelService?: any;
|
|
971
986
|
}
|
|
972
|
-
|
|
987
|
+
> =
|
|
988
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
|
|
989
|
+
require("../Database/Permissions/OwnerTableRegistry").default;
|
|
973
990
|
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
991
|
+
/*
|
|
992
|
+
* Telemetry serviceId is polymorphic across every resource type
|
|
993
|
+
* flagged `canOwnTelemetry` in the registry (Service, Monitor, Host,
|
|
994
|
+
* DockerHost, KubernetesCluster), each of which carries labels. Find
|
|
995
|
+
* rows of each whose labels intersect the user's. Keeping this set in
|
|
996
|
+
* the registry (single source of truth) means a new telemetry-owning
|
|
997
|
+
* resource is picked up here automatically — no edits needed.
|
|
998
|
+
*/
|
|
999
|
+
for (const entry of ownerTableRegistry.values()) {
|
|
1000
|
+
if (!entry.canOwnTelemetry || !entry.modelService) {
|
|
1001
|
+
continue;
|
|
1002
|
+
}
|
|
1003
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1004
|
+
const rows: Array<any> = await entry.modelService.findBy({
|
|
1005
|
+
query: {
|
|
1006
|
+
labels: labelIds,
|
|
1007
|
+
...tenantFilter,
|
|
1008
|
+
},
|
|
1009
|
+
select: { _id: true },
|
|
1010
|
+
props: { isRoot: true },
|
|
1011
|
+
skip: 0,
|
|
1012
|
+
limit: LIMIT_MAX,
|
|
1013
|
+
});
|
|
1014
|
+
for (const row of rows) {
|
|
1015
|
+
const id: ObjectID | string | undefined = row._id;
|
|
1016
|
+
if (id) {
|
|
1017
|
+
result.add(id.toString());
|
|
1018
|
+
}
|
|
989
1019
|
}
|
|
990
1020
|
}
|
|
991
1021
|
|
|
@@ -208,15 +208,23 @@ export default class OwnedScopePermission {
|
|
|
208
208
|
): Promise<Array<ObjectID>> {
|
|
209
209
|
const model: BaseModel = new modelType();
|
|
210
210
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
211
|
+
/*
|
|
212
|
+
* Which model(s) owner tables to consult. A nested model can inherit
|
|
213
|
+
* ownership from several parent resource types when its FK is
|
|
214
|
+
* polymorphic (e.g. a telemetry serviceId that may point at a Service,
|
|
215
|
+
* Host, DockerHost or KubernetesCluster) — resolve and union the owned
|
|
216
|
+
* ids across all of them. Top-level operational resources consult
|
|
217
|
+
* their own owner tables.
|
|
218
|
+
*/
|
|
219
|
+
const resolverNames: Array<string> = model.ownedThrough
|
|
220
|
+
? model.ownedThrough.parentModels.map(
|
|
221
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
222
|
+
(parentModel: any) => {
|
|
223
|
+
return parentModel.name;
|
|
224
|
+
},
|
|
225
|
+
)
|
|
226
|
+
: // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
227
|
+
[(modelType as any).name];
|
|
220
228
|
|
|
221
229
|
/*
|
|
222
230
|
* Lazy require to avoid the circular dep cycle: this file is reachable
|
|
@@ -227,66 +235,79 @@ export default class OwnedScopePermission {
|
|
|
227
235
|
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
|
|
228
236
|
require("./OwnerTableRegistry").default;
|
|
229
237
|
|
|
230
|
-
const registryEntry: OwnerTablePair | undefined =
|
|
231
|
-
ownerTableRegistry.get(resolverName);
|
|
232
|
-
if (!registryEntry) {
|
|
233
|
-
/*
|
|
234
|
-
* No registered owner tables for this model — Owned scope can't
|
|
235
|
-
* resolve, so nothing is accessible.
|
|
236
|
-
*/
|
|
237
|
-
return [];
|
|
238
|
-
}
|
|
239
|
-
|
|
240
238
|
const seen: Set<string> = new Set<string>();
|
|
241
|
-
const fkColumn: string = registryEntry.fkColumn;
|
|
242
239
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
|
|
240
|
+
for (const resolverName of resolverNames) {
|
|
241
|
+
const registryEntry: OwnerTablePair | undefined =
|
|
242
|
+
ownerTableRegistry.get(resolverName);
|
|
243
|
+
if (!registryEntry) {
|
|
244
|
+
/*
|
|
245
|
+
* No registered owner tables for this parent — skip it. Other
|
|
246
|
+
* parents (or includeProjectScope below) may still resolve.
|
|
247
|
+
*/
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const fkColumn: string = registryEntry.fkColumn;
|
|
252
|
+
|
|
253
|
+
/*
|
|
254
|
+
* User-ownership lookup. Skipped for non-user callers (API keys,
|
|
255
|
+
* Probes with no userId); those evaluate `Owned` as `All` elsewhere.
|
|
256
|
+
*/
|
|
257
|
+
if (props.userId) {
|
|
258
|
+
const userOwnedRows: Array<BaseModel> =
|
|
259
|
+
await registryEntry.ownerUserService.findBy({
|
|
260
|
+
query: {
|
|
261
|
+
userId: props.userId,
|
|
262
|
+
...(props.tenantId ? { projectId: props.tenantId } : {}),
|
|
263
|
+
},
|
|
264
|
+
select: { [fkColumn]: true },
|
|
265
|
+
props: { isRoot: true },
|
|
266
|
+
skip: 0,
|
|
267
|
+
limit: LIMIT_MAX,
|
|
268
|
+
});
|
|
269
|
+
for (const row of userOwnedRows) {
|
|
270
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
271
|
+
const value: ObjectID | undefined = (row as any)[fkColumn];
|
|
272
|
+
if (value) {
|
|
273
|
+
seen.add(value.toString());
|
|
274
|
+
}
|
|
264
275
|
}
|
|
265
276
|
}
|
|
266
|
-
}
|
|
267
277
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
278
|
+
// Team-ownership lookup.
|
|
279
|
+
if (props.userTeamIds && props.userTeamIds.length > 0) {
|
|
280
|
+
const teamOwnedRows: Array<BaseModel> =
|
|
281
|
+
await registryEntry.ownerTeamService.findBy({
|
|
282
|
+
query: {
|
|
283
|
+
teamId: QueryHelper.any(props.userTeamIds),
|
|
284
|
+
...(props.tenantId ? { projectId: props.tenantId } : {}),
|
|
285
|
+
},
|
|
286
|
+
select: { [fkColumn]: true },
|
|
287
|
+
props: { isRoot: true },
|
|
288
|
+
skip: 0,
|
|
289
|
+
limit: LIMIT_MAX,
|
|
290
|
+
});
|
|
291
|
+
for (const row of teamOwnedRows) {
|
|
292
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
293
|
+
const value: ObjectID | undefined = (row as any)[fkColumn];
|
|
294
|
+
if (value) {
|
|
295
|
+
seen.add(value.toString());
|
|
296
|
+
}
|
|
286
297
|
}
|
|
287
298
|
}
|
|
288
299
|
}
|
|
289
300
|
|
|
301
|
+
/*
|
|
302
|
+
* Polymorphic FK rows with no owning resource (the unattributed
|
|
303
|
+
* "Unknown" telemetry bucket) carry the projectId in the FK column.
|
|
304
|
+
* They belong to the project, not any single owner, so include the
|
|
305
|
+
* tenant id when the model opts in via includeProjectScope.
|
|
306
|
+
*/
|
|
307
|
+
if (model.ownedThrough?.includeProjectScope && props.tenantId) {
|
|
308
|
+
seen.add(props.tenantId.toString());
|
|
309
|
+
}
|
|
310
|
+
|
|
290
311
|
const result: Array<ObjectID> = [];
|
|
291
312
|
for (const id of seen) {
|
|
292
313
|
result.push(new ObjectID(id));
|
|
@@ -14,10 +14,27 @@ import ScheduledMaintenanceOwnerTeamService from "../../../Services/ScheduledMai
|
|
|
14
14
|
import ScheduledMaintenanceOwnerUserService from "../../../Services/ScheduledMaintenanceOwnerUserService";
|
|
15
15
|
import ServiceOwnerTeamService from "../../../Services/ServiceOwnerTeamService";
|
|
16
16
|
import ServiceOwnerUserService from "../../../Services/ServiceOwnerUserService";
|
|
17
|
+
import HostOwnerTeamService from "../../../Services/HostOwnerTeamService";
|
|
18
|
+
import HostOwnerUserService from "../../../Services/HostOwnerUserService";
|
|
19
|
+
import DockerHostOwnerTeamService from "../../../Services/DockerHostOwnerTeamService";
|
|
20
|
+
import DockerHostOwnerUserService from "../../../Services/DockerHostOwnerUserService";
|
|
21
|
+
import KubernetesClusterOwnerTeamService from "../../../Services/KubernetesClusterOwnerTeamService";
|
|
22
|
+
import KubernetesClusterOwnerUserService from "../../../Services/KubernetesClusterOwnerUserService";
|
|
17
23
|
import StatusPageOwnerTeamService from "../../../Services/StatusPageOwnerTeamService";
|
|
18
24
|
import StatusPageOwnerUserService from "../../../Services/StatusPageOwnerUserService";
|
|
19
25
|
import WorkflowOwnerTeamService from "../../../Services/WorkflowOwnerTeamService";
|
|
20
26
|
import WorkflowOwnerUserService from "../../../Services/WorkflowOwnerUserService";
|
|
27
|
+
/*
|
|
28
|
+
* The resources whose ids can appear in a telemetry row's polymorphic
|
|
29
|
+
* serviceId also expose their own service (for label-scope resolution).
|
|
30
|
+
* Imported here so the registry is the single source of truth for the
|
|
31
|
+
* telemetry serviceId polymorphism — see canOwnTelemetry / modelService.
|
|
32
|
+
*/
|
|
33
|
+
import ServiceService from "../../../Services/ServiceService";
|
|
34
|
+
import MonitorService from "../../../Services/MonitorService";
|
|
35
|
+
import HostService from "../../../Services/HostService";
|
|
36
|
+
import DockerHostService from "../../../Services/DockerHostService";
|
|
37
|
+
import KubernetesClusterService from "../../../Services/KubernetesClusterService";
|
|
21
38
|
|
|
22
39
|
/*
|
|
23
40
|
* Maps an operational model name (e.g. "Monitor") to the two services that
|
|
@@ -35,6 +52,22 @@ export interface OwnerTablePair {
|
|
|
35
52
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
36
53
|
ownerTeamService: any;
|
|
37
54
|
fkColumn: string;
|
|
55
|
+
/*
|
|
56
|
+
* True when a telemetry row's serviceId (polymorphic, discriminated by
|
|
57
|
+
* serviceType) can reference this resource type. The analytics
|
|
58
|
+
* owned/labels scope resolution iterates the entries flagged here, so
|
|
59
|
+
* the telemetry serviceId polymorphism lives only in this registry —
|
|
60
|
+
* adding a new telemetry-owning resource needs just an entry here, with
|
|
61
|
+
* no edits in ModelPermission.
|
|
62
|
+
*/
|
|
63
|
+
canOwnTelemetry?: boolean;
|
|
64
|
+
/*
|
|
65
|
+
* The resource's own service, used by labels-scope resolution to find
|
|
66
|
+
* resources whose labels match the user's. Set for canOwnTelemetry
|
|
67
|
+
* types (they all carry labels).
|
|
68
|
+
*/
|
|
69
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
70
|
+
modelService?: any;
|
|
38
71
|
}
|
|
39
72
|
|
|
40
73
|
const ownerTableRegistry: Map<string, OwnerTablePair> = new Map<
|
|
@@ -47,6 +80,8 @@ const ownerTableRegistry: Map<string, OwnerTablePair> = new Map<
|
|
|
47
80
|
ownerUserService: MonitorOwnerUserService,
|
|
48
81
|
ownerTeamService: MonitorOwnerTeamService,
|
|
49
82
|
fkColumn: "monitorId",
|
|
83
|
+
canOwnTelemetry: true,
|
|
84
|
+
modelService: MonitorService,
|
|
50
85
|
},
|
|
51
86
|
],
|
|
52
87
|
[
|
|
@@ -111,6 +146,38 @@ const ownerTableRegistry: Map<string, OwnerTablePair> = new Map<
|
|
|
111
146
|
ownerUserService: ServiceOwnerUserService,
|
|
112
147
|
ownerTeamService: ServiceOwnerTeamService,
|
|
113
148
|
fkColumn: "serviceId",
|
|
149
|
+
canOwnTelemetry: true,
|
|
150
|
+
modelService: ServiceService,
|
|
151
|
+
},
|
|
152
|
+
],
|
|
153
|
+
[
|
|
154
|
+
"Host",
|
|
155
|
+
{
|
|
156
|
+
ownerUserService: HostOwnerUserService,
|
|
157
|
+
ownerTeamService: HostOwnerTeamService,
|
|
158
|
+
fkColumn: "hostId",
|
|
159
|
+
canOwnTelemetry: true,
|
|
160
|
+
modelService: HostService,
|
|
161
|
+
},
|
|
162
|
+
],
|
|
163
|
+
[
|
|
164
|
+
"DockerHost",
|
|
165
|
+
{
|
|
166
|
+
ownerUserService: DockerHostOwnerUserService,
|
|
167
|
+
ownerTeamService: DockerHostOwnerTeamService,
|
|
168
|
+
fkColumn: "dockerHostId",
|
|
169
|
+
canOwnTelemetry: true,
|
|
170
|
+
modelService: DockerHostService,
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
[
|
|
174
|
+
"KubernetesCluster",
|
|
175
|
+
{
|
|
176
|
+
ownerUserService: KubernetesClusterOwnerUserService,
|
|
177
|
+
ownerTeamService: KubernetesClusterOwnerTeamService,
|
|
178
|
+
fkColumn: "kubernetesClusterId",
|
|
179
|
+
canOwnTelemetry: true,
|
|
180
|
+
modelService: KubernetesClusterService,
|
|
114
181
|
},
|
|
115
182
|
],
|
|
116
183
|
[
|
package/Server/Utils/Express.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import logger from "./Logger";
|
|
2
|
+
import GracefulShutdown, { ShutdownPriority } from "./GracefulShutdown";
|
|
2
3
|
import Dictionary from "../../Types/Dictionary";
|
|
3
4
|
import GenericFunction from "../../Types/GenericFunction";
|
|
4
5
|
import { JSONObject, JSONObjectOrArray } from "../../Types/JSON";
|
|
@@ -104,6 +105,37 @@ class Express {
|
|
|
104
105
|
this.httpServer = createServer(this.app);
|
|
105
106
|
}
|
|
106
107
|
|
|
108
|
+
/*
|
|
109
|
+
* On shutdown, stop accepting new connections first (before datastores are
|
|
110
|
+
* drained) so in-flight requests can finish but new ones don't acquire
|
|
111
|
+
* resources we're about to tear down. closeIdleConnections() drops idle
|
|
112
|
+
* keep-alive sockets so server.close() doesn't block waiting on them; the
|
|
113
|
+
* GracefulShutdown per-handler timeout bounds anything still in flight.
|
|
114
|
+
*/
|
|
115
|
+
GracefulShutdown.registerHandler(
|
|
116
|
+
"HttpServer",
|
|
117
|
+
ShutdownPriority.HttpServer,
|
|
118
|
+
() => {
|
|
119
|
+
return new Promise<void>((resolve: () => void) => {
|
|
120
|
+
if (!this.httpServer || !this.httpServer.listening) {
|
|
121
|
+
resolve();
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const server: Server & { closeIdleConnections?: () => void } =
|
|
126
|
+
this.httpServer;
|
|
127
|
+
|
|
128
|
+
if (typeof server.closeIdleConnections === "function") {
|
|
129
|
+
server.closeIdleConnections();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
server.close(() => {
|
|
133
|
+
resolve();
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
},
|
|
137
|
+
);
|
|
138
|
+
|
|
107
139
|
type ResolveFunction = (app: express.Application) => void;
|
|
108
140
|
|
|
109
141
|
return new Promise<express.Application>((resolve: ResolveFunction) => {
|