Skip to content

Commit

Permalink
Refactor remote debugging commands into common library, see microsoft…
Browse files Browse the repository at this point in the history
  • Loading branch information
mrcrane committed Jun 25, 2019
1 parent 969a561 commit 58b2e83
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 161 deletions.
2 changes: 1 addition & 1 deletion extension.bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ export * from 'vscode-azureextensionui';
export { SubscriptionTreeItem } from './src/explorer/SubscriptionTreeItem';
export { AzureAccountTreeItem } from './src/explorer/AzureAccountTreeItem';
export { getRandomHexString } from './src/utils/randomUtils';
export { checkForRemoteDebugSupport } from './src/commands/remoteDebug/remoteDebugCommon';
export { checkForRemoteDebugSupport } from './src/commands/remoteDebug/checkForRemoteDebugSupport';
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,7 @@
*--------------------------------------------------------------------------------------------*/

import { SiteConfigResource } from 'azure-arm-website/lib/models';
import * as vscode from 'vscode';
import { SiteClient } from 'vscode-azureappservice';
import { callWithTelemetryAndErrorHandling, DialogResponses, IActionContext } from 'vscode-azureextensionui';
import { ext } from '../../extensionVariables';

export const remoteDebugLink: string = 'https://aka.ms/appsvc-remotedebug';
export function reportMessage(message: string, progress: vscode.Progress<{}>): void {
ext.outputChannel.appendLine(message);
progress.report({ message: message });
}
import { IActionContext } from 'vscode-azureextensionui';

