diff --git a/extensions/sql-migration/src/api/azure.ts b/extensions/sql-migration/src/api/azure.ts index ae6327a78c..554bb4ea76 100644 --- a/extensions/sql-migration/src/api/azure.ts +++ b/extensions/sql-migration/src/api/azure.ts @@ -656,11 +656,6 @@ export async function deleteMigration(account: azdata.Account, subscription: Sub } } -export async function getLocationDisplayName(location: string): Promise { - const api = await getAzureCoreAPI(); - return api.getRegionDisplayName(location); -} - export async function validateIrSqlDatabaseMigrationSettings( migration: MigrationStateModel, sourceServerName: string, @@ -674,7 +669,7 @@ export async function validateIrSqlDatabaseMigrationSettings( const api = await getAzureCoreAPI(); const account = migration._azureAccount; - const subscription = migration._targetSubscription; + const subscription = migration._sqlMigrationServiceSubscription; const serviceId = migration._sqlMigrationService?.id; const host = api.getProviderMetadataForAccount(account).settings.armResource?.endpoint; const path = encodeURI(`${serviceId}/validateIr?api-version=${DMSV2_API_VERSION}`); @@ -735,11 +730,12 @@ export async function validateIrDatabaseMigrationSettings( const api = await getAzureCoreAPI(); const account = migration._azureAccount; - const subscription = migration._targetSubscription; + const serviceSubscription = migration._sqlMigrationServiceSubscription; + const targetSubscription = migration._targetSubscription; const serviceId = migration._sqlMigrationService?.id; const host = api.getProviderMetadataForAccount(account).settings.armResource?.endpoint; const path = encodeURI(`${serviceId}/validateIr?api-version=${DMSV2_API_VERSION}`); - const storage = await getStorageAccountAccessKeys(account, subscription, networkShare.storageAccount); + const storage = await getStorageAccountAccessKeys(account, targetSubscription, networkShare.storageAccount); const requestBody: ValdiateIrDatabaseMigrationRequest = { sourceDatabaseName: sourceDatabaseName ?? '', @@ -775,7 +771,7 @@ export async function validateIrDatabaseMigrationSettings( const response = await api.makeAzureRestRequest( account, - subscription, + serviceSubscription, path, azurecore.HttpRequestMethod.POST, requestBody, diff --git a/extensions/sql-migration/src/constants/strings.ts b/extensions/sql-migration/src/constants/strings.ts index d435f658a6..ebe40cb01f 100644 --- a/extensions/sql-migration/src/constants/strings.ts +++ b/extensions/sql-migration/src/constants/strings.ts @@ -759,6 +759,12 @@ export function AUTH_KEY_REFRESHED(keyName: string): string { export function SERVICE_NOT_READY(serviceName: string): string { return localize('sql.migration.service.not.ready', "Azure Database Migration Service is not registered. Azure Database Migration Service '{0}' needs to be registered with self-hosted integration runtime on any node.", serviceName); } +export function SERVICE_ERROR_NOT_READY(serviceName: string, error: string): string { + return localize('sql.migration.service.error.not.ready', + "The following error occurred while retrieving registration information for Azure Database Migration Service '{0}'. Please click refresh and try again. Error: '{1}'.", + serviceName, + error); +} export function SERVICE_READY(serviceName: string, host: string): string { return localize('sql.migration.service.ready', "Azure Database Migration Service '{0}' is connected to self-hosted integration runtime running on the node - {1}", serviceName, host); } diff --git a/extensions/sql-migration/src/dashboard/dashboardTab.ts b/extensions/sql-migration/src/dashboard/dashboardTab.ts index 975aeeed84..64c200f2b4 100644 --- a/extensions/sql-migration/src/dashboard/dashboardTab.ts +++ b/extensions/sql-migration/src/dashboard/dashboardTab.ts @@ -776,12 +776,12 @@ export class DashboardTab extends TabBase { this.serviceContextChangedEvent.event( async (e) => { if (e.connectionId === await getSourceConnectionId()) { - await this.updateServiceContext(this._serviceContextButton); + await this.updateServiceButtonContext(this._serviceContextButton); await this.refresh(); } } )); - await this.updateServiceContext(this._serviceContextButton); + await this.updateServiceButtonContext(this._serviceContextButton); return this._serviceContextButton; } diff --git a/extensions/sql-migration/src/dashboard/migrationDetailsTabBase.ts b/extensions/sql-migration/src/dashboard/migrationDetailsTabBase.ts index 865f6fd359..e6dd511f0c 100644 --- a/extensions/sql-migration/src/dashboard/migrationDetailsTabBase.ts +++ b/extensions/sql-migration/src/dashboard/migrationDetailsTabBase.ts @@ -147,7 +147,7 @@ export abstract class MigrationDetailsTabBase extends TabBase { await this.refresh(); const dialog = new ConfirmCutoverDialog(this.model); await dialog.initialize(); - + await this.refresh(); if (this.model.CutoverError) { await this.statusBar.showError( loc.MIGRATION_CUTOVER_ERROR, diff --git a/extensions/sql-migration/src/dashboard/migrationsListTab.ts b/extensions/sql-migration/src/dashboard/migrationsListTab.ts index daa959deca..2cb844e27d 100644 --- a/extensions/sql-migration/src/dashboard/migrationsListTab.ts +++ b/extensions/sql-migration/src/dashboard/migrationsListTab.ts @@ -78,7 +78,7 @@ export class MigrationsListTab extends TabBase { } } - public async refresh(): Promise { + public async refresh(initialize?: boolean): Promise { if (this.isRefreshing || this._refreshLoader === undefined) { @@ -91,6 +91,10 @@ export class MigrationsListTab extends TabBase { await this.statusBar.clearError(); + if (initialize) { + await this.updateServiceButtonContext(this._serviceContextButton); + } + await this._statusTable.updateProperty('data', []); this._migrations = await getCurrentMigrations(); await this._populateMigrationTable(); @@ -180,12 +184,11 @@ export class MigrationsListTab extends TabBase { this.serviceContextChangedEvent.event( async (e) => { if (e.connectionId === await getSourceConnectionId()) { - await this.updateServiceContext(this._serviceContextButton); - await this.refresh(); + await this.refresh(true); } } )); - await this.updateServiceContext(this._serviceContextButton); + await this.updateServiceButtonContext(this._serviceContextButton); this._searchBox = this.view.modelBuilder.inputBox() .withProps({ diff --git a/extensions/sql-migration/src/dashboard/migrationsTab.ts b/extensions/sql-migration/src/dashboard/migrationsTab.ts index 059ce3a656..be24628cd6 100644 --- a/extensions/sql-migration/src/dashboard/migrationsTab.ts +++ b/extensions/sql-migration/src/dashboard/migrationsTab.ts @@ -57,7 +57,7 @@ export class MigrationsTab extends TabBase { switch (this._selectedTabId) { case undefined: case MigrationsListTabId: - return this._migrationsListTab.refresh(); + return this._migrationsListTab.refresh(true); default: return this._migrationDetailsViewTab.refresh(); } @@ -155,11 +155,10 @@ export class MigrationsTab extends TabBase { return undefined; } - private async _openTab(tab: azdata.Tab): Promise { + private async _openTab(tab: TabBase): Promise { if (tab.id === this._selectedTabId) { return; } - await this.statusBar.clearError(); this._tab.clearItems(); this._tab.addItem(tab.content); diff --git a/extensions/sql-migration/src/dashboard/tabBase.ts b/extensions/sql-migration/src/dashboard/tabBase.ts index 4d69b1651e..d50a3b59d6 100644 --- a/extensions/sql-migration/src/dashboard/tabBase.ts +++ b/extensions/sql-migration/src/dashboard/tabBase.ts @@ -82,16 +82,12 @@ export abstract class TabBase implements azdata.Tab, vscode.Disposable { return new Date(stringDate1) > new Date(stringDate2) ? -sortDir : sortDir; } - protected async updateServiceContext(button: azdata.ButtonComponent): Promise { + protected async updateServiceButtonContext(button: azdata.ButtonComponent): Promise { const label = await getSelectedServiceStatus(); - if (button.label !== label || - button.title !== label) { - - button.label = label; - button.title = label; - - await this.refresh(); - } + await button.updateProperty('label', ''); + await button.updateProperty('title', ''); + await button.updateProperty('label', label); + await button.updateProperty('title', label); } protected createNewLoginMigrationButton(): azdata.ButtonComponent { diff --git a/extensions/sql-migration/src/dialog/createSqlMigrationService/createSqlMigrationServiceDialog.ts b/extensions/sql-migration/src/dialog/createSqlMigrationService/createSqlMigrationServiceDialog.ts index 4c77c44008..01d7baa1fc 100644 --- a/extensions/sql-migration/src/dialog/createSqlMigrationService/createSqlMigrationServiceDialog.ts +++ b/extensions/sql-migration/src/dialog/createSqlMigrationService/createSqlMigrationServiceDialog.ts @@ -61,7 +61,7 @@ export class CreateSqlMigrationServiceDialog { this._dialogObject.okButton.position = 'left'; this._dialogObject.cancelButton.position = 'left'; - let tab = azdata.window.createTab(''); + const tab = azdata.window.createTab(''); this._dialogObject.registerCloseValidator(async () => { return true; }); @@ -73,70 +73,64 @@ export class CreateSqlMigrationServiceDialog { width: '80px' }).component(); - this._disposables.push(this._formSubmitButton.onDidClick(async (e) => { - this._dialogObject.message = { - text: '' - }; - this._statusLoadingComponent.loading = true; - this.migrationServiceResourceGroupDropdown.loading = false; - this.setFormEnabledState(false); - - - const subscription = this._model._targetSubscription; - const resourceGroup = this._selectedResourceGroup; - const location = this._model._targetServerInstance.location; - const serviceName = this.migrationServiceNameText.value; - - const formValidationErrors = this.validateCreateServiceForm(subscription, resourceGroup.name, location, serviceName); - - if (formValidationErrors.length > 0) { - this.setDialogMessage(formValidationErrors); - this._statusLoadingComponent.loading = false; - this.setFormEnabledState(true); - return; - } - - try { + this._disposables.push( + this._formSubmitButton.onDidClick(async (e) => { utils.clearDialogMessage(this._dialogObject); - this._selectedResourceGroup = resourceGroup; - this._createdMigrationService = await createSqlMigrationService( - this._model._azureAccount, - subscription, - resourceGroup.name, - location, - serviceName!, - this._model._sessionId); - if (this._createdMigrationService.error) { - this.setDialogMessage(`${this._createdMigrationService.error.code} : ${this._createdMigrationService.error.message}`); - this._statusLoadingComponent.loading = false; + this._statusLoadingComponent.loading = true; + this.migrationServiceResourceGroupDropdown.loading = false; + this.setFormEnabledState(false); + + const subscription = this._model._sqlMigrationServiceSubscription; + const resourceGroup = this._selectedResourceGroup; + const location = this._model._location.name; + const serviceName = this.migrationServiceNameText.value; + + const formValidationErrors = this.validateCreateServiceForm(subscription, resourceGroup.name, location, serviceName); + + try { + if (formValidationErrors.length > 0) { + this.setDialogMessage(formValidationErrors); + this.setFormEnabledState(true); + return; + } + + utils.clearDialogMessage(this._dialogObject); + this._createdMigrationService = await createSqlMigrationService( + this._model._azureAccount, + subscription, + resourceGroup.name, + location, + serviceName!, + this._model._sessionId); + + if (this._createdMigrationService.error) { + this.setDialogMessage(`${this._createdMigrationService.error.code} : ${this._createdMigrationService.error.message}`); + this.setFormEnabledState(true); + return; + } + + if (this._isBlobContainerUsed && !this._model.isSqlDbTarget) { + this._dialogObject.okButton.enabled = true; + this._setupContainer.display = 'none'; + this._dialogObject.message = { + text: constants.DATA_MIGRATION_SERVICE_CREATED_SUCCESSFULLY, + level: azdata.window.MessageLevel.Information + }; + } else { + await this.refreshStatus(); + await this.refreshAuthTable(); + this._setupContainer.display = 'inline'; + this._testConnectionButton.hidden = false; + } + } catch (e) { + console.log(e); + this.setDialogMessage(e.message); this.setFormEnabledState(true); - return; - } - - if (this._isBlobContainerUsed && !this._model.isSqlDbTarget) { - this._dialogObject.okButton.enabled = true; - this._statusLoadingComponent.loading = false; - this._setupContainer.display = 'none'; - this._dialogObject.message = { - text: constants.DATA_MIGRATION_SERVICE_CREATED_SUCCESSFULLY, - level: azdata.window.MessageLevel.Information - }; - } else { - await this.refreshStatus(); - await this.refreshAuthTable(); - this._setupContainer.display = 'inline'; - this._testConnectionButton.hidden = false; + } finally { this._statusLoadingComponent.loading = false; } - } catch (e) { - console.log(e); - this.setDialogMessage(e.message); - this._statusLoadingComponent.loading = false; - this.setFormEnabledState(true); - return; - } - })); + })); this._statusLoadingComponent = view.modelBuilder.loadingComponent().withProps({ loadingText: constants.LOADING_MIGRATION_SERVICES, @@ -289,7 +283,11 @@ export class CreateSqlMigrationServiceDialog { }).component(); this._disposables.push(this._createResourceGroupLink.onDidClick(async e => { - const createResourceGroupDialog = new CreateResourceGroupDialog(this._model._azureAccount, this._model._targetSubscription, this._model._targetServerInstance.location); + const createResourceGroupDialog = new CreateResourceGroupDialog( + this._model._azureAccount, + this._model._sqlMigrationServiceSubscription, + this._model._location.name); + const createdResourceGroup = await createResourceGroupDialog.initialize(); if (createdResourceGroup) { this._resourceGroups.push(createdResourceGroup); @@ -324,7 +322,7 @@ export class CreateSqlMigrationServiceDialog { this.migrationServiceLocation = this._view.modelBuilder.text().withProps({ enabled: false, - value: await this._model.getLocationDisplayName(this._model._targetServerInstance.location), + value: this._model._location.displayName, CSSStyles: { 'margin': '-1em 0 0' } @@ -386,7 +384,7 @@ export class CreateSqlMigrationServiceDialog { private async populateSubscriptions(): Promise { this.migrationServiceResourceGroupDropdown.loading = true; - this.migrationServiceSubscription.value = this._model._targetSubscription.name; + this.migrationServiceSubscription.value = this._model._sqlMigrationServiceSubscription.name; await this.populateResourceGroups(); } @@ -395,7 +393,7 @@ export class CreateSqlMigrationServiceDialog { try { this._resourceGroups = await utils.getAllResourceGroups( this._model._azureAccount, - this._model._targetSubscription); + this._model._sqlMigrationServiceSubscription); this.migrationServiceResourceGroupDropdown.values = utils.getResourceDropdownValues( this._resourceGroups, constants.RESOURCE_GROUP_NOT_FOUND); @@ -510,10 +508,10 @@ export class CreateSqlMigrationServiceDialog { } private async refreshStatus(): Promise { - const subscription = this._model._targetSubscription; + const subscription = this._model._sqlMigrationServiceSubscription; const resourceGroupId = (this.migrationServiceResourceGroupDropdown.value as azdata.CategoryValue).name; const resourceGroup = getResourceName(resourceGroupId); - const location = this._model._targetServerInstance.location; + const location = this._model._location.name; const maxRetries = 5; let migrationServiceStatus!: SqlMigrationService; @@ -558,7 +556,6 @@ export class CreateSqlMigrationServiceDialog { ...styles.BODY_CSS } }); - this._dialogObject.okButton.enabled = true; } else { this._connectionStatus.text = constants.SERVICE_NOT_READY(this._createdMigrationService!.name); await this._connectionStatus.updateProperties({ @@ -568,16 +565,16 @@ export class CreateSqlMigrationServiceDialog { ...styles.BODY_CSS } }); - this._dialogObject.okButton.enabled = false; } + this._dialogObject.okButton.enabled = true; } - } + private async refreshAuthTable(): Promise { - const subscription = this._model._targetSubscription; + const subscription = this._model._sqlMigrationServiceSubscription; const resourceGroupId = (this.migrationServiceResourceGroupDropdown.value as azdata.CategoryValue).name; const resourceGroup = getResourceName(resourceGroupId); - const location = this._model._targetServerInstance.location; + const location = this._model._location.name; const keys = await getSqlMigrationServiceAuthKeys( this._model._azureAccount, subscription, diff --git a/extensions/sql-migration/src/dialog/restartMigration/restartMigrationDialog.ts b/extensions/sql-migration/src/dialog/restartMigration/restartMigrationDialog.ts index 18e547fddc..2ab6e7404d 100644 --- a/extensions/sql-migration/src/dialog/restartMigration/restartMigrationDialog.ts +++ b/extensions/sql-migration/src/dialog/restartMigration/restartMigrationDialog.ts @@ -74,6 +74,8 @@ export class RestartMigrationDialog { // Integration Runtime sqlMigrationService: serviceContext.migrationService, + serviceSubscription: null, + serviceResourceGroup: null }; const getStorageAccountResourceGroup = (storageAccountResourceId: string): azureResource.AzureResourceResourceGroup => { diff --git a/extensions/sql-migration/src/models/stateMachine.ts b/extensions/sql-migration/src/models/stateMachine.ts index b9e19ce88c..56bf2aabfc 100644 --- a/extensions/sql-migration/src/models/stateMachine.ts +++ b/extensions/sql-migration/src/models/stateMachine.ts @@ -8,7 +8,7 @@ import * as azurecore from 'azurecore'; import * as vscode from 'vscode'; import * as contracts from '../service/contracts'; import * as features from '../service/features'; -import { SqlMigrationService, SqlManagedInstance, startDatabaseMigration, StartDatabaseMigrationRequest, StorageAccount, SqlVMServer, getLocationDisplayName, getSqlManagedInstanceDatabases, AzureSqlDatabaseServer, VirtualMachineInstanceView } from '../api/azure'; +import { SqlMigrationService, SqlManagedInstance, startDatabaseMigration, StartDatabaseMigrationRequest, StorageAccount, SqlVMServer, getSqlManagedInstanceDatabases, AzureSqlDatabaseServer, VirtualMachineInstanceView } from '../api/azure'; import * as constants from '../constants/strings'; import * as nls from 'vscode-nls'; import { v4 as uuidv4 } from 'uuid'; @@ -150,6 +150,8 @@ export interface SavedInfo { blobs: Blob[]; targetDatabaseNames: string[]; sqlMigrationService: SqlMigrationService | undefined; + serviceSubscription: azurecore.azureResource.AzureResourceSubscription | null; + serviceResourceGroup: azurecore.azureResource.AzureResourceResourceGroup | null; serverAssessment: ServerAssessment | null; skuRecommendation: SkuRecommendationSavedInfo | null; } @@ -201,6 +203,7 @@ export class MigrationStateModel implements Model, vscode.Disposable { public _targetPassword!: string; public _sourceTargetMapping: Map = new Map(); + public _sqlMigrationServiceSubscription!: azurecore.azureResource.AzureResourceSubscription; public _sqlMigrationServiceResourceGroup!: azurecore.azureResource.AzureResourceResourceGroup; public _sqlMigrationService!: SqlMigrationService | undefined; public _sqlMigrationServices!: SqlMigrationService[]; @@ -342,6 +345,19 @@ export class MigrationStateModel implements Model, vscode.Disposable { r.state === ValidateIrState.Succeeded) } + public get migrationTargetServerName(): string { + switch (this._targetType) { + case MigrationTargetType.SQLMI: + return (this._targetServerInstance as azurecore.azureResource.AzureSqlManagedInstance)?.name; + case MigrationTargetType.SQLVM: + return (this._targetServerInstance as SqlVMServer)?.name; + case MigrationTargetType.SQLDB: + return (this._targetServerInstance as AzureSqlDatabaseServer)?.name; + default: + return ''; + } + } + public get isBackupContainerNetworkShare(): boolean { return this._databaseBackup?.networkContainerType === NetworkContainerType.NETWORK_SHARE; } @@ -927,10 +943,6 @@ export class MigrationStateModel implements Model, vscode.Disposable { return this.extensionContext.extensionPath; } - public getLocationDisplayName(location: string): Promise { - return getLocationDisplayName(location); - } - public async getManagedDatabases(): Promise { return ( await getSqlManagedInstanceDatabases(this._azureAccount, @@ -1107,7 +1119,7 @@ export class MigrationStateModel implements Model, vscode.Disposable { requestBody.properties.sourceDatabaseName = this._databasesForMigration[i]; const response = await startDatabaseMigration( this._azureAccount, - this._targetSubscription, + this._sqlMigrationServiceSubscription, this._sqlMigrationService?.location!, this._targetServerInstance, this._targetDatabaseNames[i], @@ -1131,9 +1143,9 @@ export class MigrationStateModel implements Model, vscode.Disposable { { 'sessionId': this._sessionId, 'tenantId': this._azureAccount.properties.tenants[0].id, - 'subscriptionId': this._targetSubscription?.id, - 'resourceGroup': this._resourceGroup?.name, - 'location': this._targetServerInstance.location, + 'subscriptionId': this._sqlMigrationServiceSubscription?.id, + 'resourceGroup': this._sqlMigrationServiceResourceGroup?.name, + 'location': this._location.name, 'targetType': this._targetType, 'hashedServerName': hashString(this._assessmentApiResponse?.assessmentResult?.name), 'hashedDatabaseName': hashString(this._databasesForMigration[i]), @@ -1197,12 +1209,16 @@ export class MigrationStateModel implements Model, vscode.Disposable { sqlMigrationService: undefined, serverAssessment: null, skuRecommendation: null, + serviceResourceGroup: null, + serviceSubscription: null, }; switch (currentPage) { case Page.Summary: case Page.IntegrationRuntime: saveInfo.sqlMigrationService = this._sqlMigrationService; + saveInfo.serviceSubscription = this._sqlMigrationServiceSubscription; + saveInfo.serviceResourceGroup = this._sqlMigrationServiceResourceGroup; saveInfo.migrationMode = this._databaseBackup.migrationMode; saveInfo.networkContainerType = this._databaseBackup.networkContainerType; @@ -1282,6 +1298,8 @@ export class MigrationStateModel implements Model, vscode.Disposable { this._databaseBackup.subscription = this.savedInfo.subscription || undefined!; this._sqlMigrationService = this.savedInfo.sqlMigrationService; + this._sqlMigrationServiceSubscription = this.savedInfo.serviceSubscription || undefined!; + this._sqlMigrationServiceResourceGroup = this.savedInfo.serviceResourceGroup || undefined!; const savedAssessmentResults = this.savedInfo.serverAssessment; if (savedAssessmentResults) { diff --git a/extensions/sql-migration/src/wizard/databaseBackupPage.ts b/extensions/sql-migration/src/wizard/databaseBackupPage.ts index 051659bd43..89ecb9984d 100644 --- a/extensions/sql-migration/src/wizard/databaseBackupPage.ts +++ b/extensions/sql-migration/src/wizard/databaseBackupPage.ts @@ -228,7 +228,7 @@ export class DatabaseBackupPage extends MigrationWizardPage { description: constants.DATABASE_BACKUP_NETWORK_SHARE_WINDOWS_USER_INFO, width: WIZARD_INPUT_COMPONENT_WIDTH, requiredIndicator: true, - CSSStyles: { ...styles.LABEL_CSS } + CSSStyles: { ...styles.LABEL_CSS }, }).component(); this._windowsUserAccountText = this._view.modelBuilder.inputBox() .withProps({ @@ -627,7 +627,13 @@ export class DatabaseBackupPage extends MigrationWizardPage { // check for storage account connectivity if ((this.migrationStateModel.isSqlMiTarget || this.migrationStateModel.isSqlVmTarget)) { - if (!(await canTargetConnectToStorageAccount(this.migrationStateModel._targetType, this.migrationStateModel._targetServerInstance, selectedStorageAccount, this.migrationStateModel._azureAccount, this.migrationStateModel._targetSubscription))) { + if (!(await canTargetConnectToStorageAccount( + this.migrationStateModel._targetType, + this.migrationStateModel._targetServerInstance, + selectedStorageAccount, + this.migrationStateModel._azureAccount, + this.migrationStateModel._targetSubscription))) { + this._inaccessibleStorageAccounts = [selectedStorageAccount.name]; } else { this._inaccessibleStorageAccounts = []; @@ -661,7 +667,11 @@ export class DatabaseBackupPage extends MigrationWizardPage { // check for storage account connectivity const selectedStorageAccount = this.migrationStateModel._storageAccounts.find(sa => sa.name === (this._networkShareContainerStorageAccountDropdown.value as azdata.CategoryValue).displayName); if ((this.migrationStateModel.isSqlMiTarget || this.migrationStateModel.isSqlVmTarget) && selectedStorageAccount) { - if (!(await canTargetConnectToStorageAccount(this.migrationStateModel._targetType, this.migrationStateModel._targetServerInstance, selectedStorageAccount, this.migrationStateModel._azureAccount, this.migrationStateModel._targetSubscription))) { + if (!(await canTargetConnectToStorageAccount( + this.migrationStateModel._targetType, + this.migrationStateModel._targetServerInstance, + selectedStorageAccount, this.migrationStateModel._azureAccount, + this.migrationStateModel._targetSubscription))) { this._inaccessibleStorageAccounts = [selectedStorageAccount.name]; } else { this._inaccessibleStorageAccounts = []; @@ -1129,7 +1139,13 @@ export class DatabaseBackupPage extends MigrationWizardPage { this._inaccessibleStorageAccounts = this._inaccessibleStorageAccounts.filter(storageAccountName => storageAccountName.toLowerCase() !== oldSelectedStorageAccount.toLowerCase()); } - if (!(await canTargetConnectToStorageAccount(this.migrationStateModel._targetType, this.migrationStateModel._targetServerInstance, selectedStorageAccount, this.migrationStateModel._azureAccount, this.migrationStateModel._targetSubscription))) { + if (!(await canTargetConnectToStorageAccount( + this.migrationStateModel._targetType, + this.migrationStateModel._targetServerInstance, + selectedStorageAccount, + this.migrationStateModel._azureAccount, + this.migrationStateModel._targetSubscription))) { + this._inaccessibleStorageAccounts = this._inaccessibleStorageAccounts.filter(storageAccountName => storageAccountName.toLowerCase() !== selectedStorageAccount.name.toLowerCase()); this._inaccessibleStorageAccounts.push(selectedStorageAccount.name); } @@ -1452,10 +1468,10 @@ export class DatabaseBackupPage extends MigrationWizardPage { private async getSubscriptionValues(): Promise { this._networkShareContainerSubscription.value = this.migrationStateModel._targetSubscription.name; - this._networkShareContainerLocation.value = await this.migrationStateModel.getLocationDisplayName(this.migrationStateModel._targetServerInstance.location); + this._networkShareContainerLocation.value = await this.migrationStateModel._location.displayName; this._blobContainerSubscription.value = this.migrationStateModel._targetSubscription.name; - this._blobContainerLocation.value = await this.migrationStateModel.getLocationDisplayName(this.migrationStateModel._targetServerInstance.location); + this._blobContainerLocation.value = this.migrationStateModel._location.displayName; this.migrationStateModel._databaseBackup.subscription = this.migrationStateModel._targetSubscription; diff --git a/extensions/sql-migration/src/wizard/integrationRuntimePage.ts b/extensions/sql-migration/src/wizard/integrationRuntimePage.ts index 5610532aeb..689173a10f 100644 --- a/extensions/sql-migration/src/wizard/integrationRuntimePage.ts +++ b/extensions/sql-migration/src/wizard/integrationRuntimePage.ts @@ -10,7 +10,7 @@ import { MigrationMode, MigrationStateModel, NetworkContainerType, StateChangeEv import { CreateSqlMigrationServiceDialog } from '../dialog/createSqlMigrationService/createSqlMigrationServiceDialog'; import * as constants from '../constants/strings'; import { WIZARD_INPUT_COMPONENT_WIDTH } from './wizardController'; -import { getFullResourceGroupFromId, getLocationDisplayName, getSqlMigrationService, getSqlMigrationServiceAuthKeys, getSqlMigrationServiceMonitoringData, SqlVMServer } from '../api/azure'; +import { getFullResourceGroupFromId, getSqlMigrationService, getSqlMigrationServiceAuthKeys, getSqlMigrationServiceMonitoringData, SqlVMServer } from '../api/azure'; import { IconPathHelper } from '../constants/iconPathHelper'; import { logError, TelemetryViews } from '../telemetry'; import * as utils from '../api/utils'; @@ -19,7 +19,7 @@ import * as styles from '../constants/styles'; export class IntergrationRuntimePage extends MigrationWizardPage { private _view!: azdata.ModelView; private _statusLoadingComponent!: azdata.LoadingComponent; - private _subscription!: azdata.TextComponent; + private _subscriptionDropdown!: azdata.DropDownComponent; private _location!: azdata.TextComponent; private _resourceGroupDropdown!: azdata.DropDownComponent; private _dmsDropdown!: azdata.DropDownComponent; @@ -27,7 +27,6 @@ export class IntergrationRuntimePage extends MigrationWizardPage { private _dmsStatusInfoBox!: azdata.InfoBoxComponent; private _authKeyTable!: azdata.DeclarativeTableComponent; private _refreshButton!: azdata.ButtonComponent; - private _connectionStatusLoader!: azdata.LoadingComponent; private _copy1!: azdata.ButtonComponent; private _copy2!: azdata.ButtonComponent; private _refresh1!: azdata.ButtonComponent; @@ -157,8 +156,13 @@ export class IntergrationRuntimePage extends MigrationWizardPage { this._networkShareButton.onDidChangeCheckedState(async checked => { if (checked) { this.migrationStateModel._databaseBackup.networkContainerType = NetworkContainerType.NETWORK_SHARE; - await utils.updateControlDisplay(this._dmsInfoContainer, true); this.migrationStateModel.refreshDatabaseBackupPage = true; + + const hasService = this.migrationStateModel._sqlMigrationService !== undefined; + await utils.updateControlDisplay(this._dmsInfoContainer, hasService); + if (hasService) { + await this.loadStatus(); + } } })); @@ -271,15 +275,13 @@ export class IntergrationRuntimePage extends MigrationWizardPage { this.migrationStateModel._databaseBackup.networkContainerType = NetworkContainerType.BLOB_CONTAINER; this._blobContainerButton.checked = true; - this._subscription.value = this.migrationStateModel._targetSubscription.name; - this._location.value = await getLocationDisplayName( - this.migrationStateModel._targetServerInstance.location); + await this.loadSubscriptionsDropdown(); + + this._location.value = this.migrationStateModel._location.displayName; await utils.updateControlDisplay( this._dmsInfoContainer, isSqlDbTarget || isNetworkShare); - - await this.loadResourceGroupDropdown(); } public async onPageLeave(pageChangeInfo: azdata.window.WizardPageChangeInfo): Promise { @@ -306,13 +308,32 @@ export class IntergrationRuntimePage extends MigrationWizardPage { value: constants.SUBSCRIPTION, CSSStyles: { ...styles.LABEL_CSS } }).component(); - this._subscription = this._view.modelBuilder.text() + + this._subscriptionDropdown = this._view.modelBuilder.dropDown() .withProps({ - enabled: false, + ariaLabel: constants.MIGRATION_SERVICE_SELECT_SERVICE_LABEL, width: WIZARD_INPUT_COMPONENT_WIDTH, + editable: true, + required: true, + fireOnTextChange: true, + placeholder: constants.SELECT_A_SERVICE, CSSStyles: { 'margin': '0' } }).component(); + this._disposables.push( + this._subscriptionDropdown.onValueChanged(async (value) => { + if (value && value !== 'undefined' && value !== constants.SERVICE_NOT_FOUND) { + const selectedSubscription = this.migrationStateModel._subscriptions.find( + sub => `${sub.name} - ${sub.id}` === value); + this.migrationStateModel._sqlMigrationServiceSubscription = (selectedSubscription) + ? selectedSubscription + : undefined!; + } else { + this.migrationStateModel._sqlMigrationServiceSubscription = undefined!; + } + await this.loadResourceGroupDropdown(); + })); + const locationLabel = this._view.modelBuilder.text() .withProps({ value: constants.LOCATION, @@ -349,8 +370,11 @@ export class IntergrationRuntimePage extends MigrationWizardPage { this.migrationStateModel._sqlMigrationServiceResourceGroup = (selectedResourceGroup) ? selectedResourceGroup : undefined!; - this.populateDms(); } + else { + this.migrationStateModel._sqlMigrationServiceResourceGroup = undefined!; + } + this.loadDmsDropdown(); })); const migrationServiceDropdownLabel = this._view.modelBuilder.text() @@ -379,15 +403,18 @@ export class IntergrationRuntimePage extends MigrationWizardPage { dms => dms.name === value && dms.properties.resourceGroup.toLowerCase() === resourceGroupName); - if (selectedDms) { - this.migrationStateModel._sqlMigrationService = selectedDms; - await this.loadStatus(); - } + const showShirStatus = selectedDms !== undefined && + (this.migrationStateModel.isSqlDbTarget || + this.migrationStateModel.isBackupContainerNetworkShare); + this.migrationStateModel._sqlMigrationService = selectedDms; await utils.updateControlDisplay( this._dmsInfoContainer, - this.migrationStateModel.isSqlDbTarget || - this.migrationStateModel.isBackupContainerNetworkShare); + showShirStatus); + + if (showShirStatus) { + await this.loadStatus(); + } } else { this.migrationStateModel._sqlMigrationService = undefined; await utils.updateControlDisplay(this._dmsInfoContainer, false); @@ -414,15 +441,15 @@ export class IntergrationRuntimePage extends MigrationWizardPage { this.migrationStateModel._sqlMigrationServiceResourceGroup = createdDmsResult.resourceGroup; this.migrationStateModel._sqlMigrationService = createdDmsResult.service; + await this.loadResourceGroupDropdown(); - this.populateDms(); })); return this._view.modelBuilder.flexContainer() .withItems([ descriptionText, subscriptionLabel, - this._subscription, + this._subscriptionDropdown, locationLabel, this._location, resourceGroupLabel, @@ -534,48 +561,71 @@ export class IntergrationRuntimePage extends MigrationWizardPage { authenticationKeysLabel, this._authKeyTable]); - this._connectionStatusLoader = this._view.modelBuilder.loadingComponent() - .withItem(statusContainer) - .withProps({ loading: false }) - .component(); - container.addItems([ connectionLabelContainer, - this._connectionStatusLoader]); + statusContainer]); return container; } + public async loadSubscriptionsDropdown(): Promise { + try { + this._subscriptionDropdown.loading = true; + this.migrationStateModel._subscriptions = await utils.getAzureSubscriptions( + this.migrationStateModel._azureAccount); + + const sub = this.migrationStateModel._sqlMigrationServiceSubscription + ?? this.migrationStateModel._targetSubscription; + + this._subscriptionDropdown.values = await utils.getAzureSubscriptionsDropdownValues( + this.migrationStateModel._subscriptions); + + utils.selectDefaultDropdownValue(this._subscriptionDropdown, sub?.id, false); + } catch (e) { + logError(TelemetryViews.IntegrationRuntimePage, 'Error loadSubscriptionsDropdown', e); + } finally { + this._subscriptionDropdown.loading = false; + } + } + public async loadResourceGroupDropdown(): Promise { try { this._resourceGroupDropdown.loading = true; - this._dmsDropdown.loading = true; + const account = this.migrationStateModel._azureAccount; + const subscription = this.migrationStateModel._sqlMigrationServiceSubscription; + const serviceId = this.migrationStateModel._sqlMigrationService?.id; + const resourceGroup = this.migrationStateModel._sqlMigrationServiceResourceGroup?.name ?? + serviceId !== undefined + ? getFullResourceGroupFromId(serviceId!) + : undefined; - this.migrationStateModel._sqlMigrationServices = await utils.getAzureSqlMigrationServices( - this.migrationStateModel._azureAccount, - this.migrationStateModel._targetSubscription); + const migrationServices = await utils.getAzureSqlMigrationServices( + account, + subscription); - this.migrationStateModel._resourceGroups = utils.getServiceResourceGroupsByLocation( - this.migrationStateModel._sqlMigrationServices, + const resourceGroups = utils.getServiceResourceGroupsByLocation( + migrationServices, this.migrationStateModel._location); this._resourceGroupDropdown.values = utils.getResourceDropdownValues( - this.migrationStateModel._resourceGroups, + resourceGroups, constants.RESOURCE_GROUP_NOT_FOUND); - const resourceGroup = this.migrationStateModel._sqlMigrationService - ? getFullResourceGroupFromId(this.migrationStateModel._sqlMigrationService?.id) - : undefined; + this.migrationStateModel._sqlMigrationServices = migrationServices; + this.migrationStateModel._resourceGroups = resourceGroups; utils.selectDefaultDropdownValue(this._resourceGroupDropdown, resourceGroup, false); + } catch (e) { + logError(TelemetryViews.IntegrationRuntimePage, 'Error loadResourceGroupDropdown', e); } finally { - this._dmsDropdown.loading = false; this._resourceGroupDropdown.loading = false; } } - public populateDms(): void { + public loadDmsDropdown(): void { try { this._dmsDropdown.loading = true; + const serviceId = this.migrationStateModel._sqlMigrationService?.id; + this._dmsDropdown.values = utils.getAzureResourceDropdownValues( this.migrationStateModel._sqlMigrationServices, this.migrationStateModel._location, @@ -584,53 +634,77 @@ export class IntergrationRuntimePage extends MigrationWizardPage { utils.selectDefaultDropdownValue( this._dmsDropdown, - this.migrationStateModel._sqlMigrationService?.id, + serviceId, false); + } catch (e) { + logError(TelemetryViews.IntegrationRuntimePage, 'Error loadDmsDropdown', e); } finally { this._dmsDropdown.loading = false; } } + private _lastIn = 0; private async loadStatus(): Promise { + const callSequence = ++this._lastIn; + let serviceName = ''; try { - this._statusLoadingComponent.loading = true; + if (callSequence === this._lastIn) { + this._statusLoadingComponent.loading = true; + } + + const service = this.migrationStateModel._sqlMigrationService; + if (service) { + const account = this.migrationStateModel._azureAccount; + const subscription = this.migrationStateModel._sqlMigrationServiceSubscription; + const resourceGroup = service.properties.resourceGroup; + const location = service.location; + serviceName = service.name; + if (service?.properties?.integrationRuntimeState) { + service.properties.integrationRuntimeState = undefined; + } - if (this.migrationStateModel._sqlMigrationService) { const migrationService = await getSqlMigrationService( - this.migrationStateModel._azureAccount, - this.migrationStateModel._targetSubscription, - this.migrationStateModel._sqlMigrationService.properties.resourceGroup, - this.migrationStateModel._sqlMigrationService.location, - this.migrationStateModel._sqlMigrationService.name); - this.migrationStateModel._sqlMigrationService = migrationService; + account, + subscription, + resourceGroup, + location, + serviceName); + + // exit if new call has started + if (callSequence !== this._lastIn) { return; } + const migrationServiceMonitoringStatus = await getSqlMigrationServiceMonitoringData( - this.migrationStateModel._azureAccount, - this.migrationStateModel._targetSubscription, - this.migrationStateModel._sqlMigrationService.properties.resourceGroup, - this.migrationStateModel._sqlMigrationService.location, - this.migrationStateModel._sqlMigrationService!.name); - this.migrationStateModel._nodeNames = migrationServiceMonitoringStatus.nodes.map( + account, + subscription, + resourceGroup, + location, + serviceName); + + const nodeNames = migrationServiceMonitoringStatus.nodes.map( node => node.nodeName); + // exit if new call has started + if (callSequence !== this._lastIn) { return; } + const migrationServiceAuthKeys = await getSqlMigrationServiceAuthKeys( - this.migrationStateModel._azureAccount, - this.migrationStateModel._targetSubscription, - this.migrationStateModel._sqlMigrationService.properties.resourceGroup, - this.migrationStateModel._sqlMigrationService.location, - this.migrationStateModel._sqlMigrationService!.name); + account, + subscription, + resourceGroup, + location, + serviceName); + + // exit if new call has started + if (callSequence !== this._lastIn) { return; } const state = migrationService.properties.integrationRuntimeState; if (state === 'Online') { await this._dmsStatusInfoBox.updateProperties({ - text: constants.SERVICE_READY( - this.migrationStateModel._sqlMigrationService!.name, - this.migrationStateModel._nodeNames.join(', ')), + text: constants.SERVICE_READY(serviceName, nodeNames.join(', ')), style: 'success' }); } else { await this._dmsStatusInfoBox.updateProperties({ - text: constants.SERVICE_NOT_READY( - this.migrationStateModel._sqlMigrationService!.name), + text: constants.SERVICE_NOT_READY(serviceName), style: 'error' }); } @@ -655,12 +729,26 @@ export class IntergrationRuntimePage extends MigrationWizardPage { } ]]; + // exit if new call has started + if (callSequence !== this._lastIn) { return; } + await this._authKeyTable.setDataValues(data); + + this.migrationStateModel._sqlMigrationService = migrationService; + this.migrationStateModel._sqlMigrationServiceSubscription = subscription; + this.migrationStateModel._nodeNames = nodeNames; } } catch (e) { - logError(TelemetryViews.IntegrationRuntimePage, 'ErrorLoadingStatus', e); + await this._dmsStatusInfoBox.updateProperties({ + text: constants.SERVICE_ERROR_NOT_READY(serviceName, e.message), + style: 'error' + }); + + logError(TelemetryViews.IntegrationRuntimePage, 'Error loadStatus', e); } finally { - this._statusLoadingComponent.loading = false; + if (callSequence === this._lastIn) { + this._statusLoadingComponent.loading = false; + } } } } diff --git a/extensions/sql-migration/src/wizard/summaryPage.ts b/extensions/sql-migration/src/wizard/summaryPage.ts index e17ecca35f..1bd80b3acc 100644 --- a/extensions/sql-migration/src/wizard/summaryPage.ts +++ b/extensions/sql-migration/src/wizard/summaryPage.ts @@ -100,8 +100,7 @@ export class SummaryPage extends MigrationWizardPage { createInformationRow( this._view, constants.LOCATION, - await this.migrationStateModel.getLocationDisplayName( - this.migrationStateModel._targetServerInstance.location)), + this.migrationStateModel._location.displayName), createInformationRow( this._view, constants.RESOURCE_GROUP, @@ -140,16 +139,15 @@ export class SummaryPage extends MigrationWizardPage { constants.IR_PAGE_TITLE), createInformationRow( this._view, constants.SUBSCRIPTION, - this.migrationStateModel._targetSubscription.name), + this.migrationStateModel._sqlMigrationServiceSubscription.name), createInformationRow( this._view, constants.LOCATION, - await this.migrationStateModel.getLocationDisplayName( - this.migrationStateModel._sqlMigrationService?.location!)), + this.migrationStateModel._location.displayName), createInformationRow( this._view, constants.RESOURCE_GROUP, - this.migrationStateModel._sqlMigrationService?.properties?.resourceGroup!), + this.migrationStateModel._sqlMigrationServiceResourceGroup.name), createInformationRow( this._view, constants.IR_PAGE_TITLE, diff --git a/extensions/sql-migration/src/wizard/targetSelectionPage.ts b/extensions/sql-migration/src/wizard/targetSelectionPage.ts index 7167379e76..3698cc736e 100644 --- a/extensions/sql-migration/src/wizard/targetSelectionPage.ts +++ b/extensions/sql-migration/src/wizard/targetSelectionPage.ts @@ -709,7 +709,10 @@ export class TargetSelectionPage extends MigrationWizardPage { if (selectedVm) { this.migrationStateModel._targetServerInstance = utils.deepClone(selectedVm)! as SqlVMServer; - this.migrationStateModel._vmInstanceView = await getVMInstanceView(this.migrationStateModel._targetServerInstance, this.migrationStateModel._azureAccount, this.migrationStateModel._targetSubscription); + this.migrationStateModel._vmInstanceView = await getVMInstanceView( + this.migrationStateModel._targetServerInstance, + this.migrationStateModel._azureAccount, + this.migrationStateModel._targetSubscription); this.wizard.message = { text: '' }; // validate power state from VM instance view @@ -870,45 +873,45 @@ export class TargetSelectionPage extends MigrationWizardPage { this._azureAccountsDropdown.loading = true; this.migrationStateModel._azureAccounts = await utils.getAzureAccounts(); - this._azureAccountsDropdown.values = await utils.getAzureAccountsDropdownValues(this.migrationStateModel._azureAccounts); - } finally { - this._azureAccountsDropdown.loading = false; const accountId = this.migrationStateModel._azureAccount?.displayInfo?.userId ?? this._serviceContext?.azureAccount?.displayInfo?.userId; + this._azureAccountsDropdown.values = await utils.getAzureAccountsDropdownValues(this.migrationStateModel._azureAccounts); utils.selectDefaultDropdownValue( this._azureAccountsDropdown, accountId, false); + } finally { + this._azureAccountsDropdown.loading = false; } } private async populateTenantsDropdown(): Promise { try { this._accountTenantDropdown.loading = true; - if (!utils.isAccountTokenStale(this.migrationStateModel._azureAccount) && - this.migrationStateModel._azureAccount?.properties?.tenants?.length > 0) { - this.migrationStateModel._accountTenants = utils.getAzureTenants(this.migrationStateModel._azureAccount); - - this._accountTenantDropdown.values = utils.getAzureTenantsDropdownValues(this.migrationStateModel._accountTenants); - } const tenantId = this.migrationStateModel._azureTenant?.id ?? this._serviceContext?.tenant?.id; + if (!utils.isAccountTokenStale(this.migrationStateModel._azureAccount) && + this.migrationStateModel._azureAccount?.properties?.tenants?.length > 0) { + this.migrationStateModel._accountTenants = utils.getAzureTenants(this.migrationStateModel._azureAccount); + this._accountTenantDropdown.values = utils.getAzureTenantsDropdownValues(this.migrationStateModel._accountTenants); + } + utils.selectDefaultDropdownValue( this._accountTenantDropdown, tenantId, true); + await this._azureAccountsDropdown.validate(); + } finally { + this._accountTenantDropdown.loading = false; await this._accountTenantFlexContainer.updateCssStyles( this.migrationStateModel._azureAccount?.properties?.tenants?.length > 1 ? { 'display': 'inline' } : { 'display': 'none' } ); - await this._azureAccountsDropdown.validate(); - } finally { - this._accountTenantDropdown.loading = false; } } @@ -916,19 +919,20 @@ export class TargetSelectionPage extends MigrationWizardPage { try { this._azureSubscriptionDropdown.loading = true; this.migrationStateModel._subscriptions = await utils.getAzureSubscriptions(this.migrationStateModel._azureAccount); - this._azureSubscriptionDropdown.values = await utils.getAzureSubscriptionsDropdownValues(this.migrationStateModel._subscriptions); - } catch (e) { - console.log(e); - } finally { - this._azureSubscriptionDropdown.loading = false; const subscriptionId = this.migrationStateModel._targetSubscription?.id ?? this._serviceContext?.subscription?.id; + this._azureSubscriptionDropdown.values = await utils.getAzureSubscriptionsDropdownValues(this.migrationStateModel._subscriptions); + utils.selectDefaultDropdownValue( this._azureSubscriptionDropdown, subscriptionId, false); + } catch (e) { + console.log(e); + } finally { + this._azureSubscriptionDropdown.loading = false; } } @@ -964,19 +968,20 @@ export class TargetSelectionPage extends MigrationWizardPage { this.migrationStateModel._targetSqlDatabaseServers); break; } - this._azureLocationDropdown.values = utils.getAzureLocationsDropdownValues(this.migrationStateModel._locations); - } catch (e) { - console.log(e); - } finally { - this._azureLocationDropdown.loading = false; + const location = this.migrationStateModel._location?.displayName ?? this._serviceContext?.location?.displayName; + this._azureLocationDropdown.values = utils.getAzureLocationsDropdownValues(this.migrationStateModel._locations); utils.selectDefaultDropdownValue( this._azureLocationDropdown, location, true); + } catch (e) { + console.log(e); + } finally { + this._azureLocationDropdown.loading = false; } } @@ -1000,24 +1005,29 @@ export class TargetSelectionPage extends MigrationWizardPage { this.migrationStateModel._location); break; } + + const resourceGroupId = this.migrationStateModel._resourceGroup?.id; + this._azureResourceGroupDropdown.values = utils.getResourceDropdownValues( this.migrationStateModel._resourceGroups, constants.RESOURCE_GROUP_NOT_FOUND); + + utils.selectDefaultDropdownValue( + this._azureResourceGroupDropdown, + resourceGroupId, + false); } catch (e) { console.log(e); } finally { this._azureResourceGroupDropdown.loading = false; - - utils.selectDefaultDropdownValue( - this._azureResourceGroupDropdown, - this.migrationStateModel._resourceGroup?.id, - false); } } private async populateResourceInstanceDropdown(): Promise { try { this._azureResourceDropdown.loading = true; + const targetName = this.migrationStateModel.migrationTargetServerName; + switch (this.migrationStateModel._targetType) { case MigrationTargetType.SQLMI: this._azureResourceDropdown.values = await utils.getManagedInstancesDropdownValues( @@ -1043,31 +1053,19 @@ export class TargetSelectionPage extends MigrationWizardPage { constants.NO_SQL_DATABASE_SERVER_FOUND); break; } - } finally { - this._azureResourceDropdown.loading = false; - let targetName = ''; - switch (this.migrationStateModel._targetType) { - case MigrationTargetType.SQLMI: - targetName = (this.migrationStateModel._targetServerInstance as azureResource.AzureSqlManagedInstance)?.name; - break; - case MigrationTargetType.SQLVM: - targetName = (this.migrationStateModel._targetServerInstance as SqlVMServer)?.name; - break; - case MigrationTargetType.SQLDB: - targetName = (this.migrationStateModel._targetServerInstance as AzureSqlDatabaseServer)?.name; - break; - } utils.selectDefaultDropdownValue( this._azureResourceDropdown, targetName, true); + } finally { + this._azureResourceDropdown.loading = false; } } private _updateTdeMigrationButtonStatus() { - - this.wizard.customButtons[TDE_MIGRATION_BUTTON_INDEX].enabled = this.migrationStateModel.tdeMigrationConfig.shouldAdsMigrateCertificates() && + this.wizard.customButtons[TDE_MIGRATION_BUTTON_INDEX].enabled = + this.migrationStateModel.tdeMigrationConfig.shouldAdsMigrateCertificates() && this.migrationStateModel._targetManagedInstances.length > 0; } diff --git a/extensions/sql-migration/src/wizard/wizardController.ts b/extensions/sql-migration/src/wizard/wizardController.ts index 754ece49c1..d29205ebfa 100644 --- a/extensions/sql-migration/src/wizard/wizardController.ts +++ b/extensions/sql-migration/src/wizard/wizardController.ts @@ -272,10 +272,7 @@ export class WizardController { stateModel: MigrationStateModel, serviceContextChangedEvent: vscode.EventEmitter): Promise { - const resourceGroup = this._getResourceGroupByName( - stateModel._resourceGroups, - stateModel._sqlMigrationService?.properties.resourceGroup); - + const resourceGroup = stateModel._sqlMigrationServiceResourceGroup; const subscription = this._getSubscriptionFromResourceId( stateModel._subscriptions, resourceGroup?.id); @@ -296,13 +293,6 @@ export class WizardController { serviceContextChangedEvent); } - private _getResourceGroupByName( - resourceGroups: azureResource.AzureResourceResourceGroup[], - displayName?: string): azureResource.AzureResourceResourceGroup | undefined { - - return resourceGroups.find(rg => rg.name === displayName); - } - private _getLocationByValue( locations: azureResource.AzureLocation[], name?: string): azureResource.AzureLocation | undefined {