mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-13 17:23:02 -05:00
Akma/login migrations (#1728)
In this PR, we make the appropriate backend service changes in order to enable the login migrations feature in the SQL migration extension. Changes include: updating the Microsoft.SqlServer.Migration.Login NuGet version to the latest version adding a new request handler for StartLoginMigrations calls, which makes the appropriate calls to the login NuGet adding ExtensionMethod helper to properly combine exception maps login migration nuget calls Co-authored-by: Akshay Mata <akma@microsoft.com>
This commit is contained in:
@@ -28,6 +28,7 @@
|
||||
<PackageReference Update="Microsoft.Azure.Kusto.Language" Version="9.0.4" />
|
||||
<PackageReference Update="Microsoft.SqlServer.Assessment" Version="[1.1.9]" />
|
||||
<PackageReference Update="Microsoft.SqlServer.Migration.Assessment" Version="1.0.20221028.23" />
|
||||
<PackageReference Update="Microsoft.SqlServer.Migration.Logins" Version="1.0.20221103.24" />
|
||||
<PackageReference Update="Microsoft.SqlServer.Management.SqlParser" Version="160.22519.0" />
|
||||
<PackageReference Update="Microsoft.Azure.OperationalInsights" Version="1.0.0" />
|
||||
<PackageReference Update="Microsoft.CodeAnalysis.CSharp" Version="3.10.0" />
|
||||
|
||||
Binary file not shown.
@@ -53,6 +53,7 @@
|
||||
<PackageReference Include="Microsoft.Data.SqlClient" />
|
||||
<PackageReference Include="Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider" />
|
||||
<PackageReference Include="Microsoft.SqlServer.Assessment" />
|
||||
<PackageReference Include="Microsoft.SqlServer.Migration.Logins" />
|
||||
<PackageReference Include="Microsoft.SqlServer.Management.SmoMetadataProvider" />
|
||||
<PackageReference Include="Microsoft.SqlServer.SqlManagementObjects" />
|
||||
<PackageReference Include="Microsoft.SqlServer.Management.SqlParser" />
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using Microsoft.SqlServer.DataCollection.Common.Contracts.OperationsInfrastructure;
|
||||
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Migration.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the steps in login migration.
|
||||
/// </summary>
|
||||
public enum LoginMigrationStep
|
||||
{
|
||||
/// <summary>
|
||||
/// Run pre-migration validations
|
||||
/// </summary>
|
||||
StartValidations,
|
||||
|
||||
/// <summary>
|
||||
/// Step to hash passwords and migrate logins
|
||||
/// </summary>
|
||||
MigrateLogins,
|
||||
|
||||
/// <summary>
|
||||
/// Step to establish users and logins from source to target
|
||||
/// </summary>
|
||||
EstablishUserMapping,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Step to migrate server roles
|
||||
/// </summary>
|
||||
MigrateServerRoles,
|
||||
|
||||
/// <summary>
|
||||
/// Step to establish roles
|
||||
/// </summary>
|
||||
EstablishServerRoleMapping,
|
||||
|
||||
/// <summary>
|
||||
/// Step to map all the grant/deny permissions for logins
|
||||
/// </summary>
|
||||
SetLoginPermissions,
|
||||
|
||||
/// <summary>
|
||||
/// Step to map all server roles grant/deny permissions
|
||||
/// </summary>
|
||||
SetServerRolePermissions
|
||||
}
|
||||
|
||||
public class StartLoginMigrationParams
|
||||
{
|
||||
/// <summary>
|
||||
/// Connection string to connect to source
|
||||
/// </summary>
|
||||
public string SourceConnectionString { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Connection string to connect to target
|
||||
/// </summary>
|
||||
public string TargetConnectionString { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of logins to migrate
|
||||
/// </summary>
|
||||
public List<string> LoginList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Azure active directory domain name (required for Windows Auth)
|
||||
/// </summary>
|
||||
public string AADDomainName{ get; set; }
|
||||
}
|
||||
|
||||
public class LoginMigrationResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Start time of the assessment
|
||||
/// </summary>
|
||||
public IDictionary<string, IEnumerable<ReportableException>> ExceptionMap { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The login migration step that just completed
|
||||
/// </summary>
|
||||
public LoginMigrationStep CompletedStep { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// How long this step took
|
||||
/// </summary>
|
||||
public string ElapsedTime{ get; set; }
|
||||
}
|
||||
|
||||
public class StartLoginMigrationRequest
|
||||
{
|
||||
public static readonly
|
||||
RequestType<StartLoginMigrationParams, LoginMigrationResult> Type =
|
||||
RequestType<StartLoginMigrationParams, LoginMigrationResult>.Create("migration/startloginmigration");
|
||||
}
|
||||
|
||||
public class ValidateLoginMigrationRequest
|
||||
{
|
||||
public static readonly
|
||||
RequestType<StartLoginMigrationParams, LoginMigrationResult> Type =
|
||||
RequestType<StartLoginMigrationParams, LoginMigrationResult>.Create("migration/validateloginmigration");
|
||||
}
|
||||
|
||||
public class MigrateLoginsRequest
|
||||
{
|
||||
public static readonly
|
||||
RequestType<StartLoginMigrationParams, LoginMigrationResult> Type =
|
||||
RequestType<StartLoginMigrationParams, LoginMigrationResult>.Create("migration/migratelogins");
|
||||
}
|
||||
|
||||
public class EstablishUserMappingRequest
|
||||
{
|
||||
public static readonly
|
||||
RequestType<StartLoginMigrationParams, LoginMigrationResult> Type =
|
||||
RequestType<StartLoginMigrationParams, LoginMigrationResult>.Create("migration/establishusermapping");
|
||||
}
|
||||
public class MigrateServerRolesAndSetPermissionsRequest
|
||||
{
|
||||
public static readonly
|
||||
RequestType<StartLoginMigrationParams, LoginMigrationResult> Type =
|
||||
RequestType<StartLoginMigrationParams, LoginMigrationResult>.Create("migration/migrateserverrolesandsetpermissions");
|
||||
}
|
||||
|
||||
public class LoginMigrationNotification
|
||||
{
|
||||
public static readonly
|
||||
EventType<LoginMigrationResult> Type =
|
||||
EventType<LoginMigrationResult>.Create("migration/loginmigrationnotification");
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||
using Microsoft.SqlTools.ServiceLayer.Hosting;
|
||||
using Microsoft.SqlTools.ServiceLayer.Migration.Contracts;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
using Microsoft.SqlServer.Migration.Logins;
|
||||
using Microsoft.SqlServer.Migration.SkuRecommendation.Aggregation;
|
||||
using Microsoft.SqlServer.Migration.SkuRecommendation.Models.Sql;
|
||||
using Microsoft.SqlServer.Migration.SkuRecommendation;
|
||||
@@ -39,8 +40,12 @@ using Microsoft.SqlServer.Migration.SkuRecommendation.ElasticStrategy.AzureSqlMa
|
||||
using Microsoft.SqlServer.Migration.SkuRecommendation.ElasticStrategy.AzureSqlDatabase;
|
||||
using Microsoft.SqlServer.Migration.SkuRecommendation.Models;
|
||||
using Microsoft.SqlServer.Migration.SkuRecommendation.Utils;
|
||||
using Microsoft.SqlServer.DataCollection.Common.Contracts.OperationsInfrastructure;
|
||||
using System.Threading;
|
||||
using Microsoft.SqlServer.Migration.Logins.Contracts;
|
||||
using Microsoft.SqlServer.Migration.Assessment.Common.Models;
|
||||
using Microsoft.SqlServer.Migration.Assessment.Common.Utils;
|
||||
using Microsoft.SqlTools.ServiceLayer.Migration.Utils;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Migration
|
||||
{
|
||||
@@ -121,6 +126,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Migration
|
||||
this.ServiceHost.SetRequestHandler(StopPerfDataCollectionRequest.Type, HandleStopPerfDataCollectionRequest);
|
||||
this.ServiceHost.SetRequestHandler(RefreshPerfDataCollectionRequest.Type, HandleRefreshPerfDataCollectionRequest);
|
||||
this.ServiceHost.SetRequestHandler(GetSkuRecommendationsRequest.Type, HandleGetSkuRecommendationsRequest);
|
||||
this.ServiceHost.SetRequestHandler(StartLoginMigrationRequest.Type, HandleStartLoginMigration);
|
||||
this.ServiceHost.SetRequestHandler(ValidateLoginMigrationRequest.Type, HandleValidateLoginMigration);
|
||||
this.ServiceHost.SetRequestHandler(MigrateLoginsRequest.Type, HandleMigrateLogins);
|
||||
this.ServiceHost.SetRequestHandler(EstablishUserMappingRequest.Type, HandleEstablishUserMapping);
|
||||
this.ServiceHost.SetRequestHandler(MigrateServerRolesAndSetPermissionsRequest.Type, HandleMigrateServerRolesAndSetPermissions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -325,6 +335,231 @@ namespace Microsoft.SqlTools.ServiceLayer.Migration
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task HandleStartLoginMigration(
|
||||
StartLoginMigrationParams parameters,
|
||||
RequestContext<LoginMigrationResult> requestContext)
|
||||
{
|
||||
try
|
||||
{
|
||||
ILoginsMigration loginMigration = new LoginsMigration(parameters.SourceConnectionString, parameters.TargetConnectionString,
|
||||
null, parameters.LoginList, parameters.AADDomainName);
|
||||
|
||||
IDictionary<string, IEnumerable<ReportableException>> exceptionMap = new Dictionary<string, IEnumerable<ReportableException>>();
|
||||
|
||||
exceptionMap.AddExceptions( await loginMigration.StartValidations(CancellationToken.None) );
|
||||
exceptionMap.AddExceptions( await loginMigration.MigrateLogins(CancellationToken.None) );
|
||||
exceptionMap.AddExceptions( loginMigration.MigrateServerRoles(CancellationToken.None) );
|
||||
exceptionMap.AddExceptions( loginMigration.EstablishUserMapping(CancellationToken.None) );
|
||||
exceptionMap.AddExceptions( await loginMigration.EstablishServerRoleMapping(CancellationToken.None) );
|
||||
exceptionMap.AddExceptions( loginMigration.SetLoginPermissions(CancellationToken.None) );
|
||||
exceptionMap.AddExceptions( loginMigration.SetServerRolePermissions(CancellationToken.None) );
|
||||
|
||||
LoginMigrationResult results = new LoginMigrationResult()
|
||||
{
|
||||
ExceptionMap = exceptionMap
|
||||
};
|
||||
|
||||
await requestContext.SendResult(results);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await requestContext.SendError(e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task HandleValidateLoginMigration(
|
||||
StartLoginMigrationParams parameters,
|
||||
RequestContext<LoginMigrationResult> requestContext)
|
||||
{
|
||||
try
|
||||
{
|
||||
ILoginsMigration loginMigration = new LoginsMigration(parameters.SourceConnectionString, parameters.TargetConnectionString,
|
||||
null, parameters.LoginList, parameters.AADDomainName);
|
||||
|
||||
IDictionary<string, IEnumerable<ReportableException>> exceptionMap = new Dictionary<string, IEnumerable<ReportableException>>();
|
||||
Stopwatch stopWatch = new Stopwatch();
|
||||
stopWatch.Start();
|
||||
exceptionMap.AddExceptions( await loginMigration.StartValidations(CancellationToken.None) );
|
||||
stopWatch.Stop();
|
||||
TimeSpan elapsedTime = stopWatch.Elapsed;
|
||||
|
||||
LoginMigrationResult results = new LoginMigrationResult()
|
||||
{
|
||||
ExceptionMap = exceptionMap,
|
||||
CompletedStep = LoginMigrationStep.StartValidations,
|
||||
ElapsedTime = MigrationServiceHelper.FormatTimeSpan(elapsedTime)
|
||||
|
||||
};
|
||||
|
||||
await requestContext.SendResult(results);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await requestContext.SendError(e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task HandleMigrateLogins(
|
||||
StartLoginMigrationParams parameters,
|
||||
RequestContext<LoginMigrationResult> requestContext)
|
||||
{
|
||||
try
|
||||
{
|
||||
ILoginsMigration loginMigration = new LoginsMigration(parameters.SourceConnectionString, parameters.TargetConnectionString,
|
||||
null, parameters.LoginList, parameters.AADDomainName);
|
||||
|
||||
IDictionary<string, IEnumerable<ReportableException>> exceptionMap = new Dictionary<string, IEnumerable<ReportableException>>();
|
||||
Stopwatch stopWatch = new Stopwatch();
|
||||
stopWatch.Start();
|
||||
exceptionMap.AddExceptions( await loginMigration.StartValidations(CancellationToken.None) );
|
||||
exceptionMap.AddExceptions( await loginMigration.MigrateLogins(CancellationToken.None) );
|
||||
stopWatch.Stop();
|
||||
TimeSpan elapsedTime = stopWatch.Elapsed;
|
||||
|
||||
LoginMigrationResult results = new LoginMigrationResult()
|
||||
{
|
||||
ExceptionMap = exceptionMap,
|
||||
CompletedStep = LoginMigrationStep.MigrateLogins,
|
||||
ElapsedTime = MigrationServiceHelper.FormatTimeSpan(elapsedTime)
|
||||
};
|
||||
|
||||
await requestContext.SendResult(results);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await requestContext.SendError(e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task HandleEstablishUserMapping(
|
||||
StartLoginMigrationParams parameters,
|
||||
RequestContext<LoginMigrationResult> requestContext)
|
||||
{
|
||||
try
|
||||
{
|
||||
ILoginsMigration loginMigration = new LoginsMigration(parameters.SourceConnectionString, parameters.TargetConnectionString,
|
||||
null, parameters.LoginList, parameters.AADDomainName);
|
||||
|
||||
IDictionary<string, IEnumerable<ReportableException>> exceptionMap = new Dictionary<string, IEnumerable<ReportableException>>();
|
||||
|
||||
Stopwatch stopWatch = new Stopwatch();
|
||||
stopWatch.Start();
|
||||
exceptionMap.AddExceptions( await loginMigration.StartValidations(CancellationToken.None) );
|
||||
exceptionMap.AddExceptions( loginMigration.EstablishUserMapping(CancellationToken.None) );
|
||||
stopWatch.Stop();
|
||||
TimeSpan elapsedTime = stopWatch.Elapsed;
|
||||
|
||||
LoginMigrationResult results = new LoginMigrationResult()
|
||||
{
|
||||
ExceptionMap = exceptionMap,
|
||||
CompletedStep = LoginMigrationStep.EstablishUserMapping,
|
||||
ElapsedTime = MigrationServiceHelper.FormatTimeSpan(elapsedTime)
|
||||
};
|
||||
|
||||
await requestContext.SendResult(results);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await requestContext.SendError(e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task HandleMigrateServerRolesAndSetPermissions(
|
||||
StartLoginMigrationParams parameters,
|
||||
RequestContext<LoginMigrationResult> requestContext)
|
||||
{
|
||||
try
|
||||
{
|
||||
ILoginsMigration loginMigration = new LoginsMigration(parameters.SourceConnectionString, parameters.TargetConnectionString,
|
||||
null, parameters.LoginList, parameters.AADDomainName);
|
||||
|
||||
IDictionary<string, IEnumerable<ReportableException>> exceptionMap = new Dictionary<string, IEnumerable<ReportableException>>();
|
||||
Stopwatch stopWatch = new Stopwatch();
|
||||
stopWatch.Start();
|
||||
exceptionMap.AddExceptions(await loginMigration.StartValidations(CancellationToken.None));
|
||||
stopWatch.Stop();
|
||||
TimeSpan elapsedTime = stopWatch.Elapsed;
|
||||
|
||||
await this.ServiceHost.SendEvent(
|
||||
LoginMigrationNotification.Type,
|
||||
new LoginMigrationResult()
|
||||
{
|
||||
ExceptionMap = exceptionMap,
|
||||
CompletedStep = LoginMigrationStep.StartValidations,
|
||||
ElapsedTime = MigrationServiceHelper.FormatTimeSpan(elapsedTime)
|
||||
});
|
||||
|
||||
stopWatch.Restart();
|
||||
exceptionMap.AddExceptions(loginMigration.MigrateServerRoles(CancellationToken.None));
|
||||
stopWatch.Stop();
|
||||
elapsedTime = stopWatch.Elapsed;
|
||||
|
||||
await this.ServiceHost.SendEvent(
|
||||
LoginMigrationNotification.Type,
|
||||
new LoginMigrationResult()
|
||||
{
|
||||
ExceptionMap = exceptionMap,
|
||||
CompletedStep = LoginMigrationStep.MigrateServerRoles,
|
||||
ElapsedTime = MigrationServiceHelper.FormatTimeSpan(elapsedTime)
|
||||
});
|
||||
|
||||
stopWatch.Restart();
|
||||
exceptionMap.AddExceptions(await loginMigration.EstablishServerRoleMapping(CancellationToken.None));
|
||||
stopWatch.Stop();
|
||||
elapsedTime = stopWatch.Elapsed;
|
||||
|
||||
await this.ServiceHost.SendEvent(
|
||||
LoginMigrationNotification.Type,
|
||||
new LoginMigrationResult()
|
||||
{
|
||||
ExceptionMap = exceptionMap,
|
||||
CompletedStep = LoginMigrationStep.EstablishServerRoleMapping,
|
||||
ElapsedTime = MigrationServiceHelper.FormatTimeSpan(elapsedTime)
|
||||
});
|
||||
|
||||
stopWatch.Restart();
|
||||
exceptionMap.AddExceptions(loginMigration.SetLoginPermissions(CancellationToken.None));
|
||||
stopWatch.Stop();
|
||||
elapsedTime = stopWatch.Elapsed;
|
||||
|
||||
await this.ServiceHost.SendEvent(
|
||||
LoginMigrationNotification.Type,
|
||||
new LoginMigrationResult()
|
||||
{
|
||||
ExceptionMap = exceptionMap,
|
||||
CompletedStep = LoginMigrationStep.SetLoginPermissions,
|
||||
ElapsedTime = MigrationServiceHelper.FormatTimeSpan(elapsedTime)
|
||||
});
|
||||
|
||||
stopWatch.Restart();
|
||||
exceptionMap.AddExceptions(loginMigration.SetServerRolePermissions(CancellationToken.None));
|
||||
stopWatch.Stop();
|
||||
elapsedTime = stopWatch.Elapsed;
|
||||
|
||||
await this.ServiceHost.SendEvent(
|
||||
LoginMigrationNotification.Type,
|
||||
new LoginMigrationResult()
|
||||
{
|
||||
ExceptionMap = exceptionMap,
|
||||
CompletedStep = LoginMigrationStep.SetServerRolePermissions,
|
||||
ElapsedTime = MigrationServiceHelper.FormatTimeSpan(elapsedTime)
|
||||
});
|
||||
|
||||
LoginMigrationResult results = new LoginMigrationResult()
|
||||
{
|
||||
ExceptionMap = exceptionMap,
|
||||
CompletedStep = LoginMigrationStep.SetServerRolePermissions,
|
||||
ElapsedTime = MigrationServiceHelper.FormatTimeSpan(elapsedTime)
|
||||
};
|
||||
|
||||
await requestContext.SendResult(results);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await requestContext.SendError(e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
internal RecommendationResultSet GenerateBaselineRecommendations(SqlInstanceRequirements req, GetSkuRecommendationsParams parameters) {
|
||||
RecommendationResultSet resultSet = new RecommendationResultSet();
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.SqlServer.DataCollection.Common.Contracts.OperationsInfrastructure;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Migration.Utils
|
||||
{
|
||||
internal static class ExtensionMethods
|
||||
{
|
||||
public static void AddExceptions(this IDictionary<string, IEnumerable<ReportableException>> exceptionMap1, IDictionary<string, IEnumerable<ReportableException>> exceptionMap2)
|
||||
{
|
||||
foreach (var keyValuePair2 in exceptionMap2)
|
||||
{
|
||||
// If the dictionary already contains the key then merge them
|
||||
if (exceptionMap1.ContainsKey(keyValuePair2.Key))
|
||||
{
|
||||
foreach (var value in keyValuePair2.Value)
|
||||
{
|
||||
exceptionMap1[keyValuePair2.Key].Append(value);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
exceptionMap1.Add(keyValuePair2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Migration.Utils
|
||||
{
|
||||
internal static class MigrationServiceHelper
|
||||
{
|
||||
public static string FormatTimeSpan(TimeSpan ts)
|
||||
{
|
||||
return String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user