mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-25 09:35:37 -05:00
Improvements in blob storage support for SQL Migration. (#15693)
* changing the cutover icon on migration cutover page. * Fixing monitoring table and pending log backups * converting file upload times in utc to local time zones * adding autorefresh to dashboard, migration status and cutover dialogs. * Supporting blob container e2e * vbump extension * Fixing some PR comments * Fixed broken blob container dropdown onChange event * Localizing display string in refresh dialog Fixing some localized strings * Fixing var declaration * making a class readonly for 250px width * removing refresh interval dialog and replacing it with hardcoded values. * Fixing summary page IR information. * surfacing test connection error * Clearing intervals on view closed to remove auto refresh.
This commit is contained in:
@@ -684,6 +684,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
}).component();
|
||||
targetDatabaseInput.onTextChanged((value) => {
|
||||
this.migrationStateModel._targetDatabaseNames[index] = value.trim();
|
||||
this.validateFields();
|
||||
});
|
||||
this._networkShareTargetDatabaseNames.push(targetDatabaseInput);
|
||||
|
||||
@@ -749,7 +750,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
fireOnTextChange: true,
|
||||
}).component();
|
||||
blobContainerDropdown.onValueChanged(value => {
|
||||
const selectedIndex = findDropDownItemIndex(blobContainerStorageAccountDropdown, value);
|
||||
const selectedIndex = findDropDownItemIndex(blobContainerDropdown, value);
|
||||
if (selectedIndex > -1 && value !== constants.NO_BLOBCONTAINERS_FOUND) {
|
||||
this.migrationStateModel._databaseBackup.blobs[index].blobContainer = this.migrationStateModel.getBlobContainer(selectedIndex);
|
||||
}
|
||||
@@ -830,23 +831,24 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
}
|
||||
});
|
||||
|
||||
const duplicates: Map<string, number[]> = new Map();
|
||||
for (let i = 0; i < this.migrationStateModel._targetDatabaseNames.length; i++) {
|
||||
const blobContainerId = this.migrationStateModel._databaseBackup.blobs[i].blobContainer.id;
|
||||
if (duplicates.has(blobContainerId)) {
|
||||
duplicates.get(blobContainerId)?.push(i);
|
||||
} else {
|
||||
duplicates.set(blobContainerId, [i]);
|
||||
if (errors.length > 0) {
|
||||
const duplicates: Map<string, number[]> = new Map();
|
||||
for (let i = 0; i < this.migrationStateModel._targetDatabaseNames.length; i++) {
|
||||
const blobContainerId = this.migrationStateModel._databaseBackup.blobs[i].blobContainer?.id;
|
||||
if (duplicates.has(blobContainerId)) {
|
||||
duplicates.get(blobContainerId)?.push(i);
|
||||
} else {
|
||||
duplicates.set(blobContainerId, [i]);
|
||||
}
|
||||
}
|
||||
duplicates.forEach((d) => {
|
||||
if (d.length > 1) {
|
||||
const dupString = `${d.map(index => this.migrationStateModel._migrationDbs[index]).join(', ')}`;
|
||||
errors.push(constants.PROVIDE_UNIQUE_CONTAINERS + dupString);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
duplicates.forEach((d) => {
|
||||
if (d.length > 1) {
|
||||
const dupString = `${d.map(index => this.migrationStateModel._migrationDbs[index]).join(', ')}`;
|
||||
errors.push(constants.PROVIDE_UNIQUE_CONTAINERS + dupString);
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import { MigrationWizardPage } from '../models/migrationWizardPage';
|
||||
import { MigrationStateModel, StateChangeEvent } from '../models/stateMachine';
|
||||
import { MigrationStateModel, NetworkContainerType, StateChangeEvent } from '../models/stateMachine';
|
||||
import { CreateSqlMigrationServiceDialog } from '../dialog/createSqlMigrationService/createSqlMigrationServiceDialog';
|
||||
import * as constants from '../constants/strings';
|
||||
import { WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController';
|
||||
import { getLocationDisplayName, getSqlMigrationService, getSqlMigrationServiceAuthKeys, getSqlMigrationServiceMonitoringData, SqlManagedInstance, SqlMigrationService } from '../api/azure';
|
||||
import { getLocationDisplayName, getSqlMigrationService, getSqlMigrationServiceAuthKeys, getSqlMigrationServiceMonitoringData, SqlManagedInstance } from '../api/azure';
|
||||
import { IconPathHelper } from '../constants/iconPathHelper';
|
||||
import { findDropDownItemIndex } from '../api/utils';
|
||||
|
||||
@@ -24,6 +24,7 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
private _resourceGroupDropdown!: azdata.DropDownComponent;
|
||||
private _dmsDropdown!: azdata.DropDownComponent;
|
||||
|
||||
private _dmsInfoContainer!: azdata.FlexContainer;
|
||||
private _dmsStatusInfoBox!: azdata.InfoBoxComponent;
|
||||
private _authKeyTable!: azdata.DeclarativeTableComponent;
|
||||
private _refreshButton!: azdata.ButtonComponent;
|
||||
@@ -34,8 +35,6 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
private _refresh1!: azdata.ButtonComponent;
|
||||
private _refresh2!: azdata.ButtonComponent;
|
||||
|
||||
private _firstEnter: boolean = true;
|
||||
|
||||
constructor(wizard: azdata.window.Wizard, migrationStateModel: MigrationStateModel) {
|
||||
super(wizard, azdata.window.createWizardPage(constants.IR_PAGE_TITLE), migrationStateModel);
|
||||
}
|
||||
@@ -51,13 +50,20 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
}
|
||||
}).component();
|
||||
|
||||
createNewMigrationService.onDidClick((e) => {
|
||||
const dialog = new CreateSqlMigrationServiceDialog(this.migrationStateModel, this);
|
||||
dialog.initialize();
|
||||
createNewMigrationService.onDidClick(async (e) => {
|
||||
const dialog = new CreateSqlMigrationServiceDialog();
|
||||
const createdDmsResult = await dialog.createNewDms(this.migrationStateModel, (<azdata.CategoryValue>this._resourceGroupDropdown.value).displayName);
|
||||
this.migrationStateModel._sqlMigrationServiceResourceGroup = createdDmsResult.resourceGroup;
|
||||
this.migrationStateModel._sqlMigrationService = createdDmsResult.service;
|
||||
await this.loadResourceGroupDropdown();
|
||||
await this.populateDms(createdDmsResult.resourceGroup);
|
||||
});
|
||||
|
||||
this._statusLoadingComponent = view.modelBuilder.loadingComponent().withItem(this.createDMSDetailsContainer()).component();
|
||||
|
||||
this._dmsInfoContainer = this._view.modelBuilder.flexContainer().withItems([
|
||||
this._statusLoadingComponent
|
||||
]).component();
|
||||
const dmsPortalInfo = this._view.modelBuilder.infoBox().withProps({
|
||||
text: constants.DMS_PORTAL_INFO,
|
||||
style: 'information',
|
||||
@@ -80,7 +86,7 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
component: dmsPortalInfo
|
||||
},
|
||||
{
|
||||
component: this._statusLoadingComponent
|
||||
component: this._dmsInfoContainer
|
||||
}
|
||||
|
||||
]
|
||||
@@ -89,10 +95,11 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
}
|
||||
|
||||
public async onPageEnter(): Promise<void> {
|
||||
if (this._firstEnter) {
|
||||
this.populateMigrationService();
|
||||
this._firstEnter = false;
|
||||
}
|
||||
|
||||
this._subscription.value = this.migrationStateModel._targetSubscription.name;
|
||||
this._location.value = await getLocationDisplayName(this.migrationStateModel._targetServerInstance.location);
|
||||
this.loadResourceGroupDropdown();
|
||||
this._dmsInfoContainer.display = (this.migrationStateModel._databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE) ? 'inline' : 'none';
|
||||
this.wizard.registerNavigationValidator((pageChangeInfo) => {
|
||||
if (pageChangeInfo.newPage < pageChangeInfo.lastPage) {
|
||||
this.wizard.message = {
|
||||
@@ -108,7 +115,7 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
};
|
||||
return false;
|
||||
}
|
||||
if (state !== 'Online') {
|
||||
if (this.migrationStateModel._databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE && state !== 'Online') {
|
||||
this.wizard.message = {
|
||||
level: azdata.window.MessageLevel.Error,
|
||||
text: constants.SERVICE_OFFLINE_ERROR
|
||||
@@ -202,6 +209,9 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
|
||||
this._dmsDropdown.onValueChanged(async (value) => {
|
||||
if (value && value !== constants.SQL_MIGRATION_SERVICE_NOT_FOUND_ERROR) {
|
||||
if (this.migrationStateModel._databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE) {
|
||||
this._dmsInfoContainer.display = 'inline';
|
||||
}
|
||||
this.wizard.message = {
|
||||
text: ''
|
||||
};
|
||||
@@ -210,6 +220,8 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
this.migrationStateModel._sqlMigrationService = this.migrationStateModel.getMigrationService(selectedIndex);
|
||||
await this.loadMigrationServiceStatus();
|
||||
}
|
||||
} else {
|
||||
this._dmsInfoContainer.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
@@ -254,8 +266,11 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
|
||||
this._refreshButton.onDidClick(async (e) => {
|
||||
this._connectionStatusLoader.loading = true;
|
||||
await this.loadStatus();
|
||||
this._connectionStatusLoader.loading = false;
|
||||
try {
|
||||
await this.loadStatus();
|
||||
} finally {
|
||||
this._connectionStatusLoader.loading = false;
|
||||
}
|
||||
});
|
||||
|
||||
const connectionLabelContainer = this._view.modelBuilder.flexContainer().withProps({
|
||||
@@ -387,53 +402,24 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
return container;
|
||||
}
|
||||
|
||||
public async populateMigrationService(sqlMigrationService?: SqlMigrationService, serviceNodes?: string[], resourceGroupName?: string): Promise<void> {
|
||||
|
||||
public async loadResourceGroupDropdown(): Promise<void> {
|
||||
this._resourceGroupDropdown.loading = true;
|
||||
this._dmsDropdown.loading = true;
|
||||
if (sqlMigrationService && serviceNodes) {
|
||||
this.migrationStateModel._sqlMigrationService = sqlMigrationService;
|
||||
this.migrationStateModel._nodeNames = serviceNodes;
|
||||
}
|
||||
try {
|
||||
this._subscription.value = this.migrationStateModel._targetSubscription.name;
|
||||
this._location.value = await getLocationDisplayName(this.migrationStateModel._targetServerInstance.location);
|
||||
this._resourceGroupDropdown.values = await this.migrationStateModel.getAzureResourceGroupDropdownValues(this.migrationStateModel._targetSubscription);
|
||||
|
||||
let index = 0;
|
||||
if (resourceGroupName) {
|
||||
index = findDropDownItemIndex(this._resourceGroupDropdown, resourceGroupName);
|
||||
}
|
||||
|
||||
if ((<azdata.CategoryValue>this._resourceGroupDropdown.value)?.displayName.toLowerCase() === (<azdata.CategoryValue>this._resourceGroupDropdown.values[index])?.displayName.toLowerCase()) {
|
||||
await this.populateDms((<azdata.CategoryValue>this._resourceGroupDropdown.value)?.displayName);
|
||||
} else {
|
||||
this._resourceGroupDropdown.value = this._resourceGroupDropdown.values[index];
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
const resourceGroupDropdownValue = this._resourceGroupDropdown.values.find(v => v.displayName === this.migrationStateModel._sqlMigrationServiceResourceGroup);
|
||||
this._resourceGroupDropdown.value = (resourceGroupDropdownValue) ? resourceGroupDropdownValue : this._resourceGroupDropdown.values[0];
|
||||
} finally {
|
||||
this._resourceGroupDropdown.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
public async populateDms(resourceGroupName: string): Promise<void> {
|
||||
if (!resourceGroupName) {
|
||||
return;
|
||||
}
|
||||
this._dmsDropdown.loading = true;
|
||||
try {
|
||||
this._dmsDropdown.values = await this.migrationStateModel.getSqlMigrationServiceValues(this.migrationStateModel._targetSubscription, <SqlManagedInstance>this.migrationStateModel._targetServerInstance, resourceGroupName);
|
||||
let index = -1;
|
||||
if (this.migrationStateModel._sqlMigrationService) {
|
||||
index = findDropDownItemIndex(this._dmsDropdown, this.migrationStateModel._sqlMigrationService.name);
|
||||
}
|
||||
if (index > -1) {
|
||||
this._dmsDropdown.value = this._dmsDropdown.values[index];
|
||||
} else {
|
||||
this._dmsDropdown.value = this._dmsDropdown.values[0];
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
const selectedSqlMigrationService = this._dmsDropdown.values.find(v => v.displayName.toLowerCase() === this.migrationStateModel._sqlMigrationService?.name.toLowerCase());
|
||||
this._dmsDropdown.value = (selectedSqlMigrationService) ? selectedSqlMigrationService : this._dmsDropdown.values[0];
|
||||
} finally {
|
||||
this._dmsDropdown.loading = false;
|
||||
}
|
||||
|
||||
@@ -61,10 +61,13 @@ export class SummaryPage extends MigrationWizardPage {
|
||||
createInformationRow(this._view, constants.LOCATION, this.migrationStateModel._sqlMigrationService.location),
|
||||
createInformationRow(this._view, constants.SUBSCRIPTION, this.migrationStateModel._sqlMigrationService.properties.resourceGroup),
|
||||
createInformationRow(this._view, constants.IR_PAGE_TITLE, this.migrationStateModel._targetSubscription.name),
|
||||
createInformationRow(this._view, constants.SUBSCRIPTION, this.migrationStateModel._sqlMigrationService.name),
|
||||
createInformationRow(this._view, constants.SHIR, this.migrationStateModel._nodeNames[0]),
|
||||
createInformationRow(this._view, constants.SUBSCRIPTION, this.migrationStateModel._sqlMigrationService.name)
|
||||
]
|
||||
);
|
||||
|
||||
if (this.migrationStateModel._databaseBackup.networkContainerType === NetworkContainerType.NETWORK_SHARE && this.migrationStateModel._nodeNames.length > 0) {
|
||||
this._flexContainer.addItem(createInformationRow(this._view, constants.SHIR, this.migrationStateModel._nodeNames.join(', ')));
|
||||
}
|
||||
}
|
||||
|
||||
public async onPageLeave(): Promise<void> {
|
||||
|
||||
Reference in New Issue
Block a user