1
votes

I wrote an ARM template to script the deploy and configuration of ServiceBus. One of the goals of the script was to make it easy to manage topics and subscriptions. In order to accomplish this, the script uses variables that are arrays.

This all works fine, but I'm seeing an issue whenever I try to use the same subscription name for two different topics. Now, I understand that a subscription can only be mapped to a single topic. The script attempts to account for that by joining the subscription name to the topic.

I should also note that the Azure UI will allow you to use the same subscription name beneath two topics. This script was derived from setting up this scenario via the azure console then exporting the ARM.

I have been over this script several dozen times and I'm not seeing the cause. Hoping new eyes will help.

Here is the script:

{
    "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "envType": {
            "type": "string",
            "allowedValues": [ "dev", "prod" ],
            "defaultValue": "dev",
            "metadata": { "description": "The environment type being created" }
        },
        "sbSku": {
            "type": "string",
            "allowedValues": [ "Standard", "Premium" ],
            "defaultValue": "Standard",
            "metadata": { "description": "The messaging tier for service Bus namespace" }
        }
    },
    "variables": {
        "defaultSASKeyName": "RootManageSharedAccessKey",
        "authRuleResourceId": "[resourceId('Microsoft.ServiceBus/namespaces/authorizationRules', variables('sbNamespaceName'), variables('defaultSASKeyName'))]",
        "sbNamespaceName": "[concat(parameters('envType'), 'eventbus')]",
        "sbVersion": "2017-04-01",
        "sbTopics": [
            "mytopic1",
            "mytopic2",
            "mytopic3",
            "mytopic4"
        ],
        "sbSubscriptions": [
            { "Name": "mysubA", "Topic": "mytopic1" },
            { "Name": "mysubB", "Topic": "mytopic2" },
            { "Name": "mysubB", "Topic": "mytopic3" },
            { "Name": "mysubC", "Topic": "mytopic4" }
        ]
    },
    "resources": [
        {
            "apiVersion": "[variables('sbVersion')]",
            "location": "[resourceGroup().location]",
            "name": "[variables('sbNamespaceName')]",
            "properties": {},
            "sku": {
                "name": "[parameters('sbSku')]"
            },
            "tags": {},
            "type": "Microsoft.ServiceBus/Namespaces"
        },
        {
            "type": "Microsoft.ServiceBus/namespaces/topics",
            "name": "[concat(variables('sbNamespaceName'), '/', variables('sbTopics')[copyIndex()])]",
            "apiVersion": "[variables('sbVersion')]",
            "location": "[resourceGroup().location]",
            "dependsOn": [
                "[concat('Microsoft.ServiceBus/namespaces/', variables('sbNamespaceName'))]"
            ],
            "properties": {
                "defaultMessageTimeToLive": "P14D",
                "maxSizeInMegabytes": 1024,
                "requiresDuplicateDetection": false,
                "enablePartitioning": true
            },
            "copy": {
                "name": "topiccopy",
                "count": "[length(variables('sbTopics'))]",
                "mode": "Serial",
                "batchSize": 3
            }
        },
        {
            "type": "Microsoft.ServiceBus/namespaces/topics/subscriptions",
            "name": "[concat(variables('sbNamespaceName'), '/', variables('sbSubscriptions')[copyIndex()].Topic, '/', variables('sbSubscriptions')[copyIndex()].Name)]",
            "apiVersion": "2017-04-01",
            "location": "East US",
            "dependsOn": [
                "[resourceId('Microsoft.ServiceBus/namespaces', variables('sbNamespaceName'))]",
                "[resourceId('Microsoft.ServiceBus/namespaces/topics', variables('sbNamespaceName'), variables('sbSubscriptions')[copyIndex()].Topic)]"
            ],
            "properties": {
                "maxDeliveryCount": 10
            },
            "copy": {
                "name": "subscriptioncopy",
                "count": "[length(variables('sbSubscriptions'))]",
                "mode": "Serial",
                "batchSize": 1
            }
        }
    ],
    "outputs": {
        "NamespaceConnectionString": {
            "type": "string",
            "value": "[listkeys(variables('authRuleResourceId'), variables('sbVersion')).primaryConnectionString]"
        },
        "SharedAccessPolicyPrimaryKey": {
            "type": "string",
            "value": "[listkeys(variables('authRuleResourceId'), variables('sbVersion')).primaryKey]"
        },
        "Topics": {
            "type": "array",
            "value": "[concat(variables('sbTopics'))]"
        },
        "Subscriptionss": {
            "type": "array",
            "value": "[concat(variables('sbSubscriptions'))]"
        }
    }
}

