Open cluster dashboard from SQL Dashboard (#7783)

* Open cluster dashboard

* Remove old translated strings and update var name

* Add exported auth type

* Add newline

* PR feedback
This commit is contained in:
Charles Gagnon
2019-10-18 17:35:47 -07:00
committed by GitHub
parent 203ff3872f
commit ab31a7b964
18 changed files with 39 additions and 80 deletions

View File

@@ -3,8 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
'use strict';
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { ClusterController } from '../controller/clusterControllerApi'; import { ClusterController } from '../controller/clusterControllerApi';
@@ -12,6 +10,8 @@ import { EndpointModel, BdcStatusModel } from '../controller/apiGenerated';
import { showErrorMessage, Endpoint } from '../utils'; import { showErrorMessage, Endpoint } from '../utils';
import { AuthType } from '../constants'; import { AuthType } from '../constants';
export type BdcDashboardOptions = { url: string, auth: AuthType, username: string, password: string };
export class BdcDashboardModel { export class BdcDashboardModel {
private _clusterController: ClusterController; private _clusterController: ClusterController;
@@ -24,8 +24,8 @@ export class BdcDashboardModel {
public onDidUpdateEndpoints = this._onDidUpdateEndpoints.event; public onDidUpdateEndpoints = this._onDidUpdateEndpoints.event;
public onDidUpdateBdcStatus = this._onDidUpdateBdcStatus.event; public onDidUpdateBdcStatus = this._onDidUpdateBdcStatus.event;
constructor(url: string, auth: AuthType, username: string, private password: string, ignoreSslVerification = true) { constructor(private options: BdcDashboardOptions, ignoreSslVerification = true) {
this._clusterController = new ClusterController(url, auth, username, password, ignoreSslVerification); this._clusterController = new ClusterController(options.url, options.auth, options.username, options.password, ignoreSslVerification);
this.refresh(); this.refresh();
} }
@@ -81,7 +81,7 @@ export class BdcDashboardModel {
serverName: sqlServerMasterEndpoint.endpoint, serverName: sqlServerMasterEndpoint.endpoint,
databaseName: undefined, databaseName: undefined,
userName: 'sa', userName: 'sa',
password: this.password, password: this.options.password,
authenticationType: '', authenticationType: '',
savePassword: true, savePassword: true,
groupFullName: undefined, groupFullName: undefined,

View File

@@ -14,7 +14,7 @@ import { TreeNode } from './bigDataCluster/tree/treeNode';
import { AddControllerDialogModel, AddControllerDialog } from './bigDataCluster/dialog/addControllerDialog'; import { AddControllerDialogModel, AddControllerDialog } from './bigDataCluster/dialog/addControllerDialog';
import { ControllerNode } from './bigDataCluster/tree/controllerTreeNode'; import { ControllerNode } from './bigDataCluster/tree/controllerTreeNode';
import { BdcDashboard } from './bigDataCluster/dialog/bdcDashboard'; import { BdcDashboard } from './bigDataCluster/dialog/bdcDashboard';
import { BdcDashboardModel } from './bigDataCluster/dialog/bdcDashboardModel'; import { BdcDashboardModel, BdcDashboardOptions } from './bigDataCluster/dialog/bdcDashboardModel';
import { MountHdfsDialogModel as MountHdfsModel, MountHdfsProperties, MountHdfsDialog, DeleteMountDialog, DeleteMountModel, RefreshMountDialog, RefreshMountModel } from './bigDataCluster/dialog/mountHdfsDialog'; import { MountHdfsDialogModel as MountHdfsModel, MountHdfsProperties, MountHdfsDialog, DeleteMountDialog, DeleteMountModel, RefreshMountDialog, RefreshMountModel } from './bigDataCluster/dialog/mountHdfsDialog';
import { getControllerEndpoint } from './bigDataCluster/utils'; import { getControllerEndpoint } from './bigDataCluster/utils';
@@ -62,9 +62,9 @@ function registerCommands(context: vscode.ExtensionContext, treeDataProvider: Co
treeDataProvider.notifyNodeChanged(node); treeDataProvider.notifyNodeChanged(node);
}); });
vscode.commands.registerCommand(ManageControllerCommand, async (node: ControllerNode) => { vscode.commands.registerCommand(ManageControllerCommand, async (info: ControllerNode | BdcDashboardOptions) => {
const title: string = `${localize('bdc.dashboard.title', "Big Data Cluster Dashboard -")} ${ControllerNode.toIpAndPort(node.url)}`; const title: string = `${localize('bdc.dashboard.title', "Big Data Cluster Dashboard -")} ${ControllerNode.toIpAndPort(info.url)}`;
const dashboard: BdcDashboard = new BdcDashboard(title, new BdcDashboardModel(node.url, node.auth, node.username, node.password)); const dashboard: BdcDashboard = new BdcDashboard(title, new BdcDashboardModel(info));
dashboard.showDashboard(); dashboard.showDashboard();
}); });

View File

@@ -77,8 +77,8 @@
} }
}, },
{ {
"command": "mssqlCluster.task.openClusterStatusNotebook", "command": "mssqlCluster.task.openClusterDashboard",
"title": "%title.openClusterStatusNotebook%", "title": "%title.openClusterDashboard%",
"icon": { "icon": {
"dark": "resources/dark/cluster_status_inverse.svg", "dark": "resources/dark/cluster_status_inverse.svg",
"light": "resources/light/cluster_status.svg" "light": "resources/light/cluster_status.svg"
@@ -251,7 +251,7 @@
"when": "false" "when": "false"
}, },
{ {
"command": "mssqlCluster.task.openClusterStatusNotebook", "command": "mssqlCluster.task.openClusterDashboard",
"when": "false" "when": "false"
} }
], ],
@@ -417,7 +417,7 @@
"mssqlCluster.task.newNotebook", "mssqlCluster.task.newNotebook",
"mssqlCluster.task.openNotebook", "mssqlCluster.task.openNotebook",
"mssqlCluster.livy.task.submitSparkJob", "mssqlCluster.livy.task.submitSparkJob",
"mssqlCluster.task.openClusterStatusNotebook" "mssqlCluster.task.openClusterDashboard"
] ]
} }
}, },

