diff --git a/extensions/azurecore/src/azureResource/azure-resource.d.ts b/extensions/azurecore/src/azureResource/azure-resource.d.ts index 46a080a9fa..1204b755d6 100644 --- a/extensions/azurecore/src/azureResource/azure-resource.d.ts +++ b/extensions/azurecore/src/azureResource/azure-resource.d.ts @@ -83,5 +83,7 @@ declare module 'azureResource' { export interface BlobContainer extends AzureResource { } export interface FileShare extends AzureResource { } + + export interface MigrationController extends AzureResource { } } } diff --git a/extensions/azurecore/src/azureResource/utils.ts b/extensions/azurecore/src/azureResource/utils.ts index 43c171fa4a..36cce59241 100644 --- a/extensions/azurecore/src/azureResource/utils.ts +++ b/extensions/azurecore/src/azureResource/utils.ts @@ -7,7 +7,7 @@ import { ResourceGraphClient } from '@azure/arm-resourcegraph'; import { TokenCredentials } from '@azure/ms-rest-js'; import axios, { AxiosRequestConfig } from 'axios'; import * as azdata from 'azdata'; -import { HttpGetRequestResult, GetResourceGroupsResult, GetSubscriptionsResult, ResourceQueryResult, GetBlobContainersResult, GetFileSharesResult } from 'azurecore'; +import { HttpGetRequestResult, GetResourceGroupsResult, GetSubscriptionsResult, ResourceQueryResult, GetBlobContainersResult, GetFileSharesResult, GetMigrationControllersResult } from 'azurecore'; import { azureResource } from 'azureResource'; import { EOL } from 'os'; import * as nls from 'vscode-nls'; @@ -369,7 +369,7 @@ export async function getBlobContainers(account: azdata.Account, subscription: a `/blobServices/default/containers?api-version=2019-06-01`; const response = await makeHttpGetRequest(account, subscription, ignoreErrors, apiEndpoint); return { - blobContainers: response.response.data.value, + blobContainers: response?.response?.data?.value ?? [], errors: response.errors ? response.errors : [] }; } @@ -382,7 +382,19 @@ export async function getFileShares(account: azdata.Account, subscription: azure `/fileServices/default/shares?api-version=2019-06-01`; const response = await makeHttpGetRequest(account, subscription, ignoreErrors, apiEndpoint); return { - fileShares: response.response.data.value, + fileShares: response?.response?.data?.value ?? [], + errors: response.errors ? response.errors : [] + }; +} + +export async function getMigrationControllers(account: azdata.Account, subscription: azureResource.AzureResourceSubscription, resourceGroupName: string, regionName: string, ignoreErrors: boolean): Promise { + const apiEndpoint = `https://${regionName}.management.azure.com` + + `/subscriptions/${subscription.id}` + + `/resourceGroups/${resourceGroupName}` + + `/providers/Microsoft.DataMigration/Controllers/default/shares?api-version=2020-09-01-preview`; + const response = await makeHttpGetRequest(account, subscription, ignoreErrors, apiEndpoint); + return { + controllers: response?.response?.data?.value ?? [], errors: response.errors ? response.errors : [] }; } diff --git a/extensions/azurecore/src/azurecore.d.ts b/extensions/azurecore/src/azurecore.d.ts index 1d1744988d..48479e3c1b 100644 --- a/extensions/azurecore/src/azurecore.d.ts +++ b/extensions/azurecore/src/azurecore.d.ts @@ -75,6 +75,8 @@ declare module 'azurecore' { getStorageAccounts(account: azdata.Account, subscriptions: azureResource.AzureResourceSubscription[], ignoreErrors?: boolean): Promise; getBlobContainers(account: azdata.Account, subscription: azureResource.AzureResourceSubscription, storageAccount: azureResource.AzureGraphResource, ignoreErrors?: boolean): Promise; getFileShares(account: azdata.Account, subscription: azureResource.AzureResourceSubscription, storageAccount: azureResource.AzureGraphResource, ignoreErrors?: boolean): Promise; + getMigrationControllers(account: azdata.Account, subscription: azureResource.AzureResourceSubscription, resourceGroupName: string, regionName: string, ignoreErrors?: boolean): Promise; + /** * Converts a region value (@see AzureRegion) into the localized Display Name * @param region The region value @@ -88,11 +90,12 @@ declare module 'azurecore' { export type GetSubscriptionsResult = { subscriptions: azureResource.AzureResourceSubscription[], errors: Error[] }; export type GetResourceGroupsResult = { resourceGroups: azureResource.AzureResourceResourceGroup[], errors: Error[] }; export type GetSqlManagedInstancesResult = { resources: azureResource.AzureGraphResource[], errors: Error[] }; - export type GetSqlServersResult = {resources: azureResource.AzureGraphResource[], errors: Error[]}; - export type GetSqlVMServersResult = {resources: azureResource.AzureGraphResource[], errors: Error[]}; - export type GetStorageAccountResult = {resources: azureResource.AzureGraphResource[], errors: Error[]}; - export type GetBlobContainersResult = {blobContainers: azureResource.BlobContainer[] | undefined, errors: Error[]}; - export type GetFileSharesResult = {fileShares: azureResource.FileShare[] | undefined, errors: Error[]}; + export type GetSqlServersResult = { resources: azureResource.AzureGraphResource[], errors: Error[] }; + export type GetSqlVMServersResult = { resources: azureResource.AzureGraphResource[], errors: Error[] }; + export type GetStorageAccountResult = { resources: azureResource.AzureGraphResource[], errors: Error[] }; + export type GetBlobContainersResult = { blobContainers: azureResource.BlobContainer[], errors: Error[] }; + export type GetFileSharesResult = { fileShares: azureResource.FileShare[], errors: Error[] }; + export type GetMigrationControllersResult = { controllers: azureResource.MigrationController[], errors: Error[] }; export type ResourceQueryResult = { resources: T[], errors: Error[] }; export type HttpGetRequestResult = { response: any, errors: Error[] }; diff --git a/extensions/azurecore/src/extension.ts b/extensions/azurecore/src/extension.ts index 711627e160..12e8cd980a 100644 --- a/extensions/azurecore/src/extension.ts +++ b/extensions/azurecore/src/extension.ts @@ -196,6 +196,13 @@ export async function activate(context: vscode.ExtensionContext): Promise { return azureResourceUtils.getFileShares(account, subscription, storageAccount, ignoreErrors); }, + getMigrationControllers(account: azdata.Account, + subscription: azureResource.AzureResourceSubscription, + resourceGroupName: string, + regionName: string, + ignoreErrors: boolean): Promise { + return azureResourceUtils.getMigrationControllers(account, subscription, resourceGroupName, regionName, ignoreErrors); + }, getRegionDisplayName: utils.getRegionDisplayName, runGraphQuery(account: azdata.Account, subscriptions: azureResource.AzureResourceSubscription[], diff --git a/extensions/machine-learning/src/test/stubs.ts b/extensions/machine-learning/src/test/stubs.ts index 7f293b6b30..07f2914d3e 100644 --- a/extensions/machine-learning/src/test/stubs.ts +++ b/extensions/machine-learning/src/test/stubs.ts @@ -8,6 +8,9 @@ import * as azurecore from 'azurecore'; import { azureResource } from 'azureResource'; export class AzurecoreApiStub implements azurecore.IExtension { + getMigrationControllers(_account: azdata.Account, _subscription: azureResource.AzureResourceSubscription, _resourceGroupName: string, _regionName: string, _ignoreErrors?: boolean): Promise { + throw new Error('Method not implemented.'); + } getFileShares(_account: azdata.Account, _subscription: azureResource.AzureResourceSubscription, _storageAccount: azureResource.AzureGraphResource, _ignoreErrors?: boolean): Promise { throw new Error('Method not implemented.'); } diff --git a/extensions/sql-migration/src/api/azure.ts b/extensions/sql-migration/src/api/azure.ts index 26bc839af2..9a0f87c0f6 100644 --- a/extensions/sql-migration/src/api/azure.ts +++ b/extensions/sql-migration/src/api/azure.ts @@ -21,20 +21,19 @@ export async function getSubscriptions(account: azdata.Account): Promise { - if (a.name < b.name) { - return -1; - } - if (a.name > b.name) { - return 1; - } - return 0; - }); + sortResourceArrayByName(listOfSubscriptions); return subscriptions.subscriptions; } export type AzureProduct = azureResource.AzureGraphResource; +export async function getResourceGroups(account: azdata.Account, subscription: Subscription): Promise { + const api = await getAzureCoreAPI(); + const result = await api.getResourceGroups(account, subscription, false); + sortResourceArrayByName(result.resourceGroups); + return result.resourceGroups; +} + export type SqlManagedInstance = AzureProduct; export async function getAvailableManagedInstanceProducts(account: azdata.Account, subscription: Subscription): Promise { const api = await getAzureCoreAPI(); @@ -71,7 +70,7 @@ export async function getFileShares(account: azdata.Account, subscription: Subsc const api = await getAzureCoreAPI(); let result = await api.getFileShares(account, subscription, storageAccount, true); let fileShares = result.fileShares; - sortResourceArrayByName(fileShares!); + sortResourceArrayByName(fileShares); return fileShares!; } @@ -79,19 +78,28 @@ export async function getBlobContainers(account: azdata.Account, subscription: S const api = await getAzureCoreAPI(); let result = await api.getBlobContainers(account, subscription, storageAccount, true); let blobContainers = result.blobContainers; - sortResourceArrayByName(blobContainers!); + sortResourceArrayByName(blobContainers); return blobContainers!; } -function sortResourceArrayByName(resourceArray: AzureProduct[] | azureResource.FileShare[] | azureResource.BlobContainer[] | undefined): void { +export async function getMigrationControllers(account: azdata.Account, subscription: Subscription, resourceGroupName: string, regionName: string): Promise { + const api = await getAzureCoreAPI(); + let result = await api.getMigrationControllers(account, subscription, resourceGroupName, regionName, true); + let controllers = result.controllers; + sortResourceArrayByName(controllers); + return controllers!; +} + +type SortableAzureResources = AzureProduct | azureResource.FileShare | azureResource.BlobContainer | azureResource.MigrationController | azureResource.AzureResourceSubscription; +function sortResourceArrayByName(resourceArray: SortableAzureResources[]): void { if (!resourceArray) { return; } - resourceArray.sort((a: AzureProduct | azureResource.BlobContainer | azureResource.FileShare, b: AzureProduct | azureResource.BlobContainer | azureResource.FileShare) => { - if (a.name! < b.name!) { + resourceArray.sort((a: SortableAzureResources, b: SortableAzureResources) => { + if (a.name.toLowerCase() < b.name.toLowerCase()) { return -1; } - if (a.name! > b.name!) { + if (a.name.toLowerCase() > b.name.toLowerCase()) { return 1; } return 0;