Add kube config and kube cluster to arc data controller screens (#13551)

This commit is contained in:
Arvind Ranasaria
2020-12-10 02:47:39 -08:00
committed by GitHub
parent dc8788b77f
commit 515b0794b0
17 changed files with 401 additions and 70 deletions

View File

@@ -14,23 +14,45 @@ import { ControllerModel } from '../../models/controllerModel';
import { InitializingComponent } from '../components/initializingComponent';
import { AzureArcTreeDataProvider } from '../tree/azureArcTreeDataProvider';
import { getErrorMessage } from '../../common/utils';
import { RadioOptionsGroup } from '../components/radioOptionsGroup';
import { getCurrentClusterContext, getDefaultKubeConfigPath, getKubeConfigClusterContexts } from '../../common/kubeUtils';
import { FilePicker } from '../components/filePicker';
export type ConnectToControllerDialogModel = { controllerModel: ControllerModel, password: string };
export interface IReadOnly {
readOnly?: boolean
}
abstract class ControllerDialogBase extends InitializingComponent {
protected _toDispose: vscode.Disposable[] = [];
protected modelBuilder!: azdata.ModelBuilder;
protected dialog: azdata.window.Dialog;
protected urlInputBox!: azdata.InputBoxComponent;
protected kubeConfigInputBox!: FilePicker;
protected clusterContextRadioGroup!: RadioOptionsGroup;
protected nameInputBox!: azdata.InputBoxComponent;
protected usernameInputBox!: azdata.InputBoxComponent;
protected passwordInputBox!: azdata.InputBoxComponent;
protected dispose(): void {
this._toDispose.forEach(disposable => disposable.dispose());
this._toDispose.length = 0; // clear the _toDispose array
}
protected getComponents(): (azdata.FormComponent<azdata.Component> & { layout?: azdata.FormItemLayout | undefined; })[] {
return [
{
component: this.urlInputBox,
title: loc.controllerUrl,
required: true
}, {
component: this.kubeConfigInputBox.component(),
title: loc.controllerKubeConfig,
required: true
}, {
component: this.clusterContextRadioGroup.component(),
title: loc.controllerClusterContext,
required: true
}, {
component: this.nameInputBox,
title: loc.controllerName,
@@ -48,7 +70,7 @@ abstract class ControllerDialogBase extends InitializingComponent {
}
protected abstract fieldToFocusOn(): azdata.Component;
protected readonlyFields(): azdata.InputBoxComponent[] { return []; }
protected readonlyFields(): IReadOnly[] { return []; }
protected initializeFields(controllerInfo: ControllerInfo | undefined, password: string | undefined) {
this.urlInputBox = this.modelBuilder.inputBox()
@@ -57,6 +79,18 @@ abstract class ControllerDialogBase extends InitializingComponent {
// If we have a model then we're editing an existing connection so don't let them modify the URL
readOnly: !!controllerInfo
}).component();
this.kubeConfigInputBox = new FilePicker(
this.modelBuilder,
controllerInfo?.kubeConfigFilePath || getDefaultKubeConfigPath(),
(disposable) => this._toDispose.push(disposable)
);
this.modelBuilder.inputBox()
.withProperties<azdata.InputBoxProperties>({
value: controllerInfo?.kubeConfigFilePath || getDefaultKubeConfigPath()
}).component();
this.clusterContextRadioGroup = new RadioOptionsGroup(this.modelBuilder, (disposable) => this._toDispose.push(disposable));
this.loadRadioGroup(controllerInfo?.kubeClusterContext);
this._toDispose.push(this.kubeConfigInputBox.onTextChanged(() => this.loadRadioGroup(controllerInfo?.kubeClusterContext)));
this.nameInputBox = this.modelBuilder.inputBox()
.withProperties<azdata.InputBoxProperties>({
value: controllerInfo?.name
@@ -81,10 +115,20 @@ abstract class ControllerDialogBase extends InitializingComponent {
this.dialog = azdata.window.createModelViewDialog(title);
}
private loadRadioGroup(previousClusterContext?: string): void {
this.clusterContextRadioGroup.load(async () => {
const clusters = await getKubeConfigClusterContexts(this.kubeConfigInputBox.value!);
return {
values: clusters.map(c => c.name),
defaultValue: getCurrentClusterContext(clusters, previousClusterContext, false),
};
});
}
public showDialog(controllerInfo?: ControllerInfo, password: string | undefined = undefined): azdata.window.Dialog {
this.id = controllerInfo?.id ?? uuid();
this.resources = controllerInfo?.resources ?? [];
this.dialog.cancelButton.onClick(() => this.handleCancel());
this._toDispose.push(this.dialog.cancelButton.onClick(() => this.handleCancel()));
this.dialog.registerContent(async (view) => {
this.modelBuilder = view.modelBuilder;
this.initializeFields(controllerInfo, password);
@@ -100,7 +144,13 @@ abstract class ControllerDialogBase extends InitializingComponent {
this.initialized = true;
});
this.dialog.registerCloseValidator(async () => await this.validate());
this.dialog.registerCloseValidator(async () => {
const isValidated = await this.validate();
if (isValidated) {
this.dispose();
}
return isValidated;
});
this.dialog.okButton.label = loc.connect;
this.dialog.cancelButton.label = loc.cancel;
azdata.window.openDialog(this.dialog);
@@ -116,6 +166,19 @@ abstract class ControllerDialogBase extends InitializingComponent {
public waitForClose(): Promise<ConnectToControllerDialogModel | undefined> {
return this.completionPromise.promise;
}
protected getControllerInfo(url: string, rememberPassword: boolean = false): ControllerInfo {
return {
id: this.id,
url: url,
kubeConfigFilePath: this.kubeConfigInputBox.value!,
kubeClusterContext: this.clusterContextRadioGroup.value!,
name: this.nameInputBox.value ?? '',
username: this.usernameInputBox.value!,
rememberPassword: rememberPassword,
resources: this.resources
};
}
}
export class ConnectToControllerDialog extends ControllerDialogBase {
@@ -164,14 +227,7 @@ export class ConnectToControllerDialog extends ControllerDialogBase {
if (!/.*:\d*$/.test(url)) {
url = `${url}:30080`;
}
const controllerInfo: ControllerInfo = {
id: this.id,
url: url,
name: this.nameInputBox.value ?? '',
username: this.usernameInputBox.value,
rememberPassword: this.rememberPwCheckBox.checked ?? false,
resources: this.resources
};
const controllerInfo: ControllerInfo = this.getControllerInfo(url, !!this.rememberPwCheckBox.checked);
const controllerModel = new ControllerModel(this.treeDataProvider, controllerInfo, this.passwordInputBox.value);
try {
// Validate that we can connect to the controller, this also populates the controllerRegistration from the connection response.
@@ -202,6 +258,8 @@ export class PasswordToControllerDialog extends ControllerDialogBase {
protected readonlyFields() {
return [
this.urlInputBox,
this.kubeConfigInputBox,
this.clusterContextRadioGroup,
this.nameInputBox,
this.usernameInputBox
];
@@ -229,14 +287,7 @@ export class PasswordToControllerDialog extends ControllerDialogBase {
return false;
}
}
const controllerInfo: ControllerInfo = {
id: this.id,
url: this.urlInputBox.value!,
name: this.nameInputBox.value!,
username: this.usernameInputBox.value!,
rememberPassword: false,
resources: []
};
const controllerInfo: ControllerInfo = this.getControllerInfo(this.urlInputBox.value!, false);
const controllerModel = new ControllerModel(this.treeDataProvider, controllerInfo, this.passwordInputBox.value);
this.completionPromise.resolve({ controllerModel: controllerModel, password: this.passwordInputBox.value });
return true;