Modules bicepparam parameter files independent of main.bicep
Is your feature request related to a problem? Please describe. Now that we can use param files we get closer to an abstraction of modules in regards to main.bicep. However we are still dealing with naming all the parameters in the main.bicep that are used the modules. If you have a big architecture with 20 components, your main.bicep referencing the modules will have a lot of parameters.
This still create a direct dependency on the module and prevents a proper solution when trying to use an ACR hosting the modules. If we assume that a bicep of an module is seen as an interface, we can dynamically insert the proper bicepparam files depending on environment (dev, acc, prod).
Describe the solution you'd like Lets assume we want to deploy a vnet and a lot of more components, but lets focus only on vnet as an example. We host our modules in an acr in azure and reference them in an main.bicep creating the architecture. We want to keep the main.bicep minimalistic for cleaner viewing but also for a decoupled situation.
vnet.bicep (br:exampleregistry.azurecr.io/bicep/modules/vnet:v1)
@description('Location for all resources.')
param location string = resourceGroup().location
@description('VNet name')
param vnetName string
@description('VNet prefix')
param vnetAddressPrefix string
@description('Subnet name')
param subnetName string
@description('Subnet prefix')
param subnetPrefix string
resource vnet 'Microsoft.Network/virtualNetworks@2023-04-01' = {
name: vnetName
location: location
properties: {
addressSpace: {
addressPrefixes: [
vnetAddressPrefix
]
}
subnets: [
{
name: subnetName
properties: {
addressPrefix: subnetPrefix
}
}
]
}
}
This is a file we keep in our project to create the architecture, so this is not hosted on the ACR for the modules. It does reference the hosted module vnet.dev.bicepparam
using 'br:exampleregistry.azurecr.io/bicep/modules/vnet:v1'
param vnetName = 'vnetname'
param vnetAddressPrefix = 'vnetAddressPrefix'
param subnetName = 'subnetname'
param subnetPrefix = 'subnetPrefix'
This is a file we keep in our specific architecture repo like main.bicep below. So in our azure devops repo we have a folder strcutre like iac/main.bicep iac/params/vnet.dev.bicepparam iac/params/vnet.acc.bicepparam iac/params/vnet.prd.bicepparam
main.bicep consisting of all the component for the architecture
@allowed([
'dev'
'acc'
'prd'
])
param environment string = 'dev'
var vnetParam object = 'iac/params/vnet.[env].bicepparam'
module vnet 'br:exampleregistry.azurecr.io/bicep/modules/vnet:v1' = {
name: 'vnetDeploy'
params: vnetParam
}
What we will achieve with this are a couple of things.
- Clean main.bicep for architecture
- Not one main.dev.bicepparam file that has a huge list of parameters that can run up
- bicep Param file per module instead of main.bicep
So in short, when referencing a module one can choose to name all the parameters within the definiton like this
module vnet 'br:exampleregistry.azurecr.io/bicep/modules/vnet:v1' = {
name: 'vnetDeploy'
params: {
param:param
param2:param2
}
}
or
module vnet 'br:exampleregistry.azurecr.io/bicep/modules/vnet:v1' = {
name: 'vnetDeploy'
params: vnetParam
}
in the end the top of you main.bicep architecture will have a lot of lines like this
var vnetParam object = 'iac/params/vnet.[env].bicepparam'
var functionParam object = 'iac/params/function.[env].bicepparam'
var storageParam object = 'iac/params/storage.[env].bicepparam'
var keyvaultParam object = 'iac/params/keyvault.[env].bicepparam'
or creating main.dev.bicepparam like this
using 'main.bicep'
var vnetParam object = 'iac/params/vnet.devbicepparam'
var functionParam object = 'iac/params/function.dev.bicepparam'
var storageParam object = 'iac/params/storage.dev.bicepparam'
var keyvaultParam object = 'iac/params/keyvault.dev.bicepparam'
and have the main.bicep have params defined like this
param vnetParam object
param functionParam object
param storageParam object
param keyvaultParam object
module vnet 'br:exampleregistry.azurecr.io/bicep/modules/vnet:v1' = {
name: 'vnetDeploy'
params: vnetParam
}
Coming from a .Net c# envrionment i think we need to think more in an interface kind of way when using modules and bicepparam files.
This also wil create a solution where can even host complete reference architectures in the ACR where we only have to supply the bicepparam files
This Design Proposal - Modular Parameters could be the solution for this request.
Your example above can be achieved like this;
// environment variables
env="dev"
// main.bicep
@description('Location for all resources.')
param location string = resourceGroup().location
@description('VNet name')
param vnetName string
@description('VNet prefix')
param vnetAddressPrefix string
@description('Subnet name')
param subnetName string
@description('Subnet prefix')
param subnetPrefix string
resource vnet 'Microsoft.Network/virtualNetworks@2023-04-01' = {
name: vnetName
location: location
properties: {
addressSpace: {
addressPrefixes: [
vnetAddressPrefix
]
}
subnets: [
{
name: subnetName
properties: {
addressPrefix: subnetPrefix
}
}
]
}
}
// main.dev.bicepparam
param vnetName = 'vnetDevName'
param vnetAddressPrefix = 'vnetDevAddressPrefix'
param subnetName = 'subnetDevName'
param subnetPrefix = 'subnetDevPrefix'
// main.acc.bicepparam
param vnetName = 'vnetAccName'
param vnetAddressPrefix = 'vnetAccAddressPrefix'
param subnetName = 'subnetAccName'
param subnetPrefix = 'subnetAccPrefix'
// main.prod.bicepparam
param vnetName = 'vnetProdName'
param vnetAddressPrefix = 'vnetProdAddressPrefix'
param subnetName = 'subnetProdName'
param subnetPrefix = 'subnetProdPrefix'
// main.bicepparam
using './main.bicep'
import { vnetName, vnetAddressPrefix, subnetName, subnetPrefix } from './main.${readEnvironmentVariable('env')}.bicepparam'
param location = 'westus'
n
Hi thank you for your link and suggestion. I just saw your proposal at the bicep community call as well.
Although the import line makes it a bit cleaner, imho there should not be a reason to need to import the parameters individually. If we really want to use modules within their power, the param file attached to the modules should be enough. Now you still need to create a hard dependency by naming the individual parameters that are present in the param bicep files.
In my proposal you can just import the file, the compiler should see that the imported param file follows the interface of referenced bicep file. I did hear you explain the reason why you want to name those specific parameters in case the module changes and all of the sudden the pipeline would fail. But again if we take a look how c# is doing this for decades. The fail might be wanted and if not, you can make nullable parameter. If you do create a change in the module that might create a fail, you need to increase the major version of the module.
I'm keeping a very interested eye into your proposal as I do believe we need to get something in order with bicep to make it even better! I think I need to see it in production to see if it might resolve my struggles as well.
hi @mennolaan,
we decided to take another look at our design proposal. I'll update the design proposal (and post a comment here) when we have an updated proposal with all valuable suggestions considered, like yours.
hi @mennolaan,
we decided to take another look at our design proposal. I'll update the design proposal (and post a comment here) when we have an updated proposal with all valuable suggestions considered, like yours.
Hi Engin, i was curious if there are any updates regarding the param files for modules? Cheers!
Currently in experimental, will close this out and track asks in the linked issue!