diff --git a/extensions/sql-migration/src/constants/strings.ts b/extensions/sql-migration/src/constants/strings.ts index b3b6acaba1..64c2787df0 100644 --- a/extensions/sql-migration/src/constants/strings.ts +++ b/extensions/sql-migration/src/constants/strings.ts @@ -116,7 +116,7 @@ export const DATABASE_BACKUP_NETWORK_SHARE_HEADER_TEXT = localize('sql.migration export const DATABASE_BACKUP_NETWORK_SHARE_LOCATION_INFO = localize('sql.migration.network.share.location.info', "Network share path for your database backups. The migration process will automatically retrieve valid backup files from this network share."); export const DATABASE_BACKUP_NETWORK_SHARE_WINDOWS_USER_INFO = localize('sql.migration.network.share.windows.user.info', "Windows user account with read access to the network share location."); export const DATABASE_BACKUP_NC_NETWORK_SHARE_HELP_TEXT = localize('sql.migration.network.share.help.text', "Provide the network share location where the backups are stored, and the user credentials used to access the share."); -export const DATABASE_BACKUP_NETWORK_SHARE_TABLE_HELP_TEXT = localize('sql.migration.network.share.storage.table.help', "Enter target database name for the selected source databases."); +export const DATABASE_BACKUP_NETWORK_SHARE_TABLE_HELP_TEXT = localize('sql.migration.network.share.storage.table.help', "Enter target database name and network share path information for the selected source databases."); export const DATABASE_BACKUP_NETWORK_SHARE_LOCATION_LABEL = localize('sql.migration.network.share.location.label', "Network share location where the backups are stored"); export const DATABASE_SERVICE_ACCOUNT_INFO_TEXT = localize('sql.migration.service.account.info.text', "Ensure that the service account running the source SQL Server instance has read privileges on the network share."); export const DATABASE_BACKUP_NETWORK_SHARE_WINDOWS_USER_LABEL = localize('sql.migration.network.share.windows.user.label', "Windows user account with read access to the network share location"); @@ -138,7 +138,7 @@ export const DATABASE_BACKUP_MIGRATION_MODE_ONLINE_LABEL = localize('sql.migrati export const DATABASE_BACKUP_MIGRATION_MODE_ONLINE_DESCRIPTION = localize('sql.migration.database.migration.mode.online.description', "Application downtime is limited to cutover at the end of migration."); export const DATABASE_BACKUP_MIGRATION_MODE_OFFLINE_LABEL = localize('sql.migration.database.migration.mode.offline.label', "Offline migration"); export const DATABASE_BACKUP_MIGRATION_MODE_OFFLINE_DESCRIPTION = localize('sql.migration.database.migration.mode.offline.description', "Application downtime will start when the migration starts."); -export const NETWORK_SHARE_PATH = localize('sql.migration.network.share.path', "\\\\Servername.domainname.com\\Backupfolder"); +export const NETWORK_SHARE_PATH_FORMAT = localize('sql.migration.network.share.path.format', "\\\\Servername.domainname.com\\Backupfolder"); export const WINDOWS_USER_ACCOUNT = localize('sql.migration.windows.user.account', "Domain\\username"); export const NO_SUBSCRIPTIONS_FOUND = localize('sql.migration.no.subscription.found', "No subscription found."); export const NO_LOCATION_FOUND = localize('sql.migration.no.location.found', "No location found."); @@ -161,7 +161,7 @@ export function INVALID_BLOB_CONTAINER_ERROR(sourceDb: string): string { export function INVALID_BLOB_LAST_BACKUP_FILE_ERROR(sourceDb: string): string { return localize('sql.migration.invalid.blob.lastBackupFile.error', "To continue, select a valid last backup file for source database '{0}'.", sourceDb); } -export const INVALID_NETWORK_SHARE_LOCATION = localize('sql.migration.invalid.network.share.location', "Invalid network share location format. Example: {0}", NETWORK_SHARE_PATH); +export const INVALID_NETWORK_SHARE_LOCATION = localize('sql.migration.invalid.network.share.location', "Invalid network share location format. Example: {0}", NETWORK_SHARE_PATH_FORMAT); export const INVALID_USER_ACCOUNT = localize('sql.migration.invalid.user.account', "Invalid user account format. Example: {0}", WINDOWS_USER_ACCOUNT); export const INVALID_TARGET_NAME_ERROR = localize('sql.migration.invalid.target.name.error', "Enter a valid name for the target database."); export const PROVIDE_UNIQUE_CONTAINERS = localize('sql.migration.provide.unique.containers', "Provide a unique container for each target database. Databases affected: "); @@ -282,6 +282,7 @@ export const SUMMARY_DATABASE_COUNT_LABEL = localize('sql.migration.summary.data export const SUMMARY_AZURE_STORAGE_SUBSCRIPTION = localize('sql.migration.summary.azure.storage.subscription', "Azure storage subscription"); export const SUMMARY_AZURE_STORAGE = localize('sql.migration.summary.azure.storage', "Azure storage"); export const NETWORK_SHARE = localize('sql.migration.network.share', "Network share"); +export const NETWORK_SHARE_PATH = localize('sql.migration.network.share.path', "Network share path"); export const BLOB_CONTAINER = localize('sql.migration.blob.container.title', "Blob container"); export const BLOB_CONTAINER_LAST_BACKUP_FILE = localize('sql.migration.blob.container.last.backup.file.label', "Last backup file"); export const BLOB_CONTAINER_RESOURCE_GROUP = localize('sql.migration.blob.container.label', "Blob container resource group"); diff --git a/extensions/sql-migration/src/dialog/retryMigration/retryMigrationDialog.ts b/extensions/sql-migration/src/dialog/retryMigration/retryMigrationDialog.ts index d3e0c05727..a320973b25 100644 --- a/extensions/sql-migration/src/dialog/retryMigration/retryMigrationDialog.ts +++ b/extensions/sql-migration/src/dialog/retryMigration/retryMigrationDialog.ts @@ -60,7 +60,7 @@ export class RetryMigrationDialog { targetSubscription: migration.subscription, targetDatabaseNames: [migration.migrationContext.name], networkContainerType: null, - networkShare: null, + networkShares: [], blobs: [], // Integration Runtime @@ -90,14 +90,16 @@ export class RetryMigrationDialog { 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: '' - }; + 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!; diff --git a/extensions/sql-migration/src/dialog/targetDatabaseSummary/targetDatabaseSummaryDialog.ts b/extensions/sql-migration/src/dialog/targetDatabaseSummary/targetDatabaseSummaryDialog.ts index 0c6df16ada..ea0f387187 100644 --- a/extensions/sql-migration/src/dialog/targetDatabaseSummary/targetDatabaseSummaryDialog.ts +++ b/extensions/sql-migration/src/dialog/targetDatabaseSummary/targetDatabaseSummaryDialog.ts @@ -19,8 +19,8 @@ export class TargetDatabaseSummaryDialog { this._tableLength = 800; dialogWidth = 900; } else { - this._tableLength = 200; - dialogWidth = 'narrow'; + this._tableLength = 700; + dialogWidth = 'medium'; } this._dialogObject = azdata.window.createModelViewDialog( constants.DATABASE_TO_BE_MIGRATED, @@ -119,6 +119,15 @@ export class TargetDatabaseSummaryDialog { headerCssStyles: headerCssStyle, hidden: this._model._databaseBackup.migrationMode === MigrationMode.ONLINE }); + } else { + columns.push({ + valueType: azdata.DeclarativeDataType.string, + displayName: constants.NETWORK_SHARE_PATH, + isReadOnly: true, + width: columnWidth, + rowCssStyles: rowCssStyle, + headerCssStyles: headerCssStyle + }); } const tableRows: azdata.DeclarativeTableCellValue[][] = []; @@ -146,6 +155,10 @@ export class TargetDatabaseSummaryDialog { value: this._model._databaseBackup.blobs[index].lastBackupFile! }); } + } else { + tableRow.push({ + value: this._model._databaseBackup.networkShares[index].networkShareLocation + }); } tableRows.push(tableRow); }); diff --git a/extensions/sql-migration/src/models/stateMachine.ts b/extensions/sql-migration/src/models/stateMachine.ts index ec56c9a81f..dbca63c6b9 100644 --- a/extensions/sql-migration/src/models/stateMachine.ts +++ b/extensions/sql-migration/src/models/stateMachine.ts @@ -77,7 +77,7 @@ export enum WizardEntryPoint { export interface DatabaseBackupModel { migrationMode: MigrationMode; networkContainerType: NetworkContainerType; - networkShare: NetworkShare; + networkShares: NetworkShare[]; subscription: azureResource.AzureResourceSubscription; blobs: Blob[]; } @@ -129,7 +129,7 @@ export interface SavedInfo { migrationMode: MigrationMode | null; databaseAssessment: string[] | null; networkContainerType: NetworkContainerType | null; - networkShare: NetworkShare | null; + networkShares: NetworkShare[]; targetSubscription: azureResource.AzureResourceSubscription | null; blobs: Blob[]; targetDatabaseNames: string[]; @@ -165,7 +165,6 @@ export class MigrationStateModel implements Model, vscode.Disposable { public _fileShares!: azureResource.FileShare[]; public _blobContainers!: azureResource.BlobContainer[]; public _lastFileNames!: azureResource.Blob[]; - public _refreshNetworkShareLocation!: azureResource.BlobContainer[]; public _targetDatabaseNames!: string[]; public _sqlMigrationServiceResourceGroup!: string; @@ -211,7 +210,7 @@ export class MigrationStateModel implements Model, vscode.Disposable { ) { this._currentState = State.INIT; this._databaseBackup = {} as DatabaseBackupModel; - this._databaseBackup.networkShare = {} as NetworkShare; + this._databaseBackup.networkShares = []; this._databaseBackup.blobs = []; this.mementoString = 'sqlMigration.assessmentResults'; } @@ -968,14 +967,14 @@ export class MigrationStateModel implements Model, vscode.Disposable { case NetworkContainerType.NETWORK_SHARE: requestBody.properties.backupConfiguration = { targetLocation: { - storageAccountResourceId: this._databaseBackup.networkShare.storageAccount.id, - accountKey: this._databaseBackup.networkShare.storageKey, + storageAccountResourceId: this._databaseBackup.networkShares[i].storageAccount.id, + accountKey: this._databaseBackup.networkShares[i].storageKey, }, sourceLocation: { fileShare: { - path: this._databaseBackup.networkShare.networkShareLocation, - username: this._databaseBackup.networkShare.windowsUser, - password: this._databaseBackup.networkShare.password, + path: this._databaseBackup.networkShares[i].networkShareLocation, + username: this._databaseBackup.networkShares[i].windowsUser, + password: this._databaseBackup.networkShares[i].password, } } }; @@ -1043,8 +1042,6 @@ export class MigrationStateModel implements Model, vscode.Disposable { localize('sql.migration.starting.migration.error', "An error occurred while starting the migration: '{0}'", e.message)); console.log(e); } - - await vscode.commands.executeCommand('sqlmigration.refreshMigrationTiles'); } } @@ -1066,7 +1063,7 @@ export class MigrationStateModel implements Model, vscode.Disposable { migrationMode: null, databaseAssessment: null, networkContainerType: null, - networkShare: null, + networkShares: [], targetSubscription: null, blobs: [], targetDatabaseNames: [], @@ -1080,7 +1077,7 @@ export class MigrationStateModel implements Model, vscode.Disposable { case Page.DatabaseBackup: saveInfo.networkContainerType = this._databaseBackup.networkContainerType; - saveInfo.networkShare = this._databaseBackup.networkShare; + saveInfo.networkShares = this._databaseBackup.networkShares; saveInfo.targetSubscription = this._databaseBackup.subscription; saveInfo.blobs = this._databaseBackup.blobs; saveInfo.targetDatabaseNames = this._targetDatabaseNames; diff --git a/extensions/sql-migration/src/wizard/databaseBackupPage.ts b/extensions/sql-migration/src/wizard/databaseBackupPage.ts index aca9cb738e..1d43be1209 100644 --- a/extensions/sql-migration/src/wizard/databaseBackupPage.ts +++ b/extensions/sql-migration/src/wizard/databaseBackupPage.ts @@ -33,7 +33,6 @@ export class DatabaseBackupPage extends MigrationWizardPage { private _networkShareContainer!: azdata.FlexContainer; private _windowsUserAccountText!: azdata.InputBoxComponent; private _passwordText!: azdata.InputBoxComponent; - private _networkSharePath!: azdata.InputBoxComponent; private _sourceHelpText!: azdata.TextComponent; private _sqlSourceUsernameInput!: azdata.InputBoxComponent; private _sqlSourcePassword!: azdata.InputBoxComponent; @@ -60,6 +59,7 @@ export class DatabaseBackupPage extends MigrationWizardPage { private _blobTableContainer!: azdata.FlexContainer; private _networkShareTargetDatabaseNames: azdata.InputBoxComponent[] = []; private _blobContainerTargetDatabaseNames: azdata.InputBoxComponent[] = []; + private _networkShareLocations: azdata.InputBoxComponent[] = []; private _existingDatabases: string[] = []; private _disposables: vscode.Disposable[] = []; @@ -257,40 +257,6 @@ export class DatabaseBackupPage extends MigrationWizardPage { } }).component(); - const networkLocationInputBoxLabel = this._view.modelBuilder.text().withProps({ - value: constants.DATABASE_BACKUP_NETWORK_SHARE_LOCATION_LABEL, - description: constants.DATABASE_BACKUP_NETWORK_SHARE_LOCATION_INFO, - width: WIZARD_INPUT_COMPONENT_WIDTH, - requiredIndicator: true, - CSSStyles: { - ...styles.LABEL_CSS - } - }).component(); - this._networkSharePath = this._view.modelBuilder.inputBox().withProps({ - placeHolder: constants.NETWORK_SHARE_PATH, - validationErrorMessage: constants.INVALID_NETWORK_SHARE_LOCATION, - width: WIZARD_INPUT_COMPONENT_WIDTH, - CSSStyles: { - 'margin-top': '-1em' - } - }).withValidation((component) => { - if (this.migrationStateModel._databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE) { - if (component.value) { - if (!/^[\\\/]{2,}[^\\\/]+[\\\/]+[^\\\/]+/.test(component.value)) { - return false; - } - } - } - return true; - }).component(); - if (this.migrationStateModel.retryMigration || (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.DatabaseBackup)) { - this._networkSharePath.value = this.migrationStateModel.savedInfo.networkShare?.networkShareLocation; - } - this._disposables.push(this._networkSharePath.onTextChanged(async (value) => { - await this.validateFields(); - this.migrationStateModel._databaseBackup.networkShare.networkShareLocation = value; - })); - const networkShareInfoBox = this._view.modelBuilder.infoBox().withProps({ text: constants.DATABASE_SERVICE_ACCOUNT_INFO_TEXT, style: 'information', @@ -332,10 +298,12 @@ export class DatabaseBackupPage extends MigrationWizardPage { return true; }).component(); if (this.migrationStateModel.retryMigration || (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.DatabaseBackup)) { - this._windowsUserAccountText.value = this.migrationStateModel.savedInfo.networkShare?.windowsUser; + this._windowsUserAccountText.value = this.migrationStateModel.savedInfo.networkShares[0].windowsUser; } this._disposables.push(this._windowsUserAccountText.onTextChanged((value) => { - this.migrationStateModel._databaseBackup.networkShare.windowsUser = value; + for (let i = 0; i < this.migrationStateModel._databaseBackup.networkShares.length; i++) { + this.migrationStateModel._databaseBackup.networkShares[i].windowsUser = value; + } })); const passwordLabel = this._view.modelBuilder.text() @@ -359,7 +327,9 @@ export class DatabaseBackupPage extends MigrationWizardPage { } }).component(); this._disposables.push(this._passwordText.onTextChanged((value) => { - this.migrationStateModel._databaseBackup.networkShare.password = value; + for (let i = 0; i < this.migrationStateModel._databaseBackup.networkShares.length; i++) { + this.migrationStateModel._databaseBackup.networkShares[i].password = value; + } })); const flexContainer = this._view.modelBuilder.flexContainer().withItems( @@ -372,8 +342,6 @@ export class DatabaseBackupPage extends MigrationWizardPage { this._sqlSourcePassword, networkShareHeading, networkShareHelpText, - networkLocationInputBoxLabel, - this._networkSharePath, networkShareInfoBox, windowsUserAccountLabel, this._windowsUserAccountText, @@ -506,6 +474,14 @@ export class DatabaseBackupPage extends MigrationWizardPage { rowCssStyles: rowCssStyle, headerCssStyles: headerCssStyles, isReadOnly: true, + width: WIZARD_TABLE_COLUMN_WIDTH + }, + { + displayName: constants.NETWORK_SHARE_PATH, + valueType: azdata.DeclarativeDataType.component, + rowCssStyles: rowCssStyle, + headerCssStyles: headerCssStyles, + isReadOnly: true, width: '300px' } ] @@ -675,7 +651,9 @@ export class DatabaseBackupPage extends MigrationWizardPage { this._disposables.push(this._networkShareStorageAccountResourceGroupDropdown.onValueChanged(async (value) => { const selectedIndex = findDropDownItemIndex(this._networkShareStorageAccountResourceGroupDropdown, value); if (selectedIndex > -1) { - this.migrationStateModel._databaseBackup.networkShare.resourceGroup = this.migrationStateModel.getAzureResourceGroup(selectedIndex); + for (let i = 0; i < this.migrationStateModel._databaseBackup.networkShares.length; i++) { + this.migrationStateModel._databaseBackup.networkShares[i].resourceGroup = this.migrationStateModel.getAzureResourceGroup(selectedIndex); + } await this.loadNetworkShareStorageDropdown(); } })); @@ -700,7 +678,9 @@ export class DatabaseBackupPage extends MigrationWizardPage { this._disposables.push(this._networkShareContainerStorageAccountDropdown.onValueChanged((value) => { const selectedIndex = findDropDownItemIndex(this._networkShareContainerStorageAccountDropdown, value); if (selectedIndex > -1) { - this.migrationStateModel._databaseBackup.networkShare.storageAccount = this.migrationStateModel.getStorageAccount(selectedIndex); + for (let i = 0; i < this.migrationStateModel._databaseBackup.networkShares.length; i++) { + this.migrationStateModel._databaseBackup.networkShares[i].storageAccount = this.migrationStateModel.getStorageAccount(selectedIndex); + } } })); @@ -757,7 +737,7 @@ export class DatabaseBackupPage extends MigrationWizardPage { public async onPageEnter(pageChangeInfo: azdata.window.WizardPageChangeInfo): Promise { if (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.DatabaseBackup) { this.migrationStateModel._databaseBackup.networkContainerType = this.migrationStateModel.savedInfo.networkContainerType; - this.migrationStateModel._databaseBackup.networkShare = this.migrationStateModel.savedInfo.networkShare; + this.migrationStateModel._databaseBackup.networkShares = this.migrationStateModel.savedInfo.networkShares; this.migrationStateModel._databaseBackup.subscription = this.migrationStateModel.savedInfo.targetSubscription; this.migrationStateModel._databaseBackup.blobs = this.migrationStateModel.savedInfo.blobs; this.migrationStateModel._targetDatabaseNames = this.migrationStateModel.savedInfo.targetDatabaseNames; @@ -809,6 +789,7 @@ export class DatabaseBackupPage extends MigrationWizardPage { this._sqlSourcePassword.value = (await azdata.connection.getCredentials(this.migrationStateModel.sourceConnectionId)).password; this._networkShareTargetDatabaseNames = []; + this._networkShareLocations = []; this._blobContainerTargetDatabaseNames = []; this._blobContainerResourceGroupDropdowns = []; this._blobContainerStorageAccountDropdowns = []; @@ -820,9 +801,11 @@ export class DatabaseBackupPage extends MigrationWizardPage { } this.migrationStateModel._targetDatabaseNames = []; this.migrationStateModel._databaseBackup.blobs = []; + this.migrationStateModel._databaseBackup.networkShares = []; this.migrationStateModel._migrationDbs.forEach((db, index) => { this.migrationStateModel._targetDatabaseNames.push(db); this.migrationStateModel._databaseBackup.blobs.push({}); + this.migrationStateModel._databaseBackup.networkShares.push({}); const targetDatabaseInput = this._view.modelBuilder.inputBox().withProps({ required: true, value: db, @@ -853,6 +836,32 @@ export class DatabaseBackupPage extends MigrationWizardPage { } this._networkShareTargetDatabaseNames.push(targetDatabaseInput); + const networkShareLocationInput = this._view.modelBuilder.inputBox().withProps({ + required: true, + placeHolder: constants.NETWORK_SHARE_PATH_FORMAT, + validationErrorMessage: constants.INVALID_NETWORK_SHARE_LOCATION, + width: '300px' + }).withValidation(c => { + if (this.migrationStateModel._databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE) { + if (c.value) { + if (!/^[\\\/]{2,}[^\\\/]+[\\\/]+[^\\\/]+/.test(c.value)) { + return false; + } + } + } + return true; + }).component(); + this._disposables.push(networkShareLocationInput.onTextChanged(async (value) => { + this.migrationStateModel._databaseBackup.networkShares[index].networkShareLocation = value.trim(); + await this.validateFields(); + })); + if (this.migrationStateModel.retryMigration || (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.DatabaseBackup)) { + networkShareLocationInput.value = this.migrationStateModel.savedInfo.networkShares[index].networkShareLocation; + } else { + networkShareLocationInput.value = this.migrationStateModel._databaseBackup.networkShares[index]?.networkShareLocation; + } + this._networkShareLocations.push(networkShareLocationInput); + const blobTargetDatabaseInput = this._view.modelBuilder.inputBox().withProps({ required: true, value: db, @@ -971,6 +980,9 @@ export class DatabaseBackupPage extends MigrationWizardPage { targetRow.push({ value: this._networkShareTargetDatabaseNames[index] }); + targetRow.push({ + value: this._networkShareLocations[index] + }); data.push(targetRow); }); await this._networkShareTargetDatabaseNamesTable.setDataValues(data); @@ -1109,11 +1121,15 @@ export class DatabaseBackupPage extends MigrationWizardPage { } break; case NetworkContainerType.NETWORK_SHARE: - const storageAccount = this.migrationStateModel._databaseBackup.networkShare.storageAccount; - this.migrationStateModel._databaseBackup.networkShare.storageKey = (await getStorageAccountAccessKeys( + // All network share migrations use the same storage account + const storageAccount = this.migrationStateModel._databaseBackup.networkShares[0].storageAccount; + const storageKey = (await getStorageAccountAccessKeys( this.migrationStateModel._azureAccount, this.migrationStateModel._databaseBackup.subscription, storageAccount)).keyName1; + for (let i = 0; i < this.migrationStateModel._databaseBackup.networkShares.length; i++) { + this.migrationStateModel._databaseBackup.networkShares[i].storageKey = storageKey; + } break; } } @@ -1165,7 +1181,6 @@ export class DatabaseBackupPage extends MigrationWizardPage { private async validateFields(): Promise { await this._sqlSourceUsernameInput.validate(); await this._sqlSourcePassword.validate(); - await this._networkSharePath.validate(); await this._windowsUserAccountText.validate(); await this._passwordText.validate(); await this._networkShareContainerSubscription.validate(); @@ -1174,6 +1189,7 @@ export class DatabaseBackupPage extends MigrationWizardPage { await this._blobContainerSubscription.validate(); for (let i = 0; i < this._networkShareTargetDatabaseNames.length; i++) { await this._networkShareTargetDatabaseNames[i].validate(); + await this._networkShareLocations[i].validate(); await this._blobContainerTargetDatabaseNames[i].validate(); await this._blobContainerResourceGroupDropdowns[i].validate(); await this._blobContainerStorageAccountDropdowns[i].validate(); @@ -1209,7 +1225,7 @@ export class DatabaseBackupPage extends MigrationWizardPage { this._networkShareStorageAccountResourceGroupDropdown.values = await this.migrationStateModel.getAzureResourceGroupDropdownValues(this.migrationStateModel._databaseBackup.subscription); if (this.hasSavedInfo(NetworkContainerType.NETWORK_SHARE, this._networkShareStorageAccountResourceGroupDropdown.values)) { this._networkShareStorageAccountResourceGroupDropdown.values.forEach((resource, index) => { - if ((resource).name.toLowerCase() === this.migrationStateModel.savedInfo?.networkShare?.resourceGroup?.id?.toLowerCase()) { + if ((resource).name.toLowerCase() === this.migrationStateModel.savedInfo?.networkShares[0].resourceGroup?.id?.toLowerCase()) { selectDropDownIndex(this._networkShareStorageAccountResourceGroupDropdown, index); } }); @@ -1227,7 +1243,7 @@ export class DatabaseBackupPage extends MigrationWizardPage { private async loadNetworkShareStorageDropdown(): Promise { this._networkShareContainerStorageAccountDropdown.loading = true; try { - this._networkShareContainerStorageAccountDropdown.values = await this.migrationStateModel.getStorageAccountValues(this.migrationStateModel._databaseBackup.subscription, this.migrationStateModel._databaseBackup.networkShare.resourceGroup); + this._networkShareContainerStorageAccountDropdown.values = await this.migrationStateModel.getStorageAccountValues(this.migrationStateModel._databaseBackup.subscription, this.migrationStateModel._databaseBackup.networkShares[0].resourceGroup); selectDropDownIndex(this._networkShareContainerStorageAccountDropdown, 0); } catch (error) { console.log(error); diff --git a/extensions/sql-migration/src/wizard/summaryPage.ts b/extensions/sql-migration/src/wizard/summaryPage.ts index 8bade3632c..8e9955e7fd 100644 --- a/extensions/sql-migration/src/wizard/summaryPage.ts +++ b/extensions/sql-migration/src/wizard/summaryPage.ts @@ -6,7 +6,7 @@ import * as azdata from 'azdata'; import * as vscode from 'vscode'; import { MigrationWizardPage } from '../models/migrationWizardPage'; -import { MigrationMode, MigrationStateModel, MigrationTargetType, NetworkContainerType, NetworkShare, Page, StateChangeEvent } from '../models/stateMachine'; +import { MigrationMode, MigrationStateModel, MigrationTargetType, NetworkContainerType, Page, StateChangeEvent } from '../models/stateMachine'; import * as constants from '../constants/strings'; import { createHeadingTextComponent, createInformationRow, createLabelTextComponent } from './wizardController'; import { getResourceGroupFromId, Subscription } from '../api/azure'; @@ -49,7 +49,7 @@ export class SummaryPage extends MigrationWizardPage { public async onPageEnter(pageChangeInfo: azdata.window.WizardPageChangeInfo): Promise { if (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.Summary) { this.migrationStateModel._databaseBackup.networkContainerType = this.migrationStateModel.savedInfo.networkContainerType; - this.migrationStateModel._databaseBackup.networkShare = this.migrationStateModel.savedInfo.networkShare; + this.migrationStateModel._databaseBackup.networkShares = this.migrationStateModel.savedInfo.networkShares; this.migrationStateModel._databaseBackup.subscription = this.migrationStateModel.savedInfo.targetSubscription; this.migrationStateModel._databaseBackup.blobs = this.migrationStateModel.savedInfo.blobs; this.migrationStateModel._targetDatabaseNames = this.migrationStateModel.savedInfo.targetDatabaseNames; @@ -158,13 +158,12 @@ export class SummaryPage extends MigrationWizardPage { flexContainer.addItems( [ createInformationRow(this._view, constants.BACKUP_LOCATION, constants.NETWORK_SHARE), - createInformationRow(this._view, constants.NETWORK_SHARE, this.migrationStateModel._databaseBackup.networkShare.networkShareLocation), - createInformationRow(this._view, constants.USER_ACCOUNT, this.migrationStateModel._databaseBackup.networkShare.windowsUser), + createInformationRow(this._view, constants.USER_ACCOUNT, this.migrationStateModel._databaseBackup.networkShares[0].windowsUser), await createHeadingTextComponent(this._view, constants.AZURE_STORAGE_ACCOUNT_TO_UPLOAD_BACKUPS), createInformationRow(this._view, constants.SUBSCRIPTION, this.migrationStateModel._databaseBackup.subscription.name), - createInformationRow(this._view, constants.LOCATION, this.migrationStateModel._databaseBackup.networkShare.storageAccount.location), - createInformationRow(this._view, constants.RESOURCE_GROUP, this.migrationStateModel._databaseBackup.networkShare.storageAccount.resourceGroup!), - createInformationRow(this._view, constants.STORAGE_ACCOUNT, this.migrationStateModel._databaseBackup.networkShare.storageAccount.name!), + createInformationRow(this._view, constants.LOCATION, this.migrationStateModel._databaseBackup.networkShares[0].storageAccount?.location), + createInformationRow(this._view, constants.RESOURCE_GROUP, this.migrationStateModel._databaseBackup.networkShares[0].storageAccount?.resourceGroup!), + createInformationRow(this._view, constants.STORAGE_ACCOUNT, this.migrationStateModel._databaseBackup.networkShares[0].storageAccount?.name!), ] ); break;