mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
notebook background execution (#8079)
* notebook background execution * code review comments * comments 2 * more logging
This commit is contained in:
@@ -98,6 +98,8 @@ export interface WizardInfo {
|
|||||||
|
|
||||||
export interface NotebookBasedDialogInfo extends DialogInfoBase {
|
export interface NotebookBasedDialogInfo extends DialogInfoBase {
|
||||||
notebook: string | NotebookInfo;
|
notebook: string | NotebookInfo;
|
||||||
|
runNotebook?: boolean;
|
||||||
|
taskName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CommandBasedDialogInfo extends DialogInfoBase {
|
export interface CommandBasedDialogInfo extends DialogInfoBase {
|
||||||
@@ -118,6 +120,7 @@ export interface DialogInfoBase {
|
|||||||
title: string;
|
title: string;
|
||||||
name: string;
|
name: string;
|
||||||
tabs: DialogTabInfo[];
|
tabs: DialogTabInfo[];
|
||||||
|
actionText?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DialogTabInfo {
|
export interface DialogTabInfo {
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
vscode.commands.registerCommand('azdata.openNotebookInputDialog', (dialogInfo: NotebookBasedDialogInfo) => {
|
vscode.commands.registerCommand('azdata.openNotebookInputDialog', (dialogInfo: NotebookBasedDialogInfo) => {
|
||||||
const dialog = new DeploymentInputDialog(notebookService, dialogInfo);
|
const dialog = new DeploymentInputDialog(notebookService, platformService, dialogInfo);
|
||||||
dialog.open();
|
dialog.open();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ export interface INotebookService {
|
|||||||
launchNotebook(notebook: string | NotebookInfo): Thenable<azdata.nb.NotebookEditor>;
|
launchNotebook(notebook: string | NotebookInfo): Thenable<azdata.nb.NotebookEditor>;
|
||||||
launchNotebookWithContent(title: string, content: string): Thenable<azdata.nb.NotebookEditor>;
|
launchNotebookWithContent(title: string, content: string): Thenable<azdata.nb.NotebookEditor>;
|
||||||
getNotebook(notebook: string | NotebookInfo): Promise<Notebook>;
|
getNotebook(notebook: string | NotebookInfo): Promise<Notebook>;
|
||||||
executeNotebook(notebook: any, env: NodeJS.ProcessEnv): Promise<NotebookExecutionResult>;
|
executeNotebook(notebook: any, env?: NodeJS.ProcessEnv): Promise<NotebookExecutionResult>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NotebookService implements INotebookService {
|
export class NotebookService implements INotebookService {
|
||||||
@@ -73,7 +73,7 @@ export class NotebookService implements INotebookService {
|
|||||||
return <Notebook>JSON.parse(await this.platformService.readTextFile(notebookPath));
|
return <Notebook>JSON.parse(await this.platformService.readTextFile(notebookPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
async executeNotebook(notebook: Notebook, env: NodeJS.ProcessEnv): Promise<NotebookExecutionResult> {
|
async executeNotebook(notebook: Notebook, env?: NodeJS.ProcessEnv): Promise<NotebookExecutionResult> {
|
||||||
const content = JSON.stringify(notebook, undefined, 4);
|
const content = JSON.stringify(notebook, undefined, 4);
|
||||||
const fileName = `nb-${getDateTimeString()}.ipynb`;
|
const fileName = `nb-${getDateTimeString()}.ipynb`;
|
||||||
const workingDirectory = this.platformService.storagePath();
|
const workingDirectory = this.platformService.storagePath();
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ export class ResourceTypeService implements IResourceTypeService {
|
|||||||
const wizard = new DeployClusterWizard(provider.wizard, new KubeService(), new AzdataService(this.platformService), this.notebookService);
|
const wizard = new DeployClusterWizard(provider.wizard, new KubeService(), new AzdataService(this.platformService), this.notebookService);
|
||||||
wizard.open();
|
wizard.open();
|
||||||
} else if (instanceOfDialogDeploymentProvider(provider)) {
|
} else if (instanceOfDialogDeploymentProvider(provider)) {
|
||||||
const dialog = new DeploymentInputDialog(this.notebookService, provider.dialog);
|
const dialog = new DeploymentInputDialog(this.notebookService, this.platformService, provider.dialog);
|
||||||
dialog.open();
|
dialog.open();
|
||||||
} else if (instanceOfNotebookDeploymentProvider(provider)) {
|
} else if (instanceOfNotebookDeploymentProvider(provider)) {
|
||||||
this.notebookService.launchNotebook(provider.notebook);
|
this.notebookService.launchNotebook(provider.notebook);
|
||||||
|
|||||||
@@ -263,8 +263,10 @@ export abstract class ToolBase implements ITool {
|
|||||||
);
|
);
|
||||||
this.version = this.getVersionFromOutput(commandOutput);
|
this.version = this.getVersionFromOutput(commandOutput);
|
||||||
if (this.version) {
|
if (this.version) {
|
||||||
|
if (this.autoInstallSupported) {
|
||||||
// discover and set the installationPath
|
// discover and set the installationPath
|
||||||
await this.setInstallationPath();
|
await this.setInstallationPath();
|
||||||
|
}
|
||||||
return ToolStatus.Installed;
|
return ToolStatus.Installed;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -8,10 +8,12 @@ import * as vscode from 'vscode';
|
|||||||
import * as nls from 'vscode-nls';
|
import * as nls from 'vscode-nls';
|
||||||
import { DialogBase } from './dialogBase';
|
import { DialogBase } from './dialogBase';
|
||||||
import { INotebookService } from '../services/notebookService';
|
import { INotebookService } from '../services/notebookService';
|
||||||
import { DialogInfo, instanceOfNotebookBasedDialogInfo } from '../interfaces';
|
import { DialogInfo, instanceOfNotebookBasedDialogInfo, NotebookBasedDialogInfo } from '../interfaces';
|
||||||
import { Validator, initializeDialog, InputComponents, setModelValues } from './modelViewUtils';
|
import { Validator, initializeDialog, InputComponents, setModelValues } from './modelViewUtils';
|
||||||
import { Model } from './model';
|
import { Model } from './model';
|
||||||
import { EOL } from 'os';
|
import { EOL } from 'os';
|
||||||
|
import { getDateTimeString, getErrorMessage } from '../utils';
|
||||||
|
import { IPlatformService } from '../services/platformService';
|
||||||
|
|
||||||
const localize = nls.loadMessageBundle();
|
const localize = nls.loadMessageBundle();
|
||||||
|
|
||||||
@@ -20,9 +22,19 @@ export class DeploymentInputDialog extends DialogBase {
|
|||||||
private inputComponents: InputComponents = {};
|
private inputComponents: InputComponents = {};
|
||||||
|
|
||||||
constructor(private notebookService: INotebookService,
|
constructor(private notebookService: INotebookService,
|
||||||
|
private platformService: IPlatformService,
|
||||||
private dialogInfo: DialogInfo) {
|
private dialogInfo: DialogInfo) {
|
||||||
super(dialogInfo.title, dialogInfo.name, false);
|
super(dialogInfo.title, dialogInfo.name, false);
|
||||||
this._dialogObject.okButton.label = localize('deploymentDialog.OKButtonText', "Open Notebook");
|
let okButtonText: string;
|
||||||
|
if (dialogInfo.actionText) {
|
||||||
|
okButtonText = dialogInfo.actionText;
|
||||||
|
} else if (instanceOfNotebookBasedDialogInfo(dialogInfo) && !dialogInfo.runNotebook) {
|
||||||
|
okButtonText = localize('deploymentDialog.OpenNotebook', "Open Notebook");
|
||||||
|
} else {
|
||||||
|
okButtonText = localize('deploymentDialog.OkButtonText', "OK");
|
||||||
|
}
|
||||||
|
|
||||||
|
this._dialogObject.okButton.label = okButtonText;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected initialize() {
|
protected initialize() {
|
||||||
@@ -63,11 +75,52 @@ export class DeploymentInputDialog extends DialogBase {
|
|||||||
setModelValues(this.inputComponents, model);
|
setModelValues(this.inputComponents, model);
|
||||||
if (instanceOfNotebookBasedDialogInfo(this.dialogInfo)) {
|
if (instanceOfNotebookBasedDialogInfo(this.dialogInfo)) {
|
||||||
model.setEnvironmentVariables();
|
model.setEnvironmentVariables();
|
||||||
|
if (this.dialogInfo.runNotebook) {
|
||||||
|
this.executeNotebook(this.dialogInfo);
|
||||||
|
} else {
|
||||||
this.notebookService.launchNotebook(this.dialogInfo.notebook).then(() => { }, (error) => {
|
this.notebookService.launchNotebook(this.dialogInfo.notebook).then(() => { }, (error) => {
|
||||||
vscode.window.showErrorMessage(error);
|
vscode.window.showErrorMessage(error);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
vscode.commands.executeCommand(this.dialogInfo.command, model);
|
vscode.commands.executeCommand(this.dialogInfo.command, model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private executeNotebook(notebookDialogInfo: NotebookBasedDialogInfo): void {
|
||||||
|
azdata.tasks.startBackgroundOperation({
|
||||||
|
displayName: notebookDialogInfo.taskName!,
|
||||||
|
description: notebookDialogInfo.taskName!,
|
||||||
|
isCancelable: false,
|
||||||
|
operation: async op => {
|
||||||
|
op.updateStatus(azdata.TaskStatus.InProgress);
|
||||||
|
const notebook = await this.notebookService.getNotebook(notebookDialogInfo.notebook);
|
||||||
|
const result = await this.notebookService.executeNotebook(notebook);
|
||||||
|
if (result.succeeded) {
|
||||||
|
op.updateStatus(azdata.TaskStatus.Succeeded);
|
||||||
|
} else {
|
||||||
|
op.updateStatus(azdata.TaskStatus.Failed, result.errorMessage);
|
||||||
|
if (result.outputNotebook) {
|
||||||
|
const viewErrorDetail = localize('resourceDeployment.ViewErrorDetail', "View error detail");
|
||||||
|
const taskFailedMessage = localize('resourceDeployment.DeployFailed', "The task \"{0}\" has failed.", notebookDialogInfo.taskName);
|
||||||
|
const selectedOption = await vscode.window.showErrorMessage(taskFailedMessage, viewErrorDetail);
|
||||||
|
this.platformService.logToOutputChannel(taskFailedMessage);
|
||||||
|
if (selectedOption === viewErrorDetail) {
|
||||||
|
try {
|
||||||
|
this.notebookService.launchNotebookWithContent(`deploy-${getDateTimeString()}`, result.outputNotebook);
|
||||||
|
} catch (error) {
|
||||||
|
const launchNotebookError = localize('resourceDeployment.FailedToOpenNotebook', "An error occurred launching the output notebook. {1}{2}.", EOL, getErrorMessage(error));
|
||||||
|
this.platformService.logToOutputChannel(launchNotebookError);
|
||||||
|
vscode.window.showErrorMessage(launchNotebookError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const errorMessage = localize('resourceDeployment.TaskFailedWithNoOutputNotebook', "The task \"{0}\" failed and no output Notebook was generated.", notebookDialogInfo.taskName);
|
||||||
|
this.platformService.logToOutputChannel(errorMessage);
|
||||||
|
vscode.window.showErrorMessage(errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,16 +17,21 @@ export function getDateTimeString(): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function setEnvironmentVariablesForInstallPaths(tools: ITool[]): void {
|
export function setEnvironmentVariablesForInstallPaths(tools: ITool[]): void {
|
||||||
|
// Use Set class to make sure the collection only contains unique values.
|
||||||
let installationPaths: Set<string> = new Set<string>();
|
let installationPaths: Set<string> = new Set<string>();
|
||||||
tools.forEach(t => {
|
tools.forEach(t => {
|
||||||
|
if (t.installationPath) {
|
||||||
// construct an env variable name with NoteBookEnvironmentVariablePrefix prefix
|
// construct an env variable name with NoteBookEnvironmentVariablePrefix prefix
|
||||||
// and tool.name as suffix, making sure of using all uppercase characters and only _ as separator
|
// and tool.name as suffix, making sure of using all uppercase characters and only _ as separator
|
||||||
const envVarName: string = `${NoteBookEnvironmentVariablePrefix}${t.name.toUpperCase().replace(/ |-/, '_')}`;
|
const envVarName: string = `${NoteBookEnvironmentVariablePrefix}${t.name.toUpperCase().replace(/ |-/g, '_')}`;
|
||||||
process.env[envVarName] = t.installationPath;
|
process.env[envVarName] = t.installationPath;
|
||||||
installationPaths.add(path.resolve(path.dirname(t.installationPath)));
|
installationPaths.add(path.resolve(path.dirname(t.installationPath)));
|
||||||
console.log(`setting env var:'${envVarName}' to: '${t.installationPath}'`);
|
console.log(`setting env var:'${envVarName}' to: '${t.installationPath}'`);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
if (installationPaths.size > 0) {
|
||||||
const envVarToolsInstallationPath: string = [...installationPaths.values()].join(path.delimiter);
|
const envVarToolsInstallationPath: string = [...installationPaths.values()].join(path.delimiter);
|
||||||
process.env[ToolsInstallPath] = envVarToolsInstallationPath;
|
process.env[ToolsInstallPath] = envVarToolsInstallationPath;
|
||||||
console.log(`setting env var:'${ToolsInstallPath}' to: '${envVarToolsInstallationPath}'`);
|
console.log(`setting env var:'${ToolsInstallPath}' to: '${envVarToolsInstallationPath}'`);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user