mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Link Database Earliest and Latest Point in time with DryRun (#17506)
This commit is contained in:
committed by
GitHub
parent
b48f392ab2
commit
08d3803453
@@ -20,7 +20,6 @@ export class MiaaBackupsPage extends DashboardPage {
|
||||
this._azApi = vscode.extensions.getExtension(azExt.extension.name)?.exports;
|
||||
this.disposables.push(
|
||||
this._miaaModel.onDatabasesUpdated(() => this.eventuallyRunOnInitialized(() => this.handleDatabasesUpdated())),
|
||||
this._miaaModel.onConfigUpdated(() => this.eventuallyRunOnInitialized(() => this.handleDatabasesUpdated()))
|
||||
);
|
||||
}
|
||||
private _databasesContainer!: azdata.DivContainer;
|
||||
@@ -32,16 +31,17 @@ export class MiaaBackupsPage extends DashboardPage {
|
||||
private _databasesMessage!: azdata.TextComponent;
|
||||
private readonly _azApi: azExt.IExtension;
|
||||
|
||||
public saveArgs: RPModel = {
|
||||
private _saveArgs: RPModel = {
|
||||
recoveryPointObjective: '',
|
||||
retentionDays: ''
|
||||
};
|
||||
|
||||
public pitrArgs = {
|
||||
private _pitrArgs = {
|
||||
destName: '',
|
||||
managedInstance: '',
|
||||
time: '',
|
||||
noWait: true
|
||||
noWait: true,
|
||||
dryRun: false
|
||||
};
|
||||
|
||||
public get title(): string {
|
||||
@@ -66,7 +66,7 @@ export class MiaaBackupsPage extends DashboardPage {
|
||||
.component();
|
||||
const content = this.modelView.modelBuilder.divContainer().component();
|
||||
this._databasesContainer = this.modelView.modelBuilder.divContainer().component();
|
||||
root.addItem(content, { CSSStyles: { 'margin': '20px' } });
|
||||
root.addItem(content, { CSSStyles: { 'margin': '5px' } });
|
||||
const databaseTitle = this.modelView.modelBuilder.text().withProps({
|
||||
value: loc.databases,
|
||||
CSSStyles: { ...cssStyles.title },
|
||||
@@ -130,11 +130,19 @@ export class MiaaBackupsPage extends DashboardPage {
|
||||
headerCssStyles: cssStyles.tableHeader,
|
||||
rowCssStyles: cssStyles.tableRow
|
||||
},
|
||||
{
|
||||
displayName: loc.earliestPitrRestorePoint,
|
||||
valueType: azdata.DeclarativeDataType.string,
|
||||
isReadOnly: true,
|
||||
width: '30%',
|
||||
headerCssStyles: cssStyles.tableHeader,
|
||||
rowCssStyles: cssStyles.tableRow
|
||||
},
|
||||
{
|
||||
displayName: loc.latestpitrRestorePoint,
|
||||
valueType: azdata.DeclarativeDataType.string,
|
||||
isReadOnly: true,
|
||||
width: '50%',
|
||||
width: '30%',
|
||||
headerCssStyles: cssStyles.tableHeader,
|
||||
rowCssStyles: cssStyles.tableRow
|
||||
},
|
||||
@@ -142,7 +150,7 @@ export class MiaaBackupsPage extends DashboardPage {
|
||||
displayName: loc.restore,
|
||||
valueType: azdata.DeclarativeDataType.component,
|
||||
isReadOnly: true,
|
||||
width: '20%',
|
||||
width: '10%',
|
||||
headerCssStyles: cssStyles.tableHeader,
|
||||
rowCssStyles: cssStyles.tableRow,
|
||||
}
|
||||
@@ -198,13 +206,13 @@ export class MiaaBackupsPage extends DashboardPage {
|
||||
this._configureRetentionPolicyButton.onDidClick(async () => {
|
||||
const retentionPolicySqlDialog = new ConfigureRPOSqlDialog(this._miaaModel);
|
||||
this.refreshRD();
|
||||
retentionPolicySqlDialog.showDialog(loc.configureRP, this.saveArgs.retentionDays);
|
||||
retentionPolicySqlDialog.showDialog(loc.configureRP, this._saveArgs.retentionDays);
|
||||
|
||||
let rpArg = await retentionPolicySqlDialog.waitForClose();
|
||||
if (rpArg) {
|
||||
try {
|
||||
this._configureRetentionPolicyButton.enabled = false;
|
||||
this.saveArgs.retentionDays = rpArg.retentionDays;
|
||||
this._saveArgs.retentionDays = rpArg.retentionDays;
|
||||
await vscode.window.withProgress(
|
||||
{
|
||||
location: vscode.ProgressLocation.Notification,
|
||||
@@ -213,7 +221,7 @@ export class MiaaBackupsPage extends DashboardPage {
|
||||
},
|
||||
async (_progress, _token): Promise<void> => {
|
||||
await this._azApi.az.sql.miarc.edit(
|
||||
this._miaaModel.info.name, this.saveArgs, this._miaaModel.controllerModel.info.namespace, this._miaaModel.controllerModel.azAdditionalEnvVars);
|
||||
this._miaaModel.info.name, this._saveArgs, this._miaaModel.controllerModel.info.namespace, this._miaaModel.controllerModel.azAdditionalEnvVars);
|
||||
|
||||
try {
|
||||
await this._miaaModel.refresh();
|
||||
@@ -244,13 +252,16 @@ export class MiaaBackupsPage extends DashboardPage {
|
||||
// If we were able to get the databases it means we have a good connection so update the username too
|
||||
let databaseDisplay = this._miaaModel.databases.map(d => [
|
||||
d.name,
|
||||
d.earliestBackup,
|
||||
d.lastBackup,
|
||||
this.createRestoreButton(d)]);
|
||||
|
||||
let databasesValues = databaseDisplay.map(d => {
|
||||
return d.map((value): azdata.DeclarativeTableCellValue => {
|
||||
return { value: value };
|
||||
});
|
||||
});
|
||||
|
||||
this._databasesTable.setDataValues(databasesValues);
|
||||
|
||||
this._databasesTableLoading.loading = false;
|
||||
@@ -271,7 +282,7 @@ export class MiaaBackupsPage extends DashboardPage {
|
||||
}
|
||||
|
||||
private refreshRD(): void {
|
||||
this.saveArgs.retentionDays = this._miaaModel.config?.spec?.backup?.retentionPeriodInDays.toString() ?? '';
|
||||
this._saveArgs.retentionDays = this._miaaModel.config?.spec?.backup?.retentionPeriodInDays.toString() ?? '';
|
||||
}
|
||||
|
||||
// Create restore button for every database entry in the database table
|
||||
@@ -292,9 +303,9 @@ export class MiaaBackupsPage extends DashboardPage {
|
||||
if (args) {
|
||||
try {
|
||||
restoreButton.enabled = false;
|
||||
this.pitrArgs.destName = args.dbName;
|
||||
this.pitrArgs.managedInstance = args.instanceName;
|
||||
this.pitrArgs.time = `"${args.restorePoint}"`;
|
||||
this._pitrArgs.destName = args.destDbName;
|
||||
this._pitrArgs.managedInstance = args.instanceName;
|
||||
this._pitrArgs.time = `"${args.restorePoint}"`;
|
||||
await vscode.window.withProgress(
|
||||
{
|
||||
location: vscode.ProgressLocation.Notification,
|
||||
@@ -303,7 +314,7 @@ export class MiaaBackupsPage extends DashboardPage {
|
||||
},
|
||||
async (_progress, _token): Promise<void> => {
|
||||
await this._azApi.az.sql.midbarc.restore(
|
||||
db.name, this.pitrArgs, this._miaaModel.controllerModel.info.namespace, this._miaaModel.controllerModel.azAdditionalEnvVars);
|
||||
db.name, this._pitrArgs, this._miaaModel.controllerModel.info.namespace, this._miaaModel.controllerModel.azAdditionalEnvVars);
|
||||
try {
|
||||
await this._miaaModel.refresh();
|
||||
} catch (error) {
|
||||
@@ -320,4 +331,6 @@ export class MiaaBackupsPage extends DashboardPage {
|
||||
}));
|
||||
return restoreButton;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ export class ConfigureRPOSqlDialog extends InitializingComponent {
|
||||
this.retentionDaysInputBox = this.modelBuilder.inputBox()
|
||||
.withProps({
|
||||
readOnly: false,
|
||||
min: 1,
|
||||
min: 0,
|
||||
max: 35,
|
||||
inputType: 'number',
|
||||
ariaLabel: loc.retentionDays,
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import { Deferred } from '../../common/promise';
|
||||
import { getTimeStamp, checkISOTimeString } from '../../common/utils';
|
||||
import * as loc from '../../localizedConstants';
|
||||
import * as vscode from 'vscode';
|
||||
import { cssStyles } from '../../constants';
|
||||
@@ -24,6 +25,7 @@ export class RestoreSqlDialog extends InitializingComponent {
|
||||
restorePoint: '-',
|
||||
earliestPitr: '-',
|
||||
latestPitr: '-',
|
||||
destDbName: '-',
|
||||
};
|
||||
|
||||
private earliestRestorePointInputBox!: azdata.InputBoxComponent;
|
||||
@@ -36,10 +38,11 @@ export class RestoreSqlDialog extends InitializingComponent {
|
||||
private instanceInputBox!: azdata.InputBoxComponent;
|
||||
protected _completionPromise = new Deferred<PITRModel | undefined>();
|
||||
private _azurecoreApi: azurecore.IExtension;
|
||||
protected disposables: vscode.Disposable[] = [];
|
||||
constructor(protected _miaaModel: MiaaModel, protected _controllerModel: ControllerModel, protected _database: DatabaseModel) {
|
||||
super();
|
||||
this._azurecoreApi = vscode.extensions.getExtension(azurecore.extension.name)?.exports;
|
||||
|
||||
this.refreshPitrSettings();
|
||||
}
|
||||
|
||||
public showDialog(dialogTitle: string): azdata.window.Dialog {
|
||||
@@ -50,14 +53,15 @@ export class RestoreSqlDialog extends InitializingComponent {
|
||||
this.refreshPitrSettings();
|
||||
const pitrTitle = this.modelBuilder.text().withProps({
|
||||
value: loc.pitr,
|
||||
CSSStyles: { ...cssStyles.title }
|
||||
CSSStyles: { ...cssStyles.title, 'margin-block-start': '0px', 'margin-block-end': '0px', 'max-width': 'auto' },
|
||||
}).component();
|
||||
const projectDetailsTitle = this.modelBuilder.text().withProps({
|
||||
value: loc.projectDetails,
|
||||
CSSStyles: { ...cssStyles.title }
|
||||
CSSStyles: { ...cssStyles.title, 'margin-block-start': '0px', 'margin-block-end': '0px', 'max-width': 'auto' }
|
||||
}).component();
|
||||
const projectDetailsTextLabel = this.modelBuilder.text().withProps({
|
||||
value: loc.projectDetailsText,
|
||||
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'margin-block-end': '0px', 'max-width': 'auto' }
|
||||
}).component();
|
||||
this.subscriptionInputBox = this.modelBuilder.inputBox()
|
||||
.withProps({
|
||||
@@ -74,10 +78,11 @@ export class RestoreSqlDialog extends InitializingComponent {
|
||||
|
||||
const sourceDetailsTitle = this.modelBuilder.text().withProps({
|
||||
value: loc.sourceDetails,
|
||||
CSSStyles: { ...cssStyles.title }
|
||||
CSSStyles: { ...cssStyles.title, 'margin-block-end': '0px', 'max-width': 'auto' }
|
||||
}).component();
|
||||
const sourceDetailsTextLabel = this.modelBuilder.text().withProps({
|
||||
value: loc.sourceDetailsText,
|
||||
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'margin-block-end': '0px', 'max-width': 'auto' }
|
||||
}).component();
|
||||
this.sourceDbInputBox = this.modelBuilder.inputBox()
|
||||
.withProps({
|
||||
@@ -85,12 +90,15 @@ export class RestoreSqlDialog extends InitializingComponent {
|
||||
ariaLabel: loc.sourceDatabase,
|
||||
value: this._database.name
|
||||
}).component();
|
||||
|
||||
const restoreDetailsTextLabel = this.modelBuilder.text().withProps({
|
||||
value: loc.restorePointText,
|
||||
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'margin-block-end': '0px', 'max-width': 'auto' }
|
||||
}).component();
|
||||
this.earliestRestorePointInputBox = this.modelBuilder.inputBox()
|
||||
.withProps({
|
||||
enabled: false,
|
||||
ariaLabel: loc.earliestPitrRestorePoint,
|
||||
value: ''
|
||||
value: this._database.earliestBackup
|
||||
}).component();
|
||||
|
||||
this.latestRestorePointInputBox = this.modelBuilder.inputBox()
|
||||
@@ -104,14 +112,39 @@ export class RestoreSqlDialog extends InitializingComponent {
|
||||
.withProps({
|
||||
readOnly: false,
|
||||
ariaLabel: loc.restorePoint,
|
||||
value: ''
|
||||
value: '',
|
||||
validationErrorMessage: loc.restorePointErrorMessage(this.earliestRestorePointInputBox.value ?? loc.earliestPitrRestorePoint, this.latestRestorePointInputBox.value ?? loc.latestpitrRestorePoint),
|
||||
}).withValidation(async () => {
|
||||
try {
|
||||
if (!checkISOTimeString(this.restorePointInputBox.value ?? '')) { return false; }
|
||||
if (this.earliestRestorePointInputBox.value) {
|
||||
if ((getTimeStamp(this.restorePointInputBox.value) >= getTimeStamp(this.earliestRestorePointInputBox.value)
|
||||
&& getTimeStamp(this.restorePointInputBox.value) <= getTimeStamp(this.latestRestorePointInputBox.value))) {
|
||||
this.pitrSettings.restorePoint = this.restorePointInputBox.value ?? '';
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
throw err;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}).component();
|
||||
const databaseDetailsTitle = this.modelBuilder.text().withProps({
|
||||
const pitrDetailsTitle = this.modelBuilder.text().withProps({
|
||||
value: loc.restorePointDetails,
|
||||
CSSStyles: { ...cssStyles.title, 'margin-block-end': '0px', 'max-width': 'auto' }
|
||||
}).component();
|
||||
const destinationDetailsTitle = this.modelBuilder.text().withProps({
|
||||
value: loc.databaseDetails,
|
||||
CSSStyles: { ...cssStyles.title }
|
||||
CSSStyles: { ...cssStyles.title, 'margin-block-end': '0px', 'max-width': 'auto' }
|
||||
}).component();
|
||||
const databaseDetailsTextLabel = this.modelBuilder.text().withProps({
|
||||
value: loc.databaseDetailsText,
|
||||
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'margin-block-end': '0px', 'max-width': 'auto' }
|
||||
}).component();
|
||||
this.databaseNameInputBox = this.modelBuilder.inputBox()
|
||||
.withProps({
|
||||
@@ -119,7 +152,10 @@ export class RestoreSqlDialog extends InitializingComponent {
|
||||
ariaLabel: loc.databaseName,
|
||||
value: ''
|
||||
}).component();
|
||||
|
||||
this.disposables.push(
|
||||
this.databaseNameInputBox.onTextChanged(() => {
|
||||
this.pitrSettings.destDbName = this.databaseNameInputBox.value ?? '';
|
||||
}));
|
||||
this.instanceInputBox = this.modelBuilder.inputBox()
|
||||
.withProps({
|
||||
enabled: false,
|
||||
@@ -128,7 +164,7 @@ export class RestoreSqlDialog extends InitializingComponent {
|
||||
}).component();
|
||||
const info = this.modelBuilder.text().withProps({
|
||||
value: loc.restoreInfo,
|
||||
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'margin-block-end': '0px' }
|
||||
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'max-width': 'auto' }
|
||||
}).component();
|
||||
|
||||
const link = this.modelBuilder.hyperlink().withProps({
|
||||
@@ -178,22 +214,7 @@ export class RestoreSqlDialog extends InitializingComponent {
|
||||
|
||||
},
|
||||
{
|
||||
component: this.earliestRestorePointInputBox,
|
||||
title: loc.earliestPitrRestorePoint,
|
||||
|
||||
},
|
||||
{
|
||||
component: this.latestRestorePointInputBox,
|
||||
title: loc.latestpitrRestorePoint,
|
||||
|
||||
},
|
||||
{
|
||||
component: this.restorePointInputBox,
|
||||
title: loc.restorePoint,
|
||||
required: true
|
||||
},
|
||||
{
|
||||
component: databaseDetailsTitle,
|
||||
component: destinationDetailsTitle,
|
||||
},
|
||||
{
|
||||
component: databaseDetailsTextLabel,
|
||||
@@ -208,6 +229,27 @@ export class RestoreSqlDialog extends InitializingComponent {
|
||||
title: loc.instance,
|
||||
|
||||
},
|
||||
{
|
||||
component: pitrDetailsTitle
|
||||
},
|
||||
{
|
||||
component: restoreDetailsTextLabel,
|
||||
},
|
||||
{
|
||||
component: this.earliestRestorePointInputBox,
|
||||
title: loc.earliestPitrRestorePoint,
|
||||
|
||||
},
|
||||
{
|
||||
component: this.latestRestorePointInputBox,
|
||||
title: loc.latestpitrRestorePoint,
|
||||
|
||||
},
|
||||
{
|
||||
component: this.restorePointInputBox,
|
||||
title: loc.restorePoint,
|
||||
required: true
|
||||
},
|
||||
],
|
||||
title: ''
|
||||
}]).withLayout({ width: '100%' }).component();
|
||||
@@ -269,4 +311,9 @@ export class RestoreSqlDialog extends InitializingComponent {
|
||||
this.pitrSettings.restorePoint = this._database.lastBackup;
|
||||
this.pitrSettings.earliestPitr = '';
|
||||
}
|
||||
public updatePitrTimeWindow(earliestPitr: string, latestPitr: string): void {
|
||||
this.earliestRestorePointInputBox.value = earliestPitr;
|
||||
this.latestRestorePointInputBox.value = latestPitr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user