View File

@@ -26,7 +26,7 @@
"title.tasks": "Tasks", "title.tasks": "Tasks",
"title.installPackages": "Install Packages", "title.installPackages": "Install Packages",
"title.configurePython": "Configure Python for Notebooks", "title.configurePython": "Configure Python for Notebooks",
"title.openClusterStatusNotebook": "Cluster Status", "title.openClusterDashboard": "Cluster\nDashboard",
"title.searchServers": "Search: Servers", "title.searchServers": "Search: Servers",
"title.clearSearchServerResult": "Search: Clear Search Server Results", "title.clearSearchServerResult": "Search: Clear Search Server Results",

View File

@@ -64,7 +64,7 @@ export enum MssqlClusterItemsSubType {
// SPARK JOB SUBMISSION ////////////////////////////////////////////////////////// // SPARK JOB SUBMISSION //////////////////////////////////////////////////////////
export const mssqlClusterNewNotebookTask = 'mssqlCluster.task.newNotebook'; export const mssqlClusterNewNotebookTask = 'mssqlCluster.task.newNotebook';
export const mssqlClusterOpenNotebookTask = 'mssqlCluster.task.openNotebook'; export const mssqlClusterOpenNotebookTask = 'mssqlCluster.task.openNotebook';
export const mssqlopenClusterStatusNotebook = 'mssqlCluster.task.openClusterStatusNotebook'; export const mssqlOpenClusterDashboard = 'mssqlCluster.task.openClusterDashboard';
export const mssqlClusterLivySubmitSparkJobCommand = 'mssqlCluster.livy.cmd.submitSparkJob'; export const mssqlClusterLivySubmitSparkJobCommand = 'mssqlCluster.livy.cmd.submitSparkJob';
export const mssqlClusterLivySubmitSparkJobFromFileCommand = 'mssqlCluster.livy.cmd.submitFileToSparkJob'; export const mssqlClusterLivySubmitSparkJobFromFileCommand = 'mssqlCluster.livy.cmd.submitFileToSparkJob';
export const mssqlClusterLivySubmitSparkJobTask = 'mssqlCluster.livy.task.submitSparkJob'; export const mssqlClusterLivySubmitSparkJobTask = 'mssqlCluster.livy.task.submitSparkJob';

View File

@@ -22,11 +22,11 @@ import { OpenSparkYarnHistoryTask } from './sparkFeature/historyTask';
import { MssqlObjectExplorerNodeProvider, mssqlOutputChannel } from './objectExplorerNodeProvider/objectExplorerNodeProvider'; import { MssqlObjectExplorerNodeProvider, mssqlOutputChannel } from './objectExplorerNodeProvider/objectExplorerNodeProvider';
import { registerSearchServerCommand } from './objectExplorerNodeProvider/command'; import { registerSearchServerCommand } from './objectExplorerNodeProvider/command';
import { MssqlIconProvider } from './iconProvider'; import { MssqlIconProvider } from './iconProvider';
import { registerServiceEndpoints } from './dashboard/serviceEndpoints'; import { registerServiceEndpoints, Endpoint } from './dashboard/serviceEndpoints';
import { getBookExtensionContributions } from './dashboard/bookExtensions'; import { getBookExtensionContributions } from './dashboard/bookExtensions';
import { registerBooksWidget } from './dashboard/bookWidget'; import { registerBooksWidget } from './dashboard/bookWidget';
import { createMssqlApi } from './mssqlApiFactory'; import { createMssqlApi } from './mssqlApiFactory';
import { AuthType } from './util/auth';
import { SqlToolsServer } from './sqlToolsServer'; import { SqlToolsServer } from './sqlToolsServer';
import { promises as fs } from 'fs'; import { promises as fs } from 'fs';
import { IconPathHelper } from './iconHelper'; import { IconPathHelper } from './iconHelper';
@@ -131,8 +131,8 @@ function activateNotebookTask(appContext: AppContext): void {
apiWrapper.registerTaskHandler(Constants.mssqlClusterOpenNotebookTask, (profile: azdata.IConnectionProfile) => { apiWrapper.registerTaskHandler(Constants.mssqlClusterOpenNotebookTask, (profile: azdata.IConnectionProfile) => {
return handleOpenNotebookTask(profile); return handleOpenNotebookTask(profile);
}); });
apiWrapper.registerTaskHandler(Constants.mssqlopenClusterStatusNotebook, (profile: azdata.IConnectionProfile) => { apiWrapper.registerTaskHandler(Constants.mssqlOpenClusterDashboard, (profile: azdata.IConnectionProfile) => {
return handleOpenClusterStatusNotebookTask(profile, appContext); return handleOpenClusterDashboardTask(profile, appContext);
}); });
} }
@@ -203,24 +203,21 @@ async function handleOpenNotebookTask(profile: azdata.IConnectionProfile): Promi
} }
} }
async function handleOpenClusterStatusNotebookTask(profile: azdata.IConnectionProfile, appContext: AppContext): Promise<void> { async function handleOpenClusterDashboardTask(profile: azdata.IConnectionProfile, appContext: AppContext): Promise<void> {
const notebookRelativePath: string = 'notebooks/tsg/cluster-status.ipynb'; const serverInfo = await azdata.connection.getServerInfo(profile.id);
const notebookFullPath: string = path.join(appContext.extensionContext.extensionPath, notebookRelativePath); const controller = Utils.getClusterEndpoints(serverInfo).find(e => e.serviceName === Endpoint.controller);
if (!(await Utils.exists(notebookFullPath))) { if (!controller) {
vscode.window.showErrorMessage(localize("fileNotFound", "Unable to find the file specified")); appContext.apiWrapper.showErrorMessage(localize('noController', "Could not find the controller endpoint for this instance"));
} else { return;
const title: string = Utils.findNextUntitledEditorName(notebookFullPath);
const untitledFileName: vscode.Uri = vscode.Uri.parse(`untitled:${title}`);
vscode.workspace.openTextDocument(notebookFullPath).then((document) => {
let initialContent = document.getText();
azdata.nb.showNotebookDocument(untitledFileName, {
connectionProfile: profile,
preview: true,
initialContent: initialContent,
initialDirtyState: false
});
});
} }
appContext.apiWrapper.executeCommand('bigDataClusters.command.manageController',
{
url: controller.endpoint,
auth: profile.authenticationType === 'Integrated' ? AuthType.Integrated : AuthType.Basic,
username: 'admin', // Default to admin as a best-guess, we'll prompt for re-entering credentials if that fails
password: profile.password
});
} }
// this method is called when your extension is deactivated // this method is called when your extension is deactivated