When executed with:

New-AzureRmResourceGroupDeployment -ResourceGroupName {xxx} -TemplateFile arm.servicebus.example.json

It returns:

New-AzureRmResourceGroupDeployment : 2:58:05 PM - Error: Code=InvalidTemplate; Message=Deployment template validation
failed: 'The template resource 'Microsoft.ServiceBus/namespaces/deveventbus/topics/mytopic3/subscriptions/mysubB'
cannot reference itself. Please see https://aka.ms/arm-template-expressions/#reference for usage details.'.
At line:1 char:1
+ New-AzureRmResourceGroupDeployment -ResourceGroupName Wiretappers_Ste ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [New-AzureRmResourceGroupDeployment], Exception
    + FullyQualifiedErrorId : Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.NewAzureResourceGroupDep
   loymentCmdlet

New-AzureRmResourceGroupDeployment : The deployment validation failed
At line:1 char:1
+ New-AzureRmResourceGroupDeployment -ResourceGroupName Wiretappers_Ste ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : CloseError: (:) [New-AzureRmResourceGroupDeployment], InvalidOperationException
    + FullyQualifiedErrorId : Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.NewAzureResourceGroupDep
   loymentCmdlet

The issue is caused by the third entry in the 'sbSubscriptions' array (mysubB/mytopic3). This is being processed in the third object beneath 'resources'.

If anyone can see my oversight, it would be appreciated.

PS. If anyone knows how to get the Azure tools to output the template json after it has expanded the "copy" node and the functions (resourceId, concat) that would be helpful as well.

UPDATE:2018-03-01 Here is a working template for future reference. See all comments below for details.

{
    "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "envType": {
            "type": "string",
            "allowedValues": [ "dev", "prod" ],
            "defaultValue": "dev",
            "metadata": { "description": "The environment type being created" }
        },
        "sbSku": {
            "type": "string",
            "allowedValues": [ "Standard", "Premium" ],
            "defaultValue": "Standard",
            "metadata": { "description": "The messaging tier for service Bus namespace" }
        }
    },
    "variables": {
        "sbNamespaceName": "[concat(parameters('envType'), 'eventbus')]",
        "sbVersion": "2017-04-01",
        "sbTopics": [
            "mytopic1",
            "mytopic2",
            "mytopic3",
            "mytopic4"
        ],
        "sbSubscriptions": [
            { "Name": "mysubA", "Topic": "mytopic1" },
            { "Name": "mysubB", "Topic": "mytopic2" },
            { "Name": "mysubB", "Topic": "mytopic3" },
            { "Name": "mysubC", "Topic": "mytopic4" }
        ]
    },
    "resources": [
        {
            "apiVersion": "[variables('sbVersion')]",
            "location": "[resourceGroup().location]",
            "name": "[variables('sbNamespaceName')]",
            "properties": {},
            "sku": {
                "name": "[parameters('sbSku')]"
            },
            "tags": {},
            "type": "Microsoft.ServiceBus/Namespaces"
        },
        {
            "type": "Microsoft.ServiceBus/namespaces/topics",
            "name": "[concat(variables('sbNamespaceName'), '/', variables('sbTopics')[copyIndex()])]",
            "apiVersion": "[variables('sbVersion')]",
            "location": "[resourceGroup().location]",
            "dependsOn": [
                "[variables('sbNamespaceName')]"
            ],
            "properties": {
                "defaultMessageTimeToLive": "P14D",
                "maxSizeInMegabytes": 1024,
                "requiresDuplicateDetection": false,
                "enablePartitioning": true
            },
            "copy": {
                "name": "topiccopy",
                "count": "[length(variables('sbTopics'))]",
                "mode": "Serial",
                "batchSize": 3
            }
        },
        {
            "type": "Microsoft.ServiceBus/namespaces/topics/subscriptions",
            "name": "[concat(variables('sbNamespaceName'), '/', variables('sbSubscriptions')[copyIndex()].Topic, '/', variables('sbSubscriptions')[copyIndex()].Name)]",
            "apiVersion": "[variables('sbVersion')]",
            "location": "[resourceGroup().location]",
            "dependsOn": [
                "[resourceId('Microsoft.ServiceBus/namespaces', variables('sbNamespaceName'))]",
                "[resourceId('Microsoft.ServiceBus/namespaces/topics', variables('sbNamespaceName'), variables('sbSubscriptions')[copyIndex()].Topic)]"
            ],
            "properties": {
                "maxDeliveryCount": 10
            },
            "copy": {
                "name": "subscriptioncopy",
                "count": "[length(variables('sbSubscriptions'))]"
            }
        }
    ],
    "outputs": {
        "Topics": {
            "type": "array",
            "value": "[concat(variables('sbTopics'))]"
        },
        "Subscriptionss": {
            "type": "array",
            "value": "[concat(variables('sbSubscriptions'))]"
        }
    }
}
1
try Test-AzureRmResourceGroupDeployment -verbose or -debug and it will show you that (most likely)4c74356b41
Thank you. The Test-AzureRmResourceGroupDeployment with -debug does show the expanded template. I was looking all over for that command.Steve R.

