mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-12 02:58:31 -05:00
SQL-Migration: add retry migration prompt (#22555)
* add retry migration prompt * updating review comments * update context menu postion to match toolbar
This commit is contained in:
@@ -11,6 +11,7 @@ import { getSessionIdHeader } from './utils';
|
||||
import { URL } from 'url';
|
||||
import { MigrationSourceAuthenticationType, MigrationStateModel, NetworkShare } from '../models/stateMachine';
|
||||
import { NetworkInterface } from './dataModels/azure/networkInterfaceModel';
|
||||
import { EOL } from 'os';
|
||||
|
||||
const ARM_MGMT_API_VERSION = '2021-04-01';
|
||||
const SQL_VM_API_VERSION = '2021-11-01-preview';
|
||||
@@ -628,6 +629,20 @@ export async function stopMigration(account: azdata.Account, subscription: Subsc
|
||||
}
|
||||
}
|
||||
|
||||
export async function retryMigration(account: azdata.Account, subscription: Subscription, migration: DatabaseMigration): Promise<void> {
|
||||
const api = await getAzureCoreAPI();
|
||||
const path = encodeURI(`${migration.id}/retry?api-version=${DMSV2_API_VERSION}`);
|
||||
const requestBody = { migrationOperationId: migration.properties.migrationOperationId };
|
||||
const host = api.getProviderMetadataForAccount(account).settings.armResource?.endpoint;
|
||||
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.POST, requestBody, true, host);
|
||||
if (response.errors.length > 0) {
|
||||
const message = response.errors
|
||||
.map(err => err.message)
|
||||
.join(', ');
|
||||
throw new Error(message);
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteMigration(account: azdata.Account, subscription: Subscription, migrationId: string): Promise<void> {
|
||||
const api = await getAzureCoreAPI();
|
||||
const path = encodeURI(`${migrationId}?api-version=${DMSV2_API_VERSION}`);
|
||||
@@ -817,6 +832,27 @@ export function getBlobContainerId(resourceGroupId: string, storageAccountName:
|
||||
return `${resourceGroupId}/providers/Microsoft.Storage/storageAccounts/${storageAccountName}/blobServices/default/containers/${blobContainerName}`;
|
||||
}
|
||||
|
||||
export function getMigrationErrors(migration: DatabaseMigration): string {
|
||||
const errors = [];
|
||||
|
||||
if (migration?.properties) {
|
||||
errors.push(migration.properties.provisioningError);
|
||||
errors.push(migration.properties.migrationFailureError?.message);
|
||||
errors.push(migration.properties.migrationStatusDetails?.fileUploadBlockingErrors ?? []);
|
||||
errors.push(migration.properties.migrationStatusDetails?.restoreBlockingReason);
|
||||
errors.push(migration.properties.migrationStatusDetails?.sqlDataCopyErrors);
|
||||
errors.push(...migration.properties.migrationStatusDetails?.invalidFiles ?? []);
|
||||
errors.push(migration.properties.migrationStatusWarnings?.completeRestoreErrorMessage);
|
||||
errors.push(migration.properties.migrationStatusWarnings?.restoreBlockingReason);
|
||||
errors.push(...migration.properties.migrationStatusDetails?.listOfCopyProgressDetails?.flatMap(cp => cp.errors) ?? []);
|
||||
}
|
||||
|
||||
// remove undefined and duplicate error entries
|
||||
return errors
|
||||
.filter((e, i, arr) => e !== undefined && i === arr.indexOf(e))
|
||||
.join(EOL);
|
||||
}
|
||||
|
||||
export interface SqlMigrationServiceProperties {
|
||||
name: string;
|
||||
subscriptionId: string;
|
||||
|
||||
@@ -29,6 +29,7 @@ export const MenuCommands = {
|
||||
CancelMigration: 'sqlmigration.cancel.migration',
|
||||
DeleteMigration: 'sqlmigration.delete.migration',
|
||||
RetryMigration: 'sqlmigration.retry.migration',
|
||||
RestartMigration: 'sqlmigration.restart.migration',
|
||||
StartMigration: 'sqlmigration.start',
|
||||
StartLoginMigration: 'sqlmigration.login.start',
|
||||
IssueReporter: 'workbench.action.openIssueReporter',
|
||||
|
||||
@@ -264,6 +264,11 @@ export function canDeleteMigration(migration: DatabaseMigration | undefined): bo
|
||||
}
|
||||
|
||||
export function canRetryMigration(migration: DatabaseMigration | undefined): boolean {
|
||||
const status = getMigrationStatus(migration);
|
||||
return status === loc.MigrationState.Retriable;
|
||||
}
|
||||
|
||||
export function canRestartMigrationWizard(migration: DatabaseMigration | undefined): boolean {
|
||||
const status = getMigrationStatus(migration);
|
||||
return status === loc.MigrationState.Canceled
|
||||
|| status === loc.MigrationState.Retriable
|
||||
|
||||
@@ -1042,6 +1042,10 @@ export const DETAILS_COPIED = localize('sql.migration.details.copied', "Details
|
||||
export const CANCEL_MIGRATION_CONFIRMATION = localize('sql.cancel.migration.confirmation', "Are you sure you want to cancel this migration?");
|
||||
export const DELETE_MIGRATION_CONFIRMATION = localize('sql.delete.migration.confirmation', "Are you sure you want to delete this migration?");
|
||||
|
||||
export const RETRY_MIGRATION_TITLE = localize('sql.retry.migration.title', "The migration failed with the following errors:");
|
||||
export const RETRY_MIGRATION_SUMMARY = localize('sql.retry.migration.summary', "Please resolve any errors before retrying the migration.");
|
||||
export const RETRY_MIGRATION_PROMPT = localize('sql.retry.migration.prompt', "Do you want to retry the failed table migrations?");
|
||||
|
||||
export const YES = localize('sql.migration.yes', "Yes");
|
||||
export const NO = localize('sql.migration.no', "No");
|
||||
export const NA = localize('sql.migration.na', "N/A");
|
||||
@@ -1361,6 +1365,11 @@ export const MIGRATION_CANNOT_RETRY = localize('sql.migration.cannot.retry', 'Mi
|
||||
export const RETRY_MIGRATION = localize('sql.migration.retry.migration', "Retry migration");
|
||||
export const MIGRATION_RETRY_ERROR = localize('sql.migration.retry.migration.error', 'An error occurred while retrying the migration.');
|
||||
|
||||
// Restart Migration
|
||||
export const MIGRATION_CANNOT_RESTART = localize('sql.migration.cannot.retry', 'Migration cannot be restarted.');
|
||||
export const RESTART_MIGRATION_WIZARD = localize('sql.migration.restart.migration.wizard', "Restart migration wizard");
|
||||
export const MIGRATION_RESTART_ERROR = localize('sql.migration.retry.migration.error', 'An error occurred while restarting the migration.');
|
||||
|
||||
export const INVALID_OWNER_URI = localize('sql.migration.invalid.owner.uri.error', 'Cannot connect to the database due to invalid OwnerUri (Parameter \'OwnerUri\')');
|
||||
export const DATABASE_BACKUP_PAGE_LOAD_ERROR = localize('sql.migration.database.backup.load.error', 'An error occurred while accessing database details.');
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import * as loc from '../constants/strings';
|
||||
import { convertByteSizeToReadableUnit, convertIsoTimeToLocalTime, getMigrationStatusImage } from '../api/utils';
|
||||
import { logError, TelemetryViews } from '../telemetry';
|
||||
import * as styles from '../constants/styles';
|
||||
import { canCancelMigration, canCutoverMigration, canDeleteMigration, canRetryMigration, getMigrationStatusString, getMigrationTargetTypeEnum, isOfflineMigation, isShirMigration } from '../constants/helper';
|
||||
import { canCancelMigration, canCutoverMigration, canDeleteMigration, canRestartMigrationWizard, getMigrationStatusString, getMigrationTargetTypeEnum, isOfflineMigation, isShirMigration } from '../constants/helper';
|
||||
import { AzureResourceKind, DatabaseMigration, getResourceName } from '../api/azure';
|
||||
import * as utils from '../api/utils';
|
||||
import * as helper from '../constants/helper';
|
||||
@@ -291,7 +291,7 @@ export class MigrationDetailsTab extends MigrationDetailsTabBase<MigrationDetail
|
||||
this.cutoverButton.enabled = canCutoverMigration(migration);
|
||||
this.cancelButton.enabled = canCancelMigration(migration);
|
||||
this.deleteButton.enabled = canDeleteMigration(migration);
|
||||
this.retryButton.enabled = canRetryMigration(migration);
|
||||
this.restartButton.enabled = canRestartMigrationWizard(migration);
|
||||
} catch (e) {
|
||||
await this.statusBar.showError(
|
||||
loc.MIGRATION_STATUS_REFRESH_ERROR,
|
||||
@@ -485,6 +485,8 @@ export class MigrationDetailsTab extends MigrationDetailsTabBase<MigrationDetail
|
||||
.withProps({ width: '100%' })
|
||||
.component();
|
||||
|
||||
await utils.updateControlDisplay(this.retryButton, false);
|
||||
|
||||
this.content = container;
|
||||
} catch (e) {
|
||||
logError(TelemetryViews.MigrationCutoverDialog, 'IntializingFailed', e);
|
||||
|
||||
@@ -8,15 +8,16 @@ import * as vscode from 'vscode';
|
||||
import { IconPathHelper } from '../constants/iconPathHelper';
|
||||
import { MigrationServiceContext } from '../models/migrationLocalStorage';
|
||||
import * as loc from '../constants/strings';
|
||||
import { DatabaseMigration, deleteMigration } from '../api/azure';
|
||||
import { DatabaseMigration, deleteMigration, getMigrationErrors, retryMigration } from '../api/azure';
|
||||
import { TabBase } from './tabBase';
|
||||
import { MigrationCutoverDialogModel } from '../dialog/migrationCutover/migrationCutoverDialogModel';
|
||||
import { ConfirmCutoverDialog } from '../dialog/migrationCutover/confirmCutoverDialog';
|
||||
import { RetryMigrationDialog } from '../dialog/retryMigration/retryMigrationDialog';
|
||||
import { RestartMigrationDialog } from '../dialog/restartMigration/restartMigrationDialog';
|
||||
import { DashboardStatusBar } from './DashboardStatusBar';
|
||||
import { canDeleteMigration } from '../constants/helper';
|
||||
import { canDeleteMigration, canRetryMigration } from '../constants/helper';
|
||||
import { logError, TelemetryViews } from '../telemetry';
|
||||
import { MenuCommands, MigrationTargetType } from '../api/utils';
|
||||
import { openRetryMigrationDialog } from '../dialog/retryMigration/retryMigrationDialog';
|
||||
|
||||
export const infoFieldLgWidth: string = '330px';
|
||||
export const infoFieldWidth: string = '250px';
|
||||
@@ -48,6 +49,7 @@ export abstract class MigrationDetailsTabBase<T> extends TabBase<T> {
|
||||
protected copyDatabaseMigrationDetails!: azdata.ButtonComponent;
|
||||
protected newSupportRequest!: azdata.ButtonComponent;
|
||||
protected retryButton!: azdata.ButtonComponent;
|
||||
protected restartButton!: azdata.ButtonComponent;
|
||||
protected summaryTextComponent: azdata.TextComponent[] = [];
|
||||
|
||||
public abstract create(
|
||||
@@ -241,14 +243,54 @@ export abstract class MigrationDetailsTabBase<T> extends TabBase<T> {
|
||||
|
||||
this.disposables.push(
|
||||
this.retryButton.onDidClick(
|
||||
async (e) => {
|
||||
await this.statusBar.clearError();
|
||||
if (canRetryMigration(this.model.migration)) {
|
||||
const errorMessage = getMigrationErrors(this.model.migration);
|
||||
await openRetryMigrationDialog(
|
||||
errorMessage,
|
||||
async () => {
|
||||
try {
|
||||
await retryMigration(
|
||||
this.serviceContext.azureAccount!,
|
||||
this.serviceContext.subscription!,
|
||||
this.model.migration);
|
||||
await this.refresh();
|
||||
} catch (e) {
|
||||
await this.statusBar.showError(
|
||||
loc.MIGRATION_RETRY_ERROR,
|
||||
loc.MIGRATION_RETRY_ERROR,
|
||||
e.message);
|
||||
logError(TelemetryViews.MigrationDetailsTab, MenuCommands.RetryMigration, e);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
await vscode.window.showInformationMessage(loc.MIGRATION_CANNOT_RETRY);
|
||||
logError(TelemetryViews.MigrationDetailsTab, MenuCommands.RetryMigration, "cannot retry migration");
|
||||
}
|
||||
}
|
||||
));
|
||||
|
||||
this.restartButton = this.view.modelBuilder.button()
|
||||
.withProps({
|
||||
label: loc.RESTART_MIGRATION_WIZARD,
|
||||
iconPath: IconPathHelper.retry,
|
||||
enabled: false,
|
||||
iconHeight: '16px',
|
||||
iconWidth: '16px',
|
||||
height: buttonHeight,
|
||||
}).component();
|
||||
|
||||
this.disposables.push(
|
||||
this.restartButton.onDidClick(
|
||||
async (e) => {
|
||||
await this.refresh();
|
||||
const retryMigrationDialog = new RetryMigrationDialog(
|
||||
const restartMigrationDialog = new RestartMigrationDialog(
|
||||
this.context,
|
||||
this.serviceContext,
|
||||
this.model.migration,
|
||||
this.serviceContextChangedEvent);
|
||||
await retryMigrationDialog.openDialog();
|
||||
await restartMigrationDialog.openDialog();
|
||||
}
|
||||
));
|
||||
|
||||
@@ -310,6 +352,7 @@ export abstract class MigrationDetailsTabBase<T> extends TabBase<T> {
|
||||
<azdata.ToolbarComponent>{ component: this.cancelButton },
|
||||
<azdata.ToolbarComponent>{ component: this.deleteButton },
|
||||
<azdata.ToolbarComponent>{ component: this.retryButton },
|
||||
<azdata.ToolbarComponent>{ component: this.restartButton },
|
||||
<azdata.ToolbarComponent>{ component: this.copyDatabaseMigrationDetails, toolbarSeparatorAfter: true },
|
||||
<azdata.ToolbarComponent>{ component: this.newSupportRequest, toolbarSeparatorAfter: true },
|
||||
<azdata.ToolbarComponent>{ component: this.refreshLoader },
|
||||
@@ -493,7 +536,7 @@ export abstract class MigrationDetailsTabBase<T> extends TabBase<T> {
|
||||
}
|
||||
|
||||
protected async showMigrationErrors(migration: DatabaseMigration): Promise<void> {
|
||||
const errorMessage = this.getMigrationErrors(migration);
|
||||
const errorMessage = getMigrationErrors(migration);
|
||||
if (errorMessage?.length > 0) {
|
||||
await this.statusBar.showError(
|
||||
loc.MIGRATION_ERROR_DETAILS_TITLE,
|
||||
|
||||
@@ -8,7 +8,7 @@ import * as vscode from 'vscode';
|
||||
import * as loc from '../constants/strings';
|
||||
import { getMigrationStatusImage, getPipelineStatusImage } from '../api/utils';
|
||||
import { logError, TelemetryViews } from '../telemetry';
|
||||
import { canCancelMigration, canCutoverMigration, canDeleteMigration, canRetryMigration, formatDateTimeString, formatNumber, formatSizeBytes, formatSizeKb, formatTime, getMigrationStatusString, getMigrationTargetTypeEnum, isOfflineMigation, PipelineStatusCodes } from '../constants/helper';
|
||||
import { canCancelMigration, canCutoverMigration, canDeleteMigration, canRestartMigrationWizard, canRetryMigration, formatDateTimeString, formatNumber, formatSizeBytes, formatSizeKb, formatTime, getMigrationStatusString, getMigrationTargetTypeEnum, isOfflineMigation, PipelineStatusCodes } from '../constants/helper';
|
||||
import { CopyProgressDetail, getResourceName } from '../api/azure';
|
||||
import { InfoFieldSchema, MigrationDetailsTabBase, MigrationTargetTypeName } from './migrationDetailsTabBase';
|
||||
import { IconPathHelper } from '../constants/iconPathHelper';
|
||||
@@ -328,6 +328,7 @@ export class MigrationDetailsTableTab extends MigrationDetailsTabBase<MigrationD
|
||||
this.cancelButton.enabled = canCancelMigration(migration);
|
||||
this.deleteButton.enabled = canDeleteMigration(migration);
|
||||
this.retryButton.enabled = canRetryMigration(migration);
|
||||
this.restartButton.enabled = canRestartMigrationWizard(migration);
|
||||
}
|
||||
|
||||
private async _populateTableData(hashSet: loc.LookupTable<number> = {}): Promise<void> {
|
||||
|
||||
@@ -9,8 +9,8 @@ import { IconPathHelper } from '../constants/iconPathHelper';
|
||||
import { getCurrentMigrations, getSelectedServiceStatus } from '../models/migrationLocalStorage';
|
||||
import * as loc from '../constants/strings';
|
||||
import { filterMigrations, getMigrationDuration, getMigrationStatusImage, getMigrationStatusWithErrors, getMigrationTime, MenuCommands } from '../api/utils';
|
||||
import { getMigrationTargetType, getMigrationMode, canCancelMigration, canCutoverMigration, canDeleteMigration } from '../constants/helper';
|
||||
import { DatabaseMigration, getResourceName } from '../api/azure';
|
||||
import { getMigrationTargetType, getMigrationMode, canCancelMigration, canCutoverMigration, canDeleteMigration, canRetryMigration } from '../constants/helper';
|
||||
import { DatabaseMigration, getMigrationErrors, getResourceName } from '../api/azure';
|
||||
import { logError, TelemetryViews } from '../telemetry';
|
||||
import { SelectMigrationServiceDialog } from '../dialog/selectMigrationService/selectMigrationServiceDialog';
|
||||
import { AdsMigrationStatus, EmptySettingValue, ServiceContextChangeEvent, TabBase } from './tabBase';
|
||||
@@ -565,7 +565,7 @@ export class MigrationsListTab extends TabBase<MigrationsListTab> {
|
||||
// "Migration status" column
|
||||
case 2:
|
||||
const statusMessage = loc.DATABASE_MIGRATION_STATUS_LABEL(getMigrationStatusWithErrors(migration));
|
||||
const errors = this.getMigrationErrors(migration!);
|
||||
const errors = getMigrationErrors(migration!);
|
||||
|
||||
this.showDialogMessage(
|
||||
loc.DATABASE_MIGRATION_STATUS_TITLE,
|
||||
@@ -592,8 +592,7 @@ export class MigrationsListTab extends TabBase<MigrationsListTab> {
|
||||
menuCommands.push(...[
|
||||
MenuCommands.ViewDatabase,
|
||||
MenuCommands.ViewTarget,
|
||||
MenuCommands.ViewService,
|
||||
MenuCommands.CopyMigration]);
|
||||
MenuCommands.ViewService]);
|
||||
|
||||
if (canCancelMigration(migration)) {
|
||||
menuCommands.push(MenuCommands.CancelMigration);
|
||||
@@ -603,6 +602,12 @@ export class MigrationsListTab extends TabBase<MigrationsListTab> {
|
||||
menuCommands.push(MenuCommands.DeleteMigration);
|
||||
}
|
||||
|
||||
if (canRetryMigration(migration)) {
|
||||
menuCommands.push(MenuCommands.RetryMigration);
|
||||
}
|
||||
|
||||
menuCommands.push(MenuCommands.CopyMigration);
|
||||
|
||||
return menuCommands;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,16 +6,16 @@
|
||||
import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import { promises as fs } from 'fs';
|
||||
import { DatabaseMigration, deleteMigration, getMigrationDetails } from '../api/azure';
|
||||
import { DatabaseMigration, deleteMigration, getMigrationDetails, getMigrationErrors, retryMigration } from '../api/azure';
|
||||
import { MenuCommands, SqlMigrationExtensionId } from '../api/utils';
|
||||
import { canCancelMigration, canCutoverMigration, canDeleteMigration, canRetryMigration } from '../constants/helper';
|
||||
import { canCancelMigration, canCutoverMigration, canDeleteMigration, canRestartMigrationWizard, canRetryMigration } from '../constants/helper';
|
||||
import { IconPathHelper } from '../constants/iconPathHelper';
|
||||
import { MigrationNotebookInfo, NotebookPathHelper } from '../constants/notebookPathHelper';
|
||||
import * as loc from '../constants/strings';
|
||||
import { SavedAssessmentDialog } from '../dialog/assessmentResults/savedAssessmentDialog';
|
||||
import { ConfirmCutoverDialog } from '../dialog/migrationCutover/confirmCutoverDialog';
|
||||
import { MigrationCutoverDialogModel } from '../dialog/migrationCutover/migrationCutoverDialogModel';
|
||||
import { RetryMigrationDialog } from '../dialog/retryMigration/retryMigrationDialog';
|
||||
import { RestartMigrationDialog } from '../dialog/restartMigration/restartMigrationDialog';
|
||||
import { SqlMigrationServiceDetailsDialog } from '../dialog/sqlMigrationService/sqlMigrationServiceDetailsDialog';
|
||||
import { MigrationLocalStorage } from '../models/migrationLocalStorage';
|
||||
import { MigrationStateModel, SavedInfo } from '../models/stateMachine';
|
||||
@@ -28,6 +28,7 @@ import { AdsMigrationStatus, MigrationDetailsEvent, ServiceContextChangeEvent }
|
||||
import { migrationServiceProvider } from '../service/provider';
|
||||
import { ApiType, SqlMigrationService } from '../service/features';
|
||||
import { getSourceConnectionId, getSourceConnectionProfile } from '../api/sqlUtils';
|
||||
import { openRetryMigrationDialog } from '../dialog/retryMigration/retryMigrationDialog';
|
||||
|
||||
export interface MenuCommandArgs {
|
||||
connectionId: string,
|
||||
@@ -354,28 +355,62 @@ export class DashboardWidget {
|
||||
this._context.subscriptions.push(
|
||||
vscode.commands.registerCommand(
|
||||
MenuCommands.RetryMigration,
|
||||
async (args: MenuCommandArgs) => {
|
||||
await this.clearError(args.connectionId);
|
||||
const service = await MigrationLocalStorage.getMigrationServiceContext();
|
||||
const migration = await this._getMigrationById(args.migrationId, args.migrationOperationId);
|
||||
if (service && migration && canRetryMigration(migration)) {
|
||||
const errorMessage = getMigrationErrors(migration);
|
||||
await openRetryMigrationDialog(
|
||||
errorMessage,
|
||||
async () => {
|
||||
try {
|
||||
await retryMigration(
|
||||
service.azureAccount!,
|
||||
service.subscription!,
|
||||
migration);
|
||||
await this._migrationsTab.refresh();
|
||||
} catch (e) {
|
||||
await this.showError(
|
||||
args.connectionId,
|
||||
loc.MIGRATION_RETRY_ERROR,
|
||||
loc.MIGRATION_RETRY_ERROR,
|
||||
e.message);
|
||||
logError(TelemetryViews.MigrationsTab, MenuCommands.RetryMigration, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
await vscode.window.showInformationMessage(loc.MIGRATION_CANNOT_RETRY);
|
||||
logError(TelemetryViews.MigrationsTab, MenuCommands.RetryMigration, "cannot retry migration");
|
||||
}
|
||||
}));
|
||||
|
||||
this._context.subscriptions.push(
|
||||
vscode.commands.registerCommand(
|
||||
MenuCommands.RestartMigration,
|
||||
async (args: MenuCommandArgs) => {
|
||||
try {
|
||||
await this.clearError(args.connectionId);
|
||||
const migration = await this._getMigrationById(args.migrationId, args.migrationOperationId);
|
||||
if (migration && canRetryMigration(migration)) {
|
||||
const retryMigrationDialog = new RetryMigrationDialog(
|
||||
if (migration && canRestartMigrationWizard(migration)) {
|
||||
const restartMigrationDialog = new RestartMigrationDialog(
|
||||
this._context,
|
||||
await MigrationLocalStorage.getMigrationServiceContext(),
|
||||
migration,
|
||||
this._onServiceContextChanged);
|
||||
await retryMigrationDialog.openDialog();
|
||||
await restartMigrationDialog.openDialog();
|
||||
}
|
||||
else {
|
||||
await vscode.window.showInformationMessage(loc.MIGRATION_CANNOT_RETRY);
|
||||
await vscode.window.showInformationMessage(loc.MIGRATION_CANNOT_RESTART);
|
||||
}
|
||||
} catch (e) {
|
||||
await this.showError(
|
||||
args.connectionId,
|
||||
loc.MIGRATION_RETRY_ERROR,
|
||||
loc.MIGRATION_RETRY_ERROR,
|
||||
loc.MIGRATION_RESTART_ERROR,
|
||||
loc.MIGRATION_RESTART_ERROR,
|
||||
e.message);
|
||||
logError(TelemetryViews.MigrationsTab, MenuCommands.RetryMigration, e);
|
||||
logError(TelemetryViews.MigrationsTab, MenuCommands.RestartMigration, e);
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
@@ -7,8 +7,6 @@ import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import * as loc from '../constants/strings';
|
||||
import { IconPathHelper } from '../constants/iconPathHelper';
|
||||
import { EOL } from 'os';
|
||||
import { DatabaseMigration } from '../api/azure';
|
||||
import { getSelectedServiceStatus } from '../models/migrationLocalStorage';
|
||||
import { MenuCommands, SqlMigrationExtensionId } from '../api/utils';
|
||||
import { DashboardStatusBar } from './DashboardStatusBar';
|
||||
@@ -184,20 +182,6 @@ export abstract class TabBase<T> implements azdata.Tab, vscode.Disposable {
|
||||
return feedbackButton;
|
||||
}
|
||||
|
||||
protected getMigrationErrors(migration: DatabaseMigration): string {
|
||||
const errors = [];
|
||||
errors.push(migration.properties.provisioningError);
|
||||
errors.push(migration.properties.migrationFailureError?.message);
|
||||
errors.push(migration.properties.migrationStatusDetails?.fileUploadBlockingErrors ?? []);
|
||||
errors.push(migration.properties.migrationStatusDetails?.restoreBlockingReason);
|
||||
errors.push(migration.properties.migrationStatusDetails?.sqlDataCopyErrors);
|
||||
|
||||
// remove undefined and duplicate error entries
|
||||
return errors
|
||||
.filter((e, i, arr) => e !== undefined && i === arr.indexOf(e))
|
||||
.join(EOL);
|
||||
}
|
||||
|
||||
protected showDialogMessage(
|
||||
title: string,
|
||||
statusMessage: string,
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 * as vscode from 'vscode';
|
||||
import * as features from '../../service/features';
|
||||
import { azureResource } from 'azurecore';
|
||||
import { getLocations, getResourceGroupFromId, getBlobContainerId, getFullResourceGroupFromId, getResourceName, DatabaseMigration, getMigrationTargetInstance } from '../../api/azure';
|
||||
import { MigrationMode, MigrationStateModel, NetworkContainerType, SavedInfo } from '../../models/stateMachine';
|
||||
import { MigrationServiceContext } from '../../models/migrationLocalStorage';
|
||||
import { WizardController } from '../../wizard/wizardController';
|
||||
import { getMigrationModeEnum, getMigrationTargetTypeEnum } from '../../constants/helper';
|
||||
import * as constants from '../../constants/strings';
|
||||
import { ServiceContextChangeEvent } from '../../dashboard/tabBase';
|
||||
import { migrationServiceProvider } from '../../service/provider';
|
||||
import { getSourceConnectionProfile } from '../../api/sqlUtils';
|
||||
|
||||
export class RestartMigrationDialog {
|
||||
|
||||
constructor(
|
||||
private readonly _context: vscode.ExtensionContext,
|
||||
private readonly _serviceContext: MigrationServiceContext,
|
||||
private readonly _migration: DatabaseMigration,
|
||||
private readonly _serviceContextChangedEvent: vscode.EventEmitter<ServiceContextChangeEvent>) {
|
||||
}
|
||||
|
||||
private async createMigrationStateModel(
|
||||
serviceContext: MigrationServiceContext,
|
||||
migration: DatabaseMigration,
|
||||
serverName: string,
|
||||
migrationService: features.SqlMigrationService,
|
||||
location: azureResource.AzureLocation): Promise<MigrationStateModel> {
|
||||
|
||||
const stateModel = new MigrationStateModel(this._context, migrationService);
|
||||
const sourceDatabaseName = migration.properties.sourceDatabaseName;
|
||||
const savedInfo: SavedInfo = {
|
||||
closedPage: 0,
|
||||
|
||||
// DatabaseSelector
|
||||
databaseAssessment: [sourceDatabaseName],
|
||||
|
||||
// SKURecommendation
|
||||
databaseList: [sourceDatabaseName],
|
||||
databaseInfoList: [],
|
||||
serverAssessment: null,
|
||||
skuRecommendation: null,
|
||||
migrationTargetType: getMigrationTargetTypeEnum(migration)!,
|
||||
|
||||
// TargetSelection
|
||||
azureAccount: serviceContext.azureAccount!,
|
||||
azureTenant: serviceContext.azureAccount!.properties.tenants[0]!,
|
||||
subscription: serviceContext.subscription!,
|
||||
location: location,
|
||||
resourceGroup: {
|
||||
id: getFullResourceGroupFromId(migration.id),
|
||||
name: getResourceGroupFromId(migration.id),
|
||||
subscription: serviceContext.subscription!,
|
||||
},
|
||||
targetServerInstance: await getMigrationTargetInstance(
|
||||
serviceContext.azureAccount!,
|
||||
serviceContext.subscription!,
|
||||
migration),
|
||||
|
||||
// MigrationMode
|
||||
migrationMode: getMigrationModeEnum(migration),
|
||||
|
||||
// DatabaseBackup
|
||||
targetDatabaseNames: [migration.name],
|
||||
networkContainerType: null,
|
||||
networkShares: [],
|
||||
blobs: [],
|
||||
|
||||
// Integration Runtime
|
||||
sqlMigrationService: serviceContext.migrationService,
|
||||
};
|
||||
|
||||
const getStorageAccountResourceGroup = (storageAccountResourceId: string): azureResource.AzureResourceResourceGroup => {
|
||||
return {
|
||||
id: getFullResourceGroupFromId(storageAccountResourceId!),
|
||||
name: getResourceGroupFromId(storageAccountResourceId!),
|
||||
subscription: this._serviceContext.subscription!
|
||||
};
|
||||
};
|
||||
const getStorageAccount = (storageAccountResourceId: string): azureResource.AzureGraphResource => {
|
||||
const storageAccountName = getResourceName(storageAccountResourceId);
|
||||
return {
|
||||
type: 'microsoft.storage/storageaccounts',
|
||||
id: storageAccountResourceId!,
|
||||
tenantId: savedInfo.azureTenant?.id!,
|
||||
subscriptionId: this._serviceContext.subscription?.id!,
|
||||
name: storageAccountName,
|
||||
location: savedInfo.location!.name,
|
||||
};
|
||||
};
|
||||
|
||||
const sourceLocation = migration.properties.backupConfiguration?.sourceLocation;
|
||||
if (sourceLocation?.fileShare) {
|
||||
savedInfo.networkContainerType = NetworkContainerType.NETWORK_SHARE;
|
||||
const storageAccountResourceId = migration.properties.backupConfiguration?.targetLocation?.storageAccountResourceId!;
|
||||
savedInfo.networkShares = [
|
||||
{
|
||||
password: '',
|
||||
networkShareLocation: sourceLocation?.fileShare?.path!,
|
||||
windowsUser: sourceLocation?.fileShare?.username!,
|
||||
storageAccount: getStorageAccount(storageAccountResourceId!),
|
||||
resourceGroup: getStorageAccountResourceGroup(storageAccountResourceId!),
|
||||
storageKey: ''
|
||||
}
|
||||
];
|
||||
} else if (sourceLocation?.azureBlob) {
|
||||
savedInfo.networkContainerType = NetworkContainerType.BLOB_CONTAINER;
|
||||
const storageAccountResourceId = sourceLocation?.azureBlob?.storageAccountResourceId!;
|
||||
savedInfo.blobs = [
|
||||
{
|
||||
blobContainer: {
|
||||
id: getBlobContainerId(getFullResourceGroupFromId(storageAccountResourceId!), getResourceName(storageAccountResourceId!), sourceLocation?.azureBlob.blobContainerName),
|
||||
name: sourceLocation?.azureBlob.blobContainerName,
|
||||
subscription: this._serviceContext.subscription!
|
||||
},
|
||||
lastBackupFile: getMigrationModeEnum(migration) === MigrationMode.OFFLINE ? migration.properties.offlineConfiguration?.lastBackupName! : undefined,
|
||||
storageAccount: getStorageAccount(storageAccountResourceId!),
|
||||
resourceGroup: getStorageAccountResourceGroup(storageAccountResourceId!),
|
||||
storageKey: ''
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
stateModel.restartMigration = true;
|
||||
stateModel.savedInfo = savedInfo;
|
||||
stateModel.serverName = serverName;
|
||||
return stateModel;
|
||||
}
|
||||
|
||||
public async openDialog(dialogName?: string) {
|
||||
const locations = await getLocations(
|
||||
this._serviceContext.azureAccount!,
|
||||
this._serviceContext.subscription!);
|
||||
|
||||
const targetInstance = await getMigrationTargetInstance(
|
||||
this._serviceContext.azureAccount!,
|
||||
this._serviceContext.subscription!,
|
||||
this._migration);
|
||||
|
||||
let location: azureResource.AzureLocation;
|
||||
locations.forEach(azureLocation => {
|
||||
if (azureLocation.name === targetInstance.location) {
|
||||
location = azureLocation;
|
||||
}
|
||||
});
|
||||
|
||||
const activeConnection = await getSourceConnectionProfile();
|
||||
let serverName: string = '';
|
||||
if (!activeConnection) {
|
||||
const connection = await azdata.connection.openConnectionDialog();
|
||||
if (connection) {
|
||||
serverName = connection.options.server;
|
||||
}
|
||||
} else {
|
||||
serverName = activeConnection.serverName;
|
||||
}
|
||||
|
||||
const migrationService = <features.SqlMigrationService>await migrationServiceProvider.getService(features.ApiType.SqlMigrationProvider)!;
|
||||
const stateModel = await this.createMigrationStateModel(this._serviceContext, this._migration, serverName, migrationService, location!);
|
||||
|
||||
if (await stateModel.loadSavedInfo()) {
|
||||
const wizardController = new WizardController(
|
||||
this._context,
|
||||
stateModel,
|
||||
this._serviceContextChangedEvent);
|
||||
await wizardController.openWizard();
|
||||
} else {
|
||||
void vscode.window.showInformationMessage(constants.MIGRATION_CANNOT_RESTART);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,173 +5,82 @@
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import * as features from '../../service/features';
|
||||
import { azureResource } from 'azurecore';
|
||||
import { getLocations, getResourceGroupFromId, getBlobContainerId, getFullResourceGroupFromId, getResourceName, DatabaseMigration, getMigrationTargetInstance } from '../../api/azure';
|
||||
import { MigrationMode, MigrationStateModel, NetworkContainerType, SavedInfo } from '../../models/stateMachine';
|
||||
import { MigrationServiceContext } from '../../models/migrationLocalStorage';
|
||||
import { WizardController } from '../../wizard/wizardController';
|
||||
import { getMigrationModeEnum, getMigrationTargetTypeEnum } from '../../constants/helper';
|
||||
import * as constants from '../../constants/strings';
|
||||
import { ServiceContextChangeEvent } from '../../dashboard/tabBase';
|
||||
import { migrationServiceProvider } from '../../service/provider';
|
||||
import { getSourceConnectionProfile } from '../../api/sqlUtils';
|
||||
|
||||
export class RetryMigrationDialog {
|
||||
export function openRetryMigrationDialog(
|
||||
errorMessage: string,
|
||||
onAcceptCallback: () => Promise<void>): void {
|
||||
|
||||
constructor(
|
||||
private readonly _context: vscode.ExtensionContext,
|
||||
private readonly _serviceContext: MigrationServiceContext,
|
||||
private readonly _migration: DatabaseMigration,
|
||||
private readonly _serviceContextChangedEvent: vscode.EventEmitter<ServiceContextChangeEvent>) {
|
||||
}
|
||||
const disposables: vscode.Disposable[] = [];
|
||||
const tab = azdata.window.createTab('');
|
||||
|
||||
private async createMigrationStateModel(
|
||||
serviceContext: MigrationServiceContext,
|
||||
migration: DatabaseMigration,
|
||||
serverName: string,
|
||||
migrationService: features.SqlMigrationService,
|
||||
location: azureResource.AzureLocation): Promise<MigrationStateModel> {
|
||||
tab.registerContent(async (view) => {
|
||||
disposables.push(
|
||||
view.onClosed(e =>
|
||||
disposables.forEach(
|
||||
d => { try { d.dispose(); } catch { } })));
|
||||
|
||||
const stateModel = new MigrationStateModel(this._context, migrationService);
|
||||
const sourceDatabaseName = migration.properties.sourceDatabaseName;
|
||||
const savedInfo: SavedInfo = {
|
||||
closedPage: 0,
|
||||
const flex = view.modelBuilder.flexContainer()
|
||||
.withItems([
|
||||
view.modelBuilder.text()
|
||||
.withProps({
|
||||
value: constants.RETRY_MIGRATION_TITLE,
|
||||
title: constants.RETRY_MIGRATION_TITLE,
|
||||
CSSStyles: { 'font-weight': '600', 'margin': '10px 0px 5px 0px' },
|
||||
})
|
||||
.component(),
|
||||
view.modelBuilder.inputBox()
|
||||
.withProps({
|
||||
value: errorMessage,
|
||||
title: errorMessage,
|
||||
readOnly: true,
|
||||
multiline: true,
|
||||
inputType: 'text',
|
||||
rows: 10,
|
||||
CSSStyles: { 'overflow': 'hidden auto', 'margin': '0px 0px 10px 0px' },
|
||||
})
|
||||
.component(),
|
||||
view.modelBuilder.text()
|
||||
.withProps({
|
||||
value: constants.RETRY_MIGRATION_SUMMARY,
|
||||
title: constants.RETRY_MIGRATION_SUMMARY,
|
||||
CSSStyles: { 'margin': '0px 0px 10px 0px' },
|
||||
})
|
||||
.component(),
|
||||
view.modelBuilder.text()
|
||||
.withProps({
|
||||
value: constants.RETRY_MIGRATION_PROMPT,
|
||||
title: constants.RETRY_MIGRATION_PROMPT,
|
||||
CSSStyles: { 'margin': '0px 0px 5px 0px' },
|
||||
})
|
||||
.component(),
|
||||
])
|
||||
.withLayout({ flexFlow: 'column', })
|
||||
.withProps({ CSSStyles: { 'margin': '0 15px 0 15px' } })
|
||||
.component();
|
||||
|
||||
// DatabaseSelector
|
||||
databaseAssessment: [sourceDatabaseName],
|
||||
await view.initializeModel(flex);
|
||||
});
|
||||
|
||||
// SKURecommendation
|
||||
databaseList: [sourceDatabaseName],
|
||||
databaseInfoList: [],
|
||||
serverAssessment: null,
|
||||
skuRecommendation: null,
|
||||
migrationTargetType: getMigrationTargetTypeEnum(migration)!,
|
||||
const dialog = azdata.window.createModelViewDialog(
|
||||
'',
|
||||
'retryMigrationDialog',
|
||||
500,
|
||||
'normal',
|
||||
undefined,
|
||||
false);
|
||||
dialog.content = [tab];
|
||||
dialog.okButton.label = constants.YES;
|
||||
dialog.okButton.position = 'left';
|
||||
dialog.cancelButton.label = constants.NO;
|
||||
dialog.cancelButton.position = 'left';
|
||||
dialog.cancelButton.focused = true;
|
||||
|
||||
// TargetSelection
|
||||
azureAccount: serviceContext.azureAccount!,
|
||||
azureTenant: serviceContext.azureAccount!.properties.tenants[0]!,
|
||||
subscription: serviceContext.subscription!,
|
||||
location: location,
|
||||
resourceGroup: {
|
||||
id: getFullResourceGroupFromId(migration.id),
|
||||
name: getResourceGroupFromId(migration.id),
|
||||
subscription: serviceContext.subscription!,
|
||||
},
|
||||
targetServerInstance: await getMigrationTargetInstance(
|
||||
serviceContext.azureAccount!,
|
||||
serviceContext.subscription!,
|
||||
migration),
|
||||
|
||||
// MigrationMode
|
||||
migrationMode: getMigrationModeEnum(migration),
|
||||
|
||||
// DatabaseBackup
|
||||
targetDatabaseNames: [migration.name],
|
||||
networkContainerType: null,
|
||||
networkShares: [],
|
||||
blobs: [],
|
||||
disposables.push(
|
||||
dialog.okButton.onClick(
|
||||
async e => await onAcceptCallback()));
|
||||
|
||||
// Integration Runtime
|
||||
sqlMigrationService: serviceContext.migrationService,
|
||||
};
|
||||
|
||||
const getStorageAccountResourceGroup = (storageAccountResourceId: string): azureResource.AzureResourceResourceGroup => {
|
||||
return {
|
||||
id: getFullResourceGroupFromId(storageAccountResourceId!),
|
||||
name: getResourceGroupFromId(storageAccountResourceId!),
|
||||
subscription: this._serviceContext.subscription!
|
||||
};
|
||||
};
|
||||
const getStorageAccount = (storageAccountResourceId: string): azureResource.AzureGraphResource => {
|
||||
const storageAccountName = getResourceName(storageAccountResourceId);
|
||||
return {
|
||||
type: 'microsoft.storage/storageaccounts',
|
||||
id: storageAccountResourceId!,
|
||||
tenantId: savedInfo.azureTenant?.id!,
|
||||
subscriptionId: this._serviceContext.subscription?.id!,
|
||||
name: storageAccountName,
|
||||
location: savedInfo.location!.name,
|
||||
};
|
||||
};
|
||||
|
||||
const sourceLocation = migration.properties.backupConfiguration?.sourceLocation;
|
||||
if (sourceLocation?.fileShare) {
|
||||
savedInfo.networkContainerType = NetworkContainerType.NETWORK_SHARE;
|
||||
const storageAccountResourceId = migration.properties.backupConfiguration?.targetLocation?.storageAccountResourceId!;
|
||||
savedInfo.networkShares = [
|
||||
{
|
||||
password: '',
|
||||
networkShareLocation: sourceLocation?.fileShare?.path!,
|
||||
windowsUser: sourceLocation?.fileShare?.username!,
|
||||
storageAccount: getStorageAccount(storageAccountResourceId!),
|
||||
resourceGroup: getStorageAccountResourceGroup(storageAccountResourceId!),
|
||||
storageKey: ''
|
||||
}
|
||||
];
|
||||
} else if (sourceLocation?.azureBlob) {
|
||||
savedInfo.networkContainerType = NetworkContainerType.BLOB_CONTAINER;
|
||||
const storageAccountResourceId = sourceLocation?.azureBlob?.storageAccountResourceId!;
|
||||
savedInfo.blobs = [
|
||||
{
|
||||
blobContainer: {
|
||||
id: getBlobContainerId(getFullResourceGroupFromId(storageAccountResourceId!), getResourceName(storageAccountResourceId!), sourceLocation?.azureBlob.blobContainerName),
|
||||
name: sourceLocation?.azureBlob.blobContainerName,
|
||||
subscription: this._serviceContext.subscription!
|
||||
},
|
||||
lastBackupFile: getMigrationModeEnum(migration) === MigrationMode.OFFLINE ? migration.properties.offlineConfiguration?.lastBackupName! : undefined,
|
||||
storageAccount: getStorageAccount(storageAccountResourceId!),
|
||||
resourceGroup: getStorageAccountResourceGroup(storageAccountResourceId!),
|
||||
storageKey: ''
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
stateModel.retryMigration = true;
|
||||
stateModel.savedInfo = savedInfo;
|
||||
stateModel.serverName = serverName;
|
||||
return stateModel;
|
||||
}
|
||||
|
||||
public async openDialog(dialogName?: string) {
|
||||
const locations = await getLocations(
|
||||
this._serviceContext.azureAccount!,
|
||||
this._serviceContext.subscription!);
|
||||
|
||||
const targetInstance = await getMigrationTargetInstance(
|
||||
this._serviceContext.azureAccount!,
|
||||
this._serviceContext.subscription!,
|
||||
this._migration);
|
||||
|
||||
let location: azureResource.AzureLocation;
|
||||
locations.forEach(azureLocation => {
|
||||
if (azureLocation.name === targetInstance.location) {
|
||||
location = azureLocation;
|
||||
}
|
||||
});
|
||||
|
||||
const activeConnection = await getSourceConnectionProfile();
|
||||
let serverName: string = '';
|
||||
if (!activeConnection) {
|
||||
const connection = await azdata.connection.openConnectionDialog();
|
||||
if (connection) {
|
||||
serverName = connection.options.server;
|
||||
}
|
||||
} else {
|
||||
serverName = activeConnection.serverName;
|
||||
}
|
||||
|
||||
const migrationService = <features.SqlMigrationService>await migrationServiceProvider.getService(features.ApiType.SqlMigrationProvider)!;
|
||||
const stateModel = await this.createMigrationStateModel(this._serviceContext, this._migration, serverName, migrationService, location!);
|
||||
|
||||
if (await stateModel.loadSavedInfo()) {
|
||||
const wizardController = new WizardController(
|
||||
this._context,
|
||||
stateModel,
|
||||
this._serviceContextChangedEvent);
|
||||
await wizardController.openWizard();
|
||||
} else {
|
||||
void vscode.window.showInformationMessage(constants.MIGRATION_CANNOT_RETRY);
|
||||
}
|
||||
}
|
||||
azdata.window.openDialog(dialog);
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ export enum Page {
|
||||
export enum WizardEntryPoint {
|
||||
Default = 'Default',
|
||||
SaveAndClose = 'SaveAndClose',
|
||||
RetryMigration = 'RetryMigration',
|
||||
RestartMigration = 'RestartMigration',
|
||||
}
|
||||
|
||||
export enum PerformanceDataSourceOptions {
|
||||
@@ -260,7 +260,7 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
public _skuEnableElastic!: boolean;
|
||||
|
||||
public refreshDatabaseBackupPage!: boolean;
|
||||
public retryMigration!: boolean;
|
||||
public restartMigration!: boolean;
|
||||
public resumeAssessment!: boolean;
|
||||
public savedInfo!: SavedInfo;
|
||||
public closedPage!: number;
|
||||
@@ -1121,8 +1121,8 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
let wizardEntryPoint = WizardEntryPoint.Default;
|
||||
if (this.resumeAssessment) {
|
||||
wizardEntryPoint = WizardEntryPoint.SaveAndClose;
|
||||
} else if (this.retryMigration) {
|
||||
wizardEntryPoint = WizardEntryPoint.RetryMigration;
|
||||
} else if (this.restartMigration) {
|
||||
wizardEntryPoint = WizardEntryPoint.RestartMigration;
|
||||
}
|
||||
if (response.status === 201 || response.status === 200) {
|
||||
sendSqlMigrationActionEvent(
|
||||
@@ -1167,7 +1167,7 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
finally {
|
||||
// kill existing data collection if user start migration
|
||||
await this.refreshPerfDataCollection();
|
||||
if ((!this.resumeAssessment || this.retryMigration) && this._perfDataCollectionIsCollecting) {
|
||||
if ((!this.resumeAssessment || this.restartMigration) && this._perfDataCollectionIsCollecting) {
|
||||
void this.stopPerfDataCollection();
|
||||
void vscode.window.showInformationMessage(
|
||||
constants.AZURE_RECOMMENDATION_STOP_POPUP);
|
||||
|
||||
@@ -99,7 +99,7 @@ export class WizardController {
|
||||
|
||||
// kill existing data collection if user relaunches the wizard via new migration or retry existing migration
|
||||
await this._model.refreshPerfDataCollection();
|
||||
if ((!this._model.resumeAssessment || this._model.retryMigration) && this._model._perfDataCollectionIsCollecting) {
|
||||
if ((!this._model.resumeAssessment || this._model.restartMigration) && this._model._perfDataCollectionIsCollecting) {
|
||||
void this._model.stopPerfDataCollection();
|
||||
void vscode.window.showInformationMessage(loc.AZURE_RECOMMENDATION_STOP_POPUP);
|
||||
}
|
||||
@@ -107,7 +107,7 @@ export class WizardController {
|
||||
const wizardSetupPromises: Thenable<void>[] = [];
|
||||
wizardSetupPromises.push(...pages.map(p => p.registerWizardContent()));
|
||||
wizardSetupPromises.push(this._wizardObject.open());
|
||||
if (this._model.retryMigration || this._model.resumeAssessment) {
|
||||
if (this._model.resumeAssessment || this._model.restartMigration) {
|
||||
if (this._model.savedInfo.closedPage >= Page.IntegrationRuntime) {
|
||||
this._model.refreshDatabaseBackupPage = true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user