export function checkForRemoteDebugSupport(siteConfig: SiteConfigResource, context: IActionContext): void {
// We read siteConfig.linuxFxVersion to find the image version:
Expand Down Expand Up @@ -61,31 +52,3 @@ function isNodeVersionSupported(nodeVersion: string): boolean {

return (major > 8 || (major === 8 && minor >= 11));
}

export async function setRemoteDebug(isRemoteDebuggingToBeEnabled: boolean, confirmMessage: string, noopMessage: string | undefined, siteClient: SiteClient, siteConfig: SiteConfigResource, progress?: vscode.Progress<{}>, learnMoreLink?: string): Promise<void> {
if (isRemoteDebuggingToBeEnabled !== siteConfig.remoteDebuggingEnabled) {
const confirmButton: vscode.MessageItem = isRemoteDebuggingToBeEnabled ? { title: 'Enable' } : { title: 'Disable' };

// don't have to check input as this handles cancels and learnMore responses
await ext.ui.showWarningMessage(confirmMessage, { modal: true, learnMoreLink }, confirmButton, DialogResponses.cancel);
siteConfig.remoteDebuggingEnabled = isRemoteDebuggingToBeEnabled;
if (progress) {
reportMessage('Updating site configuration to set remote debugging...', progress);
}

await callWithTelemetryAndErrorHandling('appService.remoteDebugUpdateConfiguration', async (context: IActionContext) => {
context.errorHandling.suppressDisplay = true;
context.errorHandling.rethrow = true;
await siteClient.updateConfiguration(siteConfig);
});

if (progress) {
reportMessage('Updating site configuration done...', progress);
}
} else {
// Update not needed
if (noopMessage) {
vscode.window.showWarningMessage(noopMessage);
}
}
}
112 changes: 9 additions & 103 deletions src/commands/remoteDebug/startRemoteDebug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,120 +3,26 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { SiteConfigResource, User } from 'azure-arm-website/lib/models';
import * as portfinder from 'portfinder';
import * as vscode from 'vscode';
import { SiteClient, TunnelProxy } from 'vscode-azureappservice';
import { callWithTelemetryAndErrorHandling, IActionContext } from 'vscode-azureextensionui';
import * as appservice from 'vscode-azureappservice';
import { IActionContext } from 'vscode-azureextensionui';
import { SiteTreeItem } from '../../explorer/SiteTreeItem';
import { WebAppTreeItem } from '../../explorer/WebAppTreeItem';
import { ext } from '../../extensionVariables';
import * as remoteDebug from './remoteDebugCommon';

let isRemoteDebugging = false;
import { checkForRemoteDebugSupport } from './checkForRemoteDebugSupport';

export async function startRemoteDebug(context: IActionContext, node?: SiteTreeItem): Promise<void> {
if (isRemoteDebugging) {
throw new Error('Azure Remote Debugging is currently starting or already started.');
}

isRemoteDebugging = true;
try {
await startRemoteDebugInternal(context, node);
} catch (error) {
isRemoteDebugging = false;
throw error;
}
}

async function startRemoteDebugInternal(context: IActionContext, node?: SiteTreeItem): Promise<void> {
if (!node) {
node = <SiteTreeItem>await ext.tree.showTreeItemPicker(WebAppTreeItem.contextValue, context);
}
const siteClient: SiteClient = node.root.client;

await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification }, async (progress: vscode.Progress<{}>): Promise<void> => {
remoteDebug.reportMessage('Fetching site configuration...', progress);
const siteConfig: SiteConfigResource = await siteClient.getSiteConfig();

remoteDebug.checkForRemoteDebugSupport(siteConfig, context);
const debugConfig: vscode.DebugConfiguration = await getDebugConfiguration();
// tslint:disable-next-line:no-unsafe-any
const localHostPortNumber: number = debugConfig.port;

remoteDebug.reportMessage('Checking app settings...', progress);

const confirmEnableMessage: string = 'The app configuration will be updated to enable remote debugging and restarted. Would you like to continue?';
await remoteDebug.setRemoteDebug(true, confirmEnableMessage, undefined, siteClient, siteConfig, progress, remoteDebug.remoteDebugLink);

remoteDebug.reportMessage('Starting tunnel proxy...', progress);

const publishCredential: User = await siteClient.getWebAppPublishCredential();
const tunnelProxy: TunnelProxy = new TunnelProxy(localHostPortNumber, siteClient, publishCredential);
await callWithTelemetryAndErrorHandling('appService.remoteDebugStartProxy', async (startContext: IActionContext) => {
startContext.errorHandling.suppressDisplay = true;
startContext.errorHandling.rethrow = true;
await tunnelProxy.startProxy();
});

remoteDebug.reportMessage('Attaching debugger...', progress);

await callWithTelemetryAndErrorHandling('appService.remoteDebugAttach', async (attachContext: IActionContext) => {
attachContext.errorHandling.suppressDisplay = true;
attachContext.errorHandling.rethrow = true;
await vscode.debug.startDebugging(undefined, debugConfig);
});

remoteDebug.reportMessage('Attached!', progress);

const terminateDebugListener: vscode.Disposable = vscode.debug.onDidTerminateDebugSession(async (event: vscode.DebugSession) => {
if (event.name === debugConfig.name) {
isRemoteDebugging = false;

if (tunnelProxy !== undefined) {
tunnelProxy.dispose();
}
terminateDebugListener.dispose();

const confirmDisableMessage: string = 'Leaving the app in debugging mode may cause performance issues. Would you like to disable debugging for this app? The app will be restarted.';
await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification }, async (innerProgress: vscode.Progress<{}>): Promise<void> => {
await remoteDebug.setRemoteDebug(false, confirmDisableMessage, undefined, siteClient, siteConfig, innerProgress, remoteDebug.remoteDebugLink);
});
}
});
const siteClient = node.root.client;
const siteConfig = await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification }, async progress => {
appservice.reportMessage('Fetching site configuration...', progress);
return await siteClient.getSiteConfig();
});
}

async function getDebugConfiguration(): Promise<vscode.DebugConfiguration> {
const sessionId: string = Date.now().toString();
const portNumber: number = await portfinder.getPortPromise();

// So far only node is supported
const config: vscode.DebugConfiguration = {
// return {
name: sessionId,
type: 'node',
protocol: 'inspector',
request: 'attach',
address: 'localhost',
port: portNumber
};

// Try to map workspace folder source files to the remote instance
if (vscode.workspace.workspaceFolders) {
if (vscode.workspace.workspaceFolders.length === 1) {
config.localRoot = vscode.workspace.workspaceFolders[0].uri.fsPath;
config.remoteRoot = '/home/site/wwwroot';
} else {
// In this case we don't know which folder to use. Show a warning and proceed.
// In the future we should allow users to choose a workspace folder to map sources from.
// tslint:disable-next-line:no-floating-promises
ext.ui.showWarningMessage('Unable to bind breakpoints from workspace when multiple folders are open. Use "loaded scripts" instead.');
}
} else {
// vscode will throw an error if you try to start debugging without any workspace folder open
throw new Error("Please open a workspace folder before attaching a debugger.");
}
checkForRemoteDebugSupport(siteConfig, context);

return config;
await appservice.startRemoteDebug(siteClient, siteConfig);
}
22 changes: 9 additions & 13 deletions src/commands/remoteDebug/stopRemoteDebug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,26 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { SiteConfigResource } from 'azure-arm-website/lib/models';
import * as vscode from 'vscode';
import { SiteClient } from 'vscode-azureappservice';
import * as appservice from 'vscode-azureappservice';
import { IActionContext } from 'vscode-azureextensionui';
import { SiteTreeItem } from '../../explorer/SiteTreeItem';
import { WebAppTreeItem } from '../../explorer/WebAppTreeItem';
import { ext } from '../../extensionVariables';
import * as remoteDebug from './remoteDebugCommon';
import { checkForRemoteDebugSupport } from './checkForRemoteDebugSupport';

