mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-16 09:35:36 -05:00
167 lines
6.0 KiB
TypeScript
167 lines
6.0 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
import * as vscode from 'vscode';
|
|
import { azureResource } from 'azureResource';
|
|
import { DatabaseMigration, SqlMigrationService, SqlManagedInstance, getMigrationStatus, AzureAsyncOperationResource, getMigrationAsyncOperationDetails, SqlVMServer, getSubscriptions } from '../api/azure';
|
|
import * as azdata from 'azdata';
|
|
|
|
export class MigrationLocalStorage {
|
|
private static context: vscode.ExtensionContext;
|
|
private static mementoToken: string = 'sqlmigration.databaseMigrations';
|
|
|
|
public static setExtensionContext(context: vscode.ExtensionContext): void {
|
|
MigrationLocalStorage.context = context;
|
|
}
|
|
|
|
public static async getMigrationsBySourceConnections(connectionProfile: azdata.connection.ConnectionProfile, refreshStatus?: boolean): Promise<MigrationContext[]> {
|
|
const undefinedSessionId = '{undefined}';
|
|
const result: MigrationContext[] = [];
|
|
const validMigrations: MigrationContext[] = [];
|
|
|
|
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 {
|
|
await this.refreshMigrationAzureAccount(migration);
|
|
|
|
if (migration.asyncUrl) {
|
|
migration.asyncOperationResult = await getMigrationAsyncOperationDetails(
|
|
migration.azureAccount,
|
|
migration.subscription,
|
|
migration.asyncUrl,
|
|
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.
|
|
switch (e.message) {
|
|
case 'ResourceDoesNotExist':
|
|
case 'NullMigrationId':
|
|
continue;
|
|
default:
|
|
console.log(e);
|
|
}
|
|
}
|
|
}
|
|
result.push(migration);
|
|
}
|
|
validMigrations.push(migration);
|
|
}
|
|
await this.context.globalState.update(this.mementoToken, validMigrations);
|
|
return result;
|
|
}
|
|
|
|
public static async refreshMigrationAzureAccount(migration: MigrationContext): Promise<void> {
|
|
if (migration.azureAccount.isStale) {
|
|
const accounts = await azdata.accounts.getAllAccounts();
|
|
const account = accounts.find(a => !a.isStale && a.key.accountId === migration.azureAccount.key.accountId);
|
|
if (account) {
|
|
const subscriptions = await getSubscriptions(account);
|
|
const subscription = subscriptions.find(s => s.id === migration.subscription.id);
|
|
if (subscription) {
|
|
migration.azureAccount = account;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static async saveMigration(
|
|
connectionProfile: azdata.connection.ConnectionProfile,
|
|
migrationContext: DatabaseMigration,
|
|
targetMI: SqlManagedInstance | SqlVMServer,
|
|
azureAccount: azdata.Account,
|
|
subscription: azureResource.AzureResourceSubscription,
|
|
controller: SqlMigrationService,
|
|
asyncURL: string,
|
|
sessionId: string): Promise<void> {
|
|
try {
|
|
let migrationMementos: MigrationContext[] = this.context.globalState.get(this.mementoToken) || [];
|
|
migrationMementos = migrationMementos.filter(m => m.migrationContext.id !== migrationContext.id);
|
|
migrationMementos.push({
|
|
sourceConnectionProfile: connectionProfile,
|
|
migrationContext: this.removeMigrationSecrets(migrationContext),
|
|
targetManagedInstance: targetMI,
|
|
subscription: subscription,
|
|
azureAccount: azureAccount,
|
|
controller: controller,
|
|
asyncUrl: asyncURL,
|
|
sessionId: sessionId
|
|
});
|
|
await this.context.globalState.update(this.mementoToken, migrationMementos);
|
|
} catch (e) {
|
|
console.log(e);
|
|
}
|
|
}
|
|
|
|
public static async clearMigrations(): Promise<void> {
|
|
await 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 {
|
|
sourceConnectionProfile: azdata.connection.ConnectionProfile,
|
|
migrationContext: DatabaseMigration,
|
|
targetManagedInstance: SqlManagedInstance | SqlVMServer,
|
|
azureAccount: azdata.Account,
|
|
subscription: azureResource.AzureResourceSubscription,
|
|
controller: SqlMigrationService,
|
|
asyncUrl: string,
|
|
asyncOperationResult?: AzureAsyncOperationResource,
|
|
sessionId?: string
|
|
}
|
|
|
|
export enum MigrationStatus {
|
|
Failed = 'Failed',
|
|
Succeeded = 'Succeeded',
|
|
InProgress = 'InProgress',
|
|
Canceled = 'Canceled',
|
|
Completing = 'Completing',
|
|
Creating = 'Creating',
|
|
Canceling = 'Canceling'
|
|
}
|
|
|
|
export enum ProvisioningState {
|
|
Failed = 'Failed',
|
|
Succeeded = 'Succeeded',
|
|
Creating = 'Creating'
|
|
}
|
|
|
|
export enum BackupFileInfoStatus {
|
|
Arrived = 'Arrived',
|
|
Uploading = 'Uploading',
|
|
Uploaded = 'Uploaded',
|
|
Restoring = 'Restoring',
|
|
Restored = 'Restored',
|
|
Canceled = 'Canceled',
|
|
Ignored = 'Ignored'
|
|
}
|