1 Answers

1
votes

Ok, i dont know what the issue is\was, but this works:

{
    "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "envType": {
            "type": "string",
            "allowedValues": [
                "dev",
                "prod",
                "zlp"
            ],
            "defaultValue": "zlp",
            "metadata": {
                "description": "The environment type being created"
            }
        },
        "sbSku": {
            "type": "string",
            "allowedValues": [
                "Standard",
                "Premium"
            ],
            "defaultValue": "Standard",
            "metadata": {
                "description": "The messaging tier for service Bus namespace"
            }
        }
    },
    "variables": {
        "sbNamespaceName": "[concat(parameters('envType'), 'eventbus')]",
        "sbVersion": "2017-04-01",
        "sbTopics": [
            "mytopic1",
            "mytopic2",
            "mytopic3",
            "mytopic4"
        ],
        "sbSubscriptions": [
            {
                "Name": "mysubA",
                "Topic": "mytopic1"
            },
            {
                "Name": "mysubB",
                "Topic": "mytopic2"
            },
            {
                "Name": "mysubB",
                "Topic": "mytopic3"
            },
            {
                "Name": "mysubC",
                "Topic": "mytopic4"
            }
        ]
    },
    "resources": [
        {
            "apiVersion": "[variables('sbVersion')]",
            "location": "[resourceGroup().location]",
            "name": "[variables('sbNamespaceName')]",
            "properties": {},
            "sku": {
                "name": "[parameters('sbSku')]"
            },
            "tags": {},
            "type": "Microsoft.ServiceBus/Namespaces"
        },
        {
            "type": "Microsoft.ServiceBus/namespaces/topics",
            "name": "[concat(variables('sbNamespaceName'), '/', variables('sbTopics')[copyIndex()])]",
            "apiVersion": "[variables('sbVersion')]",
            "location": "[resourceGroup().location]",
            "dependsOn": [
                "[variables('sbNamespaceName')]"
            ],
            "properties": {
                "defaultMessageTimeToLive": "P14D",
                "maxSizeInMegabytes": 1024,
                "requiresDuplicateDetection": false,
                "enablePartitioning": true
            },
            "copy": {
                "name": "topiccopy",
                "count": "[length(variables('sbTopics'))]"
            }
        },
        {
            "type": "Microsoft.ServiceBus/namespaces/topics/subscriptions",
            "name": "[concat(variables('sbNamespaceName'), '/', variables('sbSubscriptions')[copyIndex()].Topic, '/', variables('sbSubscriptions')[copyIndex()].Name)]",
            "apiVersion": "[variables('sbVersion')]",
            "location": "[resourceGroup().location]",
            "dependsOn": [
                "topiccopy"
            ],
            "properties": {
                "maxDeliveryCount": 10
            },
            "copy": {
                "name": "subscriptioncopy",
                "count": "[length(variables('sbSubscriptions'))]"
            }
        }
    ]
}

You can also use this to debug:

Test-AzureRmResourceGroupDeployment -verbose or -debug