mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Add SQL MIAA Upgrade Management tab (#19238)
* Added sql upgrade management page and fixed icon for dc and sql upgrade * Added logic for figuring out MIAA version, loading proper entries for table. * Added PR comment changes Co-authored-by: Candice Ye <canye@microsoft.com>
This commit is contained in:
16
extensions/arc/images/upgrade.svg
Normal file
16
extensions/arc/images/upgrade.svg
Normal file
@@ -0,0 +1,16 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18">
|
||||
<defs>
|
||||
<linearGradient id="a8a99b72-4483-4aed-9c09-505d227627b7" x1="9" y1="778.831" x2="9" y2="790.831" gradientTransform="matrix(1, 0, 0, -1, 0, 791.516)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#0078d4" />
|
||||
<stop offset="0.82" stop-color="#5ea0ef" />
|
||||
</linearGradient>
|
||||
<linearGradient id="ab11b5a0-213c-48d8-9a74-d2a9e98a4058" x1="9" y1="774.201" x2="9" y2="778.831" gradientTransform="matrix(1, 0, 0, -1, 0, 791.516)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#ccc" />
|
||||
<stop offset="1" stop-color="#707070" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect y="0.685" width="18" height="12" rx="0.6" fill="url(#a8a99b72-4483-4aed-9c09-505d227627b7)" />
|
||||
<path d="M12.61,16.315c-1.78-.28-1.85-1.56-1.85-3.63H7.23c0,2.07-.06,3.35-1.84,3.63a1,1,0,0,0-.89,1h9A1,1,0,0,0,12.61,16.315Z" fill="url(#ab11b5a0-213c-48d8-9a74-d2a9e98a4058)" />
|
||||
<path d="M4.939,6.782l0,2.588a.147.147,0,0,0,.147.147.149.149,0,0,0,.086-.028l.712-.512A4.174,4.174,0,0,0,7.506,10.3a4.084,4.084,0,0,0,1.674.361,3.909,3.909,0,0,0,.684-.06,3.993,3.993,0,0,0,1.123-.369,3.848,3.848,0,0,0,.952-.677,3.917,3.917,0,0,0,1.108-1.983.224.224,0,0,0-.153-.261.216.216,0,0,0-.066-.01.223.223,0,0,0-.214.158v0A3.372,3.372,0,0,1,11.52,9.079a3.186,3.186,0,0,1-1.762.712c-.093.009-.186.013-.278.013a3.161,3.161,0,0,1-1.531-.4,3.106,3.106,0,0,1-1.135-1.1l.99-.712a.147.147,0,0,0-.048-.261L5.123,6.641a.128.128,0,0,0-.038,0A.146.146,0,0,0,4.939,6.782Z" fill="#fff" opacity="0.8" />
|
||||
<path d="M13.065,6.628V4.041a.148.148,0,0,0-.148-.147.146.146,0,0,0-.085.028l-.67.484a4.193,4.193,0,0,0-1.7-1.357,4.114,4.114,0,0,0-1.618-.335A3.929,3.929,0,0,0,4.962,5.857a.2.2,0,0,0,.136.227.225.225,0,0,0,.058.008.2.2,0,0,0,.188-.139v0a3.4,3.4,0,0,1,1.1-1.632A3.213,3.213,0,0,1,8.2,3.607c.094-.009.188-.014.281-.014a3.13,3.13,0,0,1,1.517.4,3.052,3.052,0,0,1,1.154,1.143l-.957.69a.147.147,0,0,0,.049.261l2.634.687a.122.122,0,0,0,.037.005A.147.147,0,0,0,13.065,6.628Z" fill="#fff" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
@@ -35,6 +35,7 @@ export class IconPathHelper {
|
||||
public static properties: IconPath;
|
||||
public static networking: IconPath;
|
||||
public static pitr: IconPath;
|
||||
public static upgrade: IconPath;
|
||||
public static refresh: IconPath;
|
||||
public static reset: IconPath;
|
||||
public static support: IconPath;
|
||||
@@ -160,6 +161,10 @@ export class IconPathHelper {
|
||||
light: context.asAbsolutePath('images/pitr.svg'),
|
||||
dark: context.asAbsolutePath('images/pitr.svg'),
|
||||
};
|
||||
IconPathHelper.upgrade = {
|
||||
light: context.asAbsolutePath('images/upgrade.svg'),
|
||||
dark: context.asAbsolutePath('images/upgrade.svg'),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -341,15 +341,21 @@ export const availableUpgrades = localize('arc.availableUpgrades', "Available Up
|
||||
export const availableUpgradesDescription = localize('arc.availableUpgradesDescription', "Available upgrades for this resource are listed below. You can apply upgrades by clicking the upgrade button.");
|
||||
export const versionLog = localize('arc.versionLog', "Learn more about each release here.");
|
||||
export const onlyNextImmediateVersion = localize('arc.onlyNextImmediateVersion', "Currently, only upgrading to the next immediate version is supported.");
|
||||
export const onlyNextImmediateVersionMiaa = localize('arc.onlyNextImmediateVersionMiaa', "The version of a SQL Managed Instance can not be newer than the version of its data controller. 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 upgradeMiaa = localize('arc.upgradeMiaa', "Upgrade SQL Managed Instance");
|
||||
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 upgradeDialogController = localize('arc.upgradeDialogController', "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 upgradeDialogMiaa = localize('arc.upgradeDialogMiaa', "During a SQL managed instance upgrade, portions of the data control plane such as Custom Resource Definitions (CRDs) and containers may be upgraded. An upgrade of the SQL managed instance 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 function upgradingController(param: any): string { return localize('arc.upgradingController', "Data controller is being upgraded. You can check the status of the upgrade by running the following command: 'kubectl get datacontrollers -A'", param); }
|
||||
export function upgradingMiaa(param: any): string { return localize('arc.upgradingMiaa', "SQL managed instance is being upgraded. You can check the status of the upgrade by running the following command: 'kubectl get sqlmi -A'", param); }
|
||||
export const currentVersion = localize('arc.currentVersion', "Current version");
|
||||
export const showMiaaError = localize('arc.showMiaaError', "Error showing details of SQL managed instance.");
|
||||
export const miaaVersionError = localize('arc.miaaVersionError', "Error getting SQL managed instance version number.");
|
||||
|
||||
@@ -15,6 +15,7 @@ import { ConnectToMiaaSqlDialog } from '../ui/dialogs/connectMiaaDialog';
|
||||
import { AzureArcTreeDataProvider } from '../ui/tree/azureArcTreeDataProvider';
|
||||
import { ControllerModel, Registration } from './controllerModel';
|
||||
import { ResourceModel } from './resourceModel';
|
||||
import { ConnectionMode } from '../constants';
|
||||
|
||||
export type DatabaseModel = { name: string, status: string, earliestBackup: string, lastBackup: string };
|
||||
export type RPModel = { recoveryPointObjective: string, retentionDays: string };
|
||||
@@ -98,7 +99,26 @@ export class MiaaModel extends ResourceModel {
|
||||
this._refreshPromise = new Deferred();
|
||||
try {
|
||||
try {
|
||||
const result = await this._azApi.az.sql.miarc.show(this.info.name, this.controllerModel.info.namespace, this.controllerModel.azAdditionalEnvVars);
|
||||
let result;
|
||||
if (this.controllerModel.info.connectionMode === ConnectionMode.direct) {
|
||||
result = await this._azApi.az.sql.miarc.show(
|
||||
this.info.name,
|
||||
{
|
||||
resourceGroup: this.controllerModel.info.resourceGroup,
|
||||
namespace: undefined
|
||||
},
|
||||
this.controllerModel.azAdditionalEnvVars
|
||||
);
|
||||
} else {
|
||||
result = await this._azApi.az.sql.miarc.show(
|
||||
this.info.name,
|
||||
{
|
||||
resourceGroup: undefined,
|
||||
namespace: this.controllerModel.info.namespace
|
||||
},
|
||||
this.controllerModel.azAdditionalEnvVars
|
||||
);
|
||||
}
|
||||
this._config = result.stdout;
|
||||
this.configLastUpdated = new Date();
|
||||
this.rpSettings.retentionDays = this._config?.spec?.backup?.retentionPeriodInDays?.toString() ?? '';
|
||||
|
||||
@@ -32,7 +32,7 @@ export class ControllerUpgradesPage extends DashboardPage {
|
||||
}
|
||||
|
||||
public get icon(): { dark: string, light: string } {
|
||||
return IconPathHelper.pitr;
|
||||
return IconPathHelper.upgrade;
|
||||
}
|
||||
protected async refresh(): Promise<void> {
|
||||
await Promise.resolve(this._controllerModel.refresh(false, this._controllerModel.info.namespace));
|
||||
@@ -161,20 +161,19 @@ export class ControllerUpgradesPage extends DashboardPage {
|
||||
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;
|
||||
const nextVersion = this.getNextVersion(versions, currentVersion);
|
||||
|
||||
// Iterate through all data controller versions from latest to oldest and stop when the loop reaches the current version.
|
||||
// Only makes table entries for the current version and newer. The upgrade button will only be enabled for the very next
|
||||
// version due to Azure CLI constraints.
|
||||
for (let i = 0; i < versions.length; i++) {
|
||||
if (currentVersionHit) {
|
||||
continue;
|
||||
if (versions[i] === currentVersion) {
|
||||
formattedValues.push([versions[i], dates[i], this.createUpgradeButton(loc.currentVersion, false, '')]);
|
||||
break;
|
||||
} else if (versions[i] === nextVersion) {
|
||||
formattedValues.push([versions[i], dates[i], this.createUpgradeButton(loc.upgrade, true, nextVersion)]);
|
||||
} 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, '')]);
|
||||
}
|
||||
formattedValues.push([versions[i], dates[i], this.createUpgradeButton(loc.upgrade, false, '')]);
|
||||
}
|
||||
}
|
||||
return formattedValues;
|
||||
@@ -194,12 +193,12 @@ export class ControllerUpgradesPage extends DashboardPage {
|
||||
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 {
|
||||
// Given the list of available versions and the current version, if the current version is not the newest,
|
||||
// then return the next version available. List of versions is ordered newest to oldest.
|
||||
// If current version is the newest, then return undefined.
|
||||
private getNextVersion(versions: string[], currentVersion: string): string | undefined {
|
||||
let index = versions.indexOf(currentVersion);
|
||||
// The version at index 0 will be the latest
|
||||
// The version at index 0 will be the newest
|
||||
if (index > 0) {
|
||||
return versions[index - 1];
|
||||
} else {
|
||||
@@ -222,12 +221,12 @@ export class ControllerUpgradesPage extends DashboardPage {
|
||||
if (dialogClosed) {
|
||||
try {
|
||||
upgradeButton.enabled = false;
|
||||
vscode.window.showInformationMessage(loc.upgrading);
|
||||
vscode.window.showInformationMessage(loc.upgradingController('kubectl get datacontrollers -A\' should not be localized.'));
|
||||
await vscode.window.withProgress(
|
||||
{
|
||||
location: vscode.ProgressLocation.Notification,
|
||||
title: loc.updatingInstance(this._controllerModel.info.name),
|
||||
cancellable: false
|
||||
cancellable: true
|
||||
},
|
||||
async (_progress, _token): Promise<void> => {
|
||||
if (nextVersion !== '') {
|
||||
|
||||
@@ -12,6 +12,7 @@ import { MiaaConnectionStringsPage } from './miaaConnectionStringsPage';
|
||||
import { MiaaModel } from '../../../models/miaaModel';
|
||||
import { MiaaComputeAndStoragePage } from './miaaComputeAndStoragePage';
|
||||
import { MiaaBackupsPage } from './miaaBackupsPage';
|
||||
import { MiaaUpgradeManagementPage } from './miaaUpgradeManagementPage';
|
||||
|
||||
export class MiaaDashboard extends Dashboard {
|
||||
|
||||
@@ -31,6 +32,7 @@ export class MiaaDashboard extends Dashboard {
|
||||
const connectionStringsPage = new MiaaConnectionStringsPage(modelView, this.dashboard, this._miaaModel);
|
||||
const computeAndStoragePage = new MiaaComputeAndStoragePage(modelView, this.dashboard, this._miaaModel);
|
||||
const miaaBackupsPage = new MiaaBackupsPage(modelView, this.dashboard, this._controllerModel, this._miaaModel);
|
||||
const upgradeManagementPage = new MiaaUpgradeManagementPage(modelView, this.dashboard, this._controllerModel, this._miaaModel);
|
||||
return [
|
||||
overviewPage.tab,
|
||||
{
|
||||
@@ -38,7 +40,8 @@ export class MiaaDashboard extends Dashboard {
|
||||
tabs: [
|
||||
connectionStringsPage.tab,
|
||||
computeAndStoragePage.tab,
|
||||
miaaBackupsPage.tab
|
||||
miaaBackupsPage.tab,
|
||||
upgradeManagementPage.tab
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
@@ -0,0 +1,307 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { UpgradeSqlMiaa } from '../../dialogs/upgradeSqlMiaa';
|
||||
import { MiaaModel } from '../../../models/miaaModel';
|
||||
|
||||
export class MiaaUpgradeManagementPage extends DashboardPage {
|
||||
constructor(modelView: azdata.ModelView, dashboard: azdata.window.ModelViewDashboard, private _controllerModel: ControllerModel, private _miaaModel: MiaaModel) {
|
||||
super(modelView, dashboard);
|
||||
this._azApi = vscode.extensions.getExtension(azExt.extension.name)?.exports;
|
||||
}
|
||||
private _upgradesContainer!: azdata.DivContainer;
|
||||
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.upgrade;
|
||||
}
|
||||
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' }
|
||||
}).component();
|
||||
|
||||
const upgradesVersionLogLink = this.modelView.modelBuilder.hyperlink().withProps({
|
||||
label: loc.versionLog,
|
||||
url: 'https://docs.microsoft.com/azure/azure-arc/data/upgrade-sql-managed-instance-direct-cli?WT.mc_id=Portal-Microsoft_Azure_HybridData_Platform'
|
||||
}).component();
|
||||
|
||||
const upgradesInfoAndLink = this.modelView.modelBuilder.flexContainer()
|
||||
.withLayout({ flexWrap: 'wrap' })
|
||||
.withItems([
|
||||
infoAvailableUpgrades,
|
||||
upgradesVersionLogLink
|
||||
], { CSSStyles: { 'margin-right': '5px' } }).component();
|
||||
|
||||
content.addItem(upgradesInfoAndLink, { CSSStyles: { 'min-height': '30px' } });
|
||||
|
||||
const infoOnlyNextImmediateVersion = this.modelView.modelBuilder.text().withProps({
|
||||
value: loc.onlyNextImmediateVersionMiaa,
|
||||
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;
|
||||
}
|
||||
}));
|
||||
|
||||
return this.modelView.modelBuilder.toolbarContainer().withToolbarItems(
|
||||
[
|
||||
{ component: refreshButton, toolbarSeparatorAfter: true },
|
||||
|
||||
]
|
||||
).component();
|
||||
}
|
||||
|
||||
private async getMiaaVersion(): Promise<string | undefined> {
|
||||
try {
|
||||
let miaaShowResult;
|
||||
if (this._controllerModel.info.connectionMode === ConnectionMode.direct) {
|
||||
miaaShowResult = await this._azApi.az.sql.miarc.show(
|
||||
this._miaaModel.info.name,
|
||||
{
|
||||
resourceGroup: this._controllerModel.info.resourceGroup,
|
||||
namespace: undefined
|
||||
},
|
||||
this._controllerModel.azAdditionalEnvVars
|
||||
);
|
||||
} else {
|
||||
miaaShowResult = await this._azApi.az.sql.miarc.show(
|
||||
this._miaaModel.info.name,
|
||||
{
|
||||
resourceGroup: undefined,
|
||||
namespace: this._controllerModel.info.namespace
|
||||
},
|
||||
this._controllerModel.azAdditionalEnvVars
|
||||
);
|
||||
}
|
||||
return miaaShowResult.stdout.status.runningVersion;
|
||||
} catch (e) {
|
||||
console.error(loc.showMiaaError, e);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private async formatTableData(result: azExt.AzOutput<azExt.DcListUpgradesResult>): Promise<(string | azdata.ButtonComponent)[][]> {
|
||||
let formattedValues: (string | azdata.ButtonComponent)[][] = [];
|
||||
|
||||
const versions = result.stdout.versions;
|
||||
const dates = result.stdout.dates;
|
||||
|
||||
const currentControllerVersion = result.stdout.currentVersion;
|
||||
|
||||
const currentMiaaVersion = await this.getMiaaVersion();
|
||||
const nextMiaaVersion = currentMiaaVersion ? this.getNextVersion(versions, currentMiaaVersion) : console.error(loc.miaaVersionError);
|
||||
|
||||
if (currentMiaaVersion === currentControllerVersion) {
|
||||
for (let i = 0; i < versions.length; i++) {
|
||||
if (versions[i] === currentMiaaVersion) {
|
||||
formattedValues.push([versions[i], dates[i], this.createUpgradeButton(loc.currentVersion, false)]);
|
||||
break;
|
||||
} else {
|
||||
formattedValues.push([versions[i], dates[i], this.createUpgradeButton(loc.upgrade, false)]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < versions.length; i++) {
|
||||
if (versions[i] === nextMiaaVersion) {
|
||||
formattedValues.push([versions[i], dates[i], this.createUpgradeButton(loc.upgrade, true)]);
|
||||
formattedValues.push([versions[i + 1], dates[i + 1], this.createUpgradeButton(loc.currentVersion, false)]);
|
||||
break;
|
||||
} 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 = await 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 newest,
|
||||
// then return the next version available. List of versions is ordered newest to oldest.
|
||||
// If current version is the newest, then return undefined.
|
||||
private getNextVersion(versions: string[], currentVersion: string): string | undefined {
|
||||
let index = versions.indexOf(currentVersion);
|
||||
// The version at index 0 will be the newest
|
||||
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): azdata.ButtonComponent | string {
|
||||
let upgradeButton = this.modelView.modelBuilder.button().withProps({
|
||||
label: label,
|
||||
enabled: enabled
|
||||
}).component();
|
||||
|
||||
this.disposables.push(
|
||||
upgradeButton.onDidClick(async () => {
|
||||
const upgradeDialog = new UpgradeSqlMiaa(this._controllerModel);
|
||||
upgradeDialog.showDialog(loc.upgradeMiaa);
|
||||
let dialogClosed = await upgradeDialog.waitForClose();
|
||||
if (dialogClosed) {
|
||||
try {
|
||||
upgradeButton.enabled = false;
|
||||
vscode.window.showInformationMessage(loc.upgradingMiaa('kubectl get sqlmi -A\' should not be localized.'));
|
||||
await vscode.window.withProgress(
|
||||
{
|
||||
location: vscode.ProgressLocation.Notification,
|
||||
title: loc.updatingInstance(this._miaaModel.info.name),
|
||||
cancellable: true
|
||||
},
|
||||
async (_progress, _token): Promise<void> => {
|
||||
if (this._controllerModel.info.connectionMode === ConnectionMode.direct) {
|
||||
await this._azApi.az.sql.miarc.upgrade(
|
||||
this._miaaModel.info.name,
|
||||
{
|
||||
resourceGroup: this._controllerModel.info.resourceGroup,
|
||||
namespace: undefined
|
||||
}
|
||||
);
|
||||
} else {
|
||||
await this._azApi.az.sql.miarc.upgrade(
|
||||
this._miaaModel.info.name,
|
||||
{
|
||||
resourceGroup: undefined,
|
||||
namespace: this._controllerModel.info.namespace,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
await this._controllerModel.refresh(false, this._controllerModel.info.namespace);
|
||||
} catch (error) {
|
||||
vscode.window.showErrorMessage(loc.refreshFailed(error));
|
||||
}
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
return upgradeButton;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import { ControllerModel } from '../../models/controllerModel';
|
||||
export class UpgradeController extends InitializingComponent {
|
||||
protected modelBuilder!: azdata.ModelBuilder;
|
||||
private pitrSettings: UpgradeModel = [];
|
||||
private upgradeControllerDialogName = 'UpgradeControllerDialog';
|
||||
|
||||
protected _completionPromise = new Deferred<UpgradeModel | undefined>();
|
||||
protected disposables: vscode.Disposable[] = [];
|
||||
@@ -23,7 +24,7 @@ export class UpgradeController extends InitializingComponent {
|
||||
}
|
||||
|
||||
public showDialog(dialogTitle: string): azdata.window.Dialog {
|
||||
const dialog = azdata.window.createModelViewDialog(dialogTitle, dialogTitle, 'narrow', 'flyout');
|
||||
const dialog = azdata.window.createModelViewDialog(dialogTitle, this.upgradeControllerDialogName, 'narrow', 'flyout');
|
||||
dialog.cancelButton.onClick(() => this.handleCancel());
|
||||
dialog.registerContent(async view => {
|
||||
this.modelBuilder = view.modelBuilder;
|
||||
@@ -32,7 +33,7 @@ export class UpgradeController extends InitializingComponent {
|
||||
CSSStyles: { ...cssStyles.title, 'margin-block-start': '0px', 'margin-block-end': '0px', 'max-width': 'auto' },
|
||||
}).component();
|
||||
const areYouSureInfo = this.modelBuilder.text().withProps({
|
||||
value: loc.upgradeDialog,
|
||||
value: loc.upgradeDialogController,
|
||||
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'max-width': 'auto' }
|
||||
}).component();
|
||||
const upgradeDialog = this.modelBuilder.flexContainer().withLayout({ flexWrap: 'wrap' }).component();
|
||||
|
||||
94
extensions/arc/src/ui/dialogs/upgradeSqlMiaa.ts
Normal file
94
extensions/arc/src/ui/dialogs/upgradeSqlMiaa.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 UpgradeSqlMiaa extends InitializingComponent {
|
||||
protected modelBuilder!: azdata.ModelBuilder;
|
||||
private pitrSettings: UpgradeModel = [];
|
||||
private upgradeMiaaDialogName = 'UpgradeSqlMiaaDialog';
|
||||
|
||||
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, this.upgradeMiaaDialogName, '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.upgradeDialogMiaa,
|
||||
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 sqlmi -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user