How to reference an object in an array of objects using Bicep - azure

I am trying to output the referenceId of each subnet in a module that creates a virtual network with 4 subnets. I can get the first one, [0], but when I try output the others, [1], [2], [3] the deployment fails and throws the error:
The language expression property array index "1" is out of bounds
Below is the code to create the virtualNetwork and the subnets:
resource virtualNetwork 'Microsoft.Network/virtualNetworks#2018-11-01' = {
name: vNetName
location: location
tags: tags
properties: {
addressSpace: {
addressPrefixes: [
addressPrefix
]
}
subnets: subnets
}
}
subnets is a variable of type array:
var subnets = [
{
name: mgmtSubnetName
properties: {
addressPrefix: mgmtSubnetAddressPrefix
}
}
{
name: intSubnetName
properties: {
addressPrefix: intSubnetAddressPrefix
}
}
{
name: extSubnetName
properties: {
addressPrefix: extSubnetAddressPrefix
}
}
{
name: vdmsSubnetName
properties: {
addressPrefix: vdmsSubnetAddressPrefix
}
}
]
When I use the output line below, it returns and array that has 4 objects...one for each subnet created:
output subnets array = virtualNetwork.properties.subnets
Each object has the format below:
{
"name":"<value>",
"id":"<value>",
"etag":"<value>",
"properties":{
"provisioningState":"Succeeded",
"addressPrefix":"<value>",
"ipConfigurations":[
{
"id":"<value>"
}
],
"delegations":[]
},
"type":"Microsoft.Network/virtualNetworks/subnets"
}
When I use the output line below, it returns the first object in the subnets array:
output subnet1 object = virtualNetwork.properties.subnets[0]
When I use the output line below, it returns the resourceId of the first subnet:
output subnet1 string = virtualNetwork.properties.subnets[0].id
I am unable to retrieve the other objects in the array using indexes 1, 2, or 3.
I have also tried the resourceId function (example below) but the behavior is exactly the same for indexes 1, 2, or 3:
output subnet1Id string = resourceId('Microsoft.Network/VirtualNetworks/subnets', name, subnets[0].name)

You can use the below bicep template to deploy the vnet and subnets and output the subnets and subnet id's like below :
var subnets = [
{
name: 'vm-subnet'
properties: {
addressPrefix:'10.0.0.0/24'
}
}
{
name: 'webapp-subnet'
properties: {
addressPrefix:'10.0.1.0/24'
}
}
{
name: 'appgw-subnet'
properties: {
addressPrefix:'10.0.2.0/24'
}
}
{
name: 'bastion-subnet'
properties: {
addressPrefix:'10.0.3.0/24'
}
}
]
resource virtualNetwork 'Microsoft.Network/virtualNetworks#2018-11-01' = {
name: 'ansuman-vnet'
location: 'east us'
properties: {
addressSpace: {
addressPrefixes: [
'10.0.0.0/16'
]
}
subnets: subnets
}
}
output subnets array = [for (name, i) in subnets :{
subnets : virtualNetwork.properties.subnets[i]
}]
output subnetids array = [for (name, i) in subnets :{
subnets : virtualNetwork.properties.subnets[i].id
}]
output subnetappgw string = virtualNetwork.properties.subnets[2].id
output webappsubnet object = virtualNetwork.properties.subnets[1]
Outputs:
Note: I am using the latest Bicep version i.e. Bicep CLI version 0.4.1124

Related

How to add existing route table to subnet

I am new to bicep and I am trying to attach an existing UDR named "udr-test" to 2 subnets, unfortunately with no luck.
This is my template that work fine but without UDR configuration:
var addressSpace = [
'10.0.0.0/16'
]
var subnets = [
{
name: 'Subnet1'
subnetPrefix: '10.0.2.0/24'
}
{
name: 'Subnet2'
subnetPrefix: '10.0.3.0/24'
}
]
resource VNET 'Microsoft.Network/virtualNetworks#2021-02-01' existing = {
name: 'vnet-test'
}
#batchSize(1)
resource Subnets 'Microsoft.Network/virtualNetworks/subnets#2020-11-01' = [for (sn, index) in subnets: {
name: sn.name
parent: VNET
properties: {
addressPrefix: sn.subnetPrefix
}
}]
Do you know how I can modify the template to add the UDR as well?
There is routeTable property on the subnet resource (see documentation):
// reference to existing route table
resource routeTable 'Microsoft.Network/routeTables#2022-01-01' existing = {
name: 'udr-test'
}
#batchSize(1)
resource Subnets 'Microsoft.Network/virtualNetworks/subnets#2020-11-01' = [for (sn, index) in subnets: {
name: sn.name
parent: VNET
properties: {
addressPrefix: sn.subnetPrefix
routeTable:{
id: routeTable.id // assign the route table
}
}
}]

Iterating over multi-level yaml values in terraform

