From ce5cb320842e542071ee2dd602b1ac6d1f1560bb Mon Sep 17 00:00:00 2001 From: junierch <109680247+junierch@users.noreply.github.com> Date: Fri, 13 Jan 2023 17:41:40 -0500 Subject: [PATCH] tde-mi contracts (#21592) * tde-mi contracts * PR reviews updates --- extensions/mssql/src/constants.ts | 1 + extensions/mssql/src/contracts.ts | 32 ++++++++ extensions/mssql/src/mssql.d.ts | 34 ++++++++ extensions/mssql/src/mssqlApiFactory.ts | 5 +- extensions/mssql/src/sqlToolsServer.ts | 4 +- .../src/tdeMigration/tdeMigrationService.ts | 78 +++++++++++++++++++ 6 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 extensions/mssql/src/tdeMigration/tdeMigrationService.ts diff --git a/extensions/mssql/src/constants.ts b/extensions/mssql/src/constants.ts index 3e56ae9b28..55ab596cb8 100644 --- a/extensions/mssql/src/constants.ts +++ b/extensions/mssql/src/constants.ts @@ -22,3 +22,4 @@ export const SqlAssessmentService = 'sqlAssessmentService'; export const SqlMigrationService = 'sqlMigrationService'; export const NotebookConvertService = 'notebookConvertService'; export const AzureBlobService = 'azureBlobService'; +export const TdeMigrationService = 'tdeMigrationService'; diff --git a/extensions/mssql/src/contracts.ts b/extensions/mssql/src/contracts.ts index eb8c952b80..cafc603340 100644 --- a/extensions/mssql/src/contracts.ts +++ b/extensions/mssql/src/contracts.ts @@ -1250,3 +1250,35 @@ export namespace ExecutionPlanComparisonRequest { } // ------------------------------- < Execution Plan > ------------------------------------ + +// ------------------------------- < Tde Migration > ------------------------------------ + +export namespace TdeMigrateRequest { + export const type = new RequestType('migration/tdemigration'); +} + +export interface TdeMigrationParams { + encryptedDatabases: string[]; + sourceSqlConnectionString: string; + targetSubscriptionId: string; + targetResourceGroupName: string; + targetManagedInstanceName: string; + networkSharePath: string; + networkShareDomain: string; + networkShareUserName: string; + networkSharePassword: string; + accessToken: string; +} + +export namespace TdeMigrateProgressEvent { + export const type = new NotificationType('migration/tdemigrationprogress'); +} + + +export interface TdeMigrateProgressParams { + name: string; + success: boolean; + message: string; +} + +// ------------------------------- < Tde Migration > ------------------------------------ diff --git a/extensions/mssql/src/mssql.d.ts b/extensions/mssql/src/mssql.d.ts index e76a57dfb3..76c13d4856 100644 --- a/extensions/mssql/src/mssql.d.ts +++ b/extensions/mssql/src/mssql.d.ts @@ -45,6 +45,8 @@ declare module 'mssql' { readonly sqlMigration: ISqlMigrationService; readonly azureBlob: IAzureBlobService; + + readonly tdeMigration: ITdeMigrationService; } /** @@ -831,4 +833,36 @@ declare module 'mssql' { completedStep: LoginMigrationStep; elapsedTime: string; } + + // TDEMigration interfaces BEGIN ----------------------------------------------------------------------- + export interface TdeMigrationRequest { + encryptedDatabases: string[]; + sourceSqlConnectionString: string; + targetSubscriptionId: string; + targetResourceGroupName: string; + targetManagedInstanceName: string; + } + + export interface TdeMigrationEntryResult { + dbName: string; + success: boolean; + message: string; + } + + export interface TdeMigrationResult { + migrationStatuses: TdeMigrationEntryResult[]; + } + + export interface ITdeMigrationService { + migrateCertificate( + encryptedDatabases: string[], + sourceSqlConnectionString: string, + targetSubscriptionId: string, + targetResourceGroupName: string, + targetManagedInstanceName: string, + networkSharePath: string, + accessToken: string, + reportUpdate: (dbName: string, succeeded: boolean, message: string) => void): Promise; + } + // TDEMigration interfaces END ----------------------------------------------------------------------- } diff --git a/extensions/mssql/src/mssqlApiFactory.ts b/extensions/mssql/src/mssqlApiFactory.ts index f2038ebb68..ad678e85ab 100644 --- a/extensions/mssql/src/mssqlApiFactory.ts +++ b/extensions/mssql/src/mssqlApiFactory.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { AppContext } from './appContext'; -import { IExtension, ICmsService, IDacFxService, ISchemaCompareService, ILanguageExtensionService, ISqlAssessmentService, ISqlMigrationService, IAzureBlobService } from 'mssql'; +import { IExtension, ICmsService, IDacFxService, ISchemaCompareService, ILanguageExtensionService, ISqlAssessmentService, ISqlMigrationService, IAzureBlobService, ITdeMigrationService } from 'mssql'; import * as constants from './constants'; import { SqlToolsServer } from './sqlToolsServer'; @@ -33,6 +33,9 @@ export function createMssqlApi(context: AppContext, sqlToolsServer: SqlToolsServ }, get azureBlob() { return context.getService(constants.AzureBlobService); + }, + get tdeMigration() { + return context.getService(constants.TdeMigrationService); } }; } diff --git a/extensions/mssql/src/sqlToolsServer.ts b/extensions/mssql/src/sqlToolsServer.ts index 07c9dd274a..31b280993a 100644 --- a/extensions/mssql/src/sqlToolsServer.ts +++ b/extensions/mssql/src/sqlToolsServer.ts @@ -27,6 +27,7 @@ import { NotebookConvertService } from './notebookConvert/notebookConvertService import { SqlMigrationService } from './sqlMigration/sqlMigrationService'; import { SqlCredentialService } from './credentialstore/sqlCredentialService'; import { AzureBlobService } from './azureBlob/azureBlobService'; +import { TdeMigrationService } from './tdeMigration/tdeMigrationService'; const localize = nls.loadMessageBundle(); const outputChannel = vscode.window.createOutputChannel(Constants.serviceName); @@ -192,7 +193,8 @@ function getClientOptions(context: AppContext): ClientOptions { SqlMigrationService.asFeature(context), SqlCredentialService.asFeature(context), TableDesignerFeature, - ExecutionPlanServiceFeature + ExecutionPlanServiceFeature, + TdeMigrationService.asFeature(context), ], outputChannel: new CustomOutputChannel() }; diff --git a/extensions/mssql/src/tdeMigration/tdeMigrationService.ts b/extensions/mssql/src/tdeMigration/tdeMigrationService.ts new file mode 100644 index 0000000000..34ab51dd1f --- /dev/null +++ b/extensions/mssql/src/tdeMigration/tdeMigrationService.ts @@ -0,0 +1,78 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as mssql from 'mssql'; +import { AppContext } from '../appContext'; +import { SqlOpsDataClient, ISqlOpsFeature } from 'dataprotocol-client'; +import { ClientCapabilities } from 'vscode-languageclient'; +import * as constants from '../constants'; +import * as contracts from '../contracts'; + +export class TdeMigrationService implements mssql.ITdeMigrationService { + private _reportUpdate: (dbName: string, succeeded: boolean, error: string) => void = undefined; + + public static asFeature(context: AppContext): ISqlOpsFeature { + return class extends TdeMigrationService { + constructor(client: SqlOpsDataClient) { + super(context, client); + } + + fillClientCapabilities(capabilities: ClientCapabilities): void { + } + + initialize(): void { + this.client.onNotification(contracts.TdeMigrateProgressEvent.type, e => { + if (this._reportUpdate === undefined) { + return; + } + this._reportUpdate(e.name, e.success, e.message); + }); + } + }; + } + + private constructor(context: AppContext, protected readonly client: SqlOpsDataClient) { + context.registerService(constants.TdeMigrationService, this); + } + + async migrateCertificate( + tdeEnabledDatabases: string[], + sourceSqlConnectionString: string, + targetSubscriptionId: string, + targetResourceGroupName: string, + targetManagedInstanceName: string, + networkSharePath: string, + accessToken: string, + reportUpdate: (dbName: string, succeeded: boolean, message: string) => void): Promise { + + this._reportUpdate = reportUpdate; + let params: contracts.TdeMigrationParams = { + encryptedDatabases: tdeEnabledDatabases, + sourceSqlConnectionString: sourceSqlConnectionString, + targetSubscriptionId: targetSubscriptionId, + targetResourceGroupName: targetResourceGroupName, + targetManagedInstanceName: targetManagedInstanceName, + networkSharePath: networkSharePath, + networkShareDomain: 'a', // Will remove this on the next STS version + networkShareUserName: 'b', + networkSharePassword: 'c', + accessToken: accessToken + }; + + try { + // This call needs to be awaited so, the updates are sent during the execution of the task. + // If the task is not await, the finally block will execute and no update will be sent. + const result = await this.client.sendRequest(contracts.TdeMigrateRequest.type, params); + return result; + } + catch (e) { + this.client.logFailedRequest(contracts.TdeMigrateRequest.type, e); + } finally { + this._reportUpdate = undefined; + } + + return undefined; + } +}