Fix bugbash SQL-Migration extension migration load issues (#16575)

* fix migration refresh issues

* merge latest
This commit is contained in:
brian-harris
2021-08-05 13:24:02 -07:00
committed by GitHub
parent 33baaa475d
commit c6308b77df
9 changed files with 155 additions and 52 deletions

View File

@@ -13,6 +13,7 @@ import { azureResource } from 'azureResource';
import { IconPathHelper } from '../../constants/iconPathHelper';
import { CreateResourceGroupDialog } from '../createResourceGroup/createResourceGroupDialog';
import * as EventEmitter from 'events';
import { clearDialogMessage } from '../../api/utils';
export class CreateSqlMigrationServiceDialog {
@@ -89,6 +90,7 @@ export class CreateSqlMigrationServiceDialog {
}
try {
clearDialogMessage(this._dialogObject);
this._selectedResourceGroup = resourceGroup;
this._createdMigrationService = await createSqlMigrationService(this._model._azureAccount, subscription, resourceGroup, location, serviceName!, this._model._sessionId);
if (this._createdMigrationService.error) {
@@ -97,9 +99,6 @@ export class CreateSqlMigrationServiceDialog {
this.setFormEnabledState(true);
return;
}
this._dialogObject.message = {
text: ''
};
if (this._isBlobContainerUsed) {
this._dialogObject.okButton.enabled = true;
@@ -511,9 +510,15 @@ export class CreateSqlMigrationServiceDialog {
let migrationServiceStatus!: SqlMigrationService;
for (let i = 0; i < maxRetries; i++) {
try {
clearDialogMessage(this._dialogObject);
migrationServiceStatus = await getSqlMigrationService(this._model._azureAccount, subscription, resourceGroup, location, this._createdMigrationService.name, this._model._sessionId);
break;
} catch (e) {
this._dialogObject.message = {
text: constants.SERVICE_STATUS_REFRESH_ERROR,
description: e.message,
level: azdata.window.MessageLevel.Error
};
console.log(e);
}
await new Promise(r => setTimeout(r, 5000));

View File

@@ -6,10 +6,10 @@
import * as azdata from 'azdata';
import * as vscode from 'vscode';
import { IconPathHelper } from '../../constants/iconPathHelper';
import { MigrationContext } from '../../models/migrationLocalStorage';
import { MigrationCutoverDialogModel, MigrationStatus } from './migrationCutoverDialogModel';
import { MigrationContext, MigrationStatus, ProvisioningState } from '../../models/migrationLocalStorage';
import { MigrationCutoverDialogModel } from './migrationCutoverDialogModel';
import * as loc from '../../constants/strings';
import { convertByteSizeToReadableUnit, convertIsoTimeToLocalTime, getSqlServerName, getMigrationStatusImage, SupportedAutoRefreshIntervals } from '../../api/utils';
import { convertByteSizeToReadableUnit, convertIsoTimeToLocalTime, getSqlServerName, getMigrationStatusImage, SupportedAutoRefreshIntervals, clearDialogMessage } from '../../api/utils';
import { EOL } from 'os';
import { ConfirmCutoverDialog } from './confirmCutoverDialog';
import { MigrationMode } from '../../models/stateMachine';
@@ -445,7 +445,12 @@ export class MigrationCutoverDialog {
}
private setAutoRefresh(interval: SupportedAutoRefreshIntervals): void {
const shouldRefresh = (status: string | undefined) => !status || ['InProgress', 'Creating', 'Completing', 'Creating'].includes(status);
const shouldRefresh = (status: string | undefined) => !status
|| status === MigrationStatus.InProgress
|| status === MigrationStatus.Creating
|| status === MigrationStatus.Completing
|| status === MigrationStatus.Canceling;
if (shouldRefresh(this.getMigrationStatus())) {
const classVariable = this;
clearInterval(this._autoRefreshHandle);
@@ -474,6 +479,8 @@ export class MigrationCutoverDialog {
}
try {
clearDialogMessage(this._dialogObject);
if (this._isProvisioned() && this._isOnlineMigration()) {
this._cutoverButton.updateCssStyles({
'display': 'inline'
@@ -490,7 +497,10 @@ export class MigrationCutoverDialog {
errors.push(this._model.migrationStatus.properties.migrationStatusDetails?.restoreBlockingReason);
this._dialogObject.message = {
text: errors.filter(e => e !== undefined).join(EOL),
level: (this._model.migrationStatus.properties.migrationStatus === MigrationStatus.InProgress || this._model.migrationStatus.properties.migrationStatus === 'Completing') ? azdata.window.MessageLevel.Warning : azdata.window.MessageLevel.Error,
level: this._model.migrationStatus.properties.migrationStatus === MigrationStatus.InProgress
|| this._model.migrationStatus.properties.migrationStatus === MigrationStatus.Completing
? azdata.window.MessageLevel.Warning
: azdata.window.MessageLevel.Error,
description: this.getMigrationDetails()
};
const sqlServerInfo = await azdata.connection.getServerInfo((await azdata.connection.getCurrentConnection()).connectionId);
@@ -599,12 +609,21 @@ export class MigrationCutoverDialog {
if (restoredCount > 0 || isBlobMigration) {
this._cutoverButton.enabled = true;
}
this._cancelButton.enabled = true;
} else {
this._cutoverButton.enabled = false;
this._cancelButton.enabled = false;
}
this._cancelButton.enabled =
migrationStatusTextValue === MigrationStatus.Canceling ||
migrationStatusTextValue === MigrationStatus.Creating ||
migrationStatusTextValue === MigrationStatus.InProgress;
} catch (e) {
this._dialogObject.message = {
level: azdata.window.MessageLevel.Error,
text: loc.MIGRATION_STATUS_REFRESH_ERROR,
description: e.message
};
console.log(e);
} finally {
this.isRefreshing = false;
@@ -696,7 +715,9 @@ export class MigrationCutoverDialog {
private _isProvisioned(): boolean {
const { migrationStatus, provisioningState } = this._model._migration.migrationContext.properties;
return provisioningState === 'Succeeded' || migrationStatus === 'Completing' || migrationStatus === 'Canceling';
return provisioningState === ProvisioningState.Succeeded
|| migrationStatus === MigrationStatus.Completing
|| migrationStatus === MigrationStatus.Canceling;
}
private _isOnlineMigration(): boolean {
@@ -713,9 +734,11 @@ export class MigrationCutoverDialog {
private getMigrationStatus(): string {
if (this._model.migrationStatus) {
return this._model.migrationStatus.properties.migrationStatus ?? this._model.migrationStatus.properties.provisioningState;
return this._model.migrationStatus.properties.migrationStatus
?? this._model.migrationStatus.properties.provisioningState;
}
return this._model._migration.migrationContext.properties.migrationStatus;
return this._model._migration.migrationContext.properties.migrationStatus
?? this._model._migration.migrationContext.properties.provisioningState;
}
}

View File

@@ -8,13 +8,6 @@ import { MigrationContext } from '../../models/migrationLocalStorage';
import { sendSqlMigrationActionEvent, TelemetryAction, TelemetryViews } from '../../telemtery';
import * as constants from '../../constants/strings';
export enum MigrationStatus {
Failed = 'Failed',
Succeeded = 'Succeeded',
InProgress = 'InProgress',
Canceled = 'Canceled'
}
export class MigrationCutoverDialogModel {
public migrationStatus!: DatabaseMigration;

View File

@@ -6,11 +6,11 @@
import * as azdata from 'azdata';
import * as vscode from 'vscode';
import { IconPathHelper } from '../../constants/iconPathHelper';
import { MigrationContext, MigrationLocalStorage } from '../../models/migrationLocalStorage';
import { MigrationContext, MigrationLocalStorage, MigrationStatus, ProvisioningState } from '../../models/migrationLocalStorage';
import { MigrationCutoverDialog } from '../migrationCutover/migrationCutoverDialog';
import { AdsMigrationStatus, MigrationStatusDialogModel } from './migrationStatusDialogModel';
import * as loc from '../../constants/strings';
import { convertTimeDifferenceToDuration, filterMigrations, getMigrationStatusImage, SupportedAutoRefreshIntervals } from '../../api/utils';
import { clearDialogMessage, convertTimeDifferenceToDuration, filterMigrations, getMigrationStatusImage, SupportedAutoRefreshIntervals } from '../../api/utils';
import { SqlMigrationServiceDetailsDialog } from '../sqlMigrationService/sqlMigrationServiceDetailsDialog';
import { ConfirmCutoverDialog } from '../migrationCutover/confirmCutoverDialog';
import { MigrationCutoverDialogModel } from '../migrationCutover/migrationCutoverDialogModel';
@@ -96,8 +96,15 @@ export class MigrationStatusDialog {
azdata.window.openDialog(this._dialogObject);
}
private canCancelMigration = (status: string | undefined) => status && status in ['InProgress', 'Creating', 'Completing', 'Creating'];
private canCutoverMigration = (status: string | undefined) => status === 'InProgress';
private canCancelMigration = (status: string | undefined) => status &&
(
status === MigrationStatus.InProgress ||
status === MigrationStatus.Creating ||
status === MigrationStatus.Completing ||
status === MigrationStatus.Canceling
);
private canCutoverMigration = (status: string | undefined) => status === MigrationStatus.InProgress;
private createSearchAndRefreshContainer(): azdata.FlexContainer {
this._searchBox = this._view.modelBuilder.inputBox().withProps({
@@ -177,6 +184,7 @@ export class MigrationStatusDialog {
'sqlmigration.cutover',
async (migrationId: string) => {
try {
clearDialogMessage(this._dialogObject);
const migration = this._model._migrations.find(migration => migration.migrationContext.id === migrationId);
if (this.canCutoverMigration(migration?.migrationContext.properties.migrationStatus)) {
const cutoverDialogModel = new MigrationCutoverDialogModel(migration!);
@@ -187,6 +195,12 @@ export class MigrationStatusDialog {
await vscode.window.showInformationMessage(loc.MIGRATION_CANNOT_CUTOVER);
}
} catch (e) {
this._dialogObject.message = {
text: loc.MIGRATION_STATUS_REFRESH_ERROR,
description: e.message,
level: azdata.window.MessageLevel.Error
};
console.log(e);
}
}));
@@ -231,6 +245,7 @@ export class MigrationStatusDialog {
'sqlmigration.copy.migration',
async (migrationId: string) => {
try {
clearDialogMessage(this._dialogObject);
const migration = this._model._migrations.find(migration => migration.migrationContext.id === migrationId);
const cutoverDialogModel = new MigrationCutoverDialogModel(migration!);
await cutoverDialogModel.fetchStatus();
@@ -245,6 +260,12 @@ export class MigrationStatusDialog {
await vscode.window.showInformationMessage(loc.DETAILS_COPIED);
} catch (e) {
this._dialogObject.message = {
text: loc.MIGRATION_STATUS_REFRESH_ERROR,
description: e.message,
level: azdata.window.MessageLevel.Error
};
console.log(e);
}
}));
@@ -253,6 +274,7 @@ export class MigrationStatusDialog {
'sqlmigration.cancel.migration',
async (migrationId: string) => {
try {
clearDialogMessage(this._dialogObject);
const migration = this._model._migrations.find(migration => migration.migrationContext.id === migrationId);
if (this.canCancelMigration(migration?.migrationContext.properties.migrationStatus)) {
vscode.window.showInformationMessage(loc.CANCEL_MIGRATION_CONFIRMATION, loc.YES, loc.NO).then(async (v) => {
@@ -266,6 +288,12 @@ export class MigrationStatusDialog {
await vscode.window.showInformationMessage(loc.MIGRATION_CANNOT_CANCEL);
}
} catch (e) {
this._dialogObject.message = {
text: loc.MIGRATION_CANCELLATION_ERROR,
description: e.message,
level: azdata.window.MessageLevel.Error
};
console.log(e);
}
}));
@@ -371,7 +399,7 @@ export class MigrationStatusDialog {
}
private _getMigrationMode(migration: MigrationContext): string {
if (migration.migrationContext.properties.provisioningState === 'Creating') {
if (migration.migrationContext.properties.provisioningState === ProvisioningState.Creating) {
return '---';
}
return migration.migrationContext.properties.autoCutoverConfiguration?.autoCutover?.valueOf() ? loc.OFFLINE : loc.ONLINE;
@@ -466,11 +494,18 @@ export class MigrationStatusDialog {
this.isRefreshing = true;
try {
clearDialogMessage(this._dialogObject);
this._refreshLoader.loading = true;
const currentConnection = await azdata.connection.getCurrentConnection();
this._model._migrations = await MigrationLocalStorage.getMigrationsBySourceConnections(currentConnection, true);
await this.populateMigrationTable();
} catch (e) {
this._dialogObject.message = {
text: loc.MIGRATION_STATUS_REFRESH_ERROR,
description: e.message,
level: azdata.window.MessageLevel.Error
};
console.log(e);
} finally {
this.isRefreshing = false;
@@ -583,13 +618,10 @@ export class MigrationStatusDialog {
}
private _statusInfoMap(status: string): azdata.IconPath {
switch (status) {
case 'InProgress':
case 'Creating':
case 'Completing':
return IconPathHelper.warning;
default:
return IconPathHelper.error;
}
return status === MigrationStatus.InProgress
|| status === MigrationStatus.Creating
|| status === MigrationStatus.Completing
? IconPathHelper.warning
: IconPathHelper.error;
}
}