Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP][SQL Migration] Target provisioning experience #21782

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
2 changes: 2 additions & 0 deletions extensions/sql-migration/DEVELOPER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ For example:

## Debugging the extension service:

To debug NuGet calls, once the migration service has been launched, navigate to VSCode > Run and Debug > select ".NET Core Attach" > attach to "MicrosoftSqlToolsMigration.exe". Breakpoints should then work as intended.

### The logs for the extension and service during runtime can be accessed by:

1. Opening the command palette (Ctrl+P) and searching for "Developer: Open Extensions Logs Folder"
Expand Down
47 changes: 47 additions & 0 deletions extensions/sql-migration/src/api/sqlUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { AzureSqlDatabase, AzureSqlDatabaseServer } from './azure';
import { generateGuid } from './utils';
import * as utils from '../api/utils';
import { TelemetryAction, TelemetryViews, logError } from '../telemetry';
import { DatabaseCollationMapping } from '../service/contracts';
import * as constants from '../constants/strings';

const query_database_tables_sql = `
Expand Down Expand Up @@ -90,6 +91,16 @@ const query_login_tables_include_windows_auth_sql = `

const query_is_sys_admin_sql = `SELECT IS_SRVROLEMEMBER('sysadmin');`;

const query_get_server_collation_sql = `SELECT SERVERPROPERTY('collation');`;

const query_get_database_collations_sql = `
SELECT
db.name as database_name,
db.collation_name as database_collation
FROM sys.databases db
WHERE db.name not in ('master', 'tempdb', 'model', 'msdb')
AND is_distributor <> 1;`;

export const excludeDatabases: string[] = [
'master',
'tempdb',
Expand Down Expand Up @@ -509,3 +520,39 @@ export async function isSourceConnectionSysAdmin(): Promise<boolean> {

return getSqlBoolean(results.rows[0][0]);
}

export async function getSourceServerLevelCollation(): Promise<string> {
const sourceConnectionId = await getSourceConnectionId();
const ownerUri = await azdata.connection.getUriForConnection(sourceConnectionId);
const queryProvider = azdata.dataprotocol.getProvider<azdata.QueryProvider>(
'MSSQL',
azdata.DataProviderType.QueryProvider);

const results = await queryProvider.runQueryAndReturn(
ownerUri,
query_get_server_collation_sql);

return getSqlString(results.rows[0][0]);
}

export async function getSourceDatabaseLevelCollations(): Promise<DatabaseCollationMapping[]> {
const sourceConnectionId = await getSourceConnectionId();
const ownerUri = await azdata.connection.getUriForConnection(sourceConnectionId);
const queryProvider = azdata.dataprotocol.getProvider<azdata.QueryProvider>(
'MSSQL',
azdata.DataProviderType.QueryProvider);

const results = await queryProvider.runQueryAndReturn(
ownerUri,
query_get_database_collations_sql);

const databaseNames = results.rows.map(row => getSqlString(row[0])) ?? [];
const collations = results.rows.map(row => getSqlString(row[1])) ?? [];

return databaseNames.map((databaseName, index) => {
return {
databaseName: databaseName,
databaseCollation: collations[index]
};
});
}
27 changes: 27 additions & 0 deletions extensions/sql-migration/src/constants/strings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,33 @@ export function TIME_IN_MINUTES(val: number): number {
return val * 60000;
}

// Target provisioning
export const TARGET_PROVISIONING_LINK = localize('sql.migration.targetprovisioning.link', "Deploy to Azure");
export const TARGET_PROVISIONING_TITLE = localize('sql.migration.targetprovisioning.title', "Deployment script");
export const TARGET_PROVISIONING_HEADER = localize('sql.migration.targetprovisioning.header', "Quickstart ARM template");
export const TARGET_PROVISIONING_DESCRIPTION = localize('sql.migration.targetprovisioning.description', "If you don't already have an existing Azure SQL target, you can use this quickstart ARM template to help you provision one. An ARM (Azure Resource Manager) template defines Azure resources to deploy as well as their properties.");
export const TARGET_PROVISIONING_WARNING = localize('sql.migration.targetprovisioning.warning', "The provided template is a quickstart template. Review it, and after deployment, we recommend reviewing the {0} on how to solve common security requirements, and you should consult your database and security team on which features to implement.");
export const TARGET_PROVISIONING_BEST_PRACTICES = localize('sql.migration.targetprovisioning.bestpractices', "Best practices documentation");
export const TARGET_PROVISIONING_MI_DETAILS = localize('sql.migration.targetprovisioning.mi', "This template will create an Azure SQL Managed Instance within a new virtual network. The recommended sizing configuration, including compute size, hardware family, service tier, storage size, and server collation has been prefilled.");
export const TARGET_PROVISIONING_VM_DETAILS = localize('sql.migration.targetprovisioning.vm', "This template will create a SQL Server on Azure Virtual Machine, which includes a new virtual machine, network interface, network security group, and public IP address. The recommended sizing configuration, including VM size, storage configuration (for data, log, and tempdb), and server collation has been prefilled.");
export function TARGET_PROVISIONING_DB_DETAILS(dbCount: number): string {
return dbCount === 1
? localize('sql.migration.targetprovisioning.db.one', "This template allows you to create a SQL Server and {0} SQL Database. The recommended sizing configuration has been prefilled.", dbCount)
: localize('sql.migration.targetprovisioning.db.many', "This template allows you to create a SQL Server and {0} SQL Databases. The recommended sizing configurations have already been prefilled.", dbCount);
}

export const TARGET_PROVISIONING_HYPERLINK_LABEL = localize('sql.migration.targetprovisioning.hyperlink', "Learn more about ARM templates");
export const TARGET_PROVISIONING_IN_PROGRESS = localize('sql.migration.targetprovisioning.inprogress', "Deployment script generation in progress...");
export const TARGET_PROVISIONING_ERROR = localize('sql.migration.targetprovisioning.error', "An error occurred while generating the deployment script. Please try again.");
export const COPY_TO_CLIPBOARD = localize('sql.migration.copytoclipboard', "Copy to clipboard");
export const COPIED_TO_CLIPBOARD = localize('sql.migration.copiedtoclipboard', "Copied to clipboard");
export const TARGET_PROVISIONING_SAVE = localize('sql.migration.targetprovisioning.save', "Save template");
export const TARGET_PROVISIONING_DEPLOY = localize('sql.migration.targetprovisioning.deploy', "Deploy in Azure Portal");

export function TARGET_PROVISIONING_SAVE_SUCCESS(filePath: string): string {
return localize('sql.migration.targetprovisioning.save.success', "Successfully saved provisioning script to {0}.", filePath);
}

// Login Migrations
export function LOGIN_WIZARD_TITLE(instanceName: string): string {
return localize('sql-migration.login.wizard.title', "Migrate logins from '{0}' to Azure SQL", instanceName);
Expand Down