mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Added validations to configure dialog (#24418)
* Added validations to configure dialog * Improved validations messages text * Addressed PR feedback * Addressed PR feedback * Fixed build issue * Version bump * Changed to single quotes
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/{#version#}/microsoft.sqltools.migration-{#fileName#}",
|
"downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/{#version#}/microsoft.sqltools.migration-{#fileName#}",
|
||||||
"useDefaultLinuxRuntime": true,
|
"useDefaultLinuxRuntime": true,
|
||||||
"version": "4.7.0.13",
|
"version": "4.10.0.3",
|
||||||
"downloadFileNames": {
|
"downloadFileNames": {
|
||||||
"Windows_86": "win-x86-net7.0.zip",
|
"Windows_86": "win-x86-net7.0.zip",
|
||||||
"Windows": "win-x64-net7.0.zip",
|
"Windows": "win-x64-net7.0.zip",
|
||||||
|
|||||||
@@ -1516,8 +1516,18 @@ export const TDE_WIZARD_MSG_MANUAL = localize('sql.migration.tde.msg.manual', "Y
|
|||||||
export const TDE_WIZARD_MSG_TDE = localize('sql.migration.tde.msg.tde', "You have given Azure Data Studio access to migrate the encryption certificates and database.");
|
export const TDE_WIZARD_MSG_TDE = localize('sql.migration.tde.msg.tde', "You have given Azure Data Studio access to migrate the encryption certificates and database.");
|
||||||
export const TDE_WIZARD_MSG_EMPTY = localize('sql.migration.tde.msg.empty', "No encrypted database selected.");
|
export const TDE_WIZARD_MSG_EMPTY = localize('sql.migration.tde.msg.empty', "No encrypted database selected.");
|
||||||
|
|
||||||
|
export const TDE_VALIDATION_TITLE = localize('sql.migration.tde.validation.title', "Validation");
|
||||||
|
export const TDE_VALIDATION_REQUIREMENTS_MESSAGE = localize('sql.migration.tde.validation.requirements.message', "In order for certificate migration to succeed, you must meet all of the requirements listed below.\n\nClick \"Run validation\" to check that requirements are met.");
|
||||||
|
export const TDE_VALIDATION_STATUS_PENDING = localize('sql.migration.tde.validation.status.pending', "Pending");
|
||||||
|
export const TDE_VALIDATION_STATUS_RUNNING = localize('sql.migration.tde.validation.running', "Running");
|
||||||
|
export const TDE_VALIDATION_STATUS_SUCCEEDED = localize('sql.migration.tde.validation.status.succeeded', "Succeeded");
|
||||||
|
export const TDE_VALIDATION_STATUS_RUN_VALIDATION = localize('sql.migration.tde.validation.run.validation', "Run validation");
|
||||||
|
export const TDE_VALIDATION_DESCRIPTION = localize('sql.migration.tde.validation.description', "Description");
|
||||||
|
export const TDE_VALIDATION_ERROR = localize('sql.migration.tde.validation.error', "Error");
|
||||||
|
export const TDE_VALIDATION_TROUBLESHOOTING_TIPS = localize('sql.migration.tde.validation.troubleshooting.tips', "Troubleshooting tips");
|
||||||
|
|
||||||
export function TDE_MIGRATION_ERROR(message: string): string {
|
export function TDE_MIGRATION_ERROR(message: string): string {
|
||||||
return localize('sql.migration.starting.migration.error', "An error occurred while starting the certificate migration: '{0}'", message);
|
return localize('sql.migration.starting.migration.error', "The following error has occurred while starting the certificate migration: '{0}'", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TDE_MIGRATION_ERROR_DB(name: string, message: string): string {
|
export function TDE_MIGRATION_ERROR_DB(name: string, message: string): string {
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ import { MigrationStateModel } from '../../models/stateMachine';
|
|||||||
import * as constants from '../../constants/strings';
|
import * as constants from '../../constants/strings';
|
||||||
import * as styles from '../../constants/styles';
|
import * as styles from '../../constants/styles';
|
||||||
import * as utils from '../../api/utils';
|
import * as utils from '../../api/utils';
|
||||||
|
import { EOL } from 'os';
|
||||||
import { ConfigDialogSetting } from '../../models/tdeModels'
|
import { ConfigDialogSetting } from '../../models/tdeModels'
|
||||||
|
import { IconPathHelper } from '../../constants/iconPathHelper';
|
||||||
|
|
||||||
export class TdeConfigurationDialog {
|
export class TdeConfigurationDialog {
|
||||||
|
|
||||||
@@ -22,8 +24,12 @@ export class TdeConfigurationDialog {
|
|||||||
private _adsConfirmationCheckBox!: azdata.CheckBoxComponent;
|
private _adsConfirmationCheckBox!: azdata.CheckBoxComponent;
|
||||||
private _manualMethodWarningContainer!: azdata.FlexContainer;
|
private _manualMethodWarningContainer!: azdata.FlexContainer;
|
||||||
private _networkPathText!: azdata.InputBoxComponent;
|
private _networkPathText!: azdata.InputBoxComponent;
|
||||||
|
private _validationTable!: azdata.TableComponent;
|
||||||
|
private _validationMessagesText!: azdata.InputBoxComponent;
|
||||||
private _onClosed: () => void;
|
private _onClosed: () => void;
|
||||||
|
|
||||||
|
private _validationSuccessDescriptionErrorAndTips!: string[][];
|
||||||
|
|
||||||
constructor(public migrationStateModel: MigrationStateModel, onClosed: () => void) {
|
constructor(public migrationStateModel: MigrationStateModel, onClosed: () => void) {
|
||||||
this._onClosed = onClosed;
|
this._onClosed = onClosed;
|
||||||
}
|
}
|
||||||
@@ -130,6 +136,24 @@ export class TdeConfigurationDialog {
|
|||||||
adsMethodButton.onDidChangeCheckedState(async checked => {
|
adsMethodButton.onDidChangeCheckedState(async checked => {
|
||||||
if (checked) {
|
if (checked) {
|
||||||
this.migrationStateModel.tdeMigrationConfig.setPendingTdeMigrationMethod(ConfigDialogSetting.ExportCertificates);
|
this.migrationStateModel.tdeMigrationConfig.setPendingTdeMigrationMethod(ConfigDialogSetting.ExportCertificates);
|
||||||
|
let validationTitleData = await this.migrationStateModel.getTdeValidationTitles();
|
||||||
|
|
||||||
|
let networkPathValidated =
|
||||||
|
(this.migrationStateModel.tdeMigrationConfig.getPendingNetworkPath() !== '') &&
|
||||||
|
(this.migrationStateModel.tdeMigrationConfig.getPendingNetworkPath() === this.migrationStateModel.tdeMigrationConfig.getLastValidatedNetworkPath())
|
||||||
|
|
||||||
|
let result = validationTitleData.result.map(validationTitle => {
|
||||||
|
return [
|
||||||
|
validationTitle,
|
||||||
|
{
|
||||||
|
'icon': networkPathValidated ? IconPathHelper.completedMigration : IconPathHelper.notFound,
|
||||||
|
'title': networkPathValidated ? constants.TDE_VALIDATION_STATUS_SUCCEEDED : constants.TDE_VALIDATION_STATUS_PENDING
|
||||||
|
},
|
||||||
|
networkPathValidated ? constants.TDE_VALIDATION_STATUS_SUCCEEDED : constants.TDE_VALIDATION_STATUS_PENDING
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
await this._validationTable.updateProperty('data', result)
|
||||||
await this.updateUI();
|
await this.updateUI();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
@@ -228,6 +252,7 @@ export class TdeConfigurationDialog {
|
|||||||
this._disposables.push(
|
this._disposables.push(
|
||||||
this._networkPathText.onTextChanged(async networkPath => {
|
this._networkPathText.onTextChanged(async networkPath => {
|
||||||
this.migrationStateModel.tdeMigrationConfig.setPendingNetworkPath(networkPath);
|
this.migrationStateModel.tdeMigrationConfig.setPendingNetworkPath(networkPath);
|
||||||
|
await this.updateUI();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._adsConfirmationCheckBox = _view.modelBuilder.checkBox()
|
this._adsConfirmationCheckBox = _view.modelBuilder.checkBox()
|
||||||
@@ -245,15 +270,172 @@ export class TdeConfigurationDialog {
|
|||||||
await this.updateUI();
|
await this.updateUI();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const preValidationSeparator = _view.modelBuilder.separator().component();
|
||||||
|
|
||||||
|
const validationRequiredLabel = _view.modelBuilder.text()
|
||||||
|
.withProps({
|
||||||
|
value: constants.TDE_VALIDATION_REQUIREMENTS_MESSAGE,
|
||||||
|
CSSStyles: {
|
||||||
|
...styles.BODY_CSS,
|
||||||
|
'margin': '4px 2px 4px 2px'
|
||||||
|
}
|
||||||
|
}).component();
|
||||||
|
|
||||||
|
const runValidationButton = _view.modelBuilder.button()
|
||||||
|
.withProps(
|
||||||
|
{
|
||||||
|
label: constants.TDE_VALIDATION_STATUS_RUN_VALIDATION,
|
||||||
|
enabled: true
|
||||||
|
}).component();
|
||||||
|
|
||||||
|
this._disposables.push(
|
||||||
|
runValidationButton.onDidClick(async (e) => {
|
||||||
|
let data = this._validationTable.data.map((e) => {
|
||||||
|
return [
|
||||||
|
e[0],
|
||||||
|
{
|
||||||
|
'icon': IconPathHelper.inProgressMigration,
|
||||||
|
'title': constants.TDE_VALIDATION_STATUS_RUNNING
|
||||||
|
},
|
||||||
|
constants.TDE_VALIDATION_STATUS_RUNNING
|
||||||
|
]
|
||||||
|
});
|
||||||
|
await this._validationTable.updateProperty('data', data);
|
||||||
|
|
||||||
|
let validationData = await this.migrationStateModel.runTdeValidation(
|
||||||
|
this.migrationStateModel.tdeMigrationConfig.getPendingNetworkPath());
|
||||||
|
|
||||||
|
let allValidationsSucceeded = true;
|
||||||
|
|
||||||
|
this._validationSuccessDescriptionErrorAndTips = validationData.result.map(e => {
|
||||||
|
return [
|
||||||
|
e.validationStatus.toString(),
|
||||||
|
e.validationDescription,
|
||||||
|
e.validationErrorMessage,
|
||||||
|
e.validationTroubleshootingTips
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
let res = validationData.result.map(e => {
|
||||||
|
if (e.validationStatus < 0) {
|
||||||
|
allValidationsSucceeded = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
e.validationTitle,
|
||||||
|
{
|
||||||
|
'icon': e.validationStatus > 0 ? IconPathHelper.completedMigration : IconPathHelper.error,
|
||||||
|
'title': e.validationStatusString
|
||||||
|
},
|
||||||
|
e.validationStatusString
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
await this._validationTable.updateProperty('data', res);
|
||||||
|
|
||||||
|
if (allValidationsSucceeded) {
|
||||||
|
this.migrationStateModel.tdeMigrationConfig.setLastValidatedNetworkPath(
|
||||||
|
this.migrationStateModel.tdeMigrationConfig.getPendingNetworkPath());
|
||||||
|
await this.updateUI();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._validationTable = this._createValidationTable(_view);
|
||||||
|
|
||||||
|
this._disposables.push(
|
||||||
|
this._validationTable.onRowSelected(
|
||||||
|
async (e) => {
|
||||||
|
const selectedRows: number[] = this._validationTable.selectedRows ?? [];
|
||||||
|
|
||||||
|
let message: string = '';
|
||||||
|
selectedRows.forEach((rowIndex) => {
|
||||||
|
|
||||||
|
let successful = this._validationSuccessDescriptionErrorAndTips[rowIndex][0] === "1" // Value will be "1" if successful
|
||||||
|
let description = this._validationSuccessDescriptionErrorAndTips[rowIndex][1];
|
||||||
|
let errorMessage = this._validationSuccessDescriptionErrorAndTips[rowIndex][2];
|
||||||
|
let tips = this._validationSuccessDescriptionErrorAndTips[rowIndex][3];
|
||||||
|
|
||||||
|
message = `${constants.TDE_VALIDATION_DESCRIPTION}:${EOL}${description}`;
|
||||||
|
if (!successful) {
|
||||||
|
message += `${EOL}${EOL}`;
|
||||||
|
if (errorMessage?.length > 0) {
|
||||||
|
message += `${constants.TDE_VALIDATION_ERROR}:${EOL}${errorMessage}${EOL}${EOL}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
message += `${constants.TDE_VALIDATION_TROUBLESHOOTING_TIPS}:${EOL}${tips}`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this._validationMessagesText.value = message;
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._validationMessagesText = _view.modelBuilder.inputBox()
|
||||||
|
.withProps({
|
||||||
|
inputType: 'text',
|
||||||
|
height: 142,
|
||||||
|
multiline: true,
|
||||||
|
CSSStyles: { 'overflow': 'none auto' }
|
||||||
|
})
|
||||||
|
.component();
|
||||||
|
|
||||||
|
const postValidationSeparator = _view.modelBuilder.separator().component();
|
||||||
|
|
||||||
container.addItems([
|
container.addItems([
|
||||||
adsMethodInfoMessage,
|
adsMethodInfoMessage,
|
||||||
networkPathLabel,
|
networkPathLabel,
|
||||||
this._networkPathText,
|
this._networkPathText,
|
||||||
this._adsConfirmationCheckBox]);
|
this._adsConfirmationCheckBox,
|
||||||
|
preValidationSeparator,
|
||||||
|
validationRequiredLabel,
|
||||||
|
runValidationButton,
|
||||||
|
this._validationTable,
|
||||||
|
this._validationMessagesText,
|
||||||
|
postValidationSeparator
|
||||||
|
]);
|
||||||
|
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _createValidationTable(view: azdata.ModelView): azdata.TableComponent {
|
||||||
|
return view.modelBuilder.table()
|
||||||
|
.withProps({
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
value: 'title',
|
||||||
|
name: constants.TDE_VALIDATION_TITLE,
|
||||||
|
type: azdata.ColumnType.text,
|
||||||
|
width: 320,
|
||||||
|
headerCssClass: 'no-borders',
|
||||||
|
cssClass: 'no-borders align-with-header',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'image',
|
||||||
|
name: '',
|
||||||
|
type: azdata.ColumnType.icon,
|
||||||
|
width: 30,
|
||||||
|
headerCssClass: 'no-borders display-none',
|
||||||
|
cssClass: 'no-borders align-with-header',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'message',
|
||||||
|
name: constants.TDE_MIGRATE_COLUMN_STATUS,
|
||||||
|
type: azdata.ColumnType.text,
|
||||||
|
width: 100,
|
||||||
|
headerCssClass: 'no-borders',
|
||||||
|
cssClass: 'no-borders align-with-header',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
data: [],
|
||||||
|
width: 450,
|
||||||
|
height: 80,
|
||||||
|
CSSStyles: {
|
||||||
|
'margin-top': '10px',
|
||||||
|
'margin-bottom': '10px',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.component();
|
||||||
|
}
|
||||||
|
|
||||||
private createManualWarningContainer(_view: azdata.ModelView): azdata.FlexContainer {
|
private createManualWarningContainer(_view: azdata.ModelView): azdata.FlexContainer {
|
||||||
const container = _view.modelBuilder.flexContainer().withProps({
|
const container = _view.modelBuilder.flexContainer().withProps({
|
||||||
CSSStyles: {
|
CSSStyles: {
|
||||||
@@ -293,7 +475,7 @@ export class TdeConfigurationDialog {
|
|||||||
await utils.updateControlDisplay(this._adsMethodConfirmationContainer, exportCertsUsingAds);
|
await utils.updateControlDisplay(this._adsMethodConfirmationContainer, exportCertsUsingAds);
|
||||||
await utils.updateControlDisplay(this._manualMethodWarningContainer, this.migrationStateModel.tdeMigrationConfig.getPendingConfigDialogSetting() === ConfigDialogSetting.DoNotExport);
|
await utils.updateControlDisplay(this._manualMethodWarningContainer, this.migrationStateModel.tdeMigrationConfig.getPendingConfigDialogSetting() === ConfigDialogSetting.DoNotExport);
|
||||||
|
|
||||||
this.dialog!.okButton.enabled = this.migrationStateModel.tdeMigrationConfig.isAnyChangeReadyToBeApplied()
|
this.dialog!.okButton.enabled = this.migrationStateModel.tdeMigrationConfig.isAnyChangeReadyToBeApplied();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async openDialog(dialogName?: string,) {
|
public async openDialog(dialogName?: string,) {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { hashString, deepClone, getBlobContainerNameWithFolder, Blob, getLastBac
|
|||||||
import { SKURecommendationPage } from '../wizard/skuRecommendationPage';
|
import { SKURecommendationPage } from '../wizard/skuRecommendationPage';
|
||||||
import { excludeDatabases, getEncryptConnectionValue, getSourceConnectionId, getSourceConnectionProfile, getSourceConnectionServerInfo, getSourceConnectionString, getSourceConnectionUri, getTrustServerCertificateValue, SourceDatabaseInfo, TargetDatabaseInfo } from '../api/sqlUtils';
|
import { excludeDatabases, getEncryptConnectionValue, getSourceConnectionId, getSourceConnectionProfile, getSourceConnectionServerInfo, getSourceConnectionString, getSourceConnectionUri, getTrustServerCertificateValue, SourceDatabaseInfo, TargetDatabaseInfo } from '../api/sqlUtils';
|
||||||
import { LoginMigrationModel } from './loginMigrationModel';
|
import { LoginMigrationModel } from './loginMigrationModel';
|
||||||
import { TdeMigrationDbResult, TdeMigrationModel } from './tdeModels';
|
import { TdeMigrationDbResult, TdeMigrationModel, TdeValidationResult } from './tdeModels';
|
||||||
import { NetworkInterfaceModel } from '../api/dataModels/azure/networkInterfaceModel';
|
import { NetworkInterfaceModel } from '../api/dataModels/azure/networkInterfaceModel';
|
||||||
const localize = nls.loadMessageBundle();
|
const localize = nls.loadMessageBundle();
|
||||||
|
|
||||||
@@ -1000,6 +1000,55 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
|||||||
return opResult;
|
return opResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async getTdeValidationTitles(): Promise<OperationResult<string[]>> {
|
||||||
|
const opResult: OperationResult<string[]> = {
|
||||||
|
success: false,
|
||||||
|
result: [],
|
||||||
|
errors: []
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
opResult.result = await this.migrationService.getTdeValidationTitles() ?? [];
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return opResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async runTdeValidation(networkSharePath: string): Promise<OperationResult<TdeValidationResult[]>> {
|
||||||
|
const opResult: OperationResult<TdeValidationResult[]> = {
|
||||||
|
success: false,
|
||||||
|
result: [],
|
||||||
|
errors: []
|
||||||
|
};
|
||||||
|
|
||||||
|
const connectionString = await getSourceConnectionString();
|
||||||
|
|
||||||
|
try {
|
||||||
|
let tdeValidationResult = await this.migrationService.runTdeValidation(
|
||||||
|
connectionString,
|
||||||
|
networkSharePath);
|
||||||
|
|
||||||
|
if (tdeValidationResult !== undefined) {
|
||||||
|
opResult.result = tdeValidationResult?.map((e) => {
|
||||||
|
return {
|
||||||
|
validationTitle: e.validationTitle,
|
||||||
|
validationDescription: e.validationDescription,
|
||||||
|
validationTroubleshootingTips: e.validationTroubleshootingTips,
|
||||||
|
validationErrorMessage: e.validationErrorMessage,
|
||||||
|
validationStatus: e.validationStatus,
|
||||||
|
validationStatusString: e.validationStatusString
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return opResult;
|
||||||
|
}
|
||||||
|
|
||||||
public async startMigration() {
|
public async startMigration() {
|
||||||
const currentConnection = await getSourceConnectionProfile();
|
const currentConnection = await getSourceConnectionProfile();
|
||||||
const isOfflineMigration = this._databaseBackup.migrationMode === MigrationMode.OFFLINE;
|
const isOfflineMigration = this._databaseBackup.migrationMode === MigrationMode.OFFLINE;
|
||||||
|
|||||||
@@ -41,6 +41,15 @@ export interface TdeMigrationDbResult {
|
|||||||
message: string;
|
message: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TdeValidationResult {
|
||||||
|
validationTitle: string;
|
||||||
|
validationDescription: string;
|
||||||
|
validationTroubleshootingTips: string;
|
||||||
|
validationErrorMessage: string;
|
||||||
|
validationStatus: number;
|
||||||
|
validationStatusString: string;
|
||||||
|
}
|
||||||
|
|
||||||
export class TdeMigrationModel {
|
export class TdeMigrationModel {
|
||||||
|
|
||||||
// Settings for which the user has clicked the apply button
|
// Settings for which the user has clicked the apply button
|
||||||
@@ -53,6 +62,9 @@ export class TdeMigrationModel {
|
|||||||
private _pendingExportCertUserConsent: boolean;
|
private _pendingExportCertUserConsent: boolean;
|
||||||
private _pendingNetworkPath: string;
|
private _pendingNetworkPath: string;
|
||||||
|
|
||||||
|
// Last network path for which all validations succeeded
|
||||||
|
private _lastValidatedNetworkPath: string;
|
||||||
|
|
||||||
private _configurationCompleted: boolean;
|
private _configurationCompleted: boolean;
|
||||||
private _shownBefore: boolean;
|
private _shownBefore: boolean;
|
||||||
private _encryptedDbs: string[];
|
private _encryptedDbs: string[];
|
||||||
@@ -75,6 +87,7 @@ export class TdeMigrationModel {
|
|||||||
this._appliedExportCertUserConsent = false;
|
this._appliedExportCertUserConsent = false;
|
||||||
this._pendingExportCertUserConsent = false;
|
this._pendingExportCertUserConsent = false;
|
||||||
this._tdeMigrationCompleted = false;
|
this._tdeMigrationCompleted = false;
|
||||||
|
this._lastValidatedNetworkPath = '';
|
||||||
|
|
||||||
this._tdeMigrationCompleted = this._tdeMigrationCompleted;
|
this._tdeMigrationCompleted = this._tdeMigrationCompleted;
|
||||||
}
|
}
|
||||||
@@ -176,7 +189,12 @@ export class TdeMigrationModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this._pendingConfigDialogSetting === ConfigDialogSetting.ExportCertificates) {
|
if (this._pendingConfigDialogSetting === ConfigDialogSetting.ExportCertificates) {
|
||||||
return this._pendingExportCertUserConsent;
|
if (this._pendingNetworkPath !== this._lastValidatedNetworkPath) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._pendingNetworkPath.length > 0 &&
|
||||||
|
this._pendingExportCertUserConsent;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -213,4 +231,12 @@ export class TdeMigrationModel {
|
|||||||
public setPendingExportCertUserConsent(pendingExportCertUserConsent: boolean) {
|
public setPendingExportCertUserConsent(pendingExportCertUserConsent: boolean) {
|
||||||
this._pendingExportCertUserConsent = pendingExportCertUserConsent;
|
this._pendingExportCertUserConsent = pendingExportCertUserConsent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public setLastValidatedNetworkPath(validatedNetworkPath: string) {
|
||||||
|
this._lastValidatedNetworkPath = validatedNetworkPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getLastValidatedNetworkPath() {
|
||||||
|
return this._lastValidatedNetworkPath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -388,6 +388,11 @@ export const enum VirtualMachineFamily {
|
|||||||
standardNVSv4Family
|
standardNVSv4Family
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const enum TdeValidationStatus {
|
||||||
|
Failed = -1,
|
||||||
|
Succeeded = 1
|
||||||
|
}
|
||||||
|
|
||||||
export namespace GetSqlMigrationSkuRecommendationsRequest {
|
export namespace GetSqlMigrationSkuRecommendationsRequest {
|
||||||
export const type = new RequestType<SqlMigrationSkuRecommendationsParams, SkuRecommendationResult, void, void>('migration/getskurecommendations');
|
export const type = new RequestType<SqlMigrationSkuRecommendationsParams, SkuRecommendationResult, void, void>('migration/getskurecommendations');
|
||||||
}
|
}
|
||||||
@@ -549,3 +554,25 @@ export interface TdeMigrateProgressParams {
|
|||||||
message: string;
|
message: string;
|
||||||
statusCode: string;
|
statusCode: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TdeValidationResult {
|
||||||
|
validationTitle: string;
|
||||||
|
validationDescription: string;
|
||||||
|
validationTroubleshootingTips: string;
|
||||||
|
validationErrorMessage: string;
|
||||||
|
validationStatus: TdeValidationStatus;
|
||||||
|
validationStatusString: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TdeValidationParams {
|
||||||
|
sourceSqlConnectionString: string;
|
||||||
|
networkSharePath: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace TdeValidationRequest {
|
||||||
|
export const type = new RequestType<TdeValidationParams, TdeValidationResult[], void, void>('migration/tdevalidation');
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace TdeValidationTitlesRequest {
|
||||||
|
export const type = new RequestType<{}, string[], void, void>('migration/tdevalidationtitles');
|
||||||
|
}
|
||||||
|
|||||||
@@ -316,5 +316,34 @@ export class SqlMigrationService extends MigrationExtensionService implements co
|
|||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
async runTdeValidation(
|
||||||
|
sourceSqlConnectionString: string,
|
||||||
|
networkSharePath: string,
|
||||||
|
) {
|
||||||
|
let params: contracts.TdeValidationParams = {
|
||||||
|
sourceSqlConnectionString: sourceSqlConnectionString,
|
||||||
|
networkSharePath: networkSharePath,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
return await this._client.sendRequest(contracts.TdeValidationRequest.type, params);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
this._client.logFailedRequest(contracts.TdeValidationRequest.type, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getTdeValidationTitles() {
|
||||||
|
try {
|
||||||
|
return await this._client.sendRequest(contracts.TdeValidationTitlesRequest.type, {});
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
this._client.logFailedRequest(contracts.TdeValidationRequest.type, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user