Skip to content

Commit

Permalink
Lexically scoped child resources
Browse files Browse the repository at this point in the history
Fixes: Azure#1363

This change add support for lexical scoping/nesting of child resources.
That it, for a resource type: `My.RP/someType@2020-01-01` there's now a
simplified syntax for including a resource:
`My.RP/someType/childType@2020-01-01` inside the body of the parent.

This syntax also allows simplication of the type name of the child,
limits its scope/visibility and implies an automatic `dependsOn` to the
parent resource. The goal is to be the most idiomatic way to declare
multiple resources to be deployed with a parent/child/grandchild/etc
relationship.

This also includes the new "nested resource access" operator which
allows lookup of a nested resource:

```
output someOutput string = parent:child.properties.size
``
  • Loading branch information
rynowak committed Mar 1, 2021
1 parent 5e3c56e commit d063a4e
Show file tree
Hide file tree
Showing 61 changed files with 3,354 additions and 575 deletions.
477 changes: 477 additions & 0 deletions src/Bicep.Core.IntegrationTests/NestedResourceTests.cs

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/Bicep.Core.Samples/DataSets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ public static class DataSets

public static DataSet Outputs_CRLF => CreateDataSet();

public static DataSet NestedResources_LF => CreateDataSet();

public static DataSet Parameters_CRLF => CreateDataSet();

public static DataSet Parameters_LF => CreateDataSet();
Expand Down
68 changes: 68 additions & 0 deletions src/Bicep.Core.Samples/Files/NestedResources_LF/main.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
resource basicParent 'My.Rp/parentType@2020-12-01' = {
name: 'basicParent'
properties: {
size: 'large'
}

resource basicChild 'childType' = {
name: 'basicChild'
properties: {
size: basicParent.properties.large
style: 'cool'
}

resource basicGrandchild 'grandchildType' = {
name: 'basicGrandchild'
properties: {
size: basicParent.properties.size
style: basicChild.properties.style
}
}
}

resource basicSibling 'childType' = {
name: 'basicSibling'
properties: {
size: basicParent.properties.size
style: basicChild:basicGrandchild.properties.style
}
}
}

output referenceBasicChild string = basicParent:basicChild.properties.size
output referenceBasicGrandchild string = basicParent:basicChild:basicGrandchild.properties.style

resource existingParent 'My.Rp/parentType@2020-12-01' existing = {
name: 'existingParent'

resource existingChild 'childType' existing = {
name: 'existingChild'

resource existingGrandchild 'grandchildType' = {
name: 'existingGrandchild'
properties: {
size: existingParent.properties.size
style: existingChild.properties.style
}
}
}
}

param createParent bool
param createChild bool
param createGrandchild bool
resource conditionParent 'My.Rp/parentType@2020-12-01' = if (createParent) {
name: 'conditionParent'

resource conditionChild 'childType' = if (createChild) {
name: 'conditionChild'

resource conditionGrandchild 'grandchildType' = if (createGrandchild) {
name: 'conditionGrandchild'
properties: {
size: conditionParent.properties.size
style: conditionChild.properties.style
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
resource basicParent 'My.Rp/parentType@2020-12-01' = {
//@[21:50) [BCP081 (Warning)] Resource type "My.Rp/parentType@2020-12-01" does not have types available. |'My.Rp/parentType@2020-12-01'|
name: 'basicParent'
properties: {
size: 'large'
}

resource basicChild 'childType' = {
//@[22:33) [BCP081 (Warning)] Resource type "My.Rp/parentType/childType@2020-12-01" does not have types available. |'childType'|
name: 'basicChild'
properties: {
size: basicParent.properties.large
style: 'cool'
}

resource basicGrandchild 'grandchildType' = {
//@[29:45) [BCP081 (Warning)] Resource type "My.Rp/parentType/childType/grandchildType@2020-12-01" does not have types available. |'grandchildType'|
name: 'basicGrandchild'
properties: {
size: basicParent.properties.size
style: basicChild.properties.style
}
}
}

resource basicSibling 'childType' = {
//@[24:35) [BCP081 (Warning)] Resource type "My.Rp/parentType/childType@2020-12-01" does not have types available. |'childType'|
name: 'basicSibling'
properties: {
size: basicParent.properties.size
style: basicChild:basicGrandchild.properties.style
}
}
}

output referenceBasicChild string = basicParent:basicChild.properties.size
output referenceBasicGrandchild string = basicParent:basicChild:basicGrandchild.properties.style

resource existingParent 'My.Rp/parentType@2020-12-01' existing = {
//@[24:53) [BCP081 (Warning)] Resource type "My.Rp/parentType@2020-12-01" does not have types available. |'My.Rp/parentType@2020-12-01'|
name: 'existingParent'

resource existingChild 'childType' existing = {
//@[25:36) [BCP081 (Warning)] Resource type "My.Rp/parentType/childType@2020-12-01" does not have types available. |'childType'|
name: 'existingChild'

resource existingGrandchild 'grandchildType' = {
//@[32:48) [BCP081 (Warning)] Resource type "My.Rp/parentType/childType/grandchildType@2020-12-01" does not have types available. |'grandchildType'|
name: 'existingGrandchild'
properties: {
size: existingParent.properties.size
style: existingChild.properties.style
}
}
}
}

param createParent bool
param createChild bool
param createGrandchild bool
resource conditionParent 'My.Rp/parentType@2020-12-01' = if (createParent) {
//@[25:54) [BCP081 (Warning)] Resource type "My.Rp/parentType@2020-12-01" does not have types available. |'My.Rp/parentType@2020-12-01'|
name: 'conditionParent'

resource conditionChild 'childType' = if (createChild) {
//@[26:37) [BCP081 (Warning)] Resource type "My.Rp/parentType/childType@2020-12-01" does not have types available. |'childType'|
name: 'conditionChild'

resource conditionGrandchild 'grandchildType' = if (createGrandchild) {
//@[33:49) [BCP081 (Warning)] Resource type "My.Rp/parentType/childType/grandchildType@2020-12-01" does not have types available. |'grandchildType'|
name: 'conditionGrandchild'
properties: {
size: conditionParent.properties.size
style: conditionChild.properties.style
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
resource basicParent 'My.Rp/parentType@2020-12-01' = {
name: 'basicParent'
properties: {
size: 'large'
}

resource basicChild 'childType' = {
name: 'basicChild'
properties: {
size: basicParent.properties.large
style: 'cool'
}

resource basicGrandchild 'grandchildType' = {
name: 'basicGrandchild'
properties: {
size: basicParent.properties.size
style: basicChild.properties.style
}
}
}

resource basicSibling 'childType' = {
name: 'basicSibling'
properties: {
size: basicParent.properties.size
style: basicChild:basicGrandchild.properties.style
}
}
}

output referenceBasicChild string = basicParent:basicChild.properties.size
output referenceBasicGrandchild string = basicParent:basicChild:basicGrandchild.properties.style

resource existingParent 'My.Rp/parentType@2020-12-01' existing = {
name: 'existingParent'

resource existingChild 'childType' existing = {
name: 'existingChild'

resource existingGrandchild 'grandchildType' = {
name: 'existingGrandchild'
properties: {
size: existingParent.properties.size
style: existingChild.properties.style
}
}
}
}

param createParent bool
param createChild bool
param createGrandchild bool
resource conditionParent 'My.Rp/parentType@2020-12-01' = if (createParent) {
name: 'conditionParent'

resource conditionChild 'childType' = if (createChild) {
name: 'conditionChild'

resource conditionGrandchild 'grandchildType' = if (createGrandchild) {
name: 'conditionGrandchild'
properties: {
size: conditionParent.properties.size
style: conditionChild.properties.style
}
}
}
}
120 changes: 120 additions & 0 deletions src/Bicep.Core.Samples/Files/NestedResources_LF/main.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"createParent": {
"type": "bool"
},
"createChild": {
"type": "bool"
},
"createGrandchild": {
"type": "bool"
}
},
"functions": [],
"resources": [
{
"type": "My.Rp/parentType/childType/grandchildType",
"apiVersion": "2020-12-01",
"name": "[format('{0}/{1}/{2}', 'basicParent', 'basicChild', 'basicGrandchild')]",
"properties": {
"size": "[reference(resourceId('My.Rp/parentType', 'basicParent')).size]",
"style": "[reference(resourceId('My.Rp/parentType/childType', split(format('{0}/{1}', 'basicParent', 'basicChild'), '/')[0], split(format('{0}/{1}', 'basicParent', 'basicChild'), '/')[1])).style]"
},
"dependsOn": [
"[resourceId('My.Rp/parentType/childType', split(format('{0}/{1}', 'basicParent', 'basicChild'), '/')[0], split(format('{0}/{1}', 'basicParent', 'basicChild'), '/')[1])]",
"[resourceId('My.Rp/parentType', 'basicParent')]"
]
},
{
"type": "My.Rp/parentType/childType",
"apiVersion": "2020-12-01",
"name": "[format('{0}/{1}', 'basicParent', 'basicChild')]",
"properties": {
"size": "[reference(resourceId('My.Rp/parentType', 'basicParent')).large]",
"style": "cool"
},
"dependsOn": [
"[resourceId('My.Rp/parentType', 'basicParent')]"
]
},
{
"type": "My.Rp/parentType/childType",
"apiVersion": "2020-12-01",
"name": "[format('{0}/{1}', 'basicParent', 'basicSibling')]",
"properties": {
"size": "[reference(resourceId('My.Rp/parentType', 'basicParent')).size]",
"style": "[reference(resourceId('My.Rp/parentType/childType/grandchildType', split(format('{0}/{1}/{2}', 'basicParent', 'basicChild', 'basicGrandchild'), '/')[0], split(format('{0}/{1}/{2}', 'basicParent', 'basicChild', 'basicGrandchild'), '/')[1], split(format('{0}/{1}/{2}', 'basicParent', 'basicChild', 'basicGrandchild'), '/')[2])).style]"
},
"dependsOn": [
"[resourceId('My.Rp/parentType/childType', split(format('{0}/{1}', 'basicParent', 'basicChild'), '/')[0], split(format('{0}/{1}', 'basicParent', 'basicChild'), '/')[1])]",
"[resourceId('My.Rp/parentType', 'basicParent')]"
]
},
{
"type": "My.Rp/parentType/childType/grandchildType",
"apiVersion": "2020-12-01",
"name": "[format('{0}/{1}/{2}', 'existingParent', 'existingChild', 'existingGrandchild')]",
"properties": {
"size": "[reference(resourceId('My.Rp/parentType', 'existingParent'), '2020-12-01').size]",
"style": "[reference(resourceId('My.Rp/parentType/childType', split(format('{0}/{1}', 'existingParent', 'existingChild'), '/')[0], split(format('{0}/{1}', 'existingParent', 'existingChild'), '/')[1]), '2020-12-01').style]"
},
"dependsOn": []
},
{
"condition": "[and(and(parameters('createParent'), parameters('createChild')), parameters('createGrandchild'))]",
"type": "My.Rp/parentType/childType/grandchildType",
"apiVersion": "2020-12-01",
"name": "[format('{0}/{1}/{2}', 'conditionParent', 'conditionChild', 'conditionGrandchild')]",
"properties": {
"size": "[reference(resourceId('My.Rp/parentType', 'conditionParent')).size]",
"style": "[reference(resourceId('My.Rp/parentType/childType', split(format('{0}/{1}', 'conditionParent', 'conditionChild'), '/')[0], split(format('{0}/{1}', 'conditionParent', 'conditionChild'), '/')[1])).style]"
},
"dependsOn": [
"[resourceId('My.Rp/parentType/childType', split(format('{0}/{1}', 'conditionParent', 'conditionChild'), '/')[0], split(format('{0}/{1}', 'conditionParent', 'conditionChild'), '/')[1])]",
"[resourceId('My.Rp/parentType', 'conditionParent')]"
]
},
{
"condition": "[and(parameters('createParent'), parameters('createChild'))]",
"type": "My.Rp/parentType/childType",
"apiVersion": "2020-12-01",
"name": "[format('{0}/{1}', 'conditionParent', 'conditionChild')]",
"dependsOn": [
"[resourceId('My.Rp/parentType', 'conditionParent')]"
]
},
{
"type": "My.Rp/parentType",
"apiVersion": "2020-12-01",
"name": "basicParent",
"properties": {
"size": "large"
}
},
{
"condition": "[parameters('createParent')]",
"type": "My.Rp/parentType",
"apiVersion": "2020-12-01",
"name": "conditionParent"
}
],
"outputs": {
"referenceBasicChild": {
"type": "string",
"value": "[reference(resourceId('My.Rp/parentType/childType', split(format('{0}/{1}', 'basicParent', 'basicChild'), '/')[0], split(format('{0}/{1}', 'basicParent', 'basicChild'), '/')[1])).size]"
},
"referenceBasicGrandchild": {
"type": "string",
"value": "[reference(resourceId('My.Rp/parentType/childType/grandchildType', split(format('{0}/{1}/{2}', 'basicParent', 'basicChild', 'basicGrandchild'), '/')[0], split(format('{0}/{1}/{2}', 'basicParent', 'basicChild', 'basicGrandchild'), '/')[1], split(format('{0}/{1}/{2}', 'basicParent', 'basicChild', 'basicGrandchild'), '/')[2])).style]"
}
},
"metadata": {
"_generator": {
"name": "bicep",
"version": "dev",
"templateHash": "3280919504232588082"
}
}
}
Loading

0 comments on commit d063a4e

Please sign in to comment.