mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Enabled Azure Arc data controller upgrade for direct and indirect mode (#19060)
* Fixed a connect to Server typo * Added upgrade tab with description and title. Table is still stuck loading. * Renamed backups to upgrades. * Removed loading icon * Table appearing and not stuck loading * Saving for now to upgrade arc and azcli versions * Added upgrade confirmation dialog, populated dummy data and added upgrade apis. * Added parsing of versions and current version from listupgrades * Upgrade itself not working, but added upgrade as a part of azure cli api. * Table now populating with release dates and version numbers. Upgrade button only shows for appropriate cells. Upgrade done but no release version column. * Changed text using PM advice * Removed comments from controllerUpgrades.ts * Replaced code in upgradecontroller.ts and made refresh work * Removed one call to handleTablesUpdated * Removed some code in upgradeControllers.ts and it still works * removing more code for pitr refresh from upgradeController.ts * Created and used UpgradeModel even though it is empty * Added upgrademodel * PR comments addressed Co-authored-by: Candice Ye <canye@microsoft.com>
This commit is contained in:
@@ -178,6 +178,7 @@ export const enum ConnectionMode {
|
||||
|
||||
export namespace cssStyles {
|
||||
export const text = { 'user-select': 'text', 'cursor': 'text' };
|
||||
export const code = { 'user-select': 'text', 'cursor': 'text', 'font-style': 'italic' };
|
||||
export const title = { ...text, 'font-weight': 'bold', 'font-size': '14px' };
|
||||
export const tableHeader = { ...text, 'text-align': 'left', 'border': 'none' };
|
||||
export const tableRow = { ...text, 'border-top': 'solid 1px #ccc', 'border-bottom': 'solid 1px #ccc', 'border-left': 'none', 'border-right': 'none' };
|
||||
|
||||
@@ -127,7 +127,7 @@ export const indirect = localize('arc.indirect', "Indirect");
|
||||
export const loading = localize('arc.loading', "Loading...");
|
||||
export const refreshToEnterCredentials = localize('arc.refreshToEnterCredentials', "Refresh node to enter credentials");
|
||||
export const noInstancesAvailable = localize('arc.noInstancesAvailable', "No instances available");
|
||||
export const connectToServer = localize('arc.connecToServer', "Connect to Server");
|
||||
export const connectToServer = localize('arc.connectToServer', "Connect to Server");
|
||||
export const connectToController = localize('arc.connectToController', "Connect to Existing Controller");
|
||||
export function connectToMSSql(name: string): string { return localize('arc.connectToMSSql', "Connect to SQL managed instance - Azure Arc ({0})", name); }
|
||||
export function connectToPGSql(name: string): string { return localize('arc.connectToPGSql', "Connect to PostgreSQL Hyperscale - Azure Arc ({0})", name); }
|
||||
@@ -334,4 +334,23 @@ export const userCancelledError = localize('arc.userCancelledError', "User cance
|
||||
export const clusterContextConfigNoLongerValid = (configFile: string, clusterContext: string, error: any) => localize('clusterContextConfigNoLongerValid', "The cluster context information specified by config file: {0} and cluster context: {1} is no longer valid. Error is:\n\t{2}\n Do you want to update this information?", configFile, clusterContext, getErrorMessage(error));
|
||||
export const invalidConfigPath = localize('arc.invalidConfigPath', "Invalid config path");
|
||||
export const loadingClusterContextsError = (error: any): string => localize('arc.loadingClusterContextsError', "Error loading cluster contexts. {0}", getErrorMessage(error));
|
||||
|
||||
// Upgrade
|
||||
export const upgradeManagement = localize('arc.upgradeManagement', "Upgrade Management");
|
||||
export const availableUpgrades = localize('arc.availableUpgrades', "Available Upgrades");
|
||||
export const availableUpgradesDescription = localize('arc.availableUpgradesDescription', "Available upgrades for this resource are listed below. You can apply upgrades by selecting the upgrade button. Learn more about each of these releases at the");
|
||||
export const versionLog = localize('arc.versionLog', "version log.");
|
||||
export const onlyNextImmediateVersion = localize('arc.onlyNextImmediateVersion', "Currently, only upgrading to the next immediate version is supported.");
|
||||
export const version = localize('arc.version', "Version");
|
||||
export const releaseDate = localize('arc.releaseDate', "Release Date");
|
||||
export const releaseNotes = localize('arc.releaseNotes', "Release Notes");
|
||||
export const upgrade = localize('arc.upgrade', "Upgrade");
|
||||
export const upgradeDataController = localize('arc.upgradeDataController', "Upgrade Data Controller");
|
||||
export const areYouSure = localize('arc.areYouSure', "Are you sure you want to apply the selected upgrade?");
|
||||
export const upgradeDialog = localize('arc.upgradeDialog', "During a data controller upgrade, portions of the data control plane such as Custom Resource Definitions (CRDs) and containers may be upgraded. An upgrade of the data controller will not cause downtime for the data services (SQL Managed Instance or PostgreSQL server).");
|
||||
export const monitorUpgrade = localize('arc.monitorUpgrade', "You can check the status of the upgrade by running the following command:");
|
||||
export function errorListingLogAnalyticsWorkspaces(error: any): string { return localize('arc.errorListingLogAnalyticsWorkspaces', "Error listing Log Analytics workspaces {0}", getErrorMessage(error, true)); }
|
||||
export const noUpgrades = localize('arc.noUpgrades', 'The current version is the latest version. No upgrades available.');
|
||||
export const upgrading = localize('arc.upgrading', "Data controller is being upgraded. You can check the status of the upgrade by running the following command: 'kubectl get datacontrollers -A'"); // 'kubectl get datacontrollers -A' should not be localized.
|
||||
export const currentVersion = localize('arc.currentVersion', "Current version");
|
||||
export const releaseDateNotParsed = localize('arc.releaseDateNotParsed', "Release date could not be parsed.");
|
||||
|
||||
@@ -29,6 +29,7 @@ export type PITRModel = {
|
||||
latestPitr: string,
|
||||
destDbName: string
|
||||
};
|
||||
export type UpgradeModel = {};
|
||||
|
||||
export const systemDbs = ['master', 'msdb', 'tempdb', 'model'];
|
||||
export class MiaaModel extends ResourceModel {
|
||||
|
||||
@@ -8,6 +8,7 @@ import { Dashboard } from '../../components/dashboard';
|
||||
import { ControllerModel } from '../../../models/controllerModel';
|
||||
import { ControllerDashboardOverviewPage } from './controllerDashboardOverviewPage';
|
||||
import * as loc from '../../../localizedConstants';
|
||||
import { ControllerUpgradesPage } from './controllerUpgrades';
|
||||
|
||||
export class ControllerDashboard extends Dashboard {
|
||||
|
||||
@@ -23,8 +24,10 @@ export class ControllerDashboard extends Dashboard {
|
||||
|
||||
protected async registerTabs(modelView: azdata.ModelView): Promise<(azdata.DashboardTab | azdata.DashboardTabGroup)[]> {
|
||||
const overviewPage = new ControllerDashboardOverviewPage(modelView, this.dashboard, this._controllerModel);
|
||||
const upgradesPage = new ControllerUpgradesPage(modelView, this.dashboard, this._controllerModel);
|
||||
return [
|
||||
overviewPage.tab
|
||||
overviewPage.tab,
|
||||
upgradesPage.tab
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,287 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as azdata from 'azdata';
|
||||
import * as azExt from 'az-ext';
|
||||
import * as loc from '../../../localizedConstants';
|
||||
import { IconPathHelper, cssStyles, ConnectionMode } from '../../../constants';
|
||||
import { DashboardPage } from '../../components/dashboardPage';
|
||||
import { ControllerModel } from '../../../models/controllerModel';
|
||||
import { UpgradeController } from '../../dialogs/upgradeController';
|
||||
|
||||
export class ControllerUpgradesPage extends DashboardPage {
|
||||
constructor(modelView: azdata.ModelView, dashboard: azdata.window.ModelViewDashboard, private _controllerModel: ControllerModel) {
|
||||
super(modelView, dashboard);
|
||||
this._azApi = vscode.extensions.getExtension(azExt.extension.name)?.exports;
|
||||
}
|
||||
private _upgradesContainer!: azdata.DivContainer;
|
||||
private _configureRetentionPolicyButton!: azdata.ButtonComponent;
|
||||
private _upgradesTableLoading!: azdata.LoadingComponent;
|
||||
private _upgradesTable!: azdata.DeclarativeTableComponent;
|
||||
private _upgradesMessage!: azdata.TextComponent;
|
||||
private readonly _azApi: azExt.IExtension;
|
||||
|
||||
public get title(): string {
|
||||
return loc.upgradeManagement;
|
||||
}
|
||||
|
||||
public get id(): string {
|
||||
return 'upgrades';
|
||||
}
|
||||
|
||||
public get icon(): { dark: string, light: string } {
|
||||
return IconPathHelper.pitr;
|
||||
}
|
||||
protected async refresh(): Promise<void> {
|
||||
await Promise.resolve(this._controllerModel.refresh(false, this._controllerModel.info.namespace));
|
||||
this.handleTableUpdated();
|
||||
}
|
||||
|
||||
public get container(): azdata.Component {
|
||||
const root = this.modelView.modelBuilder.flexContainer()
|
||||
.withLayout({ flexFlow: 'column' })
|
||||
.withProps({ CSSStyles: { 'margin': '18px' } })
|
||||
.component();
|
||||
const content = this.modelView.modelBuilder.divContainer().component();
|
||||
this._upgradesContainer = this.modelView.modelBuilder.divContainer().component();
|
||||
root.addItem(content, { CSSStyles: { 'margin': '5px' } });
|
||||
|
||||
// Upgrades title and description
|
||||
const availableUpgradesTitle = this.modelView.modelBuilder.text().withProps({
|
||||
value: loc.availableUpgrades,
|
||||
CSSStyles: { ...cssStyles.title },
|
||||
}).component();
|
||||
content.addItem(availableUpgradesTitle);
|
||||
|
||||
const infoAvailableUpgrades = this.modelView.modelBuilder.text().withProps({
|
||||
value: loc.availableUpgradesDescription,
|
||||
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'margin-block-end': '0px', 'max-width': 'auto' }
|
||||
}).component();
|
||||
|
||||
const upgradesInfoDescription = this.modelView.modelBuilder.flexContainer()
|
||||
.withLayout({ flexWrap: 'wrap' })
|
||||
.withItems([
|
||||
infoAvailableUpgrades
|
||||
]).component();
|
||||
|
||||
const upgradesVersionLogLink = this.modelView.modelBuilder.hyperlink().withProps({
|
||||
label: loc.versionLog,
|
||||
url: 'https://docs.microsoft.com/en-us/azure/azure-arc/data/version-log',
|
||||
CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px' }
|
||||
}).component();
|
||||
|
||||
const upgradesInfoAndLink = this.modelView.modelBuilder.flexContainer()
|
||||
.withLayout({ flexWrap: 'wrap' })
|
||||
.withItems([
|
||||
upgradesInfoDescription,
|
||||
upgradesVersionLogLink
|
||||
], { CSSStyles: { 'margin-right': '5px' } }).component();
|
||||
|
||||
content.addItem(upgradesInfoAndLink, { CSSStyles: { 'min-height': '30px' } });
|
||||
|
||||
const infoOnlyNextImmediateVersion = this.modelView.modelBuilder.text().withProps({
|
||||
value: loc.onlyNextImmediateVersion,
|
||||
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'margin-block-end': '0px', 'max-width': 'auto' }
|
||||
}).component();
|
||||
|
||||
content.addItem(infoOnlyNextImmediateVersion, { CSSStyles: { 'min-height': '30px' } });
|
||||
|
||||
// Create loaded components
|
||||
this._upgradesTableLoading = this.modelView.modelBuilder.loadingComponent().component();
|
||||
this._upgradesTable = this.modelView.modelBuilder.declarativeTable().withProps({
|
||||
width: '100%',
|
||||
columns: [
|
||||
{
|
||||
displayName: loc.version,
|
||||
valueType: azdata.DeclarativeDataType.string,
|
||||
isReadOnly: true,
|
||||
width: '30%',
|
||||
headerCssStyles: cssStyles.tableHeader,
|
||||
rowCssStyles: cssStyles.tableRow
|
||||
},
|
||||
{
|
||||
displayName: loc.releaseDate,
|
||||
valueType: azdata.DeclarativeDataType.string,
|
||||
isReadOnly: true,
|
||||
width: '30%',
|
||||
headerCssStyles: cssStyles.tableHeader,
|
||||
rowCssStyles: cssStyles.tableRow
|
||||
},
|
||||
{
|
||||
displayName: loc.upgrade,
|
||||
valueType: azdata.DeclarativeDataType.component,
|
||||
isReadOnly: true,
|
||||
width: '10%',
|
||||
headerCssStyles: cssStyles.tableHeader,
|
||||
rowCssStyles: cssStyles.tableRow,
|
||||
}
|
||||
],
|
||||
dataValues: []
|
||||
}).component();
|
||||
|
||||
this._upgradesMessage = this.modelView.modelBuilder.text()
|
||||
.withProps({ CSSStyles: { 'text-align': 'center' } })
|
||||
.component();
|
||||
|
||||
this.handleTableUpdated();
|
||||
this._upgradesTableLoading.component = this._upgradesTable;
|
||||
|
||||
root.addItem(this._upgradesContainer);
|
||||
root.addItem(this._upgradesMessage);
|
||||
|
||||
this.initialized = true;
|
||||
|
||||
this._upgradesTableLoading.loading = false;
|
||||
this._upgradesContainer.addItem(this._upgradesTableLoading, { CSSStyles: { 'margin-bottom': '20px' } });
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
public get toolbarContainer(): azdata.ToolbarContainer {
|
||||
// Refresh
|
||||
const refreshButton = this.modelView.modelBuilder.button().withProps({
|
||||
label: loc.refresh,
|
||||
iconPath: IconPathHelper.refresh
|
||||
}).component();
|
||||
this.disposables.push(
|
||||
refreshButton.onDidClick(async () => {
|
||||
refreshButton.enabled = false;
|
||||
try {
|
||||
await this.refresh();
|
||||
} finally {
|
||||
refreshButton.enabled = true;
|
||||
}
|
||||
}));
|
||||
this._configureRetentionPolicyButton = this.modelView.modelBuilder.button().withProps({
|
||||
label: loc.configureRetentionPolicyButton,
|
||||
enabled: true,
|
||||
iconPath: IconPathHelper.edit,
|
||||
}).component();
|
||||
|
||||
return this.modelView.modelBuilder.toolbarContainer().withToolbarItems(
|
||||
[
|
||||
{ component: refreshButton, toolbarSeparatorAfter: true },
|
||||
{ component: this._configureRetentionPolicyButton, toolbarSeparatorAfter: false },
|
||||
|
||||
]
|
||||
).component();
|
||||
}
|
||||
|
||||
private formatTableData(result: azExt.AzOutput<azExt.DcListUpgradesResult>): (string | azdata.ButtonComponent)[][] {
|
||||
let formattedValues: (string | azdata.ButtonComponent)[][] = [];
|
||||
const versions = result.stdout.versions;
|
||||
const dates = result.stdout.dates;
|
||||
const currentVersion = result.stdout.currentVersion;
|
||||
const nextVersion = this.getNextUpgrade(result.stdout.versions, result.stdout.currentVersion);
|
||||
let currentVersionHit = false;
|
||||
for (let i = 0; i < versions.length; i++) {
|
||||
if (currentVersionHit) {
|
||||
continue;
|
||||
} else {
|
||||
if (versions[i] === currentVersion) {
|
||||
formattedValues.push([versions[i], dates[i], this.createUpgradeButton(loc.currentVersion, false, '')]);
|
||||
currentVersionHit = true;
|
||||
} else if (versions[i] === nextVersion) {
|
||||
formattedValues.push([versions[i], dates[i], this.createUpgradeButton(loc.upgrade, true, nextVersion)]);
|
||||
} else {
|
||||
formattedValues.push([versions[i], dates[i], this.createUpgradeButton(loc.upgrade, false, '')]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return formattedValues;
|
||||
}
|
||||
|
||||
private async handleTableUpdated(): Promise<void> {
|
||||
const result = await this._azApi.az.arcdata.dc.listUpgrades(this._controllerModel.info.namespace);
|
||||
let tableDisplay = this.formatTableData(result);
|
||||
let tableValues = tableDisplay.map(d => {
|
||||
return d.map((value: any): azdata.DeclarativeTableCellValue => {
|
||||
return { value: value };
|
||||
});
|
||||
});
|
||||
|
||||
this._upgradesTable.setDataValues(tableValues);
|
||||
this._upgradesTableLoading.loading = false;
|
||||
this._upgradesContainer.addItem(this._upgradesTableLoading, { CSSStyles: { 'margin-bottom': '20px' } });
|
||||
}
|
||||
|
||||
// Given the list of available versions and the current version, if the current version is not the latest,
|
||||
// then return the next version available. (Can only upgrade to next version due to limitations by Azure CLI arcdata extension.)
|
||||
// If current version is the latest, then return undefined.
|
||||
private getNextUpgrade(versions: string[], currentVersion: string): string | undefined {
|
||||
let index = versions.indexOf(currentVersion);
|
||||
// The version at index 0 will be the latest
|
||||
if (index > 0) {
|
||||
return versions[index - 1];
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
//Create restore button for every database entry in the database table
|
||||
private createUpgradeButton(label: string, enabled: boolean, nextVersion: string): azdata.ButtonComponent | string {
|
||||
let upgradeButton = this.modelView.modelBuilder.button().withProps({
|
||||
label: label,
|
||||
enabled: enabled
|
||||
}).component();
|
||||
|
||||
this.disposables.push(
|
||||
upgradeButton.onDidClick(async () => {
|
||||
const upgradeDialog = new UpgradeController(this._controllerModel);
|
||||
upgradeDialog.showDialog(loc.upgradeDataController);
|
||||
let dialogClosed = await upgradeDialog.waitForClose();
|
||||
if (dialogClosed) {
|
||||
try {
|
||||
upgradeButton.enabled = false;
|
||||
vscode.window.showInformationMessage(loc.upgrading);
|
||||
await vscode.window.withProgress(
|
||||
{
|
||||
location: vscode.ProgressLocation.Notification,
|
||||
title: loc.updatingInstance(this._controllerModel.info.name),
|
||||
cancellable: false
|
||||
},
|
||||
async (_progress, _token): Promise<void> => {
|
||||
if (nextVersion !== '') {
|
||||
if (this._controllerModel.info.connectionMode === ConnectionMode.direct) {
|
||||
await this._azApi.az.arcdata.dc.upgrade(
|
||||
nextVersion,
|
||||
this._controllerModel.info.name,
|
||||
this._controllerModel.info.resourceGroup,
|
||||
undefined, // Indirect mode argument - namespace
|
||||
undefined // Indirect mode argument - usek8s
|
||||
);
|
||||
} else {
|
||||
await this._azApi.az.arcdata.dc.upgrade(
|
||||
nextVersion,
|
||||
this._controllerModel.info.name,
|
||||
undefined, // Direct mode argument - resourceGroup
|
||||
this._controllerModel.info.namespace,
|
||||
true
|
||||
);
|
||||
}
|
||||
} else {
|
||||
vscode.window.showInformationMessage(loc.noUpgrades);
|
||||
}
|
||||
|
||||
try {
|
||||
await this._controllerModel.refresh(false, this._controllerModel.info.namespace);
|
||||
} catch (error) {
|
||||
vscode.window.showErrorMessage(loc.refreshFailed(error));
|
||||
}
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
vscode.window.showErrorMessage(loc.updateExtensionsFailed(error));
|
||||
} finally {
|
||||
this._configureRetentionPolicyButton.enabled = true;
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
return upgradeButton;
|
||||
}
|
||||
}
|
||||
|
||||
93
extensions/arc/src/ui/dialogs/upgradeController.ts
Normal file
93
extensions/arc/src/ui/dialogs/upgradeController.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { Deferred } from '../../common/promise';
|
||||
import * as loc from '../../localizedConstants';
|
||||
import * as vscode from 'vscode';
|
||||
import { cssStyles } from '../../constants';
|
||||
import { InitializingComponent } from '../components/initializingComponent';
|
||||
import { UpgradeModel } from '../../models/miaaModel';
|
||||
import { ControllerModel } from '../../models/controllerModel';
|
||||
|
||||
export class UpgradeController extends InitializingComponent {
|
||||
protected modelBuilder!: azdata.ModelBuilder;
|
||||
private pitrSettings: UpgradeModel = [];
|
||||
|
||||
protected _completionPromise = new Deferred<UpgradeModel | undefined>();
|
||||
protected disposables: vscode.Disposable[] = [];
|
||||
constructor(protected _controllerModel: ControllerModel) {
|
||||
super();
|
||||
}
|
||||
|
||||
public showDialog(dialogTitle: string): azdata.window.Dialog {
|
||||
const dialog = azdata.window.createModelViewDialog(dialogTitle, dialogTitle, 'narrow', 'flyout');
|
||||
dialog.cancelButton.onClick(() => this.handleCancel());
|
||||
dialog.registerContent(async view => {
|
||||
this.modelBuilder = view.modelBuilder;
|
||||
const areYouSure = this.modelBuilder.text().withProps({
|
||||
value: loc.areYouSure,
|
||||
CSSStyles: { ...cssStyles.title, 'margin-block-start': '0px', 'margin-block-end': '0px', 'max-width': 'auto' },
|
||||
}).component();
|
||||
const areYouSureInfo = this.modelBuilder.text().withProps({
|
||||
value: loc.upgradeDialog,
|
||||
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'max-width': 'auto' }
|
||||
}).component();
|
||||
const upgradeDialog = this.modelBuilder.flexContainer().withLayout({ flexWrap: 'wrap' }).component();
|
||||
|
||||
upgradeDialog.addItem(areYouSureInfo, { CSSStyles: { 'margin-right': '5px' } });
|
||||
|
||||
const monitorUpgradeInfo = this.modelBuilder.text().withProps({
|
||||
value: loc.monitorUpgrade,
|
||||
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'max-width': 'auto' }
|
||||
}).component();
|
||||
|
||||
upgradeDialog.addItem(monitorUpgradeInfo, { CSSStyles: { 'margin-right': '5px' } });
|
||||
|
||||
const monitorUpgradeCommandInfo = this.modelBuilder.text().withProps({
|
||||
value: 'kubectl get datacontrollers -A',
|
||||
CSSStyles: { ...cssStyles.code, 'margin-block-start': '0px', 'max-width': 'auto' }
|
||||
}).component();
|
||||
|
||||
upgradeDialog.addItem(monitorUpgradeCommandInfo, { CSSStyles: { 'margin-right': '5px' } });
|
||||
|
||||
let formModel = this.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
components: [
|
||||
{
|
||||
component: areYouSure
|
||||
},
|
||||
{
|
||||
component: upgradeDialog
|
||||
}
|
||||
],
|
||||
title: ''
|
||||
}]).withLayout({ width: '100%' }).component();
|
||||
await view.initializeModel(formModel);
|
||||
this.initialized = true;
|
||||
});
|
||||
|
||||
dialog.okButton.label = loc.upgrade;
|
||||
dialog.cancelButton.label = loc.cancel;
|
||||
dialog.registerCloseValidator(async () => await this.validate());
|
||||
dialog.okButton.onClick(() => {
|
||||
this._completionPromise.resolve(this.pitrSettings);
|
||||
});
|
||||
azdata.window.openDialog(dialog);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public async validate(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
private handleCancel(): void {
|
||||
this._completionPromise.resolve(undefined);
|
||||
}
|
||||
|
||||
public waitForClose(): Promise<UpgradeModel | undefined> {
|
||||
return this._completionPromise.promise;
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,23 @@ export function getAzApi(localAzDiscovered: Promise<IAzTool | undefined>, azTool
|
||||
validateAz(azToolService.localAz);
|
||||
return azToolService.localAz!.arcdata.dc.config.show(namespace, additionalEnvVars);
|
||||
}
|
||||
},
|
||||
listUpgrades: async (namespace: string, usek8s?: boolean, additionalEnvVars?: azExt.AdditionalEnvVars) => {
|
||||
await localAzDiscovered;
|
||||
validateAz(azToolService.localAz);
|
||||
return azToolService.localAz!.arcdata.dc.listUpgrades(namespace, usek8s, additionalEnvVars);
|
||||
},
|
||||
upgrade: async (
|
||||
desiredVersion: string,
|
||||
name: string,
|
||||
resourceGroup?: string,
|
||||
namespace?: string,
|
||||
usek8s?: boolean,
|
||||
additionalEnvVars?: azExt.AdditionalEnvVars
|
||||
) => {
|
||||
await localAzDiscovered;
|
||||
validateAz(azToolService.localAz);
|
||||
return azToolService.localAz!.arcdata.dc.upgrade(desiredVersion, name, resourceGroup, namespace, usek8s, additionalEnvVars);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -90,6 +90,37 @@ export class AzTool implements azExt.IAzApi {
|
||||
show: (namespace: string, additionalEnvVars?: azExt.AdditionalEnvVars): Promise<azExt.AzOutput<azExt.DcConfigShowResult>> => {
|
||||
return this.executeCommand<azExt.DcConfigShowResult>(['arcdata', 'dc', 'config', 'show', '--k8s-namespace', namespace, '--use-k8s'], additionalEnvVars);
|
||||
}
|
||||
},
|
||||
listUpgrades: async (namespace: string, usek8s?: boolean, additionalEnvVars?: azExt.AdditionalEnvVars): Promise<azExt.AzOutput<azExt.DcListUpgradesResult>> => {
|
||||
const argsArray = ['arcdata', 'dc', 'list-upgrades'];
|
||||
if (namespace) { argsArray.push('--k8s-namespace', namespace); }
|
||||
if (usek8s) { argsArray.push('--use-k8s'); }
|
||||
|
||||
const output = await this.executeCommand<string>(argsArray, additionalEnvVars);
|
||||
const versions = <string[]>parseDcListUpgrades(output.stdout);
|
||||
const currentVersion = <string>parseCurrentVersion(output.stdout);
|
||||
let dates: string[] = [];
|
||||
for (let i = 0; i < versions.length; i++) {
|
||||
dates.push(parseReleaseDateFromUpgrade(versions[i]));
|
||||
}
|
||||
return {
|
||||
stdout: {
|
||||
versions: versions,
|
||||
currentVersion: currentVersion,
|
||||
dates: dates
|
||||
},
|
||||
stderr: output.stderr
|
||||
};
|
||||
},
|
||||
upgrade: (desiredVersion: string, name: string, resourceGroup?: string, namespace?: string, usek8s?: boolean, additionalEnvVars?: azExt.AdditionalEnvVars): Promise<azExt.AzOutput<void>> => {
|
||||
const argsArray = ['arcdata', 'dc', 'upgrade', '--desired-version', desiredVersion, '--name', name];
|
||||
// Direct mode argument
|
||||
if (resourceGroup) { argsArray.push('--resource-group', resourceGroup); }
|
||||
// Indirect mode arguments
|
||||
|
||||
if (namespace) { argsArray.push('--k8s-namespace', namespace); }
|
||||
if (usek8s) { argsArray.push('--use-k8s'); }
|
||||
return this.executeCommand<void>(argsArray, additionalEnvVars);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -556,6 +587,70 @@ function parseArcExtensionVersion(raw: string): string | undefined {
|
||||
return exp.exec(raw)?.pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses out all available upgrades
|
||||
* @param raw The raw version output from az arcdata dc list-upgrades
|
||||
*/
|
||||
function parseDcListUpgrades(raw: string): string[] | undefined {
|
||||
// Currently the version is a multi-line string that contains other version information such
|
||||
// as the Python installation, with the first line holding the version of az itself.
|
||||
//
|
||||
// Found 6 valid versions. The current datacontroller version is v1.2.0_2021-12-15.
|
||||
// v1.4.1_2022-03-08
|
||||
// v1.4.0_2022-02-25
|
||||
// v1.3.0_2022-01-27
|
||||
// v1.2.0_2021-12-15 << current version
|
||||
// v1.1.0_2021-11-02
|
||||
// v1.0.0_2021-07-30
|
||||
let versions: string[] = [];
|
||||
const lines = raw.split('\n');
|
||||
const exp = /^(v\d*.\d*.\d*.\d*.\d*.\d*.\d)/;
|
||||
for (let i = 1; i < lines.length; i++) {
|
||||
let result = exp.exec(lines[i])?.pop();
|
||||
if (result) {
|
||||
versions.push(result);
|
||||
}
|
||||
}
|
||||
return versions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses out the release date from the upgrade version number and formats it into MM/DD/YYYY format.
|
||||
* For example: v1.4.1_2022-03-08 ==> 03/08/2022
|
||||
* @param raw The raw upgrade version number, such as: v1.4.1_2022-03-08
|
||||
*/
|
||||
function parseReleaseDateFromUpgrade(raw: string): string {
|
||||
let formattedDate = '';
|
||||
const exp = /^v\d*.\d*.\d*_(\d*).(\d*).(\d*.\d)/;
|
||||
let rawDate = exp.exec(raw);
|
||||
if (rawDate) {
|
||||
formattedDate += rawDate[2] + '/' + rawDate[3] + '/' + rawDate[1];
|
||||
} else {
|
||||
console.error(loc.releaseDateNotParsed);
|
||||
}
|
||||
return formattedDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses out the current version number out of all available upgrades
|
||||
* @param raw The raw version output from az arcdata dc list-upgrades
|
||||
*/
|
||||
function parseCurrentVersion(raw: string): string | undefined {
|
||||
// Currently the version is a multi-line string that contains other version information such
|
||||
// as the Python installation, with the first line holding the version of az itself.
|
||||
//
|
||||
// Found 6 valid versions. The current datacontroller version is v1.2.0_2021-12-15.
|
||||
// v1.4.1_2022-03-08
|
||||
// v1.4.0_2022-02-25
|
||||
// v1.3.0_2022-01-27
|
||||
// v1.2.0_2021-12-15 << current version
|
||||
// v1.1.0_2021-11-02
|
||||
// v1.0.0_2021-07-30
|
||||
|
||||
const exp = /The current datacontroller version is\s*(v\d*.\d*.\d*.\d*.\d*.\d*.\d)/;
|
||||
return exp.exec(raw)?.pop();
|
||||
}
|
||||
|
||||
async function executeAzCommand(command: string, args: string[], additionalEnvVars: azExt.AdditionalEnvVars = {}): Promise<ProcessOutput> {
|
||||
const debug = vscode.workspace.getConfiguration(azConfigSection).get(debugConfigKey);
|
||||
if (debug) {
|
||||
|
||||
@@ -72,3 +72,4 @@ export const userResponseToInstallPrompt = (response: string | undefined): strin
|
||||
export const userResponseToUpdatePrompt = (response: string | undefined): string => localize('az.userResponseUpdate', "User Response on prompt to update Azure CLI: {0}", response);
|
||||
export const userRequestedInstall = localize('az.userRequestedInstall', "User requested to install Azure CLI and arcdata extension using 'Azure CLI: Install' command");
|
||||
export const updateCheckSkipped = localize('az.updateCheckSkipped', "No check for new Azure CLI version availability performed as Azure CLI was not found to be installed");
|
||||
export const releaseDateNotParsed = localize('arc.releaseDateNotParsed', "Release date could not be parsed.");
|
||||
|
||||
10
extensions/azcli/src/typings/az-ext.d.ts
vendored
10
extensions/azcli/src/typings/az-ext.d.ts
vendored
@@ -116,6 +116,12 @@ declare module 'az-ext' {
|
||||
}
|
||||
}
|
||||
|
||||
export interface DcListUpgradesResult {
|
||||
versions: string[], // ["v1.4.1_2022-03-08", "v1.4.0_2022-02-25"]
|
||||
currentVersion: string, // "v1.4.1_2022-03-08"
|
||||
dates: string[] // ["03/08/2022", "02/25/2022"]
|
||||
}
|
||||
|
||||
export interface StorageVolume {
|
||||
className?: string, // "local-storage"
|
||||
size: string // "5Gi"
|
||||
@@ -332,7 +338,9 @@ declare module 'az-ext' {
|
||||
config: {
|
||||
list(additionalEnvVars?: AdditionalEnvVars): Promise<AzOutput<DcConfigListResult[]>>,
|
||||
show(namespace?: string, additionalEnvVars?: AdditionalEnvVars): Promise<AzOutput<DcConfigShowResult>>
|
||||
}
|
||||
},
|
||||
listUpgrades(namespace: string, usek8s?: boolean, additionalEnvVars?: AdditionalEnvVars): Promise<AzOutput<DcListUpgradesResult>>,
|
||||
upgrade(desiredVersion: string, name: string, resourceGroup?: string, namespace?: string, usek8s?: boolean, additionalEnvVars?: AdditionalEnvVars): Promise<AzOutput<void>>,
|
||||
}
|
||||
},
|
||||
postgres: {
|
||||
|
||||
Reference in New Issue
Block a user