mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
Make 'Script to notebook' consistent with 'Deploy' when user cancels during password re-acquisition for controller (#13557)
This commit is contained in:
@@ -114,6 +114,8 @@
|
|||||||
"# Login to the data controller.\n",
|
"# Login to the data controller.\n",
|
||||||
"#\n",
|
"#\n",
|
||||||
"os.environ[\"AZDATA_PASSWORD\"] = os.environ[\"AZDATA_NB_VAR_CONTROLLER_PASSWORD\"]\n",
|
"os.environ[\"AZDATA_PASSWORD\"] = os.environ[\"AZDATA_NB_VAR_CONTROLLER_PASSWORD\"]\n",
|
||||||
|
"os.environ[\"KUBECONFIG\"] = controller_kubeconfig\n",
|
||||||
|
"os.environ[\"KUBECTL_CONTEXT\"] = controller_kubectl_context\n",
|
||||||
"cmd = f'azdata login -e {controller_endpoint} -u {controller_username}'\n",
|
"cmd = f'azdata login -e {controller_endpoint} -u {controller_username}'\n",
|
||||||
"out=run_command()"
|
"out=run_command()"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -114,6 +114,8 @@
|
|||||||
"# Login to the data controller.\n",
|
"# Login to the data controller.\n",
|
||||||
"#\n",
|
"#\n",
|
||||||
"os.environ[\"AZDATA_PASSWORD\"] = os.environ[\"AZDATA_NB_VAR_CONTROLLER_PASSWORD\"]\n",
|
"os.environ[\"AZDATA_PASSWORD\"] = os.environ[\"AZDATA_NB_VAR_CONTROLLER_PASSWORD\"]\n",
|
||||||
|
"os.environ[\"KUBECONFIG\"] = controller_kubeconfig\n",
|
||||||
|
"os.environ[\"KUBECTL_CONTEXT\"] = controller_kubectl_context\n",
|
||||||
"cmd = f'azdata login -e {controller_endpoint} -u {controller_username}'\n",
|
"cmd = f'azdata login -e {controller_endpoint} -u {controller_username}'\n",
|
||||||
"out=run_command()"
|
"out=run_command()"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -4,11 +4,17 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import * as arc from 'arc';
|
import * as arc from 'arc';
|
||||||
|
import * as rd from 'resource-deployment';
|
||||||
|
import * as loc from '../localizedConstants';
|
||||||
import { PasswordToControllerDialog } from '../ui/dialogs/connectControllerDialog';
|
import { PasswordToControllerDialog } from '../ui/dialogs/connectControllerDialog';
|
||||||
import { AzureArcTreeDataProvider } from '../ui/tree/azureArcTreeDataProvider';
|
import { AzureArcTreeDataProvider } from '../ui/tree/azureArcTreeDataProvider';
|
||||||
import { ControllerTreeNode } from '../ui/tree/controllerTreeNode';
|
import { ControllerTreeNode } from '../ui/tree/controllerTreeNode';
|
||||||
import { UserCancelledError } from './utils';
|
|
||||||
|
|
||||||
|
export class UserCancelledError extends Error implements rd.ErrorWithType {
|
||||||
|
public get type(): rd.ErrorType {
|
||||||
|
return rd.ErrorType.userCancelled;
|
||||||
|
}
|
||||||
|
}
|
||||||
export function arcApi(treeDataProvider: AzureArcTreeDataProvider): arc.IExtension {
|
export function arcApi(treeDataProvider: AzureArcTreeDataProvider): arc.IExtension {
|
||||||
return {
|
return {
|
||||||
getRegisteredDataControllers: () => getRegisteredDataControllers(treeDataProvider),
|
getRegisteredDataControllers: () => getRegisteredDataControllers(treeDataProvider),
|
||||||
@@ -16,12 +22,13 @@ export function arcApi(treeDataProvider: AzureArcTreeDataProvider): arc.IExtensi
|
|||||||
reacquireControllerPassword: (controllerInfo: arc.ControllerInfo) => reacquireControllerPassword(treeDataProvider, controllerInfo)
|
reacquireControllerPassword: (controllerInfo: arc.ControllerInfo) => reacquireControllerPassword(treeDataProvider, controllerInfo)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function reacquireControllerPassword(treeDataProvider: AzureArcTreeDataProvider, controllerInfo: arc.ControllerInfo): Promise<string> {
|
export async function reacquireControllerPassword(treeDataProvider: AzureArcTreeDataProvider, controllerInfo: arc.ControllerInfo): Promise<string> {
|
||||||
const dialog = new PasswordToControllerDialog(treeDataProvider);
|
const dialog = new PasswordToControllerDialog(treeDataProvider);
|
||||||
dialog.showDialog(controllerInfo);
|
dialog.showDialog(controllerInfo);
|
||||||
const model = await dialog.waitForClose();
|
const model = await dialog.waitForClose();
|
||||||
if (!model) {
|
if (!model) {
|
||||||
throw new UserCancelledError();
|
throw new UserCancelledError(loc.userCancelledError);
|
||||||
}
|
}
|
||||||
return model.password;
|
return model.password;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ import * as vscode from 'vscode';
|
|||||||
import { ConnectionMode, IconPath, IconPathHelper } from '../constants';
|
import { ConnectionMode, IconPath, IconPathHelper } from '../constants';
|
||||||
import * as loc from '../localizedConstants';
|
import * as loc from '../localizedConstants';
|
||||||
|
|
||||||
export class UserCancelledError extends Error { }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the resource type name into the localized Display Name for that type.
|
* Converts the resource type name into the localized Display Name for that type.
|
||||||
* @param resourceType The resource type name to convert
|
* @param resourceType The resource type name to convert
|
||||||
|
|||||||
@@ -205,3 +205,4 @@ export const noPasswordFound = (controllerName: string) => localize('noPasswordF
|
|||||||
export const noContextFound = (configFile: string) => localize('noContextFound', "No 'contexts' found in the config file: {0}", configFile);
|
export const noContextFound = (configFile: string) => localize('noContextFound', "No 'contexts' found in the config file: {0}", configFile);
|
||||||
export const noCurrentContextFound = (configFile: string) => localize('noCurrentContextFound', "No context is marked as 'current-context' in the config file: {0}", configFile);
|
export const noCurrentContextFound = (configFile: string) => localize('noCurrentContextFound', "No context is marked as 'current-context' in the config file: {0}", configFile);
|
||||||
export const noNameInContext = (configFile: string) => localize('noNameInContext', "No name field was found in a cluster context in the config file: {0}", configFile);
|
export const noNameInContext = (configFile: string) => localize('noNameInContext', "No name field was found in a cluster context in the config file: {0}", configFile);
|
||||||
|
export const userCancelledError = localize('userCancelledError', "User cancelled the dialog");
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
import { ControllerInfo, ResourceType } from 'arc';
|
import { ControllerInfo, ResourceType } from 'arc';
|
||||||
import * as azdataExt from 'azdata-ext';
|
import * as azdataExt from 'azdata-ext';
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { UserCancelledError } from '../common/utils';
|
import { UserCancelledError } from '../common/api';
|
||||||
import * as loc from '../localizedConstants';
|
import * as loc from '../localizedConstants';
|
||||||
import { ConnectToControllerDialog } from '../ui/dialogs/connectControllerDialog';
|
import { ConnectToControllerDialog } from '../ui/dialogs/connectControllerDialog';
|
||||||
import { AzureArcTreeDataProvider } from '../ui/tree/azureArcTreeDataProvider';
|
import { AzureArcTreeDataProvider } from '../ui/tree/azureArcTreeDataProvider';
|
||||||
@@ -71,7 +71,7 @@ export class ControllerModel {
|
|||||||
await this.treeDataProvider.addOrUpdateController(model.controllerModel, model.password, false);
|
await this.treeDataProvider.addOrUpdateController(model.controllerModel, model.password, false);
|
||||||
this._password = model.password;
|
this._password = model.password;
|
||||||
} else {
|
} else {
|
||||||
throw new UserCancelledError();
|
throw new UserCancelledError(loc.userCancelledError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,9 @@ import { MiaaResourceInfo } from 'arc';
|
|||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
import * as azdataExt from 'azdata-ext';
|
import * as azdataExt from 'azdata-ext';
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
|
import { UserCancelledError } from '../common/api';
|
||||||
import { Deferred } from '../common/promise';
|
import { Deferred } from '../common/promise';
|
||||||
import { createCredentialId, parseIpAndPort, UserCancelledError } from '../common/utils';
|
import { createCredentialId, parseIpAndPort } from '../common/utils';
|
||||||
import { credentialNamespace } from '../constants';
|
import { credentialNamespace } from '../constants';
|
||||||
import * as loc from '../localizedConstants';
|
import * as loc from '../localizedConstants';
|
||||||
import { ConnectToSqlDialog } from '../ui/dialogs/connectSqlDialog';
|
import { ConnectToSqlDialog } from '../ui/dialogs/connectSqlDialog';
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ import * as sinon from 'sinon';
|
|||||||
import * as TypeMoq from 'typemoq';
|
import * as TypeMoq from 'typemoq';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { UserCancelledError } from '../../common/utils';
|
import * as loc from '../../localizedConstants';
|
||||||
|
import { UserCancelledError } from '../../common/api';
|
||||||
import { ControllerModel } from '../../models/controllerModel';
|
import { ControllerModel } from '../../models/controllerModel';
|
||||||
import { ConnectToControllerDialog } from '../../ui/dialogs/connectControllerDialog';
|
import { ConnectToControllerDialog } from '../../ui/dialogs/connectControllerDialog';
|
||||||
import { AzureArcTreeDataProvider } from '../../ui/tree/azureArcTreeDataProvider';
|
import { AzureArcTreeDataProvider } from '../../ui/tree/azureArcTreeDataProvider';
|
||||||
@@ -39,7 +40,7 @@ describe('ControllerModel', function (): void {
|
|||||||
// Returning an undefined model here indicates that the dialog closed without clicking "Ok" - usually through the user clicking "Cancel"
|
// Returning an undefined model here indicates that the dialog closed without clicking "Ok" - usually through the user clicking "Cancel"
|
||||||
sinon.stub(ConnectToControllerDialog.prototype, 'waitForClose').returns(Promise.resolve(undefined));
|
sinon.stub(ConnectToControllerDialog.prototype, 'waitForClose').returns(Promise.resolve(undefined));
|
||||||
const model = new ControllerModel(new AzureArcTreeDataProvider(mockExtensionContext.object), { id: uuid(), url: '127.0.0.1', username: 'admin', name: 'arc', rememberPassword: true, resources: [] });
|
const model = new ControllerModel(new AzureArcTreeDataProvider(mockExtensionContext.object), { id: uuid(), url: '127.0.0.1', username: 'admin', name: 'arc', rememberPassword: true, resources: [] });
|
||||||
await should(model.azdataLogin()).be.rejectedWith(new UserCancelledError());
|
await should(model.azdataLogin()).be.rejectedWith(new UserCancelledError(loc.userCancelledError));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Reads password from cred store', async function (): Promise<void> {
|
it('Reads password from cred store', async function (): Promise<void> {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import { MiaaResourceInfo, ResourceInfo, ResourceType } from 'arc';
|
import { MiaaResourceInfo, ResourceInfo, ResourceType } from 'arc';
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { UserCancelledError } from '../../common/utils';
|
import { UserCancelledError } from '../../common/api';
|
||||||
import * as loc from '../../localizedConstants';
|
import * as loc from '../../localizedConstants';
|
||||||
import { ControllerModel, Registration } from '../../models/controllerModel';
|
import { ControllerModel, Registration } from '../../models/controllerModel';
|
||||||
import { MiaaModel } from '../../models/miaaModel';
|
import { MiaaModel } from '../../models/miaaModel';
|
||||||
|
|||||||
@@ -5,6 +5,14 @@
|
|||||||
declare module 'resource-deployment' {
|
declare module 'resource-deployment' {
|
||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
|
|
||||||
|
export const enum ErrorType {
|
||||||
|
userCancelled,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ErrorWithType extends Error {
|
||||||
|
readonly type: ErrorType;
|
||||||
|
}
|
||||||
|
|
||||||
export const enum extension {
|
export const enum extension {
|
||||||
name = 'Microsoft.resource-deployment'
|
name = 'Microsoft.resource-deployment'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { DeploymentType, NotebookWizardDeploymentProvider, NotebookWizardInfo }
|
|||||||
import { IPlatformService } from '../../services/platformService';
|
import { IPlatformService } from '../../services/platformService';
|
||||||
import { NotebookWizardAutoSummaryPage } from './notebookWizardAutoSummaryPage';
|
import { NotebookWizardAutoSummaryPage } from './notebookWizardAutoSummaryPage';
|
||||||
import { NotebookWizardPage } from './notebookWizardPage';
|
import { NotebookWizardPage } from './notebookWizardPage';
|
||||||
|
import { ErrorType, ErrorWithType } from 'resource-deployment';
|
||||||
|
|
||||||
export class NotebookWizardModel extends ResourceTypeModel {
|
export class NotebookWizardModel extends ResourceTypeModel {
|
||||||
private _inputComponents: InputComponents = {};
|
private _inputComponents: InputComponents = {};
|
||||||
@@ -58,16 +59,27 @@ export class NotebookWizardModel extends ResourceTypeModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates the notebook and returns true on successful generation
|
* Generates the notebook and returns true if generation was done and so the wizard should be closed.
|
||||||
**/
|
**/
|
||||||
public async onGenerateScript(): Promise<boolean> {
|
public async onGenerateScript(): Promise<boolean> {
|
||||||
const lastPage = this.wizard.lastPage! as NotebookWizardPage;
|
const lastPage = this.wizard.lastPage! as NotebookWizardPage;
|
||||||
if (lastPage.validatePage()) {
|
if (lastPage.validatePage()) {
|
||||||
const notebook = await this.prepareNotebookAndEnvironment();
|
let notebook: Notebook | undefined;
|
||||||
await this.openNotebook(notebook);
|
try {
|
||||||
return true;
|
notebook = await this.prepareNotebookAndEnvironment();
|
||||||
|
} catch (e) {
|
||||||
|
const isUserCancelled = e instanceof Error && 'type' in e && (<ErrorWithType>e).type === ErrorType.userCancelled;
|
||||||
|
// user cancellation is a normal scenario, we just bail out of the wizard without actually opening the notebook, so rethrow for any other case
|
||||||
|
if (!isUserCancelled) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (notebook) { // open the notebook if it was successfully prepared
|
||||||
|
await this.openNotebook(notebook);
|
||||||
|
}
|
||||||
|
return true; // generation done (or cancelled at user request) so close the wizard
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false; // validation failed so do not attempt to generate the notebook and do not close the wizard
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +94,7 @@ export class NotebookWizardModel extends ResourceTypeModel {
|
|||||||
return await this.notebookService.openNotebookWithContent(notebookPath, JSON.stringify(notebook, undefined, 4));
|
return await this.notebookService.openNotebookWithContent(notebookPath, JSON.stringify(notebook, undefined, 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async prepareNotebookAndEnvironment() {
|
private async prepareNotebookAndEnvironment(): Promise<Notebook> {
|
||||||
await setModelValues(this.inputComponents, this);
|
await setModelValues(this.inputComponents, this);
|
||||||
const env: NodeJS.ProcessEnv = process.env;
|
const env: NodeJS.ProcessEnv = process.env;
|
||||||
this.setEnvironmentVariables(env, (varName) => {
|
this.setEnvironmentVariables(env, (varName) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user