mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-18 01:25:37 -05:00
[SQL Migration] Properly respect user's encryptConnection and trustServerCertificate settings (#21824)
* WIP * Always get latest current connection * Update more references * Clean up * Clean up * vbump * Update comments * Address PR feedback * Separate into helper methods
This commit is contained in:
@@ -14,7 +14,7 @@ import { v4 as uuidv4 } from 'uuid';
|
||||
import { sendSqlMigrationActionEvent, TelemetryAction, TelemetryViews, logError } from '../telemetry';
|
||||
import { hashString, deepClone } from '../api/utils';
|
||||
import { SKURecommendationPage } from '../wizard/skuRecommendationPage';
|
||||
import { excludeDatabases, getConnectionProfile, LoginTableInfo, SourceDatabaseInfo, TargetDatabaseInfo } from '../api/sqlUtils';
|
||||
import { excludeDatabases, getEncryptConnectionValue, getSourceConnectionId, getSourceConnectionProfile, getSourceConnectionServerInfo, getSourceConnectionString, getSourceConnectionUri, getTargetConnectionString, getTrustServerCertificateValue, LoginTableInfo, SourceDatabaseInfo, TargetDatabaseInfo } from '../api/sqlUtils';
|
||||
import { LoginMigrationModel, LoginMigrationStep } from './loginMigrationModel';
|
||||
import { TdeMigrationDbResult, TdeMigrationModel } from './tdeModels';
|
||||
import { NetworkInterfaceModel } from '../api/dataModels/azure/networkInterfaceModel';
|
||||
@@ -134,7 +134,6 @@ export interface Blob {
|
||||
}
|
||||
|
||||
export interface Model {
|
||||
readonly sourceConnectionId: string;
|
||||
readonly currentState: State;
|
||||
gatheringInformationError: string | undefined;
|
||||
_azureAccount: azdata.Account | undefined;
|
||||
@@ -297,7 +296,6 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
|
||||
constructor(
|
||||
public extensionContext: vscode.ExtensionContext,
|
||||
private readonly _sourceConnectionId: string,
|
||||
public readonly migrationService: mssql.ISqlMigrationService,
|
||||
public readonly tdeMigrationService: mssql.ITdeMigrationService
|
||||
) {
|
||||
@@ -373,10 +371,6 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
|| this.isBackupContainerNetworkShare;
|
||||
}
|
||||
|
||||
public get sourceConnectionId(): string {
|
||||
return this._sourceConnectionId;
|
||||
}
|
||||
|
||||
public get currentState(): State {
|
||||
return this._currentState;
|
||||
}
|
||||
@@ -387,7 +381,7 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
this._stateChangeEventEmitter.fire({ oldState, newState: this.currentState });
|
||||
}
|
||||
public async getDatabases(): Promise<string[]> {
|
||||
const temp = await azdata.connection.listDatabases(this.sourceConnectionId);
|
||||
const temp = await azdata.connection.listDatabases(await getSourceConnectionId());
|
||||
const finalResult = temp.filter((name) => !excludeDatabases.includes(name));
|
||||
return finalResult;
|
||||
}
|
||||
@@ -404,7 +398,7 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
}
|
||||
|
||||
public async getDatabaseAssessments(targetType: MigrationTargetType[]): Promise<ServerAssessment> {
|
||||
const ownerUri = await azdata.connection.getUriForConnection(this.sourceConnectionId);
|
||||
const ownerUri = await getSourceConnectionUri();
|
||||
try {
|
||||
const xEventsFilesFolderPath = ''; // to-do: collect by prompting the user in the UI - for now, blank = disabled
|
||||
const response = (await this.migrationService.getAssessments(ownerUri, this._databasesForAssessment, xEventsFilesFolderPath))!;
|
||||
@@ -472,8 +466,8 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
let fullInstanceName: string;
|
||||
|
||||
// execute a query against the source to get the correct instance name
|
||||
const connectionProfile = await this.getSourceConnectionProfile();
|
||||
const connectionUri = await azdata.connection.getUriForConnection(this._sourceConnectionId);
|
||||
const connectionProfile = await getSourceConnectionProfile();
|
||||
const connectionUri = await getSourceConnectionUri();
|
||||
const queryProvider = azdata.dataprotocol.getProvider<azdata.QueryProvider>(connectionProfile.providerId, azdata.DataProviderType.QueryProvider);
|
||||
const queryString = 'SELECT SERVERPROPERTY(\'ServerName\');';
|
||||
const queryResult = await queryProvider.runQueryAndReturn(connectionUri, queryString);
|
||||
@@ -482,9 +476,9 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
fullInstanceName = queryResult.rows[0][0].displayValue;
|
||||
} else {
|
||||
// get the instance name from connection info in case querying for the instance name doesn't work for whatever reason
|
||||
const serverInfo = await azdata.connection.getServerInfo(this.sourceConnectionId);
|
||||
const machineName = (<any>serverInfo)['machineName']; // contains the correct machine name but not necessarily the correct instance name
|
||||
const instanceName = (await this.getSourceConnectionProfile()).serverName; // contains the correct instance name but not necessarily the correct machine name
|
||||
const serverInfo = await getSourceConnectionServerInfo();
|
||||
const machineName = (<any>serverInfo)['machineName']; // contains the correct machine name but not necessarily the correct instance name
|
||||
const instanceName = connectionProfile.serverName; // contains the correct instance name but not necessarily the correct machine name
|
||||
|
||||
if (instanceName.includes('\\')) {
|
||||
fullInstanceName = machineName + '\\' + instanceName.substring(instanceName.indexOf('\\') + 1);
|
||||
@@ -554,26 +548,6 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
return this._targetServerName;
|
||||
}
|
||||
|
||||
public async getSourceConnectionString(): Promise<string> {
|
||||
return await azdata.connection.getConnectionString(this._sourceConnectionId, true);
|
||||
}
|
||||
|
||||
public async getTargetConnectionString(): Promise<string> {
|
||||
const connectionProfile = getConnectionProfile(
|
||||
this.targetServerName,
|
||||
this._targetServerInstance.id,
|
||||
this._targetUserName,
|
||||
this._targetPassword,
|
||||
true /* trustServerCertificate */);
|
||||
|
||||
const result = await azdata.connection.connect(connectionProfile, false, false);
|
||||
if (result.connected && result.connectionId) {
|
||||
return azdata.connection.getConnectionString(result.connectionId, true);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
private updateLoginMigrationResults(newResult: mssql.StartLoginMigrationResult): void {
|
||||
if (this._loginMigrationsResult && this._loginMigrationsResult.exceptionMap) {
|
||||
for (var key in newResult.exceptionMap) {
|
||||
@@ -588,8 +562,17 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
try {
|
||||
this._loginMigrationModel.AddNewLogins(this._loginsForMigration.map(row => row.loginName));
|
||||
|
||||
const sourceConnectionString = await this.getSourceConnectionString();
|
||||
const targetConnectionString = await this.getTargetConnectionString();
|
||||
const sourceConnectionString = await getSourceConnectionString();
|
||||
const targetConnectionString = await getTargetConnectionString(
|
||||
this.targetServerName,
|
||||
this._targetServerInstance.id,
|
||||
this._targetUserName,
|
||||
this._targetPassword,
|
||||
// for login migration, connect to target Azure SQL with true/true
|
||||
// to-do: take as input from the user, should be true/false for DB/MI but true/true for VM
|
||||
true /* encryptConnection */,
|
||||
true /* trustServerCertificate */);
|
||||
|
||||
var response = (await this.migrationService.migrateLogins(
|
||||
sourceConnectionString,
|
||||
targetConnectionString,
|
||||
@@ -612,8 +595,16 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
|
||||
public async establishUserMappings(): Promise<Boolean> {
|
||||
try {
|
||||
const sourceConnectionString = await this.getSourceConnectionString();
|
||||
const targetConnectionString = await this.getTargetConnectionString();
|
||||
const sourceConnectionString = await getSourceConnectionString();
|
||||
const targetConnectionString = await getTargetConnectionString(
|
||||
this.targetServerName,
|
||||
this._targetServerInstance.id,
|
||||
this._targetUserName,
|
||||
this._targetPassword,
|
||||
// for login migration, connect to target Azure SQL with true/true
|
||||
// to-do: take as input from the user, should be true/false for DB/MI but true/true for VM
|
||||
true /* encryptConnection */,
|
||||
true /* trustServerCertificate */);
|
||||
|
||||
var response = (await this.migrationService.establishUserMapping(
|
||||
sourceConnectionString,
|
||||
@@ -637,8 +628,16 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
|
||||
public async migrateServerRolesAndSetPermissions(): Promise<Boolean> {
|
||||
try {
|
||||
const sourceConnectionString = await this.getSourceConnectionString();
|
||||
const targetConnectionString = await this.getTargetConnectionString();
|
||||
const sourceConnectionString = await getSourceConnectionString();
|
||||
const targetConnectionString = await getTargetConnectionString(
|
||||
this.targetServerName,
|
||||
this._targetServerInstance.id,
|
||||
this._targetUserName,
|
||||
this._targetPassword,
|
||||
// for login migration, connect to target Azure SQL with true/true
|
||||
// to-do: take as input from the user, should be true/false for DB/MI but true/true for VM
|
||||
true /* encryptConnection */,
|
||||
true /* trustServerCertificate */);
|
||||
|
||||
var response = (await this.migrationService.migrateServerRolesAndSetPermissions(
|
||||
sourceConnectionString,
|
||||
@@ -782,7 +781,7 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
page: SKURecommendationPage): Promise<boolean> {
|
||||
try {
|
||||
if (!this.performanceCollectionInProgress()) {
|
||||
const ownerUri = await azdata.connection.getUriForConnection(this.sourceConnectionId);
|
||||
const ownerUri = await getSourceConnectionUri();
|
||||
const response = await this.migrationService.startPerfDataCollection(
|
||||
ownerUri,
|
||||
dataFolder,
|
||||
@@ -1080,12 +1079,6 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
return this.extensionContext.extensionPath;
|
||||
}
|
||||
|
||||
public async getSourceConnectionProfile(): Promise<azdata.connection.ConnectionProfile> {
|
||||
const sqlConnections = await azdata.connection.getConnections();
|
||||
return sqlConnections.find(
|
||||
value => value.connectionId === this.sourceConnectionId)!;
|
||||
}
|
||||
|
||||
public getLocationDisplayName(location: string): Promise<string> {
|
||||
return getLocationDisplayName(location);
|
||||
}
|
||||
@@ -1103,7 +1096,7 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
reportUpdate: (dbName: string, succeeded: boolean, message: string) => Promise<void>): Promise<OperationResult<TdeMigrationDbResult[]>> {
|
||||
|
||||
const tdeEnabledDatabases = this.tdeMigrationConfig.getTdeEnabledDatabases();
|
||||
const connectionString = await azdata.connection.getConnectionString(this.sourceConnectionId, true);
|
||||
const connectionString = await getSourceConnectionString();
|
||||
|
||||
const opResult: OperationResult<TdeMigrationDbResult[]> = {
|
||||
success: false,
|
||||
@@ -1148,10 +1141,7 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
}
|
||||
|
||||
public async startMigration() {
|
||||
const sqlConnections = await azdata.connection.getConnections();
|
||||
const currentConnection = sqlConnections.find(
|
||||
value => value.connectionId === this.sourceConnectionId);
|
||||
|
||||
const currentConnection = await getSourceConnectionProfile();
|
||||
const isOfflineMigration = this._databaseBackup.migrationMode === MigrationMode.OFFLINE;
|
||||
const isSqlDbTarget = this.isSqlDbTarget;
|
||||
|
||||
@@ -1166,8 +1156,8 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
authentication: this._authenticationType,
|
||||
userName: this._sqlServerUsername,
|
||||
password: this._sqlServerPassword,
|
||||
// to-do: use correct value of encryptConnection and trustServerCertificate
|
||||
trustServerCertificate: currentConnection?.options.trustServerCertificate ?? false
|
||||
encryptConnection: getEncryptConnectionValue(currentConnection),
|
||||
trustServerCertificate: getTrustServerCertificateValue(currentConnection)
|
||||
},
|
||||
scope: this._targetServerInstance.id,
|
||||
offlineConfiguration: {
|
||||
@@ -1208,14 +1198,15 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
authentication: this._authenticationType,
|
||||
userName: this._sqlServerUsername,
|
||||
password: this._sqlServerPassword,
|
||||
encryptConnection: true,
|
||||
trustServerCertificate: currentConnection?.options.trustServerCertificate ?? false,
|
||||
encryptConnection: getEncryptConnectionValue(currentConnection),
|
||||
trustServerCertificate: getTrustServerCertificateValue(currentConnection)
|
||||
};
|
||||
requestBody.properties.targetSqlConnection = {
|
||||
dataSource: sqlDbTarget.properties.fullyQualifiedDomainName,
|
||||
authentication: MigrationSourceAuthenticationType.Sql,
|
||||
userName: this._targetUserName,
|
||||
password: this._targetPassword,
|
||||
// when connecting to a target Azure SQL DB, use true/false
|
||||
encryptConnection: true,
|
||||
trustServerCertificate: false,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user