remove preview from sql db target references (#20690)

* remove preview from sql db target references

* update "Azure recommendations" label

* handle missing target tables
This commit is contained in:
brian-harris
2022-10-03 18:39:43 -07:00
committed by GitHub
parent 3df9985aff
commit 66bb40c627
5 changed files with 72 additions and 73 deletions

View File

@@ -1,8 +1,8 @@
# Azure SQL Migration
The Azure SQL Migration extension in Azure Data Studio brings together a simplified assessment, recommendation, and migration experience that delivers the following capabilities:
The [Azure SQL Migration extension for Azure Data Studio](https://docs.microsoft.com/sql/azure-data-studio/extensions/azure-sql-migration-extension) brings together a simplified assessment, recommendation, and migration experience that delivers the following capabilities:
- A responsive user interface that provides you with an end-to-end migration experience that starts with a migration readiness assessment, SKU recommendation (based on performance data), and finalizes with the actual migration to Azure SQL.
- An enhanced assessment mechanism that can evaluate SQL Server instances, identifying databases that are ready for migration to the different Azure SQL targets.
- A SKU recommendation engine that collects performance data from the source SQL Server instance on-premises, generating right-sized SKU recommendations based on your Azure SQL target.
- A SKU recommendation engine (Preview) that collects performance data from the source SQL Server instance on-premises, generating right-sized SKU recommendations based on your Azure SQL target.
- A reliable Azure service powered by Azure Database Migration Service that orchestrates data movement activities to deliver a seamless migration experience.
- The ability to run online (for migrations requiring minimal downtime) or offline (for migrations where downtime persists through the migration) migration modes to suit your business requirements.
- The flexibility to create and configure a self-hosted integration runtime to provide your own compute for accessing the source SQL Server and backups in your on-premises environment.
@@ -18,12 +18,11 @@ Open the Azure Data Studio marketplace, select and install the latest version of
- A source SQL Server database(s) running on-premises, or on SQL Server on Azure Virtual Machine or any virtual machine running in the cloud (private, public).
- An Azure SQL Managed Instance, SQL Server on Azure Virtual Machine, or Azure SQL Database to migrate your database(s) to.
> Azure SQL Database offline migrations are still in public preview.
- Your database backup location details, either a network file share or an Azure Blob Storage container.
- Your database backup location details, either a network file share or an Azure Blob Storage container (not required for Azure SQL Database targets).
## Getting started
Refer to [Migrate databases using the Azure SQL Migration extension for Azure Data Studio](https://docs.microsoft.com/azure/dms/migration-using-azure-data-studio) for detailed documentation on capabilities and concepts.
## Assessment and SKU recommendation
## Assessment and SKU recommendation (Preview)
The assessment and SKU recommendation feature evaluates the source SQL Server database(s) for migration readiness.
It also generates right-sized SKU recommendations for your Azure target to meet the performance requirements of the source SQL Server database(s) with minimal cost. [Learn more.](https://aka.ms/ads-sql-sku-recommend)
@@ -32,13 +31,12 @@ It also generates right-sized SKU recommendations for your Azure target to meet
The Azure SQL Migration extension supports database migrations to the following Azure SQL targets.
- [Azure SQL Managed Instance](https://docs.microsoft.com/azure/azure-sql/managed-instance/sql-managed-instance-paas-overview)
- [SQL Server on Azure Virtual Machines](https://docs.microsoft.com/azure/azure-sql/virtual-machines/windows/sql-server-on-azure-vm-iaas-what-is-overview)
- [Azure SQL Database (Public preview)](https://docs.microsoft.com/azure/azure-sql/database/sql-database-paas-overview?view=azuresql)
- [Azure SQL Database (Preview)](https://docs.microsoft.com/azure/azure-sql/database/sql-database-paas-overview?view=azuresql)
## Migration modes
The following migration modes are supported for the corresponding Azure SQL targets.
- Online - The source SQL Server database is available for read and write activity, while the database backups (full + log) are continuously restored on the Azure SQL target. Application downtime is limited to the duration of the cutover at the end of migration.
> Online migrations to Azure SQL Database targets are not yet supported.
- Offline - The source SQL Server database cannot be used for write activity, while the database backup files are restored on the Azure SQL target. Application downtime persists from the start until the completion of the migration process.
> Azure SQL Database offline migrations are still in public preview.

View File

@@ -94,6 +94,9 @@ export const SKU_RECOMMENDATION_CHOOSE_A_TARGET = localize('sql.migration.wizard
export const SKU_RECOMMENDATION_MI_CARD_TEXT = localize('sql.migration.sku.mi.card.title', "Azure SQL Managed Instance");
export const SKU_RECOMMENDATION_SQLDB_CARD_TEXT = localize('sql.migration.sku.sqldb.card.title', "Azure SQL Database (PREVIEW)");
export const SKU_RECOMMENDATION_VM_CARD_TEXT = localize('sql.migration.sku.vm.card.title', "SQL Server on Azure Virtual Machine");
export const SKU_RECOMMENDATION_MI_TARGET_TEXT = localize('sql.migration.sku.mi.target.title', "Azure SQL Managed Instance");
export const SKU_RECOMMENDATION_SQLDB_TARGET_TEXT = localize('sql.migration.sku.sqldb.target.title', "Azure SQL Database");
export const SKU_RECOMMENDATION_VM_TARGET_TEXT = localize('sql.migration.sku.vm.target.title', "SQL Server on Azure Virtual Machine");
export const SELECT_AZURE_MI = localize('sql.migration.select.azure.mi', "Select your target Azure subscription and your target Azure SQL Managed Instance.");
export const SELECT_AZURE_VM = localize('sql.migration.select.azure.vm', "Select your target Azure Subscription and your target SQL Server on Azure Virtual Machine for your target.");
export const SKU_RECOMMENDATION_VIEW_ASSESSMENT_MI = localize('sql.migration.sku.recommendation.view.assessment.mi', "To migrate to Azure SQL Managed Instance, view assessment results and select one or more databases.");
@@ -130,7 +133,7 @@ export function SAVE_RECOMMENDATION_REPORT_SUCCESS(filePath: string): string {
}
// SKU
export const AZURE_RECOMMENDATION = localize('sql.migration.sku.recommendation', "Azure recommendation");
export const AZURE_RECOMMENDATION = localize('sql.migration.sku.recommendation', "Azure recommendation (PREVIEW)");
export function RECOMMENDATIONS_TITLE(targetType: string): string {
return localize('sql.migration.sku.recommendations.title', "{0} Recommendations", targetType);
}
@@ -519,6 +522,9 @@ export function TABLE_SELECTION_COUNT(selectedCount: number, rowCount: number):
export function TABLE_SELECTED_COUNT(selectedCount: number, rowCount: number): string {
return localize('sql.migration.table.selected.count', "{0} of {1} tables selected", selectedCount, rowCount);
}
export function MISSING_TARGET_TABLES_COUNT(tables: number): string {
return localize('sql.migration.table.missing.count', "Missing target tables excluded from list: {0}", tables);
}
export const DATABASE_MISSING_TABLES = localize('sql.migratino.database.missing.tables', "0 tables found.");
export const DATABASE_LOADING_TABLES = localize('sql.migratino.database.loading.tables', "Loading tables list...");
export const TABLE_SELECTION_FILTER = localize('sql.migratino.table.selection.filter', "Filter tables");
@@ -659,7 +665,7 @@ export const DASHBOARD_REFRESH_MIGRATIONS_TITLE = localize('sql.migration.refres
export const DASHBOARD_REFRESH_MIGRATIONS_LABEL = localize('sql.migration.refresh.migrations.error.label', "An error occurred while refreshing the migrations list. Please check your linked Azure connection and click refresh to try again.");
export const DASHBOARD_TITLE = localize('sql.migration.dashboard.title', "Azure SQL Migration");
export const DASHBOARD_DESCRIPTION = localize('sql.migration.dashboard.description', "Determine the migration readiness of your SQL Server instances, identify a recommended Azure SQL target, and complete the migration of your SQL Server instance to Azure SQL Managed Instance, SQL Server on Azure Virtual Machines or Azure SQL Database (PREVIEW).");
export const DASHBOARD_DESCRIPTION = localize('sql.migration.dashboard.description', "Determine the migration readiness of your SQL Server instances, identify a recommended Azure SQL target, and complete the migration of your SQL Server instance to Azure SQL Managed Instance, SQL Server on Azure Virtual Machines or Azure SQL Database.");
export const DASHBOARD_MIGRATE_TASK_BUTTON_TITLE = localize('sql.migration.dashboard.migrate.task.button', "Migrate to Azure SQL");
export const DASHBOARD_MIGRATE_TASK_BUTTON_DESCRIPTION = localize('sql.migration.dashboard.migrate.task.button.description', "Migrate a SQL Server instance to Azure SQL.");
export const DATABASE_MIGRATION_STATUS = localize('sql.migration.database.migration.status', "Database migration status");
@@ -667,7 +673,7 @@ export const HELP_TITLE = localize('sql.migration.dashboard.help.title', "Help a
export const PRE_REQ_TITLE = localize('sql.migration.pre.req.title', "Things you need before starting your Azure SQL migration:");
export const PRE_REQ_1 = localize('sql.migration.pre.req.1', "An Azure account (not required for assessment or SKU recommendation functionality)");
export const PRE_REQ_2 = localize('sql.migration.pre.req.2', "A source SQL Server database(s) running on on-premises, or on SQL Server on Azure Virtual Machine or any virtual machine running in the cloud (private, public).");
export const PRE_REQ_3 = localize('sql.migration.pre.req.3', "An Azure SQL Managed Instance, SQL Server on Azure Virtual Machine, or Azure SQL Database (PREVIEW) to migrate your database(s) to.");
export const PRE_REQ_3 = localize('sql.migration.pre.req.3', "An Azure SQL Managed Instance, SQL Server on Azure Virtual Machine, or Azure SQL Database to migrate your database(s) to.");
export const PRE_REQ_4 = localize('sql.migration.pre.req.4', "Your database backup location details, either a network file share or an Azure Blob Storage container (not required for Azure SQL Database targets).");
export const MIGRATION_IN_PROGRESS = localize('sql.migration.migration.in.progress', "Database migrations in progress");
export const MIGRATION_FAILED = localize('sql.migration.failed', "Database migrations failed");

View File

@@ -35,13 +35,13 @@ export class SkuRecommendationResultsDialog {
constructor(public model: MigrationStateModel, public _targetType: MigrationTargetType) {
switch (this._targetType) {
case MigrationTargetType.SQLMI:
this.targetName = constants.SKU_RECOMMENDATION_MI_CARD_TEXT;
this.targetName = constants.SKU_RECOMMENDATION_MI_TARGET_TEXT;
break;
case MigrationTargetType.SQLVM:
this.targetName = constants.SKU_RECOMMENDATION_VM_CARD_TEXT;
this.targetName = constants.SKU_RECOMMENDATION_VM_TARGET_TEXT;
break;
case MigrationTargetType.SQLDB:
this.targetName = constants.SKU_RECOMMENDATION_SQLDB_CARD_TEXT;
this.targetName = constants.SKU_RECOMMENDATION_SQLDB_TARGET_TEXT;
break;
}

View File

@@ -9,12 +9,14 @@ import * as constants from '../../constants/strings';
import { AzureSqlDatabaseServer } from '../../api/azure';
import { collectSourceDatabaseTableInfo, collectTargetDatabaseTableInfo, TableInfo } from '../../api/sqlUtils';
import { MigrationStateModel } from '../../models/stateMachine';
import { updateControlDisplay } from '../../api/utils';
const DialogName = 'TableMigrationSelection';
export class TableMigrationSelectionDialog {
private _dialog: azdata.window.Dialog | undefined;
private _headingText!: azdata.TextComponent;
private _missingTablesText!: azdata.TextComponent;
private _filterInputBox!: azdata.InputBoxComponent;
private _tableSelectionTable!: azdata.TableComponent;
private _tableLoader!: azdata.LoadingComponent;
@@ -25,6 +27,7 @@ export class TableMigrationSelectionDialog {
private _tableSelectionMap!: Map<string, TableInfo>;
private _targetTableMap!: Map<string, TableInfo>;
private _onSaveCallback: () => Promise<void>;
private _missingTableCount: number = 0;
constructor(
model: MigrationStateModel,
@@ -92,30 +95,32 @@ export class TableMigrationSelectionDialog {
const filterText = this._filterInputBox.value ?? '';
const selectedItems: number[] = [];
let tableRow = 0;
this._missingTableCount = 0;
this._tableSelectionMap.forEach(sourceTable => {
if (filterText?.length === 0 || sourceTable.tableName.indexOf(filterText) > -1) {
let tableStatus = constants.TARGET_TABLE_MISSING;
const targetTable = this._targetTableMap.get(sourceTable.tableName);
if (targetTable) {
const targetTableRowCount = targetTable?.rowCount ?? 0;
tableStatus = targetTableRowCount > 0
const tableStatus = targetTableRowCount > 0
? constants.TARGET_TABLE_NOT_EMPTY
: '--';
}
data.push([
sourceTable.selectedForMigration,
sourceTable.tableName,
tableStatus]);
if (sourceTable.selectedForMigration && targetTable) {
selectedItems.push(tableRow);
data.push([
sourceTable.selectedForMigration,
sourceTable.tableName,
tableStatus]);
if (sourceTable.selectedForMigration) {
selectedItems.push(tableRow);
}
}
this._missingTableCount += targetTable ? 0 : 1;
tableRow++;
}
});
await this._tableSelectionTable.updateProperty('data', data);
this._tableSelectionTable.selectedRows = selectedItems;
this._updateRowSelection();
await this._updateRowSelection();
}
private async _initializeDialog(dialog: azdata.window.Dialog): Promise<void> {
@@ -135,6 +140,10 @@ export class TableMigrationSelectionDialog {
.withProps({ value: constants.DATABASE_LOADING_TABLES })
.component();
this._missingTablesText = view.modelBuilder.text()
.withProps({ display: 'none' })
.component();
this._tableSelectionTable = await this._createSelectionTable(view);
this._tableLoader = view.modelBuilder.loadingComponent()
.withItem(this._tableSelectionTable)
@@ -147,6 +156,7 @@ export class TableMigrationSelectionDialog {
.withItems([
this._filterInputBox,
this._headingText,
this._missingTablesText,
this._tableLoader],
{ flex: '0 0 auto' })
.withProps({ CSSStyles: { 'margin': '0 0 0 15px' } })
@@ -228,62 +238,36 @@ export class TableMigrationSelectionDialog {
.withValidation(() => true)
.component();
let updating: boolean = false;
this._disposables.push(
table.onRowSelected(e => {
if (updating) {
return;
}
updating = true;
// collect table list selected for migration
const selectedRows = this._tableSelectionTable.selectedRows ?? [];
const keepSelectedRows: number[] = [];
// determine if selected rows have a matching target and can be selected
selectedRows.forEach(rowIndex => {
// get selected source table name
const sourceTableName = this._tableSelectionTable.data[rowIndex][1] as string;
// get source table info
const sourceTableInfo = this._tableSelectionMap.get(sourceTableName);
if (sourceTableInfo) {
// see if source table exists on target database
const targetTableInfo = this._targetTableMap.get(sourceTableName);
// keep source table selected
sourceTableInfo.selectedForMigration = targetTableInfo !== undefined;
// update table selection map with new selectedForMigration value
this._tableSelectionMap.set(sourceTableName, sourceTableInfo);
// keep row selected
if (sourceTableInfo.selectedForMigration) {
keepSelectedRows.push(rowIndex);
table.onRowSelected(
async e => {
// collect table list selected for migration
const selectedRows = this._tableSelectionTable.selectedRows ?? [];
selectedRows.forEach(rowIndex => {
// get selected source table name
const rowData = this._tableSelectionTable.data[rowIndex];
const sourceTableName = rowData.length > 1
? rowData[1] as string
: '';
// get source table info
const sourceTableInfo = this._tableSelectionMap.get(sourceTableName);
if (sourceTableInfo) {
// see if source table exists on target database
const targetTableInfo = this._targetTableMap.get(sourceTableName);
// keep source table selected
sourceTableInfo.selectedForMigration = targetTableInfo !== undefined;
// update table selection map with new selectedForMigration value
this._tableSelectionMap.set(sourceTableName, sourceTableInfo);
}
}
});
});
// if the selected rows are different, update the selectedRows property
if (!this._areEqual(this._tableSelectionTable.selectedRows ?? [], keepSelectedRows)) {
this._tableSelectionTable.selectedRows = keepSelectedRows;
}
this._updateRowSelection();
updating = false;
}));
await this._updateRowSelection();
}));
return table;
}
private _areEqual(source: number[], target: number[]): boolean {
if (source.length === target.length) {
for (let i = 0; i < source.length; i++) {
if (source[i] !== target[i]) {
return false;
}
}
return true;
}
return false;
}
private _updateRowSelection(): void {
private async _updateRowSelection(): Promise<void> {
this._headingText.value = this._tableSelectionTable.data.length > 0
? constants.TABLE_SELECTED_COUNT(
this._tableSelectionTable.selectedRows?.length ?? 0,
@@ -291,6 +275,9 @@ export class TableMigrationSelectionDialog {
: this._tableLoader.loading
? constants.DATABASE_LOADING_TABLES
: constants.DATABASE_MISSING_TABLES;
this._missingTablesText.value = constants.MISSING_TARGET_TABLES_COUNT(this._missingTableCount);
await updateControlDisplay(this._missingTablesText, this._missingTableCount > 0);
}
private async _save(): Promise<void> {
@@ -300,7 +287,10 @@ export class TableMigrationSelectionDialog {
const selectedRows = this._tableSelectionTable.selectedRows ?? [];
const selectedTables = new Map<String, TableInfo>();
selectedRows.forEach(rowIndex => {
const tableName = this._tableSelectionTable.data[rowIndex][1] as string;
const tableRow = this._tableSelectionTable.data[rowIndex];
const tableName = tableRow.length > 1
? this._tableSelectionTable.data[rowIndex][1] as string
: '';
const tableInfo = this._tableSelectionMap.get(tableName);
if (tableInfo) {
selectedTables.set(tableName, tableInfo);

View File

@@ -95,6 +95,10 @@ export class TargetSelectionPage extends MigrationWizardPage {
this._azureResourceDropdownLabel.value = constants.AZURE_SQL_DATABASE;
this._azureResourceDropdown.ariaLabel = constants.AZURE_SQL_DATABASE;
this._updateConnectionButtonState();
if (this.migrationStateModel._didUpdateDatabasesForMigration) {
await this._resetTargetMapping();
this.migrationStateModel._didUpdateDatabasesForMigration = false;
}
break;
}
@@ -940,6 +944,7 @@ export class TargetSelectionPage extends MigrationWizardPage {
this.migrationStateModel._sourceTargetMapping.set(
sourceDatabase,
targetDatabaseInfo);
this.migrationStateModel.refreshDatabaseBackupPage = true;
this.migrationStateModel._didDatabaseMappingChange = true;
}));