From ccd5775093ae31e05734aa99ae7ad51db65fa5ca Mon Sep 17 00:00:00 2001 From: Christopher Suh Date: Fri, 31 Mar 2023 12:22:31 -0700 Subject: [PATCH] Update remaining Axios calls (#22525) * initial commit adding put and delete operations * change response.data => response.body * add client response interface * add error to interface * add reqHeaders --- .../src/account-provider/auths/httpClient.ts | 43 ++++++++++++- .../azurecore/src/azureResource/utils.ts | 47 +++++++++----- extensions/sql-migration/src/api/azure.ts | 64 +++++++++---------- 3 files changed, 102 insertions(+), 52 deletions(-) diff --git a/extensions/azurecore/src/account-provider/auths/httpClient.ts b/extensions/azurecore/src/account-provider/auths/httpClient.ts index d1553579ec..224f3ef6b0 100644 --- a/extensions/azurecore/src/account-provider/auths/httpClient.ts +++ b/extensions/azurecore/src/account-provider/auths/httpClient.ts @@ -14,7 +14,9 @@ import { NetworkUtils } from './networkUtils'; */ export enum HttpMethod { GET = 'get', - POST = 'post' + POST = 'post', + PUT = 'put', + DELETE = 'delete' } export enum HttpStatus { @@ -81,6 +83,40 @@ export class HttpClient implements INetworkModule { return networkRequestViaHttps(url, HttpMethod.POST, options, this.customAgentOptions as https.AgentOptions, cancellationToken); } } + + /** + * Http Put request + * @param url + * @param options + */ + async sendPutRequestAsync( + url: string, + options?: NetworkRequestOptions, + cancellationToken?: number + ): Promise> { + if (this.proxyUrl) { + return networkRequestViaProxy(url, this.proxyUrl, HttpMethod.PUT, options, this.customAgentOptions as http.AgentOptions, cancellationToken); + } else { + return networkRequestViaHttps(url, HttpMethod.PUT, options, this.customAgentOptions as https.AgentOptions, cancellationToken); + } + } + + /** + * Http Delete request + * @param url + * @param options + */ + async sendDeleteRequestAsync( + url: string, + options?: NetworkRequestOptions + ): Promise> { + if (this.proxyUrl) { + return networkRequestViaProxy(url, this.proxyUrl, HttpMethod.DELETE, options, this.customAgentOptions as http.AgentOptions); + } else { + return networkRequestViaHttps(url, HttpMethod.DELETE, options, this.customAgentOptions as https.AgentOptions); + } + } + } const networkRequestViaProxy = ( @@ -114,7 +150,7 @@ const networkRequestViaProxy = ( // compose a request string for the socket let postRequestStringContent: string = ''; - if (httpMethod === HttpMethod.POST) { + if (httpMethod === HttpMethod.POST || httpMethod === HttpMethod.PUT) { const body = options?.body || ''; postRequestStringContent = 'Content-Type: application/x-www-form-urlencoded\r\n' + @@ -247,6 +283,7 @@ const networkRequestViaHttps = ( timeout?: number ): Promise> => { const isPostRequest = httpMethod === HttpMethod.POST; + const isPutRequest = httpMethod === HttpMethod.PUT; const body: string = options?.body || ''; const url = new URL(urlString); const optionHeaders = options?.headers || {} as Record; @@ -264,7 +301,7 @@ const networkRequestViaHttps = ( customOptions.agent = new https.Agent(agentOptions); } - if (isPostRequest) { + if (isPostRequest || isPutRequest) { // needed for post request to work customOptions.headers = { ...customOptions.headers, diff --git a/extensions/azurecore/src/azureResource/utils.ts b/extensions/azurecore/src/azureResource/utils.ts index 6fdb90463d..83bf3fb7cc 100644 --- a/extensions/azurecore/src/azureResource/utils.ts +++ b/extensions/azurecore/src/azureResource/utils.ts @@ -5,7 +5,6 @@ import { ResourceGraphClient } from '@azure/arm-resourcegraph'; import { TokenCredentials } from '@azure/ms-rest-js'; -import axios, { AxiosRequestConfig, AxiosResponse } from 'axios'; import * as azdata from 'azdata'; import { AzureRestResponse, GetResourceGroupsResult, GetSubscriptionsResult, ResourceQueryResult, GetBlobContainersResult, GetFileSharesResult, HttpRequestMethod, GetLocationsResult, GetManagedDatabasesResult, CreateResourceGroupResult, GetBlobsResult, GetStorageAccountAccessKeyResult, AzureAccount, azureResource, AzureAccountProviderMetadata } from 'azurecore'; import { EOL } from 'os'; @@ -18,9 +17,19 @@ import { AzureResourceGroupService } from './providers/resourceGroup/resourceGro import { BlobServiceClient, StorageSharedKeyCredential } from '@azure/storage-blob'; import providerSettings from '../account-provider/providerSettings'; import * as Constants from '../constants'; +import { getProxyEnabledHttpClient } from '../utils'; +import { HttpClient } from '../account-provider/auths/httpClient'; +import { NetworkRequestOptions } from '@azure/msal-common'; const localize = nls.loadMessageBundle(); +export interface HttpClientResponse { + body: any; + headers: any; + status: Number; + error: any; +} + function getErrorMessage(error: Error | string): string { return (error instanceof Error) ? error.message : error; } @@ -162,7 +171,7 @@ export async function getLocations(appContext: AppContext, account?: AzureAccoun const path = `/subscriptions/${subscription.id}/locations?api-version=2020-01-01`; const host = getProviderMetadataForAccount(account).settings.armResource.endpoint; const response = await makeHttpRequest(account, subscription, path, HttpRequestMethod.GET, undefined, ignoreErrors, host); - result.locations.push(...response.response.data.value); + result.locations.push(...response.response.body.value); result.errors.push(...response.errors); } catch (err) { const error = new Error(localize('azure.accounts.getLocations.queryError', "Error fetching locations for account {0} ({1}) subscription {2} ({3}) tenant {4} : {5}", @@ -341,6 +350,7 @@ export async function getSelectedSubscriptions(appContext: AppContext, account?: */ export async function makeHttpRequest(account: AzureAccount, subscription: azureResource.AzureResourceSubscription, path: string, requestType: HttpRequestMethod, requestBody?: any, ignoreErrors: boolean = false, host: string = 'https://management.azure.com', requestHeaders: { [key: string]: string } = {}): Promise { const result: AzureRestResponse = { response: {}, errors: [] }; + const httpClient: HttpClient = getProxyEnabledHttpClient(); if (!account?.properties?.tenants || !Array.isArray(account.properties.tenants)) { const error = new Error(invalidAzureAccount); @@ -380,15 +390,15 @@ export async function makeHttpRequest(account: AzureAccount, subscription: azure return result; } - const reqHeaders = { + let reqHeaders = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${securityToken.token}`, ...requestHeaders - }; + } - const config: AxiosRequestConfig = { + let networkRequestOptions: NetworkRequestOptions = { headers: reqHeaders, - validateStatus: () => true // Never throw + body: requestBody }; // Adding '/' if path does not begin with it. @@ -403,19 +413,23 @@ export async function makeHttpRequest(account: AzureAccount, subscription: azure requestUrl = `${account.properties.providerSettings.settings.armResource.endpoint}${path}`; } - let response: AxiosResponse | undefined; + let response; switch (requestType) { case HttpRequestMethod.GET: - response = await axios.get(requestUrl, config); + response = await httpClient.sendGetRequestAsync(requestUrl, { + headers: reqHeaders + }); break; case HttpRequestMethod.POST: - response = await axios.post(requestUrl, requestBody, config); + response = await httpClient.sendPostRequestAsync(requestUrl, networkRequestOptions); break; case HttpRequestMethod.PUT: - response = await axios.put(requestUrl, requestBody, config); + response = await httpClient.sendPutRequestAsync(requestUrl, networkRequestOptions); break; case HttpRequestMethod.DELETE: - response = await axios.delete(requestUrl, config); + response = await httpClient.sendDeleteRequestAsync(requestUrl, { + headers: reqHeaders + }); break; default: const error = new Error(`Unknown RequestType "${requestType}"`); @@ -434,9 +448,8 @@ export async function makeHttpRequest(account: AzureAccount, subscription: azure } else if (response.status < 200 || response.status > 299) { let errorMessage: string[] = []; errorMessage.push(response.status.toString()); - errorMessage.push(response.statusText); - if (response.data && response.data.error) { - errorMessage.push(`${response.data.error.code} : ${response.data.error.message}`); + if (response.body && response.body.error) { + errorMessage.push(`${response.body.error.code} : ${response.body.error.message}`); } const error = new Error(errorMessage.join(EOL)); if (!ignoreErrors) { @@ -455,7 +468,7 @@ export async function getManagedDatabases(account: AzureAccount, subscription: a const host = getProviderMetadataForAccount(account).settings.armResource.endpoint; const response = await makeHttpRequest(account, subscription, path, HttpRequestMethod.GET, undefined, ignoreErrors, host); return { - databases: response?.response?.data?.value ?? [], + databases: response?.response?.body?.value ?? [], errors: response.errors ? response.errors : [] }; } @@ -465,7 +478,7 @@ export async function getBlobContainers(account: AzureAccount, subscription: azu const host = getProviderMetadataForAccount(account).settings.armResource.endpoint; const response = await makeHttpRequest(account, subscription, path, HttpRequestMethod.GET, undefined, ignoreErrors, host); return { - blobContainers: response?.response?.data?.value ?? [], + blobContainers: response?.response?.body?.value ?? [], errors: response.errors ? response.errors : [] }; } @@ -475,7 +488,7 @@ export async function getFileShares(account: AzureAccount, subscription: azureRe const host = getProviderMetadataForAccount(account).settings.armResource.endpoint; const response = await makeHttpRequest(account, subscription, path, HttpRequestMethod.GET, undefined, ignoreErrors, host); return { - fileShares: response?.response?.data?.value ?? [], + fileShares: response?.response?.body?.value ?? [], errors: response.errors ? response.errors : [] }; } diff --git a/extensions/sql-migration/src/api/azure.ts b/extensions/sql-migration/src/api/azure.ts index 44196cfe20..a436830c8a 100644 --- a/extensions/sql-migration/src/api/azure.ts +++ b/extensions/sql-migration/src/api/azure.ts @@ -43,7 +43,7 @@ export async function getLocations(account: azdata.Account, subscription: Subscr const path = `/subscriptions/${subscription.id}/providers/Microsoft.DataMigration?api-version=${ARM_MGMT_API_VERSION}`; const host = api.getProviderMetadataForAccount(account).settings.armResource?.endpoint; - const dataMigrationResourceProvider = (await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.GET, undefined, true, host))?.response?.data; + const dataMigrationResourceProvider = (await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.GET, undefined, true, host))?.response?.body; const sqlMigratonResource = dataMigrationResourceProvider?.resourceTypes?.find((r: any) => r.resourceType === 'SqlMigrationServices'); const sqlMigrationResourceLocations = sqlMigratonResource?.locations ?? []; if (response.errors?.length > 0) { @@ -245,8 +245,8 @@ export async function getAvailableSqlDatabaseServers(account: azdata.Account, su .join(', '); throw new Error(message); } - sortResourceArrayByName(response.response.data.value); - return response.response.data.value; + sortResourceArrayByName(response.response.body.value); + return response.response.body.value; } export async function getAvailableSqlDatabases(account: azdata.Account, subscription: Subscription, resourceGroupName: string, serverName: string): Promise { @@ -260,8 +260,8 @@ export async function getAvailableSqlDatabases(account: azdata.Account, subscrip .join(', '); throw new Error(message); } - sortResourceArrayByName(response.response.data.value); - return response.response.data.value; + sortResourceArrayByName(response.response.body.value); + return response.response.body.value; } export async function getAvailableSqlVMs(account: azdata.Account, subscription: Subscription): Promise { @@ -276,8 +276,8 @@ export async function getAvailableSqlVMs(account: azdata.Account, subscription: .join(', '); throw new Error(message); } - sortResourceArrayByName(response.response.data.value); - return response.response.data.value; + sortResourceArrayByName(response.response.body.value); + return response.response.body.value; } export async function getVMInstanceView(sqlVm: SqlVMServer, account: azdata.Account, subscription: Subscription): Promise { @@ -294,7 +294,7 @@ export async function getVMInstanceView(sqlVm: SqlVMServer, account: azdata.Acco } - return response.response.data; + return response.response.body; } export async function getAzureResourceGivenId(account: azdata.Account, subscription: Subscription, id: string, apiVersion: string): Promise { @@ -311,7 +311,7 @@ export async function getAzureResourceGivenId(account: azdata.Account, subscript } - return response.response.data; + return response.response.body; } export async function getComputeVM(sqlVm: SqlVMServer, account: azdata.Account, subscription: Subscription): Promise { @@ -367,8 +367,8 @@ export async function getSqlMigrationServiceById(account: azdata.Account, subscr .join(', '); throw new Error(message); } - response.response.data.properties.resourceGroup = getResourceGroupFromId(response.response.data.id); - return response.response.data; + response.response.body.properties.resourceGroup = getResourceGroupFromId(response.response.body.id); + return response.response.body; } export async function getSqlMigrationServicesByResourceGroup(account: azdata.Account, subscription: Subscription, resouceGroupName: string): Promise { @@ -382,11 +382,11 @@ export async function getSqlMigrationServicesByResourceGroup(account: azdata.Acc .join(', '); throw new Error(message); } - sortResourceArrayByName(response.response.data.value); - response.response.data.value.forEach((sms: SqlMigrationService) => { + sortResourceArrayByName(response.response.body.value); + response.response.body.value.forEach((sms: SqlMigrationService) => { sms.properties.resourceGroup = getResourceGroupFromId(sms.id); }); - return response.response.data.value; + return response.response.body.value; } export async function getSqlMigrationServices(account: azdata.Account, subscription: Subscription): Promise { @@ -400,11 +400,11 @@ export async function getSqlMigrationServices(account: azdata.Account, subscript .join(', '); throw new Error(message); } - sortResourceArrayByName(response.response.data.value); - response.response.data.value.forEach((sms: SqlMigrationService) => { + sortResourceArrayByName(response.response.body.value); + response.response.body.value.forEach((sms: SqlMigrationService) => { sms.properties.resourceGroup = getResourceGroupFromId(sms.id); }); - return response.response.data.value; + return response.response.body.value; } export async function createSqlMigrationService(account: azdata.Account, subscription: Subscription, resourceGroupName: string, regionName: string, sqlMigrationServiceName: string, sessionId: string): Promise { @@ -428,7 +428,7 @@ export async function createSqlMigrationService(account: azdata.Account, subscri let i = 0; for (i = 0; i < maxRetry; i++) { const asyncResponse = await api.makeAzureRestRequest(account, subscription, asyncPath, azurecore.HttpRequestMethod.GET, undefined, true, host); - const creationStatus = asyncResponse.response.data.status; + const creationStatus = asyncResponse.response.body.status; if (creationStatus === constants.ProvisioningState.Succeeded) { break; } else if (creationStatus === constants.ProvisioningState.Failed) { @@ -439,7 +439,7 @@ export async function createSqlMigrationService(account: azdata.Account, subscri if (i === maxRetry) { throw new Error(constants.DMS_PROVISIONING_FAILED); } - return response.response.data; + return response.response.body; } export async function getSqlMigrationServiceAuthKeys(account: azdata.Account, subscription: Subscription, resourceGroupName: string, regionName: string, sqlMigrationServiceName: string): Promise { @@ -454,8 +454,8 @@ export async function getSqlMigrationServiceAuthKeys(account: azdata.Account, su throw new Error(message); } return { - authKey1: response?.response?.data?.authKey1 ?? '', - authKey2: response?.response?.data?.authKey2 ?? '' + authKey1: response?.response?.body?.authKey1 ?? '', + authKey2: response?.response?.body?.authKey2 ?? '' }; } @@ -475,8 +475,8 @@ export async function regenerateSqlMigrationServiceAuthKey(account: azdata.Accou throw new Error(message); } return { - authKey1: response?.response?.data?.authKey1 ?? '', - authKey2: response?.response?.data?.authKey2 ?? '' + authKey1: response?.response?.body?.authKey1 ?? '', + authKey2: response?.response?.body?.authKey2 ?? '' }; } @@ -506,7 +506,7 @@ export async function getSqlMigrationServiceMonitoringData(account: azdata.Accou .join(', '); throw new Error(message); } - return response.response.data; + return response.response.body; } export async function startDatabaseMigration( @@ -532,7 +532,7 @@ export async function startDatabaseMigration( return { asyncUrl: asyncUrl, status: response.response.status, - databaseMigration: response.response.data + databaseMigration: response.response.body }; } @@ -552,7 +552,7 @@ export async function getMigrationDetails(account: azdata.Account, subscription: throw new Error(message); } - return response.response.data; + return response.response.body; } export async function getServiceMigrations(account: azdata.Account, subscription: Subscription, resourceId: string): Promise { @@ -567,7 +567,7 @@ export async function getServiceMigrations(account: azdata.Account, subscription throw new Error(message); } - return response.response.data.value; + return response.response.body.value; } export async function getMigrationTargetInstance(account: azdata.Account, subscription: Subscription, migration: DatabaseMigration): Promise { @@ -583,7 +583,7 @@ export async function getMigrationTargetInstance(account: azdata.Account, subscr throw new Error(message); } - return response.response.data; + return response.response.body; } export async function getMigrationAsyncOperationDetails(account: azdata.Account, subscription: Subscription, url: string): Promise { @@ -597,7 +597,7 @@ export async function getMigrationAsyncOperationDetails(account: azdata.Account, .join(', '); throw new Error(message); } - return response.response.data; + return response.response.body; } export async function startMigrationCutover(account: azdata.Account, subscription: Subscription, migration: DatabaseMigration): Promise { @@ -612,7 +612,7 @@ export async function startMigrationCutover(account: azdata.Account, subscriptio .join(', '); throw new Error(message); } - return response.response.data.value; + return response.response.body.value; } export async function stopMigration(account: azdata.Account, subscription: Subscription, migration: DatabaseMigration): Promise { @@ -718,7 +718,7 @@ export async function validateIrSqlDatabaseMigrationSettings( if (response.errors.length > 0) { throw new Error(response.errors.map(e => e.message).join(',')); } - return response.response.data; + return response.response.body; } export async function validateIrDatabaseMigrationSettings( @@ -785,7 +785,7 @@ export async function validateIrDatabaseMigrationSettings( if (response.errors.length > 0) { throw new Error(response.errors.map(e => e.message).join(',')); } - return response.response.data; + return response.response.body; } type SortableAzureResources = AzureProduct | azurecore.azureResource.FileShare | azurecore.azureResource.BlobContainer | azurecore.azureResource.Blob | azurecore.azureResource.AzureResourceSubscription | SqlMigrationService;