mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-14 01:25:37 -05:00
Maddy/prompt password when different (#4537)
* Prompt for password once when the sql instance password doesn't work for hdfs. If the user provides the correct password, connect and continue, else show Unauthorized node. * Removed the hardcoded bad password * Added check for empty folder scenarios * Added ErrorStatusCode as property of TreeNode. Checking for the error code instead of the error string to avoid localization issues * type fixed * implemented hasExpansionError
This commit is contained in:
@@ -107,7 +107,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<MssqlE
|
||||
credentialsStore.start();
|
||||
resourceProvider.start();
|
||||
|
||||
let nodeProvider = new MssqlObjectExplorerNodeProvider(appContext);
|
||||
let nodeProvider = new MssqlObjectExplorerNodeProvider(prompter, appContext);
|
||||
azdata.dataprotocol.registerObjectExplorerNodeProvider(nodeProvider);
|
||||
activateSparkFeatures(appContext);
|
||||
activateNotebookTask(appContext);
|
||||
|
||||
@@ -69,6 +69,12 @@ export class SqlClusterConnection {
|
||||
return FileSourceFactory.instance.createHdfsFileSource(options);
|
||||
}
|
||||
|
||||
public updatePassword(password : string): void{
|
||||
if(password){
|
||||
this._password = password;
|
||||
}
|
||||
}
|
||||
|
||||
private validate(connectionInfo: azdata.ConnectionInfo): void {
|
||||
if (!connectionInfo) {
|
||||
throw new Error(localize('connectionInfoUndefined', 'ConnectionInfo is undefined.'));
|
||||
|
||||
@@ -150,7 +150,7 @@ export class HdfsFileSource implements IFileSource {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.client.readdir(path, (error, files) => {
|
||||
if (error) {
|
||||
reject(error.message);
|
||||
reject(error);
|
||||
} else {
|
||||
let hdfsFiles: IFile[] = files.map(file => {
|
||||
let hdfsFile = <IHdfsFileStatus> file;
|
||||
|
||||
@@ -136,7 +136,7 @@ export class FolderNode extends HdfsFileSourceNode {
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
this.children = [ErrorNode.create(localize('errorExpanding', 'Error: {0}', utils.getErrorMessage(error)), this)];
|
||||
this.children = [ErrorNode.create(localize('errorExpanding', 'Error: {0}', utils.getErrorMessage(error)), this, error.statusCode)];
|
||||
}
|
||||
}
|
||||
return this.children;
|
||||
@@ -342,9 +342,12 @@ export class ErrorNode extends TreeNode {
|
||||
super();
|
||||
}
|
||||
|
||||
public static create(message: string, parent: TreeNode): ErrorNode {
|
||||
public static create(message: string, parent: TreeNode, errorCode?: number): ErrorNode {
|
||||
let node = new ErrorNode(message);
|
||||
node.parent = parent;
|
||||
if(errorCode){
|
||||
node.errorStatusCode = errorCode;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import { AppContext } from '../appContext';
|
||||
import * as constants from '../constants';
|
||||
import * as SqlClusterLookUp from '../sqlClusterLookUp';
|
||||
import { ICommandObjectExplorerContext } from './command';
|
||||
import { IPrompter, IQuestion, QuestionTypes } from '../prompts/question';
|
||||
|
||||
export const mssqlOutputChannel = vscode.window.createOutputChannel(constants.providerId);
|
||||
|
||||
@@ -28,7 +29,7 @@ export class MssqlObjectExplorerNodeProvider extends ProviderBase implements azd
|
||||
private sessionMap: Map<string, SqlClusterSession>;
|
||||
private expandCompleteEmitter = new vscode.EventEmitter<azdata.ObjectExplorerExpandInfo>();
|
||||
|
||||
constructor(private appContext: AppContext) {
|
||||
constructor(private prompter: IPrompter, private appContext: AppContext) {
|
||||
super();
|
||||
this.sessionMap = new Map<string, SqlClusterSession>();
|
||||
this.appContext.registerService<MssqlObjectExplorerNodeProvider>(constants.ObjectExplorerService, this);
|
||||
@@ -95,6 +96,13 @@ export class MssqlObjectExplorerNodeProvider extends ProviderBase implements azd
|
||||
return true;
|
||||
}
|
||||
|
||||
private hasExpansionError(children: TreeNode[]): boolean {
|
||||
if(children.find(c => c.errorStatusCode > 0)){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private async startExpansion(session: SqlClusterSession, nodeInfo: azdata.ExpandNodeInfo, isRefresh: boolean = false): Promise<void> {
|
||||
let expandResult: azdata.ObjectExplorerExpandInfo = {
|
||||
sessionId: session.sessionId,
|
||||
@@ -107,16 +115,26 @@ export class MssqlObjectExplorerNodeProvider extends ProviderBase implements azd
|
||||
if (node) {
|
||||
expandResult.errorMessage = node.getNodeInfo().errorMessage;
|
||||
let children = await node.getChildren(true);
|
||||
if (children) {
|
||||
expandResult.nodes = children.map(c => c.getNodeInfo());
|
||||
// There is only child returned when failure happens
|
||||
if (children.length === 1) {
|
||||
let child = children[0].getNodeInfo();
|
||||
if (child && child.nodeType === constants.MssqlClusterItems.Error) {
|
||||
expandResult.errorMessage = child.label;
|
||||
expandResult.nodes = [];
|
||||
if (children && children.length > 0) {
|
||||
// Only child returned when failure happens : When failed with 'Unauthorized' error, prompt for password.
|
||||
if (children.length === 1 && this.hasExpansionError(children)) {
|
||||
if (children[0].errorStatusCode === 401) {
|
||||
//Prompt for password
|
||||
let password: string = await this.promptPassword(localize('prmptPwd', 'Please provide the password to connect to HDFS:'));
|
||||
if (password && password.length > 0) {
|
||||
session.sqlClusterConnection.updatePassword(password);
|
||||
node.updateFileSource(session.sqlClusterConnection);
|
||||
children = await node.getChildren(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expandResult.nodes = children.map(c => c.getNodeInfo());
|
||||
if (children.length === 1 && this.hasExpansionError(children)) {
|
||||
let child = children[0].getNodeInfo();
|
||||
expandResult.errorMessage = child ? child.label : 'Unknown Error';
|
||||
expandResult.nodes = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -125,6 +143,15 @@ export class MssqlObjectExplorerNodeProvider extends ProviderBase implements azd
|
||||
this.expandCompleteEmitter.fire(expandResult);
|
||||
}
|
||||
|
||||
private async promptPassword(promptMsg: string): Promise<string> {
|
||||
return await this.prompter.promptSingle(<IQuestion>{
|
||||
type: QuestionTypes.password,
|
||||
name: 'passwordPrompt',
|
||||
message: promptMsg,
|
||||
default: ''
|
||||
}).then(confirmed => <string>confirmed);
|
||||
}
|
||||
|
||||
refreshNode(nodeInfo: azdata.ExpandNodeInfo): Thenable<boolean> {
|
||||
// TODO #3815 implement properly
|
||||
return this.expandNode(nodeInfo, true);
|
||||
|
||||
@@ -8,11 +8,15 @@
|
||||
import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import { ITreeNode } from './types';
|
||||
import { IFileSource } from './fileSources';
|
||||
import { SqlClusterConnection } from './connection';
|
||||
|
||||
type TreeNodePredicate = (node: TreeNode) => boolean;
|
||||
|
||||
export abstract class TreeNode implements ITreeNode {
|
||||
private _parent: TreeNode = undefined;
|
||||
protected fileSource: IFileSource;
|
||||
private _errorStatusCode: number;
|
||||
|
||||
public get parent(): TreeNode {
|
||||
return this._parent;
|
||||
@@ -22,6 +26,14 @@ export abstract class TreeNode implements ITreeNode {
|
||||
this._parent = node;
|
||||
}
|
||||
|
||||
public get errorStatusCode(): number {
|
||||
return this._errorStatusCode;
|
||||
}
|
||||
|
||||
public set errorStatusCode(error: number) {
|
||||
this._errorStatusCode = error;
|
||||
}
|
||||
|
||||
public generateNodePath(): string {
|
||||
let path = undefined;
|
||||
if (this.parent) {
|
||||
@@ -66,6 +78,9 @@ export abstract class TreeNode implements ITreeNode {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public updateFileSource(connection: SqlClusterConnection): void{
|
||||
this.fileSource = connection.createHdfsFileSource();
|
||||
}
|
||||
/**
|
||||
* The value to use for this node in the node path
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user