Fix HDFS support for CU5+ BDC instances (#10577)

* Fix HDFS node auth for non-root username

* more changes
This commit is contained in:
Charles Gagnon
2020-05-27 10:17:28 -07:00
committed by GitHub
parent e8dc0d15b7
commit f568ff82d8
17 changed files with 153 additions and 53 deletions

View File

@@ -0,0 +1,17 @@
declare module 'bdc' {
export const enum constants {
extensionName = 'Microsoft.big-data-cluster'
}
export interface IExtension {
getClusterController(url: string, authType: AuthType, username?: string, password?: string): IClusterController;
}
export type AuthType = 'integrated' | 'basic';
export interface IClusterController {
getClusterConfig(): Promise<any>;
getKnoxUsername(clusterUsername: string): Promise<string>;
}
}

View File

@@ -74,7 +74,5 @@ export namespace cssStyles {
export const errorText = { ...text, 'color': 'red' };
}
export type AuthType = 'integrated' | 'basic';
export const clusterEndpointsProperty = 'clusterEndpoints';
export const controllerEndpointName = 'controller';

View File

@@ -859,22 +859,12 @@ export class BdcRouterApi {
* @param connection
* @param {*} [options] Override http request options.
*/
public getCluster (xRequestId: string, connection: string, options: any = {}) : Promise<{ response: http.IncomingMessage; body: any; }> {
public getCluster (xRequestId?: string, connection?: string, options: any = {}) : Promise<{ response: http.IncomingMessage; body: any; }> {
const localVarPath = this.basePath + '/api/v1/bdc/';
let localVarQueryParameters: any = {};
let localVarHeaderParams: any = (<any>Object).assign({}, this.defaultHeaders);
let localVarFormParams: any = {};
// verify required parameter 'xRequestId' is not null or undefined
if (xRequestId === null || xRequestId === undefined) {
throw new Error('Required parameter xRequestId was null or undefined when calling getCluster.');
}
// verify required parameter 'connection' is not null or undefined
if (connection === null || connection === undefined) {
throw new Error('Required parameter connection was null or undefined when calling getCluster.');
}
localVarHeaderParams['X-Request-Id'] = ObjectSerializer.serialize(xRequestId, "string");
localVarHeaderParams['Connection'] = ObjectSerializer.serialize(connection, "string");
(<any>Object).assign(localVarHeaderParams, options.headers);

View File

@@ -7,13 +7,15 @@ import * as request from 'request';
import { authenticateKerberos, getHostAndPortFromEndpoint } from '../auth';
import { BdcRouterApi, Authentication, EndpointModel, BdcStatusModel, DefaultApi } from './apiGenerated';
import { TokenRouterApi } from './clusterApiGenerated2';
import { AuthType } from '../constants';
import * as nls from 'vscode-nls';
import { ConnectControllerDialog, ConnectControllerModel } from '../dialog/connectControllerDialog';
import { getIgnoreSslVerificationConfigSetting } from '../utils';
import { IClusterController, AuthType } from 'bdc';
const localize = nls.loadMessageBundle();
const DEFAULT_KNOX_USERNAME = 'root';
class SslAuth implements Authentication {
constructor() { }
@@ -84,7 +86,7 @@ class DefaultApiWrapper extends DefaultApi {
}
}
export class ClusterController {
export class ClusterController implements IClusterController {
private _authPromise: Promise<Authentication>;
private _url: string;
@@ -171,6 +173,42 @@ export class ClusterController {
}
}
public async getKnoxUsername(sqlLogin: string): Promise<string> {
try {
// This all is necessary because prior to CU5 BDC deployments all had the same default username for
// accessing the Knox gateway. But in the allowRunAsRoot setting was added and defaulted to false - so
// if that exists and is false then we use the username instead.
// Note that the SQL username may not necessarily be correct here either - but currently this is what
// we're requiring to run Notebooks in a BDC
const config = await this.getClusterConfig();
return config.spec?.spec?.security?.allowRunAsRoot === false ? sqlLogin : DEFAULT_KNOX_USERNAME;
} catch (err) {
console.log(`Unexpected error fetching cluster config for getKnoxUsername ${err}`);
// Optimistically fall back to SQL login since root shouldn't be typically used going forward
return sqlLogin;
}
}
public async getClusterConfig(promptConnect: boolean = false): Promise<any> {
return await this.withConnectRetry<IEndPointsResponse>(
this.getClusterConfigImpl,
promptConnect,
localize('bdc.error.getClusterConfig', "Error retrieving cluster config from {0}", this._url));
}
private async getClusterConfigImpl(self: ClusterController): Promise<any> {
let auth = await self._authPromise;
let endPointApi = new BdcApiWrapper(self._username, self._password, self._url, auth);
let options: any = {};
let result = await endPointApi.getCluster(options);
return {
response: result.response as IHttpResponse,
spec: JSON.parse(result.body.spec)
};
}
public async getEndPoints(promptConnect: boolean = false): Promise<IEndPointsResponse> {
return await this.withConnectRetry<IEndPointsResponse>(
this.getEndpointsImpl,

View File

@@ -7,11 +7,11 @@ import * as azdata from 'azdata';
import * as vscode from 'vscode';
import { ClusterController, ControllerError } from '../controller/clusterControllerApi';
import { ControllerTreeDataProvider } from '../tree/controllerTreeDataProvider';
import { AuthType } from '../constants';
import { BdcDashboardOptions } from './bdcDashboardModel';
import { ControllerNode } from '../tree/controllerTreeNode';
import { ManageControllerCommand } from '../../commands';
import * as loc from '../localizedConstants';
import { AuthType } from 'bdc';
function getAuthCategory(name: AuthType): azdata.CategoryValue {
if (name === 'basic') {

View File

@@ -8,9 +8,9 @@ import * as vscode from 'vscode';
import { ClusterController } from '../controller/clusterControllerApi';
import { EndpointModel, BdcStatusModel } from '../controller/apiGenerated';
import { Endpoint, Service } from '../utils';
import { AuthType } from '../constants';
import { ConnectControllerDialog, ConnectControllerModel } from './connectControllerDialog';
import { ControllerTreeDataProvider } from '../tree/controllerTreeDataProvider';
import { AuthType } from 'bdc';
export type BdcDashboardOptions = { url: string, auth: AuthType, username: string, password: string, rememberPassword: boolean };

View File

@@ -5,9 +5,9 @@
import * as azdata from 'azdata';
import { ClusterController, ControllerError, IEndPointsResponse } from '../controller/clusterControllerApi';
import { AuthType } from '../constants';
import { Deferred } from '../../common/promise';
import * as loc from '../localizedConstants';
import { AuthType } from 'bdc';
function getAuthCategory(name: AuthType): azdata.CategoryValue {
if (name === 'basic') {

View File

@@ -12,7 +12,7 @@ import { AddControllerNode } from './addControllerNode';
import { ControllerRootNode, ControllerNode } from './controllerTreeNode';
import { showErrorMessage } from '../utils';
import { LoadingControllerNode } from './loadingControllerNode';
import { AuthType } from '../constants';
import { AuthType } from 'bdc';
const localize = nls.loadMessageBundle();

View File

@@ -7,7 +7,8 @@ import * as vscode from 'vscode';
import * as azdata from 'azdata';
import { IControllerTreeChangeHandler } from './controllerTreeChangeHandler';
import { TreeNode } from './treeNode';
import { IconPathHelper, BdcItemType, IconPath, AuthType } from '../constants';
import { IconPathHelper, BdcItemType, IconPath } from '../constants';
import { AuthType } from 'bdc';
abstract class ControllerTreeNode extends TreeNode {

View File

@@ -17,6 +17,8 @@ import { MountHdfsDialogModel as MountHdfsModel, MountHdfsProperties, MountHdfsD
import { getControllerEndpoint } from './bigDataCluster/utils';
import * as commands from './commands';
import { HdfsDialogCancelledError } from './bigDataCluster/dialog/hdfsDialogBase';
import { IExtension, AuthType, IClusterController } from 'bdc';
import { ClusterController } from './bigDataCluster/controller/clusterControllerApi';
const localize = nls.loadMessageBundle();
@@ -24,11 +26,16 @@ const endpointNotFoundError = localize('mount.error.endpointNotFound', "Controll
let throttleTimers: { [key: string]: any } = {};
export function activate(extensionContext: vscode.ExtensionContext) {
export function activate(extensionContext: vscode.ExtensionContext): IExtension {
IconPathHelper.setExtensionContext(extensionContext);
let treeDataProvider = new ControllerTreeDataProvider(extensionContext.globalState);
registerTreeDataProvider(treeDataProvider);
registerCommands(extensionContext, treeDataProvider);
return {
getClusterController(url: string, authType: AuthType, username?: string, password?: string): IClusterController {
return new ClusterController(url, authType, username, password);
}
};
}
export function deactivate() {