I'm trying to shorten my terraform code for deploying azure vnets by iterating over values I provide in a yaml file. I want to write one .tf file with the code for the vnets, the subnets, the NSGs, etc. but I'm struggling to get the locals block right to correctly iterate through my yaml file (see below)
vnets:
- name: adds
location: eastus
address_space: ["10.1.0.0/24"]
subnets:
- name: adds
address_prefix: "10.1.0.0/27"
- name: dns
location: eastus
address_space: ["10.1.53.0/24"]
subnets:
- name: dns-inbound
address_prefix: "10.1.53.0/28"
- name: dns-outbound
address_prefix: "10.1.53.16/28"
Any help on how I should right my locals block would be appreciated!
This code will transform your yaml file into local map:
locals {
vnets = yamldecode(file("./test.yaml"))
vnets_map = {
for vnet in local.vnets.vnets :
vnet.name => {
address_space = vnet.address_space
location = vnet.location
subnets = {
for subnet in vnet.subnets :
subnet.name => subnet.address_prefix
}
}
}
}
output "example-output-dns-inbound-subnet" {
value = local.vnets_map.dns.subnets.dns-inbound
}
I took the liberty of changing lists to maps - it is better to navigate in terraform. Entire vnets_map object looks like this:
{
"adds" = {
"address_space" = [
"10.1.0.0/24",
]
"location" = "eastus"
"subnets" = {
"adds" = "10.1.0.0/27"
}
}
"dns" = {
"address_space" = [
"10.1.53.0/24",
]
"location" = "eastus"
"subnets" = {
"dns-inbound" = "10.1.53.0/28"
"dns-outbound" = "10.1.53.16/28"
}
}
}

How do I defined subnets in Bicep such that the parent Vnet has a reference and that I can dependOn the subnet deployment?

I have a situation where I need to define my subnets in the properties.subnets field of the parent virtual network otherwise I get the 'InUseSubnetCannotBeDeleted' problem
Option 1 - Defined inline
However if I define my subnets directly in the properties.subnet array (see below) then they are not created as children and I cannot seem to create a reference them as a resource for when I want to create a dependsOn reference for another resource.
resource virtualNetwork 'Microsoft.Network/virtualNetworks#2021-08-01' = {
// ... other fields
properties: {
subnets: [
// How can I get a reference to these that I can 'dependOn'?
{
name: 'subnet-1'
// ... other fields
}
{
name: 'subnet-2'
// ... other fields
}
]
}
}
Option 2 - Defined separately
resource virtualNetwork 'Microsoft.Network/virtualNetworks#2021-08-01' = {
// ... other fields
properties: {
subnets: [
subnet1 // Gives a circular reference error
]
}
}
resource subnet1 'Microsoft.Network/virtualNetworks/subnets#2021-08-01' = {
parent: virtualNetwork
name: 'subnet-1'
// ... other fields
}
I have tried defining the subnets as separate resources and then reference the resources in the properties.subnet array but, since subnets need a reference to the parent virtual network proeprty, Bicep complains about a circular reference.
It seems that ARM templates can use textual references using the name of the subnet in properties.subnets whcih could get around the circular reference, however Bicep does not allow this.
So how do I defined my subnets so that I can simulteneously satisfy the virtual network's required to have a reference to the subnets in properties.subnets as well as be able to have a resource reference that I can use in dependsOn clauses?
Maybe this will work. Bicep builds it without errors, but I have not tried to deploy it.
resource virtualNetwork 'Microsoft.Network/virtualNetworks#2021-08-01' = {
name: 'myvnet'
location: 'swedencentral'
properties: {
addressSpace: {
addressPrefixes: [
'10.0.0.0/20'
]
}
subnets: [
{
name: 'subnet-1'
properties: {
addressPrefix: '10.0.0.0/24'
}
}
]
}
}
resource subnet 'Microsoft.Network/virtualNetworks/subnets#2022-01-01' existing = {
name: 'myvnet/subnet-1'
scope: resourceGroup()
}
resource storage 'Microsoft.Storage/storageAccounts#2021-09-01' = {
name: 'mystorage'
location: 'swedencentral'
dependsOn: [
subnet
]
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
}

Get resource from symbolic name array in Bicep

