mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-16 10:58:30 -05:00
@@ -3,6 +3,8 @@
|
|||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
using Microsoft.SqlTools.Hosting.Hosting.Contracts;
|
||||||
|
|
||||||
namespace Microsoft.SqlTools.Hosting.Contracts
|
namespace Microsoft.SqlTools.Hosting.Contracts
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -19,5 +21,10 @@ namespace Microsoft.SqlTools.Hosting.Contracts
|
|||||||
public ConnectionProviderOptions ConnectionProvider { get; set; }
|
public ConnectionProviderOptions ConnectionProvider { get; set; }
|
||||||
|
|
||||||
public AdminServicesProviderOptions AdminServicesProvider { get; set; }
|
public AdminServicesProviderOptions AdminServicesProvider { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// List of features
|
||||||
|
/// </summary>
|
||||||
|
public FeatureMetadataProvider[] Features { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
//
|
||||||
|
|
||||||
|
using Microsoft.SqlTools.Hosting.Contracts;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.Hosting.Hosting.Contracts
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Includes the metadata for a feature
|
||||||
|
/// </summary>
|
||||||
|
public class FeatureMetadataProvider
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates whether the feature is enabled
|
||||||
|
/// </summary>
|
||||||
|
public bool Enabled { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Feature name
|
||||||
|
/// </summary>
|
||||||
|
public string FeatureName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The options metadata avaialble for this feature
|
||||||
|
/// </summary>
|
||||||
|
public ServiceOption[] OptionsMetadata { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,6 +29,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts
|
|||||||
var idProperty = this.Properties.FirstOrDefault(x => x.PropertyName == IdPropertyName);
|
var idProperty = this.Properties.FirstOrDefault(x => x.PropertyName == IdPropertyName);
|
||||||
Id = idProperty == null || idProperty.PropertyValue == null ? string.Empty : idProperty.PropertyValue.ToString();
|
Id = idProperty == null || idProperty.PropertyValue == null ? string.Empty : idProperty.PropertyValue.ToString();
|
||||||
}
|
}
|
||||||
|
IsSelected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -14,15 +14,18 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class RestoreParams : GeneralRequestDetails
|
public class RestoreParams : GeneralRequestDetails
|
||||||
{
|
{
|
||||||
public string SessionId
|
/// <summary>
|
||||||
|
/// Restore session id. The parameter is optional and if passed, an existing plan will be used
|
||||||
|
/// </summary>
|
||||||
|
internal string SessionId
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return GetOptionValue<string>("sessionId");
|
return GetOptionValue<string>(RestoreOptionsHelper.SessionId);
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
SetOptionValue("sessionId", value);
|
SetOptionValue(RestoreOptionsHelper.SessionId, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,75 +37,75 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Comma delimited list of backup files
|
/// Comma delimited list of backup files
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string BackupFilePaths
|
internal string BackupFilePaths
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return GetOptionValue<string>("backupFilePaths");
|
return GetOptionValue<string>(RestoreOptionsHelper.BackupFilePaths);
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
SetOptionValue("backupFilePaths", value);
|
SetOptionValue(RestoreOptionsHelper.BackupFilePaths, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Target Database name to restore to
|
/// Target Database name to restore to
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string TargetDatabaseName
|
internal string TargetDatabaseName
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return GetOptionValue<string>("targetDatabaseName");
|
return GetOptionValue<string>(RestoreOptionsHelper.TargetDatabaseName);
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
SetOptionValue("targetDatabaseName", value);
|
SetOptionValue(RestoreOptionsHelper.TargetDatabaseName, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Source Database name to restore from
|
/// Source Database name to restore from
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string SourceDatabaseName
|
internal string SourceDatabaseName
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return GetOptionValue<string>("sourceDatabaseName");
|
return GetOptionValue<string>(RestoreOptionsHelper.SourceDatabaseName);
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
SetOptionValue("sourceDatabaseName", value);
|
SetOptionValue(RestoreOptionsHelper.SourceDatabaseName, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If set to true, the db files will be relocated to default data location in the server
|
/// If set to true, the db files will be relocated to default data location in the server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool RelocateDbFiles
|
internal bool RelocateDbFiles
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return GetOptionValue<bool>("relocateDbFiles");
|
return GetOptionValue<bool>(RestoreOptionsHelper.RelocateDbFiles);
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
SetOptionValue("relocateDbFiles", value);
|
SetOptionValue(RestoreOptionsHelper.RelocateDbFiles, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ids of the backup set to restore
|
/// Ids of the backup set to restore
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string[] SelectedBackupSets
|
internal string[] SelectedBackupSets
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return GetOptionValue<string[]>("selectedBackupSets");
|
return GetOptionValue<string[]>(RestoreOptionsHelper.SelectedBackupSets);
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
SetOptionValue("selectedBackupSets", value);
|
SetOptionValue(RestoreOptionsHelper.SelectedBackupSets, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,8 +163,15 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class RestorePlanResponse
|
public class RestorePlanResponse
|
||||||
{
|
{
|
||||||
public string RestoreSessionId { get; set; }
|
/// <summary>
|
||||||
|
/// Restore session id, can be used in restore request to use an existing restore plan
|
||||||
|
/// </summary>
|
||||||
|
public string SessionId { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The list of backup sets to restore
|
||||||
|
/// </summary>
|
||||||
public DatabaseFileInfo[] BackupSetsToRestore { get; set; }
|
public DatabaseFileInfo[] BackupSetsToRestore { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -185,30 +195,14 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts
|
|||||||
public string[] DatabaseNamesFromBackupSets { get; set; }
|
public string[] DatabaseNamesFromBackupSets { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Server name
|
/// For testing purpose to verify the target database
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string ServerName { get; set; }
|
internal string DatabaseName { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Database name to restore to
|
/// Plan details
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string DatabaseName { get; set; }
|
public Dictionary<string, object> PlanDetails { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Indicates whether relocating the db files is required
|
|
||||||
/// because the original file paths are not valid in the target server
|
|
||||||
/// </summary>
|
|
||||||
public bool RelocateFilesNeeded { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Default Data folder path in the target server
|
|
||||||
/// </summary>
|
|
||||||
public string DefaultDataFolder { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Default log folder path in the target server
|
|
||||||
/// </summary>
|
|
||||||
public string DefaultLogFolder { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class RestoreRequest
|
public class RestoreRequest
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class RestoreDatabaseHelper
|
public class RestoreDatabaseHelper
|
||||||
{
|
{
|
||||||
|
public const string LastBackupTaken = "lastBackupTaken";
|
||||||
private static RestoreDatabaseHelper instance = new RestoreDatabaseHelper();
|
private static RestoreDatabaseHelper instance = new RestoreDatabaseHelper();
|
||||||
private ConcurrentDictionary<string, RestoreDatabaseTaskDataObject> restoreSessions = new ConcurrentDictionary<string, RestoreDatabaseTaskDataObject>();
|
private ConcurrentDictionary<string, RestoreDatabaseTaskDataObject> restoreSessions = new ConcurrentDictionary<string, RestoreDatabaseTaskDataObject>();
|
||||||
|
|
||||||
@@ -152,7 +152,8 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
|||||||
{
|
{
|
||||||
RestorePlanResponse response = new RestorePlanResponse()
|
RestorePlanResponse response = new RestorePlanResponse()
|
||||||
{
|
{
|
||||||
DatabaseName = restoreDataObject.RestoreParams.TargetDatabaseName
|
DatabaseName = restoreDataObject.RestoreParams.TargetDatabaseName,
|
||||||
|
PlanDetails = new System.Collections.Generic.Dictionary<string, object>()
|
||||||
};
|
};
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -162,7 +163,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
|||||||
|
|
||||||
if (restoreDataObject != null && restoreDataObject.IsValid)
|
if (restoreDataObject != null && restoreDataObject.IsValid)
|
||||||
{
|
{
|
||||||
response.RestoreSessionId = restoreDataObject.SessionId;
|
response.SessionId = restoreDataObject.SessionId;
|
||||||
response.DatabaseName = restoreDataObject.TargetDatabase;
|
response.DatabaseName = restoreDataObject.TargetDatabase;
|
||||||
response.DbFiles = restoreDataObject.DbFiles.Select(x => new RestoreDatabaseFileInfo
|
response.DbFiles = restoreDataObject.DbFiles.Select(x => new RestoreDatabaseFileInfo
|
||||||
{
|
{
|
||||||
@@ -178,12 +179,25 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
|||||||
response.ErrorMessage = SR.RestoreNotSupported;
|
response.ErrorMessage = SR.RestoreNotSupported;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
response.PlanDetails.Add(LastBackupTaken, restoreDataObject.GetLastBackupTaken());
|
||||||
|
|
||||||
response.BackupSetsToRestore = restoreDataObject.GetBackupSetInfo().Select(x => new DatabaseFileInfo(x.ConvertPropertiesToArray())).ToArray();
|
response.BackupSetsToRestore = restoreDataObject.GetBackupSetInfo().Select(x => new DatabaseFileInfo(x.ConvertPropertiesToArray())).ToArray();
|
||||||
var dbNames = restoreDataObject.GetSourceDbNames();
|
var dbNames = restoreDataObject.GetSourceDbNames();
|
||||||
response.DatabaseNamesFromBackupSets = dbNames == null ? new string[] { } : dbNames.ToArray();
|
response.DatabaseNamesFromBackupSets = dbNames == null ? new string[] { } : dbNames.ToArray();
|
||||||
response.RelocateFilesNeeded = !restoreDataObject.DbFilesLocationAreValid();
|
|
||||||
response.DefaultDataFolder = restoreDataObject.DefaultDataFileFolder;
|
// Adding the default values for some of the options in the plan details
|
||||||
response.DefaultLogFolder = restoreDataObject.DefaultLogFileFolder;
|
bool isTailLogBackupPossible = restoreDataObject.IsTailLogBackupPossible(restoreDataObject.RestorePlanner.DatabaseName);
|
||||||
|
// Default backup tail-log. It's true when tail-log backup is possible for the source database
|
||||||
|
response.PlanDetails.Add(RestoreOptionsHelper.DefaultBackupTailLog, isTailLogBackupPossible);
|
||||||
|
// Default backup file for tail-log bacup when Tail-Log bachup is set to true
|
||||||
|
response.PlanDetails.Add(RestoreOptionsHelper.DefaultTailLogBackupFile,
|
||||||
|
restoreDataObject.Util.GetDefaultTailLogbackupFile(restoreDataObject.RestorePlan.DatabaseName));
|
||||||
|
// Default stand by file path for when RESTORE WITH STANDBY is selected
|
||||||
|
response.PlanDetails.Add(RestoreOptionsHelper.DefaultStandbyFile, restoreDataObject.Util.GetDefaultStandbyFile(restoreDataObject.RestorePlan.DatabaseName));
|
||||||
|
// Default Data folder path in the target server
|
||||||
|
response.PlanDetails.Add(RestoreOptionsHelper.DefaultDataFileFolder, restoreDataObject.DefaultDataFileFolder);
|
||||||
|
// Default log folder path in the target server
|
||||||
|
response.PlanDetails.Add(RestoreOptionsHelper.DefaultLogFileFolder, restoreDataObject.DefaultLogFileFolder);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -314,12 +328,29 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
|||||||
restoreDataObject.RestorePlanner.DatabaseName = restoreDataObject.RestoreParams.SourceDatabaseName;
|
restoreDataObject.RestorePlanner.DatabaseName = restoreDataObject.RestoreParams.SourceDatabaseName;
|
||||||
}
|
}
|
||||||
restoreDataObject.TargetDatabase = restoreDataObject.RestoreParams.TargetDatabaseName;
|
restoreDataObject.TargetDatabase = restoreDataObject.RestoreParams.TargetDatabaseName;
|
||||||
//TODO: used for other types of restore
|
|
||||||
/*bool isTailLogBackupPossible = restoreDataObject.RestorePlanner.IsTailLogBackupPossible(restoreDataObject.RestorePlanner.DatabaseName);
|
restoreDataObject.RestoreOptions.KeepReplication = restoreDataObject.RestoreParams.GetOptionValue<bool>(RestoreOptionsHelper.KeepReplication);
|
||||||
restoreDataObject.RestorePlanner.BackupTailLog = isTailLogBackupPossible;
|
restoreDataObject.RestoreOptions.ReplaceDatabase = restoreDataObject.RestoreParams.GetOptionValue<bool>(RestoreOptionsHelper.ReplaceDatabase);
|
||||||
restoreDataObject.TailLogBackupFile = restoreDataObject.Util.GetDefaultTailLogbackupFile(dbName);
|
restoreDataObject.RestoreOptions.SetRestrictedUser = restoreDataObject.RestoreParams.GetOptionValue<bool>(RestoreOptionsHelper.SetRestrictedUser);
|
||||||
restoreDataObject.RestorePlanner.TailLogBackupFile = restoreDataObject.TailLogBackupFile;
|
string recoveryState = restoreDataObject.RestoreParams.GetOptionValue<string>(RestoreOptionsHelper.RecoveryState);
|
||||||
*/
|
object databaseRecoveryState;
|
||||||
|
if (Enum.TryParse(typeof(DatabaseRecoveryState), recoveryState, out databaseRecoveryState))
|
||||||
|
{
|
||||||
|
restoreDataObject.RestoreOptions.RecoveryState = (DatabaseRecoveryState)databaseRecoveryState;
|
||||||
|
}
|
||||||
|
bool isTailLogBackupPossible = restoreDataObject.IsTailLogBackupPossible(restoreDataObject.RestorePlanner.DatabaseName);
|
||||||
|
if (isTailLogBackupPossible)
|
||||||
|
{
|
||||||
|
restoreDataObject.RestorePlanner.BackupTailLog = restoreDataObject.RestoreParams.GetOptionValue<bool>(RestoreOptionsHelper.BackupTailLog);
|
||||||
|
restoreDataObject.TailLogBackupFile = restoreDataObject.RestoreParams.GetOptionValue<string>(RestoreOptionsHelper.TailLogBackupFile);
|
||||||
|
restoreDataObject.TailLogWithNoRecovery = restoreDataObject.RestoreParams.GetOptionValue<bool>(RestoreOptionsHelper.TailLogWithNoRecovery);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
restoreDataObject.RestorePlanner.BackupTailLog = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
restoreDataObject.CloseExistingConnections = restoreDataObject.RestoreParams.GetOptionValue<bool>(RestoreOptionsHelper.CloseExistingConnections);
|
||||||
|
|
||||||
restoreDataObject.UpdateRestorePlan(restoreDataObject.RestoreParams.RelocateDbFiles);
|
restoreDataObject.UpdateRestorePlan(restoreDataObject.RestoreParams.RelocateDbFiles);
|
||||||
}
|
}
|
||||||
@@ -340,6 +371,8 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
|||||||
{
|
{
|
||||||
restoreDataObject.SqlTask = sqlTask;
|
restoreDataObject.SqlTask = sqlTask;
|
||||||
restoreDataObject.Execute();
|
restoreDataObject.Execute();
|
||||||
|
RestoreDatabaseTaskDataObject cachedRestoreDataObject;
|
||||||
|
this.restoreSessions.TryRemove(restoreDataObject.SessionId, out cachedRestoreDataObject);
|
||||||
}
|
}
|
||||||
catch(Exception ex)
|
catch(Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.SqlServer.Management.Smo;
|
using Microsoft.SqlServer.Management.Smo;
|
||||||
@@ -20,6 +21,9 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
|||||||
{
|
{
|
||||||
|
|
||||||
private const char BackupMediaNameSeparator = ',';
|
private const char BackupMediaNameSeparator = ',';
|
||||||
|
private DatabaseRestorePlanner restorePlanner;
|
||||||
|
private string tailLogBackupFile;
|
||||||
|
|
||||||
public RestoreDatabaseTaskDataObject(Server server, String databaseName)
|
public RestoreDatabaseTaskDataObject(Server server, String databaseName)
|
||||||
{
|
{
|
||||||
PlanUpdateRequired = true;
|
PlanUpdateRequired = true;
|
||||||
@@ -147,6 +151,35 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the last backup taken
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public string GetLastBackupTaken()
|
||||||
|
{
|
||||||
|
string lastBackup = string.Empty;
|
||||||
|
int lastIndexSel = 0; //TODO: find the selected backup set
|
||||||
|
if (this.RestorePlanner.RestoreToLastBackup &&
|
||||||
|
this.RestorePlan.RestoreOperations[lastIndexSel] != null &&
|
||||||
|
this.RestorePlan.RestoreOperations.Count > 0 &&
|
||||||
|
this.RestorePlan.RestoreOperations[lastIndexSel].BackupSet != null)
|
||||||
|
{
|
||||||
|
int lastIndex = this.RestorePlan.RestoreOperations.Count - 1;
|
||||||
|
DateTime backupTime = this.RestorePlan.RestoreOperations[lastIndexSel].BackupSet.BackupStartDate;
|
||||||
|
string backupTimeStr = backupTime.ToLongDateString() + " " + backupTime.ToLongTimeString();
|
||||||
|
lastBackup = (lastIndexSel == lastIndex) ?
|
||||||
|
string.Format(CultureInfo.CurrentCulture, SR.TheLastBackupTaken, (backupTimeStr)) : backupTimeStr;
|
||||||
|
}
|
||||||
|
//TODO: find the selected one
|
||||||
|
else if (this.RestoreSelected[0] && !this.RestorePlanner.RestoreToLastBackup)
|
||||||
|
{
|
||||||
|
lastBackup = this.CurrentRestorePointInTime.Value.ToLongDateString() +
|
||||||
|
" " + this.CurrentRestorePointInTime.Value.ToLongTimeString();
|
||||||
|
}
|
||||||
|
return lastBackup;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Executes the restore operations
|
/// Executes the restore operations
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -170,9 +203,11 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restore Util
|
||||||
|
/// </summary>
|
||||||
public RestoreUtil Util { get; set; }
|
public RestoreUtil Util { get; set; }
|
||||||
|
|
||||||
private DatabaseRestorePlanner restorePlanner;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// SMO database restore planner used to create a restore plan
|
/// SMO database restore planner used to create a restore plan
|
||||||
@@ -182,7 +217,6 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
|||||||
get { return restorePlanner; }
|
get { return restorePlanner; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private string tailLogBackupFile;
|
|
||||||
public bool PlanUpdateRequired { get; private set; }
|
public bool PlanUpdateRequired { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -303,6 +337,40 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether [is tail log backup possible].
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if [is tail log backup possible]; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
internal bool IsTailLogBackupPossible(string databaseName)
|
||||||
|
{
|
||||||
|
if (this.Server.Version.Major < 9 || String.IsNullOrEmpty(this.restorePlanner.DatabaseName))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Database db = this.Server.Databases[databaseName];
|
||||||
|
if (db == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
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>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether [prompt before each backup].
|
/// Gets or sets a value indicating whether [prompt before each backup].
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -0,0 +1,186 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
//
|
||||||
|
|
||||||
|
using Microsoft.SqlTools.Hosting.Contracts;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
|
||||||
|
{
|
||||||
|
public class RestoreOptionsHelper
|
||||||
|
{
|
||||||
|
internal const string KeepReplication = "keepReplication";
|
||||||
|
internal const string ReplaceDatabase = "replaceDatabase";
|
||||||
|
internal const string SetRestrictedUser = "setRestrictedUser";
|
||||||
|
internal const string RecoveryState = "eecoveryState";
|
||||||
|
internal const string BackupTailLog = "backupTailLog";
|
||||||
|
internal const string DefaultBackupTailLog = "defaultBackupTailLog";
|
||||||
|
internal const string TailLogBackupFile = "tailLogBackupFile";
|
||||||
|
internal const string DefaultTailLogBackupFile = "defaultTailLogBackupFile";
|
||||||
|
internal const string TailLogWithNoRecovery = "tailLogWithNoRecovery";
|
||||||
|
internal const string CloseExistingConnections = "closeExistingConnections";
|
||||||
|
internal const string RelocateDbFiles = "relocateDbFiles";
|
||||||
|
internal const string DataFileFolder = "dataFileFolder";
|
||||||
|
internal const string DefaultDataFileFolder = "defaultDataFileFolder";
|
||||||
|
internal const string LogFileFolder = "logFileFolder";
|
||||||
|
internal const string DefaultLogFileFolder = "defaultLogFileFolder";
|
||||||
|
internal const string SessionId = "sessionId";
|
||||||
|
internal const string BackupFilePaths = "backupFilePaths";
|
||||||
|
internal const string TargetDatabaseName = "targetDatabaseName";
|
||||||
|
internal const string SourceDatabaseName = "sourceDatabaseName";
|
||||||
|
internal const string SelectedBackupSets = "selectedBackupSets";
|
||||||
|
internal const string StandbyFile = "standbyFile";
|
||||||
|
internal const string DefaultStandbyFile = "defaultStandbyFile";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the options metadata available for restore operations
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static ServiceOption[] CreateRestoreOptions()
|
||||||
|
{
|
||||||
|
ServiceOption[] options = new ServiceOption[]
|
||||||
|
{
|
||||||
|
|
||||||
|
new ServiceOption
|
||||||
|
{
|
||||||
|
Name = RestoreOptionsHelper.KeepReplication,
|
||||||
|
DisplayName = "Keep Replication",
|
||||||
|
Description = "Preserve the replication settings (WITH KEEP_REPLICATION)",
|
||||||
|
ValueType = ServiceOption.ValueTypeBoolean,
|
||||||
|
IsRequired = false,
|
||||||
|
GroupName = "Restore options"
|
||||||
|
},
|
||||||
|
new ServiceOption
|
||||||
|
{
|
||||||
|
Name = RestoreOptionsHelper.ReplaceDatabase,
|
||||||
|
DisplayName = "ReplaceDatabase",
|
||||||
|
Description = "Overwrite the existing database (WITH REPLACE)",
|
||||||
|
ValueType = ServiceOption.ValueTypeBoolean,
|
||||||
|
IsRequired = false,
|
||||||
|
GroupName = "Restore options"
|
||||||
|
},
|
||||||
|
new ServiceOption
|
||||||
|
{
|
||||||
|
Name = RestoreOptionsHelper.SetRestrictedUser,
|
||||||
|
DisplayName = "SetRestrictedUser",
|
||||||
|
Description = "Restrict access to the restored database (WITH RESTRICTED_USER)",
|
||||||
|
ValueType = ServiceOption.ValueTypeBoolean,
|
||||||
|
IsRequired = false,
|
||||||
|
GroupName = "Restore options"
|
||||||
|
},
|
||||||
|
new ServiceOption
|
||||||
|
{
|
||||||
|
Name = RestoreOptionsHelper.RecoveryState,
|
||||||
|
DisplayName = "Recovery State",
|
||||||
|
Description = "Recovery State",
|
||||||
|
ValueType = ServiceOption.ValueTypeCategory,
|
||||||
|
IsRequired = false,
|
||||||
|
GroupName = "Restore options",
|
||||||
|
CategoryValues = new CategoryValue[]
|
||||||
|
{
|
||||||
|
new CategoryValue
|
||||||
|
{
|
||||||
|
Name = "WithRecovery",
|
||||||
|
DisplayName = "RESTORE WITH RECOVERTY"
|
||||||
|
},
|
||||||
|
new CategoryValue
|
||||||
|
{
|
||||||
|
Name = "WithNoRecovery",
|
||||||
|
DisplayName = "RESTORE WITH NORECOVERTY"
|
||||||
|
},
|
||||||
|
new CategoryValue
|
||||||
|
{
|
||||||
|
Name = "WithStandBy",
|
||||||
|
DisplayName = "RESTORE WITH STANDBY"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new ServiceOption
|
||||||
|
{
|
||||||
|
Name = RestoreOptionsHelper.StandbyFile,
|
||||||
|
DisplayName = "Standby file",
|
||||||
|
Description = "Standby file",
|
||||||
|
ValueType = ServiceOption.ValueTypeString,
|
||||||
|
IsRequired = false,
|
||||||
|
GroupName = "Restore options"
|
||||||
|
},
|
||||||
|
new ServiceOption
|
||||||
|
{
|
||||||
|
Name = RestoreOptionsHelper.BackupTailLog,
|
||||||
|
DisplayName = "Backup Tail Log",
|
||||||
|
Description = "Take tail-log backup before restore",
|
||||||
|
ValueType = ServiceOption.ValueTypeBoolean,
|
||||||
|
IsRequired = false,
|
||||||
|
DefaultValue = "true",
|
||||||
|
GroupName = "Tail-Log backup"
|
||||||
|
},
|
||||||
|
new ServiceOption
|
||||||
|
{
|
||||||
|
Name = RestoreOptionsHelper.BackupTailLog,
|
||||||
|
DisplayName = "Backup Tail Log",
|
||||||
|
Description = "Take tail-log backup before restore",
|
||||||
|
ValueType = ServiceOption.ValueTypeBoolean,
|
||||||
|
IsRequired = false,
|
||||||
|
DefaultValue = "true",
|
||||||
|
GroupName = "Tail-Log backup"
|
||||||
|
},
|
||||||
|
new ServiceOption
|
||||||
|
{
|
||||||
|
Name = RestoreOptionsHelper.TailLogBackupFile,
|
||||||
|
DisplayName = "Tail Log Backup File",
|
||||||
|
Description = "Tail Log Backup File",
|
||||||
|
ValueType = ServiceOption.ValueTypeString,
|
||||||
|
IsRequired = false,
|
||||||
|
GroupName = "Tail-Log backup"
|
||||||
|
},
|
||||||
|
new ServiceOption
|
||||||
|
{
|
||||||
|
Name = RestoreOptionsHelper.TailLogWithNoRecovery,
|
||||||
|
DisplayName = "Tail Log With NoRecovery",
|
||||||
|
Description = "Leave source database in the restoring state(WITH NORECOVERTY)",
|
||||||
|
ValueType = ServiceOption.ValueTypeBoolean,
|
||||||
|
IsRequired = false,
|
||||||
|
GroupName = "Tail-Log backup"
|
||||||
|
},
|
||||||
|
new ServiceOption
|
||||||
|
{
|
||||||
|
Name = RestoreOptionsHelper.CloseExistingConnections,
|
||||||
|
DisplayName = "Close Existing Connections",
|
||||||
|
Description = "Close existing connections to destination database",
|
||||||
|
ValueType = ServiceOption.ValueTypeBoolean,
|
||||||
|
IsRequired = false,
|
||||||
|
GroupName = "Server connections"
|
||||||
|
},
|
||||||
|
new ServiceOption
|
||||||
|
{
|
||||||
|
Name = RestoreOptionsHelper.RelocateDbFiles,
|
||||||
|
DisplayName = "Relocate all files",
|
||||||
|
Description = "Relocate all files",
|
||||||
|
ValueType = ServiceOption.ValueTypeBoolean,
|
||||||
|
IsRequired = false,
|
||||||
|
GroupName = "Restore database files as"
|
||||||
|
},
|
||||||
|
new ServiceOption
|
||||||
|
{
|
||||||
|
Name = RestoreOptionsHelper.DataFileFolder,
|
||||||
|
DisplayName = "Data file folder",
|
||||||
|
Description = "Data file folder",
|
||||||
|
ValueType = ServiceOption.ValueTypeString,
|
||||||
|
IsRequired = false,
|
||||||
|
GroupName = "Restore database files as"
|
||||||
|
},
|
||||||
|
new ServiceOption
|
||||||
|
{
|
||||||
|
Name = RestoreOptionsHelper.LogFileFolder,
|
||||||
|
DisplayName = "Log file folder",
|
||||||
|
Description = "Log file folder",
|
||||||
|
ValueType = ServiceOption.ValueTypeString,
|
||||||
|
IsRequired = false,
|
||||||
|
GroupName = "Restore database files as"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3477,6 +3477,14 @@ namespace Microsoft.SqlTools.ServiceLayer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string TheLastBackupTaken
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Keys.GetString(Keys.TheLastBackupTaken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static string ConnectionServiceListDbErrorNotConnected(string uri)
|
public static string ConnectionServiceListDbErrorNotConnected(string uri)
|
||||||
{
|
{
|
||||||
return Keys.GetString(Keys.ConnectionServiceListDbErrorNotConnected, uri);
|
return Keys.GetString(Keys.ConnectionServiceListDbErrorNotConnected, uri);
|
||||||
@@ -4890,6 +4898,9 @@ namespace Microsoft.SqlTools.ServiceLayer
|
|||||||
public const string RestoreBackupSetExpiration = "RestoreBackupSetExpiration";
|
public const string RestoreBackupSetExpiration = "RestoreBackupSetExpiration";
|
||||||
|
|
||||||
|
|
||||||
|
public const string TheLastBackupTaken = "TheLastBackupTaken";
|
||||||
|
|
||||||
|
|
||||||
private Keys()
|
private Keys()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|||||||
@@ -1911,4 +1911,8 @@
|
|||||||
<value>Expiration</value>
|
<value>Expiration</value>
|
||||||
<comment></comment>
|
<comment></comment>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TheLastBackupTaken" xml:space="preserve">
|
||||||
|
<value>The last backup taken ({0})</value>
|
||||||
|
<comment></comment>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
@@ -835,4 +835,5 @@ RestoreBackupSetStartDate = Start Date
|
|||||||
RestoreBackupSetFinishDate = Finish Date
|
RestoreBackupSetFinishDate = Finish Date
|
||||||
RestoreBackupSetSize = Size
|
RestoreBackupSetSize = Size
|
||||||
RestoreBackupSetUserName = User Name
|
RestoreBackupSetUserName = User Name
|
||||||
RestoreBackupSetExpiration = Expiration
|
RestoreBackupSetExpiration = Expiration
|
||||||
|
TheLastBackupTaken = The last backup taken ({0})
|
||||||
@@ -2239,6 +2239,11 @@
|
|||||||
<target state="new">Name</target>
|
<target state="new">Name</target>
|
||||||
<note></note>
|
<note></note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="TheLastBackupTaken">
|
||||||
|
<source>The last backup taken ({0})</source>
|
||||||
|
<target state="new">The last backup taken ({0})</target>
|
||||||
|
<note></note>
|
||||||
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
@@ -16,6 +16,7 @@ using Microsoft.SqlTools.Hosting.Protocol.Channel;
|
|||||||
using Microsoft.SqlTools.Utility;
|
using Microsoft.SqlTools.Utility;
|
||||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||||
using Microsoft.SqlTools.ServiceLayer.Admin;
|
using Microsoft.SqlTools.ServiceLayer.Admin;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||||
|
|
||||||
namespace Microsoft.SqlTools.ServiceLayer.Hosting
|
namespace Microsoft.SqlTools.ServiceLayer.Hosting
|
||||||
{
|
{
|
||||||
@@ -208,7 +209,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Hosting
|
|||||||
ProviderName = ServiceHost.ProviderName,
|
ProviderName = ServiceHost.ProviderName,
|
||||||
ProviderDisplayName = ServiceHost.ProviderDescription,
|
ProviderDisplayName = ServiceHost.ProviderDescription,
|
||||||
ConnectionProvider = ConnectionProviderOptionsHelper.BuildConnectionProviderOptions(),
|
ConnectionProvider = ConnectionProviderOptionsHelper.BuildConnectionProviderOptions(),
|
||||||
AdminServicesProvider = AdminServicesProviderOptionsHelper.BuildAdminServicesProviderOptions()
|
AdminServicesProvider = AdminServicesProviderOptionsHelper.BuildAdminServicesProviderOptions(),
|
||||||
|
Features = FeaturesMetadataProviderHelper.CreateFratureMetadataProviders()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
//
|
||||||
|
// 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.SqlTools.Hosting.Hosting.Contracts;
|
||||||
|
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.ServiceLayer.Utility
|
||||||
|
{
|
||||||
|
public class FeaturesMetadataProviderHelper
|
||||||
|
{
|
||||||
|
public static FeatureMetadataProvider[] CreateFratureMetadataProviders()
|
||||||
|
{
|
||||||
|
List<FeatureMetadataProvider> featues = new List<FeatureMetadataProvider>();
|
||||||
|
|
||||||
|
featues.Add(new FeatureMetadataProvider
|
||||||
|
{
|
||||||
|
FeatureName = "Restore",
|
||||||
|
Enabled = true,
|
||||||
|
OptionsMetadata = RestoreOptionsHelper.CreateRestoreOptions()
|
||||||
|
});
|
||||||
|
|
||||||
|
return featues.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
|
|||||||
Options = new Dictionary<string, object>();
|
Options = new Dictionary<string, object>();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected T GetOptionValue<T>(string name)
|
internal T GetOptionValue<T>(string name)
|
||||||
{
|
{
|
||||||
T result = default(T);
|
T result = default(T);
|
||||||
if (Options != null && Options.ContainsKey(name))
|
if (Options != null && Options.ContainsKey(name))
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ using System.Data.SqlClient;
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.SqlServer.Management.Smo;
|
using Microsoft.SqlServer.Management.Smo;
|
||||||
using Microsoft.SqlTools.Extensibility;
|
using Microsoft.SqlTools.Extensibility;
|
||||||
@@ -58,6 +57,52 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery
|
|||||||
await VerifyRestore(fullBackUpDatabase, canRestore);
|
await VerifyRestore(fullBackUpDatabase, canRestore);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async void RestorePlanShouldCreatedSuccessfullyOnExistingDatabaseGivenReplaceOption()
|
||||||
|
{
|
||||||
|
SqlTestDb testDb = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
testDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, null, "RestoreTest");
|
||||||
|
//Create a backup from a test db but don't delete the database
|
||||||
|
await VerifyBackupFileCreated();
|
||||||
|
bool canRestore = true;
|
||||||
|
Dictionary<string, object> options = new Dictionary<string, object>();
|
||||||
|
options.Add(RestoreOptionsHelper.ReplaceDatabase, true);
|
||||||
|
|
||||||
|
await VerifyRestore(new string[] { fullBackUpDatabase }, canRestore, true, testDb.DatabaseName, null, options);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (testDb != null)
|
||||||
|
{
|
||||||
|
testDb.Cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async void RestorePlanShouldFailOnExistingDatabaseNotGivenReplaceOption()
|
||||||
|
{
|
||||||
|
SqlTestDb testDb = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
testDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, null, "RestoreTest");
|
||||||
|
//Create a backup from a test db but don't delete the database
|
||||||
|
await VerifyBackupFileCreated();
|
||||||
|
bool canRestore = true;
|
||||||
|
|
||||||
|
await VerifyRestore(new string[] { fullBackUpDatabase }, canRestore, false, testDb.DatabaseName, null, null);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (testDb != null)
|
||||||
|
{
|
||||||
|
testDb.Cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void RestoreShouldCreatedSuccessfullyGivenTwoBackupFiles()
|
public async void RestoreShouldCreatedSuccessfullyGivenTwoBackupFiles()
|
||||||
{
|
{
|
||||||
@@ -228,7 +273,13 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery
|
|||||||
return await VerifyRestore(new string[] { backupFileName }, canRestore, execute, targetDatabase);
|
return await VerifyRestore(new string[] { backupFileName }, canRestore, execute, targetDatabase);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<RestorePlanResponse> VerifyRestore(string[] backupFileNames, bool canRestore, bool execute = false, string targetDatabase = null, string[] selectedBackupSets = null)
|
private async Task<RestorePlanResponse> VerifyRestore(
|
||||||
|
string[] backupFileNames,
|
||||||
|
bool canRestore,
|
||||||
|
bool execute = false,
|
||||||
|
string targetDatabase = null,
|
||||||
|
string[] selectedBackupSets = null,
|
||||||
|
Dictionary<string, object> options = null)
|
||||||
{
|
{
|
||||||
var filePaths = backupFileNames.Select(x => GetBackupFilePath(x));
|
var filePaths = backupFileNames.Select(x => GetBackupFilePath(x));
|
||||||
string backUpFilePath = filePaths.Aggregate((current, next) => current + " ," + next);
|
string backUpFilePath = filePaths.Aggregate((current, next) => current + " ," + next);
|
||||||
@@ -247,11 +298,22 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery
|
|||||||
SelectedBackupSets = selectedBackupSets
|
SelectedBackupSets = selectedBackupSets
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if(options != null)
|
||||||
|
{
|
||||||
|
foreach (var item in options)
|
||||||
|
{
|
||||||
|
if (!request.Options.ContainsKey(item.Key))
|
||||||
|
{
|
||||||
|
request.Options.Add(item.Key, item.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var restoreDataObject = service.CreateRestoreDatabaseTaskDataObject(request);
|
var restoreDataObject = service.CreateRestoreDatabaseTaskDataObject(request);
|
||||||
var response = service.CreateRestorePlanResponse(restoreDataObject);
|
var response = service.CreateRestorePlanResponse(restoreDataObject);
|
||||||
|
|
||||||
Assert.NotNull(response);
|
Assert.NotNull(response);
|
||||||
Assert.False(string.IsNullOrWhiteSpace(response.RestoreSessionId));
|
Assert.False(string.IsNullOrWhiteSpace(response.SessionId));
|
||||||
Assert.Equal(response.CanRestore, canRestore);
|
Assert.Equal(response.CanRestore, canRestore);
|
||||||
if (canRestore)
|
if (canRestore)
|
||||||
{
|
{
|
||||||
@@ -261,15 +323,23 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery
|
|||||||
targetDatabase = response.DatabaseName;
|
targetDatabase = response.DatabaseName;
|
||||||
}
|
}
|
||||||
Assert.Equal(response.DatabaseName, targetDatabase);
|
Assert.Equal(response.DatabaseName, targetDatabase);
|
||||||
|
Assert.NotNull(response.PlanDetails);
|
||||||
|
Assert.True(response.PlanDetails.Any());
|
||||||
|
Assert.NotNull(response.PlanDetails[RestoreOptionsHelper.DefaultBackupTailLog]);
|
||||||
|
Assert.NotNull(response.PlanDetails[RestoreOptionsHelper.DefaultTailLogBackupFile]);
|
||||||
|
Assert.NotNull(response.PlanDetails[RestoreOptionsHelper.DefaultDataFileFolder]);
|
||||||
|
Assert.NotNull(response.PlanDetails[RestoreOptionsHelper.DefaultLogFileFolder]);
|
||||||
|
Assert.NotNull(response.PlanDetails[RestoreOptionsHelper.DefaultStandbyFile]);
|
||||||
|
Assert.NotNull(response.PlanDetails[RestoreOptionsHelper.DefaultStandbyFile]);
|
||||||
|
|
||||||
if(execute)
|
if(execute)
|
||||||
{
|
{
|
||||||
request.SessionId = response.RestoreSessionId;
|
request.SessionId = response.SessionId;
|
||||||
restoreDataObject = service.CreateRestoreDatabaseTaskDataObject(request);
|
restoreDataObject = service.CreateRestoreDatabaseTaskDataObject(request);
|
||||||
Assert.Equal(response.RestoreSessionId, restoreDataObject.SessionId);
|
Assert.Equal(response.SessionId, restoreDataObject.SessionId);
|
||||||
await DropDatabase(targetDatabase);
|
//await DropDatabase(targetDatabase);
|
||||||
Thread.Sleep(2000);
|
//Thread.Sleep(2000);
|
||||||
request.RelocateDbFiles = response.RelocateFilesNeeded;
|
request.RelocateDbFiles = !restoreDataObject.DbFilesLocationAreValid();
|
||||||
service.ExecuteRestore(restoreDataObject);
|
service.ExecuteRestore(restoreDataObject);
|
||||||
Assert.True(restoreDataObject.Server.Databases.Contains(targetDatabase));
|
Assert.True(restoreDataObject.Server.Databases.Contains(targetDatabase));
|
||||||
if(selectedBackupSets != null)
|
if(selectedBackupSets != null)
|
||||||
|
|||||||
Reference in New Issue
Block a user