mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-13 17:23:02 -05:00
Retrieve Azure SLO details in Database Handler (#2094)
This commit is contained in:
@@ -21,19 +21,13 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
|
||||
[DebuggerDisplay("{Name,nq}")]
|
||||
public class AzureEdition
|
||||
{
|
||||
public static readonly AzureEdition Basic = new AzureEdition("Basic", "SR.BasicAzureEdition");
|
||||
public static readonly AzureEdition Standard = new AzureEdition("Standard", "SR.StandardAzureEdition");
|
||||
public static readonly AzureEdition Premium = new AzureEdition("Premium", "SR.PremiumAzureEdition");
|
||||
public static readonly AzureEdition DataWarehouse = new AzureEdition("DataWarehouse", "SR.DataWarehouseAzureEdition");
|
||||
public static readonly AzureEdition GeneralPurpose = new AzureEdition("GeneralPurpose", "SR.GeneralPurposeAzureEdition");
|
||||
public static readonly AzureEdition BusinessCritical = new AzureEdition("BusinessCritical", "SR.BusinessCriticalAzureEdition");
|
||||
|
||||
public static readonly AzureEdition Hyperscale = new AzureEdition("Hyperscale", "SR.HyperscaleAzureEdition");
|
||||
// Free does not offer DatabaseSize >=1GB, hence it's not "supported".
|
||||
//public static readonly AzureEdition Free = new AzureEdition("Free", SR.FreeAzureEdition);
|
||||
// Stretch and system do not seem to be applicable, so I'm commenting them out
|
||||
//public static readonly AzureEdition Stretch = new AzureEdition("Stretch", SR.StretchAzureEdition);
|
||||
//public static readonly AzureEdition System = new AzureEdition("System", SR.SystemAzureEdition);
|
||||
public static readonly AzureEdition Basic = new AzureEdition("Basic", SR.BasicAzureEdition);
|
||||
public static readonly AzureEdition Standard = new AzureEdition("Standard", SR.StandardAzureEdition);
|
||||
public static readonly AzureEdition Premium = new AzureEdition("Premium", SR.PremiumAzureEdition);
|
||||
public static readonly AzureEdition DataWarehouse = new AzureEdition("DataWarehouse", SR.DataWarehouseAzureEdition);
|
||||
public static readonly AzureEdition GeneralPurpose = new AzureEdition("GeneralPurpose", SR.GeneralPurposeAzureEdition);
|
||||
public static readonly AzureEdition BusinessCritical = new AzureEdition("BusinessCritical", SR.BusinessCriticalAzureEdition);
|
||||
public static readonly AzureEdition Hyperscale = new AzureEdition("Hyperscale", SR.HyperscaleAzureEdition);
|
||||
|
||||
internal string Name { get; private set; }
|
||||
internal string DisplayName { get; private set; }
|
||||
@@ -320,6 +314,18 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
|
||||
{ "LRS", "Local" },
|
||||
{ "ZRS", "Zone" }
|
||||
};
|
||||
private static readonly string[] backupRedundancyLevels = bsrAPIToUIValueMapping.Values.ToArray();
|
||||
|
||||
/// <summary>
|
||||
/// All valid backup storage redundancy levels for an Azure SQL database
|
||||
/// </summary>
|
||||
public static string[] BackupStorageRedundancyLevels
|
||||
{
|
||||
get
|
||||
{
|
||||
return backupRedundancyLevels;
|
||||
}
|
||||
}
|
||||
|
||||
//KeyValuePair contains the BackupStorageRedundancy values for all azure editions.
|
||||
private static readonly KeyValuePair<int, string[]> keyValuePair = new KeyValuePair<int, string[]>(0, bsrAPIToUIValueMapping.Values.ToArray());
|
||||
@@ -516,7 +522,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
|
||||
/// We do this so that the AzureEdition enum can have values such as NONE or DEFAULT added
|
||||
/// without requiring clients to explicitly filter out those values themselves each time.
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<AzureEdition> GetValidAzureEditionOptions(object unused)
|
||||
public static IEnumerable<AzureEdition> GetValidAzureEditionOptions()
|
||||
{
|
||||
yield return AzureEdition.Basic;
|
||||
yield return AzureEdition.Standard;
|
||||
@@ -524,10 +530,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
|
||||
yield return AzureEdition.DataWarehouse;
|
||||
yield return AzureEdition.BusinessCritical;
|
||||
yield return AzureEdition.GeneralPurpose;
|
||||
//yield return AzureEdition.Free;
|
||||
yield return AzureEdition.Hyperscale;
|
||||
//yield return AzureEdition.Stretch;
|
||||
//yield return AzureEdition.System;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ using Microsoft.SqlTools.ServiceLayer.Management;
|
||||
using AzureEdition = Microsoft.SqlTools.ServiceLayer.Admin.AzureSqlDbHelper.AzureEdition;
|
||||
using System;
|
||||
using System.Data;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Admin
|
||||
{
|
||||
@@ -91,58 +93,56 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
|
||||
{
|
||||
return AzureSqlDbHelper.GetAzureEditionDisplayName(this.currentState.azureEdition);
|
||||
}
|
||||
// set
|
||||
// {
|
||||
// AzureEdition edition;
|
||||
// if (AzureSqlDbHelper.TryGetAzureEditionFromDisplayName(value, out edition))
|
||||
// {
|
||||
// //Try to get the ServiceLevelObjective from the api,if not the default hardcoded service level objectives will be retrieved.
|
||||
// string serverLevelObjective = AzureServiceLevelObjectiveProvider.TryGetAzureServiceLevelObjective(value, AzureServiceLocation);
|
||||
set
|
||||
{
|
||||
AzureEdition edition;
|
||||
if (AzureSqlDbHelper.TryGetAzureEditionFromDisplayName(value, out edition))
|
||||
{
|
||||
//Try to get the ServiceLevelObjective from the api,if not the default hardcoded service level objectives will be retrieved.
|
||||
// string serverLevelObjective = AzureServiceLevelObjectiveProvider.TryGetAzureServiceLevelObjective(value, AzureServiceLocation);
|
||||
|
||||
// if (!string.IsNullOrEmpty(serverLevelObjective))
|
||||
// {
|
||||
// this.currentState.azureEdition = edition;
|
||||
// this.currentState.currentServiceLevelObjective = serverLevelObjective;
|
||||
// // Instead of creating db instance with default Edition, update EditionToCreate while selecting Edition from the UI.
|
||||
// this.EditionToCreate = MapAzureEditionToDbEngineEdition(edition);
|
||||
// string storageAccountType = AzureServiceLevelObjectiveProvider.TryGetAzureStorageType(value, AzureServiceLocation);
|
||||
// if (!string.IsNullOrEmpty(storageAccountType))
|
||||
// {
|
||||
// this.currentState.backupStorageRedundancy = storageAccountType;
|
||||
// }
|
||||
// if (!string.IsNullOrEmpty(serverLevelObjective))
|
||||
// {
|
||||
// this.currentState.azureEdition = edition;
|
||||
// this.currentState.currentServiceLevelObjective = serverLevelObjective;
|
||||
// // Instead of creating db instance with default Edition, update EditionToCreate while selecting Edition from the UI.
|
||||
// this.EditionToCreate = MapAzureEditionToDbEngineEdition(edition);
|
||||
// string storageAccountType = AzureServiceLevelObjectiveProvider.TryGetAzureStorageType(value, AzureServiceLocation);
|
||||
// if (!string.IsNullOrEmpty(storageAccountType))
|
||||
// {
|
||||
// this.currentState.backupStorageRedundancy = storageAccountType;
|
||||
// }
|
||||
|
||||
// // Try to get the azure maxsize from the api,if not the default hardcoded maxsize will be retrieved.
|
||||
// DbSize dbSize = AzureServiceLevelObjectiveProvider.TryGetAzureMaxSize(value, serverLevelObjective, AzureServiceLocation);
|
||||
// if (!string.IsNullOrEmpty(dbSize.ToString()))
|
||||
// {
|
||||
// this.currentState.maxSize = new DbSize(dbSize.Size, dbSize.SizeUnit);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (edition == this.currentState.azureEdition)
|
||||
// { //No changes, return early since we don't need to do any of the changes below
|
||||
// return;
|
||||
// }
|
||||
// // Try to get the azure maxsize from the api,if not the default hardcoded maxsize will be retrieved.
|
||||
// DbSize dbSize = AzureServiceLevelObjectiveProvider.TryGetAzureMaxSize(value, serverLevelObjective, AzureServiceLocation);
|
||||
// if (!string.IsNullOrEmpty(dbSize.ToString()))
|
||||
// {
|
||||
// this.currentState.maxSize = new DbSize(dbSize.Size, dbSize.SizeUnit);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
if (edition == this.currentState.azureEdition)
|
||||
{ // No changes, return early since we don't need to do any of the changes below
|
||||
return;
|
||||
}
|
||||
|
||||
// this.currentState.azureEdition = edition;
|
||||
// this.EditionToCreate = MapAzureEditionToDbEngineEdition(edition);
|
||||
// this.CurrentServiceLevelObjective = AzureSqlDbHelper.GetDefaultServiceObjective(edition);
|
||||
// this.BackupStorageRedundancy = AzureSqlDbHelper.GetDefaultBackupStorageRedundancy(edition);
|
||||
// var defaultSize = AzureSqlDbHelper.GetDatabaseDefaultSize(edition);
|
||||
this.currentState.azureEdition = edition;
|
||||
this.EditionToCreate = MapAzureEditionToDbEngineEdition(edition);
|
||||
this.CurrentServiceLevelObjective = AzureSqlDbHelper.GetDefaultServiceObjective(edition);
|
||||
this.BackupStorageRedundancy = AzureSqlDbHelper.GetDefaultBackupStorageRedundancy(edition);
|
||||
var defaultSize = AzureSqlDbHelper.GetDatabaseDefaultSize(edition);
|
||||
|
||||
// this.MaxSize = defaultSize == null ? String.Empty : defaultSize.ToString();
|
||||
// }
|
||||
// this.NotifyObservers();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// //Can't really do much if we fail to parse the display name so just leave it as is and log a message
|
||||
// System.Diagnostics.Debug.Assert(false,
|
||||
// string.Format(CultureInfo.InvariantCulture,
|
||||
// "Failed to parse edition display name '{0}' back into AzureEdition", value));
|
||||
// }
|
||||
// }
|
||||
this.MaxSize = defaultSize == null ? String.Empty : defaultSize.ToString();
|
||||
// }
|
||||
this.NotifyObservers();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Can't really do much if we fail to parse the display name so just leave it as is and log a message
|
||||
Logger.Write(TraceEventType.Error, $"Failed to parse edition display name '{value}' back into AzureEdition");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -12437,6 +12437,70 @@ namespace Microsoft.SqlTools.ServiceLayer
|
||||
}
|
||||
}
|
||||
|
||||
public static string BasicAzureEdition
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.BasicAzureEdition);
|
||||
}
|
||||
}
|
||||
|
||||
public static string StandardAzureEdition
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.StandardAzureEdition);
|
||||
}
|
||||
}
|
||||
|
||||
public static string PremiumAzureEdition
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.PremiumAzureEdition);
|
||||
}
|
||||
}
|
||||
|
||||
public static string DataWarehouseAzureEdition
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.DataWarehouseAzureEdition);
|
||||
}
|
||||
}
|
||||
|
||||
public static string GeneralPurposeAzureEdition
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.GeneralPurposeAzureEdition);
|
||||
}
|
||||
}
|
||||
|
||||
public static string BusinessCriticalAzureEdition
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.BusinessCriticalAzureEdition);
|
||||
}
|
||||
}
|
||||
|
||||
public static string ErrorInvalidEdition
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.ErrorInvalidEdition);
|
||||
}
|
||||
}
|
||||
|
||||
public static string HyperscaleAzureEdition
|
||||
{
|
||||
get
|
||||
{
|
||||
return Keys.GetString(Keys.HyperscaleAzureEdition);
|
||||
}
|
||||
}
|
||||
|
||||
public static string ConnectionServiceListDbErrorNotConnected(string uri)
|
||||
{
|
||||
return Keys.GetString(Keys.ConnectionServiceListDbErrorNotConnected, uri);
|
||||
@@ -17794,6 +17858,30 @@ namespace Microsoft.SqlTools.ServiceLayer
|
||||
public const string prototype_file_noApplicableFileGroup = "prototype_file_noApplicableFileGroup";
|
||||
|
||||
|
||||
public const string BasicAzureEdition = "BasicAzureEdition";
|
||||
|
||||
|
||||
public const string StandardAzureEdition = "StandardAzureEdition";
|
||||
|
||||
|
||||
public const string PremiumAzureEdition = "PremiumAzureEdition";
|
||||
|
||||
|
||||
public const string DataWarehouseAzureEdition = "DataWarehouseAzureEdition";
|
||||
|
||||
|
||||
public const string GeneralPurposeAzureEdition = "GeneralPurposeAzureEdition";
|
||||
|
||||
|
||||
public const string BusinessCriticalAzureEdition = "BusinessCriticalAzureEdition";
|
||||
|
||||
|
||||
public const string ErrorInvalidEdition = "ErrorInvalidEdition";
|
||||
|
||||
|
||||
public const string HyperscaleAzureEdition = "HyperscaleAzureEdition";
|
||||
|
||||
|
||||
private Keys()
|
||||
{ }
|
||||
|
||||
|
||||
@@ -6760,4 +6760,36 @@ The Query Processor estimates that implementing the following index could improv
|
||||
<value>No Applicable Filegroup</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="BasicAzureEdition" xml:space="preserve">
|
||||
<value>Basic</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="StandardAzureEdition" xml:space="preserve">
|
||||
<value>Standard</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="PremiumAzureEdition" xml:space="preserve">
|
||||
<value>Premium</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="DataWarehouseAzureEdition" xml:space="preserve">
|
||||
<value>DataWarehouse</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="GeneralPurposeAzureEdition" xml:space="preserve">
|
||||
<value>General Purpose</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="BusinessCriticalAzureEdition" xml:space="preserve">
|
||||
<value>Business Critical</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="ErrorInvalidEdition" xml:space="preserve">
|
||||
<value>Edition value is not valid</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
<data name="HyperscaleAzureEdition" xml:space="preserve">
|
||||
<value>Hyperscale</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -2802,3 +2802,15 @@ general_containmentType_None = None
|
||||
general_containmentType_Partial = Partial
|
||||
filegroups_filestreamFiles = FILESTREAM Files
|
||||
prototype_file_noApplicableFileGroup = No Applicable Filegroup
|
||||
|
||||
############################################################################
|
||||
# Azure SQL DB
|
||||
|
||||
BasicAzureEdition = Basic
|
||||
StandardAzureEdition = Standard
|
||||
PremiumAzureEdition = Premium
|
||||
DataWarehouseAzureEdition = DataWarehouse
|
||||
GeneralPurposeAzureEdition = General Purpose
|
||||
BusinessCriticalAzureEdition = Business Critical
|
||||
ErrorInvalidEdition = Edition value is not valid
|
||||
HyperscaleAzureEdition = Hyperscale
|
||||
@@ -8281,6 +8281,46 @@ The Query Processor estimates that implementing the following index could improv
|
||||
<target state="new">No Applicable Filegroup</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="BasicAzureEdition">
|
||||
<source>Basic</source>
|
||||
<target state="new">Basic</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardAzureEdition">
|
||||
<source>Standard</source>
|
||||
<target state="new">Standard</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="PremiumAzureEdition">
|
||||
<source>Premium</source>
|
||||
<target state="new">Premium</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="DataWarehouseAzureEdition">
|
||||
<source>DataWarehouse</source>
|
||||
<target state="new">DataWarehouse</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GeneralPurposeAzureEdition">
|
||||
<source>General Purpose</source>
|
||||
<target state="new">General Purpose</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="BusinessCriticalAzureEdition">
|
||||
<source>Business Critical</source>
|
||||
<target state="new">Business Critical</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="ErrorInvalidEdition">
|
||||
<source>Edition value is not valid</source>
|
||||
<target state="new">Edition value is not valid</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="HyperscaleAzureEdition">
|
||||
<source>Hyperscale</source>
|
||||
<target state="new">Hyperscale</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -3,15 +3,19 @@
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlTools.ServiceLayer.Admin;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||
using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.ObjectManagement;
|
||||
using Microsoft.SqlTools.ServiceLayer.Test.Common;
|
||||
using NUnit.Framework;
|
||||
using static Microsoft.SqlTools.ServiceLayer.Admin.AzureSqlDbHelper;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement
|
||||
{
|
||||
@@ -162,6 +166,102 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetAzureEditionsTest()
|
||||
{
|
||||
var actualEditionNames = DatabaseHandler.AzureEditionNames;
|
||||
var expectedEditionNames = AzureSqlDbHelper.GetValidAzureEditionOptions().Select(edition => edition.DisplayName);
|
||||
Assert.That(actualEditionNames, Is.EquivalentTo(expectedEditionNames));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetAzureBackupRedundancyLevelsTest()
|
||||
{
|
||||
var actualLevels = DatabaseHandler.AzureBackupLevels;
|
||||
var expectedLevels = new string[] { "Geo", "Local", "Zone" };
|
||||
Assert.That(actualLevels, Is.EquivalentTo(expectedLevels));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetAzureServiceLevelObjectivesTest()
|
||||
{
|
||||
var actualLevelsMap = new Dictionary<string, string[]>();
|
||||
foreach (AzureEditionDetails serviceDetails in DatabaseHandler.AzureServiceLevels)
|
||||
{
|
||||
actualLevelsMap.Add(serviceDetails.EditionDisplayName, serviceDetails.Details);
|
||||
}
|
||||
|
||||
var expectedDefaults = new Dictionary<AzureEdition, string>()
|
||||
{
|
||||
{ AzureEdition.Basic, "Basic" },
|
||||
{ AzureEdition.Standard, "S0" },
|
||||
{ AzureEdition.Premium, "P1" },
|
||||
{ AzureEdition.DataWarehouse, "DW400" },
|
||||
{ AzureEdition.BusinessCritical, "BC_Gen5_2" },
|
||||
{ AzureEdition.GeneralPurpose, "GP_Gen5_2" },
|
||||
{ AzureEdition.Hyperscale, "HS_Gen5_2" }
|
||||
};
|
||||
Assert.That(actualLevelsMap.Count, Is.EqualTo(expectedDefaults.Count), "Did not get expected number of editions for DatabaseHandler's service levels");
|
||||
foreach(AzureEdition edition in expectedDefaults.Keys)
|
||||
{
|
||||
if (AzureSqlDbHelper.TryGetServiceObjectiveInfo(edition, out var expectedLevelInfo))
|
||||
{
|
||||
var expectedServiceLevels = expectedLevelInfo.Value;
|
||||
var actualServiceLevels = actualLevelsMap[edition.DisplayName];
|
||||
Assert.That(actualServiceLevels, Is.EquivalentTo(expectedServiceLevels), "Did not get expected SLO list for edition '{0}'", edition.DisplayName);
|
||||
|
||||
var expectedDefaultIndex = expectedLevelInfo.Key;
|
||||
var expectedDefault = expectedServiceLevels[expectedDefaultIndex];
|
||||
var actualDefault = actualServiceLevels[0];
|
||||
Assert.That(actualDefault, Is.EqualTo(expectedDefault), "Did not get expected default SLO for edition '{0}'", edition.DisplayName);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Fail("Could not retrieve SLO info for Azure edition '{0}'", edition.DisplayName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetAzureMaxSizesTest()
|
||||
{
|
||||
var actualSizesMap = new Dictionary<string, string[]>();
|
||||
foreach (AzureEditionDetails sizeDetails in DatabaseHandler.AzureMaxSizes)
|
||||
{
|
||||
actualSizesMap.Add(sizeDetails.EditionDisplayName, sizeDetails.Details);
|
||||
}
|
||||
|
||||
var expectedDefaults = new Dictionary<AzureEdition, string>()
|
||||
{
|
||||
{ AzureEdition.Basic, "2GB" },
|
||||
{ AzureEdition.Standard, "250GB" },
|
||||
{ AzureEdition.Premium, "500GB" },
|
||||
{ AzureEdition.DataWarehouse, "10240GB" },
|
||||
{ AzureEdition.BusinessCritical, "32GB" },
|
||||
{ AzureEdition.GeneralPurpose, "32GB" },
|
||||
{ AzureEdition.Hyperscale, "0MB" }
|
||||
};
|
||||
Assert.That(actualSizesMap.Count, Is.EqualTo(expectedDefaults.Count), "Did not get expected number of editions for DatabaseHandler's max sizes");
|
||||
foreach(AzureEdition edition in expectedDefaults.Keys)
|
||||
{
|
||||
if (AzureSqlDbHelper.TryGetDatabaseSizeInfo(edition, out var expectedSizeInfo))
|
||||
{
|
||||
var expectedSizes = expectedSizeInfo.Value.Select(size => size.ToString()).ToArray();
|
||||
var actualSizes = actualSizesMap[edition.DisplayName];
|
||||
Assert.That(actualSizes, Is.EquivalentTo(expectedSizes), "Did not get expected size list for edition '{0}'", edition.DisplayName);
|
||||
|
||||
var expectedDefaultIndex = expectedSizeInfo.Key;
|
||||
var expectedDefault = expectedSizes[expectedDefaultIndex];
|
||||
var actualDefault = actualSizes[0];
|
||||
Assert.That(actualDefault, Is.EqualTo(expectedDefault.ToString()), "Did not get expected default size for edition '{0}'", edition.DisplayName);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Fail("Could not retrieve max size info for Azure edition '{0}'", edition.DisplayName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool DatabaseExists(string dbName, Server server)
|
||||
{
|
||||
server.Databases.Refresh();
|
||||
|
||||
Reference in New Issue
Block a user