Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Write bicep into modules based on scope hierarchy rather than user constructs #42029

Merged
merged 35 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
635c7ec
Write bicep into modules based on scope hierarchy rather than user co…
JoshLove-msft Feb 16, 2024
54ad6d3
Clean up
JoshLove-msft Feb 16, 2024
b6a49f0
Merge branch 'feature/cdk' of https://github.com/Azure/azure-sdk-for-…
JoshLove-msft Feb 16, 2024
410f372
remove dead code
JoshLove-msft Feb 16, 2024
5c41e5a
Add override logic for ManagedService
JoshLove-msft Feb 16, 2024
c9add63
PR fb
JoshLove-msft Feb 16, 2024
fdd2d5e
deleted files
JoshLove-msft Feb 16, 2024
ee33dee
API
JoshLove-msft Feb 16, 2024
f5a7d2b
Fix getResources
JoshLove-msft Feb 16, 2024
16e0e5d
tests
JoshLove-msft Feb 16, 2024
78251ad
Fix outputs
JoshLove-msft Feb 16, 2024
778d52c
remove commented code
JoshLove-msft Feb 16, 2024
bd35f78
remove blank refdocs
JoshLove-msft Feb 16, 2024
725e73a
using
JoshLove-msft Feb 16, 2024
b934c99
Pass recursive as true
JoshLove-msft Feb 16, 2024
0bee48f
revert recursive change
JoshLove-msft Feb 16, 2024
8ec68ad
PR fb
JoshLove-msft Feb 17, 2024
613d506
pass true as recursive arg
JoshLove-msft Feb 17, 2024
925b313
Fix recursive call and don't mutate Parameter
JoshLove-msft Feb 17, 2024
ceceb89
API
JoshLove-msft Feb 17, 2024
beb046b
fix comments
JoshLove-msft Feb 17, 2024
9b82c38
readonly
JoshLove-msft Feb 17, 2024
2d4b7b0
add construct tests
JoshLove-msft Feb 17, 2024
dc25978
Fix enumeration
JoshLove-msft Feb 17, 2024
1521c9b
Add parameter and outputs tests
JoshLove-msft Feb 18, 2024
975fe8f
save
JoshLove-msft Feb 19, 2024
92dc0f5
update get parameters
m-nash Feb 20, 2024
7d6dc2e
update api
m-nash Feb 20, 2024
80cc65c
merge upstream feature/cdk
m-nash Feb 20, 2024
ec6c624
update after merge
m-nash Feb 20, 2024
84a4494
Fix outputs/parameters
JoshLove-msft Feb 20, 2024
499bf89
Merge branch 'module-reorganization' of https://github.com/JoshLove-m…
JoshLove-msft Feb 20, 2024
e6e32b7
avoid dupes
JoshLove-msft Feb 20, 2024
c7ffffe
fix test
JoshLove-msft Feb 20, 2024
1cd0b5a
api
JoshLove-msft Feb 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions sdk/provisioning/Azure.Provisioning/Azure.Provisioning.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ 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; } }
Expand Down Expand Up @@ -116,7 +116,7 @@ namespace Azure.Provisioning.AppService
{
public partial class AppServicePlan : Azure.Provisioning.Resource<Azure.ResourceManager.AppService.AppServicePlanData>
{
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<string, Azure.ResourceManager.AppService.AppServicePlanData>)) { }
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<string, Azure.ResourceManager.AppService.AppServicePlanData>)) { }
protected override Azure.Provisioning.Resource? FindParentInScope(Azure.Provisioning.IConstruct scope) { throw null; }
}
public static partial class AppServicesExtensions
Expand All @@ -125,7 +125,7 @@ public static partial class AppServicesExtensions
}
public partial class WebSite : Azure.Provisioning.Resource<Azure.ResourceManager.AppService.WebSiteData>
{
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<string, Azure.ResourceManager.AppService.WebSiteData>)) { }
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<string, Azure.ResourceManager.AppService.WebSiteData>)) { }
public void AddApplicationSetting(string key, Azure.Provisioning.Parameter value) { }
public void AddApplicationSetting(string key, string value) { }
public void AddLogConfig(string resourceName) { }
Expand Down Expand Up @@ -170,7 +170,7 @@ namespace Azure.Provisioning.ResourceManager
{
public partial class ResourceGroup : Azure.Provisioning.Resource<Azure.ResourceManager.Resources.ResourceGroupData>
{
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<string, Azure.ResourceManager.Resources.ResourceGroupData>)) { }
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<string, Azure.ResourceManager.Resources.ResourceGroupData>)) { }
protected override Azure.Provisioning.Resource? FindParentInScope(Azure.Provisioning.IConstruct scope) { throw null; }
}
public static partial class ResourceManagerExtensions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ 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; } }
Expand Down Expand Up @@ -116,7 +116,7 @@ namespace Azure.Provisioning.AppService
{
public partial class AppServicePlan : Azure.Provisioning.Resource<Azure.ResourceManager.AppService.AppServicePlanData>
{
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<string, Azure.ResourceManager.AppService.AppServicePlanData>)) { }
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<string, Azure.ResourceManager.AppService.AppServicePlanData>)) { }
protected override Azure.Provisioning.Resource? FindParentInScope(Azure.Provisioning.IConstruct scope) { throw null; }
}
public static partial class AppServicesExtensions
Expand All @@ -125,7 +125,7 @@ public static partial class AppServicesExtensions
}
public partial class WebSite : Azure.Provisioning.Resource<Azure.ResourceManager.AppService.WebSiteData>
{
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<string, Azure.ResourceManager.AppService.WebSiteData>)) { }
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<string, Azure.ResourceManager.AppService.WebSiteData>)) { }
public void AddApplicationSetting(string key, Azure.Provisioning.Parameter value) { }
public void AddApplicationSetting(string key, string value) { }
public void AddLogConfig(string resourceName) { }
Expand Down Expand Up @@ -170,7 +170,7 @@ namespace Azure.Provisioning.ResourceManager
{
public partial class ResourceGroup : Azure.Provisioning.Resource<Azure.ResourceManager.Resources.ResourceGroupData>
{
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<string, Azure.ResourceManager.Resources.ResourceGroupData>)) { }
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<string, Azure.ResourceManager.Resources.ResourceGroupData>)) { }
protected override Azure.Provisioning.Resource? FindParentInScope(Azure.Provisioning.IConstruct scope) { throw null; }
}
public static partial class ResourceManagerExtensions
Expand Down
32 changes: 23 additions & 9 deletions sdk/provisioning/Azure.Provisioning/src/Construct.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,20 @@ public abstract class Construct : IConstruct, IPersistableModel<Construct>
/// <param name="envName">The environment name to use. If not passed in will try to load from AZURE_ENV_NAME environment variable.</param>
/// <exception cref="ArgumentException"><paramref name="constructScope"/> is <see cref="ConstructScope.ResourceGroup"/> and <paramref name="scope"/> is null.</exception>
protected Construct(IConstruct? scope, string name, ConstructScope constructScope = ConstructScope.ResourceGroup, Guid? tenantId = null, Guid? subscriptionId = null, string? envName = null)
: this(scope, name, constructScope, tenantId, subscriptionId, envName, null, null, null)
{
}

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)
{
Expand All @@ -64,15 +78,15 @@ protected Construct(IConstruct? scope, string name, ConstructScope constructScop
_constructs = new List<IConstruct>();
_existingResources = new List<Resource>();
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;
Expand Down Expand Up @@ -103,7 +117,7 @@ public IEnumerable<Resource> GetResources(bool recursive = true)
IEnumerable<Resource> 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;
}
Expand All @@ -114,7 +128,7 @@ public IEnumerable<IConstruct> GetConstructs(bool recursive = true)
IEnumerable<IConstruct> 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;
}
Expand All @@ -125,7 +139,7 @@ public IEnumerable<Parameter> GetParameters(bool recursive = true)
IEnumerable<Parameter> result = _parameters;
if (recursive)
{
result = result.Concat(GetConstructs(false).SelectMany(c => c.GetParameters(false)));
result = result.Concat(GetResources(true).SelectMany(c => c.Parameters));
JoshLove-msft marked this conversation as resolved.
Show resolved Hide resolved
}
return result;
}
Expand All @@ -136,7 +150,7 @@ public IEnumerable<Output> GetOutputs(bool recursive = true)
IEnumerable<Output> 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;
}
Expand Down Expand Up @@ -167,7 +181,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)
Expand Down Expand Up @@ -244,7 +258,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}");
}
}

Expand Down
44 changes: 2 additions & 42 deletions sdk/provisioning/Azure.Provisioning/src/Infrastructure.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -33,46 +30,9 @@ public Infrastructure(ConstructScope constructScope = ConstructScope.Subscriptio
/// <param name="outputPath">Path to put the files.</param>
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<IConstruct>();
queue.Enqueue(this);
WriteConstructsByLevel(queue, outputPath);
}

private void WriteConstructsByLevel(Queue<IConstruct> 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);
}
}
}
57 changes: 57 additions & 0 deletions sdk/provisioning/Azure.Provisioning/src/ModuleConstruct.cs
Original file line number Diff line number Diff line change
@@ -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(),
};
}
}
}
Loading