mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-02 17:24:50 -05:00
Add advanced options to backup service (#405)
* Add advanced options for Backup * Add backup encryption strings * Add test for backup advanced option * Add strings to SR * Add verify backup restore option * Addressed PR comments * Add MIT license header
This commit is contained in:
@@ -13,6 +13,7 @@ using Microsoft.SqlServer.Management.Sdk.Sfc;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlTools.ServiceLayer.Admin;
|
||||
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
|
||||
{
|
||||
@@ -137,13 +138,14 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
|
||||
/// </summary>
|
||||
/// <param name="databaseName"></param>
|
||||
/// <returns></returns>
|
||||
public BackupConfigInfo GetBackupConfigInfo(string databaseName)
|
||||
public BackupConfigInfo CreateBackupConfigInfo(string databaseName)
|
||||
{
|
||||
BackupConfigInfo databaseInfo = new BackupConfigInfo();
|
||||
databaseInfo.RecoveryModel = this.GetRecoveryModel(databaseName);
|
||||
databaseInfo.DefaultBackupFolder = this.GetDefaultBackupFolder();
|
||||
databaseInfo.LatestBackups = this.GetLatestBackupLocations(databaseName);
|
||||
return databaseInfo;
|
||||
BackupConfigInfo configInfo = new BackupConfigInfo();
|
||||
configInfo.RecoveryModel = GetRecoveryModel(databaseName);
|
||||
configInfo.DefaultBackupFolder = GetDefaultBackupFolder();
|
||||
configInfo.LatestBackups = GetLatestBackupLocations(databaseName);
|
||||
configInfo.BackupEncryptors = GetBackupEncryptors();
|
||||
return configInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -226,17 +228,78 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
|
||||
}
|
||||
|
||||
this.backup.CopyOnly = this.backupInfo.IsCopyOnly;
|
||||
this.backup.FormatMedia = this.backupInfo.FormatMedia;
|
||||
this.backup.Initialize = this.backupInfo.Initialize;
|
||||
this.backup.SkipTapeHeader = this.backupInfo.SkipTapeHeader;
|
||||
this.backup.Checksum = this.backupInfo.Checksum;
|
||||
this.backup.ContinueAfterError = this.backupInfo.ContinueAfterError;
|
||||
|
||||
//TODO: This should be changed to get user inputs
|
||||
this.backup.FormatMedia = false;
|
||||
this.backup.Initialize = false;
|
||||
this.backup.SkipTapeHeader = true;
|
||||
this.backup.Checksum = false;
|
||||
this.backup.ContinueAfterError = false;
|
||||
this.backup.LogTruncation = BackupTruncateLogType.Truncate;
|
||||
if (!string.IsNullOrEmpty(this.backupInfo.MediaName))
|
||||
{
|
||||
this.backup.MediaName = this.backupInfo.MediaName;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(this.backupInfo.MediaDescription))
|
||||
{
|
||||
this.backup.MediaDescription = this.backupInfo.MediaDescription;
|
||||
}
|
||||
|
||||
if (this.backupInfo.TailLogBackup
|
||||
&& !this.backupRestoreUtil.IsHADRDatabase(this.backupInfo.DatabaseName)
|
||||
&& !this.backupRestoreUtil.IsMirroringEnabled(this.backupInfo.DatabaseName))
|
||||
{
|
||||
this.backup.NoRecovery = true;
|
||||
}
|
||||
|
||||
if (this.backupInfo.LogTruncation)
|
||||
{
|
||||
this.backup.LogTruncation = BackupTruncateLogType.Truncate;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.backup.LogTruncation = BackupTruncateLogType.NoTruncate;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(this.backupInfo.BackupSetDescription))
|
||||
{
|
||||
this.backup.BackupSetDescription = this.backupInfo.BackupSetDescription;
|
||||
}
|
||||
|
||||
if (this.backupInfo.RetainDays >= 0)
|
||||
{
|
||||
this.backup.RetainDays = this.backupInfo.RetainDays;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.backup.ExpirationDate = this.backupInfo.ExpirationDate;
|
||||
}
|
||||
|
||||
this.backup.CompressionOption = (BackupCompressionOptions)this.backupInfo.CompressionOption;
|
||||
|
||||
if (!string.IsNullOrEmpty(this.backupInfo.EncryptorName))
|
||||
{
|
||||
this.backup.EncryptionOption = new BackupEncryptionOptions((BackupEncryptionAlgorithm)this.backupInfo.EncryptionAlgorithm,
|
||||
(BackupEncryptorType)this.backupInfo.EncryptorType,
|
||||
this.backupInfo.EncryptorName);
|
||||
}
|
||||
|
||||
// Execute backup
|
||||
this.backup.SqlBackup(this.dataContainer.Server);
|
||||
|
||||
// Verify backup if required
|
||||
if (this.backupInfo.VerifyBackupRequired)
|
||||
{
|
||||
Restore restore = new Restore();
|
||||
restore.Devices.AddRange(this.backup.Devices);
|
||||
restore.Database = this.backup.Database;
|
||||
|
||||
string errorMessage = null;
|
||||
restore.SqlVerifyLatest(this.dataContainer.Server, out errorMessage);
|
||||
if (errorMessage != null)
|
||||
{
|
||||
throw new Exception(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -277,11 +340,34 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return true if backup to URL is supported in the current SQL Server version
|
||||
/// Returns the certificates and asymmetric keys from master for encryption
|
||||
/// </summary>
|
||||
private bool BackupToUrlSupported()
|
||||
public List<BackupEncryptor> GetBackupEncryptors()
|
||||
{
|
||||
return BackupRestoreBase.IsBackupUrlDeviceSupported(this.dataContainer.Server.PingSqlServerVersion(this.dataContainer.ServerName));
|
||||
List<BackupEncryptor> encryptors = new List<BackupEncryptor>();
|
||||
if (this.dataContainer.Server.Databases.Contains("master"))
|
||||
{
|
||||
CertificateCollection certificates = this.dataContainer.Server.Databases["master"].Certificates;
|
||||
DateTime currentUtcDateTime = DateTime.UtcNow;
|
||||
foreach (Certificate item in certificates)
|
||||
{
|
||||
if ((item.Name.StartsWith("##", StringComparison.InvariantCulture) && item.Name.EndsWith("##", StringComparison.InvariantCulture)) ||
|
||||
DateTime.Compare(item.ExpirationDate, currentUtcDateTime) < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
encryptors.Add(new BackupEncryptor((int)BackupEncryptorType.ServerCertificate, item.Name));
|
||||
}
|
||||
AsymmetricKeyCollection keys = this.dataContainer.Server.Databases["master"].AsymmetricKeys;
|
||||
foreach (AsymmetricKey item in keys)
|
||||
{
|
||||
if (item.KeyEncryptionAlgorithm == AsymmetricKeyEncryptionAlgorithm.CryptographicProviderDefined)
|
||||
{
|
||||
encryptors.Add(new BackupEncryptor((int)BackupEncryptorType.ServerAsymmetricKey, item.Name));
|
||||
}
|
||||
}
|
||||
}
|
||||
return encryptors;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -54,6 +54,33 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
|
||||
StandBy
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class for backup encryptor
|
||||
/// </summary>
|
||||
public class BackupEncryptor
|
||||
{
|
||||
/// <summary>
|
||||
/// Ctor
|
||||
/// </summary>
|
||||
/// <param name="encryptorType"></param>
|
||||
/// <param name="encryptorName"></param>
|
||||
public BackupEncryptor(int encryptorType, string encryptorName)
|
||||
{
|
||||
this.EncryptorType = encryptorType;
|
||||
this.EncryptorName = encryptorName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encryptor type - certificate or asymetric key
|
||||
/// </summary>
|
||||
public int EncryptorType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Encryptor name
|
||||
/// </summary>
|
||||
public string EncryptorName { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restore item source
|
||||
/// </summary>
|
||||
|
||||
@@ -13,11 +13,34 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts
|
||||
/// </summary>
|
||||
public class BackupConfigInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets default database info
|
||||
/// </summary>
|
||||
public DatabaseInfo DatabaseInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets recovery model of a database
|
||||
/// </summary>
|
||||
public string RecoveryModel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the latest backup set of a database
|
||||
/// </summary>
|
||||
public List<RestoreItemSource> LatestBackups { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the default backup folder
|
||||
/// </summary>
|
||||
public string DefaultBackupFolder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets backup encryptors
|
||||
/// </summary>
|
||||
public List<BackupEncryptor> BackupEncryptors { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ctor
|
||||
/// </summary>
|
||||
public BackupConfigInfo()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts
|
||||
@@ -13,7 +14,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts
|
||||
/// Name of the datbase to perfom backup
|
||||
/// </summary>
|
||||
public string DatabaseName { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Component to backup - Database or Files
|
||||
/// </summary>
|
||||
@@ -48,15 +49,104 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts
|
||||
/// List of {key: backup path, value: device type}
|
||||
/// </summary>
|
||||
public Dictionary<string, int> BackupPathDevices { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// List of selected backup paths
|
||||
/// </summary>
|
||||
public List<string> BackupPathList { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the backup should be copy-only
|
||||
/// </summary>
|
||||
public bool IsCopyOnly { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a Boolean property value that determines whether a media is formatted as the first step of the backup operation.
|
||||
/// </summary>
|
||||
public bool FormatMedia { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a Boolean property value that determines whether the devices associated with a backup operation are initialized as part of the backup operation.
|
||||
/// </summary>
|
||||
public bool Initialize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets Boolean property that determines whether the tape header is read.
|
||||
/// </summary>
|
||||
public bool SkipTapeHeader { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name used to identify a particular media set.
|
||||
/// </summary>
|
||||
public string MediaName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a textual description of the medium that contains a backup set.
|
||||
/// </summary>
|
||||
public string MediaDescription { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a Boolean property value that determines whether a checksum value is calculated during backup or restore operations.
|
||||
/// </summary>
|
||||
public bool Checksum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a Boolean property value that determines whether the backup or restore continues after a checksum error occurs.
|
||||
/// </summary>
|
||||
public bool ContinueAfterError { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a Boolean property value that determines whether to truncate the database log.
|
||||
/// </summary>
|
||||
public bool LogTruncation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a Boolean property value that determines whether to backup the tail of the log
|
||||
/// </summary>
|
||||
public bool TailLogBackup { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a textual description for a particular backup set.
|
||||
/// </summary>
|
||||
public string BackupSetDescription { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the number of days that must elapse before a backup set can be overwritten.
|
||||
/// </summary>
|
||||
public int RetainDays { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the date and time when the backup set expires and the backup data is no longer considered relevant.
|
||||
/// </summary>
|
||||
public DateTime ExpirationDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the backup compression option.
|
||||
/// This should be converted to BackupCompressionOptions when setting it to Backup object.
|
||||
/// </summary>
|
||||
public int CompressionOption { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a Boolean property that determines whether verify is required.
|
||||
/// </summary>
|
||||
public bool VerifyBackupRequired { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the algorithm type used for backup encryption.
|
||||
/// This should be converted to BackupEncryptionAlgorithm when creating BackupEncryptionOptions object.
|
||||
/// </summary>
|
||||
public int EncryptionAlgorithm { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the encryptor type used to encrypt an encryption key.
|
||||
/// This should be converted to BackupEncryptorType when creating BackupEncryptionOptions object.
|
||||
/// </summary>
|
||||
public int EncryptorType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the encryptor.
|
||||
/// </summary>
|
||||
public string EncryptorName { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,7 +281,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
|
||||
{
|
||||
BackupOperation backupOperation = new BackupOperation();
|
||||
backupOperation.Initialize(dataContainer, sqlConnection);
|
||||
return backupOperation.GetBackupConfigInfo(databaseName);
|
||||
return backupOperation.CreateBackupConfigInfo(databaseName);
|
||||
}
|
||||
|
||||
internal BackupOperation SetBackupInput(CDataContainer dataContainer, SqlConnection sqlConnection, BackupInfo input)
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
|
||||
/// </summary>
|
||||
/// <param name="databaseName"></param>
|
||||
/// <returns></returns>
|
||||
BackupConfigInfo GetBackupConfigInfo(string databaseName);
|
||||
BackupConfigInfo CreateBackupConfigInfo(string databaseName);
|
||||
|
||||
/// <summary>
|
||||
/// Set backup input properties
|
||||
|
||||
Reference in New Issue
Block a user