Skip to content

Commit 2b4621a

Browse files
authored
Add instance id to telemetry data when local-ssh failed (#67)
1 parent 6cac03a commit 2b4621a

File tree

4 files changed

+35
-20
lines changed

4 files changed

+35
-20
lines changed

src/local-ssh/ipc/extensionServiceServer.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const phaseMap: Record<WorkspaceInstanceStatus_Phase, WorkspaceInstancePhase | u
2929
[WorkspaceInstanceStatus_Phase.CREATING]: 'pending',
3030
[WorkspaceInstanceStatus_Phase.IMAGEBUILD]: 'building',
3131
[WorkspaceInstanceStatus_Phase.INITIALIZING]: 'initializing',
32-
[WorkspaceInstanceStatus_Phase.INTERRUPTED]: 'running',
32+
[WorkspaceInstanceStatus_Phase.INTERRUPTED]: 'interrupted',
3333
[WorkspaceInstanceStatus_Phase.PENDING]: 'stopping',
3434
[WorkspaceInstanceStatus_Phase.PREPARING]: 'stopped',
3535
[WorkspaceInstanceStatus_Phase.RUNNING]: 'running',
@@ -89,10 +89,6 @@ class ExtensionServiceImpl implements ExtensionServiceImplementation {
8989
]), this.logService);
9090

9191
const phase = usePublicApi ? phaseMap[(workspace as Workspace).status?.instance?.status?.phase ?? WorkspaceInstanceStatus_Phase.UNSPECIFIED] : (workspace as WorkspaceInfo).latestInstance?.status.phase;
92-
if (phase !== 'running') {
93-
// TODO(lssh): notification?
94-
throw new ServerError(Status.UNAVAILABLE, 'workspace is not running, current phase: ' + phase);
95-
}
9692

