Replacing all azdata with az (#16502)

* Changed azdata to az in azcli extension and resource-deployment, and some arc. Removed user, pass, url from controller connect blade. Commented out tests. Ported over work from old branch.

* Changed unit tests, all unit tests passing. Changed parameters to new ones, fixed some Controller Connect issues.

* Connect data controller and create dc working.

* Changed az back to azdata in necessary places in resource-deployment.

* Changed notebook values and added namespace to some params.

* Added some changes from PR to this branch

* Changed azdata.ts to az.ts and changed subscription parameter

* Brought over changes from azcli PR into this branch.

* added endpoint, username, password to getIsPassword

* Changed notebooks to use proper az params, hard coded in some values to verify it is working, removed some variableNames from package.json.

* Changed -sc to --storage-class in notebook

* Added namespace to SQL deploy, deleted dc create in api

* Deleted more dc create code and uncommented findAz() with unfinished work on Do Not Ask Again.

* Removed (preview) from extensions/arc and extensions/azcli excluding preview:true in package.json

* Commented out install/update prompts until DoNotAskAgain is implemented

* Fixed bugs: JSON Output errors are now being caught, --infrastructure now has a required UI component with dropdown options, config page loads properly, SQL create flags use full names instead of shortnames.

* Adds validation to pg extensions and bug fixes (#16486)

* Extensions

* Server parameters

* Change locaiton of postgres extensions, pr fixes

* Change location of list

* List spacing

* Commented out Don't Ask Again prompt implementation.

* Uncommented header of a test file.

* Added Azure CLI arcdata extension to Prerequisites

* Reverted package.json and yarn.lock

* Took away casting of stderr and stdout in executeCommand.

* Deleted override function for initializeFields in connectControllerDialog.ts

* Removed fakeAzApi for testing and added back in (Preview)

* Removed en-us from python notebook links.

* Deleted azdata tool from tool tests in resource-deployment

* Deleted another instance of azdata in tool test

* Add back in azdata tooltype

* Remove en-us

* Replaced AzdataTool in typings

* Reverting adding azdata tool back in

* Changed Azdata to AzdataToolOld

* Added back azdata tool type

* Added AzdataToolOld to tool types

* fix test

Co-authored-by: Candice Ye <canye@microsoft.com>
Co-authored-by: nasc17 <nasc@microsoft.com>
Co-authored-by: nasc17 <69922333+nasc17@users.noreply.github.com>
Co-authored-by: chgagnon <chgagnon@microsoft.com>
This commit is contained in:
Candice Ye
2021-08-01 15:12:24 -07:00
committed by GitHub
parent 65cc61fdbd
commit 914fe8fc29
58 changed files with 1623 additions and 2032 deletions

View File

@@ -18,7 +18,7 @@ export class ControllerDashboard extends Dashboard {
public override async showDashboard(): Promise<void> {
await super.showDashboard();
// Kick off the model refresh but don't wait on it since that's all handled with callbacks anyways
this._controllerModel.refresh(false).catch(err => console.log(`Error refreshing Controller dashboard ${err}`));
this._controllerModel.refresh(false, this._controllerModel.info.namespace).catch(err => console.log(`Error refreshing Controller dashboard ${err}`));
}
protected async registerTabs(modelView: azdata.ModelView): Promise<(azdata.DashboardTab | azdata.DashboardTabGroup)[]> {

View File

@@ -58,7 +58,7 @@ export class ControllerDashboardOverviewPage extends DashboardPage {
}
protected async refresh(): Promise<void> {
await this._controllerModel.refresh();
await this._controllerModel.refresh(false, this._controllerModel.info.namespace);
}
public get container(): azdata.Component {

View File

@@ -5,7 +5,7 @@
import * as vscode from 'vscode';
import * as azdata from 'azdata';
import * as azdataExt from 'azdata-ext';
import * as azExt from 'az-ext';
import * as loc from '../../../localizedConstants';
import { IconPathHelper, cssStyles } from '../../../constants';
import { DashboardPage } from '../../components/dashboardPage';
@@ -30,11 +30,11 @@ export class MiaaComputeAndStoragePage extends DashboardPage {
memoryRequest?: string
} = {};
private readonly _azdataApi: azdataExt.IExtension;
private readonly _azApi: azExt.IExtension;
constructor(modelView: azdata.ModelView, dashboard: azdata.window.ModelViewDashboard, private _miaaModel: MiaaModel) {
super(modelView, dashboard);
this._azdataApi = vscode.extensions.getExtension(azdataExt.extension.name)?.exports;
this._azApi = vscode.extensions.getExtension(azExt.extension.name)?.exports;
this.initializeConfigurationBoxes();
@@ -130,8 +130,8 @@ export class MiaaComputeAndStoragePage extends DashboardPage {
},
async (_progress, _token): Promise<void> => {
try {
await this._azdataApi.azdata.arc.sql.mi.edit(
this._miaaModel.info.name, this.saveArgs, this._miaaModel.controllerModel.azdataAdditionalEnvVars, this._miaaModel.controllerModel.controllerContext);
await this._azApi.az.sql.miarc.edit(
this._miaaModel.info.name, this.saveArgs, this._miaaModel.controllerModel.info.namespace, this._miaaModel.controllerModel.azAdditionalEnvVars);
} catch (err) {
this.saveButton!.enabled = true;
throw err;

View File

@@ -21,7 +21,7 @@ export class MiaaDashboard extends Dashboard {
public override async showDashboard(): Promise<void> {
await super.showDashboard();
// Kick off the model refreshes but don't wait on it since that's all handled with callbacks anyways
this._controllerModel.refresh().catch(err => console.log(`Error refreshing controller model for MIAA dashboard ${err}`));
this._controllerModel.refresh(false, this._controllerModel.info.namespace).catch(err => console.log(`Error refreshing controller model for MIAA dashboard ${err}`));
this._miaaModel.refresh().catch(err => console.log(`Error refreshing MIAA model for MIAA dashboard ${err}`));
}

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
import * as azdataExt from 'azdata-ext';
import * as azExt from 'az-ext';
import * as azurecore from 'azurecore';
import * as vscode from 'vscode';
import { getDatabaseStateDisplayText, promptForInstanceDeletion } from '../../../common/utils';
@@ -34,7 +34,7 @@ export class MiaaDashboardOverviewPage extends DashboardPage {
private _connectToServerButton!: azdata.ButtonComponent;
private _databasesTableLoading!: azdata.LoadingComponent;
private readonly _azdataApi: azdataExt.IExtension;
private readonly _azApi: azExt.IExtension;
private readonly _azurecoreApi: azurecore.IExtension;
private _instanceProperties = {
@@ -50,7 +50,7 @@ export class MiaaDashboardOverviewPage extends DashboardPage {
constructor(modelView: azdata.ModelView, dashboard: azdata.window.ModelViewDashboard, private _controllerModel: ControllerModel, private _miaaModel: MiaaModel) {
super(modelView, dashboard);
this._azdataApi = vscode.extensions.getExtension(azdataExt.extension.name)?.exports;
this._azApi = vscode.extensions.getExtension(azExt.extension.name)?.exports;
this._azurecoreApi = vscode.extensions.getExtension(azurecore.extension.name)?.exports;
this._instanceProperties.miaaAdmin = this._miaaModel.username || this._instanceProperties.miaaAdmin;
@@ -75,7 +75,7 @@ export class MiaaDashboardOverviewPage extends DashboardPage {
}
protected async refresh(): Promise<void> {
await Promise.all([this._controllerModel.refresh(), this._miaaModel.refresh()]);
await Promise.all([this._controllerModel.refresh(false, this._controllerModel.info.namespace), this._miaaModel.refresh()]);
}
public get container(): azdata.Component {
@@ -244,7 +244,7 @@ export class MiaaDashboardOverviewPage extends DashboardPage {
cancellable: false
},
async (_progress, _token) => {
return await this._azdataApi.azdata.arc.sql.mi.delete(this._miaaModel.info.name, this._controllerModel.azdataAdditionalEnvVars, this._controllerModel.controllerContext);
return await this._azApi.az.sql.miarc.delete(this._miaaModel.info.name, this._controllerModel.info.namespace, this._controllerModel.azAdditionalEnvVars);
}
);
await this._controllerModel.refreshTreeNode();

View File

@@ -5,7 +5,7 @@
import * as vscode from 'vscode';
import * as azdata from 'azdata';
import * as azdataExt from 'azdata-ext';
import * as azExt from 'az-ext';
import * as loc from '../../../localizedConstants';
import { IconPathHelper, cssStyles } from '../../../constants';
import { DashboardPage } from '../../components/dashboardPage';
@@ -45,11 +45,11 @@ export class PostgresComputeAndStoragePage extends DashboardPage {
private discardButton!: azdata.ButtonComponent;
private saveButton!: azdata.ButtonComponent;
private readonly _azdataApi: azdataExt.IExtension;
private readonly _azApi: azExt.IExtension;
constructor(modelView: azdata.ModelView, dashboard: azdata.window.ModelViewDashboard, private _postgresModel: PostgresModel) {
super(modelView, dashboard);
this._azdataApi = vscode.extensions.getExtension(azdataExt.extension.name)?.exports;
this._azApi = vscode.extensions.getExtension(azExt.extension.name)?.exports;
this.initializeConfigurationBoxes();
@@ -165,7 +165,7 @@ export class PostgresComputeAndStoragePage extends DashboardPage {
},
async (_progress, _token): Promise<void> => {
try {
await this._azdataApi.azdata.arc.postgres.server.edit(
await this._azApi.az.postgres.arcserver.edit(
this._postgresModel.info.name,
{
workers: this.saveArgs.workers,
@@ -174,7 +174,8 @@ export class PostgresComputeAndStoragePage extends DashboardPage {
memoryRequest: this.schedulingParamsToEdit(this.saveArgs.memoryRequest!),
memoryLimit: this.schedulingParamsToEdit(this.saveArgs.memoryLimit!)
},
this._postgresModel.controllerModel.azdataAdditionalEnvVars);
this._postgresModel.controllerModel.info.namespace,
this._postgresModel.controllerModel.azAdditionalEnvVars);
} catch (err) {
// If an error occurs while editing the instance then re-enable the save button since
// the edit wasn't successfully applied

View File

@@ -36,27 +36,27 @@ export class PostgresCoordinatorNodeParametersPage extends PostgresParametersPag
}
protected async saveParameterEdits(engineSettings: string): Promise<void> {
await this._azdataApi.azdata.arc.postgres.server.edit(
await this._azApi.az.postgres.arcserver.edit(
this._postgresModel.info.name,
{ coordinatorEngineSettings: engineSettings },
this._postgresModel.controllerModel.azdataAdditionalEnvVars,
this._postgresModel.controllerModel.controllerContext);
this._postgresModel.controllerModel.info.namespace,
this._postgresModel.controllerModel.azAdditionalEnvVars);
}
protected async resetAllParameters(): Promise<void> {
await this._azdataApi.azdata.arc.postgres.server.edit(
await this._azApi.az.postgres.arcserver.edit(
this._postgresModel.info.name,
{ coordinatorEngineSettings: `''`, replaceEngineSettings: true },
this._postgresModel.controllerModel.azdataAdditionalEnvVars,
this._postgresModel.controllerModel.controllerContext);
this._postgresModel.controllerModel.info.namespace,
this._postgresModel.controllerModel.azAdditionalEnvVars);
}
protected async resetParameter(parameterName: string): Promise<void> {
await this._azdataApi.azdata.arc.postgres.server.edit(
await this._azApi.az.postgres.arcserver.edit(
this._postgresModel.info.name,
{ coordinatorEngineSettings: parameterName + '=' },
this._postgresModel.controllerModel.azdataAdditionalEnvVars,
this._postgresModel.controllerModel.controllerContext);
this._postgresModel.controllerModel.info.namespace,
this._postgresModel.controllerModel.azAdditionalEnvVars);
}
}

View File

@@ -29,7 +29,7 @@ export class PostgresDashboard extends Dashboard {
await super.showDashboard();
// Kick off the model refresh but don't wait on it since that's all handled with callbacks anyways
this._controllerModel.refresh().catch(err => console.log(`Error refreshing controller model for Postgres dashboard ${err}`));
this._controllerModel.refresh(false, this._controllerModel.info.namespace).catch(err => console.log(`Error refreshing controller model for Postgres dashboard ${err}`));
this._postgresModel.refresh().catch(err => console.log(`Error refreshing Postgres model for Postgres dashboard ${err}`));
}

View File

@@ -5,7 +5,7 @@
import * as vscode from 'vscode';
import * as azdata from 'azdata';
import * as azdataExt from 'azdata-ext';
import * as azExt from 'az-ext';
import * as loc from '../../../localizedConstants';
import { IconPathHelper, cssStyles } from '../../../constants';
import { DashboardPage } from '../../components/dashboardPage';
@@ -22,11 +22,11 @@ export class PostgresExtensionsPage extends DashboardPage {
private dropExtensionsButton!: azdata.ButtonComponent;
private extensionsLink!: azdata.HyperlinkComponent;
private readonly _azdataApi: azdataExt.IExtension;
private readonly _azApi: azExt.IExtension;
constructor(modelView: azdata.ModelView, dashboard: azdata.window.ModelViewDashboard, private _postgresModel: PostgresModel) {
super(modelView, dashboard);
this._azdataApi = vscode.extensions.getExtension(azdataExt.extension.name)?.exports;
this._azApi = vscode.extensions.getExtension(azExt.extension.name)?.exports;
this.disposables.push(
this._postgresModel.onConfigUpdated(() => this.eventuallyRunOnInitialized(() => this.handleConfigUpdated())));
@@ -138,12 +138,13 @@ export class PostgresExtensionsPage extends DashboardPage {
},
async (_progress, _token): Promise<void> => {
await this._azdataApi.azdata.arc.postgres.server.edit(
await this._azApi.az.postgres.arcserver.edit(
this._postgresModel.info.name,
{
extensions: extensionList
},
this._postgresModel.controllerModel.azdataAdditionalEnvVars);
this._postgresModel.controllerModel.info.namespace,
this._postgresModel.controllerModel.azAdditionalEnvVars);
try {
await this._postgresModel.refresh();
@@ -235,6 +236,10 @@ export class PostgresExtensionsPage extends DashboardPage {
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'margin-block-end': '0px' }
}).component();
if (name === 'citus') {
checkBox.enabled = false;
}
this.disposables.push(
checkBox.onChanged(() => {
if (checkBox.checked) {
@@ -256,7 +261,7 @@ export class PostgresExtensionsPage extends DashboardPage {
*/
public async dropExtension(): Promise<void> {
this.droppedExtensions.forEach(d => {
let index = this.droppedExtensions.indexOf(d, 0);
let index = this.extensionNames.indexOf(d, 0);
this.extensionNames.splice(index, 1);
});
@@ -267,12 +272,13 @@ export class PostgresExtensionsPage extends DashboardPage {
cancellable: false
},
async (_progress, _token): Promise<void> => {
await this._azdataApi.azdata.arc.postgres.server.edit(
await this._azApi.az.postgres.arcserver.edit(
this._postgresModel.info.name,
{
extensions: this.extensionNames.join()
},
this._postgresModel.controllerModel.azdataAdditionalEnvVars
this._postgresModel.controllerModel.info.namespace,
this._postgresModel.controllerModel.azAdditionalEnvVars
);
}
);

View File

@@ -5,7 +5,7 @@
import * as vscode from 'vscode';
import * as azdata from 'azdata';
import * as azdataExt from 'azdata-ext';
import * as azExt from 'az-ext';
import * as loc from '../../../localizedConstants';
import { IconPathHelper, cssStyles, iconSize } from '../../../constants';
import { DashboardPage } from '../../components/dashboardPage';
@@ -35,11 +35,11 @@ export class PostgresOverviewPage extends DashboardPage {
private podStatusTable!: azdata.DeclarativeTableComponent;
private podStatusData: PodStatusModel[] = [];
private readonly _azdataApi: azdataExt.IExtension;
private readonly _azApi: azExt.IExtension;
constructor(modelView: azdata.ModelView, dashboard: azdata.window.ModelViewDashboard, private _controllerModel: ControllerModel, private _postgresModel: PostgresModel) {
super(modelView, dashboard);
this._azdataApi = vscode.extensions.getExtension(azdataExt.extension.name)?.exports;
this._azApi = vscode.extensions.getExtension(azExt.extension.name)?.exports;
this.disposables.push(
this._controllerModel.onRegistrationsUpdated(() => this.eventuallyRunOnInitialized(() => this.handleRegistrationsUpdated())),
@@ -223,13 +223,14 @@ export class PostgresOverviewPage extends DashboardPage {
try {
const password = await promptAndConfirmPassword(input => !input ? loc.enterANonEmptyPassword : '');
if (password) {
await this._azdataApi.azdata.arc.postgres.server.edit(
await this._azApi.az.postgres.arcserver.edit(
this._postgresModel.info.name,
{
adminPassword: true,
noWait: true
},
Object.assign({ 'AZDATA_PASSWORD': password }, this._controllerModel.azdataAdditionalEnvVars));
this._postgresModel.controllerModel.info.namespace,
Object.assign({ 'AZDATA_PASSWORD': password }, this._controllerModel.azAdditionalEnvVars));
vscode.window.showInformationMessage(loc.passwordReset);
}
} catch (error) {
@@ -257,7 +258,7 @@ export class PostgresOverviewPage extends DashboardPage {
cancellable: false
},
async (_progress, _token) => {
return await this._azdataApi.azdata.arc.postgres.server.delete(this._postgresModel.info.name, this._controllerModel.azdataAdditionalEnvVars, this._controllerModel.controllerContext);
return await this._azApi.az.postgres.arcserver.delete(this._postgresModel.info.name, this._postgresModel.controllerModel.info.namespace, this._controllerModel.azAdditionalEnvVars);
}
);
await this._controllerModel.refreshTreeNode();
@@ -294,7 +295,7 @@ export class PostgresOverviewPage extends DashboardPage {
await Promise.all([
this._postgresModel.refresh(),
this._controllerModel.refresh()
this._controllerModel.refresh(false, this._controllerModel.info.namespace)
]);
} catch (error) {
vscode.window.showErrorMessage(loc.refreshFailed(error));
@@ -351,7 +352,7 @@ export class PostgresOverviewPage extends DashboardPage {
let podModels: PodStatusModel[] = [];
const podStatus = this._postgresModel.config?.status.podsStatus;
podStatus?.forEach(p => {
podStatus?.forEach((p: { conditions: any[]; name: any; role: string; }) => {
// If a condition of the pod has a status of False, pod is not Ready
const status = p.conditions.find(c => c.status === 'False') ? loc.notReady : loc.ready;

View File

@@ -5,7 +5,7 @@
import * as vscode from 'vscode';
import * as azdata from 'azdata';
import * as azdataExt from 'azdata-ext';
import * as azExt from 'az-ext';
import * as loc from '../../../localizedConstants';
import { UserCancelledError } from '../../../common/api';
import { IconPathHelper, cssStyles } from '../../../constants';
@@ -37,12 +37,12 @@ export abstract class PostgresParametersPage extends DashboardPage {
private changedComponentValues: Set<string> = new Set();
private parameterUpdates: Map<string, string> = new Map();
protected readonly _azdataApi: azdataExt.IExtension;
protected readonly _azApi: azExt.IExtension;
constructor(modelView: azdata.ModelView, dashboard: azdata.window.ModelViewDashboard, protected _postgresModel: PostgresModel) {
super(modelView, dashboard);
this._azdataApi = vscode.extensions.getExtension(azdataExt.extension.name)?.exports;
this._azApi = vscode.extensions.getExtension(azExt.extension.name)?.exports;
this.initializeSearchBox();

View File

@@ -77,7 +77,7 @@ export class PostgresPropertiesPage extends DashboardPage {
this.loading!.loading = true;
await Promise.all([
this._postgresModel.refresh(),
this._controllerModel.refresh()
this._controllerModel.refresh(false, this._controllerModel.info.namespace)
]);
} catch (error) {
vscode.window.showErrorMessage(loc.refreshFailed(error));

View File

@@ -37,26 +37,26 @@ export class PostgresWorkerNodeParametersPage extends PostgresParametersPage {
}
protected async saveParameterEdits(engineSettings: string): Promise<void> {
await this._azdataApi.azdata.arc.postgres.server.edit(
await this._azApi.az.postgres.arcserver.edit(
this._postgresModel.info.name,
{ workerEngineSettings: engineSettings },
this._postgresModel.controllerModel.azdataAdditionalEnvVars,
this._postgresModel.controllerModel.controllerContext);
this._postgresModel.controllerModel.info.namespace,
this._postgresModel.controllerModel.azAdditionalEnvVars);
}
protected async resetAllParameters(): Promise<void> {
await this._azdataApi.azdata.arc.postgres.server.edit(
await this._azApi.az.postgres.arcserver.edit(
this._postgresModel.info.name,
{ workerEngineSettings: `''`, replaceEngineSettings: true },
this._postgresModel.controllerModel.azdataAdditionalEnvVars,
this._postgresModel.controllerModel.controllerContext);
this._postgresModel.controllerModel.info.namespace,
this._postgresModel.controllerModel.azAdditionalEnvVars);
}
protected async resetParameter(parameterName: string): Promise<void> {
await this._azdataApi.azdata.arc.postgres.server.edit(
await this._azApi.az.postgres.arcserver.edit(
this._postgresModel.info.name,
{ workerEngineSettings: parameterName + '=' },
this._postgresModel.controllerModel.azdataAdditionalEnvVars,
this._postgresModel.controllerModel.controllerContext);
this._postgresModel.controllerModel.info.namespace,
this._postgresModel.controllerModel.azAdditionalEnvVars);
}
}

View File

@@ -10,6 +10,8 @@ import { cssStyles } from '../../constants';
import { InitializingComponent } from '../components/initializingComponent';
import { PostgresModel } from '../../models/postgresModel';
export const validExtensions = ['citus', 'pgaudit', 'pgautofailover', 'pg_cron', 'pg_partman', 'plv8', 'postgis', 'postgis_raster', 'postgis_sfcgal', 'postgis_tiger_geocoder', 'tdigest'];
export class AddPGExtensionsDialog extends InitializingComponent {
protected modelBuilder!: azdata.ModelBuilder;
@@ -28,7 +30,7 @@ export class AddPGExtensionsDialog extends InitializingComponent {
this.modelBuilder = view.modelBuilder;
const info = this.modelBuilder.text().withProps({
value: loc.extensionsFunction,
value: loc.extensionsAddFunction(validExtensions.join(', ')),
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'margin-block-end': '0px' }
}).component();
@@ -45,7 +47,15 @@ export class AddPGExtensionsDialog extends InitializingComponent {
.withProps({
value: '',
ariaLabel: loc.extensionsAddList,
enabled: true
enabled: true,
validationErrorMessage: loc.extensionsAddErrorrMessage(validExtensions.join(','))
}).withValidation((component) => {
if (!component.value) {
return true;
}
let newExtensions = component.value.split(',');
return newExtensions.every(e => validExtensions.includes(e));
}).component();
let formModel = this.modelBuilder.formContainer()
@@ -56,7 +66,8 @@ export class AddPGExtensionsDialog extends InitializingComponent {
},
{
component: this.extensionsListInputBox,
title: loc.extensionsAddList
title: loc.extensionsAddList,
required: true
}
],
title: ''

View File

@@ -5,7 +5,6 @@
import { ControllerInfo, ResourceInfo } from 'arc';
import * as azdata from 'azdata';
import * as azdataExt from 'azdata-ext';
import { v4 as uuid } from 'uuid';
import * as vscode from 'vscode';
import { Deferred } from '../../common/promise';
@@ -13,12 +12,11 @@ import * as loc from '../../localizedConstants';
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, KubeClusterContext } from '../../common/kubeUtils';
import { FilePicker } from '../components/filePicker';
export type ConnectToControllerDialogModel = { controllerModel: ControllerModel, password: string };
export type ConnectToControllerDialogModel = { controllerModel: ControllerModel };
abstract class ControllerDialogBase extends InitializingComponent {
protected _toDispose: vscode.Disposable[] = [];
@@ -29,9 +27,6 @@ abstract class ControllerDialogBase extends InitializingComponent {
protected kubeConfigInputBox!: FilePicker;
protected clusterContextRadioGroup!: RadioOptionsGroup;
protected nameInputBox!: azdata.InputBoxComponent;
protected usernameInputBox!: azdata.InputBoxComponent;
protected passwordInputBox!: azdata.InputBoxComponent;
protected urlInputBox!: azdata.InputBoxComponent;
private _kubeClusters: KubeClusterContext[] = [];
@@ -46,13 +41,6 @@ abstract class ControllerDialogBase extends InitializingComponent {
component: this.namespaceInputBox,
title: loc.namespace,
required: true
},
{
component: this.urlInputBox,
title: loc.controllerUrl,
layout: {
info: loc.controllerUrlDescription
}
}, {
component: this.kubeConfigInputBox.component(),
title: loc.controllerKubeConfig,
@@ -68,14 +56,6 @@ abstract class ControllerDialogBase extends InitializingComponent {
layout: {
info: loc.controllerNameDescription
}
}, {
component: this.usernameInputBox,
title: loc.controllerUsername,
required: true
}, {
component: this.passwordInputBox,
title: loc.controllerPassword,
required: true
}
];
}
@@ -83,16 +63,11 @@ abstract class ControllerDialogBase extends InitializingComponent {
protected abstract fieldToFocusOn(): azdata.Component;
protected readonlyFields(): azdata.Component[] { return []; }
protected initializeFields(controllerInfo: ControllerInfo | undefined, password: string | undefined) {
protected initializeFields(controllerInfo: ControllerInfo | undefined) {
this.namespaceInputBox = this.modelBuilder.inputBox()
.withProps({
value: controllerInfo?.namespace,
}).component();
this.urlInputBox = this.modelBuilder.inputBox()
.withProps({
value: controllerInfo?.endpoint,
placeHolder: loc.controllerUrlPlaceholder,
}).component();
this.kubeConfigInputBox = new FilePicker(
this.modelBuilder,
controllerInfo?.kubeConfigFilePath || getDefaultKubeConfigPath(),
@@ -113,15 +88,6 @@ abstract class ControllerDialogBase extends InitializingComponent {
.withProps({
value: controllerInfo?.name
}).component();
this.usernameInputBox = this.modelBuilder.inputBox()
.withProps({
value: controllerInfo?.username
}).component();
this.passwordInputBox = this.modelBuilder.inputBox()
.withProps({
inputType: 'password',
value: password
}).component();
}
protected completionPromise = new Deferred<ConnectToControllerDialogModel | undefined>();
@@ -150,13 +116,13 @@ abstract class ControllerDialogBase extends InitializingComponent {
this.namespaceInputBox.value = currentContext?.namespace;
}
public showDialog(controllerInfo?: ControllerInfo, password: string | undefined = undefined): azdata.window.Dialog {
public showDialog(controllerInfo?: ControllerInfo): azdata.window.Dialog {
this.id = controllerInfo?.id ?? uuid();
this.resources = controllerInfo?.resources ?? [];
this._toDispose.push(this.dialog.cancelButton.onClick(() => this.handleCancel()));
this.dialog.registerContent(async (view) => {
this.modelBuilder = view.modelBuilder;
this.initializeFields(controllerInfo, password);
this.initializeFields(controllerInfo);
let formModel = this.modelBuilder.formContainer()
.withFormItems([{
@@ -192,75 +158,37 @@ abstract class ControllerDialogBase extends InitializingComponent {
return this.completionPromise.promise;
}
protected getControllerInfo(url: string, rememberPassword: boolean = false): ControllerInfo {
protected getControllerInfo(): ControllerInfo {
return {
id: this.id,
endpoint: url || undefined,
namespace: this.namespaceInputBox.value!.trim(),
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 {
protected rememberPwCheckBox!: azdata.CheckBoxComponent;
protected fieldToFocusOn() {
return this.namespaceInputBox;
}
protected override getComponents() {
return [
...super.getComponents(),
{
component: this.rememberPwCheckBox,
title: ''
}];
}
protected override initializeFields(controllerInfo: ControllerInfo | undefined, password: string | undefined) {
super.initializeFields(controllerInfo, password);
this.rememberPwCheckBox = this.modelBuilder.checkBox()
.withProps({
label: loc.rememberPassword,
checked: controllerInfo?.rememberPassword
}).component();
}
constructor(treeDataProvider: AzureArcTreeDataProvider) {
super(treeDataProvider, loc.connectToController);
}
public async validate(): Promise<boolean> {
if (!this.namespaceInputBox.value || !this.usernameInputBox.value || !this.passwordInputBox.value) {
if (!this.namespaceInputBox.value) {
return false;
}
let url = this.urlInputBox.value?.trim() || '';
if (url) {
// Only support https connections
if (url.toLowerCase().startsWith('http://')) {
url = url.replace('http', 'https');
}
// Append https if they didn't type it in
if (!url.toLowerCase().startsWith('https://')) {
url = `https://${url}`;
}
// Append default port if one wasn't specified
if (!/.*:\d*$/.test(url)) {
url = `${url}:30080`;
}
}
const controllerInfo: ControllerInfo = this.getControllerInfo(url, !!this.rememberPwCheckBox.checked);
const controllerModel = new ControllerModel(this.treeDataProvider, controllerInfo, this.passwordInputBox.value);
const controllerInfo: ControllerInfo = this.getControllerInfo();
const controllerModel = new ControllerModel(this.treeDataProvider, controllerInfo);
try {
// Validate that we can connect to the controller, this also populates the controllerRegistration from the connection response.
await controllerModel.refresh(false);
await controllerModel.refresh(false, this.namespaceInputBox.value);
// default info.name to the name of the controller instance if the user did not specify their own and to a pre-canned default if for some weird reason controller endpoint returned instanceName is also not a valid value
controllerModel.info.name = controllerModel.info.name || controllerModel.controllerConfig?.metadata.name || loc.defaultControllerName;
} catch (err) {
@@ -270,74 +198,7 @@ export class ConnectToControllerDialog extends ControllerDialogBase {
};
return false;
}
this.completionPromise.resolve({ controllerModel: controllerModel, password: this.passwordInputBox.value });
this.completionPromise.resolve({ controllerModel: controllerModel });
return true;
}
}
export class PasswordToControllerDialog extends ControllerDialogBase {
constructor(treeDataProvider: AzureArcTreeDataProvider) {
super(treeDataProvider, loc.passwordToController);
}
protected fieldToFocusOn() {
return this.passwordInputBox;
}
protected override readonlyFields(): azdata.Component[] {
return [
this.urlInputBox,
...this.kubeConfigInputBox.items,
...this.clusterContextRadioGroup.items,
this.nameInputBox,
this.usernameInputBox
];
}
public async validate(): Promise<boolean> {
if (!this.passwordInputBox.value) {
return false;
}
const controllerInfo: ControllerInfo = this.getControllerInfo(this.urlInputBox.value!, false);
const controllerModel = new ControllerModel(this.treeDataProvider, controllerInfo, this.passwordInputBox.value);
const azdataApi = <azdataExt.IExtension>vscode.extensions.getExtension(azdataExt.extension.name)?.exports;
try {
await azdataApi.azdata.login(
{
endpoint: controllerInfo.endpoint,
namespace: controllerInfo.namespace
},
controllerInfo.username,
this.passwordInputBox.value,
{
'KUBECONFIG': this.kubeConfigInputBox.value!,
'KUBECTL_CONTEXT': this.clusterContextRadioGroup.value!
}
);
} catch (e) {
if (getErrorMessage(e).match(/Wrong username or password/i)) {
this.dialog.message = {
text: loc.loginFailed,
level: azdata.window.MessageLevel.Error
};
return false;
} else {
this.dialog.message = {
text: loc.errorVerifyingPassword(e),
level: azdata.window.MessageLevel.Error
};
return false;
}
}
this.completionPromise.resolve({ controllerModel: controllerModel, password: this.passwordInputBox.value });
return true;
}
public override showDialog(controllerInfo?: ControllerInfo): azdata.window.Dialog {
const dialog = super.showDialog(controllerInfo);
dialog.okButton.label = loc.ok;
return dialog;
}
}

View File

@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import { ControllerInfo } from 'arc';
import * as azdata from 'azdata';
import * as vscode from 'vscode';
import { ControllerModel } from '../../models/controllerModel';
import { ControllerTreeNode } from './controllerTreeNode';
@@ -18,7 +17,6 @@ const mementoToken = 'arcDataControllers.v2';
*/
export class AzureArcTreeDataProvider implements vscode.TreeDataProvider<TreeNode> {
private _credentialsProvider = azdata.credentials.getProvider('arcControllerPasswords');
private _onDidChangeTreeData: vscode.EventEmitter<TreeNode | undefined> = new vscode.EventEmitter<TreeNode | undefined>();
readonly onDidChangeTreeData: vscode.Event<TreeNode | undefined> = this._onDidChangeTreeData.event;
@@ -51,14 +49,13 @@ export class AzureArcTreeDataProvider implements vscode.TreeDataProvider<TreeNod
return element;
}
public async addOrUpdateController(model: ControllerModel, password: string, refreshTree = true): Promise<void> {
public async addOrUpdateController(model: ControllerModel, refreshTree = true): Promise<void> {
const controllerNode = this.getControllerNode(model);
if (controllerNode) {
controllerNode.model.info = model.info;
} else {
this._controllerNodes.push(new ControllerTreeNode(model, this._context, this));
}
await this.updatePassword(model, password);
if (refreshTree) {
this._onDidChangeTreeData.fire(undefined);
}
@@ -71,22 +68,10 @@ export class AzureArcTreeDataProvider implements vscode.TreeDataProvider<TreeNod
public async removeController(controllerNode: ControllerTreeNode): Promise<void> {
this._controllerNodes = this._controllerNodes.filter(node => node !== controllerNode);
await this.deletePassword(controllerNode.model.info);
this._onDidChangeTreeData.fire(undefined);
await this.saveControllers();
}
public async getPassword(info: ControllerInfo): Promise<string> {
const provider = await this._credentialsProvider;
const credential = await provider.readCredential(info.id);
return credential.password;
}
private async deletePassword(info: ControllerInfo): Promise<void> {
const provider = await this._credentialsProvider;
await provider.deleteCredential(info.id);
}
/**
* Refreshes the specified node, or the entire tree if node is undefined
* @param node The node to refresh, or undefined for the whole tree
@@ -95,15 +80,6 @@ export class AzureArcTreeDataProvider implements vscode.TreeDataProvider<TreeNod
this._onDidChangeTreeData.fire(node);
}
private async updatePassword(model: ControllerModel, password: string): Promise<void> {
const provider = await this._credentialsProvider;
if (model.info.rememberPassword) {
await provider.saveCredential(model.info.id, password);
} else {
await provider.deleteCredential(model.info.id);
}
}
private async loadSavedControllers(): Promise<void> {
try {
const controllerMementos: ControllerInfo[] = this._context.globalState.get(mementoToken) || [];

View File

@@ -39,12 +39,12 @@ export class ControllerTreeNode extends TreeNode {
public override async getChildren(): Promise<TreeNode[]> {
try {
await this.model.refresh(false);
await this.model.refresh(false, this.model.info.namespace);
this.updateChildren(this.model.registrations);
} catch (err) {
vscode.window.showErrorMessage(loc.errorConnectingToController(err));
try {
await this.model.refresh(false);
await this.model.refresh(false, this.model.info.namespace);
this.updateChildren(this.model.registrations);
} catch (err) {
if (!(err instanceof UserCancelledError)) {