Adding support for sending request headers in azure core rest request API (#16443)

* Adding support for sending additional headers in azure http requests

* Added session ids in all azure rest calls

* Fixed param name

* Adding default parameter value for request headers
This commit is contained in:
Aasim Khan
2021-07-27 12:36:50 -07:00
committed by GitHub
parent 35207a1e04
commit 7a35d4aeeb
11 changed files with 79 additions and 53 deletions

View File

@@ -8,6 +8,7 @@ import * as azdata from 'azdata';
import * as azurecore from 'azurecore';
import { azureResource } from 'azureResource';
import * as constants from '../constants/strings';
import { getSessionIdHeader } from './utils';
async function getAzureCoreAPI(): Promise<azurecore.IExtension> {
const api = (await vscode.extensions.getExtension(azurecore.extension.name)?.activate()) as azurecore.IExtension;
@@ -131,10 +132,10 @@ export async function getBlobContainers(account: azdata.Account, subscription: S
return blobContainers!;
}
export async function getSqlMigrationService(account: azdata.Account, subscription: Subscription, resourceGroupName: string, regionName: string, sqlMigrationServiceName: string): Promise<SqlMigrationService> {
export async function getSqlMigrationService(account: azdata.Account, subscription: Subscription, resourceGroupName: string, regionName: string, sqlMigrationServiceName: string, sessionId: string): Promise<SqlMigrationService> {
const api = await getAzureCoreAPI();
const path = `/subscriptions/${subscription.id}/resourceGroups/${resourceGroupName}/providers/Microsoft.DataMigration/sqlMigrationServices/${sqlMigrationServiceName}?api-version=2020-09-01-preview`;
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.GET, undefined, true);
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.GET, undefined, true, undefined, getSessionIdHeader(sessionId));
if (response.errors.length > 0) {
throw new Error(response.errors.toString());
}
@@ -142,10 +143,10 @@ export async function getSqlMigrationService(account: azdata.Account, subscripti
return response.response.data;
}
export async function getSqlMigrationServices(account: azdata.Account, subscription: Subscription, regionName: string): Promise<SqlMigrationService[]> {
export async function getSqlMigrationServices(account: azdata.Account, subscription: Subscription, sessionId: string): Promise<SqlMigrationService[]> {
const api = await getAzureCoreAPI();
const path = `/subscriptions/${subscription.id}/providers/Microsoft.DataMigration/sqlMigrationServices?api-version=2020-09-01-preview`;
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.GET, undefined, true);
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.GET, undefined, true, undefined, getSessionIdHeader(sessionId));
if (response.errors.length > 0) {
throw new Error(response.errors.toString());
}
@@ -156,13 +157,13 @@ export async function getSqlMigrationServices(account: azdata.Account, subscript
return response.response.data.value;
}
export async function createSqlMigrationService(account: azdata.Account, subscription: Subscription, resourceGroupName: string, regionName: string, sqlMigrationServiceName: string): Promise<SqlMigrationService> {
export async function createSqlMigrationService(account: azdata.Account, subscription: Subscription, resourceGroupName: string, regionName: string, sqlMigrationServiceName: string, sessionId: string): Promise<SqlMigrationService> {
const api = await getAzureCoreAPI();
const path = `/subscriptions/${subscription.id}/resourceGroups/${resourceGroupName}/providers/Microsoft.DataMigration/sqlMigrationServices/${sqlMigrationServiceName}?api-version=2020-09-01-preview`;
const requestBody = {
'location': regionName
};
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.PUT, requestBody, true);
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.PUT, requestBody, true, undefined, getSessionIdHeader(sessionId));
if (response.errors.length > 0) {
throw new Error(response.errors.toString());
}
@@ -170,7 +171,7 @@ export async function createSqlMigrationService(account: azdata.Account, subscri
const maxRetry = 5;
let i = 0;
for (i = 0; i < maxRetry; i++) {
const asyncResponse = await api.makeAzureRestRequest(account, subscription, asyncUrl.replace('https://management.azure.com/', ''), azurecore.HttpRequestMethod.GET, undefined, true);
const asyncResponse = await api.makeAzureRestRequest(account, subscription, asyncUrl.replace('https://management.azure.com/', ''), azurecore.HttpRequestMethod.GET, undefined, true, undefined, getSessionIdHeader(sessionId));
const creationStatus = asyncResponse.response.data.status;
if (creationStatus === 'Succeeded') {
break;
@@ -185,10 +186,10 @@ export async function createSqlMigrationService(account: azdata.Account, subscri
return response.response.data;
}
export async function getSqlMigrationServiceAuthKeys(account: azdata.Account, subscription: Subscription, resourceGroupName: string, regionName: string, sqlMigrationServiceName: string): Promise<SqlMigrationServiceAuthenticationKeys> {
export async function getSqlMigrationServiceAuthKeys(account: azdata.Account, subscription: Subscription, resourceGroupName: string, regionName: string, sqlMigrationServiceName: string, sessionId: string): Promise<SqlMigrationServiceAuthenticationKeys> {
const api = await getAzureCoreAPI();
const path = `/subscriptions/${subscription.id}/resourceGroups/${resourceGroupName}/providers/Microsoft.DataMigration/sqlMigrationServices/${sqlMigrationServiceName}/ListAuthKeys?api-version=2020-09-01-preview`;
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.POST, undefined, true);
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.POST, undefined, true, undefined, getSessionIdHeader(sessionId));
if (response.errors.length > 0) {
throw new Error(response.errors.toString());
}
@@ -198,7 +199,7 @@ export async function getSqlMigrationServiceAuthKeys(account: azdata.Account, su
};
}
export async function regenerateSqlMigrationServiceAuthKey(account: azdata.Account, subscription: Subscription, resourceGroupName: string, regionName: string, sqlMigrationServiceName: string, keyName: string): Promise<SqlMigrationServiceAuthenticationKeys> {
export async function regenerateSqlMigrationServiceAuthKey(account: azdata.Account, subscription: Subscription, resourceGroupName: string, regionName: string, sqlMigrationServiceName: string, keyName: string, sessionId: string): Promise<SqlMigrationServiceAuthenticationKeys> {
const api = await getAzureCoreAPI();
const path = `/subscriptions/${subscription.id}/resourceGroups/${resourceGroupName}/providers/Microsoft.DataMigration/sqlMigrationServices/${sqlMigrationServiceName}/regenerateAuthKeys?api-version=2020-09-01-preview`;
const requestBody = {
@@ -206,7 +207,7 @@ export async function regenerateSqlMigrationServiceAuthKey(account: azdata.Accou
'keyName': keyName,
};
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.POST, requestBody, true);
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.POST, requestBody, true, undefined, getSessionIdHeader(sessionId));
if (response.errors.length > 0) {
throw new Error(response.errors.toString());
}
@@ -228,20 +229,20 @@ export async function getStorageAccountAccessKeys(account: azdata.Account, subsc
};
}
export async function getSqlMigrationServiceMonitoringData(account: azdata.Account, subscription: Subscription, resourceGroupName: string, regionName: string, sqlMigrationService: string): Promise<IntegrationRuntimeMonitoringData> {
export async function getSqlMigrationServiceMonitoringData(account: azdata.Account, subscription: Subscription, resourceGroupName: string, regionName: string, sqlMigrationService: string, sessionId: string): Promise<IntegrationRuntimeMonitoringData> {
const api = await getAzureCoreAPI();
const path = `/subscriptions/${subscription.id}/resourceGroups/${resourceGroupName}/providers/Microsoft.DataMigration/sqlMigrationServices/${sqlMigrationService}/monitoringData?api-version=2020-09-01-preview`;
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.GET, undefined, true);
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.GET, undefined, true, undefined, getSessionIdHeader(sessionId));
if (response.errors.length > 0) {
throw new Error(response.errors.toString());
}
return response.response.data;
}
export async function startDatabaseMigration(account: azdata.Account, subscription: Subscription, regionName: string, targetServer: SqlManagedInstance | SqlVMServer, targetDatabaseName: string, requestBody: StartDatabaseMigrationRequest): Promise<StartDatabaseMigrationResponse> {
export async function startDatabaseMigration(account: azdata.Account, subscription: Subscription, regionName: string, targetServer: SqlManagedInstance | SqlVMServer, targetDatabaseName: string, requestBody: StartDatabaseMigrationRequest, sessionId: string): Promise<StartDatabaseMigrationResponse> {
const api = await getAzureCoreAPI();
const path = `${targetServer.id}/providers/Microsoft.DataMigration/databaseMigrations/${targetDatabaseName}?api-version=2020-09-01-preview`;
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.PUT, requestBody, true);
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.PUT, requestBody, true, undefined, getSessionIdHeader(sessionId));
if (response.errors.length > 0) {
throw new Error(response.errors.toString());
}
@@ -253,10 +254,10 @@ export async function startDatabaseMigration(account: azdata.Account, subscripti
};
}
export async function getDatabaseMigration(account: azdata.Account, subscription: Subscription, regionName: string, migrationId: string): Promise<DatabaseMigration> {
export async function getDatabaseMigration(account: azdata.Account, subscription: Subscription, regionName: string, migrationId: string, sessionId: string): Promise<DatabaseMigration> {
const api = await getAzureCoreAPI();
const path = `${migrationId}?api-version=2020-09-01-preview`;
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.GET, undefined, true);
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.GET, undefined, true, undefined, getSessionIdHeader(sessionId));
if (response.errors.length > 0) {
if (response.response.status === 404 && response.response.data.error.code === 'ResourceDoesNotExist') {
throw new Error(response.response.data.error.code);
@@ -266,49 +267,49 @@ export async function getDatabaseMigration(account: azdata.Account, subscription
return response.response.data;
}
export async function getMigrationStatus(account: azdata.Account, subscription: Subscription, migration: DatabaseMigration): Promise<DatabaseMigration> {
export async function getMigrationStatus(account: azdata.Account, subscription: Subscription, migration: DatabaseMigration, sessionId: string): Promise<DatabaseMigration> {
const api = await getAzureCoreAPI();
const path = `${migration.id}?$expand=MigrationStatusDetails&api-version=2020-09-01-preview`;
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.GET, undefined, true);
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.GET, undefined, true, undefined, getSessionIdHeader(sessionId));
if (response.errors.length > 0) {
throw new Error(response.errors.toString());
}
return response.response.data;
}
export async function getMigrationAsyncOperationDetails(account: azdata.Account, subscription: Subscription, url: string): Promise<AzureAsyncOperationResource> {
export async function getMigrationAsyncOperationDetails(account: azdata.Account, subscription: Subscription, url: string, sessionId: string): Promise<AzureAsyncOperationResource> {
const api = await getAzureCoreAPI();
const response = await api.makeAzureRestRequest(account, subscription, url.replace('https://management.azure.com/', ''), azurecore.HttpRequestMethod.GET, undefined, true);
const response = await api.makeAzureRestRequest(account, subscription, url.replace('https://management.azure.com/', ''), azurecore.HttpRequestMethod.GET, undefined, true, undefined, getSessionIdHeader(sessionId));
if (response.errors.length > 0) {
throw new Error(response.errors.toString());
}
return response.response.data;
}
export async function listMigrationsBySqlMigrationService(account: azdata.Account, subscription: Subscription, sqlMigrationService: SqlMigrationService): Promise<DatabaseMigration[]> {
export async function listMigrationsBySqlMigrationService(account: azdata.Account, subscription: Subscription, sqlMigrationService: SqlMigrationService, sessionId: string): Promise<DatabaseMigration[]> {
const api = await getAzureCoreAPI();
const path = `${sqlMigrationService.id}/listMigrations?$expand=MigrationStatusDetails&api-version=2020-09-01-preview`;
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.GET, undefined, true);
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.GET, undefined, true, undefined, getSessionIdHeader(sessionId));
if (response.errors.length > 0) {
throw new Error(response.errors.toString());
}
return response.response.data.value;
}
export async function startMigrationCutover(account: azdata.Account, subscription: Subscription, migrationStatus: DatabaseMigration): Promise<any> {
export async function startMigrationCutover(account: azdata.Account, subscription: Subscription, migrationStatus: DatabaseMigration, sessionId: string): Promise<any> {
const api = await getAzureCoreAPI();
const path = `${migrationStatus.id}/operations/${migrationStatus.properties.migrationOperationId}/cutover?api-version=2020-09-01-preview`;
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.POST, undefined, true);
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.POST, undefined, true, undefined, getSessionIdHeader(sessionId));
if (response.errors.length > 0) {
throw new Error(response.errors.toString());
}
return response.response.data.value;
}
export async function stopMigration(account: azdata.Account, subscription: Subscription, migrationStatus: DatabaseMigration): Promise<void> {
export async function stopMigration(account: azdata.Account, subscription: Subscription, migrationStatus: DatabaseMigration, sessionId: string): Promise<void> {
const api = await getAzureCoreAPI();
const path = `${migrationStatus.id}/operations/${migrationStatus.properties.migrationOperationId}/cancel?api-version=2020-09-01-preview`;
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.POST, undefined, true);
const response = await api.makeAzureRestRequest(account, subscription, path, azurecore.HttpRequestMethod.POST, undefined, true, undefined, getSessionIdHeader(sessionId));
if (response.errors.length > 0) {
throw new Error(response.errors.toString());
}

View File

@@ -193,3 +193,9 @@ export function decorate(decorator: (fn: Function, key: string) => Function): Fu
descriptor[fnKey] = decorator(fn, key);
};
}
export function getSessionIdHeader(sessionId: string): { [key: string]: string } {
return {
'SqlMigrationSessionId': sessionId
};
}

View File

@@ -90,7 +90,7 @@ export class CreateSqlMigrationServiceDialog {
try {
this._selectedResourceGroup = resourceGroup;
this._createdMigrationService = await createSqlMigrationService(this._model._azureAccount, subscription, resourceGroup, location, serviceName!);
this._createdMigrationService = await createSqlMigrationService(this._model._azureAccount, subscription, resourceGroup, location, serviceName!, this._model._sessionId);
if (this._createdMigrationService.error) {
this.setDialogMessage(`${this._createdMigrationService.error.code} : ${this._createdMigrationService.error.message}`);
this._statusLoadingComponent.loading = false;
@@ -505,14 +505,14 @@ export class CreateSqlMigrationServiceDialog {
let migrationServiceStatus!: SqlMigrationService;
for (let i = 0; i < maxRetries; i++) {
try {
migrationServiceStatus = await getSqlMigrationService(this._model._azureAccount, subscription, resourceGroup, location, this._createdMigrationService.name);
migrationServiceStatus = await getSqlMigrationService(this._model._azureAccount, subscription, resourceGroup, location, this._createdMigrationService.name, this._model._sessionId);
break;
} catch (e) {
console.log(e);
}
await new Promise(r => setTimeout(r, 5000));
}
const migrationServiceMonitoringStatus = await getSqlMigrationServiceMonitoringData(this._model._azureAccount, subscription, resourceGroup, location, this._createdMigrationService!.name);
const migrationServiceMonitoringStatus = await getSqlMigrationServiceMonitoringData(this._model._azureAccount, subscription, resourceGroup, location, this._createdMigrationService!.name, this._model._sessionId);
this.irNodes = migrationServiceMonitoringStatus.nodes.map((node) => {
return node.nodeName;
});
@@ -546,7 +546,7 @@ export class CreateSqlMigrationServiceDialog {
const subscription = this._model._targetSubscription;
const resourceGroup = (this.migrationServiceResourceGroupDropdown.value as azdata.CategoryValue).name;
const location = this._model._targetServerInstance.location;
const keys = await getSqlMigrationServiceAuthKeys(this._model._azureAccount, subscription, resourceGroup, location, this._createdMigrationService!.name);
const keys = await getSqlMigrationServiceAuthKeys(this._model._azureAccount, subscription, resourceGroup, location, this._createdMigrationService!.name, this._model._sessionId);
this._copyKey1Button = this._view.modelBuilder.button().withProps({
title: constants.COPY_KEY1,

View File

@@ -27,13 +27,15 @@ export class MigrationCutoverDialogModel {
this.migrationOpStatus = (await getMigrationAsyncOperationDetails(
this._migration.azureAccount,
this._migration.subscription,
this._migration.asyncUrl
this._migration.asyncUrl,
this._migration.sessionId!
));
}
this.migrationStatus = (await getMigrationStatus(
this._migration.azureAccount,
this._migration.subscription,
this._migration.migrationContext
this._migration.migrationContext,
this._migration.sessionId!,
));
sendSqlMigrationActionEvent(
@@ -55,7 +57,8 @@ export class MigrationCutoverDialogModel {
const cutover = await startMigrationCutover(
this._migration.azureAccount,
this._migration.subscription,
this.migrationStatus
this.migrationStatus,
this._migration.sessionId!
);
sendSqlMigrationActionEvent(
TelemetryViews.MigrationCutoverDialog,
@@ -81,7 +84,8 @@ export class MigrationCutoverDialogModel {
await stopMigration(
this._migration.azureAccount,
this._migration.subscription,
this.migrationStatus
this.migrationStatus,
this._migration.sessionId!
);
sendSqlMigrationActionEvent(
TelemetryViews.MigrationCutoverDialog,

View File

@@ -66,7 +66,8 @@ export class SqlMigrationServiceDetailsDialog {
migrationContext.subscription,
migrationContext.controller.properties.resourceGroup,
migrationContext.controller.location,
migrationContext.controller.name
migrationContext.controller.name,
this.migrationContext.sessionId!
));
const serviceNodeName = serviceNode.nodes?.map(node => node.nodeName).join(', ')
|| constants.SQL_MIGRATION_SERVICE_DETAILS_STATUS_UNAVAILABLE;
@@ -209,7 +210,8 @@ export class SqlMigrationServiceDetailsDialog {
migrationContext.controller.properties.resourceGroup,
migrationContext.controller.location.toUpperCase(),
migrationContext.controller.name,
keyName);
keyName,
migrationContext.sessionId!);
if (keys?.authKey1 && keyName === AUTH_KEY1) {
await this._updateTableCell(this._migrationServiceAuthKeyTable, 0, 1, keys.authKey1, constants.SERVICE_KEY1_LABEL);
@@ -233,7 +235,8 @@ export class SqlMigrationServiceDetailsDialog {
migrationContext.subscription,
migrationContext.controller.properties.resourceGroup,
migrationContext.controller.location.toUpperCase(),
migrationContext.controller.name);
migrationContext.controller.name,
migrationContext.sessionId!);
const copyKey1Button = view.modelBuilder
.button()

View File

@@ -31,7 +31,8 @@ export class MigrationLocalStorage {
migration.migrationContext = await getMigrationStatus(
migration.azureAccount,
migration.subscription,
migration.migrationContext
migration.migrationContext,
migration.sessionId!
);
migration.migrationContext.properties.sourceDatabaseName = sourceDatabase;
migration.migrationContext.properties.backupConfiguration = backupConfiguration;
@@ -39,7 +40,8 @@ export class MigrationLocalStorage {
migration.asyncOperationResult = await getMigrationAsyncOperationDetails(
migration.azureAccount,
migration.subscription,
migration.asyncUrl
migration.asyncUrl,
migration.sessionId!
);
}
}

View File

@@ -743,7 +743,7 @@ export class MigrationStateModel implements Model, vscode.Disposable {
public async getSqlMigrationServiceValues(subscription: azureResource.AzureResourceSubscription, managedInstance: SqlManagedInstance, resourceGroupName: string): Promise<azdata.CategoryValue[]> {
let sqlMigrationServiceValues: azdata.CategoryValue[] = [];
try {
this._sqlMigrationServices = (await getSqlMigrationServices(this._azureAccount, subscription, managedInstance.location)).filter(sms => sms.location.toLowerCase() === this._targetServerInstance.location.toLowerCase() && sms.properties.resourceGroup.toLowerCase() === resourceGroupName?.toLowerCase());
this._sqlMigrationServices = (await getSqlMigrationServices(this._azureAccount, subscription, this._sessionId)).filter(sms => sms.location.toLowerCase() === this._targetServerInstance.location.toLowerCase() && sms.properties.resourceGroup.toLowerCase() === resourceGroupName?.toLowerCase());
this._sqlMigrationServices.forEach((sqlMigrationService) => {
sqlMigrationServiceValues.push({
name: sqlMigrationService.id,
@@ -839,7 +839,8 @@ export class MigrationStateModel implements Model, vscode.Disposable {
this._sqlMigrationService?.location!,
this._targetServerInstance,
this._targetDatabaseNames[i],
requestBody
requestBody,
this._sessionId
);
response.databaseMigration.properties.sourceDatabaseName = this._migrationDbs[i];
response.databaseMigration.properties.backupConfiguration = requestBody.properties.backupConfiguration!;

View File

@@ -463,21 +463,24 @@ export class IntergrationRuntimePage extends MigrationWizardPage {
this.migrationStateModel._targetSubscription,
this.migrationStateModel._sqlMigrationService.properties.resourceGroup,
this.migrationStateModel._sqlMigrationService.location,
this.migrationStateModel._sqlMigrationService.name);
this.migrationStateModel._sqlMigrationService.name,
this.migrationStateModel._sessionId);
this.migrationStateModel._sqlMigrationService = migrationService;
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._sqlMigrationService!.name,
this.migrationStateModel._sessionId);
this.migrationStateModel._nodeNames = migrationServiceMonitoringStatus.nodes.map(node => node.nodeName);
const migrationServiceAuthKeys = await getSqlMigrationServiceAuthKeys(
this.migrationStateModel._azureAccount,
this.migrationStateModel._targetSubscription,
this.migrationStateModel._sqlMigrationService.properties.resourceGroup,
this.migrationStateModel._sqlMigrationService.location,
this.migrationStateModel._sqlMigrationService!.name
this.migrationStateModel._sqlMigrationService!.name,
this.migrationStateModel._sessionId
);
this.migrationStateModel._nodeNames = migrationServiceMonitoringStatus.nodes.map((node) => {