mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-14 01:25:40 -05:00
fixed the issues with restore options (#431)
* fixed the issues with restore options connecting to server without db name
This commit is contained in:
@@ -35,6 +35,11 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts
|
||||
/// </summary>
|
||||
public object DefaultValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Error message if the current value is not valid
|
||||
/// </summary>
|
||||
public object ErrorMessage { get; set; }
|
||||
|
||||
internal static RestorePlanDetailInfo Create(string name, object currentValue, bool isReadOnly = false, bool isVisible = true, object defaultValue = null)
|
||||
{
|
||||
return new RestorePlanDetailInfo
|
||||
|
||||
@@ -15,6 +15,8 @@ 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;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
||||
{
|
||||
@@ -24,6 +26,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
||||
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
|
||||
@@ -169,6 +172,16 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
||||
{
|
||||
response.SessionId = restoreDataObject.SessionId;
|
||||
response.DatabaseName = restoreDataObject.TargetDatabase;
|
||||
response.PlanDetails.Add(RestoreOptionsHelper.TargetDatabaseName, RestorePlanDetailInfo.Create(
|
||||
name: RestoreOptionsHelper.TargetDatabaseName,
|
||||
currentValue: restoreDataObject.TargetDatabase,
|
||||
isReadOnly: !CanChangeTargetDatabase(restoreDataObject)));
|
||||
response.PlanDetails.Add(RestoreOptionsHelper.SourceDatabaseName, RestorePlanDetailInfo.Create(
|
||||
name: RestoreOptionsHelper.SourceDatabaseName,
|
||||
currentValue: restoreDataObject.RestorePlanner.DatabaseName));
|
||||
response.PlanDetails.Add(RestoreOptionsHelper.ReadHeaderFromMedia, RestorePlanDetailInfo.Create(
|
||||
name: RestoreOptionsHelper.ReadHeaderFromMedia,
|
||||
currentValue: restoreDataObject.RestorePlanner.ReadHeaderFromMedia));
|
||||
response.DbFiles = restoreDataObject.DbFiles.Select(x => new RestoreDatabaseFileInfo
|
||||
{
|
||||
FileType = x.DbFileType,
|
||||
@@ -183,10 +196,11 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
||||
response.ErrorMessage = SR.RestoreNotSupported;
|
||||
}
|
||||
|
||||
response.PlanDetails.Add(LastBackupTaken, RestorePlanDetailInfo.Create(LastBackupTaken, restoreDataObject.GetLastBackupTaken()));
|
||||
response.PlanDetails.Add(LastBackupTaken,
|
||||
RestorePlanDetailInfo.Create(name: LastBackupTaken, currentValue: restoreDataObject.GetLastBackupTaken(), isReadOnly: true));
|
||||
|
||||
response.BackupSetsToRestore = restoreDataObject.GetSelectedBakupSets();
|
||||
var dbNames = restoreDataObject.GetSourceDbNames();
|
||||
var dbNames = restoreDataObject.GetPossibleTargerDbNames();
|
||||
response.DatabaseNamesFromBackupSets = dbNames == null ? new string[] { } : dbNames.ToArray();
|
||||
|
||||
RestoreOptionsHelper.AddOptions(response, restoreDataObject);
|
||||
@@ -241,10 +255,15 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
||||
public RestoreDatabaseTaskDataObject CreateRestoreDatabaseTaskDataObject(RestoreParams restoreParams)
|
||||
{
|
||||
RestoreDatabaseTaskDataObject restoreTaskObject = null;
|
||||
restoreTaskObject = CreateRestoreForNewSession(restoreParams.OwnerUri, restoreParams.TargetDatabaseName);
|
||||
string sessionId = string.IsNullOrWhiteSpace(restoreParams.SessionId) ? Guid.NewGuid().ToString() : restoreParams.SessionId;
|
||||
if (!sessions.TryGetValue(sessionId, out restoreTaskObject))
|
||||
{
|
||||
restoreTaskObject = CreateRestoreForNewSession(restoreParams.OwnerUri, restoreParams.TargetDatabaseName);
|
||||
}
|
||||
restoreTaskObject.SessionId = sessionId;
|
||||
restoreTaskObject.RestoreParams = restoreParams;
|
||||
restoreTaskObject.TargetDatabase = restoreParams.TargetDatabaseName;
|
||||
restoreTaskObject.RestorePlanner.DatabaseName = restoreParams.TargetDatabaseName;
|
||||
return restoreTaskObject;
|
||||
}
|
||||
|
||||
@@ -303,13 +322,26 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
||||
{
|
||||
restoreDataObject.RestorePlanner.DatabaseName = restoreDataObject.RestoreParams.SourceDatabaseName;
|
||||
}
|
||||
restoreDataObject.TargetDatabase = restoreDataObject.RestoreParams.TargetDatabaseName;
|
||||
|
||||
RestoreOptionsHelper.UpdateOptionsInPlan(restoreDataObject);
|
||||
if (CanChangeTargetDatabase(restoreDataObject))
|
||||
{
|
||||
restoreDataObject.TargetDatabase = restoreDataObject.RestoreParams.TargetDatabaseName;
|
||||
}
|
||||
else
|
||||
{
|
||||
restoreDataObject.TargetDatabase = restoreDataObject.Server.ConnectionContext.DatabaseName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
restoreDataObject.UpdateRestorePlan();
|
||||
}
|
||||
|
||||
private bool CanChangeTargetDatabase(RestoreDatabaseTaskDataObject restoreDataObject)
|
||||
{
|
||||
return DatabaseUtils.IsSystemDatabaseConnection(restoreDataObject.Server.ConnectionContext.DatabaseName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the restore operation
|
||||
/// </summary>
|
||||
|
||||
@@ -26,15 +26,15 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
||||
|
||||
RestoreOptions RestoreOptions { get; }
|
||||
|
||||
string GetDefaultStandbyFile(string databaseName);
|
||||
bool IsTailLogBackupPossible(string databaseName);
|
||||
bool IsTailLogBackupWithNoRecoveryPossible(string databaseName);
|
||||
string DefaultStandbyFile { get; }
|
||||
bool IsTailLogBackupPossible { get; }
|
||||
bool IsTailLogBackupWithNoRecoveryPossible { get; }
|
||||
|
||||
bool TailLogWithNoRecovery { get; set; }
|
||||
|
||||
string TailLogBackupFile { get; set; }
|
||||
|
||||
string GetDefaultTailLogbackupFile(string databaseName);
|
||||
string DefaultTailLogbackupFile { get; }
|
||||
|
||||
RestorePlan RestorePlan { get; }
|
||||
|
||||
@@ -54,6 +54,8 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
||||
private DatabaseRestorePlanner restorePlanner;
|
||||
private string tailLogBackupFile;
|
||||
private BackupSetsFilterInfo backupSetsFilterInfo = new BackupSetsFilterInfo();
|
||||
private bool? isTailLogBackupPossible = false;
|
||||
private bool? isTailLogBackupWithNoRecoveryPossible = false;
|
||||
|
||||
public RestoreDatabaseTaskDataObject(Server server, String databaseName)
|
||||
{
|
||||
@@ -119,7 +121,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
||||
/// Database names includes in the restore plan
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<String> GetSourceDbNames()
|
||||
public List<String> GetPossibleTargerDbNames()
|
||||
{
|
||||
return Util.GetSourceDbNames(this.restorePlanner.BackupMediaList, this.CredentialName);
|
||||
}
|
||||
@@ -169,7 +171,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
||||
}
|
||||
}
|
||||
|
||||
var itemsToRemove = this.RestorePlanner.BackupMediaList.Where(x => !files.Contains(x.Name));
|
||||
var itemsToRemove = this.RestorePlanner.BackupMediaList.Where(x => !files.Contains(x.Name)).ToList();
|
||||
foreach (var item in itemsToRemove)
|
||||
{
|
||||
this.RestorePlanner.BackupMediaList.Remove(item);
|
||||
@@ -349,7 +351,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
||||
}
|
||||
else
|
||||
{
|
||||
this.dataFilesFolder = PathWrapper.GetDirectoryName(value);
|
||||
this.dataFilesFolder = PathWrapper.GetDirectoryName(value + PathWrapper.PathSeparatorFromServerConnection(Server.ConnectionContext));
|
||||
}
|
||||
if (string.IsNullOrEmpty(this.dataFilesFolder))
|
||||
{
|
||||
@@ -397,7 +399,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
||||
}
|
||||
else
|
||||
{
|
||||
this.logFilesFolder = PathWrapper.GetDirectoryName(value);
|
||||
this.logFilesFolder = PathWrapper.GetDirectoryName(value + PathWrapper.PathSeparatorFromServerConnection(Server.ConnectionContext));
|
||||
}
|
||||
if (string.IsNullOrEmpty(this.logFilesFolder))
|
||||
{
|
||||
@@ -419,32 +421,44 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
||||
/// <returns>
|
||||
/// <c>true</c> if [is tail log backup possible]; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool IsTailLogBackupPossible(string databaseName)
|
||||
public bool IsTailLogBackupPossible
|
||||
{
|
||||
if (this.Server.Version.Major < 9 || String.IsNullOrEmpty(this.restorePlanner.DatabaseName))
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!isTailLogBackupPossible.HasValue)
|
||||
{
|
||||
if (this.Server.Version.Major < 9 || String.IsNullOrEmpty(this.restorePlanner.DatabaseName))
|
||||
{
|
||||
isTailLogBackupPossible = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Database db = this.Server.Databases[this.RestorePlanner.DatabaseName];
|
||||
if (db == null)
|
||||
{
|
||||
isTailLogBackupPossible = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
db.Refresh();
|
||||
if (db.Status != DatabaseStatus.Normal && db.Status != DatabaseStatus.Suspect && db.Status != DatabaseStatus.EmergencyMode)
|
||||
{
|
||||
isTailLogBackupPossible = false;
|
||||
}
|
||||
else if (db.RecoveryModel == RecoveryModel.Full || db.RecoveryModel == RecoveryModel.BulkLogged)
|
||||
{
|
||||
isTailLogBackupPossible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
isTailLogBackupPossible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Database db = this.Server.Databases[databaseName];
|
||||
if (db == null)
|
||||
{
|
||||
return false;
|
||||
return isTailLogBackupPossible.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
db.Refresh();
|
||||
}
|
||||
|
||||
if (db.Status != DatabaseStatus.Normal && db.Status != DatabaseStatus.Suspect && db.Status != DatabaseStatus.EmergencyMode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (db.RecoveryModel == RecoveryModel.Full || db.RecoveryModel == RecoveryModel.BulkLogged)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -453,37 +467,56 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
||||
/// <returns>
|
||||
/// <c>true</c> if [is tail log backup with NORECOVERY possible]; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool IsTailLogBackupWithNoRecoveryPossible(string databaseName)
|
||||
public bool IsTailLogBackupWithNoRecoveryPossible
|
||||
{
|
||||
if (!IsTailLogBackupPossible(databaseName))
|
||||
get
|
||||
{
|
||||
return false;
|
||||
if (!isTailLogBackupWithNoRecoveryPossible.HasValue)
|
||||
{
|
||||
string databaseName = this.RestorePlanner.DatabaseName;
|
||||
if (!IsTailLogBackupPossible)
|
||||
{
|
||||
isTailLogBackupWithNoRecoveryPossible = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Database db = this.Server.Databases[databaseName];
|
||||
if (db == null)
|
||||
{
|
||||
isTailLogBackupWithNoRecoveryPossible = false;
|
||||
}
|
||||
else if (Server.Version.Major > 10 && db.DatabaseEngineType == DatabaseEngineType.Standalone && !String.IsNullOrEmpty(db.AvailabilityGroupName))
|
||||
{
|
||||
isTailLogBackupWithNoRecoveryPossible = false;
|
||||
}
|
||||
else if (db.DatabaseEngineType == DatabaseEngineType.Standalone && db.IsMirroringEnabled)
|
||||
{
|
||||
isTailLogBackupWithNoRecoveryPossible = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
isTailLogBackupWithNoRecoveryPossible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return isTailLogBackupWithNoRecoveryPossible.Value;
|
||||
}
|
||||
|
||||
Database db = this.Server.Databases[databaseName];
|
||||
if (db == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (Server.Version.Major > 10 && db.DatabaseEngineType == DatabaseEngineType.Standalone && !String.IsNullOrEmpty(db.AvailabilityGroupName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (db.DatabaseEngineType == DatabaseEngineType.Standalone && db.IsMirroringEnabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public string GetDefaultStandbyFile(string databaseName)
|
||||
public string DefaultStandbyFile
|
||||
{
|
||||
return Util.GetDefaultStandbyFile(databaseName);
|
||||
get
|
||||
{
|
||||
return Util.GetDefaultStandbyFile(this.RestorePlan != null ? this.RestorePlan.DatabaseName : string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
public string GetDefaultTailLogbackupFile(string databaseName)
|
||||
public string DefaultTailLogbackupFile
|
||||
{
|
||||
return Util.GetDefaultTailLogbackupFile(databaseName);
|
||||
get
|
||||
{
|
||||
return Util.GetDefaultTailLogbackupFile(this.RestorePlan != null ? this.RestorePlan.DatabaseName : string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -605,7 +638,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
||||
{
|
||||
get
|
||||
{
|
||||
var dbNames = GetSourceDbNames();
|
||||
var dbNames = GetPossibleTargerDbNames();
|
||||
string dbName = dbNames.FirstOrDefault();
|
||||
return dbName;
|
||||
}
|
||||
@@ -663,10 +696,6 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
||||
foreach (Restore restore in RestorePlan.RestoreOperations)
|
||||
{
|
||||
BackupSetInfo backupSetInfo = BackupSetInfo.Create(restore, Server);
|
||||
if (this.backupSetsFilterInfo.IsBackupSetSelected(restore.BackupSet))
|
||||
{
|
||||
|
||||
}
|
||||
result.Add(backupSetInfo);
|
||||
}
|
||||
|
||||
@@ -761,11 +790,21 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
||||
return ret;
|
||||
}
|
||||
|
||||
private void ResetOptions()
|
||||
{
|
||||
isTailLogBackupPossible = null;
|
||||
isTailLogBackupWithNoRecoveryPossible = null;
|
||||
bool isTailLogBackupPossibleValue = IsTailLogBackupPossible;
|
||||
bool isTailLogBackupWithNoRecoveryPossibleValue = isTailLogBackupPossibleValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates restore plan
|
||||
/// </summary>
|
||||
public void UpdateRestorePlan()
|
||||
{
|
||||
|
||||
ResetOptions();
|
||||
this.ActiveException = null; //Clear any existing exceptions as the plan is getting recreated.
|
||||
//Clear any existing exceptions as new plan is getting recreated.
|
||||
this.CreateOrUpdateRestorePlanException = null;
|
||||
@@ -781,6 +820,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
||||
{
|
||||
this.RestorePlan = this.CreateRestorePlan(this.RestorePlanner, this.RestoreOptions);
|
||||
this.Util.AddCredentialNameForUrlBackupSet(this.restorePlan, this.CredentialName);
|
||||
RestoreOptionsHelper.UpdateOptionsInPlan(this);
|
||||
if (this.ActiveException == null)
|
||||
{
|
||||
this.dbFiles = this.GetDbFiles();
|
||||
@@ -979,6 +1019,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
||||
// If the collection client sent is null, select everything; otherwise select the items that are selected in client
|
||||
bool backupSetSelected = selectedBackupSetsFromClient == null || selectedBackupSetsFromClient.Any(x => BackUpSetGuidEqualsId(backupSet, x));
|
||||
|
||||
|
||||
if (backupSetSelected)
|
||||
{
|
||||
AddBackupSetsToSelected(index, index);
|
||||
@@ -1016,6 +1057,22 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
//If the second item is not selected and it's a diff backup
|
||||
if (index == 1 && backupSet.BackupSetType == BackupSetType.Differential)
|
||||
{
|
||||
if (this.Server.Version.Major < 9 ||
|
||||
(this.RestorePlan.RestoreOperations.Count >= 3 &&
|
||||
BackupSet.IsBackupSetsInSequence(this.RestorePlan.RestoreOperations[0].BackupSet, this.RestorePlan.RestoreOperations[2].BackupSet)))
|
||||
{
|
||||
// only the item at index 1 won't be selected
|
||||
}
|
||||
else
|
||||
{
|
||||
// nothing after index 1 should be selected
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,525 @@
|
||||
//
|
||||
// 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 Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
||||
{
|
||||
/// <summary>
|
||||
/// A factory class to create restore option info
|
||||
/// </summary>
|
||||
public class RestoreOptionFactory
|
||||
{
|
||||
private static RestoreOptionFactory instance = new RestoreOptionFactory();
|
||||
|
||||
Dictionary<string, OptionBuilder> optionBuilders = new Dictionary<string, OptionBuilder>();
|
||||
|
||||
/// <summary>
|
||||
/// Singleton instance
|
||||
/// </summary>
|
||||
public static RestoreOptionFactory Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create option info using the current values
|
||||
/// </summary>
|
||||
/// <param name="optionKey">Option name</param>
|
||||
/// <param name="restoreDataObject">Restore task object</param>
|
||||
/// <returns></returns>
|
||||
public RestorePlanDetailInfo CreateOptionInfo(string optionKey, IRestoreDatabaseTaskDataObject restoreDataObject)
|
||||
{
|
||||
if(optionBuilders.ContainsKey(optionKey))
|
||||
{
|
||||
return Create(optionKey, restoreDataObject, optionBuilders[optionKey]);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Write(LogLevel.Warning, $"cannot find restore option builder for {optionKey}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the option info by validating the option
|
||||
/// </summary>
|
||||
/// <param name="optionKey"></param>
|
||||
/// <param name="restoreDataObject"></param>
|
||||
/// <param name="optionInfo"></param>
|
||||
public void UpdateOption(string optionKey, IRestoreDatabaseTaskDataObject restoreDataObject, RestorePlanDetailInfo optionInfo)
|
||||
{
|
||||
if (optionBuilders.ContainsKey(optionKey))
|
||||
{
|
||||
var builder = optionBuilders[optionKey];
|
||||
var currentValue = builder.CurrentValueFunction(restoreDataObject);
|
||||
var defaultValue = builder.DefaultValueFunction(restoreDataObject);
|
||||
var validateResult = builder.ValidateFunction(restoreDataObject, currentValue, defaultValue);
|
||||
optionInfo.IsReadOnly = validateResult.IsReadOnly;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Write(LogLevel.Warning, $"cannot find restore option builder for {optionKey}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the option value if restore tak object using the values in the restore request
|
||||
/// </summary>
|
||||
/// <param name="optionKey"></param>
|
||||
/// <param name="restoreDataObject"></param>
|
||||
public void SetValue(string optionKey, IRestoreDatabaseTaskDataObject restoreDataObject)
|
||||
{
|
||||
if(restoreDataObject != null)
|
||||
{
|
||||
if (optionBuilders.ContainsKey(optionKey))
|
||||
{
|
||||
var builder = optionBuilders[optionKey];
|
||||
if (restoreDataObject.RestoreParams != null && restoreDataObject.RestoreParams.Options.ContainsKey(optionKey))
|
||||
{
|
||||
try
|
||||
{
|
||||
var value = restoreDataObject.RestoreParams.GetOptionValue<object>(optionKey);
|
||||
builder.SetValueFunction(restoreDataObject, value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var defaultValue = builder.DefaultValueFunction(restoreDataObject);
|
||||
builder.SetValueFunction(restoreDataObject, defaultValue);
|
||||
Logger.Write(LogLevel.Warning, $"Failed tp set restore option {optionKey} error:{ex.Message}");
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
var defaultValue = builder.DefaultValueFunction(restoreDataObject);
|
||||
builder.SetValueFunction(restoreDataObject, defaultValue);
|
||||
}
|
||||
catch(Exception)
|
||||
{
|
||||
Logger.Write(LogLevel.Warning, $"Failed to set restore option {optionKey} to default value");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Write(LogLevel.Warning, $"cannot find restore option builder for {optionKey}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the options, if option is not set correctly, set to default and return the error
|
||||
/// </summary>
|
||||
/// <param name="optionKey"></param>
|
||||
/// <param name="restoreDataObject"></param>
|
||||
/// <returns></returns>
|
||||
public string ValidateOption(string optionKey, IRestoreDatabaseTaskDataObject restoreDataObject)
|
||||
{
|
||||
string errorMessage = string.Empty;
|
||||
if (optionBuilders.ContainsKey(optionKey))
|
||||
{
|
||||
var builder = optionBuilders[optionKey];
|
||||
var currentValue = builder.CurrentValueFunction(restoreDataObject);
|
||||
var defaultValue = builder.DefaultValueFunction(restoreDataObject);
|
||||
OptionValidationResult result = optionBuilders[optionKey].ValidateFunction(restoreDataObject, currentValue, defaultValue);
|
||||
if (result.IsReadOnly)
|
||||
{
|
||||
if(!ValueEqualsDefault(currentValue, defaultValue))
|
||||
{
|
||||
builder.SetValueFunction(restoreDataObject, defaultValue);
|
||||
errorMessage = $"{optionKey} is ready only and cannot be modified";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMessage = "cannot find restore option builder for {optionKey}";
|
||||
Logger.Write(LogLevel.Warning, errorMessage);
|
||||
}
|
||||
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
private bool ValueEqualsDefault(object currentValue, object defaultValue)
|
||||
{
|
||||
if(currentValue == null && defaultValue == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if(currentValue == null && defaultValue != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (currentValue != null && defaultValue == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return currentValue.Equals(defaultValue);
|
||||
}
|
||||
|
||||
|
||||
private RestoreOptionFactory()
|
||||
{
|
||||
Register(RestoreOptionsHelper.RelocateDbFiles,
|
||||
new OptionBuilder
|
||||
{
|
||||
DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
|
||||
{
|
||||
return false;
|
||||
},
|
||||
CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
|
||||
{
|
||||
return restoreDataObject.RelocateAllFiles;
|
||||
},
|
||||
ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
|
||||
{
|
||||
return new OptionValidationResult
|
||||
{
|
||||
IsReadOnly = restoreDataObject.DbFiles.Count == 0
|
||||
};
|
||||
},
|
||||
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
|
||||
{
|
||||
|
||||
restoreDataObject.RelocateAllFiles = restoreDataObject.RestoreParams.GetOptionValue<bool>(RestoreOptionsHelper.RelocateDbFiles);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
Register(RestoreOptionsHelper.DataFileFolder,
|
||||
new OptionBuilder
|
||||
{
|
||||
DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
|
||||
{
|
||||
return restoreDataObject.DefaultDataFileFolder;
|
||||
},
|
||||
CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
|
||||
{
|
||||
return restoreDataObject.DataFilesFolder;
|
||||
},
|
||||
ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
|
||||
{
|
||||
return new OptionValidationResult
|
||||
{
|
||||
IsReadOnly = !restoreDataObject.RelocateAllFiles
|
||||
};
|
||||
},
|
||||
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
|
||||
{
|
||||
|
||||
restoreDataObject.DataFilesFolder = GetValueAs<string>(value);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
Register(RestoreOptionsHelper.LogFileFolder,
|
||||
new OptionBuilder
|
||||
{
|
||||
DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
|
||||
{
|
||||
return restoreDataObject.DefaultLogFileFolder;
|
||||
},
|
||||
CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
|
||||
{
|
||||
return restoreDataObject.LogFilesFolder;
|
||||
},
|
||||
ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
|
||||
{
|
||||
return new OptionValidationResult
|
||||
{
|
||||
IsReadOnly = !restoreDataObject.RelocateAllFiles
|
||||
};
|
||||
},
|
||||
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
|
||||
{
|
||||
|
||||
restoreDataObject.LogFilesFolder = GetValueAs<string>(value);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
Register(RestoreOptionsHelper.ReplaceDatabase,
|
||||
new OptionBuilder
|
||||
{
|
||||
DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
|
||||
{
|
||||
return false;
|
||||
},
|
||||
CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
|
||||
{
|
||||
return restoreDataObject.RestoreOptions.ReplaceDatabase;
|
||||
},
|
||||
ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
|
||||
{
|
||||
return new OptionValidationResult();
|
||||
},
|
||||
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
|
||||
{
|
||||
|
||||
restoreDataObject.RestoreOptions.ReplaceDatabase = GetValueAs<bool>(value);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
Register(RestoreOptionsHelper.KeepReplication,
|
||||
new OptionBuilder
|
||||
{
|
||||
DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
|
||||
{
|
||||
return false;
|
||||
},
|
||||
CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
|
||||
{
|
||||
return restoreDataObject.RestoreOptions.KeepReplication;
|
||||
},
|
||||
ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
|
||||
{
|
||||
return new OptionValidationResult()
|
||||
{
|
||||
IsReadOnly = restoreDataObject.RestoreOptions.RecoveryState == DatabaseRecoveryState.WithNoRecovery
|
||||
};
|
||||
},
|
||||
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
|
||||
{
|
||||
|
||||
restoreDataObject.RestoreOptions.KeepReplication = GetValueAs<bool>(value);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
Register(RestoreOptionsHelper.SetRestrictedUser,
|
||||
new OptionBuilder
|
||||
{
|
||||
DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
|
||||
{
|
||||
return false;
|
||||
},
|
||||
CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
|
||||
{
|
||||
return restoreDataObject.RestoreOptions.SetRestrictedUser;
|
||||
},
|
||||
ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
|
||||
{
|
||||
return new OptionValidationResult()
|
||||
{
|
||||
};
|
||||
},
|
||||
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
|
||||
{
|
||||
|
||||
restoreDataObject.RestoreOptions.SetRestrictedUser = GetValueAs<bool>(value);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
Register(RestoreOptionsHelper.RecoveryState,
|
||||
new OptionBuilder
|
||||
{
|
||||
DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
|
||||
{
|
||||
return DatabaseRecoveryState.WithRecovery.ToString();
|
||||
},
|
||||
CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
|
||||
{
|
||||
return restoreDataObject.RestoreOptions.RecoveryState.ToString();
|
||||
},
|
||||
ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
|
||||
{
|
||||
return new OptionValidationResult()
|
||||
{
|
||||
};
|
||||
},
|
||||
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
|
||||
{
|
||||
|
||||
restoreDataObject.RestoreOptions.RecoveryState = GetValueAs<DatabaseRecoveryState>(value);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
Register(RestoreOptionsHelper.StandbyFile,
|
||||
new OptionBuilder
|
||||
{
|
||||
DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
|
||||
{
|
||||
return restoreDataObject.DefaultStandbyFile;
|
||||
},
|
||||
CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
|
||||
{
|
||||
return restoreDataObject.RestoreOptions.StandByFile;
|
||||
},
|
||||
ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
|
||||
{
|
||||
return new OptionValidationResult()
|
||||
{
|
||||
IsReadOnly = restoreDataObject.RestoreOptions.RecoveryState != DatabaseRecoveryState.WithStandBy
|
||||
};
|
||||
},
|
||||
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
|
||||
{
|
||||
|
||||
restoreDataObject.RestoreOptions.StandByFile = GetValueAs<string>(value);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
Register(RestoreOptionsHelper.BackupTailLog,
|
||||
new OptionBuilder
|
||||
{
|
||||
DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
|
||||
{
|
||||
return restoreDataObject.IsTailLogBackupPossible;
|
||||
},
|
||||
CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
|
||||
{
|
||||
return restoreDataObject.BackupTailLog;
|
||||
},
|
||||
ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
|
||||
{
|
||||
return new OptionValidationResult()
|
||||
{
|
||||
IsReadOnly = !restoreDataObject.IsTailLogBackupPossible
|
||||
};
|
||||
},
|
||||
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
|
||||
{
|
||||
|
||||
restoreDataObject.BackupTailLog = GetValueAs<bool>(value);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
Register(RestoreOptionsHelper.TailLogBackupFile,
|
||||
new OptionBuilder
|
||||
{
|
||||
DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
|
||||
{
|
||||
return restoreDataObject.DefaultTailLogbackupFile;
|
||||
},
|
||||
CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
|
||||
{
|
||||
return restoreDataObject.TailLogBackupFile;
|
||||
},
|
||||
ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
|
||||
{
|
||||
return new OptionValidationResult()
|
||||
{
|
||||
IsReadOnly = !restoreDataObject.BackupTailLog | !restoreDataObject.IsTailLogBackupPossible
|
||||
};
|
||||
},
|
||||
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
|
||||
{
|
||||
|
||||
restoreDataObject.TailLogBackupFile = GetValueAs<string>(value);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
Register(RestoreOptionsHelper.TailLogWithNoRecovery,
|
||||
new OptionBuilder
|
||||
{
|
||||
DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
|
||||
{
|
||||
return restoreDataObject.IsTailLogBackupWithNoRecoveryPossible;
|
||||
},
|
||||
CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
|
||||
{
|
||||
return restoreDataObject.TailLogWithNoRecovery;
|
||||
},
|
||||
ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
|
||||
{
|
||||
return new OptionValidationResult()
|
||||
{
|
||||
IsReadOnly = !restoreDataObject.BackupTailLog | !restoreDataObject.IsTailLogBackupWithNoRecoveryPossible
|
||||
};
|
||||
},
|
||||
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
|
||||
{
|
||||
|
||||
restoreDataObject.TailLogWithNoRecovery = GetValueAs<bool>(value);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
Register(RestoreOptionsHelper.CloseExistingConnections,
|
||||
new OptionBuilder
|
||||
{
|
||||
DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
|
||||
{
|
||||
return false;
|
||||
},
|
||||
CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
|
||||
{
|
||||
return restoreDataObject.CloseExistingConnections;
|
||||
},
|
||||
ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
|
||||
{
|
||||
return new OptionValidationResult()
|
||||
{
|
||||
//TODO: make the method public in SMO bool canDropExistingConnections = restoreDataObject.RestorePlan.CanDropExistingConnections(this.Data.RestorePlanner.DatabaseName);
|
||||
IsReadOnly = false
|
||||
};
|
||||
},
|
||||
SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
|
||||
{
|
||||
|
||||
restoreDataObject.CloseExistingConnections = GetValueAs<bool>(value);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
internal T GetValueAs<T>(object value)
|
||||
{
|
||||
return GeneralRequestDetails.GetValueAs<T>(value);
|
||||
}
|
||||
|
||||
private void Register(string optionKey, OptionBuilder optionBuilder)
|
||||
{
|
||||
optionBuilders.Add(optionKey, optionBuilder);
|
||||
}
|
||||
|
||||
private RestorePlanDetailInfo Create(
|
||||
string optionKey,
|
||||
IRestoreDatabaseTaskDataObject restoreDataObject,
|
||||
OptionBuilder optionBuilder)
|
||||
{
|
||||
object currnetValue = optionBuilder.CurrentValueFunction(restoreDataObject);
|
||||
object defaultValue = optionBuilder.DefaultValueFunction(restoreDataObject);
|
||||
OptionValidationResult validationResult = optionBuilder.ValidateFunction(restoreDataObject, currnetValue, defaultValue);
|
||||
return new RestorePlanDetailInfo
|
||||
{
|
||||
Name = optionKey,
|
||||
CurrentValue = currnetValue,
|
||||
DefaultValue = defaultValue,
|
||||
IsReadOnly = validationResult.IsReadOnly,
|
||||
IsVisiable = validationResult.IsVisible,
|
||||
ErrorMessage = validationResult.ErrorMessage
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
internal class OptionBuilder
|
||||
{
|
||||
public Func<IRestoreDatabaseTaskDataObject, object> DefaultValueFunction { get; set; }
|
||||
public Func<IRestoreDatabaseTaskDataObject, object, object, OptionValidationResult> ValidateFunction { get; set; }
|
||||
public Func<IRestoreDatabaseTaskDataObject, object> CurrentValueFunction { get; set; }
|
||||
public Func<IRestoreDatabaseTaskDataObject, object, bool> SetValueFunction { get; set; }
|
||||
}
|
||||
|
||||
internal class OptionValidationResult
|
||||
{
|
||||
public OptionValidationResult()
|
||||
{
|
||||
IsVisible = true;
|
||||
IsReadOnly = false;
|
||||
ErrorMessage = string.Empty;
|
||||
}
|
||||
public bool IsReadOnly { get; set; }
|
||||
public bool IsVisible { get; set; }
|
||||
|
||||
public string ErrorMessage { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,11 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
|
||||
{
|
||||
public class RestoreOptionsHelper
|
||||
{
|
||||
//The list of name that service sends to client as options
|
||||
private static string[] optionNames = new string[] { KeepReplication, ReplaceDatabase , SetRestrictedUser, RecoveryState ,
|
||||
BackupTailLog , TailLogBackupFile, TailLogWithNoRecovery, CloseExistingConnections, RelocateDbFiles, DataFileFolder, LogFileFolder,
|
||||
StandbyFile,
|
||||
};
|
||||
//The key names of restore info in the resquest of response
|
||||
|
||||
//Option name keepReplication
|
||||
@@ -235,125 +240,21 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
|
||||
Validate.IsNotNull(nameof(restoreDataObject), restoreDataObject);
|
||||
|
||||
Dictionary<string, RestorePlanDetailInfo> options = new Dictionary<string, RestorePlanDetailInfo>();
|
||||
string databaseName = restoreDataObject.RestorePlan == null ? string.Empty : restoreDataObject.RestorePlan.DatabaseName;
|
||||
//Files
|
||||
|
||||
// Default Data folder path in the target server
|
||||
options.Add(RestoreOptionsHelper.DataFileFolder, RestorePlanDetailInfo.Create(
|
||||
name: RestoreOptionsHelper.DataFileFolder,
|
||||
currentValue: restoreDataObject.DataFilesFolder,
|
||||
defaultValue: restoreDataObject.DefaultDataFileFolder,
|
||||
isReadOnly: !restoreDataObject.RelocateAllFiles,
|
||||
isVisible: true
|
||||
));
|
||||
|
||||
// Default log folder path in the target server
|
||||
options.Add(RestoreOptionsHelper.LogFileFolder, RestorePlanDetailInfo.Create(
|
||||
name: RestoreOptionsHelper.LogFileFolder,
|
||||
currentValue: restoreDataObject.LogFilesFolder,
|
||||
defaultValue: restoreDataObject.DefaultLogFileFolder,
|
||||
isReadOnly: !restoreDataObject.RelocateAllFiles,
|
||||
isVisible: true
|
||||
));
|
||||
|
||||
// Relocate all files
|
||||
options.Add(RestoreOptionsHelper.RelocateDbFiles, RestorePlanDetailInfo.Create(
|
||||
name: RestoreOptionsHelper.RelocateDbFiles,
|
||||
currentValue: restoreDataObject.RelocateAllFiles,
|
||||
defaultValue: false,
|
||||
isReadOnly: restoreDataObject.DbFiles.Count == 0,
|
||||
isVisible: true
|
||||
));
|
||||
|
||||
|
||||
//Options
|
||||
|
||||
//With Replace
|
||||
options.Add(RestoreOptionsHelper.ReplaceDatabase, RestorePlanDetailInfo.Create(
|
||||
name: RestoreOptionsHelper.ReplaceDatabase,
|
||||
currentValue: restoreDataObject.RestoreOptions.ReplaceDatabase,
|
||||
defaultValue: false,
|
||||
isReadOnly: false,
|
||||
isVisible: true
|
||||
));
|
||||
|
||||
//Keep replication
|
||||
options.Add(RestoreOptionsHelper.KeepReplication, RestorePlanDetailInfo.Create(
|
||||
name: RestoreOptionsHelper.KeepReplication,
|
||||
currentValue: restoreDataObject.RestoreOptions.KeepReplication,
|
||||
defaultValue: false,
|
||||
isReadOnly: restoreDataObject.RestoreOptions.RecoveryState == DatabaseRecoveryState.WithNoRecovery,
|
||||
isVisible: true
|
||||
));
|
||||
|
||||
//Restricted user
|
||||
options.Add(RestoreOptionsHelper.SetRestrictedUser, RestorePlanDetailInfo.Create(
|
||||
name: RestoreOptionsHelper.SetRestrictedUser,
|
||||
currentValue: restoreDataObject.RestoreOptions.SetRestrictedUser,
|
||||
defaultValue: false,
|
||||
isReadOnly: false,
|
||||
isVisible: true
|
||||
));
|
||||
|
||||
//State recovery
|
||||
options.Add(RestoreOptionsHelper.RecoveryState, RestorePlanDetailInfo.Create(
|
||||
name: RestoreOptionsHelper.RecoveryState,
|
||||
currentValue: restoreDataObject.RestoreOptions.RecoveryState.ToString(),
|
||||
defaultValue: DatabaseRecoveryState.WithRecovery.ToString(),
|
||||
isReadOnly: false,
|
||||
isVisible: true
|
||||
));
|
||||
|
||||
// stand by file path for when RESTORE WITH STANDBY is selected
|
||||
options.Add(RestoreOptionsHelper.StandbyFile, RestorePlanDetailInfo.Create(
|
||||
name: RestoreOptionsHelper.StandbyFile,
|
||||
currentValue: restoreDataObject.RestoreOptions.StandByFile,
|
||||
defaultValue: restoreDataObject.GetDefaultStandbyFile(databaseName),
|
||||
isReadOnly: restoreDataObject.RestoreOptions.RecoveryState != DatabaseRecoveryState.WithStandBy,
|
||||
isVisible: true
|
||||
));
|
||||
|
||||
// Tail-log backup
|
||||
// TODO:These methods are internal in SMO. after making them public, they can be removed from RestoreDatabaseTaskDataObject
|
||||
bool isTailLogBackupPossible = restoreDataObject.IsTailLogBackupPossible(databaseName);
|
||||
bool isTailLogBackupWithNoRecoveryPossible = restoreDataObject.IsTailLogBackupWithNoRecoveryPossible(databaseName);
|
||||
|
||||
options.Add(RestoreOptionsHelper.BackupTailLog, RestorePlanDetailInfo.Create(
|
||||
name: RestoreOptionsHelper.BackupTailLog,
|
||||
currentValue: restoreDataObject.BackupTailLog,
|
||||
defaultValue: isTailLogBackupPossible,
|
||||
isReadOnly: !isTailLogBackupPossible,
|
||||
isVisible: true
|
||||
));
|
||||
|
||||
options.Add(RestoreOptionsHelper.TailLogBackupFile, RestorePlanDetailInfo.Create(
|
||||
name: RestoreOptionsHelper.TailLogBackupFile,
|
||||
currentValue: restoreDataObject.TailLogBackupFile,
|
||||
defaultValue: restoreDataObject.GetDefaultTailLogbackupFile(databaseName),
|
||||
isReadOnly: !isTailLogBackupPossible,
|
||||
isVisible: true
|
||||
));
|
||||
|
||||
options.Add(RestoreOptionsHelper.TailLogWithNoRecovery, RestorePlanDetailInfo.Create(
|
||||
name: RestoreOptionsHelper.TailLogWithNoRecovery,
|
||||
currentValue: restoreDataObject.TailLogWithNoRecovery,
|
||||
defaultValue: isTailLogBackupWithNoRecoveryPossible,
|
||||
isReadOnly: !isTailLogBackupWithNoRecoveryPossible,
|
||||
isVisible: true
|
||||
));
|
||||
|
||||
|
||||
//TODO: make the method public in SMO bool canDropExistingConnections = restoreDataObject.RestorePlan.CanDropExistingConnections(this.Data.RestorePlanner.DatabaseName);
|
||||
options.Add(RestoreOptionsHelper.CloseExistingConnections, RestorePlanDetailInfo.Create(
|
||||
name: RestoreOptionsHelper.CloseExistingConnections,
|
||||
currentValue: restoreDataObject.CloseExistingConnections,
|
||||
defaultValue: false,
|
||||
isReadOnly: false, //TODO: !canDropExistingConnections
|
||||
isVisible: true
|
||||
));
|
||||
RestoreOptionFactory restoreOptionFactory = RestoreOptionFactory.Instance;
|
||||
foreach (var optionKey in optionNames)
|
||||
{
|
||||
var optionInfo = restoreOptionFactory.CreateOptionInfo(optionKey, restoreDataObject);
|
||||
options.Add(optionKey, optionInfo);
|
||||
}
|
||||
|
||||
// After all options are set verify them all again to set the read only
|
||||
foreach (var optionKey in optionNames)
|
||||
{
|
||||
restoreOptionFactory.UpdateOption(optionKey, restoreDataObject, options[optionKey]);
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add options to restore plan response
|
||||
/// </summary>
|
||||
@@ -372,58 +273,29 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
|
||||
}
|
||||
}
|
||||
|
||||
internal static T GetOptionValue<T>(string optionkey, Dictionary<string, RestorePlanDetailInfo> optionsMetadata, IRestoreDatabaseTaskDataObject restoreDataObject)
|
||||
{
|
||||
RestorePlanDetailInfo optionMetadata = null;
|
||||
if(optionsMetadata.TryGetValue(optionkey, out optionMetadata))
|
||||
{
|
||||
if (!optionMetadata.IsReadOnly)
|
||||
{
|
||||
return restoreDataObject.RestoreParams.GetOptionValue<T>(optionkey);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (T)Convert.ChangeType(optionMetadata.DefaultValue, typeof(T));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load options in restore plan
|
||||
/// </summary>
|
||||
internal static void UpdateOptionsInPlan(IRestoreDatabaseTaskDataObject restoreDataObject)
|
||||
{
|
||||
var options = RestoreOptionsHelper.CreateRestorePlanOptions(restoreDataObject);
|
||||
RestoreOptionFactory restoreOptionFactory = RestoreOptionFactory.Instance;
|
||||
|
||||
//Files
|
||||
restoreDataObject.LogFilesFolder = GetOptionValue<string>(RestoreOptionsHelper.LogFileFolder, options, restoreDataObject);
|
||||
restoreDataObject.DataFilesFolder = GetOptionValue<string>(RestoreOptionsHelper.DataFileFolder, options, restoreDataObject);
|
||||
restoreDataObject.RelocateAllFiles = GetOptionValue<bool>(RestoreOptionsHelper.RelocateDbFiles, options, restoreDataObject);
|
||||
|
||||
//Options
|
||||
object databaseRecoveryState;
|
||||
|
||||
string recoveryState = GetOptionValue<string>(RestoreOptionsHelper.RecoveryState, options, restoreDataObject);
|
||||
if (Enum.TryParse(typeof(DatabaseRecoveryState), recoveryState, out databaseRecoveryState))
|
||||
foreach (var optionKey in optionNames)
|
||||
{
|
||||
restoreDataObject.RestoreOptions.RecoveryState = (DatabaseRecoveryState)databaseRecoveryState;
|
||||
restoreOptionFactory.SetValue(optionKey, restoreDataObject);
|
||||
}
|
||||
restoreDataObject.RestoreOptions.KeepReplication = GetOptionValue<bool>(RestoreOptionsHelper.KeepReplication, options, restoreDataObject);
|
||||
restoreDataObject.RestoreOptions.ReplaceDatabase = GetOptionValue<bool>(RestoreOptionsHelper.ReplaceDatabase, options, restoreDataObject);
|
||||
restoreDataObject.RestoreOptions.SetRestrictedUser = GetOptionValue<bool>(RestoreOptionsHelper.SetRestrictedUser, options, restoreDataObject);
|
||||
restoreDataObject.RestoreOptions.StandByFile = GetOptionValue<string>(RestoreOptionsHelper.StandbyFile, options, restoreDataObject);
|
||||
|
||||
|
||||
|
||||
restoreDataObject.BackupTailLog = GetOptionValue<bool>(RestoreOptionsHelper.BackupTailLog, options, restoreDataObject);
|
||||
restoreDataObject.TailLogBackupFile = GetOptionValue<string>(RestoreOptionsHelper.TailLogBackupFile, options, restoreDataObject);
|
||||
restoreDataObject.TailLogWithNoRecovery = GetOptionValue<bool>(RestoreOptionsHelper.TailLogWithNoRecovery, options, restoreDataObject);
|
||||
|
||||
restoreDataObject.CloseExistingConnections = GetOptionValue<bool>(RestoreOptionsHelper.CloseExistingConnections, options, restoreDataObject);
|
||||
//After all options are set do a vaidation so any invalid option set to default
|
||||
foreach (var optionKey in optionNames)
|
||||
{
|
||||
string error = restoreOptionFactory.ValidateOption(optionKey, restoreDataObject);
|
||||
if (!string.IsNullOrEmpty(error))
|
||||
{
|
||||
//TODO: we could send back the error message so client knows the option is set incorrectly
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ using System.Globalization;
|
||||
using Microsoft.SqlTools.ServiceLayer.Metadata.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
|
||||
@@ -292,7 +293,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes
|
||||
Debug.Assert(IsAlwaysLeaf == false);
|
||||
|
||||
SmoQueryContext context = this.GetContextAs<SmoQueryContext>();
|
||||
bool includeSystemObjects = context != null && context.Database != null ? ObjectExplorerUtils.IsSystemDatabaseConnection(context.Database.Name) : true;
|
||||
bool includeSystemObjects = context != null && context.Database != null ? DatabaseUtils.IsSystemDatabaseConnection(context.Database.Name) : true;
|
||||
|
||||
|
||||
if (children.IsPopulating || context == null)
|
||||
|
||||
@@ -21,6 +21,7 @@ using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes;
|
||||
using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel;
|
||||
using Microsoft.SqlTools.ServiceLayer.SqlContext;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
|
||||
@@ -617,7 +618,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer
|
||||
{
|
||||
ServerNode rootNode = new ServerNode(response, serviceProvider);
|
||||
var session = new ObjectExplorerSession(response.OwnerUri, rootNode, serviceProvider, serviceProvider.GetService<ConnectionService>());
|
||||
if (!ObjectExplorerUtils.IsSystemDatabaseConnection(response.ConnectionSummary.DatabaseName))
|
||||
if (!DatabaseUtils.IsSystemDatabaseConnection(response.ConnectionSummary.DatabaseName))
|
||||
{
|
||||
// Assuming the databases are in a folder under server node
|
||||
DatabaseTreeNode databaseNode = new DatabaseTreeNode(rootNode, response.ConnectionSummary.DatabaseName);
|
||||
|
||||
@@ -73,19 +73,5 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the database is a system database
|
||||
/// </summary>
|
||||
/// <param name="databaseName">the name of database</param>
|
||||
/// <returns>return true if the database is a system database</returns>
|
||||
public static bool IsSystemDatabaseConnection(string databaseName)
|
||||
{
|
||||
return (string.IsNullOrWhiteSpace(databaseName) ||
|
||||
string.Compare(databaseName, CommonConstants.MasterDatabaseName, StringComparison.OrdinalIgnoreCase) == 0 ||
|
||||
string.Compare(databaseName, CommonConstants.MsdbDatabaseName, StringComparison.OrdinalIgnoreCase) == 0 ||
|
||||
string.Compare(databaseName, CommonConstants.ModelDatabaseName, StringComparison.OrdinalIgnoreCase) == 0 ||
|
||||
string.Compare(databaseName, CommonConstants.TempDbDatabaseName, StringComparison.OrdinalIgnoreCase) == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel
|
||||
|
||||
// TODO Consider adding IsAuthenticatingDatabaseMaster check in the code and
|
||||
// referencing result here
|
||||
if (!ObjectExplorerUtils.IsSystemDatabaseConnection(connectionSummary.DatabaseName))
|
||||
if (!DatabaseUtils.IsSystemDatabaseConnection(connectionSummary.DatabaseName))
|
||||
{
|
||||
// We either have an azure with a database specified or a Denali database using a contained user
|
||||
if (string.IsNullOrWhiteSpace(userName))
|
||||
|
||||
26
src/Microsoft.SqlTools.ServiceLayer/Utility/DatabaseUtils.cs
Normal file
26
src/Microsoft.SqlTools.ServiceLayer/Utility/DatabaseUtils.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// 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.Utility
|
||||
{
|
||||
public class DatabaseUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Check if the database is a system database
|
||||
/// </summary>
|
||||
/// <param name="databaseName">the name of database</param>
|
||||
/// <returns>return true if the database is a system database</returns>
|
||||
public static bool IsSystemDatabaseConnection(string databaseName)
|
||||
{
|
||||
return (string.IsNullOrWhiteSpace(databaseName) ||
|
||||
string.Compare(databaseName, CommonConstants.MasterDatabaseName, StringComparison.OrdinalIgnoreCase) == 0 ||
|
||||
string.Compare(databaseName, CommonConstants.MsdbDatabaseName, StringComparison.OrdinalIgnoreCase) == 0 ||
|
||||
string.Compare(databaseName, CommonConstants.ModelDatabaseName, StringComparison.OrdinalIgnoreCase) == 0 ||
|
||||
string.Compare(databaseName, CommonConstants.TempDbDatabaseName, StringComparison.OrdinalIgnoreCase) == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,18 +25,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
|
||||
object value = Options[name];
|
||||
try
|
||||
{
|
||||
if (value != null && (typeof(T) != value.GetType()))
|
||||
{
|
||||
if (typeof(T) == typeof(int) || typeof(T) == typeof(int?))
|
||||
{
|
||||
value = Convert.ToInt32(value);
|
||||
}
|
||||
else if (typeof(T) == typeof(bool) || typeof(T) == typeof(bool?))
|
||||
{
|
||||
value = Convert.ToBoolean(value);
|
||||
}
|
||||
}
|
||||
result = value != null ? (T)value : default(T);
|
||||
result = GetValueAs<T>(value);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -48,6 +37,42 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static T GetValueAs<T>(object value)
|
||||
{
|
||||
T result = default(T);
|
||||
|
||||
if (value != null && (typeof(T) != value.GetType()))
|
||||
{
|
||||
if (typeof(T) == typeof(int) || typeof(T) == typeof(int?))
|
||||
{
|
||||
value = Convert.ToInt32(value);
|
||||
}
|
||||
else if (typeof(T) == typeof(bool) || typeof(T) == typeof(bool?))
|
||||
{
|
||||
value = Convert.ToBoolean(value);
|
||||
}
|
||||
else if (typeof(T).IsEnum)
|
||||
{
|
||||
object enumValue;
|
||||
if (Enum.TryParse(typeof(T), value.ToString(), out enumValue))
|
||||
{
|
||||
value = (T)enumValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (value != null && (typeof(T).IsEnum))
|
||||
{
|
||||
object enumValue;
|
||||
if (Enum.TryParse(typeof(T), value.ToString(), out enumValue))
|
||||
{
|
||||
value = enumValue;
|
||||
}
|
||||
}
|
||||
result = value != null ? (T)value : default(T);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void SetOptionValue<T>(string name, T value)
|
||||
{
|
||||
Options = Options ?? new Dictionary<string, object>();
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// 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 Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
|
||||
{
|
||||
public class RestoreDatabaseTaskDataObjectStub : IRestoreDatabaseTaskDataObject
|
||||
{
|
||||
public string DataFilesFolder { get; set; }
|
||||
|
||||
public string DefaultDataFileFolder { get; set; }
|
||||
|
||||
public bool RelocateAllFiles { get; set; }
|
||||
public string LogFilesFolder { get; set; }
|
||||
|
||||
public string DefaultLogFileFolder { get; set; }
|
||||
|
||||
public List<DbFile> DbFiles { get; set; }
|
||||
|
||||
public RestoreOptions RestoreOptions { get; set; }
|
||||
|
||||
public bool IsTailLogBackupPossible { get; set; }
|
||||
|
||||
public bool IsTailLogBackupWithNoRecoveryPossible { get; set; }
|
||||
|
||||
public bool TailLogWithNoRecovery { get; set; }
|
||||
public string TailLogBackupFile { get; set; }
|
||||
|
||||
public RestorePlan RestorePlan { get; set; }
|
||||
|
||||
public bool CloseExistingConnections { get; set; }
|
||||
public RestoreParams RestoreParams { get; set; }
|
||||
public bool BackupTailLog { get; set; }
|
||||
|
||||
public string DefaultStandbyFile { get; set; }
|
||||
|
||||
public string DefaultTailLogbackupFile { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery;
|
||||
@@ -20,9 +21,9 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
|
||||
public void VerifyOptionsCreatedSuccessfullyIsResponse()
|
||||
{
|
||||
GeneralRequestDetails optionValues = CreateOptionsTestData();
|
||||
Mock<IRestoreDatabaseTaskDataObject> restoreDatabaseTaskDataObject = CreateRestoreDatabaseTaskDataObject(optionValues);
|
||||
IRestoreDatabaseTaskDataObject restoreDatabaseTaskDataObject = CreateRestoreDatabaseTaskDataObject(optionValues);
|
||||
|
||||
Dictionary<string, RestorePlanDetailInfo> result = RestoreOptionsHelper.CreateRestorePlanOptions(restoreDatabaseTaskDataObject.Object);
|
||||
Dictionary<string, RestorePlanDetailInfo> result = RestoreOptionsHelper.CreateRestorePlanOptions(restoreDatabaseTaskDataObject);
|
||||
Assert.NotNull(result);
|
||||
VerifyOptions(result, optionValues);
|
||||
}
|
||||
@@ -32,9 +33,9 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
|
||||
{
|
||||
GeneralRequestDetails optionValues = CreateOptionsTestData();
|
||||
optionValues.Options["DbFiles"] = new List<DbFile>();
|
||||
Mock <IRestoreDatabaseTaskDataObject> restoreDatabaseTaskDataObject = CreateRestoreDatabaseTaskDataObject(optionValues);
|
||||
IRestoreDatabaseTaskDataObject restoreDatabaseTaskDataObject = CreateRestoreDatabaseTaskDataObject(optionValues);
|
||||
|
||||
Dictionary<string, RestorePlanDetailInfo> result = RestoreOptionsHelper.CreateRestorePlanOptions(restoreDatabaseTaskDataObject.Object);
|
||||
Dictionary<string, RestorePlanDetailInfo> result = RestoreOptionsHelper.CreateRestorePlanOptions(restoreDatabaseTaskDataObject);
|
||||
Assert.NotNull(result);
|
||||
VerifyOptions(result, optionValues);
|
||||
Assert.True(result[RestoreOptionsHelper.RelocateDbFiles].IsReadOnly);
|
||||
@@ -45,9 +46,9 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
|
||||
{
|
||||
GeneralRequestDetails optionValues = CreateOptionsTestData();
|
||||
optionValues.Options["IsTailLogBackupPossible"] = false;
|
||||
Mock<IRestoreDatabaseTaskDataObject> restoreDatabaseTaskDataObject = CreateRestoreDatabaseTaskDataObject(optionValues);
|
||||
IRestoreDatabaseTaskDataObject restoreDatabaseTaskDataObject = CreateRestoreDatabaseTaskDataObject(optionValues);
|
||||
|
||||
Dictionary<string, RestorePlanDetailInfo> result = RestoreOptionsHelper.CreateRestorePlanOptions(restoreDatabaseTaskDataObject.Object);
|
||||
Dictionary<string, RestorePlanDetailInfo> result = RestoreOptionsHelper.CreateRestorePlanOptions(restoreDatabaseTaskDataObject);
|
||||
Assert.NotNull(result);
|
||||
VerifyOptions(result, optionValues);
|
||||
Assert.True(result[RestoreOptionsHelper.BackupTailLog].IsReadOnly);
|
||||
@@ -59,9 +60,9 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
|
||||
{
|
||||
GeneralRequestDetails optionValues = CreateOptionsTestData();
|
||||
optionValues.Options["IsTailLogBackupWithNoRecoveryPossible"] = false;
|
||||
Mock<IRestoreDatabaseTaskDataObject> restoreDatabaseTaskDataObject = CreateRestoreDatabaseTaskDataObject(optionValues);
|
||||
IRestoreDatabaseTaskDataObject restoreDatabaseTaskDataObject = CreateRestoreDatabaseTaskDataObject(optionValues);
|
||||
|
||||
Dictionary<string, RestorePlanDetailInfo> result = RestoreOptionsHelper.CreateRestorePlanOptions(restoreDatabaseTaskDataObject.Object);
|
||||
Dictionary<string, RestorePlanDetailInfo> result = RestoreOptionsHelper.CreateRestorePlanOptions(restoreDatabaseTaskDataObject);
|
||||
Assert.NotNull(result);
|
||||
VerifyOptions(result, optionValues);
|
||||
Assert.True(result[RestoreOptionsHelper.TailLogWithNoRecovery].IsReadOnly);
|
||||
@@ -72,9 +73,9 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
|
||||
{
|
||||
GeneralRequestDetails optionValues = CreateOptionsTestData();
|
||||
optionValues.Options[RestoreOptionsHelper.RecoveryState] = DatabaseRecoveryState.WithStandBy;
|
||||
Mock<IRestoreDatabaseTaskDataObject> restoreDatabaseTaskDataObject = CreateRestoreDatabaseTaskDataObject(optionValues);
|
||||
IRestoreDatabaseTaskDataObject restoreDatabaseTaskDataObject = CreateRestoreDatabaseTaskDataObject(optionValues);
|
||||
|
||||
Dictionary<string, RestorePlanDetailInfo> result = RestoreOptionsHelper.CreateRestorePlanOptions(restoreDatabaseTaskDataObject.Object);
|
||||
Dictionary<string, RestorePlanDetailInfo> result = RestoreOptionsHelper.CreateRestorePlanOptions(restoreDatabaseTaskDataObject);
|
||||
Assert.NotNull(result);
|
||||
VerifyOptions(result, optionValues);
|
||||
Assert.False(result[RestoreOptionsHelper.StandbyFile].IsReadOnly);
|
||||
@@ -85,9 +86,9 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
|
||||
{
|
||||
GeneralRequestDetails optionValues = CreateOptionsTestData();
|
||||
optionValues.Options[RestoreOptionsHelper.RecoveryState] = DatabaseRecoveryState.WithNoRecovery;
|
||||
Mock<IRestoreDatabaseTaskDataObject> restoreDatabaseTaskDataObject = CreateRestoreDatabaseTaskDataObject(optionValues);
|
||||
IRestoreDatabaseTaskDataObject restoreDatabaseTaskDataObject = CreateRestoreDatabaseTaskDataObject(optionValues);
|
||||
|
||||
Dictionary<string, RestorePlanDetailInfo> result = RestoreOptionsHelper.CreateRestorePlanOptions(restoreDatabaseTaskDataObject.Object);
|
||||
Dictionary<string, RestorePlanDetailInfo> result = RestoreOptionsHelper.CreateRestorePlanOptions(restoreDatabaseTaskDataObject);
|
||||
Assert.NotNull(result);
|
||||
VerifyOptions(result, optionValues);
|
||||
Assert.True(result[RestoreOptionsHelper.KeepReplication].IsReadOnly);
|
||||
@@ -99,12 +100,13 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
|
||||
RestoreParams restoreParams = CreateOptionsTestData();
|
||||
restoreParams.Options[RestoreOptionsHelper.RecoveryState] = DatabaseRecoveryState.WithNoRecovery;
|
||||
|
||||
Mock<IRestoreDatabaseTaskDataObject> restoreDatabaseTaskDataObject = CreateRestoreDatabaseTaskDataObject(restoreParams);
|
||||
Dictionary<string, RestorePlanDetailInfo> options = RestoreOptionsHelper.CreateRestorePlanOptions(restoreDatabaseTaskDataObject.Object);
|
||||
IRestoreDatabaseTaskDataObject restoreDatabaseTaskDataObject = CreateRestoreDatabaseTaskDataObject(restoreParams);
|
||||
Dictionary<string, RestorePlanDetailInfo> options = RestoreOptionsHelper.CreateRestorePlanOptions(restoreDatabaseTaskDataObject);
|
||||
|
||||
restoreParams.Options[RestoreOptionsHelper.KeepReplication] = true;
|
||||
|
||||
bool actual = RestoreOptionsHelper.GetOptionValue<bool>(RestoreOptionsHelper.KeepReplication, options, restoreDatabaseTaskDataObject.Object);
|
||||
RestoreOptionsHelper.UpdateOptionsInPlan(restoreDatabaseTaskDataObject);
|
||||
bool actual = restoreDatabaseTaskDataObject.RestoreOptions.KeepReplication;
|
||||
bool expected = (bool)options[RestoreOptionsHelper.KeepReplication].DefaultValue;
|
||||
|
||||
Assert.Equal(actual, expected);
|
||||
@@ -114,14 +116,15 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
|
||||
public void KeepReplicationShouldSetToValueInRequestGivenRecoveryStateWithRecovery()
|
||||
{
|
||||
RestoreParams restoreParams = CreateOptionsTestData();
|
||||
|
||||
|
||||
restoreParams.Options[RestoreOptionsHelper.RecoveryState] = DatabaseRecoveryState.WithRecovery;
|
||||
Mock<IRestoreDatabaseTaskDataObject> restoreDatabaseTaskDataObject = CreateRestoreDatabaseTaskDataObject(restoreParams);
|
||||
Dictionary<string, RestorePlanDetailInfo> options = RestoreOptionsHelper.CreateRestorePlanOptions(restoreDatabaseTaskDataObject.Object);
|
||||
IRestoreDatabaseTaskDataObject restoreDatabaseTaskDataObject = CreateRestoreDatabaseTaskDataObject(restoreParams);
|
||||
Dictionary<string, RestorePlanDetailInfo> options = RestoreOptionsHelper.CreateRestorePlanOptions(restoreDatabaseTaskDataObject);
|
||||
|
||||
restoreParams.Options[RestoreOptionsHelper.KeepReplication] = true;
|
||||
RestoreOptionsHelper.UpdateOptionsInPlan(restoreDatabaseTaskDataObject);
|
||||
|
||||
bool actual = RestoreOptionsHelper.GetOptionValue<bool>(RestoreOptionsHelper.KeepReplication, options, restoreDatabaseTaskDataObject.Object);
|
||||
bool actual = restoreDatabaseTaskDataObject.RestoreOptions.KeepReplication;
|
||||
bool expected = true;
|
||||
Assert.Equal(actual, expected);
|
||||
|
||||
@@ -153,32 +156,32 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
|
||||
return optionValues;
|
||||
}
|
||||
|
||||
private Mock<IRestoreDatabaseTaskDataObject> CreateRestoreDatabaseTaskDataObject(GeneralRequestDetails optionValues)
|
||||
private IRestoreDatabaseTaskDataObject CreateRestoreDatabaseTaskDataObject(GeneralRequestDetails optionValues)
|
||||
{
|
||||
var restoreDataObject = new Mock<IRestoreDatabaseTaskDataObject>();
|
||||
restoreDataObject.Setup(x => x.CloseExistingConnections).Returns(optionValues.GetOptionValue<bool>(RestoreOptionsHelper.CloseExistingConnections));
|
||||
restoreDataObject.Setup(x => x.DataFilesFolder).Returns(optionValues.GetOptionValue<string>(RestoreOptionsHelper.DataFileFolder));
|
||||
restoreDataObject.Setup(x => x.DbFiles).Returns(optionValues.GetOptionValue<List<DbFile>>("DbFiles"));
|
||||
restoreDataObject.Setup(x => x.DefaultDataFileFolder).Returns(optionValues.GetOptionValue<string>("DefaultDataFileFolder"));
|
||||
restoreDataObject.Setup(x => x.DefaultLogFileFolder).Returns(optionValues.GetOptionValue<string>("DefaultLogFileFolder"));
|
||||
restoreDataObject.Setup(x => x.IsTailLogBackupPossible(It.IsAny<string>())).Returns(optionValues.GetOptionValue<bool>("IsTailLogBackupPossible"));
|
||||
restoreDataObject.Setup(x => x.IsTailLogBackupWithNoRecoveryPossible(It.IsAny<string>())).Returns(optionValues.GetOptionValue<bool>("IsTailLogBackupWithNoRecoveryPossible"));
|
||||
restoreDataObject.Setup(x => x.GetDefaultStandbyFile(It.IsAny<string>())).Returns(optionValues.GetOptionValue<string>("GetDefaultStandbyFile"));
|
||||
restoreDataObject.Setup(x => x.GetDefaultTailLogbackupFile(It.IsAny<string>())).Returns(optionValues.GetOptionValue<string>("GetDefaultTailLogbackupFile"));
|
||||
restoreDataObject.Setup(x => x.LogFilesFolder).Returns(optionValues.GetOptionValue<string>("LogFilesFolder"));
|
||||
restoreDataObject.Setup(x => x.RelocateAllFiles).Returns(optionValues.GetOptionValue<bool>("RelocateAllFiles"));
|
||||
restoreDataObject.Setup(x => x.TailLogBackupFile).Returns(optionValues.GetOptionValue<string>("TailLogBackupFile"));
|
||||
restoreDataObject.Setup(x => x.TailLogWithNoRecovery).Returns(optionValues.GetOptionValue<bool>("TailLogWithNoRecovery"));
|
||||
restoreDataObject.Setup(x => x.BackupTailLog).Returns(optionValues.GetOptionValue<bool>("BackupTailLog"));
|
||||
restoreDataObject.Setup(x => x.RestoreParams).Returns(optionValues as RestoreParams);
|
||||
restoreDataObject.Setup(x => x.RestorePlan).Returns(() => null);
|
||||
var restoreDataObject = new RestoreDatabaseTaskDataObjectStub();
|
||||
restoreDataObject.CloseExistingConnections = optionValues.GetOptionValue<bool>(RestoreOptionsHelper.CloseExistingConnections);
|
||||
restoreDataObject.DataFilesFolder = optionValues.GetOptionValue<string>(RestoreOptionsHelper.DataFileFolder);
|
||||
restoreDataObject.DbFiles = optionValues.GetOptionValue<List<DbFile>>("DbFiles");
|
||||
restoreDataObject.DefaultDataFileFolder = optionValues.GetOptionValue<string>("DefaultDataFileFolder");
|
||||
restoreDataObject.DefaultLogFileFolder = optionValues.GetOptionValue<string>("DefaultLogFileFolder");
|
||||
restoreDataObject.IsTailLogBackupPossible = optionValues.GetOptionValue<bool>("IsTailLogBackupPossible");
|
||||
restoreDataObject.IsTailLogBackupWithNoRecoveryPossible = optionValues.GetOptionValue<bool>("IsTailLogBackupWithNoRecoveryPossible");
|
||||
restoreDataObject.DefaultStandbyFile = optionValues.GetOptionValue<string>("GetDefaultStandbyFile");
|
||||
restoreDataObject.DefaultTailLogbackupFile = optionValues.GetOptionValue<string>("GetDefaultTailLogbackupFile");
|
||||
restoreDataObject.LogFilesFolder = optionValues.GetOptionValue<string>("LogFilesFolder");
|
||||
restoreDataObject.RelocateAllFiles = optionValues.GetOptionValue<bool>("RelocateAllFiles");
|
||||
restoreDataObject.TailLogBackupFile = optionValues.GetOptionValue<string>("TailLogBackupFile");
|
||||
restoreDataObject.TailLogWithNoRecovery = optionValues.GetOptionValue<bool>("TailLogWithNoRecovery");
|
||||
restoreDataObject.BackupTailLog = optionValues.GetOptionValue<bool>("BackupTailLog");
|
||||
restoreDataObject.RestoreParams = optionValues as RestoreParams;
|
||||
restoreDataObject.RestorePlan = null;
|
||||
RestoreOptions restoreOptions = new RestoreOptions();
|
||||
restoreOptions.KeepReplication = optionValues.GetOptionValue<bool>(RestoreOptionsHelper.KeepReplication);
|
||||
restoreOptions.ReplaceDatabase = optionValues.GetOptionValue<bool>("ReplaceDatabase");
|
||||
restoreOptions.SetRestrictedUser = optionValues.GetOptionValue<bool>("SetRestrictedUser");
|
||||
restoreOptions.StandByFile = optionValues.GetOptionValue<string>("StandbyFile");
|
||||
restoreOptions.RecoveryState = optionValues.GetOptionValue<DatabaseRecoveryState>(RestoreOptionsHelper.RecoveryState);
|
||||
restoreDataObject.Setup(x => x.RestoreOptions).Returns(restoreOptions);
|
||||
restoreDataObject.RestoreOptions = restoreOptions;
|
||||
|
||||
|
||||
return restoreDataObject;
|
||||
@@ -216,7 +219,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
|
||||
|
||||
planDetailInfo = optionInResponse[RestoreOptionsHelper.KeepReplication];
|
||||
Assert.Equal(planDetailInfo.Name, RestoreOptionsHelper.KeepReplication);
|
||||
Assert.Equal(planDetailInfo.IsReadOnly, optionValues.GetOptionValue<DatabaseRecoveryState>(RestoreOptionsHelper.RecoveryState) == DatabaseRecoveryState.WithNoRecovery);
|
||||
Assert.Equal(planDetailInfo.IsReadOnly, optionValues.GetOptionValue<DatabaseRecoveryState>(RestoreOptionsHelper.RecoveryState) == DatabaseRecoveryState.WithNoRecovery);
|
||||
Assert.Equal(planDetailInfo.CurrentValue, optionValues.GetOptionValue<bool>(RestoreOptionsHelper.KeepReplication));
|
||||
Assert.Equal(planDetailInfo.DefaultValue, false);
|
||||
Assert.Equal(planDetailInfo.IsVisiable, true);
|
||||
@@ -251,14 +254,16 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
|
||||
|
||||
planDetailInfo = optionInResponse[RestoreOptionsHelper.TailLogBackupFile];
|
||||
Assert.Equal(planDetailInfo.Name, RestoreOptionsHelper.TailLogBackupFile);
|
||||
Assert.Equal(planDetailInfo.IsReadOnly, !optionValues.GetOptionValue<bool>("IsTailLogBackupPossible"));
|
||||
Assert.Equal(planDetailInfo.IsReadOnly, !optionValues.GetOptionValue<bool>("IsTailLogBackupPossible")
|
||||
| !optionValues.GetOptionValue<bool>(RestoreOptionsHelper.BackupTailLog));
|
||||
Assert.Equal(planDetailInfo.CurrentValue, optionValues.GetOptionValue<string>("TailLogBackupFile"));
|
||||
Assert.Equal(planDetailInfo.DefaultValue, optionValues.GetOptionValue<string>("GetDefaultTailLogbackupFile"));
|
||||
Assert.Equal(planDetailInfo.IsVisiable, true);
|
||||
|
||||
planDetailInfo = optionInResponse[RestoreOptionsHelper.TailLogWithNoRecovery];
|
||||
Assert.Equal(planDetailInfo.Name, RestoreOptionsHelper.TailLogWithNoRecovery);
|
||||
Assert.Equal(planDetailInfo.IsReadOnly, !optionValues.GetOptionValue<bool>("IsTailLogBackupWithNoRecoveryPossible"));
|
||||
Assert.Equal(planDetailInfo.IsReadOnly, !optionValues.GetOptionValue<bool>("IsTailLogBackupWithNoRecoveryPossible")
|
||||
| !optionValues.GetOptionValue<bool>(RestoreOptionsHelper.BackupTailLog));
|
||||
Assert.Equal(planDetailInfo.CurrentValue, optionValues.GetOptionValue<bool>("TailLogWithNoRecovery"));
|
||||
Assert.Equal(planDetailInfo.DefaultValue, optionValues.GetOptionValue<bool>("IsTailLogBackupWithNoRecoveryPossible"));
|
||||
Assert.Equal(planDetailInfo.IsVisiable, true);
|
||||
|
||||
Reference in New Issue
Block a user