mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-28 01:25:39 -05:00
Support multiple database migrations using network share (#17796)
* update database backup model to take list of network shares * remove refreshMigrationTiles after startMigration in statemachine; add null checks
This commit is contained in:
@@ -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");
|
||||
|
||||
@@ -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!;
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<void> {
|
||||
if (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.DatabaseBackup) {
|
||||
this.migrationStateModel._databaseBackup.networkContainerType = <NetworkContainerType>this.migrationStateModel.savedInfo.networkContainerType;
|
||||
this.migrationStateModel._databaseBackup.networkShare = <NetworkShare>this.migrationStateModel.savedInfo.networkShare;
|
||||
this.migrationStateModel._databaseBackup.networkShares = this.migrationStateModel.savedInfo.networkShares;
|
||||
this.migrationStateModel._databaseBackup.subscription = <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(<Blob>{});
|
||||
this.migrationStateModel._databaseBackup.networkShares.push(<NetworkShare>{});
|
||||
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<void> {
|
||||
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 ((<azdata.CategoryValue>resource).name.toLowerCase() === this.migrationStateModel.savedInfo?.networkShare?.resourceGroup?.id?.toLowerCase()) {
|
||||
if ((<azdata.CategoryValue>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<void> {
|
||||
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);
|
||||
|
||||
@@ -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<void> {
|
||||
if (this.migrationStateModel.resumeAssessment && this.migrationStateModel.savedInfo.closedPage >= Page.Summary) {
|
||||
this.migrationStateModel._databaseBackup.networkContainerType = <NetworkContainerType>this.migrationStateModel.savedInfo.networkContainerType;
|
||||
this.migrationStateModel._databaseBackup.networkShare = <NetworkShare>this.migrationStateModel.savedInfo.networkShare;
|
||||
this.migrationStateModel._databaseBackup.networkShares = this.migrationStateModel.savedInfo.networkShares;
|
||||
this.migrationStateModel._databaseBackup.subscription = <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;
|
||||
|
||||
Reference in New Issue
Block a user