mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-14 01:25:37 -05:00
Refactor functionality into LoginMigrationsModel (#21933)
This PR refactors to encapsulate all login migration functionality into LoginMigrationModel
This commit is contained in:
@@ -6,7 +6,10 @@
|
||||
import * as mssql from 'mssql';
|
||||
import { MultiStepResult, MultiStepState } from '../dialog/generic/multiStepStatusDialog';
|
||||
import * as constants from '../constants/strings';
|
||||
import { LoginTableInfo } from '../api/sqlUtils';
|
||||
import { getSourceConnectionString, getTargetConnectionString, LoginTableInfo } from '../api/sqlUtils';
|
||||
import { MigrationStateModel } from './stateMachine';
|
||||
import { logError, TelemetryViews } from '../telemetry';
|
||||
import * as contracts from '../service/contracts';
|
||||
|
||||
type ExceptionMap = { [login: string]: any }
|
||||
|
||||
@@ -59,14 +62,17 @@ export class LoginMigrationModel {
|
||||
public collectedTargetLogins: boolean = false;;
|
||||
public loginsOnSource: LoginTableInfo[] = [];
|
||||
public loginsOnTarget: string[] = [];
|
||||
private _currentStepIdx: number = 0;;
|
||||
public loginMigrationsResult!: contracts.StartLoginMigrationResult;
|
||||
public loginMigrationsError: any;
|
||||
public loginsForMigration!: LoginTableInfo[];
|
||||
private _currentStepIdx: number = 0;
|
||||
private _logins: Map<string, Login>;
|
||||
private _loginMigrationSteps: LoginMigrationStep[] = [];
|
||||
|
||||
constructor() {
|
||||
this.resultsPerStep = new Map<mssql.LoginMigrationStep, mssql.StartLoginMigrationResult>();
|
||||
this._logins = new Map<string, Login>();
|
||||
this.SetLoginMigrationSteps();
|
||||
this.setLoginMigrationSteps();
|
||||
}
|
||||
|
||||
public get currentStep(): LoginMigrationStep {
|
||||
@@ -77,39 +83,29 @@ export class LoginMigrationModel {
|
||||
return this._currentStepIdx === this._loginMigrationSteps.length;
|
||||
}
|
||||
|
||||
public AddLoginMigrationResults(step: LoginMigrationStep, newResult: mssql.StartLoginMigrationResult): void {
|
||||
const exceptionMap = this._getExceptionMapWithNormalizedKeys(newResult.exceptionMap);
|
||||
this._currentStepIdx = this._loginMigrationSteps.findIndex(s => s === step) + 1;
|
||||
public async MigrateLogins(stateMachine: MigrationStateModel): Promise<boolean> {
|
||||
this.addNewLogins(stateMachine._loginMigrationModel.loginsForMigration.map(row => row.loginName));
|
||||
return await this.runLoginMigrationStep(LoginMigrationStep.MigrateLogins, stateMachine);
|
||||
|
||||
for (const loginName of this._logins.keys()) {
|
||||
const status = loginName in exceptionMap ? MultiStepState.Failed : MultiStepState.Succeeded;
|
||||
const errors = loginName in exceptionMap ? this._extractErrors(exceptionMap, loginName) : [];
|
||||
this._addStepStateForLogin(loginName, step, status, errors);
|
||||
|
||||
if (this.isMigrationComplete) {
|
||||
const loginStatus = this._didAnyStepFail(loginName) ? MultiStepState.Failed : MultiStepState.Succeeded;
|
||||
this._markLoginStatus(loginName, loginStatus);
|
||||
}
|
||||
}
|
||||
// TODO AKMA : emit telemetry
|
||||
}
|
||||
|
||||
public ReportException(step: LoginMigrationStep, error: any): void {
|
||||
this._currentStepIdx = this._loginMigrationSteps.findIndex(s => s === step) + 1;
|
||||
public async EstablishUserMappings(stateMachine: MigrationStateModel): Promise<boolean> {
|
||||
return await this.runLoginMigrationStep(LoginMigrationStep.EstablishUserMapping, stateMachine);
|
||||
|
||||
for (const loginName of this._logins.keys()) {
|
||||
// Mark current step as failed with the error message and mark remaining messages as canceled
|
||||
let errors = [error.message];
|
||||
this._addStepStateForLogin(loginName, step, MultiStepState.Failed, errors);
|
||||
this._markRemainingSteps(loginName, MultiStepState.Canceled);
|
||||
this._markLoginStatus(loginName, MultiStepState.Failed);
|
||||
}
|
||||
|
||||
this._markMigrationComplete();
|
||||
// TODO AKMA : emit telemetry
|
||||
}
|
||||
|
||||
public async MigrateServerRolesAndSetPermissions(stateMachine: MigrationStateModel): Promise<boolean> {
|
||||
return await this.runLoginMigrationStep(LoginMigrationStep.MigrateServerRolesAndSetPermissions, stateMachine);
|
||||
|
||||
// TODO AKMA : emit telemetry
|
||||
}
|
||||
|
||||
|
||||
public GetLoginMigrationResults(loginName: string): MultiStepResult[] {
|
||||
let loginResults: MultiStepResult[] = [];
|
||||
let login = this._getLogin(loginName);
|
||||
let login = this.getLogin(loginName);
|
||||
|
||||
for (const step of this._loginMigrationSteps) {
|
||||
// The default steps and state will be added if no steps have completed
|
||||
@@ -134,11 +130,7 @@ export class LoginMigrationModel {
|
||||
return loginResults;
|
||||
}
|
||||
|
||||
public AddNewLogins(logins: string[]) {
|
||||
logins.forEach(login => this._addNewLogin(login));
|
||||
}
|
||||
|
||||
public SetLoginMigrationSteps(steps: LoginMigrationStep[] = []) {
|
||||
private setLoginMigrationSteps(steps: LoginMigrationStep[] = []) {
|
||||
this._loginMigrationSteps = [];
|
||||
|
||||
if (steps.length === 0) {
|
||||
@@ -150,12 +142,144 @@ export class LoginMigrationModel {
|
||||
}
|
||||
}
|
||||
|
||||
private addNewLogins(logins: string[]) {
|
||||
logins.forEach(login => this.addNewLogin(login));
|
||||
}
|
||||
|
||||
private _getLogin(loginName: string) {
|
||||
public addLoginMigrationResults(step: LoginMigrationStep, newResult: mssql.StartLoginMigrationResult): void {
|
||||
const exceptionMap = this.getExceptionMapWithNormalizedKeys(newResult.exceptionMap);
|
||||
this._currentStepIdx = this._loginMigrationSteps.findIndex(s => s === step) + 1;
|
||||
|
||||
for (const loginName of this._logins.keys()) {
|
||||
const status = loginName in exceptionMap ? MultiStepState.Failed : MultiStepState.Succeeded;
|
||||
const errors = loginName in exceptionMap ? this.extractErrors(exceptionMap, loginName) : [];
|
||||
this.addStepStateForLogin(loginName, step, status, errors);
|
||||
|
||||
if (this.isMigrationComplete) {
|
||||
const loginStatus = this.didAnyStepFail(loginName) ? MultiStepState.Failed : MultiStepState.Succeeded;
|
||||
this.markLoginStatus(loginName, loginStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private updateLoginMigrationResults(newResult: contracts.StartLoginMigrationResult): void {
|
||||
if (this.loginMigrationsResult && this.loginMigrationsResult.exceptionMap) {
|
||||
for (var key in newResult.exceptionMap) {
|
||||
this.loginMigrationsResult.exceptionMap[key] = [...this.loginMigrationsResult.exceptionMap[key] || [], newResult.exceptionMap[key]]
|
||||
}
|
||||
} else {
|
||||
this.loginMigrationsResult = newResult;
|
||||
}
|
||||
}
|
||||
|
||||
public reportException(step: LoginMigrationStep, error: any): void {
|
||||
this._currentStepIdx = this._loginMigrationSteps.findIndex(s => s === step) + 1;
|
||||
|
||||
for (const loginName of this._logins.keys()) {
|
||||
// Mark current step as failed with the error message and mark remaining messages as canceled
|
||||
let errors = [error.message];
|
||||
this.addStepStateForLogin(loginName, step, MultiStepState.Failed, errors);
|
||||
this.markRemainingSteps(loginName, MultiStepState.Canceled);
|
||||
this.markLoginStatus(loginName, MultiStepState.Failed);
|
||||
}
|
||||
|
||||
this.markMigrationComplete();
|
||||
}
|
||||
|
||||
private async runMigrateLoginsTask(sourceConnStr: string, targetConnStr: string, stateMachine: MigrationStateModel): Promise<boolean> {
|
||||
try {
|
||||
var response = (await stateMachine.migrationService.migrateLogins(
|
||||
sourceConnStr,
|
||||
targetConnStr,
|
||||
stateMachine._loginMigrationModel.loginsForMigration.map(row => row.loginName),
|
||||
stateMachine._aadDomainName
|
||||
))!;
|
||||
|
||||
this.updateLoginMigrationResults(response);
|
||||
this.addLoginMigrationResults(LoginMigrationStep.MigrateLogins, response);
|
||||
return true;
|
||||
|
||||
} catch (error) {
|
||||
logError(TelemetryViews.LoginMigrationWizard, 'MigratinLoginsFailed', error);
|
||||
this.reportException(LoginMigrationStep.MigrateLogins, error);
|
||||
this.loginMigrationsError = error;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private async runEstablishUserMappingTask(sourceConnStr: string, targetConnStr: string, stateMachine: MigrationStateModel): Promise<boolean> {
|
||||
try {
|
||||
var response = (await stateMachine.migrationService.establishUserMapping(
|
||||
sourceConnStr,
|
||||
targetConnStr,
|
||||
stateMachine._loginMigrationModel.loginsForMigration.map(row => row.loginName),
|
||||
stateMachine._aadDomainName
|
||||
))!;
|
||||
|
||||
this.updateLoginMigrationResults(response);
|
||||
this.addLoginMigrationResults(LoginMigrationStep.EstablishUserMapping, response);
|
||||
return false;
|
||||
|
||||
} catch (error) {
|
||||
logError(TelemetryViews.LoginMigrationWizard, 'EstablishingUserMappingFailed', error);
|
||||
this.reportException(LoginMigrationStep.EstablishUserMapping, error);
|
||||
this.loginMigrationsError = error;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private async runMigrateServerRolesAndSetPermissionsTask(sourceConnStr: string, targetConnStr: string, stateMachine: MigrationStateModel): Promise<boolean> {
|
||||
try {
|
||||
var response = (await stateMachine.migrationService.migrateServerRolesAndSetPermissions(
|
||||
sourceConnStr,
|
||||
targetConnStr,
|
||||
stateMachine._loginMigrationModel.loginsForMigration.map(row => row.loginName),
|
||||
stateMachine._aadDomainName
|
||||
))!;
|
||||
|
||||
this.updateLoginMigrationResults(response);
|
||||
this.addLoginMigrationResults(LoginMigrationStep.MigrateServerRolesAndSetPermissions, response);
|
||||
return false;
|
||||
|
||||
} catch (error) {
|
||||
logError(TelemetryViews.LoginMigrationWizard, 'MigratingServerRolesAndSettingPermissionsFailed', error);
|
||||
this.reportException(LoginMigrationStep.MigrateServerRolesAndSetPermissions, error);
|
||||
this.loginMigrationsError = error;
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private async runLoginMigrationStep(step: LoginMigrationStep, stateMachine: MigrationStateModel): Promise<boolean> {
|
||||
const sourceConnectionString = await getSourceConnectionString();
|
||||
const targetConnectionString = await getTargetConnectionString(
|
||||
stateMachine.targetServerName,
|
||||
stateMachine._targetServerInstance.id,
|
||||
stateMachine._targetUserName,
|
||||
stateMachine._targetPassword,
|
||||
// for login migration, connect to target Azure SQL with true/true
|
||||
// to-do: take as input from the user, should be true/false for DB/MI but true/true for VM
|
||||
true /* encryptConnection */,
|
||||
true /* trustServerCertificate */);
|
||||
|
||||
// Get telemtry values
|
||||
switch (step) {
|
||||
case LoginMigrationStep.MigrateLogins:
|
||||
return await this.runMigrateLoginsTask(sourceConnectionString, targetConnectionString, stateMachine);
|
||||
case LoginMigrationStep.EstablishUserMapping:
|
||||
return await this.runEstablishUserMappingTask(sourceConnectionString, targetConnectionString, stateMachine);
|
||||
case LoginMigrationStep.MigrateServerRolesAndSetPermissions:
|
||||
return await this.runMigrateServerRolesAndSetPermissionsTask(sourceConnectionString, targetConnectionString, stateMachine);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private getLogin(loginName: string) {
|
||||
return this._logins.get(loginName.toLocaleLowerCase());
|
||||
}
|
||||
|
||||
private _addNewLogin(loginName: string, status: MultiStepState = MultiStepState.Pending) {
|
||||
private addNewLogin(loginName: string, status: MultiStepState = MultiStepState.Pending) {
|
||||
let newLogin: Login = {
|
||||
loginName: loginName,
|
||||
overallStatus: status,
|
||||
@@ -165,14 +289,14 @@ export class LoginMigrationModel {
|
||||
this._logins.set(loginName.toLocaleLowerCase(), newLogin);
|
||||
}
|
||||
|
||||
private _addStepStateForLogin(loginName: string, step: LoginMigrationStep, stepStatus: MultiStepState, errors: string[] = []) {
|
||||
private addStepStateForLogin(loginName: string, step: LoginMigrationStep, stepStatus: MultiStepState, errors: string[] = []) {
|
||||
const loginExist = this._logins.has(loginName);
|
||||
|
||||
if (!loginExist) {
|
||||
this._addNewLogin(loginName, MultiStepState.Running);
|
||||
this.addNewLogin(loginName, MultiStepState.Running);
|
||||
}
|
||||
|
||||
const login = this._getLogin(loginName);
|
||||
const login = this.getLogin(loginName);
|
||||
|
||||
if (login) {
|
||||
login.overallStatus = MultiStepState.Running;
|
||||
@@ -188,22 +312,22 @@ export class LoginMigrationModel {
|
||||
}
|
||||
}
|
||||
|
||||
private _markLoginStatus(loginName: string, status: MultiStepState) {
|
||||
private markLoginStatus(loginName: string, status: MultiStepState) {
|
||||
const loginExist = this._logins.has(loginName);
|
||||
|
||||
if (!loginExist) {
|
||||
this._addNewLogin(loginName, MultiStepState.Running);
|
||||
this.addNewLogin(loginName, MultiStepState.Running);
|
||||
}
|
||||
|
||||
let login = this._getLogin(loginName);
|
||||
let login = this.getLogin(loginName);
|
||||
|
||||
if (login) {
|
||||
login.overallStatus = status;
|
||||
}
|
||||
}
|
||||
|
||||
private _didAnyStepFail(loginName: string) {
|
||||
const login = this._getLogin(loginName);
|
||||
private didAnyStepFail(loginName: string) {
|
||||
const login = this.getLogin(loginName);
|
||||
if (login) {
|
||||
return Object.values(login.statusPerStep).every(status => status === MultiStepState.Failed);
|
||||
}
|
||||
@@ -211,25 +335,25 @@ export class LoginMigrationModel {
|
||||
return false;
|
||||
}
|
||||
|
||||
private _getExceptionMapWithNormalizedKeys(exceptionMap: ExceptionMap): ExceptionMap {
|
||||
private getExceptionMapWithNormalizedKeys(exceptionMap: ExceptionMap): ExceptionMap {
|
||||
return Object.keys(exceptionMap).reduce((result: ExceptionMap, key: string) => {
|
||||
result[key.toLocaleLowerCase()] = exceptionMap[key];
|
||||
return result;
|
||||
}, {});
|
||||
}
|
||||
|
||||
private _extractErrors(exceptionMap: ExceptionMap, loginName: string): string[] {
|
||||
private extractErrors(exceptionMap: ExceptionMap, loginName: string): string[] {
|
||||
return exceptionMap[loginName].map((exception: any) => typeof exception.InnerException !== 'undefined'
|
||||
&& exception.InnerException !== null ? exception.InnerException.Message : exception.Message);
|
||||
}
|
||||
|
||||
private _markMigrationComplete() {
|
||||
private markMigrationComplete() {
|
||||
this._currentStepIdx = this._loginMigrationSteps.length;
|
||||
}
|
||||
|
||||
private _markRemainingSteps(loginName: string, status: MultiStepState) {
|
||||
private markRemainingSteps(loginName: string, status: MultiStepState) {
|
||||
for (let i = this._currentStepIdx; i < this._loginMigrationSteps.length; i++) {
|
||||
this._addStepStateForLogin(loginName, this._loginMigrationSteps[i], status, []);
|
||||
this.addStepStateForLogin(loginName, this._loginMigrationSteps[i], status, []);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@ import { v4 as uuidv4 } from 'uuid';
|
||||
import { sendSqlMigrationActionEvent, TelemetryAction, TelemetryViews, logError } from '../telemetry';
|
||||
import { hashString, deepClone } from '../api/utils';
|
||||
import { SKURecommendationPage } from '../wizard/skuRecommendationPage';
|
||||
import { excludeDatabases, getEncryptConnectionValue, getSourceConnectionId, getSourceConnectionProfile, getSourceConnectionServerInfo, getSourceConnectionString, getSourceConnectionUri, getTargetConnectionString, getTrustServerCertificateValue, LoginTableInfo, SourceDatabaseInfo, TargetDatabaseInfo } from '../api/sqlUtils';
|
||||
import { LoginMigrationModel, LoginMigrationStep } from './loginMigrationModel';
|
||||
import { excludeDatabases, getEncryptConnectionValue, getSourceConnectionId, getSourceConnectionProfile, getSourceConnectionServerInfo, getSourceConnectionString, getSourceConnectionUri, getTrustServerCertificateValue, SourceDatabaseInfo, TargetDatabaseInfo } from '../api/sqlUtils';
|
||||
import { LoginMigrationModel } from './loginMigrationModel';
|
||||
import { TdeMigrationDbResult, TdeMigrationModel } from './tdeModels';
|
||||
import { NetworkInterfaceModel } from '../api/dataModels/azure/networkInterfaceModel';
|
||||
const localize = nls.loadMessageBundle();
|
||||
@@ -253,10 +253,7 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
public _perfDataCollectionErrors!: string[];
|
||||
public _perfDataCollectionIsCollecting!: boolean;
|
||||
|
||||
public _loginsForMigration!: LoginTableInfo[];
|
||||
public _aadDomainName!: string;
|
||||
public _loginMigrationsResult!: contracts.StartLoginMigrationResult;
|
||||
public _loginMigrationsError: any;
|
||||
public _loginMigrationModel: LoginMigrationModel;
|
||||
|
||||
public readonly _refreshGetSkuRecommendationIntervalInMinutes = 10;
|
||||
@@ -523,142 +520,6 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
return this._skuRecommendationResults;
|
||||
}
|
||||
|
||||
public setTargetServerName(): void {
|
||||
switch (this._targetType) {
|
||||
case MigrationTargetType.SQLMI:
|
||||
const sqlMi = this._targetServerInstance as SqlManagedInstance;
|
||||
this._targetServerName = sqlMi.properties.fullyQualifiedDomainName;
|
||||
case MigrationTargetType.SQLDB:
|
||||
const sqlDb = this._targetServerInstance as AzureSqlDatabaseServer;
|
||||
this._targetServerName = sqlDb.properties.fullyQualifiedDomainName;
|
||||
case MigrationTargetType.SQLVM:
|
||||
// For sqlvm, we need to use ip address from the network interface to connect to the server
|
||||
const sqlVm = this._targetServerInstance as SqlVMServer;
|
||||
const networkInterfaces = Array.from(sqlVm.networkInterfaces.values());
|
||||
this._targetServerName = NetworkInterfaceModel.getIpAddress(networkInterfaces);
|
||||
}
|
||||
}
|
||||
|
||||
public get targetServerName(): string {
|
||||
// If the target server name is not already set, return it
|
||||
if (!this._targetServerName) {
|
||||
this.setTargetServerName();
|
||||
}
|
||||
|
||||
return this._targetServerName;
|
||||
}
|
||||
|
||||
private updateLoginMigrationResults(newResult: contracts.StartLoginMigrationResult): void {
|
||||
if (this._loginMigrationsResult && this._loginMigrationsResult.exceptionMap) {
|
||||
for (var key in newResult.exceptionMap) {
|
||||
this._loginMigrationsResult.exceptionMap[key] = [...this._loginMigrationsResult.exceptionMap[key] || [], newResult.exceptionMap[key]]
|
||||
}
|
||||
} else {
|
||||
this._loginMigrationsResult = newResult;
|
||||
}
|
||||
}
|
||||
|
||||
public async migrateLogins(): Promise<Boolean> {
|
||||
try {
|
||||
this._loginMigrationModel.AddNewLogins(this._loginsForMigration.map(row => row.loginName));
|
||||
|
||||
const sourceConnectionString = await getSourceConnectionString();
|
||||
const targetConnectionString = await getTargetConnectionString(
|
||||
this.targetServerName,
|
||||
this._targetServerInstance.id,
|
||||
this._targetUserName,
|
||||
this._targetPassword,
|
||||
// for login migration, connect to target Azure SQL with true/true
|
||||
// to-do: take as input from the user, should be true/false for DB/MI but true/true for VM
|
||||
true /* encryptConnection */,
|
||||
true /* trustServerCertificate */);
|
||||
|
||||
var response = (await this.migrationService.migrateLogins(
|
||||
sourceConnectionString,
|
||||
targetConnectionString,
|
||||
this._loginsForMigration.map(row => row.loginName),
|
||||
this._aadDomainName
|
||||
))!;
|
||||
|
||||
this.updateLoginMigrationResults(response);
|
||||
this._loginMigrationModel.AddLoginMigrationResults(LoginMigrationStep.MigrateLogins, response);
|
||||
} catch (error) {
|
||||
logError(TelemetryViews.LoginMigrationWizard, 'StartLoginMigrationFailed', error);
|
||||
this._loginMigrationModel.ReportException(LoginMigrationStep.MigrateLogins, error);
|
||||
this._loginMigrationsError = error;
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO AKMA : emit telemetry
|
||||
return true;
|
||||
}
|
||||
|
||||
public async establishUserMappings(): Promise<Boolean> {
|
||||
try {
|
||||
const sourceConnectionString = await getSourceConnectionString();
|
||||
const targetConnectionString = await getTargetConnectionString(
|
||||
this.targetServerName,
|
||||
this._targetServerInstance.id,
|
||||
this._targetUserName,
|
||||
this._targetPassword,
|
||||
// for login migration, connect to target Azure SQL with true/true
|
||||
// to-do: take as input from the user, should be true/false for DB/MI but true/true for VM
|
||||
true /* encryptConnection */,
|
||||
true /* trustServerCertificate */);
|
||||
|
||||
var response = (await this.migrationService.establishUserMapping(
|
||||
sourceConnectionString,
|
||||
targetConnectionString,
|
||||
this._loginsForMigration.map(row => row.loginName),
|
||||
this._aadDomainName
|
||||
))!;
|
||||
|
||||
this.updateLoginMigrationResults(response);
|
||||
this._loginMigrationModel.AddLoginMigrationResults(LoginMigrationStep.EstablishUserMapping, response);
|
||||
} catch (error) {
|
||||
logError(TelemetryViews.LoginMigrationWizard, 'StartLoginMigrationFailed', error);
|
||||
this._loginMigrationModel.ReportException(LoginMigrationStep.MigrateLogins, error);
|
||||
this._loginMigrationsError = error;
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO AKMA : emit telemetry
|
||||
return true;
|
||||
}
|
||||
|
||||
public async migrateServerRolesAndSetPermissions(): Promise<Boolean> {
|
||||
try {
|
||||
const sourceConnectionString = await getSourceConnectionString();
|
||||
const targetConnectionString = await getTargetConnectionString(
|
||||
this.targetServerName,
|
||||
this._targetServerInstance.id,
|
||||
this._targetUserName,
|
||||
this._targetPassword,
|
||||
// for login migration, connect to target Azure SQL with true/true
|
||||
// to-do: take as input from the user, should be true/false for DB/MI but true/true for VM
|
||||
true /* encryptConnection */,
|
||||
true /* trustServerCertificate */);
|
||||
|
||||
var response = (await this.migrationService.migrateServerRolesAndSetPermissions(
|
||||
sourceConnectionString,
|
||||
targetConnectionString,
|
||||
this._loginsForMigration.map(row => row.loginName),
|
||||
this._aadDomainName
|
||||
))!;
|
||||
|
||||
this.updateLoginMigrationResults(response);
|
||||
this._loginMigrationModel.AddLoginMigrationResults(LoginMigrationStep.MigrateServerRolesAndSetPermissions, response);
|
||||
|
||||
} catch (error) {
|
||||
logError(TelemetryViews.LoginMigrationWizard, 'StartLoginMigrationFailed', error);
|
||||
this._loginMigrationModel.ReportException(LoginMigrationStep.MigrateLogins, error);
|
||||
this._loginMigrationsError = error;
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO AKMA : emit telemetry
|
||||
return true;
|
||||
}
|
||||
|
||||
private async generateSkuRecommendationTelemetry(): Promise<void> {
|
||||
try {
|
||||
@@ -1474,6 +1335,31 @@ export class MigrationStateModel implements Model, vscode.Disposable {
|
||||
public get isWindowsAuthMigrationSupported(): boolean {
|
||||
return this._targetType === MigrationTargetType.SQLMI;
|
||||
}
|
||||
|
||||
public setTargetServerName(): void {
|
||||
switch (this._targetType) {
|
||||
case MigrationTargetType.SQLMI:
|
||||
const sqlMi = this._targetServerInstance as SqlManagedInstance;
|
||||
this._targetServerName = sqlMi.properties.fullyQualifiedDomainName;
|
||||
case MigrationTargetType.SQLDB:
|
||||
const sqlDb = this._targetServerInstance as AzureSqlDatabaseServer;
|
||||
this._targetServerName = sqlDb.properties.fullyQualifiedDomainName;
|
||||
case MigrationTargetType.SQLVM:
|
||||
// For sqlvm, we need to use ip address from the network interface to connect to the server
|
||||
const sqlVm = this._targetServerInstance as SqlVMServer;
|
||||
const networkInterfaces = Array.from(sqlVm.networkInterfaces.values());
|
||||
this._targetServerName = NetworkInterfaceModel.getIpAddress(networkInterfaces);
|
||||
}
|
||||
}
|
||||
|
||||
public get targetServerName(): string {
|
||||
// If the target server name is not already set, return it
|
||||
if (!this._targetServerName) {
|
||||
this.setTargetServerName();
|
||||
}
|
||||
|
||||
return this._targetServerName;
|
||||
}
|
||||
}
|
||||
|
||||
export interface ServerAssessment {
|
||||
|
||||
@@ -88,7 +88,7 @@ export class LoginMigrationStatusPage extends MigrationWizardPage {
|
||||
this.wizard.message = {
|
||||
text: constants.LOGIN_MIGRATIONS_FAILED,
|
||||
level: azdata.window.MessageLevel.Error,
|
||||
description: constants.LOGIN_MIGRATIONS_ERROR(this.migrationStateModel._loginMigrationsError.message),
|
||||
description: constants.LOGIN_MIGRATIONS_ERROR(this.migrationStateModel._loginMigrationModel.loginMigrationsError.message),
|
||||
};
|
||||
|
||||
this._progressLoader.loading = false;
|
||||
@@ -292,7 +292,7 @@ export class LoginMigrationStatusPage extends MigrationWizardPage {
|
||||
}
|
||||
|
||||
private async _loadMigratingLoginsList(stateMachine: MigrationStateModel): Promise<void> {
|
||||
const loginList = stateMachine._loginsForMigration || [];
|
||||
const loginList = stateMachine._loginMigrationModel.loginsForMigration || [];
|
||||
loginList.sort((a, b) => a.loginName.localeCompare(b.loginName));
|
||||
|
||||
this._loginsTableValues = loginList.map(login => {
|
||||
@@ -300,13 +300,13 @@ export class LoginMigrationStatusPage extends MigrationWizardPage {
|
||||
|
||||
var status = LoginMigrationStatusCodes.InProgress;
|
||||
var title = constants.LOGIN_MIGRATION_STATUS_IN_PROGRESS;
|
||||
if (stateMachine._loginMigrationsError) {
|
||||
if (stateMachine._loginMigrationModel.loginMigrationsError) {
|
||||
status = LoginMigrationStatusCodes.Failed;
|
||||
title = constants.LOGIN_MIGRATION_STATUS_FAILED;
|
||||
} else if (stateMachine._loginMigrationsResult) {
|
||||
} else if (stateMachine._loginMigrationModel.loginMigrationsResult) {
|
||||
status = LoginMigrationStatusCodes.Succeeded;
|
||||
title = constants.LOGIN_MIGRATION_STATUS_SUCCEEDED;
|
||||
var didLoginFail = Object.keys(stateMachine._loginMigrationsResult.exceptionMap).some(key => key.toLocaleLowerCase() === loginName.toLocaleLowerCase());
|
||||
var didLoginFail = Object.keys(stateMachine._loginMigrationModel.loginMigrationsResult.exceptionMap).some(key => key.toLocaleLowerCase() === loginName.toLocaleLowerCase());
|
||||
if (didLoginFail) {
|
||||
status = LoginMigrationStatusCodes.Failed;
|
||||
title = constants.LOGIN_MIGRATION_STATUS_FAILED;
|
||||
@@ -352,7 +352,7 @@ export class LoginMigrationStatusPage extends MigrationWizardPage {
|
||||
'value': constants.STARTING_LOGIN_MIGRATION
|
||||
});
|
||||
|
||||
var result = await this.migrationStateModel.migrateLogins();
|
||||
var result = await this.migrationStateModel._loginMigrationModel.MigrateLogins(this.migrationStateModel);
|
||||
|
||||
if (!result) {
|
||||
await this._migrationProgressDetails.updateProperties({
|
||||
@@ -366,7 +366,7 @@ export class LoginMigrationStatusPage extends MigrationWizardPage {
|
||||
'value': constants.ESTABLISHING_USER_MAPPINGS
|
||||
});
|
||||
|
||||
result = await this.migrationStateModel.establishUserMappings();
|
||||
result = await this.migrationStateModel._loginMigrationModel.EstablishUserMappings(this.migrationStateModel);
|
||||
|
||||
if (!result) {
|
||||
await this._migrationProgressDetails.updateProperties({
|
||||
@@ -380,7 +380,7 @@ export class LoginMigrationStatusPage extends MigrationWizardPage {
|
||||
'value': constants.MIGRATING_SERVER_ROLES_AND_SET_PERMISSIONS
|
||||
});
|
||||
|
||||
result = await this.migrationStateModel.migrateServerRolesAndSetPermissions();
|
||||
result = await this.migrationStateModel._loginMigrationModel.MigrateServerRolesAndSetPermissions(this.migrationStateModel);
|
||||
|
||||
if (!result) {
|
||||
await this._migrationProgressDetails.updateProperties({
|
||||
|
||||
@@ -92,7 +92,7 @@ export class LoginSelectorPage extends MigrationWizardPage {
|
||||
await this._loadLoginList(false);
|
||||
|
||||
// load unfiltered table list and pre-select list of logins saved in state
|
||||
await this._filterTableList('', this.migrationStateModel._loginsForMigration);
|
||||
await this._filterTableList('', this.migrationStateModel._loginMigrationModel.loginsForMigration);
|
||||
}
|
||||
|
||||
public async onPageLeave(): Promise<void> {
|
||||
@@ -115,7 +115,7 @@ export class LoginSelectorPage extends MigrationWizardPage {
|
||||
}).component();
|
||||
|
||||
this._disposables.push(
|
||||
resourceSearchBox.onTextChanged(value => this._filterTableList(value, this.migrationStateModel._loginsForMigration || [])));
|
||||
resourceSearchBox.onTextChanged(value => this._filterTableList(value, this.migrationStateModel._loginMigrationModel.loginsForMigration || [])));
|
||||
|
||||
const searchContainer = this._view.modelBuilder.divContainer().withItems([resourceSearchBox]).withProps({
|
||||
CSSStyles: {
|
||||
@@ -326,7 +326,7 @@ export class LoginSelectorPage extends MigrationWizardPage {
|
||||
}));
|
||||
|
||||
// load unfiltered table list and pre-select list of logins saved in state
|
||||
await this._filterTableList('', this.migrationStateModel._loginsForMigration);
|
||||
await this._filterTableList('', this.migrationStateModel._loginMigrationModel.loginsForMigration);
|
||||
|
||||
const flex = view.modelBuilder.flexContainer().withLayout({
|
||||
flexFlow: 'column',
|
||||
@@ -416,7 +416,7 @@ export class LoginSelectorPage extends MigrationWizardPage {
|
||||
|
||||
private async _loadLoginList(runQuery: boolean = true): Promise<void> {
|
||||
const stateMachine: MigrationStateModel = this.migrationStateModel;
|
||||
const selectedLogins: LoginTableInfo[] = stateMachine._loginsForMigration || [];
|
||||
const selectedLogins: LoginTableInfo[] = stateMachine._loginMigrationModel.loginsForMigration || [];
|
||||
|
||||
// Get source logins if caller asked us to or if we haven't collected in the past
|
||||
if (runQuery || !stateMachine._loginMigrationModel.collectedSourceLogins) {
|
||||
@@ -488,7 +488,7 @@ export class LoginSelectorPage extends MigrationWizardPage {
|
||||
await utils.updateControlDisplay(this._aadDomainNameContainer, hasSelectedWindowsLogins);
|
||||
await this._loginSelectorTable.updateProperty("height", hasSelectedWindowsLogins ? 600 : 650);
|
||||
|
||||
this.migrationStateModel._loginsForMigration = selectedLogins;
|
||||
this.migrationStateModel._loginMigrationModel.loginsForMigration = selectedLogins;
|
||||
this.updateNextButton();
|
||||
}
|
||||
|
||||
@@ -496,7 +496,7 @@ export class LoginSelectorPage extends MigrationWizardPage {
|
||||
// Only uppdate next label if we are currently on this page
|
||||
if (this._isCurrentPage) {
|
||||
this.wizard.nextButton.label = constants.LOGIN_MIGRATE_BUTTON_TEXT;
|
||||
this.wizard.nextButton.enabled = this.migrationStateModel?._loginsForMigration?.length > 0;
|
||||
this.wizard.nextButton.enabled = this.migrationStateModel?._loginMigrationModel.loginsForMigration?.length > 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user