mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-26 17:24:21 -05:00
integrate backup operation with new scriptable task (#440)
* integrate backup operation with new scriptable task
This commit is contained in:
@@ -13,8 +13,6 @@ using Microsoft.SqlServer.Management.Sdk.Sfc;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlTools.ServiceLayer.Admin;
|
||||
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using Microsoft.SqlTools.ServiceLayer.TaskServices;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
|
||||
@@ -22,13 +20,12 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
|
||||
/// <summary>
|
||||
/// This class implements backup operations
|
||||
/// </summary>
|
||||
public class BackupOperation : IBackupOperation
|
||||
public class BackupOperation : SmoScriptableTaskOperation, IBackupOperation
|
||||
{
|
||||
private CDataContainer dataContainer;
|
||||
private ServerConnection serverConnection;
|
||||
private CommonUtilities backupRestoreUtil = null;
|
||||
private Backup backup = null;
|
||||
private string scriptContent = "";
|
||||
|
||||
/// <summary>
|
||||
/// Constants
|
||||
@@ -151,22 +148,10 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
|
||||
return configInfo;
|
||||
}
|
||||
|
||||
public string ScriptContent
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.scriptContent;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.scriptContent = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The error occurred during backup operation
|
||||
/// </summary>
|
||||
public string ErrorMessage
|
||||
public override string ErrorMessage
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -174,17 +159,19 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
|
||||
}
|
||||
}
|
||||
|
||||
public SqlTask SqlTask { get; set; }
|
||||
public override Server Server
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.dataContainer.Server;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute backup
|
||||
/// </summary>
|
||||
public void Execute(TaskExecutionMode mode)
|
||||
public override void Execute()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
SqlExecutionModes oldExecutionMode = this.dataContainer.Server.ConnectionContext.SqlExecutionModes;
|
||||
this.dataContainer.Server.ConnectionContext.SqlExecutionModes = (mode == TaskExecutionMode.Script) ? SqlExecutionModes.CaptureSql: SqlExecutionModes.ExecuteAndCaptureSql;
|
||||
this.dataContainer.Server.ConnectionContext.CapturedSql.Clear();
|
||||
this.backup = new Backup();
|
||||
this.backup.Database = this.backupInfo.DatabaseName;
|
||||
this.backup.Action = this.backupActionType;
|
||||
@@ -322,24 +309,18 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
|
||||
}
|
||||
}
|
||||
|
||||
foreach (String s in this.dataContainer.Server.ConnectionContext.CapturedSql.Text)
|
||||
{
|
||||
sb.Append(s);
|
||||
sb.Append(Environment.NewLine);
|
||||
}
|
||||
this.ScriptContent = sb.ToString();
|
||||
|
||||
}
|
||||
finally
|
||||
catch(Exception)
|
||||
{
|
||||
this.dataContainer.Server.ConnectionContext.CapturedSql.Clear();
|
||||
this.dataContainer.Server.ConnectionContext.SqlExecutionModes = oldExecutionMode;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cancel backup
|
||||
/// </summary>
|
||||
public void Cancel()
|
||||
public override void Cancel()
|
||||
{
|
||||
if (this.backup != null)
|
||||
{
|
||||
|
||||
@@ -4,13 +4,15 @@
|
||||
//
|
||||
|
||||
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.TaskServices;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts
|
||||
{
|
||||
/// <summary>
|
||||
/// Backup parameters passed for execution and scripting
|
||||
/// </summary>
|
||||
public class BackupParams
|
||||
public class BackupParams : IScriptableRequestParams
|
||||
{
|
||||
/// <summary>
|
||||
/// Connection uri
|
||||
@@ -23,9 +25,9 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts
|
||||
public BackupInfo BackupInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True for generating script, false for execution
|
||||
///
|
||||
/// </summary>
|
||||
public bool IsScripting { get; set; }
|
||||
public TaskExecutionMode TaskExecutionMode { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -147,20 +147,6 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts
|
||||
/// </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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -225,6 +225,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
|
||||
{
|
||||
// create task metadata
|
||||
TaskMetadata metadata = TaskMetadata.Create(restoreParams, SR.RestoreTaskName, restoreDataObject, ConnectionServiceInstance);
|
||||
metadata.DatabaseName = restoreParams.TargetDatabaseName;
|
||||
|
||||
// create restore task and perform
|
||||
SqlTask sqlTask = SqlTaskManagerInstance.CreateAndRun<SqlTask>(metadata);
|
||||
@@ -277,23 +278,9 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
|
||||
SqlTask sqlTask = null;
|
||||
|
||||
// create task metadata
|
||||
TaskMetadata metadata = new TaskMetadata();
|
||||
metadata.ServerName = connInfo.ConnectionDetails.ServerName;
|
||||
metadata.DatabaseName = connInfo.ConnectionDetails.DatabaseName;
|
||||
metadata.TaskOperation = backupOperation;
|
||||
|
||||
if (backupParams.IsScripting)
|
||||
{
|
||||
metadata.Name = string.Format("{0} {1}", SR.BackupTaskName, SR.ScriptTaskName);
|
||||
metadata.TaskExecutionMode = TaskExecutionMode.Script;
|
||||
}
|
||||
else
|
||||
{
|
||||
metadata.Name = SR.BackupTaskName;
|
||||
metadata.TaskExecutionMode = TaskExecutionMode.ExecuteAndScript;
|
||||
}
|
||||
|
||||
sqlTask = SqlTaskManagerInstance.CreateAndRun(metadata, this.PerformBackupTaskAsync, this.CancelBackupTaskAsync);
|
||||
TaskMetadata metadata = TaskMetadata.Create(backupParams, SR.BackupTaskName, backupOperation, ConnectionServiceInstance);
|
||||
|
||||
sqlTask = SqlTaskManagerInstance.CreateAndRun<SqlTask>(metadata);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -400,88 +387,5 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
|
||||
{
|
||||
backupOperation.Execute(TaskExecutionMode.Script);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Async task to execute backup
|
||||
/// </summary>
|
||||
/// <param name="sqlTask"></param>
|
||||
/// <returns></returns>
|
||||
internal async Task<TaskResult> PerformBackupTaskAsync(SqlTask sqlTask)
|
||||
{
|
||||
IBackupOperation backupOperation = sqlTask.TaskMetadata.TaskOperation as IBackupOperation;
|
||||
TaskResult result = new TaskResult();
|
||||
|
||||
// Create a task to perform backup
|
||||
await Task.Factory.StartNew(() =>
|
||||
{
|
||||
if (backupOperation != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
sqlTask.AddMessage(SR.TaskInProgress, SqlTaskStatus.InProgress, true);
|
||||
|
||||
// Execute backup
|
||||
backupOperation.Execute(sqlTask.TaskMetadata.TaskExecutionMode);
|
||||
|
||||
// Set result
|
||||
result.TaskStatus = SqlTaskStatus.Succeeded;
|
||||
|
||||
// Send generated script to client
|
||||
if (!String.IsNullOrEmpty(backupOperation.ScriptContent))
|
||||
{
|
||||
sqlTask.AddScript(result.TaskStatus, backupOperation.ScriptContent);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.TaskStatus = SqlTaskStatus.Failed;
|
||||
result.ErrorMessage = string.Format(CultureInfo.InvariantCulture, "error:{0} inner:{1} stacktrace:{2}",
|
||||
ex.Message,
|
||||
ex.InnerException != null ? ex.InnerException.Message : "",
|
||||
ex.StackTrace);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.TaskStatus = SqlTaskStatus.Failed;
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Async task to cancel backup
|
||||
/// </summary>
|
||||
/// <param name="sqlTask"></param>
|
||||
/// <returns></returns>
|
||||
internal async Task<TaskResult> CancelBackupTaskAsync(SqlTask sqlTask)
|
||||
{
|
||||
IBackupOperation backupOperation = sqlTask.TaskMetadata.TaskOperation as IBackupOperation;
|
||||
TaskResult result = new TaskResult();
|
||||
|
||||
await Task.Factory.StartNew(() =>
|
||||
{
|
||||
if (backupOperation != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
backupOperation.Cancel();
|
||||
result.TaskStatus = SqlTaskStatus.Canceled;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.TaskStatus = SqlTaskStatus.Failed;
|
||||
result.ErrorMessage = ex.Message;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.TaskStatus = SqlTaskStatus.Failed;
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +57,8 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
||||
string DefaultTargetDbName { get; }
|
||||
string TargetDatabaseName { get; set; }
|
||||
|
||||
bool CanDropExistingConnections { get; }
|
||||
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
@@ -247,7 +249,6 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
||||
lastBackup = isTheLastOneSelected ?
|
||||
string.Format(CultureInfo.CurrentCulture, SR.TheLastBackupTaken, (backupTimeStr)) : backupTimeStr;
|
||||
}
|
||||
//TODO: find the selected one
|
||||
else if (GetFirstSelectedBackupSetIndex() == 0 && !this.RestorePlanner.RestoreToLastBackup)
|
||||
{
|
||||
lastBackup = this.CurrentRestorePointInTime.Value.ToLongDateString() +
|
||||
@@ -1242,6 +1243,21 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if can close eixisting connections for give database
|
||||
/// </summary>
|
||||
public bool CanDropExistingConnections
|
||||
{
|
||||
get
|
||||
{
|
||||
if (RestorePlan != null && RestorePlanner != null)
|
||||
{
|
||||
return RestorePlan.CanDropExistingConnections(RestorePlanner.DatabaseName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cancels the restore operations
|
||||
/// </summary>
|
||||
|
||||
@@ -482,8 +482,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
||||
{
|
||||
return new OptionValidationResult()
|
||||
{
|
||||
//TODO: make the method public in SMO bool canDropExistingConnections = restoreDataObject.RestorePlan.CanDropExistingConnections(this.Data.RestorePlanner.DatabaseName);
|
||||
IsReadOnly = false
|
||||
IsReadOnly = !restoreDataObject.CanDropExistingConnections
|
||||
};
|
||||
},
|
||||
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
|
||||
|
||||
Reference in New Issue
Block a user