Skip to content

Commit 8a871e1

Browse files
committed
Minor fixes and improve logging and telemetry
1 parent 24e64b2 commit 8a871e1

File tree

3 files changed

+82
-53
lines changed

3 files changed

+82
-53
lines changed

src/authentication.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,15 @@ export default class GitpodAuthenticationProvider extends Disposable implements
4242
const serviceUrl = new URL(gitpodHost);
4343
this._gitpodServer = new GitpodServer(serviceUrl.toString(), this._logger);
4444
this._keychain = new Keychain(this.context, `gitpod.auth.${serviceUrl.hostname}`, this._logger);
45+
this._logger.info(`Started authentication provider for ${gitpodHost}`);
4546
this._register(vscode.workspace.onDidChangeConfiguration(e => {
4647
if (e.affectsConfiguration('gitpod.host')) {
4748
const gitpodHost = vscode.workspace.getConfiguration('gitpod').get<string>('host')!;
4849
const serviceUrl = new URL(gitpodHost);
4950
this._gitpodServer.dispose();
5051
this._gitpodServer = new GitpodServer(serviceUrl.toString(), this._logger);
5152
this._keychain = new Keychain(this.context, `gitpod.auth.${serviceUrl.hostname}`, this._logger);
53+
this._logger.info(`Started authentication provider for ${gitpodHost}`);
5254

5355
this.checkForUpdates();
5456
}

src/featureSupport.ts

Lines changed: 46 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,59 +5,76 @@
55
import * as semver from 'semver';
66
import fetch from 'node-fetch';
77

8-
type Feature = |
9-
'SSHPublicKeys' |
10-
'localHeartbeat';
8+
export class GitpodVersion {
9+
static DEFAULT_VERSION = '9999.99.99';
1110

12-
const DEFAULT_VERSION = '9999.99.99';
13-
let cacheGitpodVersion: { host: string; version: string } | undefined;
14-
export async function getGitpodVersion(gitpodHost: string) {
15-
const serviceUrl = new URL(gitpodHost).toString().replace(/\/$/, '');
11+
readonly version: string;
12+
readonly raw: string;
13+
14+
constructor(gitpodVersion: string = '') {
15+
this.raw = gitpodVersion;
16+
this.version = GitpodVersion.DEFAULT_VERSION;
17+
18+
if (gitpodVersion.startsWith('release-')) {
19+
gitpodVersion = gitpodVersion.replace('release-', '');
20+
gitpodVersion = gitpodVersion.replace(/\.\d+$/, '');
21+
22+
// Remove leading zeros to make it a valid semver
23+
const [yy, mm, dd] = gitpodVersion.split('.');
24+
gitpodVersion = `${parseInt(yy, 10)}.${parseInt(mm, 10)}.${parseInt(dd, 10)}`;
25+
26+
}
27+
28+
if (semver.valid(gitpodVersion)) {
29+
this.version = gitpodVersion;
30+
}
31+
}
32+
}
33+
34+
let cacheGitpodVersion: { host: string; version: GitpodVersion } | undefined;
35+
async function getOrFetchVersionInfo(serviceUrl: string) {
1636
if (serviceUrl === 'https://gitpod.io') {
17-
return DEFAULT_VERSION;
37+
return undefined;
1838
}
1939

2040
if (serviceUrl === cacheGitpodVersion?.host) {
21-
return cacheGitpodVersion.version;
41+
return cacheGitpodVersion;
2242
}
2343

24-
let gitpodVersion: string | null;
44+
let gitpodRawVersion: string;
2545
try {
2646
const versionEndPoint = `${serviceUrl}/api/version`;
2747
const versionResponse = await fetch(versionEndPoint);
2848
if (!versionResponse.ok) {
29-
return DEFAULT_VERSION;
49+
return undefined;
3050
}
3151

32-
gitpodVersion = await versionResponse.text();
52+
gitpodRawVersion = await versionResponse.text();
3353
} catch (e) {
34-
return DEFAULT_VERSION;
35-
}
36-
37-
gitpodVersion = gitpodVersion.replace('release-', '');
38-
gitpodVersion = gitpodVersion.replace(/\.\d+$/, '');
39-
40-
// Remove leading zeros to make it a valid semver
41-
const [yy, mm, dd] = gitpodVersion.split('.');
42-
gitpodVersion = `${parseInt(yy, 10)}.${parseInt(mm, 10)}.${parseInt(dd, 10)}`;
43-
44-
gitpodVersion = semver.valid(gitpodVersion);
45-
if (!gitpodVersion) {
46-
return DEFAULT_VERSION;
54+
return undefined;
4755
}
4856

4957
cacheGitpodVersion = {
5058
host: serviceUrl,
51-
version: gitpodVersion
59+
version: new GitpodVersion(gitpodRawVersion)
5260
};
61+
return cacheGitpodVersion;
62+
}
5363

54-
return cacheGitpodVersion.version;
64+
export async function getGitpodVersion(gitpodHost: string) {
65+
const serviceUrl = new URL(gitpodHost).toString().replace(/\/$/, '');
66+
const versionInfo = await getOrFetchVersionInfo(serviceUrl);
67+
return versionInfo?.version || new GitpodVersion();
5568
}
5669

57-
export function isFeatureSupported(gitpodVersion: string, feature: Feature) {
70+
type Feature = |
71+
'SSHPublicKeys' |
72+
'localHeartbeat';
73+
74+
export function isFeatureSupported(gitpodVersion: GitpodVersion, feature: Feature) {
5875
switch (feature) {
5976
case 'SSHPublicKeys':
6077
case 'localHeartbeat':
61-
return semver.gte(gitpodVersion, '2022.7.0'); // Don't use leading zeros
78+
return semver.gte(gitpodVersion.version, '2022.7.0'); // Don't use leading zeros
6279
}
6380
}

src/remoteConnector.ts

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,7 @@ export default class RemoteConnector extends Disposable {
531531
if (identityFilePaths.length) {
532532
sshDestInfo.user = `${workspaceId}#${ownerToken}`;
533533
}
534-
this.logger.warn(`Registered SSH public keys not supported in ${gitpodHost}, using version ${gitpodVersion}`);
534+
this.logger.warn(`Registered SSH public keys not supported in ${gitpodHost}, using version ${gitpodVersion.version}`);
535535
}
536536

537537
return {
@@ -618,20 +618,28 @@ export default class RemoteConnector extends Disposable {
618618
return true;
619619
}
620620

621-
private async showSSHPasswordModal(password: string) {
621+
private async showSSHPasswordModal(password: string, gitpodHost: string) {
622622
const maskedPassword = '•'.repeat(password.length - 3) + password.substring(password.length - 3);
623623

624+
const gitpodVersion = await getGitpodVersion(gitpodHost);
625+
const sshKeysSupported = isFeatureSupported(gitpodVersion, 'SSHPublicKeys');
626+
624627
const copy: vscode.MessageItem = { title: 'Copy' };
625628
const configureSSH: vscode.MessageItem = { title: 'Configure SSH' };
626629
const showLogs: vscode.MessageItem = { title: 'Show logs', isCloseAffordance: true };
627-
const action = await vscode.window.showWarningMessage(`You don't have registered any SSH public key for this machine in your Gitpod account.\nAlternatively, copy and use this temporary password until workspace restart: ${maskedPassword}`, { modal: true }, copy, configureSSH, showLogs);
630+
const message = sshKeysSupported
631+
? `You don't have registered any SSH public key for this machine in your Gitpod account.\nAlternatively, copy and use this temporary password until workspace restart: ${maskedPassword}`
632+
: `An SSH key is required for passwordless authentication.\nAlternatively, copy and use this password: ${maskedPassword}`;
633+
const action = await vscode.window.showWarningMessage(message, { modal: true }, copy, configureSSH, showLogs);
628634
if (action === copy) {
629635
await vscode.env.clipboard.writeText(password);
630636
return;
631637
}
632638
if (action === configureSSH) {
633-
await vscode.env.openExternal(vscode.Uri.parse('https://gitpod.io/keys'));
634-
throw new Error(`SSH password modal dialog, ${configureSSH}`);
639+
const serviceUrl = new URL(gitpodHost).toString().replace(/\/$/, '');
640+
const externalUrl = sshKeysSupported ? `${serviceUrl}/keys` : 'https://www.gitpod.io/docs/configure/ssh#create-an-ssh-key';
641+
await vscode.env.openExternal(vscode.Uri.parse(externalUrl));
642+
throw new Error(`SSH password modal dialog, Configure SSH`);
635643
}
636644

637645
this.logger.show();
@@ -658,7 +666,7 @@ export default class RemoteConnector extends Disposable {
658666
if (isFeatureSupported(gitpodVersion, 'SSHPublicKeys') /* && isFeatureSupported('', 'sendHeartBeat') */) {
659667
sessionScopes.push('function:getSSHPublicKeys', 'function:sendHeartBeat');
660668
} else {
661-
this.logger.warn(`function:getSSHPublicKeys and function:sendHeartBeat session scopes not supported in ${gitpodHost}, using version ${gitpodVersion}`);
669+
this.logger.warn(`function:getSSHPublicKeys and function:sendHeartBeat session scopes not supported in ${gitpodHost}, using version ${gitpodVersion.version}`);
662670
}
663671

664672
return vscode.authentication.getSession(
@@ -680,6 +688,7 @@ export default class RemoteConnector extends Disposable {
680688
}
681689

682690
const params: SSHConnectionParams = JSON.parse(uri.query);
691+
const gitpodVersion = await getGitpodVersion(params.gitpodHost);
683692

684693
const session = await this.getGitpodSession(params.gitpodHost);
685694
if (!session) {
@@ -692,18 +701,18 @@ export default class RemoteConnector extends Disposable {
692701
let sshDestination: string | undefined;
693702
if (!forceUseLocalApp) {
694703
try {
695-
this.telemetry.sendTelemetryEvent('vscode_desktop_ssh', { kind: 'gateway', status: 'connecting', ...params });
704+
this.telemetry.sendRawTelemetryEvent('vscode_desktop_ssh', { kind: 'gateway', status: 'connecting', ...params, gitpodVersion: gitpodVersion.raw });
696705

697706
const { destination, password } = await this.getWorkspaceSSHDestination(session.accessToken, params);
698707
sshDestination = destination;
699708

700709
if (password) {
701-
await this.showSSHPasswordModal(password);
710+
await this.showSSHPasswordModal(password, params.gitpodHost);
702711
}
703712

704-
this.telemetry.sendTelemetryEvent('vscode_desktop_ssh', { kind: 'gateway', status: 'connected', ...params });
713+
this.telemetry.sendRawTelemetryEvent('vscode_desktop_ssh', { kind: 'gateway', status: 'connected', ...params, gitpodVersion: gitpodVersion.raw });
705714
} catch (e) {
706-
this.telemetry.sendRawTelemetryEvent('vscode_desktop_ssh', { kind: 'gateway', status: 'failed', reason: e.toString(), ...params });
715+
this.telemetry.sendRawTelemetryEvent('vscode_desktop_ssh', { kind: 'gateway', status: 'failed', reason: e.toString(), ...params, gitpodVersion: gitpodVersion.raw });
707716
if (e instanceof NoSSHGatewayError) {
708717
this.logger.error('No SSH gateway:', e);
709718
vscode.window.showWarningMessage(`${e.host} does not support [direct SSH access](https://github.com/gitpod-io/gitpod/blob/main/install/installer/docs/workspace-ssh-access.md), connecting via the deprecated SSH tunnel over WebSocket.`);
@@ -735,15 +744,15 @@ export default class RemoteConnector extends Disposable {
735744
let localAppSSHConfigPath: string | undefined;
736745
if (!usingSSHGateway) {
737746
try {
738-
this.telemetry.sendTelemetryEvent('vscode_desktop_ssh', { kind: 'local-app', status: 'connecting', ...params });
747+
this.telemetry.sendRawTelemetryEvent('vscode_desktop_ssh', { kind: 'local-app', status: 'connecting', ...params, gitpodVersion: gitpodVersion.raw });
739748

740749
const localAppDestData = await this.getWorkspaceLocalAppSSHDestination(params);
741750
sshDestination = localAppDestData.localAppSSHDest;
742751
localAppSSHConfigPath = localAppDestData.localAppSSHConfigPath;
743752

744-
this.telemetry.sendTelemetryEvent('vscode_desktop_ssh', { kind: 'local-app', status: 'connected', ...params });
753+
this.telemetry.sendRawTelemetryEvent('vscode_desktop_ssh', { kind: 'local-app', status: 'connected', ...params, gitpodVersion: gitpodVersion.raw });
745754
} catch (e) {
746-
this.telemetry.sendRawTelemetryEvent('vscode_desktop_ssh', { kind: 'local-app', status: 'failed', reason: e.toString(), ...params });
755+
this.telemetry.sendRawTelemetryEvent('vscode_desktop_ssh', { kind: 'local-app', status: 'failed', reason: e.toString(), ...params, gitpodVersion: gitpodVersion.raw });
747756
this.logger.error(`Failed to connect ${params.workspaceId} Gitpod workspace:`, e);
748757
if (e instanceof LocalAppError) {
749758
const seeLogs = 'See Logs';
@@ -829,26 +838,27 @@ export default class RemoteConnector extends Disposable {
829838
if (isFeatureSupported(gitpodVersion, 'localHeartbeat')) {
830839
// gitpod remote extension installation is async so sometimes gitpod-desktop will activate before gitpod-remote
831840
// let's try a few times for it to finish install
832-
let retryCount = 10;
833-
const tryStartHeartbeat = async () => {
841+
let retryCount = 15;
842+
const tryStopRemoteHeartbeat = async () => {
834843
// Check for gitpod remote extension version to avoid sending heartbeat in both extensions at the same time
835844
const isGitpodRemoteHeartbeatCancelled = await cancelGitpodRemoteHeartbeat();
836845
if (isGitpodRemoteHeartbeatCancelled) {
837-
const session = await this.getGitpodSession(connectionInfo.gitpodHost);
838-
if (session) {
839-
this.startHeartBeat(session.accessToken, connectionInfo);
840-
}
841-
this.telemetry.sendTelemetryEvent('vscode_desktop_heartbeat_state', { enabled: String(!!this.heartbeatManager), gitpodHost: connectionInfo.gitpodHost, workspaceId: connectionInfo.workspaceId, instanceId: connectionInfo.instanceId });
846+
this.telemetry.sendTelemetryEvent('vscode_desktop_heartbeat_state', { enabled: String(true), gitpodHost: connectionInfo.gitpodHost, workspaceId: connectionInfo.workspaceId, instanceId: connectionInfo.instanceId, gitpodVersion: gitpodVersion.raw });
842847
} else if (retryCount > 0) {
843848
retryCount--;
844-
setTimeout(tryStartHeartbeat, 3000);
849+
setTimeout(tryStopRemoteHeartbeat, 3000);
845850
} else {
846-
this.telemetry.sendTelemetryEvent('vscode_desktop_heartbeat_state', { enabled: String(false), gitpodHost: connectionInfo.gitpodHost, workspaceId: connectionInfo.workspaceId, instanceId: connectionInfo.instanceId });
851+
this.telemetry.sendTelemetryEvent('vscode_desktop_heartbeat_state', { enabled: String(false), gitpodHost: connectionInfo.gitpodHost, workspaceId: connectionInfo.workspaceId, instanceId: connectionInfo.instanceId, gitpodVersion: gitpodVersion.raw });
847852
}
848853
};
849-
tryStartHeartbeat();
854+
855+
const session = await this.getGitpodSession(connectionInfo.gitpodHost);
856+
if (session) {
857+
this.startHeartBeat(session.accessToken, connectionInfo);
858+
tryStopRemoteHeartbeat();
859+
}
850860
} else {
851-
this.logger.warn(`Local heatbeat not supported in ${connectionInfo.gitpodHost}, using version ${gitpodVersion}`);
861+
this.logger.warn(`Local heatbeat not supported in ${connectionInfo.gitpodHost}, using version ${gitpodVersion.version}`);
852862
}
853863
}
854864

0 commit comments

Comments
 (0)