mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-08 17:24:01 -05:00
Junierch/mi tde (#21573)
* WIP * wip tde wizard * wip for merge w master * wip * wip share * tde wizard * PR reviews updates * PR review updates * PR updates * PR review updates * PR reviews updates * Bump STS to 4.4.0.22 * PR reviews updates * fix localize build issue * fix build issue with localize * remove unused function * Windows only flag. Bug Bash fixes * Use azdata with latest STS changes * revert azdata, other PR comments * sts and extesion version upgraded. logins back
This commit is contained in:
@@ -16,6 +16,7 @@ import { hashString, deepClone } from '../api/utils';
|
||||
import { SKURecommendationPage } from '../wizard/skuRecommendationPage';
|
||||
import { excludeDatabases, getConnectionProfile, LoginTableInfo, SourceDatabaseInfo, TargetDatabaseInfo } from '../api/sqlUtils';
|
||||
import { LoginMigrationModel, LoginMigrationStep } from './loginMigrationModel';
|
||||
import { TdeMigrationDbResult, TdeMigrationModel } from './tdeModels';
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export enum ValidateIrState {
|
||||
@@ -65,6 +66,10 @@ export enum MigrationSourceAuthenticationType {
|
||||
Sql = 'SqlAuthentication'
|
||||
}
|
||||
|
||||
export enum AssessmentRuleId {
|
||||
TdeEnabled = 'TdeEnabled'
|
||||
}
|
||||
|
||||
export enum MigrationMode {
|
||||
ONLINE,
|
||||
OFFLINE
|
||||
@@ -173,6 +178,7 @@ export interface SkuRecommendationSavedInfo {
|
||||
}
|
||||
|
||||
export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
|
||||
public _azureAccounts!: azdata.Account[];
|
||||
public _azureAccount!: azdata.Account;
|
||||
public _accountTenants!: azurecore.Tenant[];
|
||||
@@ -276,6 +282,8 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
public _sessionId: string = uuidv4();
|
||||
public serverName!: string;
|
||||
|
||||
public tdeMigrationConfig: TdeMigrationModel = new TdeMigrationModel();
|
||||
|
||||
private _stateChangeEventEmitter = new vscode.EventEmitter<StateChangeEvent>();
|
||||
private _currentState: State;
|
||||
private _gatheringInformationError: string | undefined;
|
||||
@@ -289,7 +297,8 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
constructor(
|
||||
public extensionContext: vscode.ExtensionContext,
|
||||
private readonly _sourceConnectionId: string,
|
||||
public readonly migrationService: mssql.ISqlMigrationService
|
||||
public readonly migrationService: mssql.ISqlMigrationService,
|
||||
public readonly tdeMigrationService: mssql.ITdeMigrationService
|
||||
) {
|
||||
this._currentState = State.INIT;
|
||||
this._databaseBackup = {} as DatabaseBackupModel;
|
||||
@@ -300,6 +309,7 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
this._assessmentReportFilePath = '';
|
||||
this._skuRecommendationReportFilePaths = [];
|
||||
this.mementoString = 'sqlMigration.assessmentResults';
|
||||
this._targetManagedInstances = [];
|
||||
|
||||
this._skuScalingFactor = 100;
|
||||
this._skuTargetPercentile = 95;
|
||||
@@ -1074,6 +1084,55 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
).map(t => t.name);
|
||||
}
|
||||
|
||||
public async startTdeMigration(
|
||||
accessToken: string,
|
||||
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 opResult: OperationResult<TdeMigrationDbResult[]> = {
|
||||
success: false,
|
||||
result: [],
|
||||
errors: []
|
||||
};
|
||||
|
||||
try {
|
||||
|
||||
const migrationResult = await this.tdeMigrationService.migrateCertificate(
|
||||
tdeEnabledDatabases,
|
||||
connectionString,
|
||||
this._targetSubscription?.id,
|
||||
this._resourceGroup?.name,
|
||||
this._targetServerInstance.name,
|
||||
this.tdeMigrationConfig._networkPath,
|
||||
accessToken,
|
||||
reportUpdate);
|
||||
|
||||
opResult.errors = migrationResult.migrationStatuses
|
||||
.filter(entry => !entry.success)
|
||||
.map(entry => constants.TDE_MIGRATION_ERROR_DB(entry.dbName, entry.message));
|
||||
|
||||
opResult.result = migrationResult.migrationStatuses.map(m => ({
|
||||
name: m.dbName,
|
||||
success: m.success,
|
||||
message: m.message
|
||||
}));
|
||||
|
||||
} catch (e) {
|
||||
opResult.errors = [constants.TDE_MIGRATION_ERROR(e.message)];
|
||||
|
||||
opResult.result = tdeEnabledDatabases.map(m => ({
|
||||
name: m,
|
||||
success: false,
|
||||
message: e.message
|
||||
}));
|
||||
}
|
||||
|
||||
opResult.success = opResult.errors.length === 0; //Set success when there are no errors.
|
||||
return opResult;
|
||||
}
|
||||
|
||||
public async startMigration() {
|
||||
const sqlConnections = await azdata.connection.getConnections();
|
||||
const currentConnection = sqlConnections.find(
|
||||
@@ -1329,7 +1388,6 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
await this.extensionContext.globalState.update(`${this.mementoString}.${serverName}`, saveInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public async loadSavedInfo(): Promise<Boolean> {
|
||||
try {
|
||||
this._targetType = this.savedInfo.migrationTargetType || undefined!;
|
||||
@@ -1391,6 +1449,8 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public GetTargetType(): string {
|
||||
@@ -1425,3 +1485,9 @@ export interface SkuRecommendation {
|
||||
recommendations?: mssql.SkuRecommendationResult;
|
||||
recommendationError?: Error;
|
||||
}
|
||||
|
||||
export interface OperationResult<T> {
|
||||
success: boolean;
|
||||
result: T;
|
||||
errors: string[];
|
||||
}
|
||||
|
||||
173
extensions/sql-migration/src/models/tdeModels.ts
Normal file
173
extensions/sql-migration/src/models/tdeModels.ts
Normal file
@@ -0,0 +1,173 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export enum TdeMigrationState {
|
||||
Pending = 'Pending',
|
||||
Running = 'Running',
|
||||
Succeeded = 'Succeeded',
|
||||
Failed = 'Failed',
|
||||
Canceled = 'Canceled',
|
||||
}
|
||||
|
||||
export enum TdeDatabaseMigrationState {
|
||||
Running = 'Running',
|
||||
Succeeded = 'Succeeded',
|
||||
Failed = 'Failed',
|
||||
Canceled = 'Canceled',
|
||||
}
|
||||
|
||||
export interface TdeMigrationDbState {
|
||||
name: string;
|
||||
dbState: TdeDatabaseMigrationState;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface TdeMigrationResult {
|
||||
dbList: TdeMigrationDbState[];
|
||||
state: TdeMigrationState;
|
||||
}
|
||||
|
||||
|
||||
export interface TdeMigrationDbResult {
|
||||
name: string;
|
||||
success: boolean;
|
||||
message: string;
|
||||
}
|
||||
|
||||
|
||||
export class TdeMigrationModel {
|
||||
private _exportUsingADS?: boolean | undefined;
|
||||
private _adsExportConfirmation: boolean;
|
||||
private _configurationCompleted: boolean;
|
||||
private _shownBefore: boolean;
|
||||
private _encryptedDbs: string[];
|
||||
private _tdeMigrationCompleted: boolean;
|
||||
private _tdeMigrationResult: TdeMigrationResult = {
|
||||
state: TdeMigrationState.Pending,
|
||||
dbList: []
|
||||
};
|
||||
|
||||
public _networkPath: string;
|
||||
|
||||
constructor(
|
||||
) {
|
||||
this._exportUsingADS = true;
|
||||
this._adsExportConfirmation = false;
|
||||
this._configurationCompleted = false;
|
||||
this._shownBefore = false;
|
||||
this._encryptedDbs = [];
|
||||
|
||||
this._networkPath = '';
|
||||
this._tdeMigrationCompleted = false;
|
||||
}
|
||||
|
||||
// If the configuration dialog was shown already.
|
||||
public shownBefore(): boolean {
|
||||
return this._shownBefore;
|
||||
}
|
||||
|
||||
// If the configuration dialog was shown already.
|
||||
public configurationShown(): void {
|
||||
this._shownBefore = true;
|
||||
}
|
||||
|
||||
// The number of encrypted databaes
|
||||
public getTdeEnabledDatabasesCount(): number {
|
||||
return this._encryptedDbs.length;
|
||||
}
|
||||
|
||||
// Whether or not there are tde enabled databases
|
||||
public hasTdeEnabledDatabases(): boolean {
|
||||
return this.getTdeEnabledDatabasesCount() > 0;
|
||||
}
|
||||
|
||||
// The list of encrypted databaes
|
||||
public getTdeEnabledDatabases(): string[] {
|
||||
return this._encryptedDbs;
|
||||
}
|
||||
|
||||
// Sets the databases that are
|
||||
public setTdeEnabledDatabasesCount(encryptedDbs: string[]): void {
|
||||
this._encryptedDbs = encryptedDbs;
|
||||
this._tdeMigrationCompleted = false; // Reset the migration status when databases change
|
||||
this._shownBefore = false; // Reset the tde dialog showing status when databases change
|
||||
}
|
||||
|
||||
// Sets the certificate migration method
|
||||
public setTdeMigrationMethod(useAds: boolean): void {
|
||||
if (useAds) {
|
||||
this._exportUsingADS = true;
|
||||
} else {
|
||||
this._exportUsingADS = false;
|
||||
this._adsExportConfirmation = false;
|
||||
}
|
||||
this._tdeMigrationCompleted = false;
|
||||
}
|
||||
|
||||
// When a migration configuration was configured and accepted on the configuration blade.
|
||||
public setConfigurationCompleted(): void {
|
||||
this._configurationCompleted = true;
|
||||
}
|
||||
|
||||
// When ADS is configured to do the certificates migration
|
||||
public shouldAdsMigrateCertificates(): boolean {
|
||||
return this.hasTdeEnabledDatabases() && this._configurationCompleted && this.isTdeMigrationMethodAdsConfirmed();
|
||||
}
|
||||
|
||||
// When any valid method is properly set.
|
||||
public isTdeMigrationMethodSet(): boolean {
|
||||
return this.isTdeMigrationMethodAdsConfirmed() || this.isTdeMigrationMethodManual();
|
||||
}
|
||||
|
||||
// When Ads is selected as method. may still need confirmation.
|
||||
public isTdeMigrationMethodAds(): boolean {
|
||||
return this._exportUsingADS === true;
|
||||
}
|
||||
|
||||
// When ads migration method is confirmed
|
||||
public isTdeMigrationMethodAdsConfirmed(): boolean {
|
||||
return this.isTdeMigrationMethodAds() && this._adsExportConfirmation === true;
|
||||
}
|
||||
|
||||
// When manual method is selected
|
||||
public isTdeMigrationMethodManual(): boolean {
|
||||
return this._exportUsingADS === false;
|
||||
}
|
||||
|
||||
// When manual method is selected
|
||||
public tdeMigrationCompleted(): boolean {
|
||||
return this._tdeMigrationCompleted;
|
||||
}
|
||||
|
||||
// Get the value for the lastest tde migration result
|
||||
public lastTdeMigrationResult(): TdeMigrationResult {
|
||||
return this._tdeMigrationResult;
|
||||
}
|
||||
|
||||
// Set the value for the latest tde migration
|
||||
public setTdeMigrationResult(result: TdeMigrationResult): void {
|
||||
this._tdeMigrationResult = result;
|
||||
this._tdeMigrationCompleted = result.state === TdeMigrationState.Succeeded;
|
||||
}
|
||||
|
||||
// Reset last tde migration result
|
||||
public resetTdeMigrationResult() {
|
||||
this._tdeMigrationResult = {
|
||||
state: TdeMigrationState.Pending,
|
||||
dbList: []
|
||||
};
|
||||
}
|
||||
|
||||
// When the confirmation is set, for ADS certificate migration method
|
||||
public setAdsConfirmation(status: boolean, networkPath: string): void {
|
||||
if (status && this.isTdeMigrationMethodAds()) {
|
||||
this._adsExportConfirmation = true;
|
||||
|
||||
this._networkPath = networkPath;
|
||||
} else {
|
||||
this._adsExportConfirmation = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user