Backup in-progress work (#347)

* Initial checkin of backup service implementation

* Backup initial changes for the quick scenario

* misc changes

* Misc changes for backup in-progress work
This commit is contained in:
Kate Shin
2017-05-12 21:55:16 -07:00
committed by GitHub
parent 327f0a5edd
commit efe48d8bd1
12 changed files with 4796 additions and 4 deletions

View File

@@ -4,23 +4,32 @@
//
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts;
using Microsoft.SqlTools.ServiceLayer.Hosting;
using Microsoft.SqlTools.ServiceLayer.SqlContext;
using System;
using System.Threading.Tasks;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Common;
using System.Collections.Generic;
using System.Data.SqlClient;
using Microsoft.SqlTools.ServiceLayer.Common;
namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
{
public class DisasterRecoveryService
{
private static readonly Lazy<DisasterRecoveryService> instance = new Lazy<DisasterRecoveryService>(() => new DisasterRecoveryService());
private static ConnectionService connectionService = null;
private BackupFactory backupFactory;
/// <summary>
/// Default, parameterless constructor.
/// </summary>
internal DisasterRecoveryService()
{
this.backupFactory = new BackupFactory();
}
/// <summary>
@@ -31,10 +40,29 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
get { return instance.Value; }
}
/// <summary>
/// Internal for testing purposes only
/// </summary>
internal static ConnectionService ConnectionServiceInstance
{
get
{
if (connectionService == null)
{
connectionService = ConnectionService.Instance;
}
return connectionService;
}
set
{
connectionService = value;
}
}
/// <summary>
/// Initializes the service instance
/// </summary>
public void InitializeService(ServiceHost serviceHost )
public void InitializeService(ServiceHost serviceHost)
{
serviceHost.SetRequestHandler(BackupRequest.Type, HandleBackupRequest);
}
@@ -45,8 +73,89 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
internal static async Task HandleBackupRequest(
BackupParams backupParams,
RequestContext<BackupResponse> requestContext)
{
{
ConnectionInfo connInfo;
DisasterRecoveryService.ConnectionServiceInstance.TryFindConnection(
backupParams.OwnerUri,
out connInfo);
CDataContainer dataContainer;
if (connInfo != null)
{
char[] passwordArray = connInfo.ConnectionDetails.Password.ToCharArray();
if (string.Equals(connInfo.ConnectionDetails.AuthenticationType, "SqlLogin", StringComparison.OrdinalIgnoreCase))
{
unsafe
{
fixed (char* passwordPtr = passwordArray)
{
dataContainer = new CDataContainer(
CDataContainer.ServerType.SQL,
connInfo.ConnectionDetails.ServerName,
false,
connInfo.ConnectionDetails.UserName,
new System.Security.SecureString(passwordPtr, passwordArray.Length),
string.Empty);
}
}
}
else
{
dataContainer = new CDataContainer(
CDataContainer.ServerType.SQL,
connInfo.ConnectionDetails.ServerName,
true,
null,
null,
null);
}
SqlConnection sqlConn = GetSqlConnection(connInfo);
if (sqlConn != null)
{
DisasterRecoveryService.Instance.InitializeBackup(dataContainer, sqlConn, backupParams.BackupInfo);
DisasterRecoveryService.Instance.PerformBackup();
}
}
await requestContext.SendResult(new BackupResponse());
}
internal static SqlConnection GetSqlConnection(ConnectionInfo connInfo)
{
try
{
// increase the connection timeout to at least 30 seconds and and build connection string
// enable PersistSecurityInfo to handle issues in SMO where the connection context is lost in reconnections
int? originalTimeout = connInfo.ConnectionDetails.ConnectTimeout;
bool? originalPersistSecurityInfo = connInfo.ConnectionDetails.PersistSecurityInfo;
connInfo.ConnectionDetails.ConnectTimeout = Math.Max(30, originalTimeout ?? 0);
connInfo.ConnectionDetails.PersistSecurityInfo = true;
string connectionString = ConnectionService.BuildConnectionString(connInfo.ConnectionDetails);
connInfo.ConnectionDetails.ConnectTimeout = originalTimeout;
connInfo.ConnectionDetails.PersistSecurityInfo = originalPersistSecurityInfo;
// open a dedicated binding server connection
SqlConnection sqlConn = new SqlConnection(connectionString);
sqlConn.Open();
return sqlConn;
}
catch (Exception)
{
}
return null;
}
private void InitializeBackup(CDataContainer dataContainer, SqlConnection sqlConnection, BackupInfo input)
{
this.backupFactory.Initialize(dataContainer, sqlConnection, input);
}
private void PerformBackup()
{
this.backupFactory.PerformBackup();
}
}
}