From 6556eaa1ed110535fed9f8b9d19ed69014bc0021 Mon Sep 17 00:00:00 2001
From: Ram Uday Kumar <95093687+Ramudaykumar@users.noreply.github.com>
Date: Fri, 1 Sep 2023 10:34:36 +0530
Subject: [PATCH] Revalidate failed IR Validation steps (#24237)
---
extensions/sql-migration/images/redo.svg | 3 +
.../src/constants/iconPathHelper.ts | 5 +
.../sql-migration/src/constants/strings.ts | 1 +
.../validationResults/validateIrDialog.ts | 117 +++++++++++++++---
4 files changed, 109 insertions(+), 17 deletions(-)
create mode 100644 extensions/sql-migration/images/redo.svg
diff --git a/extensions/sql-migration/images/redo.svg b/extensions/sql-migration/images/redo.svg
new file mode 100644
index 0000000000..9d982e5520
--- /dev/null
+++ b/extensions/sql-migration/images/redo.svg
@@ -0,0 +1,3 @@
+
diff --git a/extensions/sql-migration/src/constants/iconPathHelper.ts b/extensions/sql-migration/src/constants/iconPathHelper.ts
index 7f6c03665a..6beca19ed0 100644
--- a/extensions/sql-migration/src/constants/iconPathHelper.ts
+++ b/extensions/sql-migration/src/constants/iconPathHelper.ts
@@ -40,6 +40,7 @@ export class IconPathHelper {
public static emptyTable: IconPath;
public static addAzureAccount: IconPath;
public static retry: IconPath;
+ public static redo: IconPath;
public static edit: IconPath;
public static restartDataCollection: IconPath;
public static stop: IconPath;
@@ -167,6 +168,10 @@ export class IconPathHelper {
light: context.asAbsolutePath('images/retry.svg'),
dark: context.asAbsolutePath('images/retry.svg')
};
+ IconPathHelper.redo = {
+ light: context.asAbsolutePath('images/redo.svg'),
+ dark: context.asAbsolutePath('images/redo.svg')
+ };
IconPathHelper.edit = {
light: context.asAbsolutePath('images/edit.svg'),
dark: context.asAbsolutePath('images/edit.svg')
diff --git a/extensions/sql-migration/src/constants/strings.ts b/extensions/sql-migration/src/constants/strings.ts
index 261351bb46..17b215952c 100644
--- a/extensions/sql-migration/src/constants/strings.ts
+++ b/extensions/sql-migration/src/constants/strings.ts
@@ -802,6 +802,7 @@ export const VALIDATION_STATE_FAILED = localize('sql.migration.validation.state.
export const VALIDATE_IR_DONE_BUTTON = localize('sql.migration.validate.ir.done.button', "Done");
export const VALIDATE_IR_HEADING = localize('sql.migration.validate.ir.heading', "We are validating the following:");
export const VALIDATE_IR_START_VALIDATION = localize('sql.migration.validate.ir.start.validation', "Start validation");
+export const VALIDATE_IR_FAILED_REVALIDATION = localize('sql.migration.validate.ir.failed.revalidation', "Revalidate failed steps");
export const VALIDATE_IR_STOP_VALIDATION = localize('sql.migration.validate.ir.stop.validation', "Stop validation");
export const VALIDATE_IR_COPY_RESULTS = localize('sql.migration.validate.ir.copy.results', "Copy validation results");
export const VALIDATE_IR_RESULTS_HEADING = localize('sql.migration.validate.ir.results.heading', "Validation step details");
diff --git a/extensions/sql-migration/src/dialog/validationResults/validateIrDialog.ts b/extensions/sql-migration/src/dialog/validationResults/validateIrDialog.ts
index ee6d561d89..2b2915af39 100644
--- a/extensions/sql-migration/src/dialog/validationResults/validateIrDialog.ts
+++ b/extensions/sql-migration/src/dialog/validationResults/validateIrDialog.ts
@@ -50,6 +50,7 @@ export class ValidateIrDialog {
private _resultsTable!: azdata.TableComponent;
private _startLoader!: azdata.LoadingComponent;
private _startButton!: azdata.ButtonComponent;
+ private _revalidationButton!: azdata.ButtonComponent;
private _cancelButton!: azdata.ButtonComponent;
private _copyButton!: azdata.ButtonComponent;
private _validationResult: any[][] = [];
@@ -144,6 +145,17 @@ export class ValidateIrDialog {
label: constants.VALIDATE_IR_STOP_VALIDATION,
enabled: false,
}).component();
+
+ this._revalidationButton = view.modelBuilder.button()
+ .withProps({
+ iconPath: IconPathHelper.redo,
+ iconHeight: 18,
+ iconWidth: 18,
+ width: 150,
+ label: constants.VALIDATE_IR_FAILED_REVALIDATION,
+ enabled: false,
+ }).component();
+
this._copyButton = view.modelBuilder.button()
.withProps({
iconPath: IconPathHelper.copy,
@@ -157,6 +169,10 @@ export class ValidateIrDialog {
this._disposables.push(
this._startButton.onDidClick(
async (e) => await this._runValidation()));
+
+ this._disposables.push(
+ this._revalidationButton.onDidClick(
+ async (e) => await this._runFailedRevalidation()));
this._disposables.push(
this._cancelButton.onDidClick(
e => {
@@ -172,6 +188,7 @@ export class ValidateIrDialog {
.withToolbarItems([
{ component: this._startButton },
{ component: this._cancelButton },
+ { component: this._revalidationButton },
{ component: this._copyButton }])
.component();
@@ -262,6 +279,7 @@ export class ValidateIrDialog {
try {
this._startLoader.loading = true;
this._startButton.enabled = false;
+ this._revalidationButton.enabled = false;
this._cancelButton.enabled = true;
this._copyButton.enabled = false;
this._dialog!.okButton.enabled = false;
@@ -274,6 +292,30 @@ export class ValidateIrDialog {
} finally {
this._startLoader.loading = false;
this._startButton.enabled = true;
+ this._revalidationButton.enabled = !this._model.isIrTargetValidated;
+ this._cancelButton.enabled = false;
+ this._copyButton.enabled = true;
+ this._dialog!.okButton.enabled = this._model.isIrTargetValidated;
+ this._dialog!.cancelButton.enabled = !this._model.isIrTargetValidated;
+ }
+ }
+
+ private async _runFailedRevalidation(results?: ValidationResult[]): Promise {
+ try {
+ this._startLoader.loading = true;
+ this._startButton.enabled = false;
+ this._revalidationButton.enabled = false;
+ this._cancelButton.enabled = true;
+ this._copyButton.enabled = false;
+ this._dialog!.okButton.enabled = false;
+ this._dialog!.cancelButton.enabled = true;
+ if (!this._model.isIrTargetValidated) {
+ await this._revalidate();
+ }
+ } finally {
+ this._startLoader.loading = false;
+ this._startButton.enabled = true;
+ this._revalidationButton.enabled = !this._model.isIrTargetValidated;
this._cancelButton.enabled = false;
this._copyButton.enabled = true;
this._dialog!.okButton.enabled = this._model.isIrTargetValidated;
@@ -373,7 +415,19 @@ export class ValidateIrDialog {
this._saveResults();
}
- private async _validateDatabaseMigration(): Promise {
+ private async _revalidate(): Promise {
+ await this._initIrResultsForRevalidation();
+
+ if (this._model.isSqlDbTarget) {
+ await this._validateSqlDbMigration(true);
+ } else {
+ await this._validateDatabaseMigration(true);
+ }
+
+ this._saveResults();
+ }
+
+ private async _validateDatabaseMigration(skipSuccessfulSteps: boolean = false): Promise {
const currentConnection = await getSourceConnectionProfile();
const sourceServerName = currentConnection?.serverName!;
const encryptConnection = getEncryptConnectionValue(currentConnection);
@@ -426,17 +480,21 @@ export class ValidateIrDialog {
};
// validate integration runtime (IR) is online
- if (!await validate(sourceDatabaseName, networkShare, true, false, false, false)) {
- this._canceled = true;
- await this._updateValidateIrResults(testNumber + 1, ValidateIrState.Canceled, [constants.VALIDATE_IR_VALIDATION_CANCELED])
- return;
+ if (!skipSuccessfulSteps || this._validationResult[testNumber][ValidationResultIndex.state] !== ValidateIrState.Succeeded) {
+ if (!await validate(sourceDatabaseName, networkShare, true, false, false, false)) {
+ this._canceled = true;
+ await this._updateValidateIrResults(testNumber + 1, ValidateIrState.Canceled, [constants.VALIDATE_IR_VALIDATION_CANCELED])
+ return;
+ }
}
testNumber++;
// validate blob container connectivity
- if (!await validate(sourceDatabaseName, networkShare, false, false, false, true)) {
- await this._updateValidateIrResults(testNumber + 1, ValidateIrState.Canceled, [constants.VALIDATE_IR_VALIDATION_CANCELED])
- return;
+ if (!skipSuccessfulSteps || this._validationResult[testNumber][ValidationResultIndex.state] !== ValidateIrState.Succeeded) {
+ if (!await validate(sourceDatabaseName, networkShare, false, false, false, true)) {
+ await this._updateValidateIrResults(testNumber + 1, ValidateIrState.Canceled, [constants.VALIDATE_IR_VALIDATION_CANCELED])
+ return;
+ }
}
for (let i = 0; i < databaseCount; i++) {
@@ -448,14 +506,18 @@ export class ValidateIrDialog {
break;
}
// validate source connectivity
- await validate(sourceDatabaseName, networkShare, false, false, true, false);
+ if (!skipSuccessfulSteps || this._validationResult[testNumber][ValidationResultIndex.state] !== ValidateIrState.Succeeded) {
+ await validate(sourceDatabaseName, networkShare, false, false, true, false);
+ }
testNumber++;
if (this._canceled) {
await this._updateValidateIrResults(testNumber, ValidateIrState.Canceled, [constants.VALIDATE_IR_VALIDATION_CANCELED])
break;
}
// valdiate source location / network share connectivity
- await validate(sourceDatabaseName, networkShare, false, true, false, false);
+ if (!skipSuccessfulSteps || this._validationResult[testNumber][ValidationResultIndex.state] !== ValidateIrState.Succeeded) {
+ await validate(sourceDatabaseName, networkShare, false, true, false, false);
+ }
}
}
@@ -469,7 +531,7 @@ export class ValidateIrDialog {
return error;
}
- private async _validateSqlDbMigration(): Promise {
+ private async _validateSqlDbMigration(skipSuccessfulSteps: boolean = false): Promise {
const currentConnection = await getSourceConnectionProfile();
const sourceServerName = currentConnection?.serverName!;
const encryptConnection = getEncryptConnectionValue(currentConnection);
@@ -521,10 +583,12 @@ export class ValidateIrDialog {
};
// validate IR is online
- if (!await validate(sourceDatabaseName, targetDatabaseName, true, false, false)) {
- this._canceled = true;
- await this._updateValidateIrResults(testNumber + 1, ValidateIrState.Canceled, [constants.VALIDATE_IR_VALIDATION_CANCELED]);
- return;
+ if (!skipSuccessfulSteps || this._validationResult[testNumber][ValidationResultIndex.state] !== ValidateIrState.Succeeded) {
+ if (!await validate(sourceDatabaseName, targetDatabaseName, true, false, false)) {
+ this._canceled = true;
+ await this._updateValidateIrResults(testNumber + 1, ValidateIrState.Canceled, [constants.VALIDATE_IR_VALIDATION_CANCELED]);
+ return;
+ }
}
for (let i = 0; i < databaseCount; i++) {
@@ -537,7 +601,9 @@ export class ValidateIrDialog {
break;
}
// validate source connectivity
- await validate(sourceDatabaseName, targetDatabaseName, false, true, false);
+ if (!skipSuccessfulSteps || this._validationResult[testNumber][ValidationResultIndex.state] !== ValidateIrState.Succeeded) {
+ await validate(sourceDatabaseName, targetDatabaseName, false, true, false);
+ }
testNumber++;
if (this._canceled) {
@@ -545,7 +611,9 @@ export class ValidateIrDialog {
break;
}
// validate target connectivity
- await validate(sourceDatabaseName, targetDatabaseName, false, false, true);
+ if (!skipSuccessfulSteps || this._validationResult[testNumber][ValidationResultIndex.state] !== ValidateIrState.Succeeded) {
+ await validate(sourceDatabaseName, targetDatabaseName, false, false, true);
+ }
}
}
@@ -584,6 +652,21 @@ export class ValidateIrDialog {
await this._resultsTable.updateProperty('data', data);
}
+ private async _initIrResultsForRevalidation(results?: ValidationResult[]): Promise {
+ this._valdiationErrors = [];
+ this._canceled = false;
+ let testNumber: number = 0;
+
+ this._validationResult.forEach(async element => {
+ if (element[ValidationResultIndex.state] !== ValidateIrState.Succeeded) {
+ await this._updateValidateIrResults(testNumber++, ValidateIrState.Pending);
+ }
+ else {
+ testNumber++;
+ }
+ });
+ }
+
private async _initSqlDbIrResults(results?: ValidationResult[]): Promise {
this._validationResult = [];
this._addValidationResult(constants.VALIDATE_IR_VALIDATION_RESULT_LABEL_SHIR);