Reputation: 1024
I have a bicep module storageAccounts.bicep, which is creating multiple storage accounts and outputing an array of their names:
@description('Name of Environment')
param environment string
param storageAccounts array = [
{
name : 'api${environment}${uniqueString(resourceGroup().id)}'
skuName : 'Standard_LRS'
accessTier : 'Hot'
}
{
name : 'web${environment}${uniqueString(resourceGroup().id)}'
skuName : 'Standard_LRS'
accessTier : 'Hot'
}
]
resource storage_resource 'Microsoft.Storage/storageAccounts@2021-06-01' = [for storage in storageAccounts: {
name : storage.name
location : resourceGroup().location
sku:{
name : storage.skuName
}
kind : 'StorageV2'
properties:{
accessTier: storage.accessTier
allowBlobPublicAccess: true
minimumTlsVersion: 'TLS1_2'
supportsHttpsTrafficOnly: true
encryption:{
keySource: 'Microsoft.Storage'
services:{
blob:{
keyType: 'Account'
enabled: true
}
file:{
keyType: 'Account'
enabled: true
}
}
}
}
}]
output storageAccounts array = [for (name, i) in storageAccounts:{
storageAccountName : name
}]
I'm passing that array into another module to create a function app, and I'm trying to find a particular item in the array, something like this:
@description('array of storage account names')
param storageAccounts array
var storageAccountName = storagesAccounts.where(function(storageAccount) {
return storageAccount.name.startsWith('api')
})
resource storageAccount 'Microsoft.Storage/storageAccounts@2019-04-01' existing = {
name: storageAccountName
}
Is this something I can do? Or would I be better creating the storage accounts separately and passing the name directly?
Upvotes: 2
Views: 4545
Reputation: 9526
Bicep supports filter lambda function. In your case the code could look like this
var storageAccountName = first(filter(storagesAccounts, x => x.name.startsWith('api'))).name
More details in this blog, which I wrote when I had a similar problem to solve https://arinco.com.au/blog/azure-bicep-find-an-item-in-an-array-of-objects/
Upvotes: 4
Reputation: 11451
Currently its not supported to find the element of an array in bicep . There are Github Issues on the same Issue 1
and Issue 2
.
As a workaround you can just pass the storage account which you need to the module and use it then in the module i.e. nested template
.
I tested the below to create the two storage account and then referring the api
storage account in the 2nd template and storing the id of the storage account in a keyvault secret like below:
multiplestorage.bicep:
@description('Name of Environment')
param environment string = 'test'
param storageAccounts array = [
{
name : 'api${environment}${uniqueString(resourceGroup().id)}'
skuName : 'Standard_LRS'
accessTier : 'Hot'
}
{
name : 'web${environment}${uniqueString(resourceGroup().id)}'
skuName : 'Standard_LRS'
accessTier : 'Hot'
}
]
resource storage_resource 'Microsoft.Storage/storageAccounts@2021-06-01' = [for storage in storageAccounts: {
name : storage.name
location : resourceGroup().location
sku:{
name : 'Standard_LRS'
}
kind : 'StorageV2'
properties:{
accessTier: 'Hot'
allowBlobPublicAccess: true
minimumTlsVersion: 'TLS1_2'
supportsHttpsTrafficOnly: true
encryption:{
keySource: 'Microsoft.Storage'
services:{
blob:{
keyType: 'Account'
enabled: true
}
file:{
keyType: 'Account'
enabled: true
}
}
}
}
}]
output storageAccounts array = [for (name, i) in storageAccounts:{
storageAccountName : name
}]
module connectionString './functionapp.bicep'=[for (name,i) in storageAccounts :if(startsWith(storage_resource[i].name,'api')){
name: 'functionappNested${i}'
params: {
storageAccounts:storage_resource[i].name
}
}]
functionapp.bicep
param storageAccounts string
resource storageAccount 'Microsoft.Storage/storageAccounts@2019-04-01' existing = {
name: storageAccounts
}
resource keyVaultShared 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = {
name: 'keyvaulttest1234ans'
}
resource storageAccountConnectionString 'Microsoft.KeyVault/vaults/secrets@2021-06-01-preview' = {
parent:keyVaultShared
name: '${keyVaultShared.name}-test'
properties:{
contentType: 'Storage Account Connection String'
value: storageAccount.id
}
}
Output:
Note: Similarly you can pass the storage account name starting with web
to another nested template as module as use it for another resource.
Upvotes: 1