Skip to content
Closed
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
62fc39b
Update subnetId local variable logic for dev center deployment
Aug 13, 2025
c1a80b7
Refactor virtual_network_subnet_ids logic for improved clarity and ef…
Aug 13, 2025
8998fbb
Refactor key vault resource definitions to enhance subnet management …
Aug 13, 2025
be0f961
Enhance Terraform outputs and variables for deployer configuration, i…
Aug 13, 2025
61bf74c
Add role assignment resources and enhance dependency management for D…
Aug 13, 2025
9d8f987
Add outputs for deployer client ID and agent subnet ID in sap_deploye…
Aug 13, 2025
05378fe
Enhance role assignments and key vault secrets management by updating…
Aug 13, 2025
3634f14
Enhance condition for additional network ID in vault_additional DNS z…
Aug 13, 2025
dd45d8d
Enhance deployer configuration by adding control plane name and resou…
Aug 13, 2025
43d878e
Refactor sap_library module to improve output handling and update pro…
Aug 13, 2025
bbc31f1
Refactor deployer resource group name assignment and enhance SPN hand…
Aug 13, 2025
019dab2
Enhance key vault secret management by adding v2 variables and valida…
Aug 13, 2025
0d4f555
Refactor debug condition checks to use lowercase 'true' for consisten…
Aug 13, 2025
f6ec2a5
Add file existence check before modifying variable file in save_confi…
Aug 13, 2025
fb6f992
Refactor deployment scripts for improved readability and functionality
Aug 13, 2025
4286e47
Remove redundant save_config_vars call in set_secrets.sh for improved…
Aug 13, 2025
8ac56ef
Refactor firewall_exists condition to improve clarity and ensure prop…
Aug 13, 2025
a5bd552
Refactor Terraform outputs and variables for SAP landscape deployment
Aug 13, 2025
7469b03
Refactor SPN key vault ID retrieval for improved clarity and consistency
Aug 13, 2025
2a63fc4
Refactor key vault secret retrieval for control plane to improve clar…
Aug 13, 2025
5b06eff
Refactor and enhance landscape and system models; add custom random I…
Aug 13, 2025
42ac987
Remove obsolete Azure AD authentication package reference from projec…
Aug 13, 2025
7364d46
Remove roles_validator.tf file to streamline Terraform module structure
Aug 13, 2025
151fe86
Add control plane permission script and enhance pipeline stages for A…
Aug 13, 2025
08867d5
Change script permissions to make the control plane permission pipeli…
Aug 13, 2025
b40edde
Fix duplicate task name for Ansible installation in pipeline configur…
Aug 13, 2025
fc09743
fix: update the arm_id parmaeter to id to parse the resource id of th…
devanshjainms Aug 13, 2025
209ff03
feat: add prefix output to set_all_secrets function for better context
Aug 13, 2025
9d52054
refactor: remove unused application configuration output handling fro…
Aug 14, 2025
fdb25b5
fix: streamline role assignment logic and improve parameter handling …
devanshjainms Aug 14, 2025
302d94d
fix: remove Azure AD authentication parameter from local backend conf…
devanshjainms Aug 14, 2025
9259d97
fix: quote variables in ImportAndReRunApply calls to prevent word spl…
devanshjainms Aug 14, 2025
56a8939
refactor: remove unused application configuration output handling fro…
Aug 14, 2025
083f4ed
fix: add dependencies for additional network peering resources
Aug 14, 2025
8feb398
fix: update references from arm_id to id for resource group and subne…
Aug 14, 2025
ea59cba
Refactor SPN variable handling to remove deprecated key vault secret …
Aug 14, 2025
e9f63a9
Downgrade azurerm provider version to 4.35.0 in both sap_deployer and…
Aug 14, 2025
47d1aa4
Add azurerm_client_config data block to import deployer resources
Aug 14, 2025
34edf6d
Add role assignment for Key Vault Administrator with conditional RBAC…
Aug 14, 2025
33d00f7
Refactor key vault secret retrieval logic to conditionally check for …
devanshjainms Aug 15, 2025
7d216a2
Remove unused role assignment for Key Vault Secrets Officer and simpl…
devanshjainms Aug 18, 2025
9e465ed
Add role assignment for Key Vault Secrets Officer with conditional sc…
devanshjainms Aug 18, 2025
1e5fd03
fix: update AMS instance type to latest API version for improved comp…
Aug 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 30 additions & 30 deletions Webapp/SDAF/Controllers/Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public static string WriteTfLine<T>(PropertyInfo property, T model)
str.AppendLine($" \"{t.Key}\" = \"{t.Value}\",");
}
}
str.Append("}");
str.Append('}');
}
else if (property.PropertyType.IsArray)
{
Expand All @@ -140,7 +140,7 @@ public static string WriteTfLine<T>(PropertyInfo property, T model)
str.Append($"\"{val}\", ");
}
str.Remove(str.Length - 2, 2);
str.Append("]");
str.Append(']');
}
else if (property.PropertyType == typeof(Image))
{
Expand All @@ -156,7 +156,7 @@ public static string WriteTfLine<T>(PropertyInfo property, T model)
str.AppendLine(" sku = " + $"\"{img.sku}\",");
str.AppendLine(" version = " + $"\"{img.version}\",");
str.AppendLine(" type = " + $"\"{img.type}\"");
str.Append("}");
str.Append('}');
}
else
{
Expand Down Expand Up @@ -266,7 +266,7 @@ public static async Task<byte[]> ProcessFormFile(IFormFile formFile,
// a display name.
MemberInfo property =
typeof(FileUploadModel).GetProperty(
formFile.Name[(formFile.Name.IndexOf(".", StringComparison.Ordinal) + 1)..]);
formFile.Name[(formFile.Name.IndexOf('.', StringComparison.Ordinal) + 1)..]);

if (property != null)
{
Expand Down Expand Up @@ -373,22 +373,22 @@ public static string TfvarToJson(string hclString)
jsonString.AppendLine("}");
break;
}
else if (currLine.StartsWith("#") || currLine == "")
else if (currLine.StartsWith('#') || currLine == "")
{
continue;
}
else if (currLine.StartsWith("}"))
else if (currLine.StartsWith('}'))
{
jsonString.Remove(jsonString.Length - 3, 1);
jsonString.AppendLine("},");
}
else
{
int equalIndex = currLine.IndexOf("=");
int equalIndex = currLine.IndexOf('=');
if (equalIndex >= 0)
{
string key = currLine[..equalIndex].Trim();
if (!key.StartsWith("\""))
if (!key.StartsWith('\"'))
{
key = "\"" + key + "\"";
}
Expand All @@ -398,11 +398,11 @@ public static string TfvarToJson(string hclString)
{
value += "[";
currLine = stringReader.ReadLine();
while (!currLine.StartsWith("}"))
while (!currLine.StartsWith('}'))
{
equalIndex = currLine.IndexOf("=");
equalIndex = currLine.IndexOf('=');
var tagKey = currLine[..equalIndex].Trim();
if (!tagKey.StartsWith("\""))
if (!tagKey.StartsWith('\"'))
{
tagKey = "\"" + tagKey + "\"";
}
Expand All @@ -415,45 +415,45 @@ public static string TfvarToJson(string hclString)
value = value.Trim(',');
value += "],";
}
else if (key.ToLower() == "\"network_address_space\"")
{
value = currLine[(equalIndex + 1)..].Trim();
if (!value.StartsWith('['))
{
value += ",";
}
else
{
string fixedValue = value.Replace('[', ' ').Replace(']', ' ');
value = fixedValue.Trim() + ",";
}
//else if (key.ToLower() == "\"network_address_space\"")
//{
// value = currLine[(equalIndex + 1)..].Trim();
// if (!value.StartsWith('['))
// {
// value += ",";
// }
// else
// {
// string fixedValue = value.Replace('[', ' ').Replace(']', ' ');
// value = fixedValue.Trim() + ",";
// }

}
//}
else if (key.EndsWith("configuration_settings\""))
{
value += "[";
currLine = stringReader.ReadLine();
while (!currLine.StartsWith("}"))
currLine = stringReader.ReadLine().Trim();
while (!currLine.StartsWith('}'))
{
equalIndex = currLine.IndexOf("=");
equalIndex = currLine.IndexOf('=');
var tagKey = currLine[..equalIndex].Trim();
if (!tagKey.StartsWith("\""))
if (!tagKey.StartsWith('\"'))
{
tagKey = "\"" + tagKey + "\"";
}
var tagValue = currLine[(equalIndex + 1)..].Trim();
value += "{";
value += "\"Key\":" + tagKey + "," + "\"Value\":" + tagValue.Trim(',');
value += "},";
currLine = stringReader.ReadLine();
currLine = stringReader.ReadLine().Trim();
}
value = value.Trim(',');
value += "],";
}
else
{
value = currLine[(equalIndex + 1)..].Trim();
if (!value.EndsWith(",") && !value.EndsWith("{"))
if (!value.EndsWith(',') && !value.EndsWith('{'))
{
value += ",";
}
Expand Down
51 changes: 49 additions & 2 deletions Webapp/SDAF/Controllers/LandscapeController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.Extensions.Configuration;
using Microsoft.Net.Http.Headers;
using Microsoft.TeamFoundation.Common;
using Newtonsoft.Json;
using SDAFWebApp.Models;
using SDAFWebApp.Services;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
Expand Down Expand Up @@ -192,7 +194,18 @@ public async Task<IActionResult> CreateAsync(LandscapeModel landscape)
landscape.Id = Helper.GenerateId(landscape);
DateTime currentDateAndTime = DateTime.Now;
landscape.LastModified = currentDateAndTime.ToShortDateString();
landscape.subscription_id = landscape.subscription.Replace("/subscriptions/", "");
if (!landscape.subscription.IsNullOrEmpty())
{
landscape.subscription_id = landscape.subscription.Replace("/subscriptions/", "");
}

if (landscape.custom_random_id.IsNullOrEmpty())
{
string chars = "ABCDEF0123456789";
var random = new Random();
landscape.custom_random_id = new string(Enumerable.Range(0, 3)
.Select(_ => chars[random.Next(chars.Length)]).ToArray());
}

await _landscapeService.CreateAsync(new LandscapeEntity(landscape));
TempData["success"] = "Successfully created workload zone " + landscape.Id;
Expand Down Expand Up @@ -247,7 +260,18 @@ public async Task<RedirectToActionResult> DeployConfirmedAsync(string id, string
LandscapeModel landscape = await GetById(id, partitionKey);

string path = $"/LANDSCAPE/{id}/{id}.tfvars";
landscape.subscription_id = landscape.subscription.Replace("/subscriptions/", "");
if (!landscape.subscription.IsNullOrEmpty())
{
landscape.subscription_id = landscape.subscription.Replace("/subscriptions/", "");
}
if (landscape.custom_random_id.IsNullOrEmpty())
{
string chars = "ABCDEF0123456789";
var random = new Random();
landscape.custom_random_id = new string(Enumerable.Range(0, 3)
.Select(_ => chars[random.Next(chars.Length)]).ToArray());
}

string content = Helper.ConvertToTerraform(landscape);

await restHelper.UpdateRepo(path, content);
Expand Down Expand Up @@ -342,6 +366,18 @@ public async Task<IActionResult> EditAsync(LandscapeModel landscape)
if (newId != landscape.Id)
{
landscape.Id = newId;
if (!landscape.subscription.IsNullOrEmpty())
{
landscape.subscription_id = landscape.subscription.Replace("/subscriptions/", "");
}
if (landscape.custom_random_id.IsNullOrEmpty())
{
string chars = "ABCDEF0123456789";
var random = new Random();
landscape.custom_random_id = new string(Enumerable.Range(0, 3)
.Select(_ => chars[random.Next(chars.Length)]).ToArray());
}

await SubmitNewAsync(landscape);
string id = landscape.Id;
string path = $"/LANDSCAPE/{id}/{id}.tfvars";
Expand Down Expand Up @@ -369,6 +405,17 @@ public async Task<IActionResult> EditAsync(LandscapeModel landscape)
}
DateTime currentDateAndTime = DateTime.Now;
landscape.LastModified = currentDateAndTime.ToShortDateString();
if (!landscape.subscription.IsNullOrEmpty())
{
landscape.subscription_id = landscape.subscription.Replace("/subscriptions/", "");
}
if (landscape.custom_random_id.IsNullOrEmpty())
{
string chars = "ABCDEF0123456789";
var random = new Random();
landscape.custom_random_id = new string(Enumerable.Range(0, 3)
.Select(_ => chars[random.Next(chars.Length)]).ToArray());
}

await _landscapeService.UpdateAsync(new LandscapeEntity(landscape));
TempData["success"] = "Successfully updated workload zone " + landscape.Id;
Expand Down
5 changes: 4 additions & 1 deletion Webapp/SDAF/Controllers/RestHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,10 @@ public async Task UpdateVariableGroup(EnvironmentModel environment, string newNa
dynamicVariables.ARM_CLIENT_SECRET = JToken.FromObject(environment.variables.ARM_CLIENT_SECRET);
dynamicVariables.ARM_TENANT_ID = JToken.FromObject(environment.variables.ARM_TENANT_ID);
dynamicVariables.ARM_SUBSCRIPTION_ID = JToken.FromObject(environment.variables.ARM_SUBSCRIPTION_ID);
dynamicVariables.sap_fqdn = JToken.FromObject(environment.variables.sap_fqdn);
dynamicVariables.APPLICATION_CONFIGURATION_NAME = JToken.FromObject(environment.variables.APPLICATION_CONFIGURATION_NAME);
dynamicVariables.TERRAFORM_REMOTE_STORAGE_ACCOUNT_NAME = JToken.FromObject(environment.variables.TERRAFORM_REMOTE_STORAGE_ACCOUNT_NAME);
dynamicVariables.DEPLOYER_KEYVAULT = JToken.FromObject(environment.variables.DEPLOYER_KEYVAULT);
dynamicVariables.CONTROL_PLANE_NAME = JToken.FromObject(environment.variables.CONTROL_PLANE_NAME);
dynamicVariables.POOL = JToken.FromObject(environment.variables.POOL);

dynamicEnvironment.variables = dynamicVariables;
Expand Down
58 changes: 53 additions & 5 deletions Webapp/SDAF/Controllers/SystemController.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using SDAFWebApp.Models;
using SDAFWebApp.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Net.Http.Headers;
using Microsoft.TeamFoundation.Common;
using Newtonsoft.Json;
using SDAFWebApp.Models;
using SDAFWebApp.Services;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
Expand Down Expand Up @@ -202,7 +204,20 @@ public async Task<IActionResult> CreateAsync(SystemModel system)
system.Id = Helper.GenerateId(system);
DateTime currentDateAndTime = DateTime.Now;
system.LastModified = currentDateAndTime.ToShortDateString();
system.subscription_id = system.subscription.Replace("/subscriptions/","");

if (!system.subscription.IsNullOrEmpty())
{
system.subscription_id = system.subscription.Replace("/subscriptions/", "");
}
if (system.custom_random_id.IsNullOrEmpty())
{
string chars = "ABCDEF0123456789";
var random = new Random();
system.custom_random_id = new string(Enumerable.Range(0, 3)
.Select(_ => chars[random.Next(chars.Length)]).ToArray());
}


SystemEntity systemEntity = new(system);
await _systemService.CreateAsync(systemEntity);
TempData["success"] = "Successfully created system " + system.Id;
Expand Down Expand Up @@ -287,7 +302,17 @@ public async Task<RedirectToActionResult> DeployConfirmedAsync(string id, string
}

string path = $"/SYSTEM/{id}/{id}.tfvars";
system.subscription_id = system.subscription.Replace("/subscriptions/", "");
if (!system.subscription.IsNullOrEmpty())
{
system.subscription_id = system.subscription.Replace("/subscriptions/", "");
}
if (system.custom_random_id.IsNullOrEmpty())
{
string chars = "ABCDEF0123456789";
var random = new Random();
system.custom_random_id = new string(Enumerable.Range(0, 3)
.Select(_ => chars[random.Next(chars.Length)]).ToArray());
}
string content = Helper.ConvertToTerraform(system);

await restHelper.UpdateRepo(path, content);
Expand Down Expand Up @@ -449,7 +474,18 @@ public async Task<IActionResult> EditAsync(SystemModel system)
system.Description = system.database_platform + " distributed system on " + system.scs_server_image.publisher + " " + system.scs_server_image.offer + " " + system.scs_server_image.sku;
}
}
system.subscription_id = system.subscription.Replace("/subscriptions/", "");
if (!system.subscription.IsNullOrEmpty())
{
system.subscription_id = system.subscription.Replace("/subscriptions/", "");
}
if (system.custom_random_id.IsNullOrEmpty())
{
string chars = "ABCDEF0123456789";
var random = new Random();
system.custom_random_id = new string(Enumerable.Range(0, 3)
.Select(_ => chars[random.Next(chars.Length)]).ToArray());
}

await SubmitNewAsync(system);
string id = system.Id;
string path = $"/SYSTEM/{id}/{id}.tfvars";
Expand Down Expand Up @@ -487,6 +523,18 @@ public async Task<IActionResult> EditAsync(SystemModel system)
system.Description = system.database_platform + " distributed system on " + system.scs_server_image.publisher + " " + system.scs_server_image.offer + " " + system.scs_server_image.sku;
}
}
if (!system.subscription.IsNullOrEmpty())
{
system.subscription_id = system.subscription.Replace("/subscriptions/", "");
}
if (system.custom_random_id.IsNullOrEmpty())
{
string chars = "ABCDEF0123456789";
var random = new Random();
system.custom_random_id = new string(Enumerable.Range(0, 3)
.Select(_ => chars[random.Next(chars.Length)]).ToArray());
}

DateTime currentDateAndTime = DateTime.Now;
system.LastModified = currentDateAndTime.ToShortDateString();
await _systemService.UpdateAsync(new SystemEntity(system));
Expand Down
32 changes: 28 additions & 4 deletions Webapp/SDAF/Models/CustomValidators.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,30 @@ public override bool IsValid(object value)
}
private static bool RegexValidation(object value, string pattern)
{
if (value == null || Regex.IsMatch((string)value, pattern)) return true;
else return false;
if(value == null) return true; // Allow null values to pass validation

bool isArray = value.GetType().IsArray;
bool returnValue = true;
if (isArray)
{
string[] arr = value as string[];
foreach (string v in arr)
{
if (!Regex.IsMatch(v, pattern))
{
returnValue = false;
}
}
}
else
{
if (!Regex.IsMatch((string)value, pattern))
{
returnValue = false;
}

}
return returnValue;
}
public class AddressPrefixValidator : ValidationAttribute
{
Expand Down Expand Up @@ -344,10 +366,12 @@ protected override ValidationResult IsValid(object value, ValidationContext cont
bool isDefault = (bool)context.ObjectInstance.GetType().GetProperty("IsDefault").GetValue(context.ObjectInstance);
if (isDefault) return ValidationResult.Success;

string prefix = (string)value;
// Safe cast using 'as'
string[] arr = value as string[];

string armId = (string)context.ObjectInstance.GetType().GetProperty("network_arm_id").GetValue(context.ObjectInstance);

if (prefix == null && armId == null)
if (arr.All(string.IsNullOrWhiteSpace) && armId == null)
{
return new ValidationResult($"At least one of network_address_space or network_arm_id must be present.");
}
Expand Down
Loading