diff --git a/sdk/provisioning/Azure.Provisioning/Azure.Provisioning.sln b/sdk/provisioning/Azure.Provisioning/Azure.Provisioning.sln index dfcd7b45d199d..4ae7ebb0e78ff 100644 --- a/sdk/provisioning/Azure.Provisioning/Azure.Provisioning.sln +++ b/sdk/provisioning/Azure.Provisioning/Azure.Provisioning.sln @@ -7,6 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Provisioning", "src\A EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Provisioning.Tests", "tests\Azure.Provisioning.Tests.csproj", "{BC884FD9-0973-4FD2-A112-F285F041A3B2}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Core.TestFramework", "..\..\core\Azure.Core.TestFramework\src\Azure.Core.TestFramework.csproj", "{A93F6964-45B3-4F08-BB85-EBC3BAC40B72}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,6 +23,10 @@ Global {BC884FD9-0973-4FD2-A112-F285F041A3B2}.Debug|Any CPU.Build.0 = Debug|Any CPU {BC884FD9-0973-4FD2-A112-F285F041A3B2}.Release|Any CPU.ActiveCfg = Release|Any CPU {BC884FD9-0973-4FD2-A112-F285F041A3B2}.Release|Any CPU.Build.0 = Release|Any CPU + {A93F6964-45B3-4F08-BB85-EBC3BAC40B72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A93F6964-45B3-4F08-BB85-EBC3BAC40B72}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A93F6964-45B3-4F08-BB85-EBC3BAC40B72}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A93F6964-45B3-4F08-BB85-EBC3BAC40B72}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/sdk/provisioning/Azure.Provisioning/api/Azure.Provisioning.net6.0.cs b/sdk/provisioning/Azure.Provisioning/api/Azure.Provisioning.net6.0.cs index 050e917cc1a5f..d8cd9d9097b9b 100644 --- a/sdk/provisioning/Azure.Provisioning/api/Azure.Provisioning.net6.0.cs +++ b/sdk/provisioning/Azure.Provisioning/api/Azure.Provisioning.net6.0.cs @@ -7,7 +7,7 @@ public static partial class CdkExtensions } public abstract partial class Construct : Azure.Provisioning.IConstruct, System.ClientModel.Primitives.IPersistableModel { - protected Construct(Azure.Provisioning.IConstruct? scope, string name, Azure.Provisioning.ConstructScope constructScope = Azure.Provisioning.ConstructScope.ResourceGroup, System.Guid? tenantId = default(System.Guid?), System.Guid? subscriptionId = default(System.Guid?), string? envName = null) { } + protected Construct(Azure.Provisioning.IConstruct? scope, string name, Azure.Provisioning.ConstructScope constructScope = Azure.Provisioning.ConstructScope.ResourceGroup, System.Guid? tenantId = default(System.Guid?), System.Guid? subscriptionId = default(System.Guid?), string? envName = null, Azure.Provisioning.ResourceManager.ResourceGroup? resourceGroup = null) { } public Azure.Provisioning.ConstructScope ConstructScope { get { throw null; } } public string EnvironmentName { get { throw null; } } public string Name { get { throw null; } } @@ -55,12 +55,12 @@ public partial interface IConstruct } public abstract partial class Infrastructure : Azure.Provisioning.Construct { - public Infrastructure(Azure.Provisioning.ConstructScope constructScope = Azure.Provisioning.ConstructScope.Subscription, System.Guid? tenantId = default(System.Guid?), System.Guid? subscriptionId = default(System.Guid?), string? envName = null) : base (default(Azure.Provisioning.IConstruct), default(string), default(Azure.Provisioning.ConstructScope), default(System.Guid?), default(System.Guid?), default(string)) { } + public Infrastructure(Azure.Provisioning.ConstructScope constructScope = Azure.Provisioning.ConstructScope.Subscription, System.Guid? tenantId = default(System.Guid?), System.Guid? subscriptionId = default(System.Guid?), string? envName = null) : base (default(Azure.Provisioning.IConstruct), default(string), default(Azure.Provisioning.ConstructScope), default(System.Guid?), default(System.Guid?), default(string), default(Azure.Provisioning.ResourceManager.ResourceGroup)) { } public void Build(string? outputPath = null) { } } public partial class Output { - public Output(string name, string value, Azure.Provisioning.IConstruct source, bool isLiteral = false, bool isSecure = false) { } + internal Output() { } public bool IsLiteral { get { throw null; } } public bool IsSecure { get { throw null; } } public string Name { get { throw null; } } @@ -71,6 +71,7 @@ public readonly partial struct Parameter { private readonly object _dummy; private readonly int _dummyPrimitive; + public Parameter(Azure.Provisioning.Output output) { throw null; } public Parameter(string name, string? description = null, object? defaultValue = null, bool isSecure = false) { throw null; } public object? DefaultValue { get { throw null; } } public string? Description { get { throw null; } } @@ -82,7 +83,6 @@ public abstract partial class Resource : System.ClientModel.Primitives.IPersista protected Resource(Azure.Provisioning.IConstruct scope, Azure.Provisioning.Resource? parent, string resourceName, Azure.Core.ResourceType resourceType, string version, System.Func createProperties) { } public Azure.Core.ResourceIdentifier Id { get { throw null; } } public string Name { get { throw null; } } - public System.Collections.Generic.IList Parameters { get { throw null; } } public Azure.Provisioning.Resource? Parent { get { throw null; } } public Azure.Provisioning.IConstruct Scope { get { throw null; } } public string Version { get { throw null; } } @@ -116,7 +116,7 @@ namespace Azure.Provisioning.AppService { public partial class AppServicePlan : Azure.Provisioning.Resource { - public AppServicePlan(Azure.Provisioning.IConstruct scope, string resourceName, string version = "2021-02-01", Azure.Core.AzureLocation? location = default(Azure.Core.AzureLocation?)) : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func)) { } + public AppServicePlan(Azure.Provisioning.IConstruct scope, string resourceName, string version = "2021-02-01", Azure.Core.AzureLocation? location = default(Azure.Core.AzureLocation?), Azure.Provisioning.ResourceManager.ResourceGroup? parent = null) : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func)) { } protected override Azure.Provisioning.Resource? FindParentInScope(Azure.Provisioning.IConstruct scope) { throw null; } } public static partial class AppServicesExtensions @@ -125,7 +125,7 @@ public static partial class AppServicesExtensions } public partial class WebSite : Azure.Provisioning.Resource { - public WebSite(Azure.Provisioning.IConstruct scope, string resourceName, Azure.Provisioning.AppService.AppServicePlan appServicePlan, Azure.Provisioning.AppService.WebSiteRuntime runtime, string runtimeVersion, string version = "2021-02-01", Azure.Core.AzureLocation? location = default(Azure.Core.AzureLocation?)) : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func)) { } + public WebSite(Azure.Provisioning.IConstruct scope, string resourceName, Azure.Provisioning.AppService.AppServicePlan appServicePlan, Azure.Provisioning.AppService.WebSiteRuntime runtime, string runtimeVersion, string version = "2021-02-01", Azure.Core.AzureLocation? location = default(Azure.Core.AzureLocation?), Azure.Provisioning.ResourceManager.ResourceGroup? parent = null) : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func)) { } public void AddApplicationSetting(string key, Azure.Provisioning.Parameter value) { } public void AddApplicationSetting(string key, string value) { } public void AddLogConfig(string resourceName) { } @@ -150,13 +150,13 @@ namespace Azure.Provisioning.KeyVaults { public partial class KeyVault : Azure.Provisioning.Resource { - public KeyVault(Azure.Provisioning.IConstruct scope, string name = "kv", string version = "2023-02-01", Azure.Core.AzureLocation? location = default(Azure.Core.AzureLocation?)) : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func)) { } + public KeyVault(Azure.Provisioning.IConstruct scope, string name = "kv", string version = "2023-02-01", Azure.Core.AzureLocation? location = default(Azure.Core.AzureLocation?), Azure.Provisioning.ResourceManager.ResourceGroup? resourceGroup = null) : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func)) { } public void AddAccessPolicy(Azure.Provisioning.Output output) { } protected override Azure.Provisioning.Resource? FindParentInScope(Azure.Provisioning.IConstruct scope) { throw null; } } public static partial class KeyVaultExtensions { - public static Azure.Provisioning.KeyVaults.KeyVault AddKeyVault(this Azure.Provisioning.IConstruct construct, Azure.Provisioning.ResourceManager.ResourceGroup? parent = null, string name = "kv") { throw null; } + public static Azure.Provisioning.KeyVaults.KeyVault AddKeyVault(this Azure.Provisioning.IConstruct construct, Azure.Provisioning.ResourceManager.ResourceGroup? resourceGroup = null, string name = "kv") { throw null; } public static System.Collections.Generic.IEnumerable GetSecrets(this Azure.Provisioning.IConstruct construct) { throw null; } } public partial class KeyVaultSecret : Azure.Provisioning.Resource @@ -170,7 +170,7 @@ namespace Azure.Provisioning.ResourceManager { public partial class ResourceGroup : Azure.Provisioning.Resource { - public ResourceGroup(Azure.Provisioning.IConstruct scope, string name = "rg", string version = "2023-07-01", Azure.Core.AzureLocation? location = default(Azure.Core.AzureLocation?)) : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func)) { } + public ResourceGroup(Azure.Provisioning.IConstruct scope, string name = "rg", string version = "2023-07-01", Azure.Core.AzureLocation? location = default(Azure.Core.AzureLocation?), Azure.Provisioning.ResourceManager.Subscription? parent = null) : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func)) { } protected override Azure.Provisioning.Resource? FindParentInScope(Azure.Provisioning.IConstruct scope) { throw null; } } public static partial class ResourceManagerExtensions diff --git a/sdk/provisioning/Azure.Provisioning/api/Azure.Provisioning.netstandard2.0.cs b/sdk/provisioning/Azure.Provisioning/api/Azure.Provisioning.netstandard2.0.cs index 050e917cc1a5f..d8cd9d9097b9b 100644 --- a/sdk/provisioning/Azure.Provisioning/api/Azure.Provisioning.netstandard2.0.cs +++ b/sdk/provisioning/Azure.Provisioning/api/Azure.Provisioning.netstandard2.0.cs @@ -7,7 +7,7 @@ public static partial class CdkExtensions } public abstract partial class Construct : Azure.Provisioning.IConstruct, System.ClientModel.Primitives.IPersistableModel { - protected Construct(Azure.Provisioning.IConstruct? scope, string name, Azure.Provisioning.ConstructScope constructScope = Azure.Provisioning.ConstructScope.ResourceGroup, System.Guid? tenantId = default(System.Guid?), System.Guid? subscriptionId = default(System.Guid?), string? envName = null) { } + protected Construct(Azure.Provisioning.IConstruct? scope, string name, Azure.Provisioning.ConstructScope constructScope = Azure.Provisioning.ConstructScope.ResourceGroup, System.Guid? tenantId = default(System.Guid?), System.Guid? subscriptionId = default(System.Guid?), string? envName = null, Azure.Provisioning.ResourceManager.ResourceGroup? resourceGroup = null) { } public Azure.Provisioning.ConstructScope ConstructScope { get { throw null; } } public string EnvironmentName { get { throw null; } } public string Name { get { throw null; } } @@ -55,12 +55,12 @@ public partial interface IConstruct } public abstract partial class Infrastructure : Azure.Provisioning.Construct { - public Infrastructure(Azure.Provisioning.ConstructScope constructScope = Azure.Provisioning.ConstructScope.Subscription, System.Guid? tenantId = default(System.Guid?), System.Guid? subscriptionId = default(System.Guid?), string? envName = null) : base (default(Azure.Provisioning.IConstruct), default(string), default(Azure.Provisioning.ConstructScope), default(System.Guid?), default(System.Guid?), default(string)) { } + public Infrastructure(Azure.Provisioning.ConstructScope constructScope = Azure.Provisioning.ConstructScope.Subscription, System.Guid? tenantId = default(System.Guid?), System.Guid? subscriptionId = default(System.Guid?), string? envName = null) : base (default(Azure.Provisioning.IConstruct), default(string), default(Azure.Provisioning.ConstructScope), default(System.Guid?), default(System.Guid?), default(string), default(Azure.Provisioning.ResourceManager.ResourceGroup)) { } public void Build(string? outputPath = null) { } } public partial class Output { - public Output(string name, string value, Azure.Provisioning.IConstruct source, bool isLiteral = false, bool isSecure = false) { } + internal Output() { } public bool IsLiteral { get { throw null; } } public bool IsSecure { get { throw null; } } public string Name { get { throw null; } } @@ -71,6 +71,7 @@ public readonly partial struct Parameter { private readonly object _dummy; private readonly int _dummyPrimitive; + public Parameter(Azure.Provisioning.Output output) { throw null; } public Parameter(string name, string? description = null, object? defaultValue = null, bool isSecure = false) { throw null; } public object? DefaultValue { get { throw null; } } public string? Description { get { throw null; } } @@ -82,7 +83,6 @@ public abstract partial class Resource : System.ClientModel.Primitives.IPersista protected Resource(Azure.Provisioning.IConstruct scope, Azure.Provisioning.Resource? parent, string resourceName, Azure.Core.ResourceType resourceType, string version, System.Func createProperties) { } public Azure.Core.ResourceIdentifier Id { get { throw null; } } public string Name { get { throw null; } } - public System.Collections.Generic.IList Parameters { get { throw null; } } public Azure.Provisioning.Resource? Parent { get { throw null; } } public Azure.Provisioning.IConstruct Scope { get { throw null; } } public string Version { get { throw null; } } @@ -116,7 +116,7 @@ namespace Azure.Provisioning.AppService { public partial class AppServicePlan : Azure.Provisioning.Resource { - public AppServicePlan(Azure.Provisioning.IConstruct scope, string resourceName, string version = "2021-02-01", Azure.Core.AzureLocation? location = default(Azure.Core.AzureLocation?)) : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func)) { } + public AppServicePlan(Azure.Provisioning.IConstruct scope, string resourceName, string version = "2021-02-01", Azure.Core.AzureLocation? location = default(Azure.Core.AzureLocation?), Azure.Provisioning.ResourceManager.ResourceGroup? parent = null) : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func)) { } protected override Azure.Provisioning.Resource? FindParentInScope(Azure.Provisioning.IConstruct scope) { throw null; } } public static partial class AppServicesExtensions @@ -125,7 +125,7 @@ public static partial class AppServicesExtensions } public partial class WebSite : Azure.Provisioning.Resource { - public WebSite(Azure.Provisioning.IConstruct scope, string resourceName, Azure.Provisioning.AppService.AppServicePlan appServicePlan, Azure.Provisioning.AppService.WebSiteRuntime runtime, string runtimeVersion, string version = "2021-02-01", Azure.Core.AzureLocation? location = default(Azure.Core.AzureLocation?)) : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func)) { } + public WebSite(Azure.Provisioning.IConstruct scope, string resourceName, Azure.Provisioning.AppService.AppServicePlan appServicePlan, Azure.Provisioning.AppService.WebSiteRuntime runtime, string runtimeVersion, string version = "2021-02-01", Azure.Core.AzureLocation? location = default(Azure.Core.AzureLocation?), Azure.Provisioning.ResourceManager.ResourceGroup? parent = null) : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func)) { } public void AddApplicationSetting(string key, Azure.Provisioning.Parameter value) { } public void AddApplicationSetting(string key, string value) { } public void AddLogConfig(string resourceName) { } @@ -150,13 +150,13 @@ namespace Azure.Provisioning.KeyVaults { public partial class KeyVault : Azure.Provisioning.Resource { - public KeyVault(Azure.Provisioning.IConstruct scope, string name = "kv", string version = "2023-02-01", Azure.Core.AzureLocation? location = default(Azure.Core.AzureLocation?)) : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func)) { } + public KeyVault(Azure.Provisioning.IConstruct scope, string name = "kv", string version = "2023-02-01", Azure.Core.AzureLocation? location = default(Azure.Core.AzureLocation?), Azure.Provisioning.ResourceManager.ResourceGroup? resourceGroup = null) : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func)) { } public void AddAccessPolicy(Azure.Provisioning.Output output) { } protected override Azure.Provisioning.Resource? FindParentInScope(Azure.Provisioning.IConstruct scope) { throw null; } } public static partial class KeyVaultExtensions { - public static Azure.Provisioning.KeyVaults.KeyVault AddKeyVault(this Azure.Provisioning.IConstruct construct, Azure.Provisioning.ResourceManager.ResourceGroup? parent = null, string name = "kv") { throw null; } + public static Azure.Provisioning.KeyVaults.KeyVault AddKeyVault(this Azure.Provisioning.IConstruct construct, Azure.Provisioning.ResourceManager.ResourceGroup? resourceGroup = null, string name = "kv") { throw null; } public static System.Collections.Generic.IEnumerable GetSecrets(this Azure.Provisioning.IConstruct construct) { throw null; } } public partial class KeyVaultSecret : Azure.Provisioning.Resource @@ -170,7 +170,7 @@ namespace Azure.Provisioning.ResourceManager { public partial class ResourceGroup : Azure.Provisioning.Resource { - public ResourceGroup(Azure.Provisioning.IConstruct scope, string name = "rg", string version = "2023-07-01", Azure.Core.AzureLocation? location = default(Azure.Core.AzureLocation?)) : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func)) { } + public ResourceGroup(Azure.Provisioning.IConstruct scope, string name = "rg", string version = "2023-07-01", Azure.Core.AzureLocation? location = default(Azure.Core.AzureLocation?), Azure.Provisioning.ResourceManager.Subscription? parent = null) : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func)) { } protected override Azure.Provisioning.Resource? FindParentInScope(Azure.Provisioning.IConstruct scope) { throw null; } } public static partial class ResourceManagerExtensions diff --git a/sdk/provisioning/Azure.Provisioning/src/Construct.cs b/sdk/provisioning/Azure.Provisioning/src/Construct.cs index b1130a312585c..7a5f2be994cae 100644 --- a/sdk/provisioning/Azure.Provisioning/src/Construct.cs +++ b/sdk/provisioning/Azure.Provisioning/src/Construct.cs @@ -7,6 +7,7 @@ using System.IO; using System.Linq; using Azure.Provisioning.ResourceManager; +using Microsoft.Extensions.Azure; namespace Azure.Provisioning { @@ -48,8 +49,23 @@ public abstract class Construct : IConstruct, IPersistableModel /// The tenant id to use. If not passed in will try to load from AZURE_TENANT_ID environment variable. /// The subscription id to use. If not passed in will try to load from AZURE_SUBSCRIPTION_ID environment variable. /// The environment name to use. If not passed in will try to load from AZURE_ENV_NAME environment variable. + /// /// is and is null. - protected Construct(IConstruct? scope, string name, ConstructScope constructScope = ConstructScope.ResourceGroup, Guid? tenantId = null, Guid? subscriptionId = null, string? envName = null) + protected Construct(IConstruct? scope, string name, ConstructScope constructScope = ConstructScope.ResourceGroup, Guid? tenantId = null, Guid? subscriptionId = null, string? envName = null, ResourceGroup? resourceGroup = null) + : this(scope, name, constructScope, tenantId, subscriptionId, envName, null, null, resourceGroup) + { + } + + internal Construct( + IConstruct? scope, + string name, + ConstructScope constructScope, + Guid? tenantId = default, + Guid? subscriptionId = default, + string? envName = default, + Tenant? tenant = default, + Subscription? subscription = default, + ResourceGroup? resourceGroup = default) { if (scope is null && constructScope == ConstructScope.ResourceGroup) { @@ -64,15 +80,15 @@ protected Construct(IConstruct? scope, string name, ConstructScope constructScop _constructs = new List(); _existingResources = new List(); Name = name; - Root = scope?.Root ?? new Tenant(this, tenantId); + Root = tenant ?? scope?.Root ?? new Tenant(this, tenantId); ConstructScope = constructScope; if (constructScope == ConstructScope.ResourceGroup) { - ResourceGroup = scope!.ResourceGroup ?? scope.GetOrAddResourceGroup(); + ResourceGroup = resourceGroup ?? scope!.ResourceGroup ?? scope.GetOrAddResourceGroup(); } if (constructScope == ConstructScope.Subscription) { - Subscription = scope is null ? this.GetOrCreateSubscription(subscriptionId) : scope.Subscription ?? scope.GetOrCreateSubscription(subscriptionId); + Subscription = subscription ?? (scope is null ? this.GetOrCreateSubscription(subscriptionId) : scope.Subscription ?? scope.GetOrCreateSubscription(subscriptionId)); } _environmentName = envName; @@ -103,7 +119,7 @@ public IEnumerable GetResources(bool recursive = true) IEnumerable result = _resources; if (recursive) { - result = result.Concat(GetConstructs(false).SelectMany(c => c.GetResources(false))); + result = result.Concat(GetConstructs(false).SelectMany(c => c.GetResources(true))); } return result; } @@ -114,7 +130,7 @@ public IEnumerable GetConstructs(bool recursive = true) IEnumerable result = _constructs; if (recursive) { - result = result.Concat(GetConstructs(false).SelectMany(c => c.GetConstructs(false))); + result = result.Concat(GetConstructs(false).SelectMany(c => c.GetConstructs(true))); } return result; } @@ -125,7 +141,7 @@ public IEnumerable GetParameters(bool recursive = true) IEnumerable result = _parameters; if (recursive) { - result = result.Concat(GetConstructs(false).SelectMany(c => c.GetParameters(false))); + result = result.Concat(GetConstructs(false).SelectMany(c => c.GetParameters(true))); } return result; } @@ -136,7 +152,7 @@ public IEnumerable GetOutputs(bool recursive = true) IEnumerable result = _outputs; if (recursive) { - result = result.Concat(GetConstructs(false).SelectMany(c => c.GetOutputs(false))); + result = result.Concat(GetConstructs(false).SelectMany(c => c.GetOutputs(true))); } return result; } @@ -167,7 +183,7 @@ public void AddOutput(Output output) private string GetScopeName() { - return ResourceGroup?.Name ?? Subscription?.Name ?? "tenant()"; + return ResourceGroup?.Name ?? (Subscription != null ? $"subscription('{Subscription.Name}')" : "tenant()"); } private BinaryData SerializeModuleReference(ModelReaderWriterOptions options) @@ -178,18 +194,21 @@ private BinaryData SerializeModuleReference(ModelReaderWriterOptions options) stream.WriteLine($" scope: {GetScopeName()}"); var parametersToWrite = new HashSet(); - GetAllParametersRecursive(this, parametersToWrite, false); - if (parametersToWrite.Count() > 0) + var outputs = new HashSet(GetOutputs()); + foreach (var p in GetParameters(false)) + { + if (!ShouldExposeParameter(p, outputs)) + { + continue; + } + parametersToWrite.Add(p); + } + if (parametersToWrite.Count > 0) { stream.WriteLine($" params: {{"); foreach (var parameter in parametersToWrite) { - var value = parameter.IsFromOutput - ? parameter.IsLiteral - ? $"'{parameter.Value}'" - : parameter.Value - : parameter.Name; - stream.WriteLine($" {parameter.Name}: {value}"); + stream.WriteLine($" {parameter.Name}: {parameter.GetParameterString(Scope!)}"); } stream.WriteLine($" }}"); } @@ -244,7 +263,7 @@ private void WriteScopeLine(MemoryStream stream) { if (ConstructScope != ConstructScope.ResourceGroup) { - stream.WriteLine($"targetScope = {ConstructScope.ToString().ToCamelCase()}{Environment.NewLine}"); + stream.WriteLine($"targetScope = '{ConstructScope.ToString().ToCamelCase()}'{Environment.NewLine}"); } } @@ -260,13 +279,13 @@ internal void WriteOutputs(MemoryStream stream) foreach (var output in outputsToWrite) { string value; - if (output.IsLiteral || output.Source.Equals(this)) + if (output.IsLiteral || ReferenceEquals(this, output.ModuleSource)) { value = output.IsLiteral ? $"'{output.Value}'" : output.Value; } else { - value = $"{output.Source.Name}.outputs.{output.Name}"; + value = $"{output.ModuleSource!.Name}.outputs.{output.Name}"; } string name = output.Name; stream.WriteLine($"output {name} string = {value}"); @@ -291,8 +310,13 @@ private void WriteParameters(MemoryStream stream) { var parametersToWrite = new HashSet(); GetAllParametersRecursive(this, parametersToWrite, false); + var outputs = new HashSet(GetOutputs()); foreach (var parameter in parametersToWrite) { + if (!ShouldExposeParameter(parameter, outputs)) + { + continue; + } string defaultValue = parameter.DefaultValue is null ? string.Empty : $" = '{parameter.DefaultValue}'"; if (parameter.IsSecure) @@ -303,6 +327,12 @@ private void WriteParameters(MemoryStream stream) } } + private bool ShouldExposeParameter(Parameter parameter, HashSet outputs) + { + // Don't expose the parameter if the output that was used to create the parameter is already in scope. + return parameter.Output == null || !outputs.Contains(parameter.Output); + } + private void GetAllParametersRecursive(IConstruct construct, HashSet visited, bool isChild) { if (!isChild) diff --git a/sdk/provisioning/Azure.Provisioning/src/Infrastructure.cs b/sdk/provisioning/Azure.Provisioning/src/Infrastructure.cs index c9c49198eea9c..6b26702e18cde 100644 --- a/sdk/provisioning/Azure.Provisioning/src/Infrastructure.cs +++ b/sdk/provisioning/Azure.Provisioning/src/Infrastructure.cs @@ -2,9 +2,6 @@ // Licensed under the MIT License. using System; -using System.ClientModel.Primitives; -using System.Collections.Generic; -using System.IO; namespace Azure.Provisioning { @@ -23,7 +20,7 @@ public abstract class Infrastructure : Construct /// The subscription id to use. If not passed in will try to load from AZURE_SUBSCRIPTION_ID environment variable. /// The environment name to use. If not passed in will try to load from AZURE_ENV_NAME environment variable. public Infrastructure(ConstructScope constructScope = ConstructScope.Subscription, Guid? tenantId = null, Guid? subscriptionId = null, string? envName = null) - : base(null, "default", constructScope, tenantId, subscriptionId, envName ?? Environment.GetEnvironmentVariable("AZURE_ENV_NAME") ?? throw new Exception("No environment variable found named 'AZURE_ENV_NAME'")) + : base(null, "default", constructScope, tenantId, subscriptionId, envName ?? Environment.GetEnvironmentVariable("AZURE_ENV_NAME") ?? throw new Exception("No environment variable found named 'AZURE_ENV_NAME'"), resourceGroup: null) { } @@ -33,46 +30,9 @@ public Infrastructure(ConstructScope constructScope = ConstructScope.Subscriptio /// Path to put the files. public void Build(string? outputPath = null) { - outputPath ??= $".\\{GetType().Name}"; - outputPath = Path.GetFullPath(outputPath); + var moduleInfrastructure = new ModuleInfrastructure(this); - WriteBicepFile(this, outputPath); - - var queue = new Queue(); - queue.Enqueue(this); - WriteConstructsByLevel(queue, outputPath); - } - - private void WriteConstructsByLevel(Queue constructs, string outputPath) - { - while (constructs.Count > 0) - { - var construct = constructs.Dequeue(); - foreach (var child in construct.GetConstructs(false)) - { - constructs.Enqueue(child); - } - WriteBicepFile(construct, outputPath); - } - } - - private string GetFilePath(IConstruct construct, string outputPath) - { - string fileName = object.ReferenceEquals(construct, this) ? Path.Combine(outputPath, "main.bicep") : Path.Combine(outputPath, "resources", construct.Name, $"{construct.Name}.bicep"); - Directory.CreateDirectory(Path.GetDirectoryName(fileName)!); - return fileName; - } - - private void WriteBicepFile(IConstruct construct, string outputPath) - { - using var stream = new FileStream(GetFilePath(construct, outputPath), FileMode.Create); -#if NET6_0_OR_GREATER - stream.Write(ModelReaderWriter.Write(construct, new ModelReaderWriterOptions("bicep"))); -#else - BinaryData data = ModelReaderWriter.Write(construct, new ModelReaderWriterOptions("bicep")); - var buffer = data.ToArray(); - stream.Write(buffer, 0, buffer.Length); -#endif + moduleInfrastructure.Write(outputPath); } } } diff --git a/sdk/provisioning/Azure.Provisioning/src/ModuleConstruct.cs b/sdk/provisioning/Azure.Provisioning/src/ModuleConstruct.cs new file mode 100644 index 0000000000000..d7a962e6af3ae --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning/src/ModuleConstruct.cs @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Azure.Provisioning.ResourceManager; + +namespace Azure.Provisioning +{ + internal class ModuleConstruct : Construct + { + public ModuleConstruct(ModuleResource resource) + : base( + resource.Scope, + resource.Resource is Subscription ? resource.Resource.Name : resource.Resource.Id.Name.Replace('-', '_'), + ResourceToConstructScope(resource.Resource), + tenant: GetTenant(resource.Resource), + subscription: GetSubscription(resource.Resource), + resourceGroup: resource.Resource as ResourceGroup) + { + } + + public bool IsRoot { get; set; } + + private static Tenant? GetTenant(Resource resource) + { + return resource switch + { + Tenant tenant => tenant, + Subscription sub => (Tenant) sub.Parent!, + ResourceGroup rg => (Tenant) rg.Parent!.Parent!, + _ => null, + }; + } + + private static Subscription? GetSubscription(Resource resource) + { + return resource switch + { + Subscription subscription => subscription, + ResourceGroup rg => (Subscription) rg.Parent!, + _ => null, + }; + } + + private static ConstructScope ResourceToConstructScope(Resource resource) + { + return resource switch + { + Tenant => ConstructScope.Tenant, + ResourceManager.Subscription => ConstructScope.Subscription, + //TODO managementgroup support + ResourceManager.ResourceGroup => ConstructScope.ResourceGroup, + _ => throw new InvalidOperationException(), + }; + } + } +} diff --git a/sdk/provisioning/Azure.Provisioning/src/ModuleInfrastructure.cs b/sdk/provisioning/Azure.Provisioning/src/ModuleInfrastructure.cs new file mode 100644 index 0000000000000..4f50bbe45ad26 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning/src/ModuleInfrastructure.cs @@ -0,0 +1,197 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Azure.Provisioning.ResourceManager; + +namespace Azure.Provisioning +{ + internal class ModuleInfrastructure + { + private readonly Infrastructure _infrastructure; + private readonly ModuleConstruct _rootConstruct; + + public ModuleInfrastructure(Infrastructure infrastructure) + { + _infrastructure = infrastructure; + Dictionary> resourceTree = BuildResourceTree(); + + ModuleConstruct? root = null; + BuildModuleConstructs(_infrastructure.Root, resourceTree, null, ref root); + _rootConstruct = root!; + + AddOutputsToModules(); + } + + public void Write(string? outputPath = null) + { + outputPath ??= $".\\{GetType().Name}"; + outputPath = Path.GetFullPath(outputPath); + + WriteBicepFile(_rootConstruct, outputPath); + + var queue = new Queue(); + queue.Enqueue(_rootConstruct); + WriteConstructsByLevel(queue, outputPath); + } + + private void AddOutputsToModules() + { + // Get all of the user-defined constructs in addition to the Infrastructure construct + foreach (var construct in _infrastructure.GetConstructs(true).Concat(new[] { _infrastructure })) + { + // ToList to avoid modifying the collection while iterating + foreach (var output in construct.GetOutputs(false).ToList()) + { + output.ModuleSource = output.Resource.ModuleScope!; + output.Resource.ModuleScope!.AddOutput(output); + } + } + } + + private Dictionary> BuildResourceTree() + { + var resources = _infrastructure.GetResources(true); + Dictionary> resourceTree = new(); + HashSet visited = new(); + foreach (var resource in resources) + { + VisitResource(resource, resourceTree, visited); + } + + return resourceTree; + } + + private void VisitResource(Resource resource, Dictionary> resourceTree, HashSet visited) + { + if (!visited.Add(resource)) + { + return; + } + + if (!resourceTree.ContainsKey(resource)) + { + resourceTree[resource] = new List(); + } + + if (resource.Parent != null) + { + if (!resourceTree.ContainsKey(resource.Parent)) + { + resourceTree[resource.Parent] = new List(); + } + resourceTree[resource.Parent].Add(resource); + VisitResource(resource.Parent, resourceTree, visited); + } + } + + private void BuildModuleConstructs(Resource resource, Dictionary> resourceTree, ModuleConstruct? parentScope, ref ModuleConstruct? root) + { + ModuleConstruct? construct = null; + var moduleResource = new ModuleResource(resource, parentScope); + + if (NeedsModuleConstruct(resource, resourceTree)) + { + construct = new ModuleConstruct(moduleResource); + + if (parentScope == null) + { + root = construct; + construct.IsRoot = true; + parentScope = construct; + } + } + + if (parentScope != null) + { + parentScope.AddResource(resource); + resource.ModuleScope = parentScope; + } + + if (parentScope != null) + { + foreach (var parameter in resource.Parameters) + { + parentScope.AddParameter(parameter); + } + + foreach (var typeDictPair in resource.ParameterOverrides) + { + // ToList to avoid modifying the collection while iterating + foreach (var propertyParameterPair in typeDictPair.Value.ToList()) + { + var parameterToCopy = propertyParameterPair.Value; + resource.ParameterOverrides[typeDictPair.Key][propertyParameterPair.Key] = new Parameter( + parameterToCopy.Name, + parameterToCopy.Description, + parameterToCopy.DefaultValue, + parameterToCopy.IsSecure, + parentScope, + parameterToCopy.Value); + } + } + } + + foreach (var child in resourceTree[resource]) + { + BuildModuleConstructs(child, resourceTree, construct ?? parentScope, ref root); + } + } + + private bool NeedsModuleConstruct(Resource resource, Dictionary> resourceTree) + { + if (!(resource is Tenant || resource is Subscription || resource is ResourceGroup)) + { + return false; + } + if (resource is Tenant) + { + // TODO add management group check + return resourceTree[resource].Count > 1; + } + if (resource is Subscription || resource is ResourceGroup) + { + // TODO add policy support + return resourceTree[resource].Count > 0; + } + + return false; + } + + private void WriteConstructsByLevel(Queue constructs, string outputPath) + { + while (constructs.Count > 0) + { + var construct = constructs.Dequeue(); + foreach (var child in construct.GetConstructs(false)) + { + constructs.Enqueue((ModuleConstruct)child); + } + WriteBicepFile(construct, outputPath); + } + } + + private string GetFilePath(ModuleConstruct construct, string outputPath) + { + string fileName = construct.IsRoot ? Path.Combine(outputPath, "main.bicep") : Path.Combine(outputPath, "resources", construct.Name, $"{construct.Name}.bicep"); + Directory.CreateDirectory(Path.GetDirectoryName(fileName)!); + return fileName; + } + + private void WriteBicepFile(ModuleConstruct construct, string outputPath) + { + using var stream = new FileStream(GetFilePath(construct, outputPath), FileMode.Create); +#if NET6_0_OR_GREATER + stream.Write(ModelReaderWriter.Write(construct, new ModelReaderWriterOptions("bicep"))); +#else + BinaryData data = ModelReaderWriter.Write(construct, new ModelReaderWriterOptions("bicep")); + var buffer = data.ToArray(); + stream.Write(buffer, 0, buffer.Length); +#endif + } + } +} diff --git a/sdk/provisioning/Azure.Provisioning/src/ModuleResource.cs b/sdk/provisioning/Azure.Provisioning/src/ModuleResource.cs new file mode 100644 index 0000000000000..0ba71b81d4712 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning/src/ModuleResource.cs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Azure.Provisioning +{ + internal class ModuleResource + { + public Resource Resource { get; } + + public ModuleConstruct? Scope { get; } + + public ModuleResource(Resource resource, ModuleConstruct? scope) + { + Resource = resource; + Scope = scope; + } + } +} diff --git a/sdk/provisioning/Azure.Provisioning/src/Output.cs b/sdk/provisioning/Azure.Provisioning/src/Output.cs index 0ec2ea6fdb751..181090508992b 100644 --- a/sdk/provisioning/Azure.Provisioning/src/Output.cs +++ b/sdk/provisioning/Azure.Provisioning/src/Output.cs @@ -27,6 +27,9 @@ public class Output /// public bool IsSecure { get; } internal IConstruct Source { get; } + internal IConstruct? ModuleSource { get; set; } + + internal Resource Resource { get; } /// /// Initializes a new instance of the . @@ -36,13 +39,15 @@ public class Output /// The output source. /// Is the output a literal value. /// Is the output secure. - public Output(string name, string value, IConstruct source, bool isLiteral = false, bool isSecure = false) + /// + internal Output(string name, string value, IConstruct source, Resource resource, bool isLiteral = false, bool isSecure = false) { Name = name; Value = value; IsLiteral = isLiteral; IsSecure = isSecure; Source = source; + Resource = resource; } } } diff --git a/sdk/provisioning/Azure.Provisioning/src/Parameter.cs b/sdk/provisioning/Azure.Provisioning/src/Parameter.cs index 1ac6491823745..10d197c054973 100644 --- a/sdk/provisioning/Azure.Provisioning/src/Parameter.cs +++ b/sdk/provisioning/Azure.Provisioning/src/Parameter.cs @@ -1,6 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System.Collections.Generic; +using System.Linq; + namespace Azure.Provisioning { /// @@ -30,8 +33,13 @@ public readonly struct Parameter internal bool IsLiteral { get; } internal string? Value { get; } internal IConstruct? Source { get; } + internal Output? Output { get; } - internal Parameter(Output output) + /// + /// + /// + /// + public Parameter(Output output) { Name = output.Name; IsSecure = output.IsSecure; @@ -39,6 +47,17 @@ internal Parameter(Output output) IsLiteral = output.IsLiteral; Value = output.Value; Source = output.Source; + Output = output; + } + + internal Parameter(string name, string? description, object? defaultValue, bool isSecure, IConstruct source, string? value) + { + Name = name; + Description = description; + DefaultValue = defaultValue; + IsSecure = isSecure; + Source = source; + Value = value; } /// @@ -55,5 +74,22 @@ public Parameter(string name, string? description = default, object? defaultValu DefaultValue = defaultValue; IsSecure = isSecure; } + + internal string GetParameterString(IConstruct parentScope) + { + // If the parameter is not from an output, use the parameter name. + if (Output == null) + { + return Name; + } + // If the parameter is an output from the current scope, use its Value. + if (ReferenceEquals(Output!.ModuleSource, parentScope)) + { + return Value!; + } + + // Otherwise it is an output from a different scope, use the full reference. + return $"{Output!.ModuleSource!.Name}.outputs.{Name}"; + } } } diff --git a/sdk/provisioning/Azure.Provisioning/src/Resource.cs b/sdk/provisioning/Azure.Provisioning/src/Resource.cs index 3358f7b94abd6..c6b782cd29bd1 100644 --- a/sdk/provisioning/Azure.Provisioning/src/Resource.cs +++ b/sdk/provisioning/Azure.Provisioning/src/Resource.cs @@ -4,7 +4,9 @@ using System; using System.ClientModel.Primitives; using System.Collections.Generic; +using System.Diagnostics; using System.IO; +using System.Linq; using System.Security.Cryptography; using System.Text; using Azure.Core; @@ -21,7 +23,7 @@ namespace Azure.Provisioning public abstract class Resource : IPersistableModel #pragma warning restore AZC0012 // Avoid single word type names { - internal Dictionary> ParameterOverrides { get; } + internal Dictionary> ParameterOverrides { get; } private IList Dependencies { get; } @@ -57,7 +59,9 @@ internal void AddDependency(Resource resource) /// /// Gets the parameters of the resource. /// - public IList Parameters { get; } + internal IList Parameters { get; } + + internal IConstruct? ModuleScope { get; set; } /// /// Initializes a new instance of the . @@ -76,11 +80,11 @@ protected Resource(IConstruct scope, Resource? parent, string resourceName, Reso var azureName = GetAzureName(scope, resourceName); Scope = scope; Parameters = new List(); - Parent = parent ?? FindParentInScope(scope); + Parent = parent ?? FindParentInScope(scope); Scope.AddResource(this); ResourceData = createProperties(azureName); Version = version; - ParameterOverrides = new Dictionary>(); + ParameterOverrides = new Dictionary>(); Dependencies = new List(); ResourceType = resourceType; Id = Parent is null @@ -145,12 +149,15 @@ private protected void AssignParameter(object instance, string propertyName, Par { if (ParameterOverrides.TryGetValue(instance, out var overrides)) { - overrides[propertyName] = parameter.Name; + overrides[propertyName] = parameter; } else { - ParameterOverrides.Add(instance, new Dictionary { { propertyName, parameter.Name } }); + ParameterOverrides.Add(instance, new Dictionary { { propertyName, parameter } }); } + Scope.AddParameter(parameter); + //TODO: We should not need this instead a parameter should have a reference to the resource it is associated with but belong to the construct only. + //https://github.com/Azure/azure-sdk-for-net/issues/42066 Parameters.Add(parameter); } @@ -167,7 +174,7 @@ private protected void AssignParameter(object instance, string propertyName, Par /// If the is not found on the resources properties. private protected Output AddOutput(string name, object instance, string propertyName, string expression, bool isLiteral = false, bool isSecure = false) { - var result = new Output(name, $"{Name}.{expression}", Scope, isLiteral, isSecure); + var result = new Output(name, $"{Name}.{expression}", Scope, this, isLiteral, isSecure); Scope.AddOutput(result); return result; } @@ -231,7 +238,12 @@ private BinaryData SerializeModule(ModelReaderWriterOptions options) var bicepOptions = new BicepModelReaderWriterOptions(); foreach (var parameter in ParameterOverrides) { - bicepOptions.ParameterOverrides.Add(parameter.Key, parameter.Value); + var dict = new Dictionary(); + foreach (var kvp in parameter.Value) + { + dict.Add(kvp.Key, kvp.Value.GetParameterString(ModuleScope!)); + } + bicepOptions.ParameterOverrides.Add(parameter.Key, dict); } var data = ModelReaderWriter.Write(ResourceData, bicepOptions).ToMemory(); @@ -246,16 +258,18 @@ private BinaryData SerializeModule(ModelReaderWriterOptions options) private bool NeedsScope() { + Debug.Assert(ModuleScope != null, "ModuleScope should not be null"); + switch (Parent) { case ResourceGroup _: - return Scope.ConstructScope != ConstructScope.ResourceGroup; + return ModuleScope!.ConstructScope != ConstructScope.ResourceGroup; case Subscription _: - return Scope.ConstructScope != ConstructScope.Subscription; + return ModuleScope!.ConstructScope != ConstructScope.Subscription; case Tenant _: - return Scope.ConstructScope != ConstructScope.Tenant; + return ModuleScope!.ConstructScope != ConstructScope.Tenant; default: - return Scope.ConstructScope != ConstructScope.ResourceGroup; + return ModuleScope!.ConstructScope != ConstructScope.ResourceGroup; } } diff --git a/sdk/provisioning/Azure.Provisioning/src/keyvault/KeyVault.cs b/sdk/provisioning/Azure.Provisioning/src/keyvault/KeyVault.cs index a9886757edfbc..b9636402c17eb 100644 --- a/sdk/provisioning/Azure.Provisioning/src/keyvault/KeyVault.cs +++ b/sdk/provisioning/Azure.Provisioning/src/keyvault/KeyVault.cs @@ -24,8 +24,9 @@ public class KeyVault : Resource /// The name. /// The version. /// The location. - public KeyVault(IConstruct scope, string name = "kv", string version = "2023-02-01", AzureLocation? location = default) - : base(scope, null, name, ResourceTypeName, version, (name) => ArmKeyVaultModelFactory.KeyVaultData( + /// + public KeyVault(IConstruct scope, string name = "kv", string version = "2023-02-01", AzureLocation? location = default, ResourceGroup? resourceGroup = default) + : base(scope, resourceGroup, name, ResourceTypeName, version, (name) => ArmKeyVaultModelFactory.KeyVaultData( name: name, resourceType: ResourceTypeName, location: location ?? Environment.GetEnvironmentVariable("AZURE_LOCATION") ?? AzureLocation.WestUS, diff --git a/sdk/provisioning/Azure.Provisioning/src/keyvault/KeyVaultAddAccessPolicy.cs b/sdk/provisioning/Azure.Provisioning/src/keyvault/KeyVaultAddAccessPolicy.cs index 7f9783eae90ed..f37cbaf6a6a74 100644 --- a/sdk/provisioning/Azure.Provisioning/src/keyvault/KeyVaultAddAccessPolicy.cs +++ b/sdk/provisioning/Azure.Provisioning/src/keyvault/KeyVaultAddAccessPolicy.cs @@ -32,7 +32,7 @@ public KeyVaultAddAccessPolicy(IConstruct scope, Parameter principalIdParameter, }) })) { - ParameterOverrides.Add(Properties.AccessPolicies[0], new Dictionary { { nameof(KeyVaultAccessPolicy.ObjectId), GetParamValue(principalIdParameter, scope) } }); + ParameterOverrides.Add(Properties.AccessPolicies[0], new Dictionary { { nameof(KeyVaultAccessPolicy.ObjectId), principalIdParameter } }); } private static string GetParamValue(Parameter principalIdParameter, IConstruct scope) diff --git a/sdk/provisioning/Azure.Provisioning/src/keyvault/KeyVaultExtensions.cs b/sdk/provisioning/Azure.Provisioning/src/keyvault/KeyVaultExtensions.cs index 95073c439965a..ddb6582902af5 100644 --- a/sdk/provisioning/Azure.Provisioning/src/keyvault/KeyVaultExtensions.cs +++ b/sdk/provisioning/Azure.Provisioning/src/keyvault/KeyVaultExtensions.cs @@ -15,12 +15,12 @@ public static class KeyVaultExtensions /// Adds a to the construct. /// /// The construct. - /// The parent. + /// The parent. /// The name. /// - public static KeyVault AddKeyVault(this IConstruct construct, ResourceGroup? parent = null, string name = "kv") + public static KeyVault AddKeyVault(this IConstruct construct, ResourceGroup? resourceGroup = null, string name = "kv") { - return new KeyVault(construct, name); + return new KeyVault(construct, name, resourceGroup: resourceGroup); } /// diff --git a/sdk/provisioning/Azure.Provisioning/src/resourcemanager/ResourceGroup.cs b/sdk/provisioning/Azure.Provisioning/src/resourcemanager/ResourceGroup.cs index e14f4477a1e2b..c69be981062eb 100644 --- a/sdk/provisioning/Azure.Provisioning/src/resourcemanager/ResourceGroup.cs +++ b/sdk/provisioning/Azure.Provisioning/src/resourcemanager/ResourceGroup.cs @@ -23,8 +23,9 @@ public class ResourceGroup : Resource /// The name of the resourceGroup. /// The version of the resourceGroup. /// The location of the resourceGroup. - public ResourceGroup(IConstruct scope, string name = "rg", string version = "2023-07-01", AzureLocation? location = default) - : base(scope, null, name, ResourceType, version, (name) => ResourceManagerModelFactory.ResourceGroupData( + /// The parent of the resourceGroup. + public ResourceGroup(IConstruct scope, string name = "rg", string version = "2023-07-01", AzureLocation? location = default, Subscription? parent = default) + : base(scope, parent, name, ResourceType, version, (name) => ResourceManagerModelFactory.ResourceGroupData( name: name, resourceType: ResourceType, tags: new Dictionary { { "azd-env-name", scope.EnvironmentName } }, diff --git a/sdk/provisioning/Azure.Provisioning/src/resourcemanager/ResourceManagerExtensions.cs b/sdk/provisioning/Azure.Provisioning/src/resourcemanager/ResourceManagerExtensions.cs index 49000090eb282..0ed54ac7cea8a 100644 --- a/sdk/provisioning/Azure.Provisioning/src/resourcemanager/ResourceManagerExtensions.cs +++ b/sdk/provisioning/Azure.Provisioning/src/resourcemanager/ResourceManagerExtensions.cs @@ -23,7 +23,7 @@ public static ResourceGroup AddResourceGroup(this IConstruct construct) throw new InvalidOperationException("ResourceGroup already exists on the construct"); } - return new ResourceGroup(construct, "rg"); + return new ResourceGroup(construct, name: "rg"); } /// @@ -44,7 +44,7 @@ public static ResourceGroup GetOrAddResourceGroup(this IConstruct construct) /// The see . public static Subscription GetOrCreateSubscription(this IConstruct construct, Guid? subscriptionId = null) { - return construct.Subscription ?? construct.GetSingleResource() ?? new Subscription(construct, subscriptionId); + return construct.Subscription ?? (subscriptionId != null ? new Subscription(construct, subscriptionId) : construct.GetSingleResource())!; } } } diff --git a/sdk/provisioning/Azure.Provisioning/src/websites/AppServicePlan.cs b/sdk/provisioning/Azure.Provisioning/src/websites/AppServicePlan.cs index 44d66e3476050..bc70f642958b4 100644 --- a/sdk/provisioning/Azure.Provisioning/src/websites/AppServicePlan.cs +++ b/sdk/provisioning/Azure.Provisioning/src/websites/AppServicePlan.cs @@ -23,8 +23,9 @@ public class AppServicePlan : Resource /// The resource name. /// The version. /// The location. - public AppServicePlan(IConstruct scope, string resourceName, string version = "2021-02-01", AzureLocation? location = default) - : base(scope, null, resourceName, ResourceTypeName, version, (name) => ArmAppServiceModelFactory.AppServicePlanData( + /// The resource group. + public AppServicePlan(IConstruct scope, string resourceName, string version = "2021-02-01", AzureLocation? location = default, ResourceGroup? parent = default) + : base(scope, parent, resourceName, ResourceTypeName, version, (name) => ArmAppServiceModelFactory.AppServicePlanData( name: name, location: location ?? Environment.GetEnvironmentVariable("AZURE_LOCATION") ?? AzureLocation.WestUS, sku: new AppServiceSkuDescription() { Name = "B1" }, diff --git a/sdk/provisioning/Azure.Provisioning/src/websites/AppServicesExtensions.cs b/sdk/provisioning/Azure.Provisioning/src/websites/AppServicesExtensions.cs index b0c834c309019..3e7a4c518db34 100644 --- a/sdk/provisioning/Azure.Provisioning/src/websites/AppServicesExtensions.cs +++ b/sdk/provisioning/Azure.Provisioning/src/websites/AppServicesExtensions.cs @@ -19,7 +19,7 @@ public static class AppServicesExtensions /// public static AppServicePlan AddAppServicePlan(this IConstruct construct, ResourceGroup? parent = null, string name = "appServicePlan") { - return new AppServicePlan(construct, name); ; + return new AppServicePlan(construct, name, parent: parent); } } } diff --git a/sdk/provisioning/Azure.Provisioning/src/websites/WebSite.cs b/sdk/provisioning/Azure.Provisioning/src/websites/WebSite.cs index de258213a8cab..57a753998e886 100644 --- a/sdk/provisioning/Azure.Provisioning/src/websites/WebSite.cs +++ b/sdk/provisioning/Azure.Provisioning/src/websites/WebSite.cs @@ -45,8 +45,9 @@ public class WebSite : Resource /// The runtime version /// The version. /// The location. - public WebSite(IConstruct scope, string resourceName, AppServicePlan appServicePlan, WebSiteRuntime runtime, string runtimeVersion, string version = "2021-02-01", AzureLocation? location = default) - : base(scope, null, resourceName, ResourceTypeName, version, (name) => ArmAppServiceModelFactory.WebSiteData( + /// The resource group. + public WebSite(IConstruct scope, string resourceName, AppServicePlan appServicePlan, WebSiteRuntime runtime, string runtimeVersion, string version = "2021-02-01", AzureLocation? location = default, ResourceGroup? parent = null) + : base(scope, parent, resourceName, ResourceTypeName, version, (name) => ArmAppServiceModelFactory.WebSiteData( name: name, location: location ?? Environment.GetEnvironmentVariable("AZURE_LOCATION") ?? AzureLocation.WestUS, resourceType: ResourceTypeName, diff --git a/sdk/provisioning/Azure.Provisioning/tests/Azure.Provisioning.Tests.csproj b/sdk/provisioning/Azure.Provisioning/tests/Azure.Provisioning.Tests.csproj index e1fd392f2fe0a..961469ea67ecb 100644 --- a/sdk/provisioning/Azure.Provisioning/tests/Azure.Provisioning.Tests.csproj +++ b/sdk/provisioning/Azure.Provisioning/tests/Azure.Provisioning.Tests.csproj @@ -13,6 +13,7 @@ + diff --git a/sdk/provisioning/Azure.Provisioning/tests/ConstructTests.cs b/sdk/provisioning/Azure.Provisioning/tests/ConstructTests.cs new file mode 100644 index 0000000000000..9552f32c7d008 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning/tests/ConstructTests.cs @@ -0,0 +1,153 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Linq; +using Azure.Provisioning.ResourceManager; +using Azure.Provisioning.Storage; +using NUnit.Framework; + +namespace Azure.Provisioning.Tests +{ + public class ConstructTests + { + [Test] + [TestCase(true)] + [TestCase(false)] + public void GetConstructsNoChildConstructs(bool recursive) + { + var infra = new TestInfrastructure(); + var constructs = infra.GetConstructs(recursive); + + // the only construct is the infrastructure itself which doesn't get included in GetConstructs + Assert.AreEqual(0, constructs.Count()); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void GetConstructsChildConstructs(bool recursive) + { + var infra = new TestInfrastructure(); + infra.AddFrontEndWebSite(); + var constructs = infra.GetConstructs(recursive); + + Assert.AreEqual(1, constructs.Count()); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void GetConstructsGrandchildConstructs(bool recursive) + { + var infra = new TestInfrastructure(); + + var childScope = new TestInfrastructure(); + childScope.AddConstruct(new TestInfrastructure()); + infra.AddConstruct(childScope); + + var constructs = infra.GetConstructs(recursive); + + var expected = recursive ? 2 : 1; + Assert.AreEqual(expected, constructs.Count()); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void GetResourcesNoChildConstructs(bool recursive) + { + var infra = new TestInfrastructure(); + _ = new ResourceGroup(infra, "rg1"); + _ = new ResourceGroup(infra, "rg2"); + + var resources = infra.GetResources(recursive); + + Assert.AreEqual(4, resources.Count()); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void GetResourcesChildConstructs(bool recursive) + { + var infra = new TestInfrastructure(); + var rg1 = new ResourceGroup(infra, "rg1"); + + var childScope = infra.AddFrontEndWebSite(resourceGroup: rg1); + _ = new ResourceGroup(childScope, "rg2"); + + var expected = recursive ? 10 : 6; + var resources = infra.GetResources(recursive); + + Assert.AreEqual(expected, resources.Count()); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void GetParametersNoChildConstructs(bool recursive) + { + var infra = new TestInfrastructure(); + var rg1 = new ResourceGroup(infra, "rg1"); + + rg1.AssignParameter(r => r.Location, new Parameter("location")); + + var parameters = infra.GetParameters(recursive); + var expected = recursive ? 1 : 1; + Assert.AreEqual(expected, parameters.Count()); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void GetParametersChildConstructs(bool recursive) + { + var infra = new TestInfrastructure(); + var rg1 = new ResourceGroup(infra, "rg1"); + rg1.AssignParameter(r => r.Location, new Parameter("location")); + + var childScope = infra.AddFrontEndWebSite(); + var rg2 = new ResourceGroup(childScope, "rg2"); + rg2.AssignParameter(r => r.Location, new Parameter("location")); + + var expected = recursive ? 2 : 1; + var parameters = infra.GetParameters(recursive); + + Assert.AreEqual(expected, parameters.Count()); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void GetOutputsNoChildConstructs(bool recursive) + { + var infra = new TestInfrastructure(); + var rg1 = new ResourceGroup(infra, "rg1"); + + rg1.AddOutput(r => r.Location, "location"); + + var outputs = infra.GetOutputs(recursive); + Assert.AreEqual(1, outputs.Count()); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void GetOutputsChildConstructs(bool recursive) + { + var infra = new TestInfrastructure(); + var rg1 = new ResourceGroup(infra, "rg1"); + rg1.AddOutput(r => r.Location, "location"); + + var childScope = infra.AddFrontEndWebSite(); + var rg2 = new ResourceGroup(childScope, "rg2"); + rg2.AddOutput(r => r.Location, "location"); + + // front end website has an output + var expected = recursive ? 3 : 1; + var outputs = infra.GetOutputs(recursive); + + Assert.AreEqual(expected, outputs.Count()); + } + } +} diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/AppConfiguration/main.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/AppConfiguration/main.bicep index 086bbe72e4533..163f0ff9d1c26 100644 --- a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/AppConfiguration/main.bicep +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/AppConfiguration/main.bicep @@ -1,4 +1,4 @@ -targetScope = subscription +targetScope = 'subscription' resource resourceGroup_I6QNkoPsb 'Microsoft.Resources/resourceGroups@2023-07-01' = { @@ -9,15 +9,9 @@ resource resourceGroup_I6QNkoPsb 'Microsoft.Resources/resourceGroups@2023-07-01' } } -resource appConfigurationStore_sgecYnln3 'Microsoft.AppConfiguration/configurationStores@2023-03-01' = { +module rg_TEST './resources/rg_TEST/rg_TEST.bicep' = { + name: 'rg_TEST' scope: resourceGroup_I6QNkoPsb - name: 'store-TEST' - location: 'westus' - sku: { - name: 'free' - } - properties: { - } } -output appConfigurationStore_sgecYnln3_endpoint string = appConfigurationStore_sgecYnln3.properties.endpoint +output appConfigurationStore_sgecYnln3_endpoint string = rg_TEST.outputs.appConfigurationStore_sgecYnln3_endpoint diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/AppConfiguration/resources/rg_TEST/rg_TEST.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/AppConfiguration/resources/rg_TEST/rg_TEST.bicep new file mode 100644 index 0000000000000..12efbf2dc8b00 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/AppConfiguration/resources/rg_TEST/rg_TEST.bicep @@ -0,0 +1,12 @@ + +resource appConfigurationStore_sgecYnln3 'Microsoft.AppConfiguration/configurationStores@2023-03-01' = { + name: 'store-TEST' + location: 'westus' + sku: { + name: 'free' + } + properties: { + } +} + +output appConfigurationStore_sgecYnln3_endpoint string = appConfigurationStore_sgecYnln3.properties.endpoint diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/MultipleSubscriptions/main.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/MultipleSubscriptions/main.bicep new file mode 100644 index 0000000000000..bbd8a186882d6 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/MultipleSubscriptions/main.bicep @@ -0,0 +1,12 @@ +targetScope = 'tenant' + + +module subscription_O0vZNnri3 './resources/subscription_O0vZNnri3/subscription_O0vZNnri3.bicep' = { + name: 'subscription_O0vZNnri3' + scope: subscription('subscription_O0vZNnri3') +} + +module subscription_i7MQMw1U7 './resources/subscription_i7MQMw1U7/subscription_i7MQMw1U7.bicep' = { + name: 'subscription_i7MQMw1U7' + scope: subscription('subscription_i7MQMw1U7') +} diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/MultipleSubscriptions/resources/subscription_O0vZNnri3/subscription_O0vZNnri3.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/MultipleSubscriptions/resources/subscription_O0vZNnri3/subscription_O0vZNnri3.bicep new file mode 100644 index 0000000000000..ebb9a61118abd --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/MultipleSubscriptions/resources/subscription_O0vZNnri3/subscription_O0vZNnri3.bicep @@ -0,0 +1,10 @@ +targetScope = 'subscription' + + +resource resourceGroup_grHjXx8QF 'Microsoft.Resources/resourceGroups@2023-07-01' = { + name: 'rg-TEST' + location: 'westus' + tags: { + 'azd-env-name': 'TEST' + } +} diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/MultipleSubscriptions/resources/subscription_i7MQMw1U7/subscription_i7MQMw1U7.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/MultipleSubscriptions/resources/subscription_i7MQMw1U7/subscription_i7MQMw1U7.bicep new file mode 100644 index 0000000000000..34344c2dc39a9 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/MultipleSubscriptions/resources/subscription_i7MQMw1U7/subscription_i7MQMw1U7.bicep @@ -0,0 +1,10 @@ +targetScope = 'subscription' + + +resource resourceGroup_U95xWHMzX 'Microsoft.Resources/resourceGroups@2023-07-01' = { + name: 'rg-TEST' + location: 'westus' + tags: { + 'azd-env-name': 'TEST' + } +} diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/OutputsSpanningModules/main.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/OutputsSpanningModules/main.bicep new file mode 100644 index 0000000000000..df4929f7b2eee --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/OutputsSpanningModules/main.bicep @@ -0,0 +1,49 @@ +targetScope = 'subscription' + + +resource resourceGroup_AVG5HpqPz 'Microsoft.Resources/resourceGroups@2023-07-01' = { + name: 'rg1-TEST' + location: 'westus' + tags: { + 'azd-env-name': 'TEST' + } +} + +resource resourceGroup_hu2r8JaSi 'Microsoft.Resources/resourceGroups@2023-07-01' = { + name: 'rg2-TEST' + location: 'westus' + tags: { + 'azd-env-name': 'TEST' + } +} + +resource resourceGroup_Q4i0lpa1h 'Microsoft.Resources/resourceGroups@2023-07-01' = { + name: 'rg3-TEST' + location: 'westus' + tags: { + 'azd-env-name': 'TEST' + } +} + +module rg1_TEST './resources/rg1_TEST/rg1_TEST.bicep' = { + name: 'rg1_TEST' + scope: resourceGroup_AVG5HpqPz +} + +module rg2_TEST './resources/rg2_TEST/rg2_TEST.bicep' = { + name: 'rg2_TEST' + scope: resourceGroup_hu2r8JaSi + params: { + STORAGE_PRINCIPAL_ID: rg1_TEST.outputs.STORAGE_PRINCIPAL_ID + LOCATION: rg1_TEST.outputs.LOCATION + } +} + +module rg3_TEST './resources/rg3_TEST/rg3_TEST.bicep' = { + name: 'rg3_TEST' + scope: resourceGroup_Q4i0lpa1h +} + +output STORAGE_PRINCIPAL_ID string = rg1_TEST.outputs.STORAGE_PRINCIPAL_ID +output LOCATION string = rg1_TEST.outputs.LOCATION +output SERVICE_API_IDENTITY_PRINCIPAL_ID string = rg3_TEST.outputs.SERVICE_API_IDENTITY_PRINCIPAL_ID diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/OutputsSpanningModules/resources/rg1_TEST/rg1_TEST.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/OutputsSpanningModules/resources/rg1_TEST/rg1_TEST.bicep new file mode 100644 index 0000000000000..a067a8e757d48 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/OutputsSpanningModules/resources/rg1_TEST/rg1_TEST.bicep @@ -0,0 +1,77 @@ + +resource appServicePlan_viooTTlOI 'Microsoft.Web/serverfarms@2021-02-01' = { + name: 'appServicePlan-TEST' + location: 'westus' + sku: { + name: 'B1' + } + properties: { + reserved: true + } +} + +resource webSite_dOTaZfna6 'Microsoft.Web/sites@2021-02-01' = { + name: 'frontEnd-TEST' + location: 'westus' + identity: { + } + kind: 'app,linux' + properties: { + serverFarmId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1-TEST/providers/Microsoft.Web/serverfarms/appServicePlan-TEST' + siteConfig: { + linuxFxVersion: 'node|18-lts' + alwaysOn: true + appCommandLine: './entrypoint.sh -o ./env-config.js && pm2 serve /home/site/wwwroot --no-daemon --spa' + experiments: { + } + cors: { + allowedOrigins: [ + 'https://portal.azure.com' + 'https://ms.portal.azure.com' + ] + } + minTlsVersion: '1.2' + ftpsState: 'FtpsOnly' + } + httpsOnly: true + } +} + +resource applicationSettingsResource_MAMFSSuFs 'Microsoft.Web/sites/config@2021-02-01' = { + parent: webSite_dOTaZfna6 + name: 'appsettings' +} + +resource keyVault_BRsYQF4qT 'Microsoft.KeyVault/vaults@2023-02-01' = { + name: 'kv-TEST' + location: LOCATION + properties: { + tenantId: '00000000-0000-0000-0000-000000000000' + sku: { + name: 'standard' + family: 'A' + } + } +} + +resource keyVaultAddAccessPolicy_lQ2z7dHpX 'Microsoft.KeyVault/vaults/accessPolicies@2023-02-01' = { + parent: keyVault_BRsYQF4qT + name: 'add' + properties: { + accessPolicies: [ + { + tenantId: '00000000-0000-0000-0000-000000000000' + objectId: SERVICE_API_IDENTITY_PRINCIPAL_ID + permissions: { + secrets: [ + 'get' + 'list' + ] + } + } + ] + } +} + +output STORAGE_PRINCIPAL_ID string = webSite_dOTaZfna6.identity.principalId +output LOCATION string = webSite_dOTaZfna6.location diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/OutputsSpanningModules/resources/rg2_TEST/rg2_TEST.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/OutputsSpanningModules/resources/rg2_TEST/rg2_TEST.bicep new file mode 100644 index 0000000000000..b506f40b2de1a --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/OutputsSpanningModules/resources/rg2_TEST/rg2_TEST.bicep @@ -0,0 +1,38 @@ +@description('') +param STORAGE_PRINCIPAL_ID string + +@description('') +param LOCATION string + + +resource webSite_80I4ejz5T 'Microsoft.Web/sites@2021-02-01' = { + name: 'frontEnd-TEST' + location: LOCATION + identity: { + } + kind: 'app,linux' + properties: { + serverFarmId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1-TEST/providers/Microsoft.Web/serverfarms/appServicePlan-TEST' + siteConfig: { + linuxFxVersion: 'node|18-lts' + alwaysOn: true + appCommandLine: './entrypoint.sh -o ./env-config.js && pm2 serve /home/site/wwwroot --no-daemon --spa' + experiments: { + } + cors: { + allowedOrigins: [ + 'https://portal.azure.com' + 'https://ms.portal.azure.com' + ] + } + minTlsVersion: '1.2' + ftpsState: 'FtpsOnly' + } + httpsOnly: true + } +} + +resource applicationSettingsResource_eTrLWYWog 'Microsoft.Web/sites/config@2021-02-01' = { + parent: webSite_80I4ejz5T + name: 'appsettings' +} diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/resources/TestFrontEndWebSite/TestFrontEndWebSite.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/OutputsSpanningModules/resources/rg3_TEST/rg3_TEST.bicep similarity index 60% rename from sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/resources/TestFrontEndWebSite/TestFrontEndWebSite.bicep rename to sdk/provisioning/Azure.Provisioning/tests/Infrastructure/OutputsSpanningModules/resources/rg3_TEST/rg3_TEST.bicep index dc133defcbbe7..3e6eecdefdca1 100644 --- a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/resources/TestFrontEndWebSite/TestFrontEndWebSite.bicep +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/OutputsSpanningModules/resources/rg3_TEST/rg3_TEST.bicep @@ -1,20 +1,12 @@ -resource appServicePlan_kjMZSF1FP 'Microsoft.Web/serverfarms@2021-02-01' existing = { - name: 'appServicePlan_kjMZSF1FP' -} - -resource keyVault_CRoMbemLF 'Microsoft.KeyVault/vaults@2023-02-01' existing = { - name: 'keyVault_CRoMbemLF' -} - -resource webSite_W5EweSXEq 'Microsoft.Web/sites@2021-02-01' = { +resource webSite_Y34mQ7HgU 'Microsoft.Web/sites@2021-02-01' = { name: 'frontEnd-TEST' location: 'westus' identity: { } kind: 'app,linux' properties: { - serverFarmId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-TEST/providers/Microsoft.Web/serverfarms/appServicePlan-TEST' + serverFarmId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1-TEST/providers/Microsoft.Web/serverfarms/appServicePlan-TEST' siteConfig: { linuxFxVersion: 'node|18-lts' alwaysOn: true @@ -34,13 +26,13 @@ resource webSite_W5EweSXEq 'Microsoft.Web/sites@2021-02-01' = { } } -resource applicationSettingsResource_9BG7vUQd2 'Microsoft.Web/sites/config@2021-02-01' = { - parent: webSite_W5EweSXEq +resource applicationSettingsResource_1XX3wQExf 'Microsoft.Web/sites/config@2021-02-01' = { + parent: webSite_Y34mQ7HgU name: 'appsettings' } -resource webSiteConfigLogs_giqxapQs0 'Microsoft.Web/sites/config@2021-02-01' = { - parent: webSite_W5EweSXEq +resource webSiteConfigLogs_vhJa9LaNc 'Microsoft.Web/sites/config@2021-02-01' = { + parent: webSite_Y34mQ7HgU name: 'logs' properties: { applicationLogs: { @@ -64,4 +56,4 @@ resource webSiteConfigLogs_giqxapQs0 'Microsoft.Web/sites/config@2021-02-01' = { } } -output SERVICE_API_IDENTITY_PRINCIPAL_ID string = webSite_W5EweSXEq.identity.principalId +output SERVICE_API_IDENTITY_PRINCIPAL_ID string = webSite_Y34mQ7HgU.identity.principalId diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/ResourceGroupOnly/main.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/ResourceGroupOnly/main.bicep index c61a4b9e1bfce..b775ff0ab5b6b 100644 --- a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/ResourceGroupOnly/main.bicep +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/ResourceGroupOnly/main.bicep @@ -1,4 +1,4 @@ -targetScope = subscription +targetScope = 'subscription' resource resourceGroup_I6QNkoPsb 'Microsoft.Resources/resourceGroups@2023-07-01' = { diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/StorageBlobDefaults/main.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/StorageBlobDefaults/main.bicep index efd8c4f974fdf..da7e83d582e03 100644 --- a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/StorageBlobDefaults/main.bicep +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/StorageBlobDefaults/main.bicep @@ -1,4 +1,4 @@ -targetScope = subscription +targetScope = 'subscription' resource resourceGroup_I6QNkoPsb 'Microsoft.Resources/resourceGroups@2023-07-01' = { @@ -9,23 +9,7 @@ resource resourceGroup_I6QNkoPsb 'Microsoft.Resources/resourceGroups@2023-07-01' } } -resource storageAccount_8fTaUIzOg 'Microsoft.Storage/storageAccounts@2022-09-01' = { +module rg_TEST './resources/rg_TEST/rg_TEST.bicep' = { + name: 'rg_TEST' scope: resourceGroup_I6QNkoPsb - name: 'photoacct2af3506bedd4415' - location: 'westus' - sku: { - name: 'Premium_LRS' - } - kind: 'StorageV2' - properties: { - } -} - -resource blobService_1iUqwyvnt 'Microsoft.Storage/storageAccounts/blobServices@2022-09-01' = { - parent: storageAccount_8fTaUIzOg - name: 'default' - properties: { - cors: { - } - } } diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/StorageBlobDefaults/resources/rg_TEST/rg_TEST.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/StorageBlobDefaults/resources/rg_TEST/rg_TEST.bicep new file mode 100644 index 0000000000000..4fd8ed1fb0729 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/StorageBlobDefaults/resources/rg_TEST/rg_TEST.bicep @@ -0,0 +1,20 @@ + +resource storageAccount_o16OWzTQE 'Microsoft.Storage/storageAccounts@2022-09-01' = { + name: 'photoacct985209930ac24f6' + location: 'westus' + sku: { + name: 'Premium_LRS' + } + kind: 'StorageV2' + properties: { + } +} + +resource blobService_b1lTObtBZ 'Microsoft.Storage/storageAccounts/blobServices@2022-09-01' = { + parent: storageAccount_o16OWzTQE + name: 'default' + properties: { + cors: { + } + } +} diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/StorageBlobDropDown/main.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/StorageBlobDropDown/main.bicep index 7994d65dcd582..da7e83d582e03 100644 --- a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/StorageBlobDropDown/main.bicep +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/StorageBlobDropDown/main.bicep @@ -1,4 +1,4 @@ -targetScope = subscription +targetScope = 'subscription' resource resourceGroup_I6QNkoPsb 'Microsoft.Resources/resourceGroups@2023-07-01' = { @@ -9,26 +9,7 @@ resource resourceGroup_I6QNkoPsb 'Microsoft.Resources/resourceGroups@2023-07-01' } } -resource storageAccount_VpeHv8O32 'Microsoft.Storage/storageAccounts@2022-09-01' = { +module rg_TEST './resources/rg_TEST/rg_TEST.bicep' = { + name: 'rg_TEST' scope: resourceGroup_I6QNkoPsb - name: 'photoacct414ad12f6b9c4a2' - location: 'westus' - sku: { - name: 'Premium_LRS' - } - kind: 'StorageV2' - properties: { - } -} - -resource blobService_6SRi2s6Pf 'Microsoft.Storage/storageAccounts/blobServices@2022-09-01' = { - parent: storageAccount_VpeHv8O32 - name: 'default' - properties: { - cors: { - } - deleteRetentionPolicy: { - enabled: true - } - } } diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/StorageBlobDropDown/resources/rg_TEST/rg_TEST.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/StorageBlobDropDown/resources/rg_TEST/rg_TEST.bicep new file mode 100644 index 0000000000000..84adbe11a46b6 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/StorageBlobDropDown/resources/rg_TEST/rg_TEST.bicep @@ -0,0 +1,23 @@ + +resource storageAccount_xlURFCc5A 'Microsoft.Storage/storageAccounts@2022-09-01' = { + name: 'photoaccte6de904bc2d5415' + location: 'westus' + sku: { + name: 'Premium_LRS' + } + kind: 'StorageV2' + properties: { + } +} + +resource blobService_AhHMDPJzw 'Microsoft.Storage/storageAccounts/blobServices@2022-09-01' = { + parent: storageAccount_xlURFCc5A + name: 'default' + properties: { + cors: { + } + deleteRetentionPolicy: { + enabled: true + } + } +} diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL1/main.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL1/main.bicep index 4ab9eac1108ab..8ab036a1810a9 100644 --- a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL1/main.bicep +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL1/main.bicep @@ -1,4 +1,4 @@ -targetScope = subscription +targetScope = 'subscription' @secure() @description('SQL Server administrator password') @@ -18,248 +18,13 @@ resource resourceGroup_I6QNkoPsb 'Microsoft.Resources/resourceGroups@2023-07-01' } } -resource appServicePlan_kjMZSF1FP 'Microsoft.Web/serverfarms@2021-02-01' = { +module rg_TEST './resources/rg_TEST/rg_TEST.bicep' = { + name: 'rg_TEST' scope: resourceGroup_I6QNkoPsb - name: 'appServicePlan-TEST' - location: 'westus' - sku: { - name: 'B1' - } - properties: { - reserved: true - } -} - -resource webSite_W5EweSXEq 'Microsoft.Web/sites@2021-02-01' = { - scope: resourceGroup_I6QNkoPsb - name: 'frontEnd-TEST' - location: 'westus' - identity: { - } - kind: 'app,linux' - properties: { - serverFarmId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-TEST/providers/Microsoft.Web/serverfarms/appServicePlan-TEST' - siteConfig: { - linuxFxVersion: 'node|18-lts' - alwaysOn: true - appCommandLine: './entrypoint.sh -o ./env-config.js && pm2 serve /home/site/wwwroot --no-daemon --spa' - experiments: { - } - cors: { - allowedOrigins: [ - 'https://portal.azure.com' - 'https://ms.portal.azure.com' - ] - } - minTlsVersion: '1.2' - ftpsState: 'FtpsOnly' - } - httpsOnly: true - } -} - -resource applicationSettingsResource_9BG7vUQd2 'Microsoft.Web/sites/config@2021-02-01' = { - parent: webSite_W5EweSXEq - name: 'appsettings' -} - -resource keyVault_CRoMbemLF 'Microsoft.KeyVault/vaults@2023-02-01' = { - scope: resourceGroup_I6QNkoPsb - name: 'kv-TEST' - location: 'westus' - properties: { - tenantId: '00000000-0000-0000-0000-000000000000' - sku: { - name: 'standard' - family: 'A' - } - } -} - -resource keyVaultAddAccessPolicy_NWCGclP20 'Microsoft.KeyVault/vaults/accessPolicies@2023-02-01' = { - parent: keyVault_CRoMbemLF - name: 'add' - properties: { - accessPolicies: [ - { - tenantId: '00000000-0000-0000-0000-000000000000' - objectId: webSite_W5EweSXEq.identity.principalId - permissions: { - secrets: [ - 'get' - 'list' - ] - } - } - ] - } -} - -resource keyVaultSecret_NmXfhaHvM 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = { - parent: keyVault_CRoMbemLF - name: 'sqlAdminPassword-TEST' - properties: { - value: sqlAdminPassword - } -} - -resource keyVaultSecret_QRsiyFBMe 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = { - parent: keyVault_CRoMbemLF - name: 'appUserPassword-TEST' - properties: { - value: appUserPassword - } -} - -resource sqlServer_zjdvvB2wl 'Microsoft.Sql/servers@2022-08-01-preview' = { - scope: resourceGroup_I6QNkoPsb - name: 'sqlserver-TEST' - location: 'westus' - properties: { - administratorLogin: 'sqladmin' - administratorLoginPassword: sqlAdminPassword - version: '12.0' - minimalTlsVersion: '1.2' - publicNetworkAccess: 'Enabled' - } -} - -resource sqlDatabase_U7NzorRJT 'Microsoft.Sql/servers/databases@2022-08-01-preview' = { - parent: sqlServer_zjdvvB2wl - name: 'db-TEST' - location: 'westus' - properties: { - } -} - -resource keyVaultSecret_7eiFxkj0r 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = { - parent: keyVault_CRoMbemLF - name: 'connectionString-TEST' - properties: { - value: 'Server=${sqlServer_zjdvvB2wl.properties.fullyQualifiedDomainName}; Database=${sqlDatabase_U7NzorRJT.name}; User=appUser; Password=${appUserPassword}' - } -} - -resource sqlFirewallRule_eS4m8st65 'Microsoft.Sql/servers/firewallRules@2020-11-01-preview' = { - parent: sqlServer_zjdvvB2wl - name: 'firewallRule-TEST' - properties: { - startIpAddress: '0.0.0.1' - endIpAddress: '255.255.255.254' - } -} - -resource deploymentScript_3Zq2Pl8xa 'Microsoft.Resources/deploymentScripts@2020-10-01' = { - scope: resourceGroup_I6QNkoPsb - name: 'cliScript-TEST' - location: 'westus' - kind: 'AzureCLI' - properties: { - cleanupPreference: 'OnSuccess' - scriptContent: ''' -wget https://github.com/microsoft/go-sqlcmd/releases/download/v0.8.1/sqlcmd-v0.8.1-linux-x64.tar.bz2 -tar x -f sqlcmd-v0.8.1-linux-x64.tar.bz2 -C . -cat < ./initDb.sql -drop user ${APPUSERNAME} -go -create user ${APPUSERNAME} with password = '${APPUSERPASSWORD}' -go -alter role db_owner add member ${APPUSERNAME} -go -SCRIPT_END -./sqlcmd -S ${DBSERVER} -d ${DBNAME} -U ${SQLADMIN} -i ./initDb.sql''' - environmentVariables: [ - { - name: 'APPUSERNAME' - value: 'appUser' - } - { - name: 'APPUSERPASSWORD' - secureValue: '_p_.appUserPassword' - } - { - name: 'DBNAME' - value: '_p_.sqlDatabase_U7NzorRJT.name' - } - { - name: 'DBSERVER' - value: '_p_.sqlServer_zjdvvB2wl.properties.fullyQualifiedDomainName' - } - { - name: 'SQLCMDPASSWORD' - secureValue: '_p_.sqlAdminPassword' - } - { - name: 'SQLADMIN' - value: 'sqlAdmin' - } - ] - retentionInterval: 'PT1H' - timeout: 'PT5M' - azCliVersion: '2.37.0' - } -} - -resource webSite_4pzZqR2OO 'Microsoft.Web/sites@2021-02-01' = { - scope: resourceGroup_I6QNkoPsb - name: 'backEnd-TEST' - location: 'westus' - identity: { - } - kind: 'app,linux' - properties: { - serverFarmId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-TEST/providers/Microsoft.Web/serverfarms/appServicePlan-TEST' - siteConfig: { - linuxFxVersion: 'dotnetcore|6.0' - alwaysOn: true - appCommandLine: '' - experiments: { - } - cors: { - allowedOrigins: [ - 'https://portal.azure.com' - 'https://ms.portal.azure.com' - ] - } - minTlsVersion: '1.2' - ftpsState: 'FtpsOnly' - } - httpsOnly: true - } -} - -resource applicationSettingsResource_vEe46o8Zn 'Microsoft.Web/sites/config@2021-02-01' = { - parent: webSite_4pzZqR2OO - name: 'appsettings' - properties: { - 'SCM_DO_BUILD_DURING_DEPLOYMENT': 'False' - 'ENABLE_ORYX_BUILD': 'True' - } -} - -resource webSiteConfigLogs_giqxapQs0 'Microsoft.Web/sites/config@2021-02-01' = { - parent: webSite_W5EweSXEq - name: 'logs' - properties: { - applicationLogs: { - fileSystem: { - level: 'Verbose' - } - } - httpLogs: { - fileSystem: { - retentionInMb: 35 - retentionInDays: 1 - enabled: true - } - } - failedRequestsTracing: { - enabled: true - } - detailedErrorMessages: { - enabled: true - } + params: { + sqlAdminPassword: sqlAdminPassword + appUserPassword: appUserPassword } } -output SERVICE_API_IDENTITY_PRINCIPAL_ID string = webSite_W5EweSXEq.identity.principalId +output SERVICE_API_IDENTITY_PRINCIPAL_ID string = rg_TEST.outputs.SERVICE_API_IDENTITY_PRINCIPAL_ID diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL1/resources/rg_TEST/rg_TEST.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL1/resources/rg_TEST/rg_TEST.bicep new file mode 100644 index 0000000000000..fd18134828a04 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL1/resources/rg_TEST/rg_TEST.bicep @@ -0,0 +1,248 @@ +@secure() +@description('SQL Server administrator password') +param sqlAdminPassword string + +@secure() +@description('Application user password') +param appUserPassword string + + +resource appServicePlan_kjMZSF1FP 'Microsoft.Web/serverfarms@2021-02-01' = { + name: 'appServicePlan-TEST' + location: 'westus' + sku: { + name: 'B1' + } + properties: { + reserved: true + } +} + +resource webSite_W5EweSXEq 'Microsoft.Web/sites@2021-02-01' = { + name: 'frontEnd-TEST' + location: 'westus' + identity: { + } + kind: 'app,linux' + properties: { + serverFarmId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-TEST/providers/Microsoft.Web/serverfarms/appServicePlan-TEST' + siteConfig: { + linuxFxVersion: 'node|18-lts' + alwaysOn: true + appCommandLine: './entrypoint.sh -o ./env-config.js && pm2 serve /home/site/wwwroot --no-daemon --spa' + experiments: { + } + cors: { + allowedOrigins: [ + 'https://portal.azure.com' + 'https://ms.portal.azure.com' + ] + } + minTlsVersion: '1.2' + ftpsState: 'FtpsOnly' + } + httpsOnly: true + } +} + +resource applicationSettingsResource_9BG7vUQd2 'Microsoft.Web/sites/config@2021-02-01' = { + parent: webSite_W5EweSXEq + name: 'appsettings' +} + +resource webSiteConfigLogs_giqxapQs0 'Microsoft.Web/sites/config@2021-02-01' = { + parent: webSite_W5EweSXEq + name: 'logs' + properties: { + applicationLogs: { + fileSystem: { + level: 'Verbose' + } + } + httpLogs: { + fileSystem: { + retentionInMb: 35 + retentionInDays: 1 + enabled: true + } + } + failedRequestsTracing: { + enabled: true + } + detailedErrorMessages: { + enabled: true + } + } +} + +resource keyVault_CRoMbemLF 'Microsoft.KeyVault/vaults@2023-02-01' = { + name: 'kv-TEST' + location: 'westus' + properties: { + tenantId: '00000000-0000-0000-0000-000000000000' + sku: { + name: 'standard' + family: 'A' + } + } +} + +resource keyVaultAddAccessPolicy_NWCGclP20 'Microsoft.KeyVault/vaults/accessPolicies@2023-02-01' = { + parent: keyVault_CRoMbemLF + name: 'add' + properties: { + accessPolicies: [ + { + tenantId: '00000000-0000-0000-0000-000000000000' + objectId: SERVICE_API_IDENTITY_PRINCIPAL_ID + permissions: { + secrets: [ + 'get' + 'list' + ] + } + } + ] + } +} + +resource keyVaultSecret_NmXfhaHvM 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = { + parent: keyVault_CRoMbemLF + name: 'sqlAdminPassword-TEST' + properties: { + value: sqlAdminPassword + } +} + +resource keyVaultSecret_QRsiyFBMe 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = { + parent: keyVault_CRoMbemLF + name: 'appUserPassword-TEST' + properties: { + value: appUserPassword + } +} + +resource keyVaultSecret_7eiFxkj0r 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = { + parent: keyVault_CRoMbemLF + name: 'connectionString-TEST' + properties: { + value: 'Server=${sqlServer_zjdvvB2wl.properties.fullyQualifiedDomainName}; Database=${sqlDatabase_U7NzorRJT.name}; User=appUser; Password=${appUserPassword}' + } +} + +resource sqlServer_zjdvvB2wl 'Microsoft.Sql/servers@2022-08-01-preview' = { + name: 'sqlserver-TEST' + location: 'westus' + properties: { + administratorLogin: 'sqladmin' + administratorLoginPassword: sqlAdminPassword + version: '12.0' + minimalTlsVersion: '1.2' + publicNetworkAccess: 'Enabled' + } +} + +resource sqlDatabase_U7NzorRJT 'Microsoft.Sql/servers/databases@2022-08-01-preview' = { + parent: sqlServer_zjdvvB2wl + name: 'db-TEST' + location: 'westus' + properties: { + } +} + +resource sqlFirewallRule_eS4m8st65 'Microsoft.Sql/servers/firewallRules@2020-11-01-preview' = { + parent: sqlServer_zjdvvB2wl + name: 'firewallRule-TEST' + properties: { + startIpAddress: '0.0.0.1' + endIpAddress: '255.255.255.254' + } +} + +resource deploymentScript_3Zq2Pl8xa 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: 'cliScript-TEST' + location: 'westus' + kind: 'AzureCLI' + properties: { + cleanupPreference: 'OnSuccess' + scriptContent: ''' +wget https://github.com/microsoft/go-sqlcmd/releases/download/v0.8.1/sqlcmd-v0.8.1-linux-x64.tar.bz2 +tar x -f sqlcmd-v0.8.1-linux-x64.tar.bz2 -C . +cat < ./initDb.sql +drop user ${APPUSERNAME} +go +create user ${APPUSERNAME} with password = '${APPUSERPASSWORD}' +go +alter role db_owner add member ${APPUSERNAME} +go +SCRIPT_END +./sqlcmd -S ${DBSERVER} -d ${DBNAME} -U ${SQLADMIN} -i ./initDb.sql''' + environmentVariables: [ + { + name: 'APPUSERNAME' + value: 'appUser' + } + { + name: 'APPUSERPASSWORD' + secureValue: '_p_.appUserPassword' + } + { + name: 'DBNAME' + value: '_p_.sqlDatabase_U7NzorRJT.name' + } + { + name: 'DBSERVER' + value: '_p_.sqlServer_zjdvvB2wl.properties.fullyQualifiedDomainName' + } + { + name: 'SQLCMDPASSWORD' + secureValue: '_p_.sqlAdminPassword' + } + { + name: 'SQLADMIN' + value: 'sqlAdmin' + } + ] + retentionInterval: 'PT1H' + timeout: 'PT5M' + azCliVersion: '2.37.0' + } +} + +resource webSite_4pzZqR2OO 'Microsoft.Web/sites@2021-02-01' = { + name: 'backEnd-TEST' + location: 'westus' + identity: { + } + kind: 'app,linux' + properties: { + serverFarmId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-TEST/providers/Microsoft.Web/serverfarms/appServicePlan-TEST' + siteConfig: { + linuxFxVersion: 'dotnetcore|6.0' + alwaysOn: true + appCommandLine: '' + experiments: { + } + cors: { + allowedOrigins: [ + 'https://portal.azure.com' + 'https://ms.portal.azure.com' + ] + } + minTlsVersion: '1.2' + ftpsState: 'FtpsOnly' + } + httpsOnly: true + } +} + +resource applicationSettingsResource_vEe46o8Zn 'Microsoft.Web/sites/config@2021-02-01' = { + parent: webSite_4pzZqR2OO + name: 'appsettings' + properties: { + 'SCM_DO_BUILD_DURING_DEPLOYMENT': 'False' + 'ENABLE_ORYX_BUILD': 'True' + } +} + +output SERVICE_API_IDENTITY_PRINCIPAL_ID string = webSite_W5EweSXEq.identity.principalId diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL2/main.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL2/main.bicep index 5211bdb4ea9f5..8ab036a1810a9 100644 --- a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL2/main.bicep +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL2/main.bicep @@ -1,4 +1,4 @@ -targetScope = subscription +targetScope = 'subscription' @secure() @description('SQL Server administrator password') @@ -18,57 +18,8 @@ resource resourceGroup_I6QNkoPsb 'Microsoft.Resources/resourceGroups@2023-07-01' } } -resource appServicePlan_kjMZSF1FP 'Microsoft.Web/serverfarms@2021-02-01' = { - scope: resourceGroup_I6QNkoPsb - name: 'appServicePlan-TEST' - location: 'westus' - sku: { - name: 'B1' - } - properties: { - reserved: true - } -} - -resource keyVault_CRoMbemLF 'Microsoft.KeyVault/vaults@2023-02-01' = { - scope: resourceGroup_I6QNkoPsb - name: 'kv-TEST' - location: 'westus' - properties: { - tenantId: '00000000-0000-0000-0000-000000000000' - sku: { - name: 'standard' - family: 'A' - } - } -} - -resource keyVaultAddAccessPolicy_NWCGclP20 'Microsoft.KeyVault/vaults/accessPolicies@2023-02-01' = { - parent: keyVault_CRoMbemLF - name: 'add' - properties: { - accessPolicies: [ - { - tenantId: '00000000-0000-0000-0000-000000000000' - objectId: TestFrontEndWebSite.outputs.SERVICE_API_IDENTITY_PRINCIPAL_ID - permissions: { - secrets: [ - 'get' - 'list' - ] - } - } - ] - } -} - -module TestFrontEndWebSite './resources/TestFrontEndWebSite/TestFrontEndWebSite.bicep' = { - name: 'TestFrontEndWebSite' - scope: resourceGroup_I6QNkoPsb -} - -module TestCommonSqlDatabase './resources/TestCommonSqlDatabase/TestCommonSqlDatabase.bicep' = { - name: 'TestCommonSqlDatabase' +module rg_TEST './resources/rg_TEST/rg_TEST.bicep' = { + name: 'rg_TEST' scope: resourceGroup_I6QNkoPsb params: { sqlAdminPassword: sqlAdminPassword @@ -76,9 +27,4 @@ module TestCommonSqlDatabase './resources/TestCommonSqlDatabase/TestCommonSqlDat } } -module TestBackEndWebSite './resources/TestBackEndWebSite/TestBackEndWebSite.bicep' = { - name: 'TestBackEndWebSite' - scope: resourceGroup_I6QNkoPsb -} - -output SERVICE_API_IDENTITY_PRINCIPAL_ID string = TestFrontEndWebSite.outputs.SERVICE_API_IDENTITY_PRINCIPAL_ID +output SERVICE_API_IDENTITY_PRINCIPAL_ID string = rg_TEST.outputs.SERVICE_API_IDENTITY_PRINCIPAL_ID diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL2/resources/TestBackEndWebSite/TestBackEndWebSite.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL2/resources/TestBackEndWebSite/TestBackEndWebSite.bicep deleted file mode 100644 index 5bf70fec31e9f..0000000000000 --- a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL2/resources/TestBackEndWebSite/TestBackEndWebSite.bicep +++ /dev/null @@ -1,40 +0,0 @@ - -resource appServicePlan_kjMZSF1FP 'Microsoft.Web/serverfarms@2021-02-01' existing = { - name: 'appServicePlan_kjMZSF1FP' -} - -resource webSite_4pzZqR2OO 'Microsoft.Web/sites@2021-02-01' = { - name: 'backEnd-TEST' - location: 'westus' - identity: { - } - kind: 'app,linux' - properties: { - serverFarmId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-TEST/providers/Microsoft.Web/serverfarms/appServicePlan-TEST' - siteConfig: { - linuxFxVersion: 'dotnetcore|6.0' - alwaysOn: true - appCommandLine: '' - experiments: { - } - cors: { - allowedOrigins: [ - 'https://portal.azure.com' - 'https://ms.portal.azure.com' - ] - } - minTlsVersion: '1.2' - ftpsState: 'FtpsOnly' - } - httpsOnly: true - } -} - -resource applicationSettingsResource_vEe46o8Zn 'Microsoft.Web/sites/config@2021-02-01' = { - parent: webSite_4pzZqR2OO - name: 'appsettings' - properties: { - 'SCM_DO_BUILD_DURING_DEPLOYMENT': 'False' - 'ENABLE_ORYX_BUILD': 'True' - } -} diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL2/resources/TestCommonSqlDatabase/TestCommonSqlDatabase.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL2/resources/TestCommonSqlDatabase/TestCommonSqlDatabase.bicep deleted file mode 100644 index b6e644f6cc615..0000000000000 --- a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL2/resources/TestCommonSqlDatabase/TestCommonSqlDatabase.bicep +++ /dev/null @@ -1,115 +0,0 @@ -@secure() -@description('SQL Server administrator password') -param sqlAdminPassword string - -@secure() -@description('Application user password') -param appUserPassword string - - -resource keyVault_CRoMbemLF 'Microsoft.KeyVault/vaults@2023-02-01' existing = { - name: 'keyVault_CRoMbemLF' -} - -resource keyVaultSecret_NmXfhaHvM 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = { - parent: keyVault_CRoMbemLF - name: 'sqlAdminPassword-TEST' - properties: { - value: sqlAdminPassword - } -} - -resource keyVaultSecret_QRsiyFBMe 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = { - parent: keyVault_CRoMbemLF - name: 'appUserPassword-TEST' - properties: { - value: appUserPassword - } -} - -resource sqlServer_zjdvvB2wl 'Microsoft.Sql/servers@2022-08-01-preview' = { - name: 'sqlserver-TEST' - location: 'westus' - properties: { - administratorLogin: 'sqladmin' - administratorLoginPassword: sqlAdminPassword - version: '12.0' - minimalTlsVersion: '1.2' - publicNetworkAccess: 'Enabled' - } -} - -resource sqlDatabase_U7NzorRJT 'Microsoft.Sql/servers/databases@2022-08-01-preview' = { - parent: sqlServer_zjdvvB2wl - name: 'db-TEST' - location: 'westus' - properties: { - } -} - -resource keyVaultSecret_7eiFxkj0r 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = { - parent: keyVault_CRoMbemLF - name: 'connectionString-TEST' - properties: { - value: 'Server=${sqlServer_zjdvvB2wl.properties.fullyQualifiedDomainName}; Database=${sqlDatabase_U7NzorRJT.name}; User=appUser; Password=${appUserPassword}' - } -} - -resource sqlFirewallRule_eS4m8st65 'Microsoft.Sql/servers/firewallRules@2020-11-01-preview' = { - parent: sqlServer_zjdvvB2wl - name: 'firewallRule-TEST' - properties: { - startIpAddress: '0.0.0.1' - endIpAddress: '255.255.255.254' - } -} - -resource deploymentScript_3Zq2Pl8xa 'Microsoft.Resources/deploymentScripts@2020-10-01' = { - name: 'cliScript-TEST' - location: 'westus' - kind: 'AzureCLI' - properties: { - cleanupPreference: 'OnSuccess' - scriptContent: ''' -wget https://github.com/microsoft/go-sqlcmd/releases/download/v0.8.1/sqlcmd-v0.8.1-linux-x64.tar.bz2 -tar x -f sqlcmd-v0.8.1-linux-x64.tar.bz2 -C . -cat < ./initDb.sql -drop user ${APPUSERNAME} -go -create user ${APPUSERNAME} with password = '${APPUSERPASSWORD}' -go -alter role db_owner add member ${APPUSERNAME} -go -SCRIPT_END -./sqlcmd -S ${DBSERVER} -d ${DBNAME} -U ${SQLADMIN} -i ./initDb.sql''' - environmentVariables: [ - { - name: 'APPUSERNAME' - value: 'appUser' - } - { - name: 'APPUSERPASSWORD' - secureValue: '_p_.appUserPassword' - } - { - name: 'DBNAME' - value: '_p_.sqlDatabase_U7NzorRJT.name' - } - { - name: 'DBSERVER' - value: '_p_.sqlServer_zjdvvB2wl.properties.fullyQualifiedDomainName' - } - { - name: 'SQLCMDPASSWORD' - secureValue: '_p_.sqlAdminPassword' - } - { - name: 'SQLADMIN' - value: 'sqlAdmin' - } - ] - retentionInterval: 'PT1H' - timeout: 'PT5M' - azCliVersion: '2.37.0' - } -} diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL2/resources/TestFrontEndWebSite/TestFrontEndWebSite.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL2/resources/TestFrontEndWebSite/TestFrontEndWebSite.bicep deleted file mode 100644 index dc133defcbbe7..0000000000000 --- a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL2/resources/TestFrontEndWebSite/TestFrontEndWebSite.bicep +++ /dev/null @@ -1,67 +0,0 @@ - -resource appServicePlan_kjMZSF1FP 'Microsoft.Web/serverfarms@2021-02-01' existing = { - name: 'appServicePlan_kjMZSF1FP' -} - -resource keyVault_CRoMbemLF 'Microsoft.KeyVault/vaults@2023-02-01' existing = { - name: 'keyVault_CRoMbemLF' -} - -resource webSite_W5EweSXEq 'Microsoft.Web/sites@2021-02-01' = { - name: 'frontEnd-TEST' - location: 'westus' - identity: { - } - kind: 'app,linux' - properties: { - serverFarmId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-TEST/providers/Microsoft.Web/serverfarms/appServicePlan-TEST' - siteConfig: { - linuxFxVersion: 'node|18-lts' - alwaysOn: true - appCommandLine: './entrypoint.sh -o ./env-config.js && pm2 serve /home/site/wwwroot --no-daemon --spa' - experiments: { - } - cors: { - allowedOrigins: [ - 'https://portal.azure.com' - 'https://ms.portal.azure.com' - ] - } - minTlsVersion: '1.2' - ftpsState: 'FtpsOnly' - } - httpsOnly: true - } -} - -resource applicationSettingsResource_9BG7vUQd2 'Microsoft.Web/sites/config@2021-02-01' = { - parent: webSite_W5EweSXEq - name: 'appsettings' -} - -resource webSiteConfigLogs_giqxapQs0 'Microsoft.Web/sites/config@2021-02-01' = { - parent: webSite_W5EweSXEq - name: 'logs' - properties: { - applicationLogs: { - fileSystem: { - level: 'Verbose' - } - } - httpLogs: { - fileSystem: { - retentionInMb: 35 - retentionInDays: 1 - enabled: true - } - } - failedRequestsTracing: { - enabled: true - } - detailedErrorMessages: { - enabled: true - } - } -} - -output SERVICE_API_IDENTITY_PRINCIPAL_ID string = webSite_W5EweSXEq.identity.principalId diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL2/resources/rg_TEST/rg_TEST.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL2/resources/rg_TEST/rg_TEST.bicep new file mode 100644 index 0000000000000..ba408adc23da3 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL2/resources/rg_TEST/rg_TEST.bicep @@ -0,0 +1,248 @@ +@secure() +@description('SQL Server administrator password') +param sqlAdminPassword string + +@secure() +@description('Application user password') +param appUserPassword string + + +resource appServicePlan_kjMZSF1FP 'Microsoft.Web/serverfarms@2021-02-01' = { + name: 'appServicePlan-TEST' + location: 'westus' + sku: { + name: 'B1' + } + properties: { + reserved: true + } +} + +resource keyVault_CRoMbemLF 'Microsoft.KeyVault/vaults@2023-02-01' = { + name: 'kv-TEST' + location: 'westus' + properties: { + tenantId: '00000000-0000-0000-0000-000000000000' + sku: { + name: 'standard' + family: 'A' + } + } +} + +resource keyVaultAddAccessPolicy_NWCGclP20 'Microsoft.KeyVault/vaults/accessPolicies@2023-02-01' = { + parent: keyVault_CRoMbemLF + name: 'add' + properties: { + accessPolicies: [ + { + tenantId: '00000000-0000-0000-0000-000000000000' + objectId: SERVICE_API_IDENTITY_PRINCIPAL_ID + permissions: { + secrets: [ + 'get' + 'list' + ] + } + } + ] + } +} + +resource keyVaultSecret_NmXfhaHvM 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = { + parent: keyVault_CRoMbemLF + name: 'sqlAdminPassword-TEST' + properties: { + value: sqlAdminPassword + } +} + +resource keyVaultSecret_QRsiyFBMe 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = { + parent: keyVault_CRoMbemLF + name: 'appUserPassword-TEST' + properties: { + value: appUserPassword + } +} + +resource keyVaultSecret_7eiFxkj0r 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = { + parent: keyVault_CRoMbemLF + name: 'connectionString-TEST' + properties: { + value: 'Server=${sqlServer_zjdvvB2wl.properties.fullyQualifiedDomainName}; Database=${sqlDatabase_U7NzorRJT.name}; User=appUser; Password=${appUserPassword}' + } +} + +resource webSite_W5EweSXEq 'Microsoft.Web/sites@2021-02-01' = { + name: 'frontEnd-TEST' + location: 'westus' + identity: { + } + kind: 'app,linux' + properties: { + serverFarmId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-TEST/providers/Microsoft.Web/serverfarms/appServicePlan-TEST' + siteConfig: { + linuxFxVersion: 'node|18-lts' + alwaysOn: true + appCommandLine: './entrypoint.sh -o ./env-config.js && pm2 serve /home/site/wwwroot --no-daemon --spa' + experiments: { + } + cors: { + allowedOrigins: [ + 'https://portal.azure.com' + 'https://ms.portal.azure.com' + ] + } + minTlsVersion: '1.2' + ftpsState: 'FtpsOnly' + } + httpsOnly: true + } +} + +resource applicationSettingsResource_9BG7vUQd2 'Microsoft.Web/sites/config@2021-02-01' = { + parent: webSite_W5EweSXEq + name: 'appsettings' +} + +resource webSiteConfigLogs_giqxapQs0 'Microsoft.Web/sites/config@2021-02-01' = { + parent: webSite_W5EweSXEq + name: 'logs' + properties: { + applicationLogs: { + fileSystem: { + level: 'Verbose' + } + } + httpLogs: { + fileSystem: { + retentionInMb: 35 + retentionInDays: 1 + enabled: true + } + } + failedRequestsTracing: { + enabled: true + } + detailedErrorMessages: { + enabled: true + } + } +} + +resource sqlServer_zjdvvB2wl 'Microsoft.Sql/servers@2022-08-01-preview' = { + name: 'sqlserver-TEST' + location: 'westus' + properties: { + administratorLogin: 'sqladmin' + administratorLoginPassword: sqlAdminPassword + version: '12.0' + minimalTlsVersion: '1.2' + publicNetworkAccess: 'Enabled' + } +} + +resource sqlDatabase_U7NzorRJT 'Microsoft.Sql/servers/databases@2022-08-01-preview' = { + parent: sqlServer_zjdvvB2wl + name: 'db-TEST' + location: 'westus' + properties: { + } +} + +resource sqlFirewallRule_eS4m8st65 'Microsoft.Sql/servers/firewallRules@2020-11-01-preview' = { + parent: sqlServer_zjdvvB2wl + name: 'firewallRule-TEST' + properties: { + startIpAddress: '0.0.0.1' + endIpAddress: '255.255.255.254' + } +} + +resource deploymentScript_3Zq2Pl8xa 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: 'cliScript-TEST' + location: 'westus' + kind: 'AzureCLI' + properties: { + cleanupPreference: 'OnSuccess' + scriptContent: ''' +wget https://github.com/microsoft/go-sqlcmd/releases/download/v0.8.1/sqlcmd-v0.8.1-linux-x64.tar.bz2 +tar x -f sqlcmd-v0.8.1-linux-x64.tar.bz2 -C . +cat < ./initDb.sql +drop user ${APPUSERNAME} +go +create user ${APPUSERNAME} with password = '${APPUSERPASSWORD}' +go +alter role db_owner add member ${APPUSERNAME} +go +SCRIPT_END +./sqlcmd -S ${DBSERVER} -d ${DBNAME} -U ${SQLADMIN} -i ./initDb.sql''' + environmentVariables: [ + { + name: 'APPUSERNAME' + value: 'appUser' + } + { + name: 'APPUSERPASSWORD' + secureValue: '_p_.appUserPassword' + } + { + name: 'DBNAME' + value: '_p_.sqlDatabase_U7NzorRJT.name' + } + { + name: 'DBSERVER' + value: '_p_.sqlServer_zjdvvB2wl.properties.fullyQualifiedDomainName' + } + { + name: 'SQLCMDPASSWORD' + secureValue: '_p_.sqlAdminPassword' + } + { + name: 'SQLADMIN' + value: 'sqlAdmin' + } + ] + retentionInterval: 'PT1H' + timeout: 'PT5M' + azCliVersion: '2.37.0' + } +} + +resource webSite_4pzZqR2OO 'Microsoft.Web/sites@2021-02-01' = { + name: 'backEnd-TEST' + location: 'westus' + identity: { + } + kind: 'app,linux' + properties: { + serverFarmId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-TEST/providers/Microsoft.Web/serverfarms/appServicePlan-TEST' + siteConfig: { + linuxFxVersion: 'dotnetcore|6.0' + alwaysOn: true + appCommandLine: '' + experiments: { + } + cors: { + allowedOrigins: [ + 'https://portal.azure.com' + 'https://ms.portal.azure.com' + ] + } + minTlsVersion: '1.2' + ftpsState: 'FtpsOnly' + } + httpsOnly: true + } +} + +resource applicationSettingsResource_vEe46o8Zn 'Microsoft.Web/sites/config@2021-02-01' = { + parent: webSite_4pzZqR2OO + name: 'appsettings' + properties: { + 'SCM_DO_BUILD_DURING_DEPLOYMENT': 'False' + 'ENABLE_ORYX_BUILD': 'True' + } +} + +output SERVICE_API_IDENTITY_PRINCIPAL_ID string = webSite_W5EweSXEq.identity.principalId diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/main.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/main.bicep index a4ee26f642678..c7f95043cdce2 100644 --- a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/main.bicep +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/main.bicep @@ -1,4 +1,4 @@ -targetScope = subscription +targetScope = 'subscription' @secure() @description('SQL Server administrator password') @@ -18,11 +18,29 @@ resource resourceGroup_I6QNkoPsb 'Microsoft.Resources/resourceGroups@2023-07-01' } } -module TestWebSiteWithSqlBackEnd './resources/TestWebSiteWithSqlBackEnd/TestWebSiteWithSqlBackEnd.bicep' = { - name: 'TestWebSiteWithSqlBackEnd' +resource resourceGroup_I6QNkoPsb 'Microsoft.Resources/resourceGroups@2023-07-01' = { + name: 'rg-TEST' + location: 'westus' + tags: { + 'azd-env-name': 'TEST' + } +} + +module rg_TEST './resources/rg_TEST/rg_TEST.bicep' = { + name: 'rg_TEST' + scope: resourceGroup_I6QNkoPsb + params: { + sqlAdminPassword: sqlAdminPassword + } +} + +module rg_TEST './resources/rg_TEST/rg_TEST.bicep' = { + name: 'rg_TEST' scope: resourceGroup_I6QNkoPsb params: { sqlAdminPassword: sqlAdminPassword appUserPassword: appUserPassword } } + +output SERVICE_API_IDENTITY_PRINCIPAL_ID string = rg_TEST.outputs.SERVICE_API_IDENTITY_PRINCIPAL_ID diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/resources/TestBackEndWebSite/TestBackEndWebSite.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/resources/TestBackEndWebSite/TestBackEndWebSite.bicep deleted file mode 100644 index 5bf70fec31e9f..0000000000000 --- a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/resources/TestBackEndWebSite/TestBackEndWebSite.bicep +++ /dev/null @@ -1,40 +0,0 @@ - -resource appServicePlan_kjMZSF1FP 'Microsoft.Web/serverfarms@2021-02-01' existing = { - name: 'appServicePlan_kjMZSF1FP' -} - -resource webSite_4pzZqR2OO 'Microsoft.Web/sites@2021-02-01' = { - name: 'backEnd-TEST' - location: 'westus' - identity: { - } - kind: 'app,linux' - properties: { - serverFarmId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-TEST/providers/Microsoft.Web/serverfarms/appServicePlan-TEST' - siteConfig: { - linuxFxVersion: 'dotnetcore|6.0' - alwaysOn: true - appCommandLine: '' - experiments: { - } - cors: { - allowedOrigins: [ - 'https://portal.azure.com' - 'https://ms.portal.azure.com' - ] - } - minTlsVersion: '1.2' - ftpsState: 'FtpsOnly' - } - httpsOnly: true - } -} - -resource applicationSettingsResource_vEe46o8Zn 'Microsoft.Web/sites/config@2021-02-01' = { - parent: webSite_4pzZqR2OO - name: 'appsettings' - properties: { - 'SCM_DO_BUILD_DURING_DEPLOYMENT': 'False' - 'ENABLE_ORYX_BUILD': 'True' - } -} diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/resources/TestCommonSqlDatabase/TestCommonSqlDatabase.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/resources/TestCommonSqlDatabase/TestCommonSqlDatabase.bicep deleted file mode 100644 index b6e644f6cc615..0000000000000 --- a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/resources/TestCommonSqlDatabase/TestCommonSqlDatabase.bicep +++ /dev/null @@ -1,115 +0,0 @@ -@secure() -@description('SQL Server administrator password') -param sqlAdminPassword string - -@secure() -@description('Application user password') -param appUserPassword string - - -resource keyVault_CRoMbemLF 'Microsoft.KeyVault/vaults@2023-02-01' existing = { - name: 'keyVault_CRoMbemLF' -} - -resource keyVaultSecret_NmXfhaHvM 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = { - parent: keyVault_CRoMbemLF - name: 'sqlAdminPassword-TEST' - properties: { - value: sqlAdminPassword - } -} - -resource keyVaultSecret_QRsiyFBMe 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = { - parent: keyVault_CRoMbemLF - name: 'appUserPassword-TEST' - properties: { - value: appUserPassword - } -} - -resource sqlServer_zjdvvB2wl 'Microsoft.Sql/servers@2022-08-01-preview' = { - name: 'sqlserver-TEST' - location: 'westus' - properties: { - administratorLogin: 'sqladmin' - administratorLoginPassword: sqlAdminPassword - version: '12.0' - minimalTlsVersion: '1.2' - publicNetworkAccess: 'Enabled' - } -} - -resource sqlDatabase_U7NzorRJT 'Microsoft.Sql/servers/databases@2022-08-01-preview' = { - parent: sqlServer_zjdvvB2wl - name: 'db-TEST' - location: 'westus' - properties: { - } -} - -resource keyVaultSecret_7eiFxkj0r 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = { - parent: keyVault_CRoMbemLF - name: 'connectionString-TEST' - properties: { - value: 'Server=${sqlServer_zjdvvB2wl.properties.fullyQualifiedDomainName}; Database=${sqlDatabase_U7NzorRJT.name}; User=appUser; Password=${appUserPassword}' - } -} - -resource sqlFirewallRule_eS4m8st65 'Microsoft.Sql/servers/firewallRules@2020-11-01-preview' = { - parent: sqlServer_zjdvvB2wl - name: 'firewallRule-TEST' - properties: { - startIpAddress: '0.0.0.1' - endIpAddress: '255.255.255.254' - } -} - -resource deploymentScript_3Zq2Pl8xa 'Microsoft.Resources/deploymentScripts@2020-10-01' = { - name: 'cliScript-TEST' - location: 'westus' - kind: 'AzureCLI' - properties: { - cleanupPreference: 'OnSuccess' - scriptContent: ''' -wget https://github.com/microsoft/go-sqlcmd/releases/download/v0.8.1/sqlcmd-v0.8.1-linux-x64.tar.bz2 -tar x -f sqlcmd-v0.8.1-linux-x64.tar.bz2 -C . -cat < ./initDb.sql -drop user ${APPUSERNAME} -go -create user ${APPUSERNAME} with password = '${APPUSERPASSWORD}' -go -alter role db_owner add member ${APPUSERNAME} -go -SCRIPT_END -./sqlcmd -S ${DBSERVER} -d ${DBNAME} -U ${SQLADMIN} -i ./initDb.sql''' - environmentVariables: [ - { - name: 'APPUSERNAME' - value: 'appUser' - } - { - name: 'APPUSERPASSWORD' - secureValue: '_p_.appUserPassword' - } - { - name: 'DBNAME' - value: '_p_.sqlDatabase_U7NzorRJT.name' - } - { - name: 'DBSERVER' - value: '_p_.sqlServer_zjdvvB2wl.properties.fullyQualifiedDomainName' - } - { - name: 'SQLCMDPASSWORD' - secureValue: '_p_.sqlAdminPassword' - } - { - name: 'SQLADMIN' - value: 'sqlAdmin' - } - ] - retentionInterval: 'PT1H' - timeout: 'PT5M' - azCliVersion: '2.37.0' - } -} diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/resources/TestWebSiteWithSqlBackEnd/TestWebSiteWithSqlBackEnd.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/resources/TestWebSiteWithSqlBackEnd/TestWebSiteWithSqlBackEnd.bicep deleted file mode 100644 index 5de221b117742..0000000000000 --- a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/resources/TestWebSiteWithSqlBackEnd/TestWebSiteWithSqlBackEnd.bicep +++ /dev/null @@ -1,74 +0,0 @@ -@secure() -@description('SQL Server administrator password') -param sqlAdminPassword string - -@secure() -@description('Application user password') -param appUserPassword string - - -resource appServicePlan_kjMZSF1FP 'Microsoft.Web/serverfarms@2021-02-01' = { - name: 'appServicePlan-TEST' - location: 'westus' - sku: { - name: 'B1' - } - properties: { - reserved: true - } -} - -resource keyVault_CRoMbemLF 'Microsoft.KeyVault/vaults@2023-02-01' = { - name: 'kv-TEST' - location: 'westus' - tags: { - 'key': 'value' - } - properties: { - tenantId: '00000000-0000-0000-0000-000000000000' - sku: { - name: 'standard' - family: 'A' - } - } -} - -resource keyVaultAddAccessPolicy_NWCGclP20 'Microsoft.KeyVault/vaults/accessPolicies@2023-02-01' = { - parent: keyVault_CRoMbemLF - name: 'add' - properties: { - accessPolicies: [ - { - tenantId: '00000000-0000-0000-0000-000000000000' - objectId: TestFrontEndWebSite.outputs.SERVICE_API_IDENTITY_PRINCIPAL_ID - permissions: { - secrets: [ - 'get' - 'list' - ] - } - } - ] - } -} - -module TestFrontEndWebSite './resources/TestFrontEndWebSite/TestFrontEndWebSite.bicep' = { - name: 'TestFrontEndWebSite' - scope: resourceGroup_I6QNkoPsb -} - -module TestCommonSqlDatabase './resources/TestCommonSqlDatabase/TestCommonSqlDatabase.bicep' = { - name: 'TestCommonSqlDatabase' - scope: resourceGroup_I6QNkoPsb - params: { - sqlAdminPassword: sqlAdminPassword - appUserPassword: appUserPassword - } -} - -module TestBackEndWebSite './resources/TestBackEndWebSite/TestBackEndWebSite.bicep' = { - name: 'TestBackEndWebSite' - scope: resourceGroup_I6QNkoPsb -} - -output SERVICE_API_IDENTITY_PRINCIPAL_ID string = TestFrontEndWebSite.outputs.SERVICE_API_IDENTITY_PRINCIPAL_ID diff --git a/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/resources/rg_TEST/rg_TEST.bicep b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/resources/rg_TEST/rg_TEST.bicep new file mode 100644 index 0000000000000..6b4d6c508815d --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning/tests/Infrastructure/WebSiteUsingL3/resources/rg_TEST/rg_TEST.bicep @@ -0,0 +1,136 @@ +@secure() +@description('SQL Server administrator password') +param sqlAdminPassword string + +@secure() +@description('Application user password') +param appUserPassword string + + +resource appServicePlan_kjMZSF1FP 'Microsoft.Web/serverfarms@2021-02-01' = { + name: 'appServicePlan-TEST' + location: 'westus' + sku: { + name: 'B1' + } + properties: { + reserved: true + } +} + +resource keyVault_CRoMbemLF 'Microsoft.KeyVault/vaults@2023-02-01' = { + name: 'kv-TEST' + location: 'westus' + tags: { + 'key': 'value' + } + properties: { + tenantId: '00000000-0000-0000-0000-000000000000' + sku: { + name: 'standard' + family: 'A' + } + } +} + +resource keyVaultAddAccessPolicy_NWCGclP20 'Microsoft.KeyVault/vaults/accessPolicies@2023-02-01' = { + parent: keyVault_CRoMbemLF + name: 'add' + properties: { + accessPolicies: [ + { + tenantId: '00000000-0000-0000-0000-000000000000' + objectId: SERVICE_API_IDENTITY_PRINCIPAL_ID + permissions: { + secrets: [ + 'get' + 'list' + ] + } + } + ] + } +} + +resource keyVaultSecret_NmXfhaHvM 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = { + parent: keyVault_CRoMbemLF + name: 'sqlAdminPassword-TEST' + properties: { + value: sqlAdminPassword + } +} + +resource keyVaultSecret_QRsiyFBMe 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = { + parent: keyVault_CRoMbemLF + name: 'appUserPassword-TEST' + properties: { + value: appUserPassword + } +} + +resource keyVaultSecret_7eiFxkj0r 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = { + parent: keyVault_CRoMbemLF + name: 'connectionString-TEST' + properties: { + value: 'Server=${sqlServer_zjdvvB2wl.properties.fullyQualifiedDomainName}; Database=${sqlDatabase_U7NzorRJT.name}; User=appUser; Password=${appUserPassword}' + } +} + +resource webSite_W5EweSXEq 'Microsoft.Web/sites@2021-02-01' = { + name: 'frontEnd-TEST' + location: 'westus' + identity: { + } + kind: 'app,linux' + properties: { + serverFarmId: '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-TEST/providers/Microsoft.Web/serverfarms/appServicePlan-TEST' + siteConfig: { + linuxFxVersion: 'node|18-lts' + alwaysOn: true + appCommandLine: './entrypoint.sh -o ./env-config.js && pm2 serve /home/site/wwwroot --no-daemon --spa' + experiments: { + } + cors: { + allowedOrigins: [ + 'https://portal.azure.com' + 'https://ms.portal.azure.com' + ] + } + minTlsVersion: '1.2' + ftpsState: 'FtpsOnly' + } + httpsOnly: true + } +} + +resource applicationSettingsResource_9BG7vUQd2 'Microsoft.Web/sites/config@2021-02-01' = { + parent: webSite_W5EweSXEq + name: 'appsettings' +} + +resource webSiteConfigLogs_giqxapQs0 'Microsoft.Web/sites/config@2021-02-01' = { + parent: webSite_W5EweSXEq + name: 'logs' + properties: { + applicationLogs: { + fileSystem: { + level: 'Verbose' + } + } + httpLogs: { + fileSystem: { + retentionInMb: 35 + retentionInDays: 1 + enabled: true + } + } + failedRequestsTracing: { + enabled: true + } + detailedErrorMessages: { + enabled: true + } + } +} + +output SERVICE_API_IDENTITY_PRINCIPAL_ID string = webSite_W5EweSXEq.identity.principalId diff --git a/sdk/provisioning/Azure.Provisioning/tests/ProvisioningTests.cs b/sdk/provisioning/Azure.Provisioning/tests/ProvisioningTests.cs index d8ab7312a499f..aebf64d3ff315 100644 --- a/sdk/provisioning/Azure.Provisioning/tests/ProvisioningTests.cs +++ b/sdk/provisioning/Azure.Provisioning/tests/ProvisioningTests.cs @@ -6,6 +6,8 @@ using System; using System.IO; using System.Diagnostics; +using Azure.Core.TestFramework; +using Azure.Core.Tests.TestFramework; using Azure.Provisioning.AppService; using Azure.Provisioning.KeyVaults; using Azure.Provisioning.Sql; @@ -129,6 +131,44 @@ public void AppConfiguration() infra.Build(GetOutputPath()); } + [Test] + public void MultipleSubscriptions() + { + // ensure deterministic subscription names and directories + var random = new TestRandom(RecordedTestMode.Playback, 1); + var infra = new TestSubscriptionInfrastructure(); + var sub1 = new Subscription(infra, random.NewGuid()); + var sub2 = new Subscription(infra, random.NewGuid()); + _ = new ResourceGroup(infra, parent: sub1); + _ = new ResourceGroup(infra, parent: sub2); + infra.Build(GetOutputPath()); + } + + [Test] + public void OutputsSpanningModules() + { + var infra = new TestInfrastructure(); + var rg1 = new ResourceGroup(infra, "rg1"); + var rg2 = new ResourceGroup(infra, "rg2"); + var rg3 = new ResourceGroup(infra, "rg3"); + var appServicePlan = infra.AddAppServicePlan(parent: rg1); + WebSite frontEnd1 = new WebSite(infra, "frontEnd", appServicePlan, WebSiteRuntime.Node, "18-lts", parent: rg1); + + var output1 = frontEnd1.AddOutput(data => data.Identity.PrincipalId, "STORAGE_PRINCIPAL_ID"); + var output2 = frontEnd1.AddOutput(data => data.Location, "LOCATION"); + + KeyVault keyVault = infra.AddKeyVault(resourceGroup: rg1); + keyVault.AssignParameter(data => data.Location, new Parameter(output2)); + + WebSite frontEnd2 = new WebSite(infra, "frontEnd", appServicePlan, WebSiteRuntime.Node, "18-lts", parent: rg2); + + frontEnd2.AssignParameter(data => data.Identity.PrincipalId, new Parameter(output1)); + frontEnd2.AssignParameter(data => data.Location, new Parameter(output2)); + + _ = new TestFrontEndWebSite(infra, parent: rg3); + infra.Build(GetOutputPath()); + } + private static string GetGitRoot() { ProcessStartInfo startInfo = new ProcessStartInfo diff --git a/sdk/provisioning/Azure.Provisioning/tests/TestExtensions.cs b/sdk/provisioning/Azure.Provisioning/tests/TestExtensions.cs index d277b2111c1c3..2d322e530c850 100644 --- a/sdk/provisioning/Azure.Provisioning/tests/TestExtensions.cs +++ b/sdk/provisioning/Azure.Provisioning/tests/TestExtensions.cs @@ -3,14 +3,15 @@ using Azure.Provisioning.AppService; using Azure.Provisioning.KeyVaults; +using Azure.Provisioning.ResourceManager; namespace Azure.Provisioning.Tests { public static class TestExtensions { - public static TestFrontEndWebSite AddFrontEndWebSite(this IConstruct construct, KeyVault? keyVault = null, AppServicePlan? appServicePlan = null) + public static TestFrontEndWebSite AddFrontEndWebSite(this IConstruct construct, KeyVault? keyVault = null, AppServicePlan? appServicePlan = null, ResourceGroup? resourceGroup = null) { - return new TestFrontEndWebSite(construct, keyVault, appServicePlan); + return new TestFrontEndWebSite(construct, keyVault, appServicePlan, resourceGroup); } public static TestCommonSqlDatabase AddCommonSqlDatabase(this IConstruct construct, KeyVault? keyVault = null) diff --git a/sdk/provisioning/Azure.Provisioning/tests/TestFrontEndWebSite.cs b/sdk/provisioning/Azure.Provisioning/tests/TestFrontEndWebSite.cs index 30053d1eb4aa7..75cb43dd64a5c 100644 --- a/sdk/provisioning/Azure.Provisioning/tests/TestFrontEndWebSite.cs +++ b/sdk/provisioning/Azure.Provisioning/tests/TestFrontEndWebSite.cs @@ -9,14 +9,9 @@ namespace Azure.Provisioning.Tests { public class TestFrontEndWebSite : Construct { - public TestFrontEndWebSite(IConstruct scope, KeyVault? keyVault = null, AppServicePlan? appServicePlan = null) - : base(scope, nameof(TestFrontEndWebSite)) + public TestFrontEndWebSite(IConstruct scope, KeyVault? keyVault = null, AppServicePlan? appServicePlan = null, ResourceGroup? parent = null) + : base(scope, nameof(TestFrontEndWebSite), resourceGroup: parent ?? new ResourceGroup(scope, "rg")) { - if (ResourceGroup is null) - { - ResourceGroup = new ResourceGroup(scope, "rg"); - } - appServicePlan = UseExistingResource(appServicePlan, () => scope.AddAppServicePlan(ResourceGroup)); keyVault = UseExistingResource(keyVault, () => scope.AddKeyVault(ResourceGroup)); diff --git a/sdk/provisioning/Azure.Provisioning/tests/TestSubscriptionInfrastructure.cs b/sdk/provisioning/Azure.Provisioning/tests/TestSubscriptionInfrastructure.cs new file mode 100644 index 0000000000000..fd80ae167118f --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning/tests/TestSubscriptionInfrastructure.cs @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; + +namespace Azure.Provisioning.Tests +{ + public class TestSubscriptionInfrastructure : Infrastructure + { + public TestSubscriptionInfrastructure() + : base(ConstructScope.Tenant, Guid.Empty, Guid.Empty, "TEST") + { + } + } +} diff --git a/sdk/resourcemanager/Azure.ResourceManager/src/Common/Custom/Models/ManagedServiceIdentity.Serialization.cs b/sdk/resourcemanager/Azure.ResourceManager/src/Common/Custom/Models/ManagedServiceIdentity.Serialization.cs index 7189a9ad5a2f8..6f2a424278d69 100644 --- a/sdk/resourcemanager/Azure.ResourceManager/src/Common/Custom/Models/ManagedServiceIdentity.Serialization.cs +++ b/sdk/resourcemanager/Azure.ResourceManager/src/Common/Custom/Models/ManagedServiceIdentity.Serialization.cs @@ -87,27 +87,59 @@ BinaryData IPersistableModel.Write(ModelReaderWriterOpti private BinaryData SerializeBicep(ModelReaderWriterOptions options) { StringBuilder builder = new StringBuilder(); + BicepModelReaderWriterOptions bicepOptions = options as BicepModelReaderWriterOptions; + IDictionary propertyOverrides = null; + bool hasObjectOverride = bicepOptions != null && bicepOptions.ParameterOverrides.TryGetValue(this, out propertyOverrides); + bool hasPropertyOverride = false; + string propertyOverride = null; builder.AppendLine("{"); - if (Optional.IsDefined(PrincipalId)) + hasPropertyOverride = hasObjectOverride && propertyOverrides.TryGetValue(nameof(PrincipalId), out propertyOverride); + if (Optional.IsDefined(PrincipalId) || hasPropertyOverride) { builder.Append(" principalId:"); - builder.AppendLine($" '{PrincipalId.Value}'"); + if (hasPropertyOverride) + { + builder.AppendLine($" {propertyOverride}"); + } + else + { + builder.AppendLine($" '{PrincipalId.Value}'"); + } } - if (Optional.IsDefined(TenantId)) + + hasPropertyOverride = hasObjectOverride && propertyOverrides.TryGetValue(nameof(TenantId), out propertyOverride); + if (Optional.IsDefined(TenantId) || hasPropertyOverride) { builder.Append("tenantId:"); - builder.AppendLine($" '{TenantId.Value}'"); + if (hasPropertyOverride) + { + builder.AppendLine($" {propertyOverride}"); + } + else + { + builder.AppendLine($" '{TenantId.Value}'"); + } } - if (UserAssignedIdentities.Any()) + + hasPropertyOverride = hasObjectOverride && propertyOverrides.TryGetValue(nameof(UserAssignedIdentities), out propertyOverride); + if (UserAssignedIdentities.Any() || hasPropertyOverride) { builder.Append(" userAssignedIdentities:"); builder.AppendLine(" {"); - foreach (var item in UserAssignedIdentities) + if (hasPropertyOverride) { - builder.Append($" {item.Key}:"); - AppendChildObject(builder, item.Value, options, 4, false); + builder.AppendLine($" {propertyOverride}"); } + else + { + foreach (var item in UserAssignedIdentities) + { + builder.Append($" {item.Key}:"); + AppendChildObject(builder, item.Value, options, 4, false); + } + } + builder.AppendLine(" }"); }