9793
const ideUrl = usePublicApi ? (workspace as Workspace).status?.instance?.status?.url : (workspace as WorkspaceInfo).latestInstance?.ideUrl;
9894
if (!ideUrl) {
@@ -102,7 +98,7 @@ class ExtensionServiceImpl implements ExtensionServiceImplementation {
10298
const workspaceHost = url.host.substring(url.host.indexOf('.') + 1);
10399
const instanceId = (usePublicApi ? (workspace as Workspace).status?.instance?.instanceId : (workspace as WorkspaceInfo).latestInstance?.id) as string;
104100

105-
const sshkey = await this.getWorkspaceSSHKey(ownerToken, workspaceId, workspaceHost);
101+
const sshkey = phase === 'running' ? (await this.getWorkspaceSSHKey(ownerToken, workspaceId, workspaceHost)) : '';
106102

107103
return {
108104
gitpodHost,
@@ -111,7 +107,8 @@ class ExtensionServiceImpl implements ExtensionServiceImplementation {
111107
instanceId,
112108
workspaceHost,
113109
ownerToken,
114-
sshkey
110+
sshkey,
111+
phase: phase ?? 'unknown',
115112
};
116113
} catch (e) {
117114
this.logService.error(e, 'failed to get workspace auth info');

src/local-ssh/proxy.ts

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import { SshClient } from '@microsoft/dev-tunnels-ssh-tcp';
77
import { NodeStream, SshClientCredentials, SshClientSession, SshDisconnectReason, SshServerSession, SshSessionConfiguration, Stream, WebSocketStream } from '@microsoft/dev-tunnels-ssh';
88
import { importKey, importKeyBytes } from '@microsoft/dev-tunnels-ssh-keys';
99
import { ExtensionServiceDefinition, GetWorkspaceAuthInfoResponse, SendErrorReportRequest, SendLocalSSHUserFlowStatusRequest } from '../proto/typescript/ipc/v1/ipc';
10-
import { Client, ClientError, Status, createChannel, createClient } from 'nice-grpc';
11-
import { retry, retryWithStop } from '../common/async';
10+
import { Client, createChannel, createClient } from 'nice-grpc';
11+
import { retry } from '../common/async';
1212
import { WebSocket } from 'ws';
1313
import * as stream from 'stream';
1414
import { ILogService } from '../services/logService';
@@ -46,8 +46,9 @@ type SSHUserFlowTelemetry = Partial<SendLocalSSHUserFlowStatusRequest>;
4646

4747
type FailedToProxyCode = 'SSH.AuthenticationFailed' | 'TUNNEL.AuthenticateSSHKeyFailed' | 'NoRunningInstance' | 'FailedToGetAuthInfo';
4848
class FailedToProxyError extends Error {
49-
constructor(public readonly failureCode: FailedToProxyCode) {
50-
super('Failed to proxy connection: ' + failureCode);
49+
constructor(public readonly failureCode: FailedToProxyCode, originError?: Error) {
50+
const msg = 'Failed to proxy connection: ' + failureCode
51+
super(originError ? (msg + ': ' + originError.toString()) : msg );
5152
this.name = 'FailedToProxyError';
5253
}
5354

@@ -154,6 +155,9 @@ class WebSocketSSHProxy {
154155
const workspaceInfo = await this.retryGetWorkspaceInfo(username);
155156
flow.instanceId = workspaceInfo.instanceId;
156157
flow.userId = workspaceInfo.userId;
158+
if (workspaceInfo.phase !== 'running') {
159+
throw new FailedToProxyError('NoRunningInstance')
160+
}
157161

158162
if (FORCE_TUNNEL) {
159163
return this.getTunnelSSHConfig(workspaceInfo);
@@ -213,15 +217,9 @@ class WebSocketSSHProxy {
213217
}
214218

215219
async retryGetWorkspaceInfo(username: string) {
216-
return retryWithStop(async (stop) => {
220+
return retry(async () => {
217221
return this.extensionIpc.getWorkspaceAuthInfo({ workspaceId: username, gitpodHost: this.options.host }).catch(e => {
218-
if (e instanceof ClientError) {
219-
if (e.code === Status.UNAVAILABLE && e.details.startsWith('workspace is not running')) {
220-
stop();
221-
throw new FailedToProxyError('NoRunningInstance');
222-
}
223-
}
224-
throw new FailedToProxyError('FailedToGetAuthInfo');
222+
throw new FailedToProxyError('FailedToGetAuthInfo', e);
225223
});
226224
}, 200, 50);
227225
}

src/proto/ipc/v1/ipc.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,5 @@ message GetWorkspaceAuthInfoResponse {
8383
string gitpod_host = 5;
8484
string user_id = 6;
8585
string sshkey = 7;
86+
string phase = 8;
8687
}

src/proto/typescript/ipc/v1/ipc.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ export interface GetWorkspaceAuthInfoResponse {
203203
gitpodHost: string;
204204
userId: string;
205205
sshkey: string;
206+
phase: string;
206207
}
207208

208209
function createBaseSendErrorReportRequest(): SendErrorReportRequest {
@@ -636,7 +637,16 @@ export const GetWorkspaceAuthInfoRequest = {
636637
};
637638

638639
function createBaseGetWorkspaceAuthInfoResponse(): GetWorkspaceAuthInfoResponse {
639-
return { workspaceId: "", instanceId: "", workspaceHost: "", ownerToken: "", gitpodHost: "", userId: "", sshkey: "" };
640+
return {
641+
workspaceId: "",
642+
instanceId: "",
643+
workspaceHost: "",
644+
ownerToken: "",
645+
gitpodHost: "",
646+
userId: "",
647+
sshkey: "",
648+
phase: "",
649+
};
640650
}
641651

642652
export const GetWorkspaceAuthInfoResponse = {
@@ -662,6 +672,9 @@ export const GetWorkspaceAuthInfoResponse = {
662672
if (message.sshkey !== "") {
663673
writer.uint32(58).string(message.sshkey);
664674
}
675+
if (message.phase !== "") {
676+
writer.uint32(66).string(message.phase);
677+
}
665678
return writer;
666679
},
667680

@@ -693,6 +706,9 @@ export const GetWorkspaceAuthInfoResponse = {
693706
case 7:
694707
message.sshkey = reader.string();
695708
break;
709+
case 8:
710+
message.phase = reader.string();
711+
break;
696712
default:
697713
reader.skipType(tag & 7);
698714
break;
@@ -710,6 +726,7 @@ export const GetWorkspaceAuthInfoResponse = {
710726
gitpodHost: isSet(object.gitpodHost) ? String(object.gitpodHost) : "",
711727
userId: isSet(object.userId) ? String(object.userId) : "",
712728
sshkey: isSet(object.sshkey) ? String(object.sshkey) : "",
729+
phase: isSet(object.phase) ? String(object.phase) : "",
713730
};
714731
},
715732

@@ -722,6 +739,7 @@ export const GetWorkspaceAuthInfoResponse = {
722739
message.gitpodHost !== undefined && (obj.gitpodHost = message.gitpodHost);
723740
message.userId !== undefined && (obj.userId = message.userId);
724741
message.sshkey !== undefined && (obj.sshkey = message.sshkey);
742+
message.phase !== undefined && (obj.phase = message.phase);
725743
return obj;
726744
},
727745

@@ -738,6 +756,7 @@ export const GetWorkspaceAuthInfoResponse = {
738756
message.gitpodHost = object.gitpodHost ?? "";
739757
message.userId = object.userId ?? "";
740758
message.sshkey = object.sshkey ?? "";
759+
message.phase = object.phase ?? "";
741760
return message;
742761
},
743762
};

0 commit comments

Comments
 (0)