In Bicep I am creating an array of origin groups with a for loop. I want to be able to reference specific values in this array as a parent for another resource.
I'm creating the array like this:
var originGroups = [
{
name: 'firstOriginGroup'
}
{
name: 'secondOriginGroup'
}
]
resource origin_groups 'Microsoft.Cdn/profiles/originGroups#2021-06-01' = [for group in originGroups :{
name: group.name
other properties...
}
Then I have an array of origin groups, "Microsoft.Cdn/profiles/originGroups#2021-06-01[]". I then want to make a origin with a parent. secondOriginGroup.
resource my_origin 'Microsoft.Cdn/profiles/originGroups/origins#2021-06-01' = {
name: 'myOrigin'
parent: origin_groups[ //select specific name here ]
other parameters...
}
Is it posible in bicep to select a specific indexer here or am i only able to index on ordinal numbers? Am I able to do, where name == 'secondOriginGroup'?
You could loop through the originGroups again and filter on 'secondOriginGroup':
resource my_origin 'Microsoft.Cdn/profiles/originGroups/origins#2021-06-01' = [for (group, i) in originGroups: if (group.name == 'secondOriginGroup') {
name: 'myOrigin'
parent: origin_groups[i]
other parameters...
}]
You'll need to use indexes in your loop, like this:
var originGroups = [
{
name: 'firstOriginGroup'
}
{
name: 'secondOriginGroup'
}
]
resource origin_groups 'Microsoft.Cdn/profiles/originGroups#2021-06-01' = [for (group, index) in originGroups :{
name: group.name
other properties...
}
resource my_origin 'Microsoft.Cdn/profiles/originGroups/origins#2021-06-01' = {
name: 'myOrigin'
parent: origin_groups[index]
other parameters...
}

How to select and add multiple subnets of a VNet in networking section of an azure eventHub using bicep

How to select and add multiple subnets of a VNet in the networking section of an azure eventHub resource using azure bicep.
// Create an event hub namespace
var eventHubNamespaceName = 'evhns-demo1436'
resource eventHubNamespace 'Microsoft.EventHub/namespaces#2021-01-01-preview' = {
name: eventHubNamespaceName
location: resourceGroup().location
sku: {
name: 'Standard'
tier: 'Standard'
capacity: 1
}
properties: {
zoneRedundant: true
}
}
// Create an event hub inside the namespace
var eventHubName = 'evh-demo1436'
resource eventHubNamespaceName_eventHubName 'Microsoft.EventHub/namespaces/eventhubs#2021-01-01-preview' = {
parent: eventHubNamespace
name: eventHubName
properties: {
messageRetentionInDays: 7
partitionCount: 1
}
}
// Grant Listen and Send on our event hub
resource eventHubNamespaceName_eventHubName_ListenSend 'Microsoft.EventHub/namespaces/eventhubs/authorizationRules#2021-01-01-preview' = {
parent: eventHubNamespaceName_eventHubName
name: 'ListenSend'
properties: {
rights: [
'Listen'
'Send'
]
}
dependsOn: [
eventHubNamespace
]
}
resource testVnet 'Microsoft.Network/virtualNetworks#2021-03-01' existing = {
name: 'testvnet'
}
resource testsubnet 'Microsoft.Network/virtualNetworks/subnets#2021-03-01' existing = {
parent: testVnet
name: 'testsubnet'
}
resource enHubVnetRule 'Microsoft.EventHub/namespaces/virtualnetworkrules#2018-01-01-preview' = {
name: 'vnetName'
parent: eventHubNamespace
properties: {
virtualNetworkSubnetId: testsubnet.id
}
}
With above code I can only add one particular subnet of a VNet to the VNet entry of azure EventHub resource in networking section using azure bicep.
How do I fetch all subnets of a VNet and add/select them all to the VNet entry of azure EventHub resource in networking section using azure bicep.
You have to use for loop for the subnet block and virtual-network rule block like below:
// Create an event hub namespace
param eventHubNamespaceName string = 'evhns-demo1436'
resource eventHubNamespace 'Microsoft.EventHub/namespaces#2021-01-01-preview' = {
name: eventHubNamespaceName
location: resourceGroup().location
sku: {
name: 'Standard'
tier: 'Standard'
capacity: 1
}
properties: {
zoneRedundant: true
}
}
// Create an event hub inside the namespace
param eventHubName string = 'evh-demo1436'
resource eventHubNamespaceName_eventHubName 'Microsoft.EventHub/namespaces/eventhubs#2021-01-01-preview' = {
parent: eventHubNamespace
name: eventHubName
properties: {
messageRetentionInDays: 7
partitionCount: 1
}
}
// Grant Listen and Send on our event hub
resource eventHubNamespaceName_eventHubName_ListenSend 'Microsoft.EventHub/namespaces/eventhubs/authorizationRules#2021-01-01-preview' = {
parent: eventHubNamespaceName_eventHubName
name: 'ListenSend'
properties: {
rights: [
'Listen'
'Send'
]
}
dependsOn: [
eventHubNamespace
]
}
param subnets array =[
'test'
'mysubnet'
]
param vnetname string = 'test-ansuman'
resource testVnet 'Microsoft.Network/virtualNetworks#2021-03-01' existing = {
name: vnetname
}
resource testsubnet 'Microsoft.Network/virtualNetworks/subnets#2021-03-01' existing =[for subnet in subnets : {
parent: testVnet
name: subnet
}]
resource enHubVnetRule 'Microsoft.EventHub/namespaces/virtualnetworkrules#2018-01-01-preview' = [for (subnet,i) in subnets :{
name: '${vnetname}-${subnet}'
parent: eventHubNamespace
properties: {
virtualNetworkSubnetId:testsubnet[i].id
}
}]
Output:

Resources