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

@@ -194,7 +194,7 @@ export function isEditorTitleFree(title: string): boolean {
return !hasTextDoc && !hasNotebookDoc;
}
export function getClusterEndpoints(serverInfo: azdata.ServerInfo): IEndpoint[] | undefined {
export function getClusterEndpoints(serverInfo: azdata.ServerInfo): IEndpoint[] {
let endpoints: RawEndpoint[] = serverInfo.options['clusterEndpoints'];
if (!endpoints || endpoints.length === 0) { return []; }

View File

@@ -16,6 +16,7 @@ const localize = nls.loadMessageBundle();
import { JupyterKernel } from './jupyterKernel';
import { Deferred } from '../common/promise';
import { JupyterServerInstallation } from './jupyterServerInstallation';
import * as bdc from 'bdc';
const configBase = {
'kernel_python_credentials': {
@@ -56,11 +57,11 @@ const configBase = {
const KNOX_ENDPOINT_SERVER = 'host';
const KNOX_ENDPOINT_PORT = 'knoxport';
const KNOX_ENDPOINT_GATEWAY = 'gateway';
const CONTROLLER_ENDPOINT = 'controller';
const SQL_PROVIDER = 'MSSQL';
const USER = 'user';
const AUTHTYPE = 'authenticationType';
const INTEGRATED_AUTH = 'integrated';
const DEFAULT_CLUSTER_USER_NAME = 'root';
export class JupyterSessionManager implements nb.SessionManager {
private _ready: Deferred<void>;
@@ -272,34 +273,50 @@ export class JupyterSession implements nb.ISession {
await fs.writeFile(configFilePath, JSON.stringify(config));
}
public async configureConnection(connection: IConnectionProfile): Promise<void> {
if (connection && connection.providerName && this.isSparkKernel(this.sessionImpl.kernel.name)) {
// TODO may need to reenable a way to get the credential
// await this._connection.getCredential();
public async configureConnection(connectionProfile: IConnectionProfile): Promise<void> {
if (connectionProfile && connectionProfile.providerName && this.isSparkKernel(this.sessionImpl.kernel.name)) {
// %_do_not_call_change_endpoint is a SparkMagic command that lets users change endpoint options,
// such as user/profile/host name/auth type
//Update server info with bigdata endpoint - Unified Connection
if (connection.providerName === SQL_PROVIDER) {
let clusterEndpoint: utils.IEndpoint = await this.getClusterEndpoint(connection.id, KNOX_ENDPOINT_GATEWAY);
if (!clusterEndpoint) {
if (connectionProfile.providerName === SQL_PROVIDER) {
const endpoints = await this.getClusterEndpoints(connectionProfile.id);
const gatewayEndpoint: utils.IEndpoint = endpoints?.find(ep => ep.serviceName.toLowerCase() === KNOX_ENDPOINT_GATEWAY);
if (!gatewayEndpoint) {
return Promise.reject(new Error(localize('connectionNotValid', "Spark kernels require a connection to a SQL Server Big Data Cluster master instance.")));
}
let hostAndPort = utils.getHostAndPortFromEndpoint(clusterEndpoint.endpoint);
connection.options[KNOX_ENDPOINT_SERVER] = hostAndPort.host;
connection.options[KNOX_ENDPOINT_PORT] = hostAndPort.port;
connection.options[USER] = DEFAULT_CLUSTER_USER_NAME;
let gatewayHostAndPort = utils.getHostAndPortFromEndpoint(gatewayEndpoint.endpoint);
connectionProfile.options[KNOX_ENDPOINT_SERVER] = gatewayHostAndPort.host;
connectionProfile.options[KNOX_ENDPOINT_PORT] = gatewayHostAndPort.port;
// root is the default username for pre-CU5 instances, so while we prefer to use the connection username
// as a default now we'll still fall back to root if it's empty for some reason. (but the calls below should
// get the actual correct value regardless)
connectionProfile.options[USER] = connectionProfile.userName || 'root';
try {
const bdcApi = <bdc.IExtension>await vscode.extensions.getExtension(bdc.constants.extensionName).activate();
const controllerEndpoint = endpoints.find(ep => ep.serviceName.toLowerCase() === CONTROLLER_ENDPOINT);
const controller = bdcApi.getClusterController(controllerEndpoint.endpoint, 'basic', connectionProfile.userName, connectionProfile.password);
connectionProfile.options[USER] = await controller.getKnoxUsername(connectionProfile.userName);
} catch (err) {
console.log(`Unexpected error getting Knox username for Spark kernel: ${err}`);
}
}
else {
connection.options[KNOX_ENDPOINT_PORT] = this.getKnoxPortOrDefault(connection);
connectionProfile.options[KNOX_ENDPOINT_PORT] = this.getKnoxPortOrDefault(connectionProfile);
}
this.setHostAndPort(':', connection);
this.setHostAndPort(',', connection);
this.setHostAndPort(':', connectionProfile);
this.setHostAndPort(',', connectionProfile);
let server = vscode.Uri.parse(utils.getLivyUrl(connection.options[KNOX_ENDPOINT_SERVER], connection.options[KNOX_ENDPOINT_PORT])).toString();
let doNotCallChangeEndpointParams = this.isIntegratedAuth(connection) ?
`%_do_not_call_change_endpoint --server=${server} --auth=Kerberos`
: `%_do_not_call_change_endpoint --username=${connection.options[USER]} --password=${connection.options['password']} --server=${server} --auth=Basic_Access`;
let server = vscode.Uri.parse(utils.getLivyUrl(connectionProfile.options[KNOX_ENDPOINT_SERVER], connectionProfile.options[KNOX_ENDPOINT_PORT])).toString();
let doNotCallChangeEndpointParams: string;
if (this.isIntegratedAuth(connectionProfile)) {
doNotCallChangeEndpointParams = `%_do_not_call_change_endpoint --server=${server} --auth=Kerberos`;
} else {
const credentials = await connection.getCredentials(connectionProfile.id);
doNotCallChangeEndpointParams = `%_do_not_call_change_endpoint --username=${connectionProfile.options[USER]} --password=${credentials.password} --server=${server} --auth=Basic_Access`;
}
let future = this.sessionImpl.kernel.requestExecute({
code: doNotCallChangeEndpointParams
}, true);
@@ -348,16 +365,12 @@ export class JupyterSession implements nb.ISession {
return port;
}
private async getClusterEndpoint(profileId: string, serviceName: string): Promise<utils.IEndpoint> {
private async getClusterEndpoints(profileId: string): Promise<utils.IEndpoint[]> {
let serverInfo: ServerInfo = await connection.getServerInfo(profileId);
if (!serverInfo || !serverInfo.options) {
return undefined;
return [];
}
let endpoints: utils.IEndpoint[] = utils.getClusterEndpoints(serverInfo);
if (!endpoints || endpoints.length === 0) {
return undefined;
}
return endpoints.find(ep => ep.serviceName.toLowerCase() === serviceName.toLowerCase());
return utils.getClusterEndpoints(serverInfo);
}
private async setEnvironmentVars(skip: boolean = false): Promise<void> {

View File

@@ -6,4 +6,5 @@
/// <reference path='../../../../src/sql/azdata.d.ts'/>
/// <reference path='../../../../src/sql/azdata.proposed.d.ts'/>
/// <reference path='../../../../src/vs/vscode.d.ts'/>
/// <reference path='../../../big-data-cluster/src/bdc.d.ts'/>
/// <reference types='@types/node'/>