Retrieve Azure SLO details in Database Handler (#2094)

This commit is contained in:
Cory Rivera
2023-06-12 11:44:17 -07:00
committed by GitHub
parent 323f3827e2
commit 808172bc20
10 changed files with 462 additions and 73 deletions

View File

@@ -17,6 +17,7 @@ using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Management;
using Microsoft.SqlTools.ServiceLayer.ObjectManagement.Contracts;
using Microsoft.SqlTools.ServiceLayer.Utility;
using Microsoft.SqlTools.Utility;
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
{
@@ -37,6 +38,11 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
private static readonly Dictionary<string, ContainmentType> containmentTypeEnums = new Dictionary<string, ContainmentType>();
private static readonly Dictionary<string, RecoveryModel> recoveryModelEnums = new Dictionary<string, RecoveryModel>();
internal static readonly string[] AzureEditionNames;
internal static readonly string[] AzureBackupLevels;
internal static readonly AzureEditionDetails[] AzureMaxSizes;
internal static readonly AzureEditionDetails[] AzureServiceLevels;
static DatabaseHandler()
{
displayCompatLevels.Add(CompatibilityLevel.Version70, SR.compatibilityLevel_sphinx);
@@ -71,6 +77,13 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
{
recoveryModelEnums.Add(displayRecoveryModels[key], key);
}
// Azure SLO info is invariant of server information, so set up static objects we can return later
var editions = AzureSqlDbHelper.GetValidAzureEditionOptions();
AzureEditionNames = editions.Select(edition => edition.DisplayName).ToArray();
AzureBackupLevels = AzureSqlDbHelper.BackupStorageRedundancyLevels;
AzureMaxSizes = GetAzureMaxSizes(editions);
AzureServiceLevels = GetAzureServiceLevels(editions);
}
public DatabaseHandler(ConnectionService connectionService) : base(connectionService)
@@ -99,18 +112,17 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
var prototype = taskHelper.Prototype;
var azurePrototype = prototype as DatabasePrototypeAzure;
bool isDw = azurePrototype != null && azurePrototype.AzureEdition == AzureEdition.DataWarehouse;
bool isAzureDB = dataContainer.Server.ServerType == DatabaseEngineType.SqlAzureDatabase;
var databaseViewInfo = new DatabaseViewInfo()
{
ObjectInfo = new DatabaseInfo()
ObjectInfo = new DatabaseInfo(),
IsAzureDB = isAzureDB
};
// azure sql db doesn't have a sysadmin fixed role
var compatibilityLevelEnabled = !isDw &&
(dataContainer.LoggedInUserIsSysadmin ||
dataContainer.Server.ServerType ==
DatabaseEngineType.SqlAzureDatabase);
if (dataContainer.Server.ServerType == DatabaseEngineType.SqlAzureDatabase)
var compatibilityLevelEnabled = !isDw && (dataContainer.LoggedInUserIsSysadmin || isAzureDB);
if (isAzureDB)
{
// Azure doesn't allow modifying the collation after DB creation
bool collationEnabled = !prototype.Exists;
@@ -133,6 +145,10 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
databaseViewInfo.CompatibilityLevels = GetCompatibilityLevels(dataContainer.SqlServerVersion, prototype);
}
}
databaseViewInfo.AzureBackupRedundancyLevels = AzureBackupLevels;
databaseViewInfo.AzureServiceLevelObjectives = AzureServiceLevels;
databaseViewInfo.AzureEditions = AzureEditionNames;
databaseViewInfo.AzureMaxSizes = AzureMaxSizes;
}
else
{
@@ -148,7 +164,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
}
// Skip adding logins if running against an Azure SQL DB
if (dataContainer.Server.ServerType != DatabaseEngineType.SqlAzureDatabase)
if (!isAzureDB)
{
var logins = new List<string>();
foreach (Login login in dataContainer.Server.Logins)
@@ -283,6 +299,27 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
db110.DatabaseContainmentType = containmentTypeEnums[database.ContainmentType];
}
if (prototype is DatabasePrototypeAzure dbAz)
{
// Set edition first since the prototype will fill all the Azure fields with default values
if (database.AzureEdition != null)
{
dbAz.AzureEditionDisplay = database.AzureEdition;
}
if (database.AzureBackupRedundancyLevel != null)
{
dbAz.BackupStorageRedundancy = database.AzureBackupRedundancyLevel;
}
if (database.AzureServiceLevelObjective != null)
{
dbAz.CurrentServiceLevelObjective = database.AzureServiceLevelObjective;
}
if (database.AzureMaxSize != null)
{
dbAz.MaxSize = database.AzureMaxSize;
}
}
string sqlScript = string.Empty;
using (var actions = new DatabaseActions(dataContainer, configAction, prototype))
using (var executionHandler = new ExecutonHandler(actions))
@@ -583,5 +620,65 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
// previous loop did not find the prototype compatibility level in this server's compatability options, so treat compatibility levels as unsupported for this server
return Array.Empty<string>();
}
/// <summary>
/// Get supported service level objectives for this Azure server.
/// </summary>
private static AzureEditionDetails[] GetAzureServiceLevels(IEnumerable<AzureEdition> editions)
{
var levels = new List<AzureEditionDetails>();
foreach (AzureEdition edition in editions)
{
if (AzureSqlDbHelper.TryGetServiceObjectiveInfo(edition, out var serviceInfoPair))
{
// Move default value to the front of the list
var serviceLevelsList = new List<string>(serviceInfoPair.Value);
var defaultIndex = serviceInfoPair.Key;
if (defaultIndex >= 0 && defaultIndex < serviceLevelsList.Count)
{
var defaultServiceObjective = serviceLevelsList[defaultIndex];
serviceLevelsList.RemoveAt(defaultIndex);
serviceLevelsList.Insert(0, defaultServiceObjective);
}
var details = new AzureEditionDetails() { EditionDisplayName = edition.DisplayName, Details = serviceLevelsList.ToArray() };
levels.Add(details);
}
else
{
Logger.Error($"Failed to get service level objective info for edition '{edition.Name}'");
}
}
return levels.ToArray();
}
/// <summary>
/// Get supported maximum sizes for this Azure server.
/// </summary>
private static AzureEditionDetails[] GetAzureMaxSizes(IEnumerable<AzureEdition> editions)
{
var sizes = new List<AzureEditionDetails>();
foreach (AzureEdition edition in editions)
{
if (AzureSqlDbHelper.TryGetDatabaseSizeInfo(edition, out var sizeInfoPair))
{
// Move default value to the front of the list
var sizeInfoList = new List<DbSize>(sizeInfoPair.Value);
var defaultIndex = sizeInfoPair.Key;
if (defaultIndex >= 0 && defaultIndex < sizeInfoList.Count)
{
var defaultSizeInfo = sizeInfoList[defaultIndex];
sizeInfoList.RemoveAt(defaultIndex);
sizeInfoList.Insert(0, defaultSizeInfo);
}
var details = new AzureEditionDetails() { EditionDisplayName = edition.DisplayName, Details = sizeInfoList.Select(info => info.ToString()).ToArray() };
sizes.Add(details);
}
else
{
Logger.Error($"Failed to get database size info for edition '{edition.Name}'");
}
}
return sizes.ToArray();
}
}
}

View File

@@ -15,5 +15,10 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
public string? RecoveryModel { get; set; }
public string? CompatibilityLevel { get; set; }
public string? ContainmentType { get; set; }
public string? AzureBackupRedundancyLevel { get; set; }
public string? AzureServiceLevelObjective { get; set; }
public string? AzureEdition { get; set; }
public string? AzureMaxSize { get; set; }
}
}

View File

@@ -14,5 +14,17 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
public string[] CompatibilityLevels { get; set; }
public string[] ContainmentTypes { get; set; }
public string[] RecoveryModels { get; set; }
public bool IsAzureDB { get; set; }
public string[] AzureBackupRedundancyLevels { get; set; }
public AzureEditionDetails[] AzureServiceLevelObjectives { get; set; }
public string[] AzureEditions { get; set; }
public AzureEditionDetails[] AzureMaxSizes { get; set; }
}
public class AzureEditionDetails
{
public string EditionDisplayName { get; set; }
public string[] Details { get; set; }
}
}