Skip to content

Commit

Permalink
Features to resource deployment to add arc control create in ARC exte…
Browse files Browse the repository at this point in the history
…nsion (#10088)

* save not yet tested work

* Merge from master.

* Screeens Shared for Feeedback

* Code complete

* remove unneeded changes

* remove unnecessary comma

* remov wss

* remove dead code

* PR feedback

* checkpoint fixes

* PR & minor fixes

* minor fix for feature of  resourceType options being optional.

* reverting experimental change

* separating out changes for future featurework.

* revert unneeded change

* review feedback fixes

* review feedback

* rename InputFieldComponent to InputComponent
  • Loading branch information
ranasaria authored Apr 29, 2020
1 parent a9bfdf0 commit 3531156
Show file tree
Hide file tree
Showing 21 changed files with 728 additions and 174 deletions.
1 change: 1 addition & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
"type": "chrome",
"request": "attach",
"name": "Attach to azuredatastudio",
"timeout": 50000,
"port": 9222
},
{
Expand Down
6 changes: 3 additions & 3 deletions extensions/resource-deployment/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@
],
"providers": [
{
"wizard": {
"bdcWizard": {
"type": "new-aks",
"notebook": "%bdc-2019-aks-notebook%"
},
Expand All @@ -257,7 +257,7 @@
"when": "target=new-aks&&version=bdc2019"
},
{
"wizard": {
"bdcWizard": {
"type": "existing-aks",
"notebook": "%bdc-2019-existing-aks-notebook%"
},
Expand All @@ -272,7 +272,7 @@
"when": "target=existing-aks&&version=bdc2019"
},
{
"wizard": {
"bdcWizard": {
"type": "existing-kubeadm",
"notebook": "%bdc-2019-existing-kubeadm-notebook%"
},
Expand Down
1 change: 1 addition & 0 deletions extensions/resource-deployment/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@

export const DeploymentConfigurationKey: string = 'deployment';
export const AzdataInstallLocationKey: string = 'azdataInstallLocation';
export const ToolsInstallPath = 'AZDATA_NB_VAR_TOOLS_INSTALLATION_PATH';
88 changes: 69 additions & 19 deletions extensions/resource-deployment/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as azdata from 'azdata';
import * as vscode from 'vscode';

Expand Down Expand Up @@ -40,8 +41,12 @@ export interface DialogDeploymentProvider extends DeploymentProviderBase {
dialog: DialogInfo;
}

export interface WizardDeploymentProvider extends DeploymentProviderBase {
wizard: WizardInfo;
export interface BdcWizardDeploymentProvider extends DeploymentProviderBase {
bdcWizard: WizardInfo;
}

export interface NotebookWizardDeploymentProvider extends DeploymentProviderBase {
notebookWizard: NotebookWizardInfo;
}

export interface NotebookDeploymentProvider extends DeploymentProviderBase {
Expand All @@ -64,8 +69,12 @@ export function instanceOfDialogDeploymentProvider(obj: any): obj is DialogDeplo
return obj && 'dialog' in obj;
}

export function instanceOfWizardDeploymentProvider(obj: any): obj is WizardDeploymentProvider {
return obj && 'wizard' in obj;
export function instanceOfWizardDeploymentProvider(obj: any): obj is BdcWizardDeploymentProvider {
return obj && 'bdcWizard' in obj;
}

export function instanceOfNotebookWizardDeploymentProvider(obj: any): obj is NotebookWizardDeploymentProvider {
return obj && 'notebookWizard' in obj;
}

export function instanceOfNotebookDeploymentProvider(obj: any): obj is NotebookDeploymentProvider {
Expand All @@ -89,13 +98,31 @@ export interface DeploymentProviderBase {
when: string;
}

export type DeploymentProvider = DialogDeploymentProvider | WizardDeploymentProvider | NotebookDeploymentProvider | WebPageDeploymentProvider | DownloadDeploymentProvider | CommandDeploymentProvider;
export type DeploymentProvider = DialogDeploymentProvider | BdcWizardDeploymentProvider | NotebookWizardDeploymentProvider | NotebookDeploymentProvider | WebPageDeploymentProvider | DownloadDeploymentProvider | CommandDeploymentProvider;

export interface WizardInfo {
notebook: string | NotebookInfo;
type: BdcDeploymentType;
}

export interface NotebookWizardInfo extends WizardInfoBase {
notebook: string | NotebookInfo;
}

export interface WizardInfoBase extends SharedFieldAttributes {
taskName?: string;
type?: DeploymentType;
runNotebook?: boolean;
actionText?: string;
title: string;
pages: NotebookWizardPageInfo[];
summaryPage: NotebookWizardPageInfo;
generateSummaryPage: boolean;
}

export interface NotebookWizardPageInfo extends PageInfoBase {
description?: string;
}
export interface NotebookBasedDialogInfo extends DialogInfoBase {
notebook: string | NotebookInfo;
runNotebook?: boolean;
Expand Down Expand Up @@ -123,20 +150,24 @@ export interface DialogInfoBase {
actionText?: string;
}

export interface DialogTabInfo {
export interface DialogTabInfo extends PageInfoBase {
}

export interface PageInfoBase extends SharedFieldAttributes {
title: string;
isSummaryPage?: boolean;
sections: SectionInfo[];
labelWidth?: string;
inputWidth?: string;
}

export interface SectionInfo {
title: string;
fields?: FieldInfo[]; // Use this if the dialog is not wide. All fields will be displayed in one column, label will be placed on top of the input component.
rows?: RowInfo[]; // Use this for wide dialog or wizard. label will be placed to the left of the input component.
export interface SharedFieldAttributes {
labelWidth?: string;
inputWidth?: string;
labelPosition?: LabelPosition; // Default value is top
}
export interface SectionInfo extends SharedFieldAttributes {
title?: string;
fields?: FieldInfo[]; // Use this if the dialog is not wide. All fields will be displayed in one column, label will be placed on top of the input component.
rows?: RowInfo[]; // Use this for wide dialog or wizard. label will be placed to the left of the input component.
collapsible?: boolean;
collapsed?: boolean;
spaceBetweenFields?: string;
Expand All @@ -146,9 +177,13 @@ export interface RowInfo {
fields: FieldInfo[];
}

export interface FieldInfo {
export interface SubFieldInfo {
label: string;
variableName?: string;
}

export interface FieldInfo extends SubFieldInfo, SharedFieldAttributes {
subFields?: SubFieldInfo[];
type: FieldType;
defaultValue?: string;
confirmationRequired?: boolean;
Expand All @@ -162,21 +197,26 @@ export interface FieldInfo {
options?: string[] | azdata.CategoryValue[];
placeHolder?: string;
userName?: string; // needed for sql server's password complexity requirement check, password can not include the login name.
labelWidth?: string;
inputWidth?: string;
description?: string;
labelPosition?: LabelPosition; // overwrite the labelPosition of SectionInfo.
fontStyle?: FontStyle;
labelFontWeight?: FontWeight;
textFontWeight?: FontWeight;
links?: azdata.LinkArea[];
editable?: boolean; // for editable dropdown,
editable?: boolean; // for editable drop-down,
enabled?: boolean;
}

export interface AzureAccountFieldInfo extends FieldInfo {
export interface KubeClusterContextFieldInfo extends FieldInfo {
configFileVariableName?: string;
}
export interface AzureAccountFieldInfo extends AzureLocationsFieldInfo {
subscriptionVariableName?: string;
resourceGroupVariableName?: string;
}

export interface AzureLocationsFieldInfo extends FieldInfo {
locationVariableName?: string;
displayLocationVariableName?: string;
locations?: string[]
}

Expand All @@ -202,9 +242,13 @@ export enum FieldType {
SQLPassword = 'sql_password',
Password = 'password',
Options = 'options',
RadioOptions = 'radio_options',
ReadonlyText = 'readonly_text',
Checkbox = 'checkbox',
AzureAccount = 'azure_account'
AzureAccount = 'azure_account',
AzureLocations = 'azure_locations',
FilePicker = 'file_picker',
KubeClusterContextPicker = 'kube_cluster_context_picker'
}

export interface NotebookInfo {
Expand Down Expand Up @@ -278,6 +322,12 @@ export const enum BdcDeploymentType {
ExistingKubeAdm = 'existing-kubeadm'
}

export const enum ArcDeploymentType {
NewControlPlane = 'new-control-plane'
}

export type DeploymentType = ArcDeploymentType | BdcDeploymentType;

export interface Command {
command: string;
sudo?: boolean;
Expand Down
4 changes: 4 additions & 0 deletions extensions/resource-deployment/src/localizedConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@ export const account = localize('azure.account', "Azure Account");
export const subscription = localize('azure.account.subscription', "Subscription");
export const resourceGroup = localize('azure.account.resourceGroup', "Resource Group");
export const location = localize('azure.account.location', "Azure Location");
export const browse = localize('filePicker.browse', "Browse");
export const select = localize('filePicker.select', "Select");
export const kubeConfigFilePath = localize('kubeConfigClusterPicker.kubeConfigFilePatht', "Kube config file path");
export const clusterContextNotFound = localize('kubeConfigClusterPicker.clusterContextNotFound', "No cluster context information found");
64 changes: 37 additions & 27 deletions extensions/resource-deployment/src/services/kubeService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,39 +14,49 @@ export interface KubeClusterContext {
}

export interface IKubeService {
getDefautConfigPath(): string;
getDefaultConfigPath(): string;
getClusterContexts(configFile: string): Promise<KubeClusterContext[]>;
}

export class KubeService implements IKubeService {
getDefautConfigPath(): string {
return path.join(os.homedir(), '.kube', 'config');
getDefaultConfigPath(): string {
return getDefaultKubeConfigPath();
}

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;
});
return getKubeConfigClusterContexts(configFile);
}
}

export function getKubeConfigClusterContexts(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;
});
}

export function getDefaultKubeConfigPath(): string {
return path.join(os.homedir(), '.kube', 'config');
}

43 changes: 41 additions & 2 deletions extensions/resource-deployment/src/services/notebookService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
*--------------------------------------------------------------------------------------------*/

import * as azdata from 'azdata';
import { EOL } from 'os';
import * as path from 'path';
import { isString } from 'util';
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import { IPlatformService } from './platformService';
import { NotebookInfo } from '../interfaces';
import { getErrorMessage, getDateTimeString } from '../utils';
import { getDateTimeString, getErrorMessage } from '../utils';
import { IPlatformService } from './platformService';
const localize = nls.loadMessageBundle();

export interface Notebook {
Expand All @@ -36,6 +37,7 @@ export interface INotebookService {
launchNotebookWithContent(title: string, content: string): Thenable<azdata.nb.NotebookEditor>;
getNotebook(notebook: string | NotebookInfo): Promise<Notebook>;
executeNotebook(notebook: any, env?: NodeJS.ProcessEnv): Promise<NotebookExecutionResult>;
backgroundExecuteNotebook(taskName: string | undefined, notebookInfo: string | NotebookInfo, tempNoteBookPrefix: string, platformService: IPlatformService): void;
}

export class NotebookService implements INotebookService {
Expand Down Expand Up @@ -107,6 +109,43 @@ export class NotebookService implements INotebookService {
}
}

public backgroundExecuteNotebook(taskName: string | undefined, notebookInfo: string | NotebookInfo, tempNotebookPrefix: string, platformService: IPlatformService): void {
azdata.tasks.startBackgroundOperation({
displayName: taskName!,
description: taskName!,
isCancelable: false,
operation: async op => {
op.updateStatus(azdata.TaskStatus.InProgress);
const notebook = await this.getNotebook(notebookInfo);
const result = await this.executeNotebook(notebook);
if (result.succeeded) {
op.updateStatus(azdata.TaskStatus.Succeeded);
} else {
op.updateStatus(azdata.TaskStatus.Failed, result.errorMessage);
if (result.outputNotebook) {
const viewErrorDetail = localize('resourceDeployment.ViewErrorDetail', "View error detail");
const taskFailedMessage = localize('resourceDeployment.BackgroundExecutionFailed', "The task \"{0}\" has failed.", taskName);
const selectedOption = await vscode.window.showErrorMessage(taskFailedMessage, viewErrorDetail);
platformService.logToOutputChannel(taskFailedMessage);
if (selectedOption === viewErrorDetail) {
try {
this.launchNotebookWithContent(`${tempNotebookPrefix}-${getDateTimeString()}`, result.outputNotebook);
} catch (error) {
const launchNotebookError = localize('resourceDeployment.FailedToOpenNotebook', "An error occurred launching the output notebook. {1}{2}.", EOL, getErrorMessage(error));
platformService.logToOutputChannel(launchNotebookError);
vscode.window.showErrorMessage(launchNotebookError);
}
}
} else {
const errorMessage = localize('resourceDeployment.TaskFailedWithNoOutputNotebook', "The task \"{0}\" failed and no output Notebook was generated.", taskName);
platformService.logToOutputChannel(errorMessage);
vscode.window.showErrorMessage(errorMessage);
}
}
}
});
}

async getNotebookFullPath(notebook: string | NotebookInfo): Promise<string> {
const notebookPath = this.getNotebookPath(notebook);
let notebookExists = await this.platformService.fileExists(notebookPath);
Expand Down
Loading

0 comments on commit 3531156

Please sign in to comment.