Skip to content
This repository was archived by the owner on Feb 8, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
9e9e47b
Ask user about collecting data (disabled for now)
gzdunek Dec 21, 2022
93b2558
Add `UsageEventService`, generate `IAppContext` basing on `AppContext`
gzdunek Dec 21, 2022
40858ae
Add gRPC method to report usage events
gzdunek Dec 21, 2022
7c55c5c
Extend `RuntimeSettings` with some os/connect info
gzdunek Dec 21, 2022
3a682f9
Collect actual events
gzdunek Dec 21, 2022
ceb2097
Merge branch 'master' into gzdunek/collect-usage-events
gzdunek Dec 30, 2022
f985129
Revert adding `runBeforeUiIsVisible/runAfterUiIsVisible` to context, …
gzdunek Dec 30, 2022
febea18
Move logger to the class
gzdunek Dec 30, 2022
5aac72c
Send events in dev mode
gzdunek Dec 30, 2022
2b1093e
Revert changes to `IAppContext`
gzdunek Dec 30, 2022
943ebb6
Remove tshd usage events, create Prehog events directly
gzdunek Dec 30, 2022
1e4505e
Remove `connect.` from `distinctId` (it will be added in prehog)
gzdunek Dec 30, 2022
b97f5d7
Rename `UsageEventService` to `UsageService`
gzdunek Jan 3, 2023
492fe48
Rename `UsageEventWithDate` to `ReportUsageEventRequest`
gzdunek Jan 3, 2023
10a2977
Rename `prehogEvent`, `prehogApiEvent` etc
gzdunek Jan 3, 2023
c04639e
Add more comments
gzdunek Jan 3, 2023
98dd193
Merge branch 'master' into gzdunek/collect-usage-events
gzdunek Jan 3, 2023
3b27e8c
Read version from `package.json` in dev mode
gzdunek Jan 3, 2023
1aca8f9
Fix tests
gzdunek Jan 3, 2023
b74a13d
Rename method and type in `UsageService`
gzdunek Jan 3, 2023
7a6a408
Rename `ReportEvent` to `ReportUsageEvent` in gRPC service for better…
gzdunek Jan 3, 2023
d596be5
Move warning up, adjust some methods names to events names
gzdunek Jan 3, 2023
207d623
Rename `connectVersion` to `appVersion`
gzdunek Jan 3, 2023
02df49a
Show warning when reporting usage event fails
gzdunek Jan 3, 2023
a860fa9
Merge branch 'master' into gzdunek/collect-usage-events
gzdunek Jan 4, 2023
97f8c63
Provide `authClusterId` in `getClusterProperties`
gzdunek Jan 4, 2023
e8e394d
Update protos to final version
gzdunek Jan 10, 2023
7836241
Collect connector type
gzdunek Jan 10, 2023
3330210
Pass prehog address to tshd
gzdunek Jan 10, 2023
a69c7af
Merge branch 'master' into gzdunek/collect-usage-events
gzdunek Jan 10, 2023
b3ac84d
Merge branch 'master' into gzdunek/collect-usage-events
gzdunek Jan 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/teleterm/src/mainProcess/fixtures/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ export class MockMainProcessClient implements MainProcessClient {
requestedNetworkAddress: '',
},
installationId: '123e4567-e89b-12d3-a456-426614174000',
arch: 'arm64',
osVersion: '22.2.0',
connectVersion: '11.1.0',
};
}

Expand Down
3 changes: 3 additions & 0 deletions packages/teleterm/src/mainProcess/runtimeSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ function getRuntimeSettings(): RuntimeSettings {
installationId: loadInstallationId(
path.resolve(app.getPath('userData'), 'installation_id')
),
arch: os.arch(),
osVersion: os.release(),
connectVersion: app.getVersion(),
};
}

Expand Down
3 changes: 3 additions & 0 deletions packages/teleterm/src/mainProcess/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ export type RuntimeSettings = {
requestedNetworkAddress: string;
};
installationId: string;
arch: string;
osVersion: string;
connectVersion: string;
};

