Skip to content

Commit

Permalink
Make AddDependency public and use project ref for ease of testing (#4…
Browse files Browse the repository at this point in the history
…3257)

* Make AddDependency public and use project ref for ease of testing

* Handle empty construct
  • Loading branch information
JoshLove-msft committed Apr 8, 2024
1 parent 0e30d39 commit 3f4a495
Show file tree
Hide file tree
Showing 18 changed files with 293 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ public abstract partial class Resource : System.ClientModel.Primitives.IPersista
protected object ResourceData { get { throw null; } }
public Azure.Provisioning.IConstruct Scope { get { throw null; } }
public string Version { get { throw null; } }
public void AddDependency(Azure.Provisioning.Resource resource) { }
public Azure.Provisioning.RoleAssignment AssignRole(Azure.Provisioning.RoleDefinition roleDefinition, System.Guid? principalId = default(System.Guid?), Azure.ResourceManager.Authorization.Models.RoleManagementPrincipalType? principalType = default(Azure.ResourceManager.Authorization.Models.RoleManagementPrincipalType?)) { throw null; }
protected virtual Azure.Provisioning.Resource? FindParentInScope(Azure.Provisioning.IConstruct scope) { throw null; }
protected virtual string GetAzureName(Azure.Provisioning.IConstruct scope, string resourceName) { throw null; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ public abstract partial class Resource : System.ClientModel.Primitives.IPersista
protected object ResourceData { get { throw null; } }
public Azure.Provisioning.IConstruct Scope { get { throw null; } }
public string Version { get { throw null; } }
public void AddDependency(Azure.Provisioning.Resource resource) { }
public Azure.Provisioning.RoleAssignment AssignRole(Azure.Provisioning.RoleDefinition roleDefinition, System.Guid? principalId = default(System.Guid?), Azure.ResourceManager.Authorization.Models.RoleManagementPrincipalType? principalType = default(Azure.ResourceManager.Authorization.Models.RoleManagementPrincipalType?)) { throw null; }
protected virtual Azure.Provisioning.Resource? FindParentInScope(Azure.Provisioning.IConstruct scope) { throw null; }
protected virtual string GetAzureName(Azure.Provisioning.IConstruct scope, string resourceName) { throw null; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ public abstract partial class Resource : System.ClientModel.Primitives.IPersista
protected object ResourceData { get { throw null; } }
public Azure.Provisioning.IConstruct Scope { get { throw null; } }
public string Version { get { throw null; } }
public void AddDependency(Azure.Provisioning.Resource resource) { }
public Azure.Provisioning.RoleAssignment AssignRole(Azure.Provisioning.RoleDefinition roleDefinition, System.Guid? principalId = default(System.Guid?), Azure.ResourceManager.Authorization.Models.RoleManagementPrincipalType? principalType = default(Azure.ResourceManager.Authorization.Models.RoleManagementPrincipalType?)) { throw null; }
protected virtual Azure.Provisioning.Resource? FindParentInScope(Azure.Provisioning.IConstruct scope) { throw null; }
protected virtual string GetAzureName(Azure.Provisioning.IConstruct scope, string resourceName) { throw null; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ public abstract partial class Resource : System.ClientModel.Primitives.IPersista
protected object ResourceData { get { throw null; } }
public Azure.Provisioning.IConstruct Scope { get { throw null; } }
public string Version { get { throw null; } }
public void AddDependency(Azure.Provisioning.Resource resource) { }
public Azure.Provisioning.RoleAssignment AssignRole(Azure.Provisioning.RoleDefinition roleDefinition, System.Guid? principalId = default(System.Guid?), Azure.ResourceManager.Authorization.Models.RoleManagementPrincipalType? principalType = default(Azure.ResourceManager.Authorization.Models.RoleManagementPrincipalType?)) { throw null; }
protected virtual Azure.Provisioning.Resource? FindParentInScope(Azure.Provisioning.IConstruct scope) { throw null; }
protected virtual string GetAzureName(Azure.Provisioning.IConstruct scope, string resourceName) { throw null; }
Expand Down
2 changes: 1 addition & 1 deletion sdk/provisioning/Azure.Provisioning/assets.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
"AssetsRepo": "Azure/azure-sdk-assets",
"AssetsRepoPrefixPath": "net",
"TagPrefix": "net/provisioning/Azure.Provisioning",
"Tag": "net/provisioning/Azure.Provisioning_6da137c164"
"Tag": "net/provisioning/Azure.Provisioning_3336ebb5fd"
}
17 changes: 13 additions & 4 deletions sdk/provisioning/Azure.Provisioning/src/ModuleInfrastructure.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ public void Write(string? outputPath = null)
outputPath ??= $".\\{GetType().Name}";
outputPath = Path.GetFullPath(outputPath);

WriteBicepFile(_rootConstruct!, outputPath);
WriteBicepFile(_rootConstruct, outputPath);
if (_rootConstruct == null)
{
return;
}

var queue = new Queue<ModuleConstruct>();
queue.Enqueue(_rootConstruct!);
Expand Down Expand Up @@ -190,16 +194,21 @@ private void WriteConstructsByLevel(Queue<ModuleConstruct> constructs, string ou
}
}

private string GetFilePath(ModuleConstruct construct, string 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");
string fileName = construct == null || 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)
private void WriteBicepFile(ModuleConstruct? construct, string outputPath)
{
using var stream = new FileStream(GetFilePath(construct, outputPath), FileMode.Create);
// just create an empty file if there is no construct
if (construct == null)
{
return;
}
#if NET6_0_OR_GREATER
stream.Write(construct.SerializeModule());
#else
Expand Down
6 changes: 5 additions & 1 deletion sdk/provisioning/Azure.Provisioning/src/Resource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ public abstract class Resource : IPersistableModel<Resource>

private IList<Resource> Dependencies { get; }

internal void AddDependency(Resource resource)
/// <summary>
/// Adds a dependency to the resource.
/// </summary>
/// <param name="resource">The dependency for this resource.</param>
public void AddDependency(Resource resource)
{
Dependencies.Add(resource);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
targetScope = 'resourceGroup'

@description('')
param location string = resourceGroup().location


resource storageAccount_7EH24TZOS 'Microsoft.Storage/storageAccounts@2022-09-01' = {
name: toLower(take('photoAcct${uniqueString(resourceGroup().id)}', 24))
location: location
sku: {
name: 'Premium_LRS'
}
kind: 'BlockBlobStorage'
properties: {
networkAcls: {
defaultAction: 'Deny'
}
}
}

resource storageAccount_GoC2YPRJs 'Microsoft.Storage/storageAccounts@2022-09-01' = {
dependsOn: [
storageAccount_7EH24TZOS
]
name: toLower(take('photoAcct2${uniqueString(resourceGroup().id)}', 24))
location: location
sku: {
name: 'Premium_LRS'
}
kind: 'BlockBlobStorage'
properties: {
networkAcls: {
defaultAction: 'Deny'
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
targetScope = 'subscription'


resource resourceGroup_I6QNkoPsb 'Microsoft.Resources/resourceGroups@2023-07-01' = {
name: 'rg-TEST'
location: 'westus'
tags: {
'azd-env-name': 'TEST'
}
}

module rg_TEST_module './resources/rg_TEST_module/rg_TEST_module.bicep' = {
name: 'rg_TEST_module'
scope: resourceGroup_I6QNkoPsb
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

resource userAssignedIdentity_AHWXCnFeG 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' existing = {
name: 'existingUserAssignedIdentity'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
targetScope = 'resourceGroup'

@description('')
param location string = resourceGroup().location

@description('')
param principalId string


resource storageAccount_7EH24TZOS 'Microsoft.Storage/storageAccounts@2022-09-01' = {
name: toLower(take('photoAcct${uniqueString(resourceGroup().id)}', 24))
location: location
sku: {
name: 'Premium_LRS'
}
kind: 'BlockBlobStorage'
properties: {
networkAcls: {
defaultAction: 'Deny'
}
}
}

resource blobService_7QL3qUuBS 'Microsoft.Storage/storageAccounts/blobServices@2022-09-01' = {
parent: storageAccount_7EH24TZOS
name: 'default'
properties: {
}
}

resource roleAssignment_NfInNFBlY 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
scope: storageAccount_7EH24TZOS
name: guid(storageAccount_7EH24TZOS.id, principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe'))
properties: {
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')
principalId: principalId
principalType: 'ServicePrincipal'
}
}

resource roleAssignment_cmAstwnTk 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
scope: storageAccount_7EH24TZOS
name: guid(storageAccount_7EH24TZOS.id, principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88'))
properties: {
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')
principalId: principalId
principalType: 'ServicePrincipal'
}
}

resource roleAssignment_4GhzPkC6K 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
scope: storageAccount_7EH24TZOS
name: guid(storageAccount_7EH24TZOS.id, '00000000-0000-0000-0000-000000000000', subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3'))
properties: {
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')
principalId: '00000000-0000-0000-0000-000000000000'
principalType: 'User'
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
targetScope = 'subscription'


resource resourceGroup_I6QNkoPsb 'Microsoft.Resources/resourceGroups@2023-07-01' = {
name: 'rg-TEST'
location: 'westus'
tags: {
'azd-env-name': 'TEST'
}
}

module rg_TEST_module './resources/rg_TEST_module/rg_TEST_module.bicep' = {
name: 'rg_TEST_module'
scope: resourceGroup_I6QNkoPsb
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@

resource storageAccount_ZnnWSenAP 'Microsoft.Storage/storageAccounts@2022-09-01' = {
name: toLower(take('photoAcct${uniqueString(resourceGroup().id)}', 24))
location: 'westus'
sku: {
name: 'Premium_LRS'
}
kind: 'BlockBlobStorage'
properties: {
networkAcls: {
defaultAction: 'Deny'
}
}
}

resource blobService_wAcYakiP0 'Microsoft.Storage/storageAccounts/blobServices@2022-09-01' = {
parent: storageAccount_ZnnWSenAP
name: 'default'
properties: {
}
}

resource roleAssignment_q3YvdxEC7 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
scope: storageAccount_ZnnWSenAP
name: guid(storageAccount_ZnnWSenAP.id, '00000000-0000-0000-0000-000000000000', subscriptionResourceId('00000000-0000-0000-0000-000000000000', 'Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe'))
properties: {
roleDefinitionId: subscriptionResourceId('00000000-0000-0000-0000-000000000000', 'Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')
principalId: '00000000-0000-0000-0000-000000000000'
principalType: 'ServicePrincipal'
}
}

resource roleAssignment_c4BGrZguw 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
scope: storageAccount_ZnnWSenAP
name: guid(storageAccount_ZnnWSenAP.id, '00000000-0000-0000-0000-000000000000', subscriptionResourceId('00000000-0000-0000-0000-000000000000', 'Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88'))
properties: {
roleDefinitionId: subscriptionResourceId('00000000-0000-0000-0000-000000000000', 'Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')
principalId: '00000000-0000-0000-0000-000000000000'
principalType: 'ServicePrincipal'
}
}

resource roleAssignment_YUoGSZS0y 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
scope: storageAccount_ZnnWSenAP
name: guid(storageAccount_ZnnWSenAP.id, '00000000-0000-0000-0000-000000000000', subscriptionResourceId('00000000-0000-0000-0000-000000000000', 'Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3'))
properties: {
roleDefinitionId: subscriptionResourceId('00000000-0000-0000-0000-000000000000', 'Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')
principalId: '00000000-0000-0000-0000-000000000000'
principalType: 'User'
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
targetScope = 'resourceGroup'

@description('')
param location string = resourceGroup().location


resource storageAccount_7EH24TZOS 'Microsoft.Storage/storageAccounts@2022-09-01' = {
name: toLower(take('photoAcct${uniqueString(resourceGroup().id)}', 24))
location: location
sku: {
name: 'Premium_LRS'
}
kind: 'BlockBlobStorage'
properties: {
networkAcls: {
defaultAction: 'Deny'
}
}
}

resource blobService_7QL3qUuBS 'Microsoft.Storage/storageAccounts/blobServices@2022-09-01' = {
parent: storageAccount_7EH24TZOS
name: 'default'
properties: {
}
}

resource roleAssignment_Xx3s4qhkk 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
scope: storageAccount_7EH24TZOS
name: guid(storageAccount_7EH24TZOS.id, '00000000-0000-0000-0000-000000000000', subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe'))
properties: {
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')
principalId: '00000000-0000-0000-0000-000000000000'
principalType: 'ServicePrincipal'
}
}

resource roleAssignment_LfCpykUe9 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
scope: storageAccount_7EH24TZOS
name: guid(storageAccount_7EH24TZOS.id, '00000000-0000-0000-0000-000000000000', subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88'))
properties: {
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')
principalId: '00000000-0000-0000-0000-000000000000'
principalType: 'ServicePrincipal'
}
}

resource roleAssignment_4GhzPkC6K 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
scope: storageAccount_7EH24TZOS
name: guid(storageAccount_7EH24TZOS.id, '00000000-0000-0000-0000-000000000000', subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3'))
properties: {
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')
principalId: '00000000-0000-0000-0000-000000000000'
principalType: 'User'
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
targetScope = 'resourceGroup'

@description('')
param location string = resourceGroup().location


resource userAssignedIdentity_gswVmGJeD 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
name: toLower(take('useridentity${uniqueString(resourceGroup().id)}', 24))
location: location
properties: {
}
}
21 changes: 21 additions & 0 deletions sdk/provisioning/Azure.Provisioning/tests/ProvisioningTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,27 @@ public async Task UserAssignedIdentities()
await ValidateBicepAsync(interactiveMode: true);
}

[RecordedTest]
public async Task DependentResources()
{
TestInfrastructure infra = new TestInfrastructure(configuration: new Configuration { UseInteractiveMode = true });
var sa1 = infra.AddStorageAccount(name: "photoAcct", sku: StorageSkuName.PremiumLrs, kind: StorageKind.BlockBlobStorage);
var sa2 = infra.AddStorageAccount(name: "photoAcct2", sku: StorageSkuName.PremiumLrs, kind: StorageKind.BlockBlobStorage);
sa2.AddDependency(sa1);

infra.Build(GetOutputPath());

await ValidateBicepAsync(interactiveMode: true);
}

[RecordedTest]
public async Task EmptyConstructDoesNotThrow()
{
TestInfrastructure infra = new TestInfrastructure();
infra.Build(GetOutputPath());
await ValidateBicepAsync();
}

[RecordedTest]
public async Task ExistingUserAssignedIdentityResource()
{
Expand Down
2 changes: 1 addition & 1 deletion sdk/provisioning/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
</PropertyGroup>

<ItemGroup Condition="'$(AssemblyName)' != 'Azure.Provisioning'">
<PackageReference Include="Azure.Provisioning" />
<ProjectReference Include="../../Azure.Provisioning/src/Azure.Provisioning.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down

0 comments on commit 3f4a495

Please sign in to comment.