View File

@@ -5,6 +5,11 @@
import * as kerberos from 'kerberos'; import * as kerberos from 'kerberos';
export enum AuthType {
Integrated = 'integrated',
Basic = 'basic'
}
export async function authenticateKerberos(hostname: string): Promise<string> { export async function authenticateKerberos(hostname: string): Promise<string> {
const service = 'HTTP' + (process.platform === 'win32' ? '/' : '@') + hostname; const service = 'HTTP' + (process.platform === 'win32' ? '/' : '@') + hostname;
const mechOID = kerberos.GSS_MECH_OID_KRB5; const mechOID = kerberos.GSS_MECH_OID_KRB5;

View File

@@ -94,10 +94,6 @@
<source xml:lang="en">Configure Python for Notebooks</source> <source xml:lang="en">Configure Python for Notebooks</source>
<target state="translated">Python für Notebooks konfigurieren</target> <target state="translated">Python für Notebooks konfigurieren</target>
</trans-unit> </trans-unit>
<trans-unit id="title.openClusterStatusNotebook">
<source xml:lang="en">Cluster Status</source>
<target state="translated">Clusterstatus</target>
</trans-unit>
<trans-unit id="title.searchServers"> <trans-unit id="title.searchServers">
<source xml:lang="en">Search: Servers</source> <source xml:lang="en">Search: Servers</source>
<target state="translated">Suche: Server</target> <target state="translated">Suche: Server</target>

View File

@@ -73,9 +73,6 @@
<trans-unit id="title.configurePython"> <trans-unit id="title.configurePython">
<source xml:lang="en">Configure Python for Notebooks</source> <source xml:lang="en">Configure Python for Notebooks</source>
</trans-unit> </trans-unit>
<trans-unit id="title.openClusterStatusNotebook">
<source xml:lang="en">Cluster Status</source>
</trans-unit>
<trans-unit id="title.searchServers"> <trans-unit id="title.searchServers">
<source xml:lang="en">Search: Servers</source> <source xml:lang="en">Search: Servers</source>
</trans-unit> </trans-unit>

View File

@@ -94,10 +94,6 @@
<source xml:lang="en">Configure Python for Notebooks</source> <source xml:lang="en">Configure Python for Notebooks</source>
<target state="translated">Configurar Python para Notebooks</target> <target state="translated">Configurar Python para Notebooks</target>
</trans-unit> </trans-unit>
<trans-unit id="title.openClusterStatusNotebook">
<source xml:lang="en">Cluster Status</source>
<target state="translated">Estado del clúster</target>
</trans-unit>
<trans-unit id="title.searchServers"> <trans-unit id="title.searchServers">
<source xml:lang="en">Search: Servers</source> <source xml:lang="en">Search: Servers</source>
<target state="translated">Buscar: Servidores</target> <target state="translated">Buscar: Servidores</target>

View File

@@ -94,10 +94,6 @@
<source xml:lang="en">Configure Python for Notebooks</source> <source xml:lang="en">Configure Python for Notebooks</source>
<target state="translated">Configurer Python pour Notebooks</target> <target state="translated">Configurer Python pour Notebooks</target>
</trans-unit> </trans-unit>
<trans-unit id="title.openClusterStatusNotebook">
<source xml:lang="en">Cluster Status</source>
<target state="translated">État du cluster</target>
</trans-unit>
<trans-unit id="title.searchServers"> <trans-unit id="title.searchServers">
<source xml:lang="en">Search: Servers</source> <source xml:lang="en">Search: Servers</source>
<target state="translated">Recherche : Serveurs</target> <target state="translated">Recherche : Serveurs</target>

View File

@@ -94,10 +94,6 @@
<source xml:lang="en">Configure Python for Notebooks</source> <source xml:lang="en">Configure Python for Notebooks</source>
<target state="translated">Configura Python per Notebooks</target> <target state="translated">Configura Python per Notebooks</target>
</trans-unit> </trans-unit>
<trans-unit id="title.openClusterStatusNotebook">
<source xml:lang="en">Cluster Status</source>
<target state="translated">Stato cluster</target>
</trans-unit>
<trans-unit id="title.searchServers"> <trans-unit id="title.searchServers">
<source xml:lang="en">Search: Servers</source> <source xml:lang="en">Search: Servers</source>
<target state="translated">Ricerca: Server</target> <target state="translated">Ricerca: Server</target>

View File

@@ -94,10 +94,6 @@
<source xml:lang="en">Configure Python for Notebooks</source> <source xml:lang="en">Configure Python for Notebooks</source>
<target state="translated">ノートブック用 Python の構成</target> <target state="translated">ノートブック用 Python の構成</target>
</trans-unit> </trans-unit>
<trans-unit id="title.openClusterStatusNotebook">
<source xml:lang="en">Cluster Status</source>
<target state="translated">クラスター状態</target>
</trans-unit>
<trans-unit id="title.searchServers"> <trans-unit id="title.searchServers">
<source xml:lang="en">Search: Servers</source> <source xml:lang="en">Search: Servers</source>
<target state="translated">検索: サーバー</target> <target state="translated">検索: サーバー</target>

View File

@@ -94,10 +94,6 @@
<source xml:lang="en">Configure Python for Notebooks</source> <source xml:lang="en">Configure Python for Notebooks</source>
<target state="translated">노트북용 Python 구성</target> <target state="translated">노트북용 Python 구성</target>
</trans-unit> </trans-unit>
<trans-unit id="title.openClusterStatusNotebook">
<source xml:lang="en">Cluster Status</source>
<target state="translated">클러스터 상태</target>
</trans-unit>
<trans-unit id="title.searchServers"> <trans-unit id="title.searchServers">
<source xml:lang="en">Search: Servers</source> <source xml:lang="en">Search: Servers</source>
<target state="translated">검색: 서버</target> <target state="translated">검색: 서버</target>

View File

@@ -94,10 +94,6 @@
<source xml:lang="en">Configure Python for Notebooks</source> <source xml:lang="en">Configure Python for Notebooks</source>
<target state="translated">Configurar o Python para notebooks</target> <target state="translated">Configurar o Python para notebooks</target>
</trans-unit> </trans-unit>
<trans-unit id="title.openClusterStatusNotebook">
<source xml:lang="en">Cluster Status</source>
<target state="translated">Status do cluster</target>
</trans-unit>
<trans-unit id="title.searchServers"> <trans-unit id="title.searchServers">
<source xml:lang="en">Search: Servers</source> <source xml:lang="en">Search: Servers</source>
<target state="translated">Pesquisa: servidores</target> <target state="translated">Pesquisa: servidores</target>

View File

@@ -94,10 +94,6 @@
<source xml:lang="en">Configure Python for Notebooks</source> <source xml:lang="en">Configure Python for Notebooks</source>
<target state="translated">Настройка Python для Записных книжек</target> <target state="translated">Настройка Python для Записных книжек</target>
</trans-unit> </trans-unit>
<trans-unit id="title.openClusterStatusNotebook">
<source xml:lang="en">Cluster Status</source>
<target state="translated">Состояние кластера</target>
</trans-unit>
<trans-unit id="title.searchServers"> <trans-unit id="title.searchServers">
<source xml:lang="en">Search: Servers</source> <source xml:lang="en">Search: Servers</source>
<target state="translated">Поиск: Серверы</target> <target state="translated">Поиск: Серверы</target>

View File

@@ -94,10 +94,6 @@
<source xml:lang="en">Configure Python for Notebooks</source> <source xml:lang="en">Configure Python for Notebooks</source>
<target state="translated">为笔记本配置 Python</target> <target state="translated">为笔记本配置 Python</target>
</trans-unit> </trans-unit>
<trans-unit id="title.openClusterStatusNotebook">
<source xml:lang="en">Cluster Status</source>
<target state="translated">群集状态</target>
</trans-unit>
<trans-unit id="title.searchServers"> <trans-unit id="title.searchServers">
<source xml:lang="en">Search: Servers</source> <source xml:lang="en">Search: Servers</source>
<target state="translated">搜索: 服务器</target> <target state="translated">搜索: 服务器</target>

View File

@@ -94,10 +94,6 @@
<source xml:lang="en">Configure Python for Notebooks</source> <source xml:lang="en">Configure Python for Notebooks</source>
<target state="translated">為 Notebooks 設定 Python</target> <target state="translated">為 Notebooks 設定 Python</target>
</trans-unit> </trans-unit>
<trans-unit id="title.openClusterStatusNotebook">
<source xml:lang="en">Cluster Status</source>
<target state="translated">叢集狀態</target>
</trans-unit>
<trans-unit id="title.searchServers"> <trans-unit id="title.searchServers">
<source xml:lang="en">Search: Servers</source> <source xml:lang="en">Search: Servers</source>
<target state="translated">搜尋: 伺服器</target> <target state="translated">搜尋: 伺服器</target>