Dev/brih/bugs/merge rtm hotfix changes (#16792)

* improves migration context loading error handling

* remove secrets and encode uris
This commit is contained in:
brian-harris
2021-08-16 16:24:41 -07:00
committed by GitHub
parent a92ba424ac
commit c12cdffe9b
5 changed files with 76 additions and 62 deletions

View File

@@ -124,7 +124,7 @@ export type SqlVMServer = {
};
export async function getAvailableSqlVMs(account: azdata.Account, subscription: Subscription, resourceGroup: azureResource.AzureResourceResourceGroup): Promise<SqlVMServer[]> {
const api = await getAzureCoreAPI();
const path = `/subscriptions/${subscription.id}/resourceGroups/${resourceGroup.name}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachines?api-version=2017-03-01-preview`;
const path = encodeURI(`/subscriptions/${subscription.id}/resourceGroups/${resourceGroup.name}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachines?api-version=2017-03-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());
@@ -167,7 +167,7 @@ export async function getBlobs(account: azdata.Account, subscription: Subscripti
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 path = encodeURI(`/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, undefined, getSessionIdHeader(sessionId));
if (response.errors.length > 0) {
throw new Error(response.errors.toString());
@@ -178,7 +178,7 @@ export async function getSqlMigrationService(account: azdata.Account, subscripti
export async function getSqlMigrationServices(account: azdata.Account, subscription: Subscription, resouceGroupName: string, sessionId: string): Promise<SqlMigrationService[]> {
const api = await getAzureCoreAPI();
const path = `/subscriptions/${subscription.id}/resourceGroups/${resouceGroupName}/providers/Microsoft.DataMigration/sqlMigrationServices?api-version=2020-09-01-preview`;
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));
if (response.errors.length > 0) {
throw new Error(response.errors.toString());
@@ -192,7 +192,7 @@ export async function getSqlMigrationServices(account: azdata.Account, subscript
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 path = encodeURI(`/subscriptions/${subscription.id}/resourceGroups/${resourceGroupName}/providers/Microsoft.DataMigration/sqlMigrationServices/${sqlMigrationServiceName}?api-version=2020-09-01-preview`);
const requestBody = {
'location': regionName
};
@@ -221,7 +221,7 @@ export async function createSqlMigrationService(account: azdata.Account, subscri
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 path = encodeURI(`/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, undefined, getSessionIdHeader(sessionId));
if (response.errors.length > 0) {
throw new Error(response.errors.toString());
@@ -234,7 +234,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, 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 path = encodeURI(`/subscriptions/${subscription.id}/resourceGroups/${resourceGroupName}/providers/Microsoft.DataMigration/sqlMigrationServices/${sqlMigrationServiceName}/regenerateAuthKeys?api-version=2020-09-01-preview`);
const requestBody = {
'location': regionName,
'keyName': keyName,
@@ -264,7 +264,7 @@ export async function getStorageAccountAccessKeys(account: azdata.Account, subsc
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 path = encodeURI(`/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, undefined, getSessionIdHeader(sessionId));
if (response.errors.length > 0) {
throw new Error(response.errors.toString());
@@ -274,7 +274,7 @@ export async function getSqlMigrationServiceMonitoringData(account: azdata.Accou
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 path = encodeURI(`${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, undefined, getSessionIdHeader(sessionId));
if (response.errors.length > 0) {
throw new Error(response.errors.toString());
@@ -287,27 +287,34 @@ export async function startDatabaseMigration(account: azdata.Account, subscripti
};
}
export async function getMigrationStatus(account: azdata.Account, subscription: Subscription, migration: DatabaseMigration, sessionId: string, asyncUrl: string): Promise<DatabaseMigration> {
export async function getMigrationStatus(account: azdata.Account, subscription: Subscription, migration: DatabaseMigration, sessionId: string): Promise<DatabaseMigration> {
if (!migration.id) {
throw new Error('NullMigrationId');
}
const migrationOperationId = migration.properties?.migrationOperationId;
if (migrationOperationId === undefined &&
migration.properties.provisioningState === ProvisioningState.Failed) {
return migration;
}
const path = migrationOperationId === undefined
? encodeURI(`${migration.id}?$expand=MigrationStatusDetails&api-version=2020-09-01-preview`)
: encodeURI(`${migration.id}?migrationOperationId=${migrationOperationId}&$expand=MigrationStatusDetails&api-version=2020-09-01-preview`);
const api = await getAzureCoreAPI();
const migrationOperationId = getMigrationOperationId(migration, asyncUrl);
const path = `${migration.id}?migrationOperationId=${migrationOperationId}&$expand=MigrationStatusDetails&api-version=2020-09-01-preview`;
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;
}
function getMigrationOperationId(migration: DatabaseMigration, asyncUrl: string): string {
// migrationOperationId may be undefined when provisioning has failed
// fall back to the operationId from the asyncUrl in the create migration response
if (migration.properties.migrationOperationId) {
return migration.properties.migrationOperationId;
const migrationUpdate: DatabaseMigration = response.response.data;
if (migration.properties) {
migrationUpdate.properties.sourceDatabaseName = migration.properties.sourceDatabaseName;
migrationUpdate.properties.backupConfiguration = migration.properties.backupConfiguration;
}
return asyncUrl
? vscode.Uri.parse(asyncUrl)?.path?.split('/').reverse()[0]
: '';
return migrationUpdate;
}
export async function getMigrationAsyncOperationDetails(account: azdata.Account, subscription: Subscription, url: string, sessionId: string): Promise<AzureAsyncOperationResource> {
@@ -321,7 +328,7 @@ export async function getMigrationAsyncOperationDetails(account: azdata.Account,
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 path = encodeURI(`${sqlMigrationService.id}/listMigrations?$expand=MigrationStatusDetails&api-version=2020-09-01-preview`);
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());
@@ -331,7 +338,7 @@ export async function listMigrationsBySqlMigrationService(account: azdata.Accoun
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 path = encodeURI(`${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, undefined, getSessionIdHeader(sessionId));
if (response.errors.length > 0) {
throw new Error(response.errors.toString());
@@ -341,7 +348,7 @@ export async function startMigrationCutover(account: azdata.Account, subscriptio
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 path = encodeURI(`${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, undefined, getSessionIdHeader(sessionId));
if (response.errors.length > 0) {
throw new Error(response.errors.toString());

View File

@@ -95,27 +95,27 @@ export function filterMigrations(databaseMigrations: MigrationContext[], statusF
filteredMigration = databaseMigrations;
} else if (statusFilter === AdsMigrationStatus.ONGOING) {
filteredMigration = databaseMigrations.filter((value) => {
const status = value.migrationContext.properties.migrationStatus;
const provisioning = value.migrationContext.properties.provisioningState;
const status = value.migrationContext.properties?.migrationStatus;
const provisioning = value.migrationContext.properties?.provisioningState;
return status === MigrationStatus.InProgress
|| status === MigrationStatus.Creating
|| provisioning === MigrationStatus.Creating;
});
} else if (statusFilter === AdsMigrationStatus.SUCCEEDED) {
filteredMigration = databaseMigrations.filter((value) => {
const status = value.migrationContext.properties.migrationStatus;
const status = value.migrationContext.properties?.migrationStatus;
return status === MigrationStatus.Succeeded;
});
} else if (statusFilter === AdsMigrationStatus.FAILED) {
filteredMigration = databaseMigrations.filter((value) => {
const status = value.migrationContext.properties.migrationStatus;
const provisioning = value.migrationContext.properties.provisioningState;
const status = value.migrationContext.properties?.migrationStatus;
const provisioning = value.migrationContext.properties?.provisioningState;
return status === MigrationStatus.Failed
|| provisioning === ProvisioningState.Failed;
});
} else if (statusFilter === AdsMigrationStatus.COMPLETING) {
filteredMigration = databaseMigrations.filter((value) => {
const status = value.migrationContext.properties.migrationStatus;
const status = value.migrationContext.properties?.migrationStatus;
return status === MigrationStatus.Completing;
});
}

View File

@@ -18,27 +18,25 @@ export class MigrationCutoverDialogModel {
public async fetchStatus(): Promise<void> {
if (this._migration.asyncUrl) {
this.migrationOpStatus = (await getMigrationAsyncOperationDetails(
this.migrationOpStatus = await getMigrationAsyncOperationDetails(
this._migration.azureAccount,
this._migration.subscription,
this._migration.asyncUrl,
this._migration.sessionId!
));
this._migration.sessionId!);
}
this.migrationStatus = (await getMigrationStatus(
this.migrationStatus = await getMigrationStatus(
this._migration.azureAccount,
this._migration.subscription,
this._migration.migrationContext,
this._migration.sessionId!,
this._migration.asyncUrl
));
this._migration.sessionId!);
sendSqlMigrationActionEvent(
TelemetryViews.MigrationCutoverDialog,
TelemetryAction.MigrationStatus,
{
'sessionId': this._migration.sessionId!,
'migrationStatus': this.migrationStatus.properties.migrationStatus
'migrationStatus': this.migrationStatus.properties?.migrationStatus
},
{}
);

View File

@@ -316,7 +316,7 @@ export class MigrationStatusDialog {
this._searchBox.value!);
migrations.sort((m1, m2) => {
return new Date(m1.migrationContext.properties.startedOn) > new Date(m2.migrationContext.properties.startedOn) ? -1 : 1;
return new Date(m1.migrationContext.properties?.startedOn) > new Date(m2.migrationContext.properties?.startedOn) ? -1 : 1;
});
const data: azdata.DeclarativeTableCellValue[][] = migrations.map((migration, index) => {

View File

@@ -23,14 +23,11 @@ export class MigrationLocalStorage {
const migrationMementos: MigrationContext[] = this.context.globalState.get(this.mementoToken) || [];
for (let i = 0; i < migrationMementos.length; i++) {
const migration = migrationMementos[i];
migration.migrationContext = this.removeMigrationSecrets(migration.migrationContext);
migration.sessionId = migration.sessionId ?? undefinedSessionId;
if (migration.sourceConnectionProfile.serverName === connectionProfile.serverName) {
if (refreshStatus) {
try {
const autoCutoverConfiguration = migration.migrationContext.properties.autoCutoverConfiguration;
const backupConfiguration = migration.migrationContext.properties.backupConfiguration;
const sourceDatabase = migration.migrationContext.properties.sourceDatabaseName;
await this.refreshMigrationAzureAccount(migration);
if (migration.asyncUrl) {
@@ -38,28 +35,23 @@ export class MigrationLocalStorage {
migration.azureAccount,
migration.subscription,
migration.asyncUrl,
migration.sessionId!
);
migration.migrationContext = await getMigrationStatus(
migration.azureAccount,
migration.subscription,
migration.migrationContext,
migration.sessionId!,
migration.asyncUrl
);
migration.migrationContext.properties.sourceDatabaseName = sourceDatabase;
migration.migrationContext.properties.backupConfiguration = backupConfiguration;
migration.migrationContext.properties.autoCutoverConfiguration = autoCutoverConfiguration;
migration.sessionId!);
}
migration.migrationContext = await getMigrationStatus(
migration.azureAccount,
migration.subscription,
migration.migrationContext,
migration.sessionId!);
}
catch (e) {
// Keeping only valid migrations in cache. Clearing all the migrations which return ResourceDoesNotExit error.
if (e.message === 'ResourceDoesNotExist') {
continue;
} else {
console.log(e);
switch (e.message) {
case 'ResourceDoesNotExist':
case 'NullMigrationId':
continue;
default:
console.log(e);
}
}
}
@@ -99,7 +91,7 @@ export class MigrationLocalStorage {
migrationMementos = migrationMementos.filter(m => m.migrationContext.id !== migrationContext.id);
migrationMementos.push({
sourceConnectionProfile: connectionProfile,
migrationContext: migrationContext,
migrationContext: this.removeMigrationSecrets(migrationContext),
targetManagedInstance: targetMI,
subscription: subscription,
azureAccount: azureAccount,
@@ -116,6 +108,23 @@ export class MigrationLocalStorage {
public static clearMigrations() {
this.context.globalState.update(this.mementoToken, ([] as MigrationContext[]));
}
public static removeMigrationSecrets(migration: DatabaseMigration): DatabaseMigration {
// remove secrets from migration context
if (migration.properties.sourceSqlConnection?.password) {
migration.properties.sourceSqlConnection.password = '';
}
if (migration.properties.backupConfiguration?.sourceLocation?.fileShare?.password) {
migration.properties.backupConfiguration.sourceLocation.fileShare.password = '';
}
if (migration.properties.backupConfiguration?.sourceLocation?.azureBlob?.accountKey) {
migration.properties.backupConfiguration.sourceLocation.azureBlob.accountKey = '';
}
if (migration.properties.backupConfiguration?.targetLocation?.accountKey) {
migration.properties.backupConfiguration.targetLocation.accountKey = '';
}
return migration;
}
}
export interface MigrationContext {