chew224
chew224

Reputation: 501

Azure ARM Inline IF not working

I am trying to build an Azure VNET via .json template.

I am trying to use an inline conditional statement to either create a 2nd subnet or skip creating the 2nd subnet. I do not think I am using json('null') correctly, or if this is even possible. My understanding is if json('null') is chosen, nothing is chosen.

Any help is appreciated!

"apiVersion": "2016-06-01",
"type": "Microsoft.Network/virtualNetworks",
"name": "My-VNET",
"location": "[resourceGroup().location]",
"properties": {
    "addressSpace": {
        "addressPrefixes": [
            "[parameters('virtualNetworkCIDR')]"
        ]
    },
    "subnets": [{
            "name": "[parameters('firstSubnetName')]",
            "properties": {
                "addressPrefix": "10.10.1.0/24"
            }
        }, {
            "name": "[if(equals(parameters('createSecondSubnet'), 'Yes'), parameters('secondSubnetName'), json('null'))]",
            "properties": {
                "addressPrefix": "10.10.2.0/24"
            }
        }
    ]
}

Upvotes: 0

Views: 388

Answers (2)

David
David

Reputation: 28

I'm sure that you managed to get some kind of solution to this a while ago ... however, I have a solution that works well for this sort of thing ... it doesn't use conditional statements though.

In PowerShell create some hash-tables like so ...

# Resource group Hashtables.
$rgDev = @{
    Name = "DEV-RG"
    SubscriptionId = $subNonProd
    Location = "desiredregion"
}
$rgUat = @{
    Name = "UAT-RG"
    SubscriptionId = $subNonProd
    Location = "desiredregion"
}

#Vnet Hashtables
$vnetDev = @{
    ResourceGroup = $rgDev
    VnetName = "Dev-vnet"
    CIDR = @('x.x.x.x/27')
    Subnets = @(
             @{
                Name = "Dev-Web-subnet"
                CIDR = "y.y.y.y/28"
             },
             @{
                Name = "Dev-DB-subnet"
                CIDR = "z.z.z.z/28"
             })
}
$vnetUat = @{
    ResourceGroup = $rgUat
    VnetName = "UAT-vnet"
    CIDR = @('f.f.f.f/27')
    Subnets = @(
             @{
                Name = "UAT-Web-subnet"
                CIDR = "g.g.g.g/28"
             },
             @{
                Name = "UAT-DB-subnet"
                CIDR = "h.h.h.h/28"
             })
}

Next I lump the hashtables into an array and foreach over the lot. I have a little script that switches my context so that I can deploy to multiple subscriptions in the one bootstrap type script.

$vnets = @($vnetDev, $vnetUat)

ForEach ($vn in $vnets) {

    $deploymentName = $vn.VnetName + "_Deployment."

    .\SwitchSubscription.ps1 -subName $vn.ResourceGroup.SubscriptionName -subId $vn.ResourceGroup.SubscriptionId

    New-AzureRmResourceGroupDeployment  -Name $deploymentName `
                                        -ResourceGroupName $vn.ResourceGroup.Name `
                                        -TemplateFile .\JSONFiles\Vnets.json `
                                        -vnet $vn

}

The Parameters section of the ARM template looks like this ...

    "parameters": {        
        "vnet": {
            "type": "object",
        }
    },

then the Resource Section looks like this ...

        {
            "name": "[concat(parameters('vnet').VnetName)]",
            "type": "Microsoft.Network/virtualNetworks",
            "apiVersion": "2017-10-01",
            "location": "[resourceGroup().location]",
            "tags": "[parameters('vnet').tags]",
            "properties": {
                "addressSpace": {
                    "addressPrefixes": "[parameters('vnet').CIDR]"
                },
                "copy": [
                    {
                        "name": "subnets",
                        "count": "[length(parameters('vnet').Subnets)]",
                        "input": {
                            "name": "[parameters('vnet').Subnets[copyIndex('Subnets')].Name]",
                            "properties": {
                                "addressPrefix": "[parameters('vnet').Subnets[copyIndex('Subnets')].CIDR]"
                            }
                        }
                    }
                ]
            }
        }
    ]

So what this all does is pass an object through to the ARM template that can have one Vnet with one or more subnets and create them all.

Hopefully this will help someone else out when / if they find this when googling.

Cheers,

Dave.

:)

Upvotes: 1

TravisCragg_MSFT
TravisCragg_MSFT

Reputation: 177

Normally to conditionally create resources in a template, you can use the "Condition" property: https://learn.microsoft.com/en-us/azure/architecture/building-blocks/extending-templates/conditional-deploy

if you would like to create multiple of a single type of resource, you can use the "Copy" property: https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-multiple#resource-iteration

Unfortunately, subnets do not have a condition or a copy property, because they are a sub-resource of the "Virtual Network" resource. Because of this, the entire VNET will need to be conditional, and you can specify multiple VNETS with only 1 of them deploying. The VNETS can also not have the same name, so you will need to specify multiple VNETS in your template.

For Example:

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
    "NumberofSubnets": {
      "type": "string",
      "allowedValues": ["1","2"],
      "metadata": {
        "description": "would you like to deploy 1 or 2 subnets?"
      }
    }
    },
    "resources": [
        {
        "type": "Microsoft.Network/virtualNetworks",
        "apiVersion": "2016-06-01",
        "name": "My-VNET1",
        "location": "[resourceGroup().location]",
        "condition": "[equals(parameters('NumberofSubnets'), 1)]",
        "properties": {
            "addressSpace": {
            "addressPrefixes": ["10.10.0.0/23"]
            },
    "subnets": [{
            "name": "Subnet1",
            "properties": {
                "addressPrefix": "10.10.0.0/24"
            }
        }
        ]
        }
        },
        {
        "type": "Microsoft.Network/virtualNetworks",
        "apiVersion": "2016-06-01",
        "name": "My-VNET2",
        "location": "[resourceGroup().location]",
        "condition": "[equals(parameters('NumberofSubnets'), 2)]",
        "properties": {
            "addressSpace": {
            "addressPrefixes": ["10.10.0.0/23"]
            },
    "subnets": [{
            "name": "Subnet1",
            "properties": {
                "addressPrefix": "10.10.0.0/24"
            }
        },
        {
            "name": "Subnet2",
            "properties": {
                "addressPrefix": "10.10.1.0/24"
            }
        }
        ]
        }
        }
    ]
}

This will solve your problem, but given a large amount of Subnets, you can see how a template can get very tedious.

The Best but most complicated way is to use linked templates. This Repository shows how you can create a dynamic number of subnets using linked templates

Upvotes: 1

Related Questions