export async function stopRemoteDebug(context: IActionContext, node?: SiteTreeItem): Promise<void> {
if (!node) {
node = <SiteTreeItem>await ext.tree.showTreeItemPicker(WebAppTreeItem.contextValue, context);
}
const siteClient: SiteClient = node.root.client;

const confirmMessage: string = 'The app configuration will be updated to disable remote debugging and restarted. Would you like to continue?';
const noopMessage: string = 'The app is not configured for debugging.';

await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification }, async (progress: vscode.Progress<{}>): Promise<void> => {
remoteDebug.reportMessage('Fetching site configuration...', progress);
const siteConfig: SiteConfigResource = await siteClient.getSiteConfig();
const siteClient = node.root.client;
const siteConfig = await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification }, async progress => {
appservice.reportMessage('Fetching site configuration...', progress);
return await siteClient.getSiteConfig();
});

remoteDebug.checkForRemoteDebugSupport(siteConfig, context);
checkForRemoteDebugSupport(siteConfig, context);

await remoteDebug.setRemoteDebug(false, confirmMessage, noopMessage, siteClient, siteConfig, progress, remoteDebug.remoteDebugLink);
});
await appservice.startRemoteDebug(siteClient, siteConfig);
}
11 changes: 5 additions & 6 deletions src/commands/startSsh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@
import { SiteConfigResource, User } from 'azure-arm-website/lib/models';
import * as portfinder from 'portfinder';
import * as vscode from 'vscode';
import { SiteClient, TunnelProxy } from 'vscode-azureappservice';
import { reportMessage, setRemoteDebug, SiteClient, TunnelProxy } from 'vscode-azureappservice';
import { IActionContext } from 'vscode-azureextensionui';
import { SiteTreeItem } from '../explorer/SiteTreeItem';
import { WebAppTreeItem } from '../explorer/WebAppTreeItem';
import { ext } from '../extensionVariables';
import { delay } from '../utils/delay';
import * as remoteDebug from './remoteDebug/remoteDebugCommon';

export type sshTerminal = {
starting: boolean,
Expand Down Expand Up @@ -55,22 +54,22 @@ async function startSshInternal(node: SiteTreeItem): Promise<void> {

await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification }, async (progress: vscode.Progress<{}>): Promise<void> => {

remoteDebug.reportMessage('Checking app settings...', progress);
reportMessage('Checking app settings...', progress);

const confirmDisableMessage: string = 'Remote debugging must be disabled in order to SSH. This will restart the app.';
const siteConfig: SiteConfigResource = await siteClient.getSiteConfig();
// remote debugging has to be disabled in order to tunnel to the 2222 port
await remoteDebug.setRemoteDebug(false, confirmDisableMessage, undefined, siteClient, siteConfig, progress);
await setRemoteDebug(false, confirmDisableMessage, undefined, siteClient, siteConfig, progress);

remoteDebug.reportMessage('Initializing SSH...', progress);
reportMessage('Initializing SSH...', progress);
const publishCredential: User = await siteClient.getWebAppPublishCredential();
const localHostPortNumber: number = await portfinder.getPortPromise();
// should always be an unbound port
const tunnelProxy: TunnelProxy = new TunnelProxy(localHostPortNumber, siteClient, publishCredential, true);

await tunnelProxy.startProxy();

remoteDebug.reportMessage('Connecting to SSH...', progress);
reportMessage('Connecting to SSH...', progress);
await connectToTunnelProxy(node, tunnelProxy, localHostPortNumber);
});
}
Expand Down

0 comments on commit 58b2e83

Please sign in to comment.