From fa227c88c90fc6fdc30f82a87bde19600f12b032 Mon Sep 17 00:00:00 2001 From: Raymond Truong Date: Tue, 15 Mar 2022 10:45:43 -0700 Subject: [PATCH] [SQL Migration] Add state check to target MI resource on target selection page (#18673) * Add MI ready state check and error message * Fix a typo * Update error message logic * Update '(Unavailable)' prefix to be localized string * Show error messsage when non-Ready MI is initially selected (not just on Next button) * Update error message with appropriate casing and actionable step --- .../sql-migration/src/constants/strings.ts | 7 +++++++ .../sql-migration/src/models/stateMachine.ts | 19 +++++++++++++---- .../src/wizard/targetSelectionPage.ts | 21 +++++++++++++++++-- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/extensions/sql-migration/src/constants/strings.ts b/extensions/sql-migration/src/constants/strings.ts index abc6cc667d..96e188832b 100644 --- a/extensions/sql-migration/src/constants/strings.ts +++ b/extensions/sql-migration/src/constants/strings.ts @@ -249,6 +249,10 @@ export function AZURE_SQL_TARGET_PAGE_DESCRIPTION(targetInstance: string = 'inst export const AZURE_SQL_DATABASE_MANAGED_INSTANCE = localize('sql.migration.azure.sql.database.managed.instance', "Azure SQL Managed Instance"); export const NO_MANAGED_INSTANCE_FOUND = localize('sql.migration.no.managedInstance.found', "No managed instance found."); export const INVALID_MANAGED_INSTANCE_ERROR = localize('sql.migration.invalid.managedInstance.error', "To continue, select a valid managed instance."); +export function UNAVAILABLE_MANAGED_INSTANCE_PREFIX(miName: string): string { + return localize('sql.migration.unavailable.managedInstance', "(Unavailable) {0}", miName); +} + // Virtual Machine export const AZURE_SQL_DATABASE_VIRTUAL_MACHINE = localize('sql.migration.azure.sql.database.virtual.machine', "SQL Server on Azure Virtual Machines"); @@ -291,6 +295,9 @@ export function ACCOUNT_ACCESS_ERROR(account: AzureAccount, error: Error) { `${account?.properties?.tenants[0]?.displayName} (${account?.properties?.tenants[0]?.userId})`, error.message); } +export function MI_NOT_READY_ERROR(miName: string, state: string): string { + return localize('sql.migration.mi.not.ready', "The managed instance '{0}' is unavailable for migration because it is currently in the '{1}' state. To continue, select an available managed instance.", miName, state); +} // database backup page export const DATABASE_BACKUP_PAGE_TITLE = localize('sql.migration.database.page.title', "Database backup"); diff --git a/extensions/sql-migration/src/models/stateMachine.ts b/extensions/sql-migration/src/models/stateMachine.ts index 6d3e3381fb..bbb91a9738 100644 --- a/extensions/sql-migration/src/models/stateMachine.ts +++ b/extensions/sql-migration/src/models/stateMachine.ts @@ -1008,10 +1008,21 @@ export class MigrationStateModel implements Model, vscode.Disposable { } this._targetManagedInstances.forEach((managedInstance) => { - managedInstanceValues.push({ - name: managedInstance.id, - displayName: `${managedInstance.name}` - }); + let managedInstanceValue: azdata.CategoryValue; + + if (managedInstance.properties.state === 'Ready') { + managedInstanceValue = { + name: managedInstance.id, + displayName: `${managedInstance.name}` + }; + } else { + managedInstanceValue = { + name: managedInstance.id, + displayName: constants.UNAVAILABLE_MANAGED_INSTANCE_PREFIX(managedInstance.name) + }; + } + + managedInstanceValues.push(managedInstanceValue); }); if (managedInstanceValues.length === 0) { diff --git a/extensions/sql-migration/src/wizard/targetSelectionPage.ts b/extensions/sql-migration/src/wizard/targetSelectionPage.ts index c488a9c54e..cc33302ba9 100644 --- a/extensions/sql-migration/src/wizard/targetSelectionPage.ts +++ b/extensions/sql-migration/src/wizard/targetSelectionPage.ts @@ -12,6 +12,7 @@ import * as constants from '../constants/strings'; import * as styles from '../constants/styles'; import { WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController'; import { deepClone, findDropDownItemIndex, selectDropDownIndex, selectDefaultDropdownValue } from '../api/utils'; +import { azureResource } from 'azureResource'; export class TargetSelectionPage extends MigrationWizardPage { private _view!: azdata.ModelView; @@ -120,9 +121,14 @@ export class TargetSelectionPage extends MigrationWizardPage { const resourceDropdownValue = (this._azureResourceDropdown.value)?.displayName; switch (this.migrationStateModel._targetType) { case MigrationTargetType.SQLMI: { - if (!this.migrationStateModel._targetServerInstance || - resourceDropdownValue === constants.NO_MANAGED_INSTANCE_FOUND) { + let targetMi = this.migrationStateModel._targetServerInstance as azureResource.AzureSqlManagedInstance; + if (!targetMi || resourceDropdownValue === constants.NO_MANAGED_INSTANCE_FOUND) { errors.push(constants.INVALID_MANAGED_INSTANCE_ERROR); + break; + } + if (targetMi.properties.state !== 'Ready') { + errors.push(constants.MI_NOT_READY_ERROR(targetMi.name, targetMi.properties.state)); + break; } break; } @@ -403,6 +409,17 @@ export class TargetSelectionPage extends MigrationWizardPage { case MigrationTargetType.SQLMI: this.migrationStateModel._targetServerInstance = this.migrationStateModel.getManagedInstance(selectedIndex); + if (this.migrationStateModel._targetServerInstance.properties.state !== 'Ready') { + this.wizard.message = { + text: constants.MI_NOT_READY_ERROR(this.migrationStateModel._targetServerInstance.name, this.migrationStateModel._targetServerInstance.properties.state), + level: azdata.window.MessageLevel.Error + }; + } else { + this.wizard.message = { + text: '', + level: azdata.window.MessageLevel.Error + }; + } break; } } else {