mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-27 17:23:21 -05:00
[SQL Migration] List resource groups based on available resources (#18846)
* WIP - implemented logic to show resource groups as derived from list of resources, instead of directly listing all resource groups * Remove comments * Remove getResourceGroupByName and craft resource group object manually instead * Update subscription and location list when tenant is changed * Define Azure resource types locally instead of modifying azurecore * Add SQL VM scenario * Split getAzureResourceGroupDropdownValues into four separate functions * Refresh only subscription list when tenant is changed * Create new DMS dialog should show all resource groups * Remove unnecessary async code
This commit is contained in:
@@ -99,9 +99,9 @@ export type SqlVMServer = {
|
||||
tenantId: string,
|
||||
subscriptionId: string
|
||||
};
|
||||
export async function getAvailableSqlVMs(account: azdata.Account, subscription: Subscription, resourceGroup: azureResource.AzureResourceResourceGroup): Promise<SqlVMServer[]> {
|
||||
export async function getAvailableSqlVMs(account: azdata.Account, subscription: Subscription): Promise<SqlVMServer[]> {
|
||||
const api = await getAzureCoreAPI();
|
||||
const path = encodeURI(`/subscriptions/${subscription.id}/resourceGroups/${resourceGroup.name}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachines?api-version=2017-03-01-preview`);
|
||||
const path = encodeURI(`/subscriptions/${subscription.id}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachines?api-version=2021-11-01-preview`);
|
||||
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.GET, undefined, true);
|
||||
if (response.errors.length > 0) {
|
||||
throw new Error(response.errors.toString());
|
||||
@@ -153,10 +153,10 @@ export async function getSqlMigrationService(account: azdata.Account, subscripti
|
||||
return response.response.data;
|
||||
}
|
||||
|
||||
export async function getSqlMigrationServices(account: azdata.Account, subscription: Subscription, resouceGroupName: string, sessionId: string): Promise<SqlMigrationService[]> {
|
||||
export async function getSqlMigrationServices(account: azdata.Account, subscription: Subscription): Promise<SqlMigrationService[]> {
|
||||
const api = await getAzureCoreAPI();
|
||||
const path = encodeURI(`/subscriptions/${subscription.id}/resourceGroups/${resouceGroupName}/providers/Microsoft.DataMigration/sqlMigrationServices?api-version=2020-09-01-preview`);
|
||||
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.GET, undefined, true, undefined, getSessionIdHeader(sessionId));
|
||||
const path = encodeURI(`/subscriptions/${subscription.id}/providers/Microsoft.DataMigration/sqlMigrationServices?api-version=2022-01-30-preview`);
|
||||
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.GET, undefined, true);
|
||||
if (response.errors.length > 0) {
|
||||
throw new Error(response.errors.toString());
|
||||
}
|
||||
@@ -339,7 +339,7 @@ export async function getLocationDisplayName(location: string): Promise<string>
|
||||
}
|
||||
|
||||
type SortableAzureResources = AzureProduct | azureResource.FileShare | azureResource.BlobContainer | azureResource.Blob | azureResource.AzureResourceSubscription | SqlMigrationService;
|
||||
function sortResourceArrayByName(resourceArray: SortableAzureResources[]): void {
|
||||
export function sortResourceArrayByName(resourceArray: SortableAzureResources[]): void {
|
||||
if (!resourceArray) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import { azureResource } from 'azureResource';
|
||||
import * as azurecore from 'azurecore';
|
||||
import * as vscode from 'vscode';
|
||||
import * as mssql from 'mssql';
|
||||
import { getAvailableManagedInstanceProducts, getAvailableStorageAccounts, getBlobContainers, getFileShares, getSqlMigrationServices, getSubscriptions, SqlMigrationService, SqlManagedInstance, startDatabaseMigration, StartDatabaseMigrationRequest, StorageAccount, getAvailableSqlVMs, SqlVMServer, getLocations, getResourceGroups, getLocationDisplayName, getSqlManagedInstanceDatabases, getBlobs } from '../api/azure';
|
||||
import { getAvailableManagedInstanceProducts, getAvailableStorageAccounts, getBlobContainers, getFileShares, getSqlMigrationServices, getSubscriptions, SqlMigrationService, SqlManagedInstance, startDatabaseMigration, StartDatabaseMigrationRequest, StorageAccount, getAvailableSqlVMs, SqlVMServer, getLocations, getLocationDisplayName, getSqlManagedInstanceDatabases, getBlobs, sortResourceArrayByName, getFullResourceGroupFromId, getResourceGroupFromId, getResourceGroups } from '../api/azure';
|
||||
import * as constants from '../constants/strings';
|
||||
import { MigrationLocalStorage } from './migrationLocalStorage';
|
||||
import * as nls from 'vscode-nls';
|
||||
@@ -78,6 +78,7 @@ export enum PerformanceDataSourceOptions {
|
||||
CollectData = 'CollectData',
|
||||
OpenExisting = 'OpenExisting',
|
||||
}
|
||||
|
||||
export interface DatabaseBackupModel {
|
||||
migrationMode: MigrationMode;
|
||||
networkContainerType: NetworkContainerType;
|
||||
@@ -961,6 +962,203 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
} else {
|
||||
this._resourceGroups = [];
|
||||
}
|
||||
this._resourceGroups.forEach((rg) => {
|
||||
resourceGroupValues.push({
|
||||
name: rg.id,
|
||||
displayName: rg.name
|
||||
});
|
||||
});
|
||||
if (resourceGroupValues.length === 0) {
|
||||
resourceGroupValues = [
|
||||
{
|
||||
displayName: constants.RESOURCE_GROUP_NOT_FOUND,
|
||||
name: ''
|
||||
}
|
||||
];
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
resourceGroupValues = [
|
||||
{
|
||||
displayName: constants.RESOURCE_GROUP_NOT_FOUND,
|
||||
name: ''
|
||||
}
|
||||
];
|
||||
}
|
||||
return resourceGroupValues;
|
||||
}
|
||||
|
||||
public async getAzureResourceGroupForManagedInstancesDropdownValues(subscription: azureResource.AzureResourceSubscription): Promise<azdata.CategoryValue[]> {
|
||||
let resourceGroupValues: azdata.CategoryValue[] = [];
|
||||
try {
|
||||
if (this._azureAccount && subscription) {
|
||||
let managedInstances = await getAvailableManagedInstanceProducts(this._azureAccount, subscription);
|
||||
this._resourceGroups = managedInstances.map((mi) => {
|
||||
return <azureResource.AzureResourceResourceGroup>{
|
||||
id: getFullResourceGroupFromId(mi.id),
|
||||
name: getResourceGroupFromId(mi.id),
|
||||
subscription: {
|
||||
id: mi.subscriptionId
|
||||
},
|
||||
tenant: mi.tenantId,
|
||||
};
|
||||
});
|
||||
|
||||
// remove duplicates
|
||||
this._resourceGroups = this._resourceGroups.filter((v, i, a) => a.findIndex(v2 => (v2.id === v.id)) === i);
|
||||
sortResourceArrayByName(this._resourceGroups);
|
||||
} else {
|
||||
this._resourceGroups = [];
|
||||
}
|
||||
|
||||
this._resourceGroups.forEach((rg) => {
|
||||
resourceGroupValues.push({
|
||||
name: rg.id,
|
||||
displayName: rg.name
|
||||
});
|
||||
});
|
||||
|
||||
if (resourceGroupValues.length === 0) {
|
||||
resourceGroupValues = [
|
||||
{
|
||||
displayName: constants.RESOURCE_GROUP_NOT_FOUND,
|
||||
name: ''
|
||||
}
|
||||
];
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
resourceGroupValues = [
|
||||
{
|
||||
displayName: constants.RESOURCE_GROUP_NOT_FOUND,
|
||||
name: ''
|
||||
}
|
||||
];
|
||||
}
|
||||
return resourceGroupValues;
|
||||
}
|
||||
|
||||
public async getAzureResourceGroupForVirtualMachinesDropdownValues(subscription: azureResource.AzureResourceSubscription): Promise<azdata.CategoryValue[]> {
|
||||
let resourceGroupValues: azdata.CategoryValue[] = [];
|
||||
try {
|
||||
if (this._azureAccount && subscription) {
|
||||
let virtualMachines = await getAvailableSqlVMs(this._azureAccount, subscription);
|
||||
this._resourceGroups = virtualMachines.map((vm) => {
|
||||
return <azureResource.AzureResourceResourceGroup>{
|
||||
id: getFullResourceGroupFromId(vm.id),
|
||||
name: getResourceGroupFromId(vm.id),
|
||||
subscription: {
|
||||
id: vm.subscriptionId
|
||||
},
|
||||
tenant: vm.tenantId,
|
||||
};
|
||||
});
|
||||
|
||||
// remove duplicates
|
||||
this._resourceGroups = this._resourceGroups.filter((v, i, a) => a.findIndex(v2 => (v2.id === v.id)) === i);
|
||||
sortResourceArrayByName(this._resourceGroups);
|
||||
} else {
|
||||
this._resourceGroups = [];
|
||||
}
|
||||
|
||||
this._resourceGroups.forEach((rg) => {
|
||||
resourceGroupValues.push({
|
||||
name: rg.id,
|
||||
displayName: rg.name
|
||||
});
|
||||
});
|
||||
|
||||
if (resourceGroupValues.length === 0) {
|
||||
resourceGroupValues = [
|
||||
{
|
||||
displayName: constants.RESOURCE_GROUP_NOT_FOUND,
|
||||
name: ''
|
||||
}
|
||||
];
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
resourceGroupValues = [
|
||||
{
|
||||
displayName: constants.RESOURCE_GROUP_NOT_FOUND,
|
||||
name: ''
|
||||
}
|
||||
];
|
||||
}
|
||||
return resourceGroupValues;
|
||||
}
|
||||
|
||||
public async getAzureResourceGroupForStorageAccountsDropdownValues(subscription: azureResource.AzureResourceSubscription): Promise<azdata.CategoryValue[]> {
|
||||
let resourceGroupValues: azdata.CategoryValue[] = [];
|
||||
try {
|
||||
if (this._azureAccount && subscription) {
|
||||
let storageAccounts = await getAvailableStorageAccounts(this._azureAccount, subscription);
|
||||
this._resourceGroups = storageAccounts.map((sa) => {
|
||||
return <azureResource.AzureResourceResourceGroup>{
|
||||
id: getFullResourceGroupFromId(sa.id),
|
||||
name: getResourceGroupFromId(sa.id),
|
||||
subscription: {
|
||||
id: sa.subscriptionId
|
||||
},
|
||||
tenant: sa.tenantId,
|
||||
};
|
||||
});
|
||||
|
||||
// remove duplicates
|
||||
this._resourceGroups = this._resourceGroups.filter((v, i, a) => a.findIndex(v2 => (v2.id === v.id)) === i);
|
||||
sortResourceArrayByName(this._resourceGroups);
|
||||
} else {
|
||||
this._resourceGroups = [];
|
||||
}
|
||||
|
||||
this._resourceGroups.forEach((rg) => {
|
||||
resourceGroupValues.push({
|
||||
name: rg.id,
|
||||
displayName: rg.name
|
||||
});
|
||||
});
|
||||
|
||||
if (resourceGroupValues.length === 0) {
|
||||
resourceGroupValues = [
|
||||
{
|
||||
displayName: constants.RESOURCE_GROUP_NOT_FOUND,
|
||||
name: ''
|
||||
}
|
||||
];
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
resourceGroupValues = [
|
||||
{
|
||||
displayName: constants.RESOURCE_GROUP_NOT_FOUND,
|
||||
name: ''
|
||||
}
|
||||
];
|
||||
}
|
||||
return resourceGroupValues;
|
||||
}
|
||||
|
||||
public async getAzureResourceGroupForSqlMigrationServicesDropdownValues(subscription: azureResource.AzureResourceSubscription): Promise<azdata.CategoryValue[]> {
|
||||
let resourceGroupValues: azdata.CategoryValue[] = [];
|
||||
try {
|
||||
if (this._azureAccount && subscription) {
|
||||
let dmsInstances = await getSqlMigrationServices(this._azureAccount, subscription);
|
||||
this._resourceGroups = dmsInstances.map((dms) => {
|
||||
return <azureResource.AzureResourceResourceGroup>{
|
||||
id: getFullResourceGroupFromId(dms.id),
|
||||
name: getResourceGroupFromId(dms.id),
|
||||
subscription: {
|
||||
id: dms.properties.subscriptionId
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// remove duplicates
|
||||
this._resourceGroups = this._resourceGroups.filter((v, i, a) => a.findIndex(v2 => (v2.id === v.id)) === i);
|
||||
sortResourceArrayByName(this._resourceGroups);
|
||||
} else {
|
||||
this._resourceGroups = [];
|
||||
}
|
||||
|
||||
this._resourceGroups.forEach((rg) => {
|
||||
resourceGroupValues.push({
|
||||
@@ -1059,8 +1257,8 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
let virtualMachineValues: azdata.CategoryValue[] = [];
|
||||
try {
|
||||
if (this._azureAccount && subscription && location && resourceGroup) {
|
||||
this._targetSqlVirtualMachines = (await getAvailableSqlVMs(this._azureAccount, subscription, resourceGroup)).filter((virtualMachine) => {
|
||||
if (virtualMachine?.location?.toLowerCase() === location?.name?.toLowerCase()) {
|
||||
this._targetSqlVirtualMachines = (await getAvailableSqlVMs(this._azureAccount, subscription)).filter((virtualMachine) => {
|
||||
if (virtualMachine?.location?.toLowerCase() === location?.name?.toLowerCase() && getResourceGroupFromId(virtualMachine.id).toLowerCase() === resourceGroup?.name.toLowerCase()) {
|
||||
if (virtualMachine.properties.sqlImageOffer) {
|
||||
return virtualMachine.properties.sqlImageOffer.toLowerCase().includes('-ws'); //filtering out all non windows sql vms.
|
||||
}
|
||||
@@ -1068,6 +1266,7 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
virtualMachineValues = this._targetSqlVirtualMachines.map((virtualMachine) => {
|
||||
return {
|
||||
name: virtualMachine.id,
|
||||
@@ -1272,7 +1471,7 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
let sqlMigrationServiceValues: azdata.CategoryValue[] = [];
|
||||
try {
|
||||
if (this._azureAccount && subscription && resourceGroupName && this._targetServerInstance) {
|
||||
this._sqlMigrationServices = (await getSqlMigrationServices(this._azureAccount, subscription, resourceGroupName?.toLowerCase(), this._sessionId)).filter(sms => sms.location.toLowerCase() === this._targetServerInstance.location.toLowerCase());
|
||||
this._sqlMigrationServices = (await getSqlMigrationServices(this._azureAccount, subscription)).filter(sms => sms.location.toLowerCase() === this._targetServerInstance.location.toLowerCase() && sms.properties.resourceGroup.toLowerCase() === resourceGroupName.toLowerCase());
|
||||
} else {
|
||||
this._sqlMigrationServices = [];
|
||||
}
|
||||
|
||||
@@ -1261,7 +1261,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
private async loadNetworkStorageResourceGroup(): Promise<void> {
|
||||
this._networkShareStorageAccountResourceGroupDropdown.loading = true;
|
||||
try {
|
||||
this._networkShareStorageAccountResourceGroupDropdown.values = await this.migrationStateModel.getAzureResourceGroupDropdownValues(this.migrationStateModel._databaseBackup.subscription);
|
||||
this._networkShareStorageAccountResourceGroupDropdown.values = await this.migrationStateModel.getAzureResourceGroupForStorageAccountsDropdownValues(this.migrationStateModel._databaseBackup.subscription);
|
||||
selectDefaultDropdownValue(this._networkShareStorageAccountResourceGroupDropdown, this.migrationStateModel._databaseBackup?.networkShares[0]?.resourceGroup?.id, false);
|
||||
} catch (error) {
|
||||
logError(TelemetryViews.DatabaseBackupPage, 'ErrorLoadingNetworkStorageResourceGroup', error);
|
||||
@@ -1288,7 +1288,7 @@ export class DatabaseBackupPage extends MigrationWizardPage {
|
||||
private async loadBlobResourceGroup(): Promise<void> {
|
||||
this._blobContainerResourceGroupDropdowns.forEach(v => v.loading = true);
|
||||
try {
|
||||
const resourceGroupValues = await this.migrationStateModel.getAzureResourceGroupDropdownValues(this.migrationStateModel._databaseBackup.subscription);
|
||||
const resourceGroupValues = await this.migrationStateModel.getAzureResourceGroupForStorageAccountsDropdownValues(this.migrationStateModel._databaseBackup.subscription);
|
||||
this._blobContainerResourceGroupDropdowns.forEach((dropDown, index) => {
|
||||
dropDown.values = resourceGroupValues;
|
||||
selectDefaultDropdownValue(dropDown, this.migrationStateModel._databaseBackup?.blobs[index]?.resourceGroup?.id, false);
|
||||
|
||||
@@ -379,7 +379,7 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
|
||||
this._resourceGroupDropdown.loading = true;
|
||||
this._dmsDropdown.loading = true;
|
||||
try {
|
||||
this._resourceGroupDropdown.values = await this.migrationStateModel.getAzureResourceGroupDropdownValues(this.migrationStateModel._targetSubscription);
|
||||
this._resourceGroupDropdown.values = await this.migrationStateModel.getAzureResourceGroupForSqlMigrationServicesDropdownValues(this.migrationStateModel._targetSubscription);
|
||||
const resourceGroup = (this.migrationStateModel._sqlMigrationService)
|
||||
? getFullResourceGroupFromId(this.migrationStateModel._sqlMigrationService?.id)
|
||||
: undefined;
|
||||
|
||||
@@ -252,7 +252,7 @@ export class TargetSelectionPage extends MigrationWizardPage {
|
||||
fireOnTextChange: true,
|
||||
}).component();
|
||||
|
||||
this._disposables.push(this._accountTenantDropdown.onValueChanged(value => {
|
||||
this._disposables.push(this._accountTenantDropdown.onValueChanged(async (value) => {
|
||||
/**
|
||||
* Replacing all the tenants in azure account with the tenant user has selected.
|
||||
* All azure requests will only run on this tenant from now on
|
||||
@@ -263,6 +263,7 @@ export class TargetSelectionPage extends MigrationWizardPage {
|
||||
if (selectedIndex > -1) {
|
||||
this.migrationStateModel._azureAccount.properties.tenants = [this.migrationStateModel.getTenant(selectedIndex)];
|
||||
}
|
||||
await this.populateSubscriptionDropdown();
|
||||
}));
|
||||
|
||||
this._accountTenantFlexContainer = this._view.modelBuilder.flexContainer()
|
||||
@@ -480,7 +481,14 @@ export class TargetSelectionPage extends MigrationWizardPage {
|
||||
public async populateResourceGroupDropdown(): Promise<void> {
|
||||
try {
|
||||
this.updateDropdownLoadingStatus(TargetDropDowns.ResourceGroup, true);
|
||||
this._azureResourceGroupDropdown.values = await this.migrationStateModel.getAzureResourceGroupDropdownValues(this.migrationStateModel._targetSubscription);
|
||||
switch (this.migrationStateModel._targetType) {
|
||||
case MigrationTargetType.SQLMI:
|
||||
this._azureResourceGroupDropdown.values = await this.migrationStateModel.getAzureResourceGroupForManagedInstancesDropdownValues(this.migrationStateModel._targetSubscription);
|
||||
break;
|
||||
case MigrationTargetType.SQLVM:
|
||||
this._azureResourceGroupDropdown.values = await this.migrationStateModel.getAzureResourceGroupForVirtualMachinesDropdownValues(this.migrationStateModel._targetSubscription);
|
||||
break;
|
||||
}
|
||||
selectDefaultDropdownValue(this._azureResourceGroupDropdown, this.migrationStateModel._resourceGroup?.id, false);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
|
||||
Reference in New Issue
Block a user