Skip to content

Commit

Permalink
Added Azure SQL Standard estimation
Browse files Browse the repository at this point in the history
  • Loading branch information
kamil-mrzyglod committed Jul 24, 2022
1 parent 0279311 commit deed68a
Show file tree
Hide file tree
Showing 14 changed files with 347 additions and 17 deletions.
13 changes: 9 additions & 4 deletions arm-estimator-generator/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,21 @@ internal class Program
{
private static async Task<int> Main(string[] args)
{
File.AppendAllText("compute.csv", "type;serviceId;serviceName;skuId;skuName;productId;productName;meterId;meterName" + Environment.NewLine);
if(File.Exists("sql.csv"))
{
File.Delete("sql.csv");
}

File.AppendAllText("sql.csv", "type;serviceId;serviceName;skuId;skuName;productId;productName;meterId;meterName" + Environment.NewLine);

var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, $"https://prices.azure.com/api/retail/prices?$filter=serviceFamily eq 'Compute' and armRegionName eq 'westeurope'");
var request = new HttpRequestMessage(HttpMethod.Get, $"https://prices.azure.com/api/retail/prices?$filter=serviceName eq 'SQL Database' and armRegionName eq 'westeurope'");
var response = await client.SendAsync(request);
var data = JsonSerializer.Deserialize<RetailAPIResponse>(await response.Content.ReadAsStreamAsync());

foreach(var item in data.Items)
{
File.AppendAllText("compute.csv", $"{item.type};{item.serviceId};{item.serviceName};{item.skuId};{item.skuName};{item.productId};{item.productName};{item.meterId};{item.meterName}" + Environment.NewLine);
File.AppendAllText("sql.csv", $"{item.type};{item.serviceId};{item.serviceName};{item.skuId};{item.skuName};{item.productId};{item.productName};{item.meterId};{item.meterName}" + Environment.NewLine);
}

var nextLink = data.NextPageLink;
Expand All @@ -33,7 +38,7 @@ private static async Task<int> Main(string[] args)

foreach (var item in data.Items)
{
File.AppendAllText("compute.csv", $"{item.type};{item.serviceId};{item.serviceName};{item.skuId};{item.skuName};{item.productId};{item.productName};{item.meterId};{item.meterName}" + Environment.NewLine);
File.AppendAllText("sql.csv", $"{item.type};{item.serviceId};{item.serviceName};{item.skuId};{item.skuName};{item.productId};{item.productName};{item.meterId};{item.meterName}" + Environment.NewLine);
}

return data.NextPageLink;
Expand Down
4 changes: 3 additions & 1 deletion arm-estimator/Calculation/BaseEstimation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
{
internal static readonly int HoursInMonth = 720;
internal readonly RetailItem[] items;
internal readonly WhatIfAfterChange change;

public BaseEstimation(RetailItem[] items)
public BaseEstimation(RetailItem[] items, WhatIfAfterChange change)
{
this.items = items;
this.change = change;
}
}
4 changes: 2 additions & 2 deletions arm-estimator/Products/AKS/AKSEstimationCalculation.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
internal class AKSEstimationCalculation : BaseEstimation, IEstimationCalculation
{
public AKSEstimationCalculation(RetailItem[] items)
: base(items)
public AKSEstimationCalculation(RetailItem[] items, WhatIfAfterChange change)
: base(items, change)
{
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
internal class AppServicePlanEstimationCalculation : BaseEstimation, IEstimationCalculation
{
public AppServicePlanEstimationCalculation(RetailItem[] items)
: base(items)
public AppServicePlanEstimationCalculation(RetailItem[] items, WhatIfAfterChange change)
: base(items, change)
{
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
internal class ContainerAppsEstimationCalculation : BaseEstimation, IEstimationCalculation
{
public ContainerAppsEstimationCalculation(RetailItem[] items)
: base(items)
public ContainerAppsEstimationCalculation(RetailItem[] items, WhatIfAfterChange change)
: base(items, change)
{
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
internal class ContainerRegistryEstimationCalculation : BaseEstimation, IEstimationCalculation
{
public ContainerRegistryEstimationCalculation(RetailItem[] items)
: base(items)
public ContainerRegistryEstimationCalculation(RetailItem[] items, WhatIfAfterChange change)
: base(items, change)
{
}

Expand Down
60 changes: 60 additions & 0 deletions arm-estimator/Products/SQL/SQLEstimationCalculation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
internal class SQLEstimationCalculation : BaseEstimation, IEstimationCalculation
{
public SQLEstimationCalculation(RetailItem[] items, WhatIfAfterChange change)
: base(items, change)
{
}

public IOrderedEnumerable<RetailItem> GetItems()
{
var consumptionMetrics = this.items.Where(_ => _.type != "Reservation");

return this.items.Where(_ => _.type != "Reservation").OrderByDescending(_ => _.retailPrice);
}

public double GetTotalCost()
{
double? estimatedCost = 0;
var items = GetItems();

foreach(var item in items)
{
// B DTUs
if(item.meterId == "cae64797-9ecf-4906-b517-6238c80c045f")
{
estimatedCost += item.retailPrice * 30;
}
// S0 DTUs
else if (item.meterId == "a149966f-73b4-4e1d-b335-d2a572b1e6bd")
{
estimatedCost += item.retailPrice * 30;
}
// S1 DTUs
else if (item.meterId == "54c6bbf3-322b-406d-8411-101bc4b9443a")
{
estimatedCost += item.retailPrice * 30;
}
// S2 DTUs
else if (item.meterId == "f303a21a-05f1-4563-b2ad-7523eebc4058")
{
estimatedCost += item.retailPrice * 30;
}
// S3 DTUs
else if (item.meterId == "6bafdc11-b964-4895-9d4e-a0e548db1b2b")
{
estimatedCost += item.retailPrice * 30;
}
// 10 DTU - everything above S3
else if (item.meterId == "94aaed62-bf2f-4461-8f69-078933cb2f72")
{
estimatedCost += item.retailPrice * 30;
}
else
{
estimatedCost += item.retailPrice;
}
}

return estimatedCost == null ? 0 : (double)estimatedCost;
}
}
31 changes: 31 additions & 0 deletions arm-estimator/Products/SQL/SQLQueryFilter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Microsoft.Extensions.Logging;

internal class SQLQueryFilter : IQueryFilter
{
private const string ServiceId = "DZH3180HX10K";

private readonly WhatIfAfterChange afterState;
private readonly ILogger logger;

public SQLQueryFilter(WhatIfAfterChange afterState, ILogger logger)
{
this.afterState = afterState;
this.logger = logger;
}

public string? GetFiltersBasedOnDesiredState()
{
var location = this.afterState.location;
var sku = this.afterState.sku?.name;
if (sku == null)
{
this.logger.LogError("Can't create a filter for Azure SQL when SKU is unavailable.");
return null;
}

var skuIds = SQLSupportedData.SkuToSkuIdMap[sku];
var skuIdsFilter = string.Join(" or ", skuIds.Select(_ => $"skuId eq '{_}'"));

return $"$filter=serviceId eq '{ServiceId}' and armRegionName eq '{location}' and ({skuIdsFilter})";
}
}
21 changes: 21 additions & 0 deletions arm-estimator/Products/SQL/SQLRetailQuery.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Microsoft.Extensions.Logging;

internal class SQLRetailQuery : BaseRetailQuery, IRetailQuery
{
public SQLRetailQuery(WhatIfChange change, ILogger logger)
: base(change, logger)
{
}

public string? GetQueryUrl()
{
if (this.change.after == null)
{
this.logger.LogError("Can't generate Retail API query if desired state is unavailable.");
return null;
}

var filter = new SQLQueryFilter(this.change.after, this.logger).GetFiltersBasedOnDesiredState();
return $"https://prices.azure.com/api/retail/prices?{filter}";
}
}
59 changes: 59 additions & 0 deletions arm-estimator/Products/SQL/SQLSupportedData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
internal class SQLSupportedData
{
public static readonly IReadOnlyDictionary<string, string[]> SkuToSkuIdMap = new Dictionary<string, string[]>()
{
{ "Free", new[] {
"DZH318Z0BQH9/0013"
}
},
{ "Basic", new[] {
"DZH318Z0BQGZ/004K"
}
},
{ "S0", new[] {
"DZH318Z0BQHF/00LB"
}
},
{ "S1", new[] {
"DZH318Z0BQHF/00LT"
}
},
{ "S2", new[] {
"DZH318Z0BQHF/017X"
}
},
{ "S3", new[] {
"DZH318Z0BQHF/00TX"
}
},
{ "S4", new[] {
"DZH318Z0BQHF/014D"
}
},
{ "S6", new[] {
"DZH318Z0BQHF/00TZ"
}
},
{ "S7", new[] {
"DZH318Z0BQHF/012N"
}
},
{ "S9", new[] {
"DZH318Z0BQHF/00SQ"
}
},
{ "S12", new[] {
"DZH318Z0BQHF/00LJ"
}
}
};

public static readonly IReadOnlyDictionary<string, int> SkuToDTUsMap = new Dictionary<string, int>()
{
{ "S4", 200 },
{ "S6", 400 },
{ "S7", 800 },
{ "S9", 1600 },
{ "S12", 3000 }
};
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
internal class StorageAccountEstimationCalculation : BaseEstimation, IEstimationCalculation
{
public StorageAccountEstimationCalculation(RetailItem[] items)
: base(items)
public StorageAccountEstimationCalculation(RetailItem[] items, WhatIfAfterChange change)
: base(items, change)
{
}

Expand Down
14 changes: 13 additions & 1 deletion arm-estimator/WhatIf/WhatIfProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ public async Task Process(WhatIfChange[] changes)
case "Microsoft.App/containerApps":
totalCost += await Calculate<ContainerAppsRetailQuery, ContainerAppsEstimationCalculation>(change, id);
break;
case "Microsoft.Sql/servers":
totalCost += 0;
break;
case "Microsoft.Sql/servers/databases":
totalCost += await Calculate<SQLRetailQuery, SQLEstimationCalculation>(change, id);
break;
default:
logger.LogWarning("{resourceType} is not yet supported.", id.ResourceType);
break;
Expand All @@ -71,7 +77,13 @@ private async Task<double> Calculate<TQuery, TCalculation>(WhatIfChange change,
return 0;
}

if (Activator.CreateInstance(typeof(TCalculation), new object[] { data.Items }) is not TCalculation estimation)
if(change.after == null)
{
this.logger.LogError("No data available for WhatIf operation.");
return 0;
}

if (Activator.CreateInstance(typeof(TCalculation), new object[] { data.Items, change.after }) is not TCalculation estimation)
{
this.logger.LogError("Couldn't create an instance of {type}.", typeof(TCalculation));
return 0;
Expand Down
61 changes: 61 additions & 0 deletions arm-estimator/templates/complex.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,67 @@ resource containerapp 'Microsoft.App/containerApps@2022-03-01' = {
name: 'containerapp'
location: 'westeurope'
properties: {
}
}

resource dbserver 'Microsoft.Sql/servers@2021-11-01-preview' = {
name: 'sqlserver'
location: 'westeurope'
properties: {

}
}

resource dbbasic 'Microsoft.Sql/servers/databases@2021-11-01-preview' = {
parent: dbserver
name: 'dbbasic'
location: 'westeurope'
sku: {
name: 'Basic'
}
}

resource dbstandard0 'Microsoft.Sql/servers/databases@2021-11-01-preview' = {
parent: dbserver
name: 'dbstandard0'
location: 'westeurope'
sku: {
name: 'S0'
}
}

resource dbstandard1 'Microsoft.Sql/servers/databases@2021-11-01-preview' = {
parent: dbserver
name: 'dbstandard1'
location: 'westeurope'
sku: {
name: 'S1'
}
}

resource dbstandard2 'Microsoft.Sql/servers/databases@2021-11-01-preview' = {
parent: dbserver
name: 'dbstandard2'
location: 'westeurope'
sku: {
name: 'S2'
}
}

resource dbstandard3 'Microsoft.Sql/servers/databases@2021-11-01-preview' = {
parent: dbserver
name: 'dbstandard3'
location: 'westeurope'
sku: {
name: 'S3'
}
}

resource dbstandard4 'Microsoft.Sql/servers/databases@2021-11-01-preview' = {
parent: dbserver
name: 'dbstandard4'
location: 'westeurope'
sku: {
name: 'S4'
}
}
Loading

0 comments on commit deed68a

Please sign in to comment.