diff --git a/extensions/sql-migration/src/constants/strings.ts b/extensions/sql-migration/src/constants/strings.ts index bb3b971329..95cc07f7c3 100644 --- a/extensions/sql-migration/src/constants/strings.ts +++ b/extensions/sql-migration/src/constants/strings.ts @@ -796,6 +796,8 @@ export function VALIDATE_IR_VALIDATION_STATUS(state: string | undefined, errors? } } +export const VALIDATE_IR_ERROR_GATEWAY_TIMEOUT = localize('sql.migration.validate.error.gatewaytimeout', "A time-out was encountered while validating a resource connection. Learn more: https://aka.ms/dms-migrations-troubleshooting."); + export function VALIDATE_IR_VALIDATION_STATUS_ERROR_COUNT(state: string | undefined, errorCount: number): string { const status = state ?? ''; return errorCount > 1 diff --git a/extensions/sql-migration/src/dialog/validationResults/validateIrDialog.ts b/extensions/sql-migration/src/dialog/validationResults/validateIrDialog.ts index 2e41152e39..126400f71d 100644 --- a/extensions/sql-migration/src/dialog/validationResults/validateIrDialog.ts +++ b/extensions/sql-migration/src/dialog/validationResults/validateIrDialog.ts @@ -11,9 +11,18 @@ import { MigrationStateModel, MigrationTargetType, NetworkShare, ValidateIrState import { EOL } from 'os'; import { IconPathHelper } from '../../constants/iconPathHelper'; import { getEncryptConnectionValue, getSourceConnectionProfile, getTrustServerCertificateValue } from '../../api/sqlUtils'; +import { logError, TelemetryViews } from '../../telemetry'; const DialogName = 'ValidateIrDialog'; +enum HttpStatusCodes { + GatewayTimeout = "504\r\n", +} + +enum HttpStatusExceptionCodes { + ConnectionTimeoutError = "ConnectionTimeoutError", +} + enum ValidationResultIndex { message = 0, icon = 1, @@ -405,10 +414,12 @@ export class ValidateIrDialog { return true; } } catch (error) { + const err = this._formatError(error); + logError(TelemetryViews.ValidIrDialog, err.message, error); await this._updateValidateIrResults( testNumber, ValidateIrState.Failed, - [constants.VALIDATE_IR_VALIDATION_RESULT_API_ERROR(sourceDatabase, error)]); + [constants.VALIDATE_IR_VALIDATION_RESULT_API_ERROR(sourceDatabase, err)]); } return false; }; @@ -447,6 +458,16 @@ export class ValidateIrDialog { } } + private _formatError(error: Error): Error { + if (error?.message?.startsWith(HttpStatusCodes.GatewayTimeout)) { + return { + name: HttpStatusExceptionCodes.ConnectionTimeoutError, + message: constants.VALIDATE_IR_ERROR_GATEWAY_TIMEOUT, + }; + } + return error; + } + private async _validateSqlDbMigration(): Promise { const currentConnection = await getSourceConnectionProfile(); const sourceServerName = currentConnection?.serverName!; @@ -464,8 +485,8 @@ export class ValidateIrDialog { testSourceConnectivity: boolean, testTargetConnectivity: boolean): Promise => { - await this._updateValidateIrResults(testNumber, ValidateIrState.Running); try { + await this._updateValidateIrResults(testNumber, ValidateIrState.Running); const response = await validateIrSqlDatabaseMigrationSettings( this._model, sourceServerName, @@ -488,10 +509,12 @@ export class ValidateIrDialog { return true; } } catch (error) { + const err = this._formatError(error); + logError(TelemetryViews.ValidIrDialog, err.message, error); await this._updateValidateIrResults( testNumber, ValidateIrState.Failed, - [constants.VALIDATE_IR_VALIDATION_RESULT_API_ERROR(sourceDatabase, error)]); + [constants.VALIDATE_IR_VALIDATION_RESULT_API_ERROR(sourceDatabase, err)]); } return false; }; diff --git a/extensions/sql-migration/src/telemetry.ts b/extensions/sql-migration/src/telemetry.ts index 41829136f5..7b8e60e686 100644 --- a/extensions/sql-migration/src/telemetry.ts +++ b/extensions/sql-migration/src/telemetry.ts @@ -43,6 +43,7 @@ export enum TelemetryViews { LoginMigrationSelectorPage = 'LoginMigrationSelectorPage', LoginMigrationStatusPage = 'LoginMigrationStatusPage', TdeConfigurationDialog = 'TdeConfigurationDialog', + ValidIrDialog = 'validIrDialog', } export enum TelemetryAction {