mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-11 10:38:31 -05:00
Retry sql migration (#17376)
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import { MigrationStateModel, MigrationTargetType } from '../../models/stateMachine';
|
||||
import { MigrationStateModel, MigrationTargetType, Page } from '../../models/stateMachine';
|
||||
import { SqlDatabaseTree } from './sqlDatabasesTree';
|
||||
import { SqlMigrationImpactedObjectInfo } from '../../../../mssql/src/mssql';
|
||||
import { SKURecommendationPage } from '../../wizard/skuRecommendationPage';
|
||||
@@ -32,7 +32,7 @@ export class AssessmentResultsDialog {
|
||||
|
||||
constructor(public ownerUri: string, public model: MigrationStateModel, public title: string, private _skuRecommendationPage: SKURecommendationPage, private _targetType: MigrationTargetType) {
|
||||
this._model = model;
|
||||
if (this._model.resumeAssessment && this._model.savedInfo.closedPage >= 2) {
|
||||
if (this._model.resumeAssessment && this._model.savedInfo.closedPage >= Page.DatabaseBackup) {
|
||||
this._model._databaseAssessment = <string[]>this._model.savedInfo.databaseAssessment;
|
||||
}
|
||||
this._tree = new SqlDatabaseTree(this._model, this._targetType);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import { SqlMigrationAssessmentResultItem, SqlMigrationImpactedObjectInfo } from '../../../../mssql/src/mssql';
|
||||
import { MigrationStateModel, MigrationTargetType } from '../../models/stateMachine';
|
||||
import { MigrationStateModel, MigrationTargetType, Page } from '../../models/stateMachine';
|
||||
import * as constants from '../../constants/strings';
|
||||
import { debounce } from '../../api/utils';
|
||||
import { IconPath, IconPathHelper } from '../../constants/iconPathHelper';
|
||||
@@ -142,7 +142,7 @@ export class SqlDatabaseTree {
|
||||
...styles.BOLD_NOTE_CSS,
|
||||
'margin': '0px 15px 0px 15px'
|
||||
},
|
||||
value: constants.DATABASES(0, this._model._databaseAssessment.length)
|
||||
value: constants.DATABASES(0, this._model._databaseAssessment?.length)
|
||||
}).component();
|
||||
return this._databaseCount;
|
||||
}
|
||||
@@ -187,10 +187,7 @@ export class SqlDatabaseTree {
|
||||
).component();
|
||||
|
||||
this._disposables.push(this._databaseTable.onDataChanged(async () => {
|
||||
await this._databaseCount.updateProperties({
|
||||
'value': constants.DATABASES(this.selectedDbs().length, this._model._databaseAssessment.length)
|
||||
});
|
||||
this._model._databaseSelection = <azdata.DeclarativeTableCellValue[][]>this._databaseTable.dataValues;
|
||||
await this.updateValuesOnSelection();
|
||||
}));
|
||||
|
||||
this._disposables.push(this._databaseTable.onRowSelected(async (e) => {
|
||||
@@ -200,7 +197,7 @@ export class SqlDatabaseTree {
|
||||
this._activeIssues = [];
|
||||
}
|
||||
this._dbName.value = this._dbNames[e.row];
|
||||
this._recommendationTitle.value = constants.ISSUES_COUNT(this._activeIssues.length);
|
||||
this._recommendationTitle.value = constants.ISSUES_COUNT(this._activeIssues?.length);
|
||||
this._recommendation.value = constants.ISSUES_DETAILS;
|
||||
await this._resultComponent.updateCssStyles({
|
||||
'display': 'block'
|
||||
@@ -307,7 +304,7 @@ export class SqlDatabaseTree {
|
||||
'display': 'none'
|
||||
});
|
||||
this._recommendation.value = constants.WARNINGS_DETAILS;
|
||||
this._recommendationTitle.value = constants.WARNINGS_COUNT(this._activeIssues.length);
|
||||
this._recommendationTitle.value = constants.WARNINGS_COUNT(this._activeIssues?.length);
|
||||
if (this._targetType === MigrationTargetType.SQLMI) {
|
||||
await this.refreshResults();
|
||||
}
|
||||
@@ -424,7 +421,7 @@ export class SqlDatabaseTree {
|
||||
}
|
||||
|
||||
private handleFailedAssessment(): boolean {
|
||||
const failedAssessment: boolean = this._model._assessmentResults.assessmentError !== undefined
|
||||
const failedAssessment: boolean = this._model._assessmentResults?.assessmentError !== undefined
|
||||
|| (this._model._assessmentResults?.errors?.length || 0) > 0;
|
||||
if (failedAssessment) {
|
||||
this._dialog.message = {
|
||||
@@ -439,12 +436,12 @@ export class SqlDatabaseTree {
|
||||
|
||||
private getAssessmentError(): string {
|
||||
const errors: string[] = [];
|
||||
const assessmentError = this._model._assessmentResults.assessmentError;
|
||||
const assessmentError = this._model._assessmentResults?.assessmentError;
|
||||
if (assessmentError) {
|
||||
errors.push(`message: ${assessmentError.message}${EOL}stack: ${assessmentError.stack}`);
|
||||
}
|
||||
if (this._model?._assessmentResults?.errors?.length! > 0) {
|
||||
errors.push(...this._model._assessmentResults.errors?.map(
|
||||
errors.push(...this._model._assessmentResults?.errors?.map(
|
||||
e => `message: ${e.message}${EOL}errorSummary: ${e.errorSummary}${EOL}possibleCauses: ${e.possibleCauses}${EOL}guidance: ${e.guidance}${EOL}errorId: ${e.errorId}`)!);
|
||||
}
|
||||
|
||||
@@ -791,7 +788,7 @@ export class SqlDatabaseTree {
|
||||
|
||||
public async refreshResults(): Promise<void> {
|
||||
if (this._targetType === MigrationTargetType.SQLMI) {
|
||||
if (this._activeIssues.length === 0) {
|
||||
if (this._activeIssues?.length === 0) {
|
||||
/// show no issues here
|
||||
await this._assessmentsTable.updateCssStyles({
|
||||
'display': 'none',
|
||||
@@ -858,7 +855,7 @@ export class SqlDatabaseTree {
|
||||
|| [];
|
||||
|
||||
await this._assessmentResultsTable.setDataValues(assessmentResults);
|
||||
this._assessmentResultsTable.selectedRow = assessmentResults.length > 0 ? 0 : -1;
|
||||
this._assessmentResultsTable.selectedRow = assessmentResults?.length > 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
public async refreshAssessmentDetails(selectedIssue?: SqlMigrationAssessmentResultItem): Promise<void> {
|
||||
@@ -872,7 +869,7 @@ export class SqlDatabaseTree {
|
||||
await this._impactedObjectsTable.setDataValues(this._impactedObjects.map(
|
||||
(object) => [{ value: object.objectType }, { value: object.name }]));
|
||||
|
||||
this._impactedObjectsTable.selectedRow = this._impactedObjects.length > 0 ? 0 : -1;
|
||||
this._impactedObjectsTable.selectedRow = this._impactedObjects?.length > 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
public refreshImpactedObject(impactedObject?: SqlMigrationImpactedObjectInfo): void {
|
||||
@@ -927,17 +924,17 @@ export class SqlDatabaseTree {
|
||||
style: styleLeft
|
||||
},
|
||||
{
|
||||
value: this._model._assessmentResults.issues.length,
|
||||
value: this._model._assessmentResults?.issues?.length,
|
||||
style: styleRight
|
||||
}
|
||||
]
|
||||
];
|
||||
this._model._assessmentResults.databaseAssessments.sort((db1, db2) => {
|
||||
return db2.issues.length - db1.issues.length;
|
||||
this._model._assessmentResults?.databaseAssessments.sort((db1, db2) => {
|
||||
return db2.issues?.length - db1.issues?.length;
|
||||
});
|
||||
// Reset the dbName list so that it is in sync with the table
|
||||
this._dbNames = this._model._assessmentResults.databaseAssessments.map(da => da.name);
|
||||
this._model._assessmentResults.databaseAssessments.forEach((db) => {
|
||||
this._dbNames = this._model._assessmentResults?.databaseAssessments.map(da => da.name);
|
||||
this._model._assessmentResults?.databaseAssessments.forEach((db) => {
|
||||
let selectable = true;
|
||||
if (db.issues.find(item => item.databaseRestoreFails)) {
|
||||
selectable = false;
|
||||
@@ -954,7 +951,7 @@ export class SqlDatabaseTree {
|
||||
style: styleLeft
|
||||
},
|
||||
{
|
||||
value: db.issues.length,
|
||||
value: db.issues?.length,
|
||||
style: styleRight
|
||||
}
|
||||
]
|
||||
@@ -962,13 +959,27 @@ export class SqlDatabaseTree {
|
||||
});
|
||||
}
|
||||
await this._instanceTable.setDataValues(instanceTableValues);
|
||||
if (this._model.resumeAssessment && this._model.savedInfo.closedPage >= 2) {
|
||||
if (this._model.resumeAssessment && this._model.savedInfo.closedPage >= Page.SKURecommendation && this._targetType === this._model.savedInfo.migrationTargetType) {
|
||||
await this._databaseTable.setDataValues(this._model.savedInfo.migrationDatabases);
|
||||
} else {
|
||||
if (this._model.retryMigration && this._targetType === this._model.savedInfo.migrationTargetType) {
|
||||
const sourceDatabaseName = this._model.savedInfo.databaseList[0];
|
||||
const sourceDatabaseIndex = this._dbNames.indexOf(sourceDatabaseName);
|
||||
this._databaseTableValues[sourceDatabaseIndex][0].value = true;
|
||||
}
|
||||
|
||||
await this._databaseTable.setDataValues(this._databaseTableValues);
|
||||
await this.updateValuesOnSelection();
|
||||
}
|
||||
}
|
||||
|
||||
private async updateValuesOnSelection() {
|
||||
await this._databaseCount.updateProperties({
|
||||
'value': constants.DATABASES(this.selectedDbs()?.length, this._model._databaseAssessment?.length)
|
||||
});
|
||||
this._model._databaseSelection = <azdata.DeclarativeTableCellValue[][]>this._databaseTable.dataValues;
|
||||
}
|
||||
|
||||
// undo when bug #16445 is fixed
|
||||
private createIconTextCell(icon: IconPath, text: string): string {
|
||||
return text;
|
||||
|
||||
@@ -12,15 +12,19 @@ import * as loc from '../../constants/strings';
|
||||
import { convertByteSizeToReadableUnit, convertIsoTimeToLocalTime, getSqlServerName, getMigrationStatusImage, SupportedAutoRefreshIntervals, clearDialogMessage, displayDialogErrorMessage } from '../../api/utils';
|
||||
import { EOL } from 'os';
|
||||
import { ConfirmCutoverDialog } from './confirmCutoverDialog';
|
||||
import { RetryMigrationDialog } from '../retryMigration/retryMigrationDialog';
|
||||
import * as styles from '../../constants/styles';
|
||||
import { canRetryMigration } from '../../constants/helper';
|
||||
|
||||
const refreshFrequency: SupportedAutoRefreshIntervals = 30000;
|
||||
const statusImageSize: number = 14;
|
||||
|
||||
export class MigrationCutoverDialog {
|
||||
private _context: vscode.ExtensionContext;
|
||||
private _dialogObject!: azdata.window.Dialog;
|
||||
private _view!: azdata.ModelView;
|
||||
private _model: MigrationCutoverDialogModel;
|
||||
private _migration: MigrationContext;
|
||||
|
||||
private _databaseTitleName!: azdata.TextComponent;
|
||||
private _cutoverButton!: azdata.ButtonComponent;
|
||||
@@ -29,6 +33,7 @@ export class MigrationCutoverDialog {
|
||||
private _refreshLoader!: azdata.LoadingComponent;
|
||||
private _copyDatabaseMigrationDetails!: azdata.ButtonComponent;
|
||||
private _newSupportRequest!: azdata.ButtonComponent;
|
||||
private _retryButton!: azdata.ButtonComponent;
|
||||
|
||||
private _sourceDatabaseInfoField!: InfoFieldSchema;
|
||||
private _sourceDetailsInfoField!: InfoFieldSchema;
|
||||
@@ -53,7 +58,9 @@ export class MigrationCutoverDialog {
|
||||
|
||||
readonly _infoFieldWidth: string = '250px';
|
||||
|
||||
constructor(migration: MigrationContext) {
|
||||
constructor(context: vscode.ExtensionContext, migration: MigrationContext) {
|
||||
this._context = context;
|
||||
this._migration = migration;
|
||||
this._model = new MigrationCutoverDialogModel(migration);
|
||||
this._dialogObject = azdata.window.createModelViewDialog('', 'MigrationCutoverDialog', 'wide');
|
||||
}
|
||||
@@ -301,11 +308,11 @@ export class MigrationCutoverDialog {
|
||||
iconWidth: '16px',
|
||||
label: loc.COMPLETE_CUTOVER,
|
||||
height: '20px',
|
||||
width: '150px',
|
||||
width: '140px',
|
||||
enabled: false,
|
||||
CSSStyles: {
|
||||
...styles.BODY_CSS,
|
||||
'display': this._isOnlineMigration() ? 'inline' : 'none'
|
||||
'display': this._isOnlineMigration() ? 'block' : 'none'
|
||||
}
|
||||
}).component();
|
||||
|
||||
@@ -330,7 +337,7 @@ export class MigrationCutoverDialog {
|
||||
iconWidth: '16px',
|
||||
label: loc.CANCEL_MIGRATION,
|
||||
height: '20px',
|
||||
width: '150px',
|
||||
width: '140px',
|
||||
enabled: false,
|
||||
CSSStyles: {
|
||||
...styles.BODY_CSS,
|
||||
@@ -353,6 +360,28 @@ export class MigrationCutoverDialog {
|
||||
flex: '0'
|
||||
});
|
||||
|
||||
this._retryButton = this._view.modelBuilder.button().withProps({
|
||||
label: loc.RETRY_MIGRATION,
|
||||
iconPath: IconPathHelper.retry,
|
||||
enabled: false,
|
||||
iconHeight: '16px',
|
||||
iconWidth: '16px',
|
||||
height: '20px',
|
||||
width: '120px',
|
||||
CSSStyles: {
|
||||
...styles.BODY_CSS,
|
||||
}
|
||||
}).component();
|
||||
this._disposables.push(this._retryButton.onDidClick(
|
||||
async (e) => {
|
||||
await this.refreshStatus();
|
||||
let retryMigrationDialog = new RetryMigrationDialog(this._context, this._migration);
|
||||
await retryMigrationDialog.openDialog();
|
||||
}
|
||||
));
|
||||
headerActions.addItem(this._retryButton, {
|
||||
flex: '0',
|
||||
});
|
||||
|
||||
this._refreshButton = this._view.modelBuilder.button().withProps({
|
||||
iconPath: IconPathHelper.refresh,
|
||||
@@ -360,7 +389,7 @@ export class MigrationCutoverDialog {
|
||||
iconWidth: '16px',
|
||||
label: 'Refresh',
|
||||
height: '20px',
|
||||
width: '100px',
|
||||
width: '80px',
|
||||
CSSStyles: {
|
||||
...styles.BODY_CSS,
|
||||
}
|
||||
@@ -379,7 +408,7 @@ export class MigrationCutoverDialog {
|
||||
iconWidth: '16px',
|
||||
label: loc.COPY_MIGRATION_DETAILS,
|
||||
height: '20px',
|
||||
width: '200px',
|
||||
width: '160px',
|
||||
CSSStyles: {
|
||||
...styles.BODY_CSS,
|
||||
}
|
||||
@@ -406,7 +435,7 @@ export class MigrationCutoverDialog {
|
||||
iconHeight: '16px',
|
||||
iconWidth: '16px',
|
||||
height: '20px',
|
||||
width: '180px',
|
||||
width: '160px',
|
||||
CSSStyles: {
|
||||
...styles.BODY_CSS,
|
||||
}
|
||||
@@ -567,7 +596,7 @@ export class MigrationCutoverDialog {
|
||||
|
||||
if (this._isOnlineMigration()) {
|
||||
await this._cutoverButton.updateCssStyles({
|
||||
'display': 'inline'
|
||||
'display': 'block'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -720,6 +749,9 @@ export class MigrationCutoverDialog {
|
||||
this._cancelButton.enabled =
|
||||
migrationStatusTextValue === MigrationStatus.Creating ||
|
||||
migrationStatusTextValue === MigrationStatus.InProgress;
|
||||
|
||||
this._retryButton.enabled = canRetryMigration(migrationStatusTextValue);
|
||||
|
||||
} catch (e) {
|
||||
displayDialogErrorMessage(this._dialogObject, loc.MIGRATION_STATUS_REFRESH_ERROR, e);
|
||||
console.log(e);
|
||||
|
||||
@@ -14,7 +14,8 @@ import { clearDialogMessage, convertTimeDifferenceToDuration, displayDialogError
|
||||
import { SqlMigrationServiceDetailsDialog } from '../sqlMigrationService/sqlMigrationServiceDetailsDialog';
|
||||
import { ConfirmCutoverDialog } from '../migrationCutover/confirmCutoverDialog';
|
||||
import { MigrationCutoverDialogModel } from '../migrationCutover/migrationCutoverDialogModel';
|
||||
import { getMigrationTargetType, getMigrationMode } from '../../constants/helper';
|
||||
import { getMigrationTargetType, getMigrationMode, canRetryMigration } from '../../constants/helper';
|
||||
import { RetryMigrationDialog } from '../retryMigration/retryMigrationDialog';
|
||||
|
||||
const refreshFrequency: SupportedAutoRefreshIntervals = 180000;
|
||||
|
||||
@@ -29,9 +30,11 @@ const MenuCommands = {
|
||||
ViewService: 'sqlmigration.view.service',
|
||||
CopyMigration: 'sqlmigration.copy.migration',
|
||||
CancelMigration: 'sqlmigration.cancel.migration',
|
||||
RetryMigration: 'sqlmigration.retry.migration',
|
||||
};
|
||||
|
||||
export class MigrationStatusDialog {
|
||||
private _context: vscode.ExtensionContext;
|
||||
private _model: MigrationStatusDialogModel;
|
||||
private _dialogObject!: azdata.window.Dialog;
|
||||
private _view!: azdata.ModelView;
|
||||
@@ -45,7 +48,8 @@ export class MigrationStatusDialog {
|
||||
|
||||
private isRefreshing = false;
|
||||
|
||||
constructor(migrations: MigrationContext[], private _filter: AdsMigrationStatus) {
|
||||
constructor(context: vscode.ExtensionContext, migrations: MigrationContext[], private _filter: AdsMigrationStatus) {
|
||||
this._context = context;
|
||||
this._model = new MigrationStatusDialogModel(migrations);
|
||||
this._dialogObject = azdata.window.createModelViewDialog(loc.MIGRATION_STATUS, 'MigrationControllerDialog', 'wide');
|
||||
}
|
||||
@@ -221,7 +225,7 @@ export class MigrationStatusDialog {
|
||||
async (migrationId: string) => {
|
||||
try {
|
||||
const migration = this._model._migrations.find(migration => migration.migrationContext.id === migrationId);
|
||||
const dialog = new MigrationCutoverDialog(migration!);
|
||||
const dialog = new MigrationCutoverDialog(this._context, migration!);
|
||||
await dialog.initialize();
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
@@ -302,6 +306,25 @@ export class MigrationStatusDialog {
|
||||
console.log(e);
|
||||
}
|
||||
}));
|
||||
|
||||
this._disposables.push(vscode.commands.registerCommand(
|
||||
MenuCommands.RetryMigration,
|
||||
async (migrationId: string) => {
|
||||
try {
|
||||
clearDialogMessage(this._dialogObject);
|
||||
const migration = this._model._migrations.find(migration => migration.migrationContext.id === migrationId);
|
||||
if (canRetryMigration(migration?.migrationContext.properties.migrationStatus)) {
|
||||
let retryMigrationDialog = new RetryMigrationDialog(this._context, migration!);
|
||||
await retryMigrationDialog.openDialog();
|
||||
}
|
||||
else {
|
||||
await vscode.window.showInformationMessage(loc.MIGRATION_CANNOT_RETRY);
|
||||
}
|
||||
} catch (e) {
|
||||
displayDialogErrorMessage(this._dialogObject, loc.MIGRATION_RETRY_ERROR, e);
|
||||
console.log(e);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private async populateMigrationTable(): Promise<void> {
|
||||
@@ -366,7 +389,7 @@ export class MigrationStatusDialog {
|
||||
}).component();
|
||||
|
||||
this._disposables.push(databaseHyperLink.onDidClick(
|
||||
async (e) => await (new MigrationCutoverDialog(migration)).initialize()));
|
||||
async (e) => await (new MigrationCutoverDialog(this._context, migration)).initialize()));
|
||||
|
||||
return this._view.modelBuilder
|
||||
.flexContainer()
|
||||
@@ -416,6 +439,10 @@ export class MigrationStatusDialog {
|
||||
menuCommands.push(MenuCommands.CancelMigration);
|
||||
}
|
||||
|
||||
if (canRetryMigration(migrationStatus)) {
|
||||
menuCommands.push(MenuCommands.RetryMigration);
|
||||
}
|
||||
|
||||
return menuCommands;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 mssql from '../../../../mssql';
|
||||
import { azureResource } from 'azureResource';
|
||||
import { getLocations, getResourceGroupFromId, getBlobContainerId, getFullResourceGroupFromId, getResourceName } from '../../api/azure';
|
||||
import { MigrationMode, MigrationStateModel, NetworkContainerType, SavedInfo, Page } from '../../models/stateMachine';
|
||||
import { MigrationContext } from '../../models/migrationLocalStorage';
|
||||
import { WizardController } from '../../wizard/wizardController';
|
||||
import { getMigrationModeEnum, getMigrationTargetTypeEnum } from '../../constants/helper';
|
||||
|
||||
export class RetryMigrationDialog {
|
||||
private _context: vscode.ExtensionContext;
|
||||
private _migration: MigrationContext;
|
||||
|
||||
constructor(context: vscode.ExtensionContext, migration: MigrationContext) {
|
||||
this._context = context;
|
||||
this._migration = migration;
|
||||
}
|
||||
|
||||
private createMigrationStateModel(migration: MigrationContext, connectionId: string, serverName: string, api: mssql.IExtension, location: azureResource.AzureLocation): MigrationStateModel {
|
||||
let stateModel = new MigrationStateModel(this._context, connectionId, api.sqlMigration);
|
||||
|
||||
const sourceDatabaseName = migration.migrationContext.properties.sourceDatabaseName;
|
||||
let savedInfo: SavedInfo;
|
||||
savedInfo = {
|
||||
closedPage: Page.AzureAccount,
|
||||
|
||||
// AzureAccount
|
||||
azureAccount: migration.azureAccount,
|
||||
azureTenant: migration.azureAccount.properties.tenants[0],
|
||||
|
||||
// DatabaseSelector
|
||||
selectedDatabases: [],
|
||||
|
||||
// SKURecommendation
|
||||
databaseAssessment: [],
|
||||
databaseList: [sourceDatabaseName],
|
||||
migrationDatabases: [],
|
||||
serverAssessment: null,
|
||||
|
||||
migrationTargetType: getMigrationTargetTypeEnum(migration)!,
|
||||
subscription: migration.subscription,
|
||||
location: location,
|
||||
resourceGroup: {
|
||||
id: getFullResourceGroupFromId(migration.targetManagedInstance.id),
|
||||
name: getResourceGroupFromId(migration.targetManagedInstance.id),
|
||||
subscription: migration.subscription
|
||||
},
|
||||
targetServerInstance: migration.targetManagedInstance,
|
||||
|
||||
// MigrationMode
|
||||
migrationMode: getMigrationModeEnum(migration),
|
||||
|
||||
// DatabaseBackup
|
||||
targetSubscription: migration.subscription,
|
||||
targetDatabaseNames: [migration.migrationContext.name],
|
||||
networkContainerType: null,
|
||||
networkShare: null,
|
||||
blobs: [],
|
||||
|
||||
// Integration Runtime
|
||||
migrationServiceId: migration.migrationContext.properties.migrationService,
|
||||
};
|
||||
|
||||
const getStorageAccountResourceGroup = (storageAccountResourceId: string) => {
|
||||
return {
|
||||
id: getFullResourceGroupFromId(storageAccountResourceId!),
|
||||
name: getResourceGroupFromId(storageAccountResourceId!),
|
||||
subscription: migration.subscription
|
||||
};
|
||||
};
|
||||
const getStorageAccount = (storageAccountResourceId: string) => {
|
||||
const storageAccountName = getResourceName(storageAccountResourceId);
|
||||
return {
|
||||
type: 'microsoft.storage/storageaccounts',
|
||||
id: storageAccountResourceId!,
|
||||
tenantId: savedInfo.azureTenant?.id!,
|
||||
subscriptionId: migration.subscription.id,
|
||||
name: storageAccountName,
|
||||
location: savedInfo.location!.name,
|
||||
};
|
||||
};
|
||||
|
||||
const sourceLocation = migration.migrationContext.properties.backupConfiguration.sourceLocation;
|
||||
if (sourceLocation?.fileShare) {
|
||||
savedInfo.networkContainerType = NetworkContainerType.NETWORK_SHARE;
|
||||
const storageAccountResourceId = migration.migrationContext.properties.backupConfiguration.targetLocation?.storageAccountResourceId!;
|
||||
savedInfo.networkShare = {
|
||||
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: migration.subscription
|
||||
},
|
||||
lastBackupFile: getMigrationModeEnum(migration) === MigrationMode.OFFLINE ? migration.migrationContext.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._migration.azureAccount, this._migration.subscription);
|
||||
let location: azureResource.AzureLocation;
|
||||
locations.forEach(azureLocation => {
|
||||
if (azureLocation.name === this._migration.targetManagedInstance.location) {
|
||||
location = azureLocation;
|
||||
}
|
||||
});
|
||||
|
||||
let activeConnection = await azdata.connection.getCurrentConnection();
|
||||
let connectionId: string = '';
|
||||
let serverName: string = '';
|
||||
if (!activeConnection) {
|
||||
const connection = await azdata.connection.openConnectionDialog();
|
||||
if (connection) {
|
||||
connectionId = connection.connectionId;
|
||||
serverName = connection.options.server;
|
||||
}
|
||||
} else {
|
||||
connectionId = activeConnection.connectionId;
|
||||
serverName = activeConnection.serverName;
|
||||
}
|
||||
|
||||
const api = (await vscode.extensions.getExtension(mssql.extension.name)?.activate()) as mssql.IExtension;
|
||||
const stateModel = this.createMigrationStateModel(this._migration, connectionId, serverName, api, location!);
|
||||
|
||||
const wizardController = new WizardController(this._context, stateModel);
|
||||
await wizardController.openWizard(stateModel.sourceConnectionId);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user