Azure / Azure/bicep

Bicep abstraction for mixed-scope templates

Open
#12,533 0 comments 4 reactions 1 assignee Assigned to @alex-frankel View on GitHub
enhancement Needs: Upvote
Dominant language
Bicep
Stars
3.6k
Forks
830
Avg merge
1d 21m
Merged PRs (30d)
79

Description

**Is your feature request related to a problem? Please describe.**
When setting up complex deployments that span multiple scopes it can become a bit messy when you need to create new Bicep-files (modules) in order to switch scope.

I'll go through a small simplified example of what I mean.

The following `main.bicep` is deployed to the subscription scope, it creates a resource group and a module:

```bicep
// main.bicep
targetScope = 'subscription'

param resourceGroupName string
param storageAccountName string
param location string

resource rg 'Microsoft.Resources/resourceGroups@2023-07-01' = {
name: resourceGroupName
location: location
}

module storage 'modules/storage.bicep' = {
scope: rg
name: 'storage-module'
params: {
location: location
storageAccountName: storageAccountName
}
}
```

The module in `modules/storage.bicep` is deployed to the resource group scope, it creates a storage account:

```bicep
// modules/storage.bicep
param storageAccountName string
param location string

resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
name: storageAccountName
location: location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
}
```

This example only has one of these scope-jumps, but there could be more if you deploy at a higher scope.

_(**Note**: There could be other situations where you need to use a module, even though you might not like to do it. I don't have a simple example to illustrate this but it involves using values that are not known at compile-time, then you need to create a module and send the values (that are unknown at compile-time) into this module.)_

For the simple example above it would be convenient to have Bicep allow me to define everything in the same template, and then handle the creation of the required ARM-structure with sub-deployments for me underneath. I.e. Bicep should be able to abstract this for me.

**Describe the solution you'd like**
My idea is to instead create the example above as in the following `main.bicep`:

```bicep
// main.bicep
targetScope = 'subscription' // we still set the main scope, where we create the initial deployment

param resourceGroupName string
param storageAccountName string
param location string

resource rg 'Microsoft.Resources/resourceGroups@2023-07-01' = {
name: resourceGroupName
location: location
}

resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
scope: rg
name: storageAccountName
location: location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
}
```

The new thing here is that I can set a `scope` on the storage account resource. If I run `az bicep build -f main.bicep` for this file I should end up with:

```json
{
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"_generator": {
"name": "bicep",
"version": "0.23.1.45101",
"templateHash": "7528206918474232928"
}
},
"parameters": {
"resourceGroupName": {
"type": "string"
},
"storageAccountName": {
"type": "string"
},
"location": {
"type": "string"
}
},
"resources": [
{
"type": "Microsoft.Resources/resourceGroups",
"apiVersion": "2023-07-01",
"name": "[parameters('resourceGroupName')]",
"location": "[parameters('location')]"
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2022-09-01",
"name": "storage-module",
"resourceGroup": "[parameters('resourceGroupName')]",
"properties": {
"expressionEvaluationOptions": {
"scope": "inner"
},
"mode": "Incremental",
"parameters": {
"location": {
"value": "[parameters('location')]"
},
"storageAccountName": {
"value": "[parameters('storageAccountName')]"
}
},
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"_generator": {
"name": "bicep",
"version": "0.23.1.45101",
"templateHash": "16210097254981877065"
}
},
"parameters": {
"storageAccountName": {
"type": "string"
},
"location": {
"type": "string"
}
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2023-01-01",
"name": "[parameters('storageAccountName')]",
"location": "[parameters('location')]",
"sku": {
"name": "Standard_LRS"
},
"kind": "StorageV2"
}
]
}
},
"dependsOn": [
"[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('resourceGroupName'))]"
]
}
]
}
```

This is the same output that is generated for the current working solution presented above.

In this case Bicep has noticed that I am creating a mixed-scope deployment and created a nested deployment automatically.

I can't think of any obvious blockers for a feature like this, but please let me know if there are any!

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.