mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
wizard for deploying bdc (#7183)
* wip * wip2 * wip eod 820 * wip 822 * text component improvements and misc changes * aria-label * targetClusterPage wip * target cluster page * target cluster page * wip 827 * wip deployment profile page * profile page * service settings page * wip 0903 * 0909 wip * 0910 * 0911 * sql instance and working directory * notebooks * docker version on windows * EULA env var * 917 updates * address comments * use async file access * fix the summary page display issue for ad auth * add save json file buttons * use promise for private methds * review feedbacks * refactor * pass json to notebooks * fix no tool scenario * bypass tool check if installed * update hint text * update notebooks * workaround azdata first time use * comments * accept eula and some text update * fix the error in package.json * promise instead of thenable * comments * fix typo
This commit is contained in:
59
extensions/resource-deployment/src/services/azdataService.ts
Normal file
59
extensions/resource-deployment/src/services/azdataService.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as path from 'path';
|
||||
import { IPlatformService } from './platformService';
|
||||
import { BigDataClusterDeploymentProfile } from './bigDataClusterDeploymentProfile';
|
||||
|
||||
interface BdcConfigListOutput {
|
||||
stdout: string[];
|
||||
}
|
||||
|
||||
export interface IAzdataService {
|
||||
getDeploymentProfiles(): Promise<BigDataClusterDeploymentProfile[]>;
|
||||
}
|
||||
|
||||
export class AzdataService implements IAzdataService {
|
||||
constructor(private platformService: IPlatformService) {
|
||||
}
|
||||
|
||||
public async getDeploymentProfiles(): Promise<BigDataClusterDeploymentProfile[]> {
|
||||
await this.ensureWorkingDirectoryExists();
|
||||
const profileNames = await this.getDeploymentProfileNames();
|
||||
return await Promise.all(profileNames.map(profile => this.getDeploymentProfileInfo(profile)));
|
||||
}
|
||||
|
||||
private async getDeploymentProfileNames(): Promise<string[]> {
|
||||
const env: NodeJS.ProcessEnv = {};
|
||||
// azdata requires this environment variables to be set
|
||||
env['ACCEPT_EULA'] = 'yes';
|
||||
const cmd = 'azdata bdc config list -o json';
|
||||
// Run the command twice to workaround the issue:
|
||||
// First time use of the azdata will have extra EULA related string in the output
|
||||
// there is no easy and reliable way to filter out the profile names from it.
|
||||
await this.platformService.runCommand(cmd, { additionalEnvironmentVariables: env });
|
||||
const stdout = await this.platformService.runCommand(cmd);
|
||||
const output = <BdcConfigListOutput>JSON.parse(stdout);
|
||||
return output.stdout;
|
||||
}
|
||||
|
||||
private async getDeploymentProfileInfo(profileName: string): Promise<BigDataClusterDeploymentProfile> {
|
||||
await this.platformService.runCommand(`azdata bdc config init --source ${profileName} --target ${profileName} --force`, { workingDirectory: this.platformService.storagePath() });
|
||||
const configObjects = await Promise.all([
|
||||
this.getJsonObjectFromFile(path.join(this.platformService.storagePath(), profileName, 'bdc.json')),
|
||||
this.getJsonObjectFromFile(path.join(this.platformService.storagePath(), profileName, 'control.json'))
|
||||
]);
|
||||
return new BigDataClusterDeploymentProfile(profileName, configObjects[0], configObjects[1]);
|
||||
}
|
||||
|
||||
private async ensureWorkingDirectoryExists(): Promise<void> {
|
||||
if (! await this.platformService.fileExists(this.platformService.storagePath())) {
|
||||
await this.platformService.makeDirectory(this.platformService.storagePath());
|
||||
}
|
||||
}
|
||||
|
||||
private async getJsonObjectFromFile(path: string): Promise<any> {
|
||||
return JSON.parse(await this.platformService.readTextFile(path));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export const SqlServerMasterResource = 'master';
|
||||
export const DataResource = 'data-0';
|
||||
export const HdfsResource = 'storage-0';
|
||||
export const ComputeResource = 'compute-0';
|
||||
export const NameNodeResource = 'nmnode-0';
|
||||
export const SparkHeadResource = 'sparkhead';
|
||||
export const ZooKeeperResource = 'zookeeper';
|
||||
export const SparkResource = 'spark-0';
|
||||
export const HadrEnabledSetting = 'hadr.enabled';
|
||||
|
||||
interface ServiceEndpoint {
|
||||
port: number;
|
||||
serviceType: ServiceType;
|
||||
name: EndpointName;
|
||||
}
|
||||
type ServiceType = 'NodePort' | 'LoadBalancer';
|
||||
type EndpointName = 'Controller' | 'Master' | 'Knox' | 'MasterSecondary';
|
||||
|
||||
export class BigDataClusterDeploymentProfile {
|
||||
constructor(private _profileName: string, private _bdcConfig: any, private _controlConfig: any) {
|
||||
// TODO: add validation logic for these 2 objects
|
||||
// https://github.com/microsoft/azuredatastudio/issues/7344
|
||||
}
|
||||
|
||||
public get profileName(): string {
|
||||
return this._profileName;
|
||||
}
|
||||
|
||||
public get clusterName(): string {
|
||||
return this._bdcConfig.metadata.name;
|
||||
}
|
||||
|
||||
public set clusterName(value: string) {
|
||||
this._bdcConfig.metadata.name = value;
|
||||
}
|
||||
|
||||
public get bdcConfig(): any {
|
||||
return this._bdcConfig;
|
||||
}
|
||||
|
||||
public get controlConfig(): any {
|
||||
return this._controlConfig;
|
||||
}
|
||||
|
||||
public get sqlServerReplicas(): number {
|
||||
return this.getReplicas(SqlServerMasterResource);
|
||||
}
|
||||
|
||||
public set sqlServerReplicas(replicas: number) {
|
||||
this.setReplicas(SqlServerMasterResource, replicas);
|
||||
}
|
||||
|
||||
public get hdfsNameNodeReplicas(): number {
|
||||
return this.getReplicas(NameNodeResource);
|
||||
}
|
||||
|
||||
public set hdfsNameNodeReplicas(replicas: number) {
|
||||
this.setReplicas(NameNodeResource, replicas);
|
||||
}
|
||||
|
||||
public get sparkHeadReplicas(): number {
|
||||
return this.getReplicas(SparkHeadResource);
|
||||
}
|
||||
|
||||
public set sparkHeadReplicas(replicas: number) {
|
||||
this.setReplicas(SparkHeadResource, replicas);
|
||||
}
|
||||
|
||||
public get dataReplicas(): number {
|
||||
return this.getReplicas(DataResource);
|
||||
}
|
||||
|
||||
public set dataReplicas(replicas: number) {
|
||||
this.setReplicas(SparkHeadResource, replicas);
|
||||
}
|
||||
|
||||
public get hdfsReplicas(): number {
|
||||
return this.getReplicas(HdfsResource);
|
||||
}
|
||||
|
||||
public set hdfsReplicas(replicas: number) {
|
||||
this.setReplicas(HdfsResource, replicas);
|
||||
}
|
||||
|
||||
public get zooKeeperReplicas(): number {
|
||||
return this.getReplicas(ZooKeeperResource);
|
||||
}
|
||||
|
||||
public set zooKeeperReplicas(replicas: number) {
|
||||
this.setReplicas(ZooKeeperResource, replicas);
|
||||
}
|
||||
|
||||
public get computeReplicas(): number {
|
||||
return this.getReplicas(ComputeResource);
|
||||
}
|
||||
|
||||
public set computeReplicas(replicas: number) {
|
||||
this.setReplicas(ComputeResource, replicas);
|
||||
}
|
||||
|
||||
public get sparkReplicas(): number {
|
||||
return this._bdcConfig.spec.resources[SparkResource] ? this.getReplicas(SparkResource) : 0;
|
||||
}
|
||||
|
||||
public get hadrEnabled(): boolean {
|
||||
const value = this._bdcConfig.spec.resources[SqlServerMasterResource].spec.settings.sql[HadrEnabledSetting];
|
||||
return value === true || value === 'true';
|
||||
}
|
||||
|
||||
public set hadrEnabled(value: boolean) {
|
||||
this._bdcConfig.spec.resources[SqlServerMasterResource].spec.settings.sql[HadrEnabledSetting] = value;
|
||||
}
|
||||
|
||||
public get includeSpark(): boolean {
|
||||
return <boolean>this._bdcConfig.spec.resources[HdfsResource].spec.settings.spark.includeSpark;
|
||||
}
|
||||
|
||||
public set includeSpark(value: boolean) {
|
||||
this._bdcConfig.spec.resources[HdfsResource].spec.settings.spark.includeSpark = value;
|
||||
}
|
||||
|
||||
public get controllerDataStorageClass(): string {
|
||||
return <string>this._controlConfig.spec.storage.data.className;
|
||||
}
|
||||
|
||||
public set controllerDataStorageClass(value: string) {
|
||||
this._controlConfig.spec.storage.data.className = value;
|
||||
}
|
||||
|
||||
public get controllerDataStorageSize(): number {
|
||||
return <number>this._controlConfig.spec.storage.data.size.replace('Gi', '');
|
||||
}
|
||||
|
||||
public set controllerDataStorageSize(value: number) {
|
||||
this._controlConfig.spec.storage.data.size = value;
|
||||
}
|
||||
|
||||
public get controllerLogsStorageClass(): string {
|
||||
return <string>this._controlConfig.spec.storage.logs.className;
|
||||
}
|
||||
|
||||
public set controllerLogsStorageClass(value: string) {
|
||||
this._controlConfig.spec.storage.logs.className = value;
|
||||
}
|
||||
|
||||
public get controllerLogsStorageSize(): number {
|
||||
return <number>this._controlConfig.spec.storage.logs.size.replace('Gi', '');
|
||||
}
|
||||
|
||||
public set controllerLogsStorageSize(value: number) {
|
||||
this._controlConfig.spec.storage.logs.size = value;
|
||||
}
|
||||
|
||||
public setResourceStorage(resourceName: 'data-0' | 'master' | 'storage-0', dataStorageClass: string, dataStorageSize: number, logsStorageClass: string, logsStorageSize: number) {
|
||||
this.bdcConfig.spec.resources[resourceName]['storage'] = {
|
||||
data: {
|
||||
size: `${dataStorageSize}Gi`,
|
||||
className: dataStorageClass,
|
||||
accessMode: 'ReadWriteOnce'
|
||||
},
|
||||
logs: {
|
||||
size: `${logsStorageSize}Gi`,
|
||||
className: logsStorageClass,
|
||||
accessMode: 'ReadWriteOnce'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public get controllerPort(): number {
|
||||
return this.getEndpointPort(this._controlConfig.spec.endpoints, 'Controller', 30080);
|
||||
}
|
||||
|
||||
public set controllerPort(port: number) {
|
||||
this.setEndpointPort(this._controlConfig.spec.endpoints, 'Controller', port);
|
||||
}
|
||||
|
||||
public get sqlServerPort(): number {
|
||||
return this.getEndpointPort(this._bdcConfig.spec.resources.master.spec.endpoints, 'Master', 31433);
|
||||
}
|
||||
|
||||
public set sqlServerPort(port: number) {
|
||||
this.setEndpointPort(this._bdcConfig.spec.resources.master.spec.endpoints, 'Master', port);
|
||||
}
|
||||
|
||||
public get sqlServerReadableSecondaryPort(): number {
|
||||
return this.getEndpointPort(this._bdcConfig.spec.resources.master.spec.endpoints, 'MasterSecondary', 31436);
|
||||
}
|
||||
|
||||
public set sqlServerReadableSecondaryPort(port: number) {
|
||||
this.setEndpointPort(this._bdcConfig.spec.resources.master.spec.endpoints, 'MasterSecondary', port);
|
||||
}
|
||||
|
||||
public get gatewayPort(): number {
|
||||
return this.getEndpointPort(this._bdcConfig.spec.resources.gateway.spec.endpoints, 'Knox', 30443);
|
||||
}
|
||||
|
||||
public set gatewayPort(port: number) {
|
||||
this.setEndpointPort(this._bdcConfig.spec.resources.gateway.spec.endpoints, 'Knox', port);
|
||||
}
|
||||
|
||||
public addSparkResource(replicas: number): void {
|
||||
this._bdcConfig.spec.resources[SparkResource] = {
|
||||
metadata: {
|
||||
kind: 'Pool',
|
||||
name: 'default'
|
||||
},
|
||||
spec: {
|
||||
type: 'Spark',
|
||||
replicas: replicas
|
||||
}
|
||||
};
|
||||
|
||||
this._bdcConfig.spec.services.spark.resources.push(SparkResource);
|
||||
this._bdcConfig.spec.services.hdfs.resources.push(SparkResource);
|
||||
}
|
||||
|
||||
public get activeDirectorySupported(): boolean {
|
||||
// TODO: Implement AD authentication
|
||||
return false;
|
||||
}
|
||||
|
||||
public getBdcJson(readable: boolean = true): string {
|
||||
return this.stringifyJson(this._bdcConfig, readable);
|
||||
}
|
||||
|
||||
public getControlJson(readable: boolean = true): string {
|
||||
return this.stringifyJson(this._controlConfig, readable);
|
||||
}
|
||||
|
||||
private stringifyJson(obj: any, readable: boolean): string {
|
||||
return JSON.stringify(obj, undefined, readable ? 4 : 0);
|
||||
}
|
||||
|
||||
private getReplicas(resourceName: string): number {
|
||||
return <number>this._bdcConfig.spec.resources[resourceName].spec.replicas;
|
||||
}
|
||||
|
||||
private setReplicas(resourceName: string, replicas: number): void {
|
||||
this._bdcConfig.spec.resources[resourceName].spec.replicas = replicas;
|
||||
}
|
||||
|
||||
private getEndpointPort(endpoints: ServiceEndpoint[], name: EndpointName, defaultValue: number): number {
|
||||
const endpoint = endpoints.find(endpoint => endpoint.name === name);
|
||||
return endpoint ? endpoint.port : defaultValue;
|
||||
}
|
||||
|
||||
private setEndpointPort(endpoints: ServiceEndpoint[], name: EndpointName, port: number): void {
|
||||
const endpoint = endpoints.find(endpoint => endpoint.name === name);
|
||||
if (endpoint) {
|
||||
endpoint.port = port;
|
||||
} else {
|
||||
endpoints.push({
|
||||
name: name,
|
||||
serviceType: 'NodePort',
|
||||
port: port
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
52
extensions/resource-deployment/src/services/kubeService.ts
Normal file
52
extensions/resource-deployment/src/services/kubeService.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as path from 'path';
|
||||
import * as os from 'os';
|
||||
import * as yamljs from 'yamljs';
|
||||
import * as fs from 'fs';
|
||||
|
||||
export interface KubeClusterContext {
|
||||
name: string;
|
||||
isCurrentContext: boolean;
|
||||
}
|
||||
|
||||
export interface IKubeService {
|
||||
getDefautConfigPath(): string;
|
||||
getClusterContexts(configFile: string): Promise<KubeClusterContext[]>;
|
||||
}
|
||||
|
||||
export class KubeService implements IKubeService {
|
||||
getDefautConfigPath(): string {
|
||||
return path.join(os.homedir(), '.kube', 'config');
|
||||
}
|
||||
|
||||
getClusterContexts(configFile: string): Promise<KubeClusterContext[]> {
|
||||
return fs.promises.access(configFile).catch((error) => {
|
||||
if (error && error.code === 'ENOENT') {
|
||||
return [];
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}).then(() => {
|
||||
const config = yamljs.load(configFile);
|
||||
const rawContexts = <any[]>config['contexts'];
|
||||
const currentContext = <string>config['current-context'];
|
||||
const contexts: KubeClusterContext[] = [];
|
||||
if (currentContext && rawContexts && rawContexts.length > 0) {
|
||||
rawContexts.forEach(rawContext => {
|
||||
const name = <string>rawContext['name'];
|
||||
if (name) {
|
||||
contexts.push({
|
||||
name: name,
|
||||
isCurrentContext: name === currentContext
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
return contexts;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import * as path from 'path';
|
||||
@@ -14,7 +13,7 @@ import { NotebookInfo } from '../interfaces';
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export interface INotebookService {
|
||||
launchNotebook(notebook: string | NotebookInfo): void;
|
||||
launchNotebook(notebook: string | NotebookInfo): Thenable<azdata.nb.NotebookEditor>;
|
||||
}
|
||||
|
||||
export class NotebookService implements INotebookService {
|
||||
@@ -25,18 +24,22 @@ export class NotebookService implements INotebookService {
|
||||
* Copy the notebook to the user's home directory and launch the notebook from there.
|
||||
* @param notebook the path of the notebook
|
||||
*/
|
||||
launchNotebook(notebook: string | NotebookInfo): void {
|
||||
launchNotebook(notebook: string | NotebookInfo): Thenable<azdata.nb.NotebookEditor> {
|
||||
const notebookPath = this.getNotebook(notebook);
|
||||
const notebookFullPath = path.join(this.extensionPath, notebookPath);
|
||||
if (notebookPath && this.platformService.fileExists(notebookPath)) {
|
||||
this.showNotebookAsUntitled(notebookPath);
|
||||
}
|
||||
else if (notebookPath && this.platformService.fileExists(notebookFullPath)) {
|
||||
this.showNotebookAsUntitled(notebookFullPath);
|
||||
}
|
||||
else {
|
||||
this.platformService.showErrorMessage(localize('resourceDeployment.notebookNotFound', "The notebook {0} does not exist", notebookPath));
|
||||
}
|
||||
return this.platformService.fileExists(notebookPath).then((notebookPathExists) => {
|
||||
if (notebookPathExists) {
|
||||
return this.showNotebookAsUntitled(notebookPath);
|
||||
} else {
|
||||
return this.platformService.fileExists(notebookFullPath).then(notebookFullPathExists => {
|
||||
if (notebookFullPathExists) {
|
||||
return this.showNotebookAsUntitled(notebookFullPath);
|
||||
} else {
|
||||
throw localize('resourceDeployment.notebookNotFound', "The notebook {0} does not exist", notebookPath);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,12 +77,12 @@ export class NotebookService implements INotebookService {
|
||||
return title;
|
||||
}
|
||||
|
||||
showNotebookAsUntitled(notebookPath: string): void {
|
||||
showNotebookAsUntitled(notebookPath: string): Thenable<azdata.nb.NotebookEditor> {
|
||||
let targetFileName: string = this.findNextUntitledEditorName(notebookPath);
|
||||
const untitledFileName: vscode.Uri = vscode.Uri.parse(`untitled:${targetFileName}`);
|
||||
vscode.workspace.openTextDocument(notebookPath).then((document) => {
|
||||
return vscode.workspace.openTextDocument(notebookPath).then((document) => {
|
||||
let initialContent = document.getText();
|
||||
azdata.nb.showNotebookDocument(untitledFileName, {
|
||||
return azdata.nb.showNotebookDocument(untitledFileName, {
|
||||
connectionProfile: undefined,
|
||||
preview: false,
|
||||
initialContent: initialContent,
|
||||
|
||||
@@ -2,37 +2,58 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as vscode from 'vscode';
|
||||
import * as azdata from 'azdata';
|
||||
import * as cp from 'child_process';
|
||||
|
||||
/**
|
||||
* Abstract of platform dependencies
|
||||
*/
|
||||
export interface IPlatformService {
|
||||
platform(): string;
|
||||
copyFile(source: string, target: string): void;
|
||||
fileExists(file: string): boolean;
|
||||
storagePath(): string;
|
||||
copyFile(source: string, target: string): Promise<void>;
|
||||
fileExists(file: string): Promise<boolean>;
|
||||
openFile(filePath: string): void;
|
||||
showErrorMessage(message: string): void;
|
||||
isNotebookNameUsed(title: string): boolean;
|
||||
makeDirectory(path: string): Promise<void>;
|
||||
readTextFile(filePath: string): Promise<string>;
|
||||
runCommand(command: string, options?: CommandOptions): Promise<string>;
|
||||
}
|
||||
|
||||
export interface CommandOptions {
|
||||
workingDirectory?: string;
|
||||
additionalEnvironmentVariables?: NodeJS.ProcessEnv;
|
||||
}
|
||||
|
||||
export class PlatformService implements IPlatformService {
|
||||
constructor(private _storagePath: string = '') {
|
||||
}
|
||||
|
||||
storagePath(): string {
|
||||
return this._storagePath;
|
||||
}
|
||||
|
||||
platform(): string {
|
||||
return process.platform;
|
||||
}
|
||||
|
||||
copyFile(source: string, target: string): void {
|
||||
// tslint:disable-next-line:no-sync
|
||||
fs.copyFileSync(source, target);
|
||||
copyFile(source: string, target: string): Promise<void> {
|
||||
return fs.promises.copyFile(source, target);
|
||||
}
|
||||
|
||||
fileExists(file: string): boolean {
|
||||
// tslint:disable-next-line:no-sync
|
||||
return fs.existsSync(file);
|
||||
fileExists(file: string): Promise<boolean> {
|
||||
return fs.promises.access(file).then(() => {
|
||||
return true;
|
||||
}).catch(error => {
|
||||
if (error && error.code === 'ENOENT') {
|
||||
return false;
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
openFile(filePath: string): void {
|
||||
@@ -46,4 +67,28 @@ export class PlatformService implements IPlatformService {
|
||||
isNotebookNameUsed(title: string): boolean {
|
||||
return (azdata.nb.notebookDocuments.findIndex(doc => doc.isUntitled && doc.fileName === title) > -1);
|
||||
}
|
||||
|
||||
makeDirectory(path: string): Promise<void> {
|
||||
return fs.promises.mkdir(path);
|
||||
}
|
||||
|
||||
readTextFile(filePath: string): Promise<string> {
|
||||
return fs.promises.readFile(filePath, 'utf8');
|
||||
}
|
||||
|
||||
runCommand(command: string, options?: CommandOptions): Promise<string> {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
const env = Object.assign({}, process.env, options && options.additionalEnvironmentVariables);
|
||||
cp.exec(command, {
|
||||
cwd: options && options.workingDirectory,
|
||||
env: env
|
||||
}, (error, stdout, stderror) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve(stdout);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import * as cp from 'child_process';
|
||||
@@ -16,7 +15,10 @@ import { INotebookService } from './notebookService';
|
||||
import { IPlatformService } from './platformService';
|
||||
import { IToolsService } from './toolsService';
|
||||
import { ResourceType, ResourceTypeOption, DeploymentProvider } from '../interfaces';
|
||||
import { DeployClusterWizard } from '../ui/deployClusterWizard/deployClusterWizard';
|
||||
import { NotebookInputDialog } from '../ui/notebookInputDialog';
|
||||
import { KubeService } from './kubeService';
|
||||
import { AzdataService } from './azdataService';
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export interface IResourceTypeService {
|
||||
@@ -138,7 +140,7 @@ export class ResourceTypeService implements IResourceTypeService {
|
||||
let providerIndex = 1;
|
||||
resourceType.providers.forEach(provider => {
|
||||
const providerPositionInfo = `${positionInfo}, provider index: ${providerIndex} `;
|
||||
if (!provider.dialog && !provider.notebook && !provider.downloadUrl && !provider.webPageUrl) {
|
||||
if (!provider.wizard && !provider.dialog && !provider.notebook && !provider.downloadUrl && !provider.webPageUrl) {
|
||||
errorMessages.push(`No deployment method defined for the provider, ${providerPositionInfo}`);
|
||||
}
|
||||
|
||||
@@ -195,7 +197,10 @@ export class ResourceTypeService implements IResourceTypeService {
|
||||
|
||||
public startDeployment(provider: DeploymentProvider): void {
|
||||
const self = this;
|
||||
if (provider.dialog) {
|
||||
if (provider.wizard) {
|
||||
const wizard = new DeployClusterWizard(provider.wizard, new KubeService(), new AzdataService(this.platformService), this.notebookService);
|
||||
wizard.open();
|
||||
} else if (provider.dialog) {
|
||||
const dialog = new NotebookInputDialog(this.notebookService, provider.dialog);
|
||||
dialog.open();
|
||||
} else if (provider.notebook) {
|
||||
|
||||
@@ -2,12 +2,20 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
import { ToolType, ITool } from '../../interfaces';
|
||||
|
||||
import { ToolType } from '../../interfaces';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { SemVer } from 'semver';
|
||||
import { IPlatformService } from '../platformService';
|
||||
import { EOL } from 'os';
|
||||
import { ToolBase } from './toolBase';
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class AzCliTool implements ITool {
|
||||
export class AzCliTool extends ToolBase {
|
||||
constructor(platformService: IPlatformService) {
|
||||
super(platformService);
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return 'azcli';
|
||||
}
|
||||
@@ -23,4 +31,19 @@ export class AzCliTool implements ITool {
|
||||
get displayName(): string {
|
||||
return localize('resourceDeployment.AzCLIDisplayName', 'Azure CLI');
|
||||
}
|
||||
|
||||
get homePage(): string {
|
||||
return 'https://docs.microsoft.com/cli/azure/install-azure-cli';
|
||||
}
|
||||
|
||||
protected getVersionFromOutput(output: string): SemVer | undefined {
|
||||
if (output && output.includes('azure-cli')) {
|
||||
return new SemVer(output.split(EOL)[0].replace('azure-cli', '').replace(/ /g, '').replace('*', ''));
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
protected get versionCommand(): string {
|
||||
return 'az --version';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,21 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
import { ToolType, ITool } from '../../interfaces';
|
||||
|
||||
import { ToolType } from '../../interfaces';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { SemVer } from 'semver';
|
||||
import { EOL } from 'os';
|
||||
import { IPlatformService } from '../platformService';
|
||||
import { ToolBase } from './toolBase';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class AzdataTool implements ITool {
|
||||
export class AzdataTool extends ToolBase {
|
||||
constructor(platformService: IPlatformService) {
|
||||
super(platformService);
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return 'azdata';
|
||||
}
|
||||
@@ -23,4 +32,20 @@ export class AzdataTool implements ITool {
|
||||
get displayName(): string {
|
||||
return localize('resourceDeployment.AzdataDisplayName', "azdata");
|
||||
}
|
||||
}
|
||||
|
||||
get homePage(): string {
|
||||
return 'https://docs.microsoft.com/sql/big-data-cluster/deploy-install-azdata';
|
||||
}
|
||||
|
||||
protected get versionCommand(): string {
|
||||
return 'azdata -v';
|
||||
}
|
||||
|
||||
protected getVersionFromOutput(output: string): SemVer | undefined {
|
||||
let version: SemVer | undefined = undefined;
|
||||
if (output && output.split(EOL).length > 0) {
|
||||
version = new SemVer(output.split(EOL)[0].replace(/ /g, ''));
|
||||
}
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,20 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
import { ToolType, ITool } from '../../interfaces';
|
||||
|
||||
import { ToolType } from '../../interfaces';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { SemVer } from 'semver';
|
||||
import { IPlatformService } from '../platformService';
|
||||
import { ToolBase } from './toolBase';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class DockerTool implements ITool {
|
||||
export class DockerTool extends ToolBase {
|
||||
constructor(platformService: IPlatformService) {
|
||||
super(platformService);
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return 'docker';
|
||||
}
|
||||
@@ -23,4 +31,19 @@ export class DockerTool implements ITool {
|
||||
get displayName(): string {
|
||||
return localize('resourceDeployment.DockerDisplayName', 'Docker');
|
||||
}
|
||||
}
|
||||
|
||||
get homePage(): string {
|
||||
return 'https://docs.docker.com/install';
|
||||
}
|
||||
|
||||
protected getVersionFromOutput(output: string): SemVer | undefined {
|
||||
let version: SemVer | undefined = undefined;
|
||||
if (output) {
|
||||
version = new SemVer(JSON.parse(output).Client.Version, true);
|
||||
}
|
||||
return version;
|
||||
}
|
||||
protected get versionCommand(): string {
|
||||
return 'docker version --format "{{json .}}"';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,20 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
import { ToolType, ITool } from '../../interfaces';
|
||||
|
||||
import { ToolType } from '../../interfaces';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { SemVer } from 'semver';
|
||||
import { IPlatformService } from '../platformService';
|
||||
import { ToolBase } from './toolBase';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class KubeCtlTool implements ITool {
|
||||
export class KubeCtlTool extends ToolBase {
|
||||
constructor(platformService: IPlatformService) {
|
||||
super(platformService);
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return 'kubectl';
|
||||
}
|
||||
@@ -23,4 +31,21 @@ export class KubeCtlTool implements ITool {
|
||||
get displayName(): string {
|
||||
return localize('resourceDeployment.KubeCtlDisplayName', 'kubectl');
|
||||
}
|
||||
|
||||
get homePage(): string {
|
||||
return 'https://kubernetes.io/docs/tasks/tools/install-kubectl';
|
||||
}
|
||||
|
||||
protected getVersionFromOutput(output: string): SemVer | undefined {
|
||||
let version: SemVer | undefined = undefined;
|
||||
if (output) {
|
||||
const versionJson = JSON.parse(output);
|
||||
version = new SemVer(`${versionJson.clientVersion.major}.${versionJson.clientVersion.minor}.0`);
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
protected get versionCommand(): string {
|
||||
return 'kubectl version -o json --client';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ToolType, ITool } from '../../interfaces';
|
||||
import { SemVer } from 'semver';
|
||||
import { IPlatformService } from '../platformService';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { EOL } from 'os';
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export abstract class ToolBase implements ITool {
|
||||
constructor(private _platformService: IPlatformService) { }
|
||||
|
||||
abstract name: string;
|
||||
abstract displayName: string;
|
||||
abstract description: string;
|
||||
abstract type: ToolType;
|
||||
abstract homePage: string;
|
||||
protected abstract getVersionFromOutput(output: string): SemVer | undefined;
|
||||
protected abstract readonly versionCommand: string;
|
||||
|
||||
public get version(): SemVer | undefined {
|
||||
return this._version;
|
||||
}
|
||||
|
||||
public get isInstalled(): boolean {
|
||||
return this._isInstalled;
|
||||
}
|
||||
|
||||
public get statusDescription(): string | undefined {
|
||||
return this._statusDescription;
|
||||
}
|
||||
|
||||
public loadInformation(): Promise<void> {
|
||||
if (this._isInstalled) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
this._isInstalled = false;
|
||||
this._statusDescription = undefined;
|
||||
this._version = undefined;
|
||||
this._versionOutput = undefined;
|
||||
return this._platformService.runCommand(this.versionCommand).then((stdout) => {
|
||||
this._versionOutput = stdout;
|
||||
this._version = this.getVersionFromOutput(stdout);
|
||||
if (this._version) {
|
||||
this._isInstalled = true;
|
||||
} else {
|
||||
throw localize('deployCluster.InvalidToolVersionOutput', "Invalid output received.");
|
||||
}
|
||||
}).catch((error) => {
|
||||
const errorMessage = typeof error === 'string' ? error :
|
||||
typeof error.message === 'string' ? error.message : '';
|
||||
this._statusDescription = localize('deployCluster.GetToolVersionError', "Error retrieving version information.{0}Error: {1}{0}stdout: {2} ", EOL, errorMessage, this._versionOutput);
|
||||
});
|
||||
}
|
||||
|
||||
private _isInstalled: boolean = false;
|
||||
private _version?: SemVer;
|
||||
private _statusDescription?: string;
|
||||
private _versionOutput?: string;
|
||||
}
|
||||
@@ -2,12 +2,12 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
import { ITool } from '../interfaces';
|
||||
import { DockerTool } from './tools/dockerTool';
|
||||
import { AzCliTool } from './tools/azCliTool';
|
||||
import { AzdataTool } from './tools/azdataTool';
|
||||
import { KubeCtlTool } from './tools/kubeCtlTool';
|
||||
import { IPlatformService } from './platformService';
|
||||
|
||||
export interface IToolsService {
|
||||
getToolByName(toolName: string): ITool | undefined;
|
||||
@@ -16,11 +16,11 @@ export interface IToolsService {
|
||||
export class ToolsService implements IToolsService {
|
||||
private supportedTools: ITool[];
|
||||
|
||||
constructor() {
|
||||
this.supportedTools = [new DockerTool(), new AzCliTool(), new AzdataTool(), new KubeCtlTool()];
|
||||
constructor(private _platformService: IPlatformService) {
|
||||
this.supportedTools = [new DockerTool(this._platformService), new AzCliTool(this._platformService), new AzdataTool(this._platformService), new KubeCtlTool(this._platformService)];
|
||||
}
|
||||
|
||||
getToolByName(toolName: string): ITool | undefined {
|
||||
return this.supportedTools.find(t => t.name === toolName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user