Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor remote debugging commands into common library #1045

Merged
merged 2 commits into from
Aug 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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';
24 changes: 4 additions & 20 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
"onCommand:appService.OpenLogStream",
"onCommand:appService.StopLogStream",
"onCommand:appService.StartRemoteDebug",
"onCommand:appService.StopRemoteDebug",
"onCommand:appService.StartSsh",
"onCommand:appService.CreateSlot",
"onCommand:appService.DeploySlot",
Expand Down Expand Up @@ -228,11 +227,6 @@
"title": "Start Remote Debugging",
"category": "Azure App Service"
},
{
"command": "appService.StopRemoteDebug",
"title": "Stop Remote Debugging",
"category": "Azure App Service"
},
{
"command": "appService.StartSsh",
"title": "SSH into Web App",
Expand Down Expand Up @@ -523,17 +517,12 @@
{
"command": "appService.StartRemoteDebug",
"when": "view == azureAppService && viewItem == appService",
"group": "5_appServiceRemoteDebugCommands@1"
},
{
"command": "appService.StopRemoteDebug",
"when": "view == azureAppService && viewItem == appService",
"group": "5_appServiceRemoteDebugCommands@2"
"group": "5_appServiceRemoteCommands@1"
},
{
"command": "appService.StartSsh",
"when": "view == azureAppService && viewItem == appService",
"group": "6_appServiceRemoteSshCommands@1"
"group": "5_appServiceRemoteCommands@2"
},
{
"command": "appService.CreateSlot",
Expand Down Expand Up @@ -613,17 +602,12 @@
{
"command": "appService.StartRemoteDebug",
"when": "view == azureAppService && viewItem == deploymentSlot",
"group": "5_appServiceRemoteDebugCommands@1"
},
{
"command": "appService.StopRemoteDebug",
"when": "view == azureAppService && viewItem == deploymentSlot",
"group": "5_appServiceRemoteDebugCommands@2"
"group": "5_appServiceRemoteCommands@1"
},
{
"command": "appService.Refresh",
"when": "view == azureAppService && viewItem == deploymentSlot",
"group": "6_deploymentSlotRefreshCommands@1"
"group": "5_appServiceRemoteCommands@2"
},
{
"command": "appService.EnableFileLogging",
Expand Down
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);
}
32 changes: 0 additions & 32 deletions src/commands/remoteDebug/stopRemoteDebug.ts

This file was deleted.

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
2 changes: 0 additions & 2 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import { viewCommitInGitHub } from './commands/deployments/viewCommitInGitHub';
import { viewDeploymentLogs } from './commands/deployments/viewDeploymentLogs';
import { enableFileLogging } from './commands/enableFileLogging';
import { startRemoteDebug } from './commands/remoteDebug/startRemoteDebug';
import { stopRemoteDebug } from './commands/remoteDebug/stopRemoteDebug';
import { showFile } from './commands/showFile';
import { startSsh } from './commands/startSsh';
import { startStreamingLogs } from './commands/startStreamingLogs';
Expand Down Expand Up @@ -268,7 +267,6 @@ export async function activateInternal(
registerCommand('appService.LogPoints.OpenScript', openScript);

registerCommand('appService.StartRemoteDebug', startRemoteDebug);
registerCommand('appService.StopRemoteDebug', stopRemoteDebug);
registerCommand('appService.StartSsh', startSsh);

registerCommand('appService.showFile', async (_actionContext: IActionContext, node: FileTreeItem) => { await showFile(node, fileEditor); }, 500);
Expand Down