export type MainProcessClient = {
Expand Down
15 changes: 15 additions & 0 deletions packages/teleterm/src/services/tshd/createClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import middleware, { withLogging } from './middleware';
import * as types from './types';
import createAbortController from './createAbortController';
import { AccessRequest, ResourceID } from './v1/access_request_pb';
import { mapUsageEvent } from './mapUsageEvent';
import { ReportEventRequest } from './types';

export default function createClient(
addr: string,
Expand Down Expand Up @@ -655,6 +657,19 @@ export default function createClient(
});
});
},

reportUsageEvent(event: ReportEventRequest) {
const req = mapUsageEvent(event);
return new Promise<void>((resolve, reject) => {
tshd.reportEvent(req, err => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
},
};
return client;
}
Expand Down
1 change: 1 addition & 0 deletions packages/teleterm/src/services/tshd/fixtures/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export class MockTshClient implements TshClient {
) => Promise<undefined>;
logout: (clusterUri: string) => Promise<undefined>;
transferFile: () => undefined;
reportUsageEvent: () => undefined;
}

export const gateway: Gateway = {
Expand Down
99 changes: 99 additions & 0 deletions packages/teleterm/src/services/tshd/mapUsageEvent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb';

import {
AccessRequestAssumeRoleEvent,
AccessRequestCreateEvent,
AccessRequestReviewEvent,
ClusterProperties,
ProtocolRunEvent,
ConnectUsageEventOneOf,
LoginEvent,
FileTransferRunEvent,
ReportEventRequest,
UserJobRoleUpdateEvent,
} from 'teleterm/services/tshd/v1/usage_events_pb';

import * as types from './types';

export function mapUsageEvent(event: types.ReportEventRequest) {
return new ReportEventRequest()
.setDistinctId(event.distinctId)
.setTimestamp(Timestamp.fromDate(event.timestamp))
.setEvent(mapEventBody(event.event));
}

function mapEventBody(
event: ConnectUsageEventOneOf.AsObject
): ConnectUsageEventOneOf {
if (event.loginEvent) {
const { loginEvent } = event;
return new ConnectUsageEventOneOf().setLoginEvent(
new LoginEvent()
.setClusterProperties(mapClusterProperties(loginEvent))
.setOs(loginEvent.os)
.setArch(loginEvent.arch)
.setOsVersion(loginEvent.osVersion)
.setConnectVersion(loginEvent.connectVersion)
);
}
if (event.protocolRunEvent) {
const { protocolRunEvent } = event;
return new ConnectUsageEventOneOf().setProtocolRunEvent(
new ProtocolRunEvent()
.setClusterProperties(mapClusterProperties(protocolRunEvent))
.setProtocol(protocolRunEvent.protocol)
);
}
if (event.accessRequestCreateEvent) {
const { accessRequestCreateEvent } = event;
return new ConnectUsageEventOneOf().setAccessRequestCreateEvent(
new AccessRequestCreateEvent()
.setClusterProperties(mapClusterProperties(accessRequestCreateEvent))
.setKind(accessRequestCreateEvent.kind)
);
}
if (event.accessRequestReviewEvent) {
const { accessRequestReviewEvent } = event;
return new ConnectUsageEventOneOf().setAccessRequestReviewEvent(
new AccessRequestReviewEvent().setClusterProperties(
mapClusterProperties(accessRequestReviewEvent)
)
);
}
if (event.accessRequestAssumeRoleEvent) {
const { accessRequestAssumeRoleEvent } = event;
return new ConnectUsageEventOneOf().setAccessRequestAssumeRoleEvent(
new AccessRequestAssumeRoleEvent().setClusterProperties(
mapClusterProperties(accessRequestAssumeRoleEvent)
)
);
}
if (event.fileTransferRunEvent) {
const { fileTransferRunEvent } = event;
return new ConnectUsageEventOneOf().setFileTransferRunEvent(
new FileTransferRunEvent()
.setClusterProperties(mapClusterProperties(fileTransferRunEvent))
.setDirection(fileTransferRunEvent.direction)
);
}
if (event.userJobRoleUpdateEvent) {
const { userJobRoleUpdateEvent } = event;
return new ConnectUsageEventOneOf().setUserJobRoleUpdateEvent(
new UserJobRoleUpdateEvent().setJobRole(userJobRoleUpdateEvent.jobRole)
);
}

throw new Error(`Unrecognized event: ${JSON.stringify(event)}`);
}

function mapClusterProperties(e: {
clusterProperties?: ClusterProperties.AsObject;
}): ClusterProperties {
if (!e.clusterProperties) {
throw new Error('Missing cluster metadata');
}
return new ClusterProperties()
.setAuthClusterId(e.clusterProperties.authClusterId)
.setClusterName(e.clusterProperties.clusterName)
.setUserName(e.clusterProperties.userName);
}
26 changes: 25 additions & 1 deletion packages/teleterm/src/services/tshd/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,34 +14,48 @@ import apiApp from './v1/app_pb';
import apiService from './v1/service_pb';
import apiAuthSettings from './v1/auth_settings_pb';
import apiAccessRequest from './v1/access_request_pb';
import apiUsageEvents from './v1/usage_events_pb';

export type Application = apiApp.App.AsObject;

export interface Kube extends apiKube.Kube.AsObject {
uri: uri.KubeUri;
}

export interface Server extends apiServer.Server.AsObject {
uri: uri.ServerUri;
}

export interface Gateway extends apigateway.Gateway.AsObject {
uri: uri.GatewayUri;
targetUri: uri.DatabaseUri;
}

export type AccessRequest = apiAccessRequest.AccessRequest.AsObject;
export type ResourceId = apiAccessRequest.ResourceID.AsObject;
export type AccessRequestReview = apiAccessRequest.AccessRequestReview.AsObject;

export interface GetServersResponse
extends apiService.GetServersResponse.AsObject {
agentsList: Server[];
}

export interface GetDatabasesResponse
extends apiService.GetDatabasesResponse.AsObject {
agentsList: Database[];
}

export interface GetKubesResponse extends apiService.GetKubesResponse.AsObject {
agentsList: Kube[];
}

export type GetRequestableRolesResponse =
apiService.GetRequestableRolesResponse.AsObject;

export type ReportEventRequest = Modify<
apiUsageEvents.ReportEventRequest.AsObject,
{ timestamp: Date }
>;
// Available types are listed here:
// https://github.com/gravitational/teleport/blob/v9.0.3/lib/defaults/defaults.go#L513-L530
//
Expand All @@ -53,20 +67,26 @@ export type GatewayProtocol =
| 'cockroachdb'
| 'redis'
| 'sqlserver';

export interface Database extends apiDb.Database.AsObject {
uri: uri.DatabaseUri;
}

export interface Cluster extends apiCluster.Cluster.AsObject {
uri: uri.ClusterUri;
loggedInUser?: LoggedInUser;
}

export type LoggedInUser = apiCluster.LoggedInUser.AsObject & {
assumedRequests?: Record<string, AssumedRequest>;
};
export type AuthProvider = apiAuthSettings.AuthProvider.AsObject;
export type AuthSettings = apiAuthSettings.AuthSettings.AsObject;

export type FileTransferRequest = apiService.FileTransferRequest.AsObject;
export interface FileTransferRequest
extends apiService.FileTransferRequest.AsObject {
clusterUri: uri.ClusterUri;
}

export type WebauthnCredentialInfo = apiService.CredentialInfo.AsObject;
export type WebauthnLoginPrompt =
Expand Down Expand Up @@ -160,6 +180,7 @@ export type TshClient = {
options: FileTransferRequest,
abortSignal?: TshAbortSignal
) => FileTransferListeners;
reportUsageEvent: (event: ReportEventRequest) => Promise<void>;
};

export type TshAbortController = {
Expand Down Expand Up @@ -233,3 +254,6 @@ export type AssumedRequest = {
expires: Date;
roles: string[];
};

// Replaces object property with a new type
type Modify<T, R> = Omit<T, keyof R> & R;
18 changes: 18 additions & 0 deletions packages/teleterm/src/services/tshd/v1/service_grpc_pb.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 35 additions & 0 deletions packages/teleterm/src/services/tshd/v1/service_grpc_pb.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/teleterm/src/services/tshd/v1/service_pb.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions packages/teleterm/src/services/tshd/v1/service_pb.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading