@oneuptime/common 10.4.13 → 10.4.15
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/AnalyticsBaseModel/AnalyticsBaseModel.ts +49 -0
- package/Models/AnalyticsModels/AuditLog.ts +8 -0
- package/Models/AnalyticsModels/ExceptionInstance.ts +1 -0
- package/Models/AnalyticsModels/Log.ts +1 -0
- package/Models/AnalyticsModels/Metric.ts +10 -0
- package/Models/AnalyticsModels/MonitorLog.ts +1 -0
- package/Models/AnalyticsModels/Profile.ts +1 -0
- package/Models/AnalyticsModels/ProfileSample.ts +1 -0
- package/Models/AnalyticsModels/Span.ts +1 -0
- package/Models/DatabaseModels/Alert.ts +2 -0
- package/Models/DatabaseModels/AlertCustomField.ts +37 -0
- package/Models/DatabaseModels/AlertFeed.ts +1 -0
- package/Models/DatabaseModels/CallLog.ts +2 -0
- package/Models/DatabaseModels/DockerHost.ts +34 -0
- package/Models/DatabaseModels/EmailLog.ts +2 -0
- package/Models/DatabaseModels/Host.ts +34 -0
- package/Models/DatabaseModels/Incident.ts +1 -0
- package/Models/DatabaseModels/IncidentCustomField.ts +37 -0
- package/Models/DatabaseModels/IncidentFeed.ts +1 -0
- package/Models/DatabaseModels/IncidentMember.ts +9 -0
- package/Models/DatabaseModels/KubernetesCluster.ts +34 -0
- package/Models/DatabaseModels/MonitorCustomField.ts +37 -0
- package/Models/DatabaseModels/MonitorFeed.ts +1 -0
- package/Models/DatabaseModels/MonitorProbe.ts +1 -0
- package/Models/DatabaseModels/OnCallDutyPolicyCustomField.ts +37 -0
- package/Models/DatabaseModels/OnCallDutyPolicyTimeLog.ts +3 -0
- package/Models/DatabaseModels/ScheduledMaintenanceCustomField.ts +37 -0
- package/Models/DatabaseModels/SmsLog.ts +2 -0
- package/Models/DatabaseModels/StatusPageCustomField.ts +37 -0
- package/Models/DatabaseModels/StatusPageSubscriber.ts +2 -0
- package/Models/DatabaseModels/TableView.ts +40 -0
- package/Models/DatabaseModels/TeamMemberCustomField.ts +37 -0
- package/Models/DatabaseModels/TelemetryException.ts +2 -0
- package/Models/DatabaseModels/UserOnCallLog.ts +1 -0
- package/Models/DatabaseModels/WorkflowLog.ts +1 -0
- package/Server/API/BaseAnalyticsAPI.ts +128 -20
- package/Server/API/MetricAPI.ts +5 -138
- package/Server/API/ProjectAPI.ts +52 -15
- package/Server/API/StatusAPI.ts +103 -7
- package/Server/EnvironmentConfig.ts +69 -0
- package/Server/Infrastructure/Postgres/DataSourceOptions.ts +26 -1
- package/Server/Infrastructure/Postgres/SchemaMigrations/1779392865146-AddAgentVersionToKubernetesDockerHost.ts +29 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1779392970424-AddPerformanceIndexes.ts +160 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1779536271671-AddFacetsToTableView.ts +13 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1779540427366-AddIsMemberNotifiedIndex.ts +34 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1779619108628-AddDropdownOptionsToCustomFields.ts +67 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
- package/Server/Infrastructure/PostgresDatabase.ts +2 -5
- package/Server/Middleware/ProjectAuthorization.ts +31 -53
- package/Server/Middleware/UserAuthorization.ts +106 -64
- package/Server/Services/AccessTokenService.ts +1 -1
- package/Server/Services/AnalyticsDatabaseService.ts +24 -4
- package/Server/Services/ApiKeyService.ts +100 -1
- package/Server/Services/DockerHostService.ts +5 -0
- package/Server/Services/HostService.ts +6 -0
- package/Server/Services/KubernetesClusterService.ts +33 -10
- package/Server/Services/MetricService.ts +113 -0
- package/Server/Services/MonitorService.ts +10 -3
- package/Server/Services/ProjectService.ts +93 -2
- package/Server/Services/TeamMemberService.ts +36 -0
- package/Server/Services/UserService.ts +38 -0
- package/Server/Utils/Response.ts +4 -1
- package/Server/Utils/UserPermission/UserPermission.ts +17 -1
- package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +2 -2
- package/Types/API/HTTPResponse.ts +16 -0
- package/Types/BaseDatabase/ListResult.ts +6 -0
- package/Types/CustomField/CustomFieldType.ts +2 -0
- package/Types/Date.ts +9 -1
- package/Types/ListData.ts +14 -0
- package/Types/Monitor/DnsMonitor/DnsMonitorResponse.ts +3 -0
- package/Types/Monitor/DnssecMonitor/DnssecMonitorResponse.ts +5 -0
- package/Types/Monitor/DomainMonitor/DomainMonitorResponse.ts +4 -0
- package/Types/Monitor/ExternalStatusPageMonitor/ExternalStatusPageMonitorResponse.ts +4 -0
- package/Types/Monitor/SnmpMonitor/SnmpMonitorResponse.ts +3 -0
- package/Types/Probe/ProbeAttempt.ts +9 -0
- package/Types/Probe/ProbeMonitorResponse.ts +3 -0
- package/UI/Components/BulkUpdate/BulkOwnerActions.tsx +504 -0
- package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +64 -54
- package/UI/Components/CustomFields/CustomFieldsDetail.tsx +38 -0
- package/UI/Components/CustomFields/DropdownOptionsInput.tsx +150 -0
- package/UI/Components/Detail/Detail.tsx +78 -11
- package/UI/Components/List/List.tsx +6 -0
- package/UI/Components/ModelTable/BaseModelTable.tsx +74 -2
- package/UI/Components/ModelTable/TableView.tsx +70 -30
- package/UI/Components/Pagination/Pagination.tsx +75 -33
- package/UI/Components/Table/Table.tsx +6 -0
- package/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.ts +1 -0
- package/build/dist/Models/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel.js +33 -0
- package/build/dist/Models/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/AuditLog.js +8 -0
- package/build/dist/Models/AnalyticsModels/AuditLog.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/ExceptionInstance.js +1 -0
- package/build/dist/Models/AnalyticsModels/ExceptionInstance.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Log.js +1 -0
- package/build/dist/Models/AnalyticsModels/Log.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Metric.js +10 -0
- package/build/dist/Models/AnalyticsModels/Metric.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/MonitorLog.js +1 -0
- package/build/dist/Models/AnalyticsModels/MonitorLog.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Profile.js +1 -0
- package/build/dist/Models/AnalyticsModels/Profile.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/ProfileSample.js +1 -0
- package/build/dist/Models/AnalyticsModels/ProfileSample.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Span.js +1 -0
- package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Alert.js +3 -1
- package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertCustomField.js +38 -0
- package/build/dist/Models/DatabaseModels/AlertCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertFeed.js +2 -1
- package/build/dist/Models/DatabaseModels/AlertFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/CallLog.js +4 -1
- package/build/dist/Models/DatabaseModels/CallLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DockerHost.js +35 -0
- package/build/dist/Models/DatabaseModels/DockerHost.js.map +1 -1
- package/build/dist/Models/DatabaseModels/EmailLog.js +4 -1
- package/build/dist/Models/DatabaseModels/EmailLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Host.js +35 -0
- package/build/dist/Models/DatabaseModels/Host.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Incident.js +2 -1
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentCustomField.js +38 -0
- package/build/dist/Models/DatabaseModels/IncidentCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentFeed.js +2 -1
- package/build/dist/Models/DatabaseModels/IncidentFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentMember.js +11 -1
- package/build/dist/Models/DatabaseModels/IncidentMember.js.map +1 -1
- package/build/dist/Models/DatabaseModels/KubernetesCluster.js +35 -0
- package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MonitorCustomField.js +38 -0
- package/build/dist/Models/DatabaseModels/MonitorCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MonitorFeed.js +2 -1
- package/build/dist/Models/DatabaseModels/MonitorFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MonitorProbe.js +2 -0
- package/build/dist/Models/DatabaseModels/MonitorProbe.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyCustomField.js +38 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyTimeLog.js +3 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyTimeLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceCustomField.js +38 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/SmsLog.js +4 -1
- package/build/dist/Models/DatabaseModels/SmsLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageCustomField.js +38 -0
- package/build/dist/Models/DatabaseModels/StatusPageCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js +4 -1
- package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TableView.js +40 -0
- package/build/dist/Models/DatabaseModels/TableView.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TeamMemberCustomField.js +38 -0
- package/build/dist/Models/DatabaseModels/TeamMemberCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TelemetryException.js +3 -1
- package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallLog.js +1 -0
- package/build/dist/Models/DatabaseModels/UserOnCallLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/WorkflowLog.js +2 -1
- package/build/dist/Models/DatabaseModels/WorkflowLog.js.map +1 -1
- package/build/dist/Server/API/BaseAnalyticsAPI.js +105 -18
- package/build/dist/Server/API/BaseAnalyticsAPI.js.map +1 -1
- package/build/dist/Server/API/MetricAPI.js +5 -113
- package/build/dist/Server/API/MetricAPI.js.map +1 -1
- package/build/dist/Server/API/ProjectAPI.js +42 -14
- package/build/dist/Server/API/ProjectAPI.js.map +1 -1
- package/build/dist/Server/API/StatusAPI.js +75 -8
- package/build/dist/Server/API/StatusAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +41 -0
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js +20 -2
- package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779392865146-AddAgentVersionToKubernetesDockerHost.js +16 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779392865146-AddAgentVersionToKubernetesDockerHost.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779392970424-AddPerformanceIndexes.js +63 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779392970424-AddPerformanceIndexes.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779536271671-AddFacetsToTableView.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779536271671-AddFacetsToTableView.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779540427366-AddIsMemberNotifiedIndex.js +27 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779540427366-AddIsMemberNotifiedIndex.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779619108628-AddDropdownOptionsToCustomFields.js +28 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779619108628-AddDropdownOptionsToCustomFields.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/PostgresDatabase.js +2 -2
- package/build/dist/Server/Infrastructure/PostgresDatabase.js.map +1 -1
- package/build/dist/Server/Middleware/ProjectAuthorization.js +21 -39
- package/build/dist/Server/Middleware/ProjectAuthorization.js.map +1 -1
- package/build/dist/Server/Middleware/UserAuthorization.js +83 -50
- package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
- package/build/dist/Server/Services/AccessTokenService.js +1 -1
- package/build/dist/Server/Services/AccessTokenService.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +22 -3
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/ApiKeyService.js +86 -0
- package/build/dist/Server/Services/ApiKeyService.js.map +1 -1
- package/build/dist/Server/Services/DockerHostService.js +5 -1
- package/build/dist/Server/Services/DockerHostService.js.map +1 -1
- package/build/dist/Server/Services/HostService.js +5 -1
- package/build/dist/Server/Services/HostService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesClusterService.js +21 -11
- package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
- package/build/dist/Server/Services/MetricService.js +89 -0
- package/build/dist/Server/Services/MetricService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +8 -3
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +84 -2
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/TeamMemberService.js +24 -0
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +36 -0
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Utils/Response.js +6 -5
- package/build/dist/Server/Utils/Response.js.map +1 -1
- package/build/dist/Server/Utils/UserPermission/UserPermission.js +13 -1
- package/build/dist/Server/Utils/UserPermission/UserPermission.js.map +1 -1
- package/build/dist/Tests/Server/Services/AnalyticsDatabaseService.test.js +2 -2
- package/build/dist/Tests/Server/Services/AnalyticsDatabaseService.test.js.map +1 -1
- package/build/dist/Types/API/HTTPResponse.js +15 -0
- package/build/dist/Types/API/HTTPResponse.js.map +1 -1
- package/build/dist/Types/CustomField/CustomFieldType.js +2 -0
- package/build/dist/Types/CustomField/CustomFieldType.js.map +1 -1
- package/build/dist/Types/Date.js +10 -1
- package/build/dist/Types/Date.js.map +1 -1
- package/build/dist/Types/ListData.js +4 -0
- package/build/dist/Types/ListData.js.map +1 -1
- package/build/dist/Types/Probe/ProbeAttempt.js +2 -0
- package/build/dist/Types/Probe/ProbeAttempt.js.map +1 -0
- package/build/dist/UI/Components/BulkUpdate/BulkOwnerActions.js +376 -0
- package/build/dist/UI/Components/BulkUpdate/BulkOwnerActions.js.map +1 -0
- package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js +32 -25
- package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js.map +1 -1
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +32 -0
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
- package/build/dist/UI/Components/CustomFields/DropdownOptionsInput.js +84 -0
- package/build/dist/UI/Components/CustomFields/DropdownOptionsInput.js.map +1 -0
- package/build/dist/UI/Components/Detail/Detail.js +34 -3
- package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
- package/build/dist/UI/Components/List/List.js +1 -1
- package/build/dist/UI/Components/List/List.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +45 -5
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/TableView.js +40 -19
- package/build/dist/UI/Components/ModelTable/TableView.js.map +1 -1
- package/build/dist/UI/Components/Pagination/Pagination.js +62 -36
- package/build/dist/UI/Components/Pagination/Pagination.js.map +1 -1
- package/build/dist/UI/Components/Table/Table.js +1 -1
- package/build/dist/UI/Components/Table/Table.js.map +1 -1
- package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js +1 -0
- package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
import ApiKeyService from "../Services/ApiKeyService";
|
|
2
2
|
import GlobalConfigService from "../Services/GlobalConfigService";
|
|
3
3
|
import UserService from "../Services/UserService";
|
|
4
|
-
import QueryHelper from "../Types/Database/QueryHelper";
|
|
5
4
|
import {
|
|
6
5
|
ExpressRequest,
|
|
7
6
|
ExpressResponse,
|
|
8
7
|
NextFunction,
|
|
9
8
|
OneUptimeRequest,
|
|
10
9
|
} from "../Utils/Express";
|
|
11
|
-
import OneUptimeDate from "../../Types/Date";
|
|
12
10
|
import Dictionary from "../../Types/Dictionary";
|
|
13
11
|
import BadDataException from "../../Types/Exception/BadDataException";
|
|
14
12
|
import ObjectID from "../../Types/ObjectID";
|
|
15
13
|
import { UserTenantAccessPermission } from "../../Types/Permission";
|
|
16
14
|
import UserType from "../../Types/UserType";
|
|
17
|
-
import ApiKey from "../../Models/DatabaseModels/ApiKey";
|
|
18
15
|
import GlobalConfig from "../../Models/DatabaseModels/GlobalConfig";
|
|
19
16
|
import User from "../../Models/DatabaseModels/User";
|
|
20
17
|
import APIKeyAccessPermission from "../Utils/APIKey/AccessPermission";
|
|
@@ -89,62 +86,43 @@ export default class ProjectMiddleware {
|
|
|
89
86
|
);
|
|
90
87
|
}
|
|
91
88
|
|
|
92
|
-
|
|
89
|
+
/*
|
|
90
|
+
* Cached lookup — see ApiKeyService.findApiKey. Hot path for any
|
|
91
|
+
* automated caller hitting the API by key.
|
|
92
|
+
*/
|
|
93
|
+
const apiKeyRow: { id: ObjectID; projectId: ObjectID } | null =
|
|
94
|
+
await ApiKeyService.findApiKey(apiKey);
|
|
93
95
|
|
|
94
|
-
if (
|
|
95
|
-
|
|
96
|
-
query: {
|
|
97
|
-
apiKey: apiKey,
|
|
98
|
-
expiresAt: QueryHelper.greaterThan(OneUptimeDate.getCurrentDate()),
|
|
99
|
-
},
|
|
100
|
-
select: {
|
|
101
|
-
_id: true,
|
|
102
|
-
projectId: true,
|
|
103
|
-
},
|
|
104
|
-
props: { isRoot: true },
|
|
105
|
-
});
|
|
96
|
+
if (apiKeyRow) {
|
|
97
|
+
tenantId = apiKeyRow.projectId;
|
|
106
98
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
99
|
+
(req as OneUptimeRequest).tenantId = tenantId;
|
|
100
|
+
(req as OneUptimeRequest).userType = UserType.API;
|
|
101
|
+
|
|
102
|
+
/*
|
|
103
|
+
* TODO: Add API key permissions.
|
|
104
|
+
*/
|
|
105
|
+
(req as OneUptimeRequest).userGlobalAccessPermission =
|
|
106
|
+
await APIKeyAccessPermission.getDefaultApiGlobalPermission(tenantId);
|
|
107
|
+
|
|
108
|
+
const userTenantAccessPermission: UserTenantAccessPermission | null =
|
|
109
|
+
await APIKeyAccessPermission.getApiTenantAccessPermission(
|
|
110
|
+
tenantId,
|
|
111
|
+
apiKeyRow.id,
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
if (userTenantAccessPermission) {
|
|
115
|
+
(req as OneUptimeRequest).userTenantAccessPermission = {};
|
|
116
|
+
(
|
|
117
|
+
(req as OneUptimeRequest)
|
|
118
|
+
.userTenantAccessPermission as Dictionary<UserTenantAccessPermission>
|
|
119
|
+
)[tenantId.toString()] = userTenantAccessPermission;
|
|
113
120
|
|
|
114
|
-
(
|
|
115
|
-
|
|
116
|
-
if (apiKeyModel) {
|
|
117
|
-
(req as OneUptimeRequest).userType = UserType.API;
|
|
118
|
-
/*
|
|
119
|
-
* TODO: Add API key permissions.
|
|
120
|
-
* (req as OneUptimeRequest).permissions =
|
|
121
|
-
* apiKeyModel.permissions || [];
|
|
122
|
-
*/
|
|
123
|
-
(req as OneUptimeRequest).userGlobalAccessPermission =
|
|
124
|
-
await APIKeyAccessPermission.getDefaultApiGlobalPermission(
|
|
125
|
-
tenantId,
|
|
126
|
-
);
|
|
127
|
-
|
|
128
|
-
const userTenantAccessPermission: UserTenantAccessPermission | null =
|
|
129
|
-
await APIKeyAccessPermission.getApiTenantAccessPermission(
|
|
130
|
-
tenantId,
|
|
131
|
-
apiKeyModel.id!,
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
if (userTenantAccessPermission) {
|
|
135
|
-
(req as OneUptimeRequest).userTenantAccessPermission = {};
|
|
136
|
-
(
|
|
137
|
-
(req as OneUptimeRequest)
|
|
138
|
-
.userTenantAccessPermission as Dictionary<UserTenantAccessPermission>
|
|
139
|
-
)[tenantId.toString()] = userTenantAccessPermission;
|
|
140
|
-
|
|
141
|
-
return next();
|
|
142
|
-
}
|
|
143
|
-
}
|
|
121
|
+
return next();
|
|
144
122
|
}
|
|
145
123
|
}
|
|
146
124
|
|
|
147
|
-
if (!
|
|
125
|
+
if (!apiKeyRow) {
|
|
148
126
|
// check master key.
|
|
149
127
|
const masterKeyGlobalConfig: GlobalConfig | null =
|
|
150
128
|
await GlobalConfigService.findOneBy({
|
|
@@ -17,7 +17,6 @@ import Response from "../Utils/Response";
|
|
|
17
17
|
import ProjectMiddleware from "./ProjectAuthorization";
|
|
18
18
|
import SpanUtil from "../Utils/Telemetry/SpanUtil";
|
|
19
19
|
import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
|
|
20
|
-
import OneUptimeDate from "../../Types/Date";
|
|
21
20
|
import Dictionary from "../../Types/Dictionary";
|
|
22
21
|
import Exception from "../../Types/Exception/Exception";
|
|
23
22
|
import NotAuthenticatedException from "../../Types/Exception/NotAuthenticatedException";
|
|
@@ -201,8 +200,12 @@ export default class UserMiddleware {
|
|
|
201
200
|
if (tenantId) {
|
|
202
201
|
oneuptimeRequest.tenantId = tenantId;
|
|
203
202
|
|
|
204
|
-
|
|
205
|
-
|
|
203
|
+
/*
|
|
204
|
+
* Fire-and-forget: lastActive write is debounced inside the service
|
|
205
|
+
* (60s in-process cache) and we don't need the result before
|
|
206
|
+
* continuing.
|
|
207
|
+
*/
|
|
208
|
+
void ProjectService.updateLastActive(tenantId);
|
|
206
209
|
}
|
|
207
210
|
|
|
208
211
|
if (ProjectMiddleware.hasApiKey(req)) {
|
|
@@ -253,31 +256,50 @@ export default class UserMiddleware {
|
|
|
253
256
|
: {}),
|
|
254
257
|
});
|
|
255
258
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
data: { lastActive: OneUptimeDate.getCurrentDate() },
|
|
262
|
-
});
|
|
259
|
+
/*
|
|
260
|
+
* Fire-and-forget: lastActive write is debounced inside the service
|
|
261
|
+
* (60s in-process cache) and we don't need the result before continuing.
|
|
262
|
+
*/
|
|
263
|
+
void UserService.updateLastActive(new ObjectID(userId));
|
|
263
264
|
|
|
264
|
-
|
|
265
|
-
|
|
265
|
+
/*
|
|
266
|
+
* Resolve global permission, tenant permission, and team membership in
|
|
267
|
+
* parallel. These were previously sequential awaits — each added an
|
|
268
|
+
* extra round-trip latency to every authenticated request. The original
|
|
269
|
+
* code wrapped only the tenant-side calls in try/catch (to convert
|
|
270
|
+
* SsoAuthorizationException etc. into an HTTP error response); we
|
|
271
|
+
* preserve that semantic by routing the rejection through the same
|
|
272
|
+
* catch only when tenantId is present.
|
|
273
|
+
*/
|
|
274
|
+
const userGlobalAccessPermissionPromise: Promise<UserGlobalAccessPermission | null> =
|
|
275
|
+
AccessTokenService.getUserGlobalAccessPermission(
|
|
266
276
|
oneuptimeRequest.userAuthorization.userId,
|
|
267
277
|
);
|
|
268
278
|
|
|
269
|
-
|
|
270
|
-
oneuptimeRequest.userGlobalAccessPermission = userGlobalAccessPermission;
|
|
271
|
-
}
|
|
279
|
+
let userGlobalAccessPermission: UserGlobalAccessPermission | null = null;
|
|
272
280
|
|
|
273
281
|
if (tenantId) {
|
|
274
282
|
try {
|
|
275
|
-
const userTenantAccessPermission:
|
|
276
|
-
|
|
283
|
+
const [globalPermission, userTenantAccessPermission, userTeamIds]: [
|
|
284
|
+
UserGlobalAccessPermission | null,
|
|
285
|
+
UserTenantAccessPermission | null,
|
|
286
|
+
Array<ObjectID>,
|
|
287
|
+
] = await Promise.all([
|
|
288
|
+
userGlobalAccessPermissionPromise,
|
|
289
|
+
UserMiddleware.getUserTenantAccessPermissionWithTenantId({
|
|
277
290
|
req,
|
|
278
291
|
tenantId,
|
|
279
292
|
userId: new ObjectID(userId),
|
|
280
|
-
})
|
|
293
|
+
}),
|
|
294
|
+
TeamMemberService.getTeamIdsForUser(new ObjectID(userId), tenantId),
|
|
295
|
+
]);
|
|
296
|
+
|
|
297
|
+
userGlobalAccessPermission = globalPermission;
|
|
298
|
+
|
|
299
|
+
if (userGlobalAccessPermission) {
|
|
300
|
+
oneuptimeRequest.userGlobalAccessPermission =
|
|
301
|
+
userGlobalAccessPermission;
|
|
302
|
+
}
|
|
281
303
|
|
|
282
304
|
if (userTenantAccessPermission) {
|
|
283
305
|
oneuptimeRequest.userTenantAccessPermission = {};
|
|
@@ -291,14 +313,17 @@ export default class UserMiddleware {
|
|
|
291
313
|
* an extra DB roundtrip on every permission check. Absent for non-user
|
|
292
314
|
* callers (API keys, Probes); `Owned` then evaluates as `All`.
|
|
293
315
|
*/
|
|
294
|
-
oneuptimeRequest.userTeamIds =
|
|
295
|
-
await TeamMemberService.getTeamIdsForUser(
|
|
296
|
-
new ObjectID(userId),
|
|
297
|
-
tenantId,
|
|
298
|
-
);
|
|
316
|
+
oneuptimeRequest.userTeamIds = userTeamIds;
|
|
299
317
|
} catch (error) {
|
|
300
318
|
return Response.sendErrorResponse(req, res, error as Exception);
|
|
301
319
|
}
|
|
320
|
+
} else {
|
|
321
|
+
userGlobalAccessPermission = await userGlobalAccessPermissionPromise;
|
|
322
|
+
|
|
323
|
+
if (userGlobalAccessPermission) {
|
|
324
|
+
oneuptimeRequest.userGlobalAccessPermission =
|
|
325
|
+
userGlobalAccessPermission;
|
|
326
|
+
}
|
|
302
327
|
}
|
|
303
328
|
|
|
304
329
|
if (req.headers["is-multi-tenant-query"]) {
|
|
@@ -468,32 +493,36 @@ export default class UserMiddleware {
|
|
|
468
493
|
}): Promise<UserTenantAccessPermission | null> {
|
|
469
494
|
const { req, tenantId, userId } = data;
|
|
470
495
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
496
|
+
/*
|
|
497
|
+
* Resolve the SSO requirement and the tenant permission in parallel.
|
|
498
|
+
* `getRequireSsoForLogin` is cached in-process for 60s, so this is
|
|
499
|
+
* usually free; the tenant permission lookup is the expensive call.
|
|
500
|
+
*/
|
|
501
|
+
const [requireSsoForLogin, tenantPermission]: [
|
|
502
|
+
boolean,
|
|
503
|
+
UserTenantAccessPermission | null,
|
|
504
|
+
] = await Promise.all([
|
|
505
|
+
ProjectService.getRequireSsoForLogin(tenantId).catch((err: Error) => {
|
|
506
|
+
/*
|
|
507
|
+
* Preserve the original behavior of throwing a TenantNotFoundException
|
|
508
|
+
* for an unknown project. Any other error re-throws.
|
|
509
|
+
*/
|
|
510
|
+
if (err.message === "Project not found") {
|
|
511
|
+
throw new TenantNotFoundException("Invalid tenantId");
|
|
512
|
+
}
|
|
513
|
+
throw err;
|
|
514
|
+
}),
|
|
515
|
+
AccessTokenService.getUserTenantAccessPermission(userId, tenantId),
|
|
516
|
+
]);
|
|
484
517
|
|
|
485
518
|
if (
|
|
486
|
-
|
|
519
|
+
requireSsoForLogin &&
|
|
487
520
|
!UserMiddleware.doesSsoTokenForProjectExist(req, tenantId, userId)
|
|
488
521
|
) {
|
|
489
522
|
throw new SsoAuthorizationException();
|
|
490
523
|
}
|
|
491
524
|
|
|
492
|
-
|
|
493
|
-
return await AccessTokenService.getUserTenantAccessPermission(
|
|
494
|
-
userId,
|
|
495
|
-
tenantId,
|
|
496
|
-
);
|
|
525
|
+
return tenantPermission;
|
|
497
526
|
}
|
|
498
527
|
|
|
499
528
|
@CaptureSpan()
|
|
@@ -524,34 +553,47 @@ export default class UserMiddleware {
|
|
|
524
553
|
},
|
|
525
554
|
});
|
|
526
555
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
556
|
+
/*
|
|
557
|
+
* Resolve permissions for every project in parallel. With the previous
|
|
558
|
+
* for-await loop this scaled linearly with project count, adding one
|
|
559
|
+
* round-trip per project even on cache hits.
|
|
560
|
+
*/
|
|
561
|
+
const resolved: Array<{
|
|
562
|
+
projectId: ObjectID;
|
|
563
|
+
permission: UserTenantAccessPermission | null;
|
|
564
|
+
}> = await Promise.all(
|
|
565
|
+
projectIds.map(async (projectId: ObjectID) => {
|
|
566
|
+
if (
|
|
567
|
+
projects.find((p: Project) => {
|
|
568
|
+
return p._id === projectId.toString() && p.requireSsoForLogin;
|
|
569
|
+
}) &&
|
|
570
|
+
!UserMiddleware.doesSsoTokenForProjectExist(req, projectId, userId)
|
|
571
|
+
) {
|
|
572
|
+
return {
|
|
573
|
+
projectId,
|
|
574
|
+
permission:
|
|
575
|
+
UserPermissionUtil.getDefaultUserTenantAccessPermission(
|
|
576
|
+
projectId,
|
|
577
|
+
),
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
return {
|
|
581
|
+
projectId,
|
|
582
|
+
permission: await AccessTokenService.getUserTenantAccessPermission(
|
|
545
583
|
userId,
|
|
546
584
|
projectId,
|
|
547
|
-
)
|
|
548
|
-
|
|
585
|
+
),
|
|
586
|
+
};
|
|
587
|
+
}),
|
|
588
|
+
);
|
|
549
589
|
|
|
550
|
-
|
|
590
|
+
let result: Dictionary<UserTenantAccessPermission> | null = null;
|
|
591
|
+
for (const { projectId, permission } of resolved) {
|
|
592
|
+
if (permission) {
|
|
551
593
|
if (!result) {
|
|
552
594
|
result = {};
|
|
553
595
|
}
|
|
554
|
-
result[projectId.toString()] =
|
|
596
|
+
result[projectId.toString()] = permission;
|
|
555
597
|
}
|
|
556
598
|
}
|
|
557
599
|
|
|
@@ -199,7 +199,7 @@ export class AccessTokenService extends BaseService {
|
|
|
199
199
|
|
|
200
200
|
await GlobalCache.setJSON(
|
|
201
201
|
PermissionNamespace.ProjectPermission,
|
|
202
|
-
|
|
202
|
+
UserPermissionUtil.buildTenantPermissionCacheKey(userId, projectId),
|
|
203
203
|
permission,
|
|
204
204
|
);
|
|
205
205
|
|
|
@@ -535,9 +535,19 @@ export default class AnalyticsDatabaseService<
|
|
|
535
535
|
): Promise<Array<TBaseModel>> {
|
|
536
536
|
try {
|
|
537
537
|
if (!findBy.sort || Object.keys(findBy.sort).length === 0) {
|
|
538
|
+
/*
|
|
539
|
+
* Default sort uses the model's declared `defaultSortColumn`
|
|
540
|
+
* (e.g. `time` for Log, `startTime` for Span) so the query
|
|
541
|
+
* streams from the ClickHouse sort key. The historical
|
|
542
|
+
* fallback of `createdAt` is not in the sort key on most
|
|
543
|
+
* analytics tables, which triggered a full sort even on
|
|
544
|
+
* small LIMITed queries.
|
|
545
|
+
*/
|
|
546
|
+
const defaultSortColumn: string =
|
|
547
|
+
this.model.defaultSortColumn || "createdAt";
|
|
538
548
|
findBy.sort = {
|
|
539
|
-
|
|
540
|
-
};
|
|
549
|
+
[defaultSortColumn]: SortOrder.Descending,
|
|
550
|
+
} as any;
|
|
541
551
|
|
|
542
552
|
if (!findBy.select) {
|
|
543
553
|
findBy.select = {} as any;
|
|
@@ -910,10 +920,20 @@ export default class AnalyticsDatabaseService<
|
|
|
910
920
|
deleteBy.query
|
|
911
921
|
);
|
|
912
922
|
|
|
923
|
+
/*
|
|
924
|
+
* Use ClickHouse lightweight deletes (`DELETE FROM`) rather than
|
|
925
|
+
* `ALTER TABLE … DELETE`. The latter creates an async mutation that
|
|
926
|
+
* rewrites whole parts and is bounded by `number_of_mutations_to_throw`
|
|
927
|
+
* (default 1000). Customers with chatty state transitions hit that
|
|
928
|
+
* ceiling and every subsequent delete fails with TOO_MANY_MUTATIONS.
|
|
929
|
+
* Lightweight deletes mark rows via the hidden `_row_exists` column
|
|
930
|
+
* and are reconciled during normal merges, so they don't accumulate
|
|
931
|
+
* in the mutations queue.
|
|
932
|
+
*/
|
|
913
933
|
/* eslint-disable prettier/prettier */
|
|
914
934
|
const statement: Statement = SQL`
|
|
915
|
-
|
|
916
|
-
|
|
935
|
+
DELETE FROM ${databaseName}.${this.model.tableName}
|
|
936
|
+
WHERE TRUE `.append(whereStatement);
|
|
917
937
|
|
|
918
938
|
logger.debug(`${this.model.tableName} Delete Statement`, { tableName: this.model.tableName } as LogAttributes);
|
|
919
939
|
logger.debug(statement, { tableName: this.model.tableName } as LogAttributes);
|
|
@@ -1,10 +1,41 @@
|
|
|
1
1
|
import CreateBy from "../Types/Database/CreateBy";
|
|
2
|
-
import
|
|
2
|
+
import DeleteBy from "../Types/Database/DeleteBy";
|
|
3
|
+
import UpdateBy from "../Types/Database/UpdateBy";
|
|
4
|
+
import { OnCreate, OnDelete, OnUpdate } from "../Types/Database/Hooks";
|
|
3
5
|
import DatabaseService from "./DatabaseService";
|
|
6
|
+
import OneUptimeDate from "../../Types/Date";
|
|
4
7
|
import ObjectID from "../../Types/ObjectID";
|
|
8
|
+
import QueryHelper from "../Types/Database/QueryHelper";
|
|
5
9
|
import Model from "../../Models/DatabaseModels/ApiKey";
|
|
6
10
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
11
|
+
import InMemoryTTLCache from "../Infrastructure/InMemoryTTLCache";
|
|
12
|
+
|
|
13
|
+
/*
|
|
14
|
+
* 60s is the worst-case staleness on any single API node after a key is
|
|
15
|
+
* revoked from the dashboard. We invalidate in-process immediately on
|
|
16
|
+
* delete/update; this TTL is the upper bound for *other* processes.
|
|
17
|
+
*/
|
|
18
|
+
const POSITIVE_TTL_MS: number = 60 * 1000;
|
|
19
|
+
/*
|
|
20
|
+
* Short TTL on misses so an invalid-key flood can't pin entries in the
|
|
21
|
+
* bounded cache for long while still absorbing repeat hits.
|
|
22
|
+
*/
|
|
23
|
+
const NEGATIVE_TTL_MS: number = 10 * 1000;
|
|
24
|
+
|
|
25
|
+
interface CachedApiKey {
|
|
26
|
+
id: string;
|
|
27
|
+
projectId: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
7
30
|
export class Service extends DatabaseService<Model> {
|
|
31
|
+
/*
|
|
32
|
+
* Cache of `apiKey -> { id, projectId }`. The project-auth middleware hits
|
|
33
|
+
* this on every API-key-authenticated request; without it that's a
|
|
34
|
+
* Postgres findOneBy per request for automated callers.
|
|
35
|
+
*/
|
|
36
|
+
private apiKeyCache: InMemoryTTLCache<CachedApiKey | null> =
|
|
37
|
+
new InMemoryTTLCache(10_000);
|
|
38
|
+
|
|
8
39
|
public constructor() {
|
|
9
40
|
super(Model);
|
|
10
41
|
}
|
|
@@ -16,6 +47,74 @@ export class Service extends DatabaseService<Model> {
|
|
|
16
47
|
createBy.data.apiKey = ObjectID.generate();
|
|
17
48
|
return { createBy, carryForward: null };
|
|
18
49
|
}
|
|
50
|
+
|
|
51
|
+
@CaptureSpan()
|
|
52
|
+
protected override async onBeforeUpdate(
|
|
53
|
+
updateBy: UpdateBy<Model>,
|
|
54
|
+
): Promise<OnUpdate<Model>> {
|
|
55
|
+
/*
|
|
56
|
+
* We don't know which keys are being updated without a query; updates
|
|
57
|
+
* are rare so clearing is cheap.
|
|
58
|
+
*/
|
|
59
|
+
this.apiKeyCache.clear();
|
|
60
|
+
return { updateBy, carryForward: null };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@CaptureSpan()
|
|
64
|
+
protected override async onBeforeDelete(
|
|
65
|
+
deleteBy: DeleteBy<Model>,
|
|
66
|
+
): Promise<OnDelete<Model>> {
|
|
67
|
+
this.apiKeyCache.clear();
|
|
68
|
+
return { deleteBy, carryForward: null };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Resolves an API key string to its row, with a short-lived in-process
|
|
73
|
+
* cache. Returns null for unknown or expired keys (also cached, for a
|
|
74
|
+
* shorter TTL). Use this from the auth middleware hot path instead of
|
|
75
|
+
* calling `findOneBy` directly.
|
|
76
|
+
*/
|
|
77
|
+
@CaptureSpan()
|
|
78
|
+
public async findApiKey(
|
|
79
|
+
apiKey: ObjectID,
|
|
80
|
+
): Promise<{ id: ObjectID; projectId: ObjectID } | null> {
|
|
81
|
+
const cacheKey: string = apiKey.toString();
|
|
82
|
+
const cached: CachedApiKey | null | undefined =
|
|
83
|
+
this.apiKeyCache.get(cacheKey);
|
|
84
|
+
if (cached !== undefined) {
|
|
85
|
+
if (cached === null) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
id: new ObjectID(cached.id),
|
|
90
|
+
projectId: new ObjectID(cached.projectId),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const row: Model | null = await this.findOneBy({
|
|
95
|
+
query: {
|
|
96
|
+
apiKey: apiKey,
|
|
97
|
+
expiresAt: QueryHelper.greaterThan(OneUptimeDate.getCurrentDate()),
|
|
98
|
+
},
|
|
99
|
+
select: {
|
|
100
|
+
_id: true,
|
|
101
|
+
projectId: true,
|
|
102
|
+
},
|
|
103
|
+
props: { isRoot: true },
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
if (!row || !row.id || !row.projectId) {
|
|
107
|
+
this.apiKeyCache.set(cacheKey, null, NEGATIVE_TTL_MS);
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
this.apiKeyCache.set(
|
|
112
|
+
cacheKey,
|
|
113
|
+
{ id: row.id.toString(), projectId: row.projectId.toString() },
|
|
114
|
+
POSITIVE_TTL_MS,
|
|
115
|
+
);
|
|
116
|
+
return { id: row.id, projectId: row.projectId };
|
|
117
|
+
}
|
|
19
118
|
}
|
|
20
119
|
|
|
21
120
|
export default new Service();
|
|
@@ -132,6 +132,7 @@ export class Service extends DatabaseService<Model> {
|
|
|
132
132
|
extra?: {
|
|
133
133
|
osType?: string | undefined;
|
|
134
134
|
osVersion?: string | undefined;
|
|
135
|
+
agentVersion?: string | undefined;
|
|
135
136
|
},
|
|
136
137
|
): Promise<void> {
|
|
137
138
|
const cacheKey: string = hostId.toString();
|
|
@@ -141,6 +142,7 @@ export class Service extends DatabaseService<Model> {
|
|
|
141
142
|
JSON.stringify({
|
|
142
143
|
osType: extra?.osType ?? null,
|
|
143
144
|
osVersion: extra?.osVersion ?? null,
|
|
145
|
+
agentVersion: extra?.agentVersion ?? null,
|
|
144
146
|
}),
|
|
145
147
|
)
|
|
146
148
|
.digest("hex");
|
|
@@ -173,6 +175,9 @@ export class Service extends DatabaseService<Model> {
|
|
|
173
175
|
if (extra?.osVersion) {
|
|
174
176
|
data.osVersion = extra.osVersion;
|
|
175
177
|
}
|
|
178
|
+
if (extra?.agentVersion) {
|
|
179
|
+
data.agentVersion = extra.agentVersion;
|
|
180
|
+
}
|
|
176
181
|
|
|
177
182
|
await this.updateOneById({
|
|
178
183
|
id: hostId,
|
|
@@ -135,6 +135,7 @@ export class Service extends DatabaseService<Model> {
|
|
|
135
135
|
containerRuntime?: string | undefined;
|
|
136
136
|
dockerHostId?: ObjectID | undefined;
|
|
137
137
|
kubernetesClusterId?: ObjectID | undefined;
|
|
138
|
+
agentVersion?: string | undefined;
|
|
138
139
|
},
|
|
139
140
|
): Promise<void> {
|
|
140
141
|
/*
|
|
@@ -204,6 +205,9 @@ export class Service extends DatabaseService<Model> {
|
|
|
204
205
|
if (extra?.kubernetesClusterId) {
|
|
205
206
|
data.kubernetesClusterId = extra.kubernetesClusterId;
|
|
206
207
|
}
|
|
208
|
+
if (extra?.agentVersion) {
|
|
209
|
+
data.agentVersion = extra.agentVersion;
|
|
210
|
+
}
|
|
207
211
|
|
|
208
212
|
await this.updateOneById({
|
|
209
213
|
id: hostId,
|
|
@@ -227,6 +231,7 @@ export class Service extends DatabaseService<Model> {
|
|
|
227
231
|
containerRuntime?: string | undefined;
|
|
228
232
|
dockerHostId?: ObjectID | undefined;
|
|
229
233
|
kubernetesClusterId?: ObjectID | undefined;
|
|
234
|
+
agentVersion?: string | undefined;
|
|
230
235
|
}): string {
|
|
231
236
|
const normalized: Record<string, string | number | null> = {
|
|
232
237
|
osType: extra?.osType ?? null,
|
|
@@ -241,6 +246,7 @@ export class Service extends DatabaseService<Model> {
|
|
|
241
246
|
containerRuntime: extra?.containerRuntime ?? null,
|
|
242
247
|
dockerHostId: extra?.dockerHostId?.toString() ?? null,
|
|
243
248
|
kubernetesClusterId: extra?.kubernetesClusterId?.toString() ?? null,
|
|
249
|
+
agentVersion: extra?.agentVersion ?? null,
|
|
244
250
|
};
|
|
245
251
|
|
|
246
252
|
return crypto
|
|
@@ -127,28 +127,51 @@ export class Service extends DatabaseService<Model> {
|
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
@CaptureSpan()
|
|
130
|
-
public async updateLastSeen(
|
|
130
|
+
public async updateLastSeen(
|
|
131
|
+
clusterId: ObjectID,
|
|
132
|
+
extra?: {
|
|
133
|
+
agentVersion?: string | undefined;
|
|
134
|
+
},
|
|
135
|
+
): Promise<void> {
|
|
131
136
|
const cacheKey: string = clusterId.toString();
|
|
137
|
+
const extrasFingerprint: string = crypto
|
|
138
|
+
.createHash("sha1")
|
|
139
|
+
.update(
|
|
140
|
+
JSON.stringify({
|
|
141
|
+
agentVersion: extra?.agentVersion ?? null,
|
|
142
|
+
}),
|
|
143
|
+
)
|
|
144
|
+
.digest("hex");
|
|
132
145
|
|
|
133
146
|
const cached: string | null = await GlobalCache.getString(
|
|
134
147
|
LAST_SEEN_CACHE_NAMESPACE,
|
|
135
148
|
cacheKey,
|
|
136
149
|
);
|
|
137
150
|
|
|
138
|
-
if (cached) {
|
|
139
|
-
return; //
|
|
151
|
+
if (cached === extrasFingerprint) {
|
|
152
|
+
return; // same data was written recently
|
|
140
153
|
}
|
|
141
154
|
|
|
142
|
-
await GlobalCache.setString(
|
|
143
|
-
|
|
144
|
-
|
|
155
|
+
await GlobalCache.setString(
|
|
156
|
+
LAST_SEEN_CACHE_NAMESPACE,
|
|
157
|
+
cacheKey,
|
|
158
|
+
extrasFingerprint,
|
|
159
|
+
{ expiresInSeconds: LAST_SEEN_THROTTLE_SECONDS },
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
163
|
+
const data: any = {
|
|
164
|
+
lastSeenAt: OneUptimeDate.getCurrentDate(),
|
|
165
|
+
otelCollectorStatus: "connected",
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
if (extra?.agentVersion) {
|
|
169
|
+
data.agentVersion = extra.agentVersion;
|
|
170
|
+
}
|
|
145
171
|
|
|
146
172
|
await this.updateOneById({
|
|
147
173
|
id: clusterId,
|
|
148
|
-
data:
|
|
149
|
-
lastSeenAt: OneUptimeDate.getCurrentDate(),
|
|
150
|
-
otelCollectorStatus: "connected",
|
|
151
|
-
},
|
|
174
|
+
data: data,
|
|
152
175
|
props: {
|
|
153
176
|
isRoot: true,
|
|
154
177
|
},
|