//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.SqlServer.Management.Assessment;
using Microsoft.SqlServer.Management.Assessment.Checks;
using Microsoft.SqlServer.Migration.Assessment.Common.Contracts.Models;
using Microsoft.SqlServer.Migration.Assessment.Common.Engine;
using Microsoft.SqlServer.Migration.Assessment.Common.Models;
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
using Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection;
using Microsoft.SqlTools.ServiceLayer.Hosting;
using Microsoft.SqlTools.ServiceLayer.Migration.Contracts;
using Microsoft.SqlTools.ServiceLayer.SqlAssessment;
using Microsoft.SqlTools.ServiceLayer.SqlAssessment.Contracts;
namespace Microsoft.SqlTools.ServiceLayer.Migration
{
///
/// Main class for Migration Service functionality
///
public sealed class MigrationService : IDisposable
{
private static ConnectionService connectionService = null;
private static readonly Lazy instance = new Lazy(() => new MigrationService());
private bool disposed;
///
/// Construct a new MigrationService instance with default parameters
///
public MigrationService()
{
}
///
/// Gets the singleton instance object
///
public static MigrationService Instance
{
get { return instance.Value; }
}
///
/// Internal for testing purposes only
///
internal static ConnectionService ConnectionService
{
get
{
if (connectionService == null)
{
connectionService = ConnectionService.Instance;
}
return connectionService;
}
set
{
connectionService = value;
}
}
///
/// Gets the used to run assessment operations.
///
internal Engine Engine { get; } = new Engine();
///
/// Service host object for sending/receiving requests/events.
/// Internal for testing purposes.
///
internal IProtocolEndpoint ServiceHost
{
get;
set;
}
///
/// Initializes the Migration Service instance
///
public void InitializeService(ServiceHost serviceHost)
{
this.ServiceHost = serviceHost;
this.ServiceHost.SetRequestHandler(MigrationAssessmentsRequest.Type, HandleMigrationAssessmentsRequest);
}
///
/// Handle request to start a migration session
///
internal async Task HandleMigrationAssessmentsRequest(
MigrationAssessmentsParams parameters,
RequestContext requestContext)
{
string randomUri = Guid.NewGuid().ToString();
try
{
// get connection
if (!ConnectionService.TryFindConnection(parameters.OwnerUri, out var connInfo))
{
await requestContext.SendError("Could not find migration connection");
return;
}
ConnectParams connectParams = new ConnectParams
{
OwnerUri = randomUri,
Connection = connInfo.ConnectionDetails,
Type = ConnectionType.Default
};
await ConnectionService.Connect(connectParams);
var connection = await ConnectionService.Instance.GetOrOpenConnection(randomUri, ConnectionType.Default);
var serverInfo = ReliableConnectionHelper.GetServerVersion(connection);
var hostInfo = ReliableConnectionHelper.GetServerHostInfo(connection);
var server = new SqlObjectLocator
{
Connection = connection,
EngineEdition = SqlAssessmentService.GetEngineEdition(serverInfo.EngineEditionId),
Name = serverInfo.ServerName,
ServerName = serverInfo.ServerName,
Type = SqlObjectType.Server,
Urn = serverInfo.ServerName,
Version = Version.Parse(serverInfo.ServerVersion),
Platform = hostInfo.Platform
};
var db = SqlAssessmentService.GetDatabaseLocator(server, connection.Database);
var results = await GetAssessmentItems(server);
var result = new MigrationAssessmentResult();
result.Items.AddRange(results);
await requestContext.SendResult(result);
}
finally
{
ConnectionService.Disconnect(new DisconnectParams { OwnerUri = randomUri, Type = null });
}
}
internal class AssessmentRequest : IAssessmentRequest
{
private readonly Check[] checks = null;
public AssessmentRequest(ISqlObjectLocator locator)
{
Target = locator ?? throw new ArgumentNullException(nameof(locator));
}
public EvaluationContext