Skip to content

Commit

Permalink
generic way to support scriptable operations (#438)
Browse files Browse the repository at this point in the history
* implemented a generic way to support scriptable operations
  • Loading branch information
llali authored Aug 18, 2017
1 parent 3915688 commit 39dedd8
Show file tree
Hide file tree
Showing 25 changed files with 951 additions and 287 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[![Travis CI](https://travis-ci.org/Microsoft/sqltoolsservice.svg?branch=dev)](https://travis-ci.org/Microsoft/sqltoolsservice)
[![AppVeyor](https://ci.appveyor.com/api/projects/status/github/Microsoft/sqltoolsservice?svg=true&retina=true&branch=dev)](https://ci.appveyor.com/project/kburtram/sqltoolsservice)
[![Coverage Status](https://coveralls.io/repos/github/Microsoft/sqltoolsservice/badge.svg?branch=dev)](https://coveralls.io/github/Microsoft/sqltoolsservice?branch=dev)
[![Coverage Status](https://coveralls.io/repos/github/Microsoft/sqltoolsservice/badge.svg?branch=dev)](https://coveralls.io/github/Microsoft/sqltoolsservice?branch=master)

# Microsoft SQL Tools Service
The SQL Tools Service is an application that provides core functionality for various SQL Server tools. These features include the following:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public class BackupOperation : IBackupOperation
/// this is used when the backup dialog is launched in the context of a backup device
/// The InitialBackupDestination will be loaded in LoadData
private string initialBackupDestination = string.Empty;

// Helps in populating the properties of an Azure blob given its URI
private class BlobProperties
{
Expand Down Expand Up @@ -163,6 +163,19 @@ public string ScriptContent
}
}

/// <summary>
/// The error occurred during backup operation
/// </summary>
public string ErrorMessage
{
get
{
return string.Empty;
}
}

public SqlTask SqlTask { get; set; }

/// <summary>
/// Execute backup
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
//

using System.Collections.Generic;
using Microsoft.SqlTools.ServiceLayer.TaskServices;
using Microsoft.SqlTools.ServiceLayer.Utility;
using Newtonsoft.Json.Linq;

Expand All @@ -12,7 +13,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts
/// <summary>
/// Restore request parameters
/// </summary>
public class RestoreParams : GeneralRequestDetails
public class RestoreParams : GeneralRequestDetails, IScriptableRequestParams
{
/// <summary>
/// Restore session id. The parameter is optional and if passed, an existing plan will be used
Expand Down Expand Up @@ -140,6 +141,26 @@ internal IEnumerable<string> SelectedBackupSets
SetOptionValue(RestoreOptionsHelper.SelectedBackupSets, value);
}
}

/// <summary>
/// The executation mode for the operation. default is execution
/// </summary>
public TaskExecutionMode TaskExecutionMode { get; set; }

/// <summary>
/// Same as Target Database name. Used by task manager to create task info
/// </summary>
public string DatabaseName
{
get
{
return TargetDatabaseName;
}
set
{
TargetDatabaseName = value;
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -224,15 +224,10 @@ internal async Task HandleRestoreRequest(
if (restoreDataObject != null)
{
// create task metadata
TaskMetadata metadata = new TaskMetadata();
metadata.ServerName = connInfo.ConnectionDetails.ServerName;
metadata.DatabaseName = restoreParams.TargetDatabaseName;
metadata.Name = SR.RestoreTaskName;
metadata.IsCancelable = true;
metadata.Data = restoreDataObject;
TaskMetadata metadata = TaskMetadata.Create(restoreParams, SR.RestoreTaskName, restoreDataObject, ConnectionServiceInstance);

// create restore task and perform
SqlTask sqlTask = SqlTaskManagerInstance.CreateAndRun(metadata, this.restoreDatabaseService.RestoreTaskAsync, restoreDatabaseService.CancelTaskAsync);
SqlTask sqlTask = SqlTaskManagerInstance.CreateAndRun<SqlTask>(metadata);
response.TaskId = sqlTask.TaskId.ToString();
}
else
Expand Down Expand Up @@ -285,8 +280,7 @@ internal async Task HandleBackupRequest(
TaskMetadata metadata = new TaskMetadata();
metadata.ServerName = connInfo.ConnectionDetails.ServerName;
metadata.DatabaseName = connInfo.ConnectionDetails.DatabaseName;
metadata.Data = backupOperation;
metadata.IsCancelable = true;
metadata.TaskOperation = backupOperation;

if (backupParams.IsScripting)
{
Expand Down Expand Up @@ -414,7 +408,7 @@ internal void ScriptBackup(BackupOperation backupOperation)
/// <returns></returns>
internal async Task<TaskResult> PerformBackupTaskAsync(SqlTask sqlTask)
{
IBackupOperation backupOperation = sqlTask.TaskMetadata.Data as IBackupOperation;
IBackupOperation backupOperation = sqlTask.TaskMetadata.TaskOperation as IBackupOperation;
TaskResult result = new TaskResult();

// Create a task to perform backup
Expand Down Expand Up @@ -463,7 +457,7 @@ await Task.Factory.StartNew(() =>
/// <returns></returns>
internal async Task<TaskResult> CancelBackupTaskAsync(SqlTask sqlTask)
{
IBackupOperation backupOperation = sqlTask.TaskMetadata.Data as IBackupOperation;
IBackupOperation backupOperation = sqlTask.TaskMetadata.TaskOperation as IBackupOperation;
TaskResult result = new TaskResult();

await Task.Factory.StartNew(() =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,11 @@
using System.Linq;
using System.Data.Common;
using System.Data.SqlClient;
using System.Threading.Tasks;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection;
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts;
using Microsoft.SqlTools.ServiceLayer.TaskServices;
using Microsoft.SqlTools.Utility;
using System.Collections.Concurrent;
using Microsoft.SqlTools.ServiceLayer.Utility;
Expand All @@ -28,107 +26,6 @@ public class RestoreDatabaseHelper
public const string LastBackupTaken = "lastBackupTaken";
private ConcurrentDictionary<string, RestoreDatabaseTaskDataObject> sessions = new ConcurrentDictionary<string, RestoreDatabaseTaskDataObject>();

/// <summary>
/// Create a backup task for execution and cancellation
/// </summary>
/// <param name="sqlTask"></param>
/// <returns></returns>
internal async Task<TaskResult> RestoreTaskAsync(SqlTask sqlTask)
{
sqlTask.AddMessage(SR.TaskInProgress, SqlTaskStatus.InProgress, true);
RestoreDatabaseTaskDataObject restoreDataObject = sqlTask.TaskMetadata.Data as RestoreDatabaseTaskDataObject;
TaskResult taskResult = null;

if (restoreDataObject != null)
{
// Create a task to perform backup
return await Task.Factory.StartNew(() =>
{
TaskResult result = new TaskResult();
try
{
if (restoreDataObject.IsValid)
{
ExecuteRestore(restoreDataObject, sqlTask);
result.TaskStatus = SqlTaskStatus.Succeeded;
}
else
{
result.TaskStatus = SqlTaskStatus.Failed;
if (restoreDataObject.ActiveException != null)
{
result.ErrorMessage = restoreDataObject.ActiveException.Message;
}
else
{
result.ErrorMessage = SR.RestoreNotSupported;
}
}
}
catch (Exception ex)
{
result.TaskStatus = SqlTaskStatus.Failed;
result.ErrorMessage = ex.Message;
if (ex.InnerException != null)
{
result.ErrorMessage += Environment.NewLine + ex.InnerException.Message;
}
if (restoreDataObject != null && restoreDataObject.ActiveException != null)
{
result.ErrorMessage += Environment.NewLine + restoreDataObject.ActiveException.Message;
}
}
return result;
});
}
else
{
taskResult = new TaskResult();
taskResult.TaskStatus = SqlTaskStatus.Failed;
}

return taskResult;
}



/// <summary>
/// Async task to cancel restore
/// </summary>
public async Task<TaskResult> CancelTaskAsync(SqlTask sqlTask)
{
RestoreDatabaseTaskDataObject restoreDataObject = sqlTask.TaskMetadata.Data as RestoreDatabaseTaskDataObject;
TaskResult taskResult = null;


if (restoreDataObject != null && restoreDataObject.IsValid)
{
// Create a task for backup cancellation request
return await Task.Factory.StartNew(() =>
{
foreach (Restore restore in restoreDataObject.RestorePlan.RestoreOperations)
{
restore.Abort();
}
return new TaskResult
{
TaskStatus = SqlTaskStatus.Canceled
};
});
}
else
{
taskResult = new TaskResult();
taskResult.TaskStatus = SqlTaskStatus.Failed;
}

return taskResult;
}

/// <summary>
/// Creates response which includes information about the server given to restore (default data location, db names with backupsets)
/// </summary>
Expand Down Expand Up @@ -166,7 +63,7 @@ public RestorePlanResponse CreateRestorePlanResponse(RestoreDatabaseTaskDataObje
{
if (restoreDataObject != null && restoreDataObject.IsValid)
{
UpdateRestorePlan(restoreDataObject);
restoreDataObject.UpdateRestoreTaskObject();

if (restoreDataObject != null && restoreDataObject.IsValid)
{
Expand Down Expand Up @@ -227,6 +124,7 @@ public RestorePlanResponse CreateRestorePlanResponse(RestoreDatabaseTaskDataObje
response.ErrorMessage += Environment.NewLine;
response.ErrorMessage += ex.InnerException.Message;
}
Logger.Write(LogLevel.Normal, $"Failed to create restore plan. error: { response.ErrorMessage}");
}
return response;

Expand Down Expand Up @@ -295,63 +193,11 @@ private RestoreDatabaseTaskDataObject CreateRestoreForNewSession(string ownerUri
return null;
}

/// <summary>
/// Create a restore data object that includes the plan to do the restore operation
/// </summary>
/// <param name="requestParam"></param>
/// <returns></returns>
private void UpdateRestorePlan(RestoreDatabaseTaskDataObject restoreDataObject)
{
bool shouldCreateNewPlan = restoreDataObject.ShouldCreateNewPlan();

if (!string.IsNullOrEmpty(restoreDataObject.RestoreParams.BackupFilePaths))
{
restoreDataObject.AddFiles(restoreDataObject.RestoreParams.BackupFilePaths);
}
restoreDataObject.RestorePlanner.ReadHeaderFromMedia = restoreDataObject.RestoreParams.ReadHeaderFromMedia;

RestoreOptionFactory.Instance.SetAndValidate(RestoreOptionsHelper.SourceDatabaseName, restoreDataObject);
RestoreOptionFactory.Instance.SetAndValidate(RestoreOptionsHelper.TargetDatabaseName, restoreDataObject);

if (shouldCreateNewPlan)
{
restoreDataObject.CreateNewRestorePlan();
}

restoreDataObject.UpdateRestorePlan();

}


private bool CanChangeTargetDatabase(RestoreDatabaseTaskDataObject restoreDataObject)
{
return DatabaseUtils.IsSystemDatabaseConnection(restoreDataObject.Server.ConnectionContext.DatabaseName);
}

/// <summary>
/// Executes the restore operation
/// </summary>
/// <param name="requestParam"></param>
public void ExecuteRestore(RestoreDatabaseTaskDataObject restoreDataObject, SqlTask sqlTask = null)
{
// Restore Plan should be already created and updated at this point
UpdateRestorePlan(restoreDataObject);

if (restoreDataObject != null && CanRestore(restoreDataObject))
{
try
{
restoreDataObject.SqlTask = sqlTask;
restoreDataObject.Execute();
}
catch(Exception ex)
{
throw ex;
}
}
else
{
throw new InvalidOperationException(SR.RestoreNotSupported);
}
}
}
}
Loading

0 comments on commit 39dedd8

Please sign in to comment.